mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-09-17 23:51:19 +00:00
* refractor(proactive): upgrade proactive feature with disentangled job and steps * refactor(proactive): apply audit fixes - rename read-side job 'proactive' -> 'proactive_read' (less confusing vs the refresh pipeline) - drop dedicated agent_wrapper.proactive; extraction reuses the default wrapper - simplify schema: remove unused ProactiveExtractOutput/TopicUpdate, drop resource_paths - extract no longer scans resource/ directly (daily notes already carry resource content) - update tests and docs accordingly * feat(proactive): strict extract-output gate and prompt total budget - parse_extract_reply now requires a contract section (follow_ups/extends/updates as a list); non-empty replies with misspelled section names trigger the existing one-shot retry instead of silently checkpointing changed files - pack_paths gains max_total_chars; extract packs newest daily material first, keeps the first file on overflow, and records omitted files in a trailer (default budget 300000 chars, configurable via max_total_chars) - tests: schema gate unit, schema-error retry e2e, budget unit + e2e * feat(proactive): add scenario-card plan step and generative agenda step * feat(proactive): digest-personal profile personalization and leaner LLM contract - extract/plan/agenda now draw a user profile block from <digest_dir>/personal/*.md (frontmatter description + body excerpt, per-file budget, profile.md fallback) - all daily access honours the configured daily_dir (prompt paths parameterized, config-driven fallbacks) so workspaces using e.g. memory/ work unchanged - schema trim: drop dead fields errors/material_paths, carry_forward_all -> count - shrink LLM output contract: new topics emit title/reason/confidence/paths only; keywords removed end-to-end, evidence derived from paths[0] (updates keep it) * fix(proactive): skip checkpoint when extract reply stays unusable after retry Two consecutive unparseable replies now short-circuit the round without checkpointing, so the same material is retried next round instead of being silently consumed (closes the residual audit #1 gap: the structural gate detected schema-wrong output but a double failure still checkpointed). * fix(proactive): replace running bool with reference-counted job activity tracker for the idle gate * refactor(proactive): remove job activity tracking and idle gate, restore job tree to upstream * fix(proactive): address second audit round (readonly reader, mtime checkpoint, wider fallbacks, profile containment, horizon content, expiry boundary) * refactor(dream): strip interests.yaml ownership from dream, proactive is now the sole writer * refactor(dream): separate proactive topic generation * ci: update renamed auto dream smoke test * fix(proactive): complete refresh migration and docs --------- Co-authored-by: jinli.yl <jinli.yl@alibaba-inc.com>
260 lines
10 KiB
Markdown
260 lines
10 KiB
Markdown
# Proactive
|
|
|
|
`proactive_read` is ReMe's interface for reading proactive memory. It does not reanalyze daily notes or call an LLM. It
|
|
reads interest topics written by the independent proactive refresh flow:
|
|
|
|
```text
|
|
daily/<date>/interests.yaml
|
|
```
|
|
|
|
A host agent can use it to learn "what is worth proactive attention today," then decide whether to remind the user, ask
|
|
a follow-up question, recommend a next step, or produce a proactive insight.
|
|
|
|
`interests.yaml` is generated by the proactive refresh pipeline, scheduled by `proactive_refresh_cron` by default.
|
|
`proactive_read` only reads and exposes the result; Auto Dream is an independent daily-to-digest flow and does not read
|
|
or write proactive state.
|
|
|
|
## Configuration
|
|
|
|
The default configuration is in `reme/config/default.yaml`. It defines the same refresh steps twice: a local-only
|
|
one-shot job for maintenance and debugging, and the scheduled job that runs every day at 18:00 in the application
|
|
timezone:
|
|
|
|
```yaml
|
|
proactive_refresh:
|
|
backend: base
|
|
enable_serve: false
|
|
steps: &proactive_refresh_steps
|
|
- backend: proactive_extract_step
|
|
file_catalog: proactive
|
|
scan_days: 2
|
|
carry_forward_days: 14
|
|
max_carry_forward_topics: 20
|
|
llm_timeout_seconds: 300
|
|
max_chars_per_file: 60000
|
|
max_total_chars: 300000
|
|
- backend: proactive_topics_step
|
|
known_threshold: 0.85
|
|
known_threshold_calibrated_for: text-embedding-v4@1024
|
|
min_push_confidence: 0.5
|
|
max_topics: 10
|
|
- backend: proactive_plan_step
|
|
- backend: proactive_agenda_step
|
|
- backend: proactive_finish_step
|
|
file_catalog: proactive
|
|
|
|
proactive_refresh_cron:
|
|
backend: cron
|
|
cron: "0 18 * * *"
|
|
steps: *proactive_refresh_steps
|
|
```
|
|
|
|
The anchor above is only a compact illustration; `default.yaml` spells out both step lists explicitly. The read job is:
|
|
|
|
```yaml
|
|
proactive_read:
|
|
backend: base
|
|
description: "Proactive: read daily/<date>/interests.yaml and expose the latest user-interest topics."
|
|
parameters:
|
|
type: object
|
|
properties:
|
|
date:
|
|
type: string
|
|
default: ""
|
|
include_content:
|
|
type: boolean
|
|
default: true
|
|
horizon_days:
|
|
type: integer
|
|
default: 1
|
|
min_confidence:
|
|
type: number
|
|
default: 0.4
|
|
steps:
|
|
- backend: proactive_step
|
|
min_confidence: 0.4
|
|
```
|
|
|
|
Parameters:
|
|
|
|
| Parameter | Purpose |
|
|
|-------------------|------------------------------------------------------------------------------------------------------|
|
|
| `date` | Date to read in `YYYY-MM-DD` format. When empty, use today in the application's timezone. |
|
|
| `include_content` | Whether to return the raw YAML in the answer and metadata. Defaults to `true`. |
|
|
| `horizon_days` | Read one day's exposure file, or use the truth source for a wider evidence horizon. Defaults to `1`. |
|
|
| `min_confidence` | Minimum topic confidence to return. Defaults to `0.4`; legacy topics use `0.5`. |
|
|
|
|
### Refresh cost, files, and opt-out
|
|
|
|
When no daily Markdown note changed, refresh exits before calling an LLM and does not create a new exposure file. With
|
|
changed material, extraction normally makes one LLM call and may retry once after an unusable reply. If push candidates
|
|
remain, planning makes one additional call; agenda generation makes one more when there are multiple candidates. A
|
|
refresh therefore makes at most four LLM calls with the default chain.
|
|
|
|
The refresh pipeline maintains the rebuildable `daily/_proactive.yaml` truth source, writes
|
|
`daily/<date>/interests.yaml`, and advances the independent `proactive` file catalog. Auto Dream does not read or write
|
|
any of those proactive artifacts.
|
|
|
|
To disable automatic refresh, use an explicit application config that omits the `proactive_refresh_cron` job. Keep the
|
|
local-only `proactive_refresh` job if you still want on-demand maintenance. Because it has `enable_serve: false`, it is
|
|
not exposed through HTTP or MCP.
|
|
|
|
## Input Contract
|
|
|
|
A current proactive-refresh file looks like this:
|
|
|
|
```yaml
|
|
version: 2
|
|
date: 2026-06-20
|
|
generated_at: 2026-06-20T18:00:00+08:00
|
|
push: true
|
|
topics:
|
|
- id: baa88ad49cb2
|
|
title: Quality regression in the memory retrieval pipeline
|
|
reason: The user has recently made repeated changes to search, node_search, and dream integration.
|
|
kind: follow_up
|
|
confidence: 0.86
|
|
first_seen: 2026-06-20
|
|
last_evidence_at: 2026-06-20
|
|
evidence: daily/2026-06-20/session.md
|
|
paths:
|
|
- daily/2026-06-20/session.md
|
|
agenda:
|
|
- topic_id: baa88ad49cb2
|
|
title: Quality regression in the memory retrieval pipeline
|
|
scenario_type: resume_task
|
|
opener: Review the latest retrieval regression before the next release.
|
|
next_action: Compare the failing query against the previous index snapshot.
|
|
preconditions: []
|
|
delivery: in_conversation
|
|
linked_memory: []
|
|
order_reason: Recent evidence and a concrete next action.
|
|
suppressed: []
|
|
```
|
|
|
|
Current v2 topics include stable identity, kind, confidence, evidence dates, and source paths. The reader also accepts
|
|
legacy v1 files containing `title`, `reason`, `evidence`, `keywords`, and `paths`; missing v2 confidence falls back to
|
|
`0.5`.
|
|
|
|
## Return Value
|
|
|
|
When the file is read successfully, `proactive_step` returns `summary` and `topics` in the primary answer. When
|
|
`include_content=true`, the answer also contains `content`. The same result fields remain available in standard response
|
|
metadata:
|
|
|
|
| Field | Description |
|
|
|-----------|------------------------------------------------------|
|
|
| `date` | The date actually read. |
|
|
| `path` | `daily/<date>/interests.yaml`. |
|
|
| `topics` | Parsed topic list. |
|
|
| `content` | Raw YAML; returned only when `include_content=true`. |
|
|
| `skipped` | `true` when the file does not exist. |
|
|
| `error` | Read or parse error. |
|
|
| `summary` | Short summary. |
|
|
| `agenda` | Today's proactive agenda (optional, v2 files only). |
|
|
|
|
When today's `interests.yaml` was produced by the proactive refresh chain with an agenda,
|
|
the answer also carries an `agenda` field: the ordered agenda items, each with `topic_id`,
|
|
`title`, `scenario_type`, `opener` (a natural conversation opener), `next_action` (the
|
|
minimal executable step), `preconditions`, `delivery`, `linked_memory` and `order_reason`.
|
|
Agenda items whose topic is resolved or below `min_confidence` are filtered out on read;
|
|
the field is absent when the file has no agenda.
|
|
|
|
When the file exists and parses successfully, the answer is structured data. For example:
|
|
|
|
```json
|
|
{
|
|
"summary": "Read 1 proactive topic(s) from daily/2026-06-20/interests.yaml",
|
|
"topics": [
|
|
{
|
|
"id": "baa88ad49cb2",
|
|
"title": "Quality regression in the memory retrieval pipeline",
|
|
"reason": "The user has recently made repeated changes to search, node_search, and dream integration.",
|
|
"kind": "follow_up",
|
|
"confidence": 0.86,
|
|
"first_seen": "2026-06-20",
|
|
"last_evidence_at": "2026-06-20",
|
|
"evidence": "daily/2026-06-20/session.md",
|
|
"paths": ["daily/2026-06-20/session.md"]
|
|
}
|
|
],
|
|
"agenda": [
|
|
{
|
|
"topic_id": "baa88ad49cb2",
|
|
"title": "Quality regression in the memory retrieval pipeline",
|
|
"scenario_type": "resume_task",
|
|
"opener": "Review the latest retrieval regression before the next release.",
|
|
"next_action": "Compare the failing query against the previous index snapshot.",
|
|
"preconditions": [],
|
|
"delivery": "in_conversation",
|
|
"linked_memory": [],
|
|
"order_reason": "Recent evidence and a concrete next action."
|
|
}
|
|
],
|
|
"content": "date: 2026-06-20\n..."
|
|
}
|
|
```
|
|
|
|
With `include_content=false`, the `content` field is omitted from the answer. Missing-file and read-error answers remain
|
|
explicit `Skipped: ...` and `Error: ...` messages, respectively.
|
|
|
|
A missing file is not an error. The call succeeds with a skipped result:
|
|
|
|
```text
|
|
Skipped: interests file not found at daily/2026-06-20/interests.yaml
|
|
```
|
|
|
|
This lets a host agent treat "there is no proactive refresh result for today yet" as a normal empty state.
|
|
|
|
## Running Proactive
|
|
|
|
Run one refresh immediately through the normal application lifecycle:
|
|
|
|
```bash
|
|
reme start job=proactive_refresh date=2026-06-20
|
|
```
|
|
|
|
This command may call the configured LLM and may update `_proactive.yaml`, `interests.yaml`, and the proactive catalog.
|
|
It does not run Auto Dream.
|
|
|
|
Read the generated topics:
|
|
|
|
```bash
|
|
reme proactive_read date=2026-06-20
|
|
```
|
|
|
|
Omit the raw YAML content:
|
|
|
|
```bash
|
|
reme proactive_read date=2026-06-20 include_content=false
|
|
```
|
|
|
|
## Relationship to auto_dream
|
|
|
|
Proactive refresh and Auto Dream consume daily notes independently:
|
|
|
|
```text
|
|
daily notes -> auto_dream -> digest
|
|
daily notes -> proactive_refresh_cron -> daily/<date>/interests.yaml -> proactive_read -> host agent
|
|
```
|
|
|
|
The proactive responsibilities are divided as follows:
|
|
|
|
| Module | Responsibility |
|
|
|--------------------------|--------------------------------------------------------|
|
|
| `proactive_refresh` | Run the refresh pipeline once from the local CLI. |
|
|
| `proactive_refresh_cron` | Run the same writer pipeline every day at 18:00. |
|
|
| `proactive_step` | Read `interests.yaml` and expose it to the host agent. |
|
|
|
|
`proactive_read` does not modify files, update a catalog, or decide whether the user should be interrupted. It only provides
|
|
the day's topic material. The caller's product policy determines whether, when, and in what tone to push it to the user.
|
|
|
|
## Failure Modes
|
|
|
|
| Scenario | Behavior |
|
|
|-------------------------------------|--------------------------------------------------------|
|
|
| `interests.yaml` does not exist | `success=true`, `skipped=true`, `topics=[]`. |
|
|
| YAML cannot be read or parsed | `success=false`; the answer contains an error summary. |
|
|
| YAML exists but has no valid topics | `success=true`, `topics=[]`. |
|
|
|
|
Callers should therefore check `success` first, then `skipped`, and finally whether `topics` is empty.
|