@fonlan/dsh-gitmemo 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -9
- package/README.zh.md +77 -9
- package/lib/client.js +721 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +158 -15
- package/lib/index.js +414 -17
- package/lib/mem.d.ts +75 -5
- package/lib/mem.js +182 -18
- package/lib/migrate.js +2 -1
- package/lib/systemone.d.ts +213 -0
- package/lib/systemone.js +283 -0
- package/package.json +33 -5
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@ dependency, and no manual memory commands are ever needed.
|
|
|
16
16
|
- **Git-only** — no runtime dependency beyond the `git` CLI
|
|
17
17
|
- **Token-efficient** — reuses prior conclusions via `mem_search`; subagents carry neither the workflow rules nor the tool schemas
|
|
18
18
|
- **Immutable entries** — every write creates a new file; corrections use `mem_replace` (one commit deletes the old file and adds the new one), withdrawal uses `mem_delete`
|
|
19
|
+
- **Knowledge freshness** — `mem_replace` is not just for user corrections: work that overrules a stored conclusion actively replaces it; `mem_search` scores hits as distinct matched keywords + a mild recency bonus (≤ +0.5, linearly decaying to 0 over ~180 days), so conflicting stale conclusions lose to their replacements
|
|
20
|
+
- **Topic pages (MOC)** — a `kind: "topic"` entry aggregates a topic's "current truth": the summary states the currently-valid conclusions and the page evolves via `mem_replace` (kind is inherited), not per-task rewrites
|
|
21
|
+
- **Wiki links between entries** — content references other entries as `[[<commit-hash>]]`; `mem_read` with `expand: true` resolves those links one hop and automatically follows the `GitMemo-Replaces` chain to a replaced target's active version (dangling links come back with an error)
|
|
19
22
|
- **Structured search** — commit messages carry `GitMemo-*` trailers (keywords, digest, search-text projections); search is `git log --grep --fixed-strings` over commit messages only — entry bodies are never scanned
|
|
20
23
|
- **Auditable** — every memory action is a commit in `.mem`'s Git history; replaced/deleted entries stay readable by hash
|
|
21
24
|
- **Crash-safe** — write/delete/replace run under a cross-process lock with a journal written before entry mutation; migration uses a sibling swap journal so an interrupted directory exchange is recovered before automatic initialization
|
|
@@ -25,11 +28,11 @@ dependency, and no manual memory commands are ever needed.
|
|
|
25
28
|
|
|
26
29
|
| Piece | Description |
|
|
27
30
|
| --- | --- |
|
|
28
|
-
| `mem_search` | Search memories: `keywords` (array of 1–12, 中英文同义词), `skip` + `snapshot` (stable pagination). Returns up to 20 scored hits with `summary` / `keywords` / `matched_keywords` |
|
|
29
|
-
| `mem_read` | Read one memory entry by create/replace commit hash (full markdown; historical hashes stay readable) |
|
|
30
|
-
| `mem_write` | Store a task outcome: `title` + `summary` + `keywords` (2–12) + `content` (engine generates front matter), optional `related_branches` / `related_paths`. One ADD commit per immutable file |
|
|
31
|
+
| `mem_search` | Search memories: `keywords` (array of 1–12, 中英文同义词), `skip` + `snapshot` (stable pagination). Returns up to 20 scored hits with `summary` / `keywords` / `kind` / `matched_keywords` (score = matched keywords + recency bonus) |
|
|
32
|
+
| `mem_read` | Read one memory entry by create/replace commit hash (full markdown; historical hashes stay readable); returns `kind`; optional `expand: true` resolves `[[hash]]` links one hop |
|
|
33
|
+
| `mem_write` | Store a task outcome: `title` + `summary` + `keywords` (2–12) + `content` (engine generates front matter), optional `kind` (`"task"` default / `"topic"` aggregated page), `related_branches` / `related_paths`. One ADD commit per immutable file |
|
|
31
34
|
| `mem_delete` | Withdraw an obsolete conclusion (requires `commit_hash` + `reason`) |
|
|
32
|
-
| `mem_replace` | Correct an outdated conclusion in ONE atomic commit (D old + A new) — never delete-then-write |
|
|
35
|
+
| `mem_replace` | Correct an outdated conclusion in ONE atomic commit (D old + A new) — never delete-then-write. Triggered by user corrections AND by work that overrules a stored conclusion; `kind` defaults to the replaced entry's kind |
|
|
33
36
|
| Scoped rules | The workflow rules + the five tools are registered into **root agents only** (`delegationDepth === 0`) at `agent/created`; subagents carry neither |
|
|
34
37
|
|
|
35
38
|
## Installation
|
|
@@ -62,8 +65,92 @@ The bundle patch ships with sensible defaults; override them in the profile's
|
|
|
62
65
|
searchLimit: 20 # max hits per mem_search call (page size)
|
|
63
66
|
lockTimeoutMs: 30000 # cross-process lock wait timeout
|
|
64
67
|
projectRoot: null # optional explicit project root (defaults to the session cwd)
|
|
68
|
+
systemOne: # optional System-one recall gate, see below
|
|
69
|
+
enabled: true
|
|
70
|
+
endpoint: https://api.typesafe.ai/v1/systemone
|
|
71
|
+
model: jev-latest
|
|
72
|
+
mode: noul # noul | score
|
|
73
|
+
threshold: 0.5 # noul mode: keep a candidate when P(yes) >= this
|
|
65
74
|
```
|
|
66
75
|
|
|
76
|
+
## System-one Recall Gate (optional)
|
|
77
|
+
|
|
78
|
+
A `mem_search` page can be handed to a **System-one model** (TypeSafe Jev by
|
|
79
|
+
default) for one fast judgement, so memories that are **completely unrelated**
|
|
80
|
+
to the current task are dropped before they are injected. Only genuinely
|
|
81
|
+
reusable entries survive.
|
|
82
|
+
|
|
83
|
+
- **Inert by default.** The gate runs only when a usable credential is
|
|
84
|
+
configured (`apiKey`, the credential named by `apiKeyEnv`, or the environment
|
|
85
|
+
variable). With nothing configured, recall behaves **byte-for-byte** as it did
|
|
86
|
+
before the gate existed.
|
|
87
|
+
- **Fails open.** A timeout, a non-2xx response, an unparseable body — any
|
|
88
|
+
failure keeps every candidate and reports why in `gated.degraded` +
|
|
89
|
+
`gated.reason`. **A broken endpoint can never hide a memory.**
|
|
90
|
+
- **Never empties a page.** If the model rejects the whole page, at least
|
|
91
|
+
`minKeep` (default 1) best-ranked candidates are retained, so "the gate removed
|
|
92
|
+
it" and "there was nothing there" stay distinguishable. The tool's `gated` line
|
|
93
|
+
says so out loud — such a page carries a `NOTE(no candidate scored above the
|
|
94
|
+
threshold…)` marker, so a retained floor is never mistaken for a candidate that
|
|
95
|
+
genuinely passed. `judged=` counts only the candidates actually sent to the
|
|
96
|
+
endpoint, with anything past `maxCandidates` reported as `untouched=`
|
|
97
|
+
(unjudged candidates are never dropped).
|
|
98
|
+
- **Recoverable.** `gated.dropped_hashes` lists 8-char hashes of dropped
|
|
99
|
+
entries; `mem_read <short-hash>` brings one back at any time.
|
|
100
|
+
- **Auditable.** Every candidate's probability/score and keep/drop verdict goes
|
|
101
|
+
to the plugin log (off the model context), and the endpoint's reported
|
|
102
|
+
`usage.input_tokens` lands in `gated.input_tokens`, so the gate's own cost is
|
|
103
|
+
directly measurable.
|
|
104
|
+
|
|
105
|
+
### Settings
|
|
106
|
+
|
|
107
|
+
| Field | Default | Meaning |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `enabled` | `true` | Master switch; still a no-op without a credential |
|
|
110
|
+
| `endpoint` | `https://api.typesafe.ai/v1/systemone` | Any endpoint speaking the same request/answer contract (self-hosted, LiteLLM pass-through, …) |
|
|
111
|
+
| `model` | `jev-latest` | Model identifier sent in the request body |
|
|
112
|
+
| `apiKey` | — | Declared `role("secret")`: redacted on read, write-only in the form |
|
|
113
|
+
| `apiKeyEnv` | `TYPESAFE_API_KEY` | Credential reference; resolved literal key → credentials service → environment |
|
|
114
|
+
| `mode` | `noul` | `noul` (yes/no probability) or `score` (graded levels) |
|
|
115
|
+
| `threshold` | `0.5` | `noul` mode: keep when P(yes) ≥ this |
|
|
116
|
+
| `scoreMin` | `2` | `score` mode cutoff. Note Jev's `score` is `Σ(level_index × probability)`, ranging 0…levels−1 (5 levels → 0…4), **not 0–1** |
|
|
117
|
+
| `minKeep` | `1` | Candidates retained when the whole page is rejected |
|
|
118
|
+
| `maxCandidates` | `20` | Candidates judged per request; the remainder is **never judged and never dropped** |
|
|
119
|
+
| `maxTaskChars` | `2000` | Task-text truncation length |
|
|
120
|
+
| `timeoutMs` | `8000` | Request deadline |
|
|
121
|
+
|
|
122
|
+
Every field is marked `.volatile()` — that is the precondition for the DSH
|
|
123
|
+
settings plane to see the entry and apply edits live.
|
|
124
|
+
|
|
125
|
+
### Settings page
|
|
126
|
+
|
|
127
|
+
The plugin ships a settings card (**Settings → GitMemo**) where the gate can be
|
|
128
|
+
switched on and off and the endpoint, model and API key can be filled in
|
|
129
|
+
directly, applying immediately with no restart. The API key is written through
|
|
130
|
+
the credentials domain — it is **never persisted as a plaintext config value** —
|
|
131
|
+
and the form is write-only. The switch stages `systemOne.enabled`; turning it off
|
|
132
|
+
leaves recall byte-for-byte as it was before the gate existed, and a **Save** is
|
|
133
|
+
what writes it (the switch alone is a draft). An absent `enabled` reads as on, so
|
|
134
|
+
an unconfigured section shows the gate as enabled — which is what the host
|
|
135
|
+
default does.
|
|
136
|
+
|
|
137
|
+
### Known trade-offs
|
|
138
|
+
|
|
139
|
+
- **English-first.** Jev's primary training language is English; CJK works but
|
|
140
|
+
the vendor documents lower accuracy. The gate's question wording is English;
|
|
141
|
+
only the candidate text and task text may be Chinese.
|
|
142
|
+
- **Context ceiling.** 64k tokens per request, of which `state` + the longest
|
|
143
|
+
single question may use 32k. `maxCandidates` and `maxTaskChars` exist to hold
|
|
144
|
+
that line.
|
|
145
|
+
- **Latency on the critical path.** Recall runs before every repo task, and the
|
|
146
|
+
gate adds one network round trip (~0.4s observed), so `timeoutMs` defaults to
|
|
147
|
+
8s and every failure path fails open.
|
|
148
|
+
- **Data egress.** Memory summaries leave the machine. TypeSafe currently offers
|
|
149
|
+
**no** zero data retention; point `endpoint` at a self-hosted implementation
|
|
150
|
+
(e.g. MIT-licensed `jeff`) or a local endpoint to avoid egress entirely.
|
|
151
|
+
- **Billing.** Priced per input token ($0.042 per million input tokens, output
|
|
152
|
+
free) — not per call.
|
|
153
|
+
|
|
67
154
|
## Memory Location & Format
|
|
68
155
|
|
|
69
156
|
The `.mem` repository lives at the **project root** of the calling session's workspace
|
|
@@ -83,7 +170,8 @@ The `.mem` repository lives at the **project root** of the calling session's wor
|
|
|
83
170
|
`.gitignore`), and refuses to run when the parent repo already tracks `.mem` content.
|
|
84
171
|
- Every write creates a brand-new file with an exclusive create (never overwrites), commits
|
|
85
172
|
one ADD commit with structured trailers, and records the code branch/SHA/related paths in
|
|
86
|
-
the entry front matter.
|
|
173
|
+
the entry front matter. Front matter always carries `kind` (`"task"` or `"topic"`); topic
|
|
174
|
+
entries additionally carry a `GitMemo-Kind: topic` commit trailer.
|
|
87
175
|
|
|
88
176
|
The whole memory stays readable with plain `git`:
|
|
89
177
|
|
|
@@ -97,7 +185,8 @@ git -C .mem show <commit-hash>
|
|
|
97
185
|
1. **Before work — search.** For repo-related tasks, extract 1–12 中英文关键词 → `mem_search`.
|
|
98
186
|
Pure chat and general Q&A need no search.
|
|
99
187
|
2. **Preselect results.** Based on `title` / `summary` / `keywords` / `score` /
|
|
100
|
-
`matched_keywords`, `mem_read` at most 5 most relevant memories
|
|
188
|
+
`matched_keywords`, `mem_read` at most 5 most relevant memories (`kind: "topic"` entries
|
|
189
|
+
are a topic's aggregated entry point — prefer them); paginate with `skip` +
|
|
101
190
|
the returned `snapshot`.
|
|
102
191
|
3. **End-of-session checkpoint — the only write path.** When the conversation is ending,
|
|
103
192
|
`mem_write` every completed repo-related task that still lacks a memory and whose outcome is
|
|
@@ -106,10 +195,17 @@ git -C .mem show <commit-hash>
|
|
|
106
195
|
operational git actions. `keywords` should be task-related words NOT already present in
|
|
107
196
|
`title` / `summary` (中英文同义词 both fine) — words already there are searchable via
|
|
108
197
|
`title` / `summary` themselves, so repeating them does not improve recall.
|
|
109
|
-
4. **
|
|
198
|
+
4. **Keep fresh.** If the user corrects a stored conclusion and a replacement exists →
|
|
110
199
|
`mem_replace` (never delete-then-write). If it is obsolete with no replacement →
|
|
111
|
-
`mem_delete` with a `reason`.
|
|
112
|
-
|
|
200
|
+
`mem_delete` with a `reason`. The same applies — without waiting for the user — when this
|
|
201
|
+
session's own work overrules a stored conclusion (implemented/refactored away). When search
|
|
202
|
+
returns conflicting old/new conclusions, trust the newer one (score already includes the
|
|
203
|
+
recency bonus).
|
|
204
|
+
5. **Topic pages.** Once a topic has accumulated several memories — or needs a "current truth"
|
|
205
|
+
entry point — write one `kind: "topic"` aggregated entry: the summary states the currently
|
|
206
|
+
valid conclusions, and the content links the evidence entries as `[[<commit-hash>]]` with a
|
|
207
|
+
one-line status each; evolve topic pages via `mem_replace`.
|
|
208
|
+
6. **Subagent results.** Only the root agent decides whether a session-level memory is written.
|
|
113
209
|
|
|
114
210
|
## Development
|
|
115
211
|
|
package/README.zh.md
CHANGED
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
- **仅依赖 Git** —— 除 `git` CLI 外无任何运行时依赖
|
|
16
16
|
- **省 token** —— 通过 `mem_search` 复用既有结论;子代理既不携带工作流规则也不携带工具 schema
|
|
17
17
|
- **条目不可变** —— 每次写入都创建新文件;更正用 `mem_replace`(一个提交同时删除旧文件、新增新文件),作废用 `mem_delete`
|
|
18
|
+
- **知识保鲜** —— `mem_replace` 不只用于用户更正:本次工作覆盖旧结论时同样主动替换;`mem_search` 评分为「命中关键词数 + 温和的 recency 加成(≤ +0.5,180 天线性衰减到 0)」,新旧结论冲突时自动偏向新条目
|
|
19
|
+
- **主题聚合页(MOC)** —— `kind: "topic"` 条目聚合一个主题的「当前真相」:summary 概括当下有效结论,靠 `mem_replace` 演进(kind 自动继承),不按任务重复新增
|
|
20
|
+
- **条目间 Wiki 链接** —— content 里用 `[[<commit-hash>]]` 引用其他条目;`mem_read` 传 `expand: true` 一跳展开链接目标,并自动跟随 `GitMemo-Replaces` 链到被替换条目的最新版本(悬空链接带 error 返回)
|
|
18
21
|
- **结构化搜索** —— commit message 携带 `GitMemo-*` trailers(keywords、digest、search-text 投影);搜索只对 commit message 执行 `git log --grep --fixed-strings`,绝不扫描条目正文
|
|
19
22
|
- **可审计** —— 每次记忆操作都是 `.mem` Git 历史中的一次提交;被替换/删除的条目仍可按哈希读取
|
|
20
23
|
- **崩溃安全** —— write/delete/replace 在修改条目前先写事务 journal;迁移另用 sibling swap journal,目录交换中断后会在自动初始化前恢复
|
|
@@ -24,11 +27,11 @@
|
|
|
24
27
|
|
|
25
28
|
| 内容 | 说明 |
|
|
26
29
|
| --- | --- |
|
|
27
|
-
| `mem_search` | 搜索记忆:`keywords`(1–12 个关键词数组,建议中英文同义词)、`skip` + `snapshot`(稳定分页)。每次最多返回 20 条带 `summary` / `keywords` / `matched_keywords`
|
|
28
|
-
| `mem_read` | 按创建/替换提交哈希读取一条记忆的完整 markdown
|
|
29
|
-
| `mem_write` | 存储任务结论:`title` + `summary` + `keywords`(2–12)+ `content`(front matter 由引擎生成),可选 `related_branches` / `related_paths`。每个不可变文件对应一个 ADD 提交 |
|
|
30
|
+
| `mem_search` | 搜索记忆:`keywords`(1–12 个关键词数组,建议中英文同义词)、`skip` + `snapshot`(稳定分页)。每次最多返回 20 条带 `summary` / `keywords` / `kind` / `matched_keywords` 的评分结果(score = 命中关键词数 + recency 加成) |
|
|
31
|
+
| `mem_read` | 按创建/替换提交哈希读取一条记忆的完整 markdown(历史哈希仍可读);返回 `kind`;可选 `expand: true` 一跳展开条目内的 `[[hash]]` 链接 |
|
|
32
|
+
| `mem_write` | 存储任务结论:`title` + `summary` + `keywords`(2–12)+ `content`(front matter 由引擎生成),可选 `kind`(`"task"` 缺省 / `"topic"` 聚合页)、`related_branches` / `related_paths`。每个不可变文件对应一个 ADD 提交 |
|
|
30
33
|
| `mem_delete` | 作废无替代结论(需要 `commit_hash` + `reason`) |
|
|
31
|
-
| `mem_replace` | 一个原子提交内更正旧结论(D 旧文件 + A 新文件)——
|
|
34
|
+
| `mem_replace` | 一个原子提交内更正旧结论(D 旧文件 + A 新文件)—— 禁止先删后写。触发面不只是用户更正:本次工作覆盖旧结论时同样应主动 replace;`kind` 缺省继承被替换条目 |
|
|
32
35
|
| 作用域规则 | 工作流规则与五个工具只在 `agent/created` 时注册进**根 Agent**(`delegationDepth === 0`);子代理两者皆无 |
|
|
33
36
|
|
|
34
37
|
## 安装
|
|
@@ -60,8 +63,71 @@ bundle patch 自带合理默认值,可在 profile 的 `cordis.patch.yml` 中
|
|
|
60
63
|
searchLimit: 20 # 每次 mem_search 返回的最大条数(每页大小)
|
|
61
64
|
lockTimeoutMs: 30000 # 跨进程锁等待超时
|
|
62
65
|
projectRoot: null # 可选:显式项目根目录(默认取会话工作目录)
|
|
66
|
+
systemOne: # 可选:System-one 召回门控,见下节
|
|
67
|
+
enabled: true
|
|
68
|
+
endpoint: https://api.typesafe.ai/v1/systemone
|
|
69
|
+
model: jev-latest
|
|
70
|
+
mode: noul # noul | score
|
|
71
|
+
threshold: 0.5 # noul 模式:概率 ≥ 该值才保留
|
|
63
72
|
```
|
|
64
73
|
|
|
74
|
+
## System-one 召回门控(可选)
|
|
75
|
+
|
|
76
|
+
`mem_search` 的候选页可以交给一个 **System-one 模型**(默认 [TypeSafe Jev](https://docs.typesafe.ai))
|
|
77
|
+
做一次快速判断,把与当前任务**完全无关**的记忆从注入内容里剔除,只留下真正可复用的条目。
|
|
78
|
+
|
|
79
|
+
- **默认不生效。** 只有配置了可用凭据(`apiKey` / `apiKeyEnv` 指向的凭据 / 环境变量)时门控才会运行;
|
|
80
|
+
没配就完全走原有召回路径,行为与开启前**逐字节一致**。
|
|
81
|
+
- **失败即放行(fail-open)。** 端点超时、HTTP 非 2xx、响应无法解析……任何异常都会保留全部候选,
|
|
82
|
+
并在 `gated.degraded` + `gated.reason` 里说明原因。**坏掉的端点绝不会让记忆消失。**
|
|
83
|
+
- **绝不返回空页。** 若模型把整页都判为无关,至少保留 `minKeep`(默认 1)条最相关候选,避免
|
|
84
|
+
「过滤掉了」和「本来就没有」变得无法区分。这种情况会在 `gated` 文本行里明说:该行带
|
|
85
|
+
`NOTE(no candidate scored above the threshold…)` 标记,兜底保留下来的条目不会被误读成
|
|
86
|
+
「真有候选通过了」。`judged=` 只计实际送判的条数,超出 `maxCandidates` 的部分以
|
|
87
|
+
`untouched=` 标出(未送判的候选永不剔除)。
|
|
88
|
+
- **可回收。** `gated.dropped_hashes` 给出被剔除条目的 8 位短哈希,Agent 或用户可随时
|
|
89
|
+
`mem_read <短哈希>` 把误删的记忆读回来。
|
|
90
|
+
- **可审计。** 每条候选的概率/分数与 keep/drop 判定写入插件日志(不占用模型上下文);端点返回的
|
|
91
|
+
`usage.input_tokens` 记在 `gated.input_tokens` 里,门控自身的开销可被直接测量。
|
|
92
|
+
|
|
93
|
+
### 配置字段
|
|
94
|
+
|
|
95
|
+
| 字段 | 默认值 | 说明 |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| `enabled` | `true` | 总开关;无凭据时仍是无操作 |
|
|
98
|
+
| `endpoint` | `https://api.typesafe.ai/v1/systemone` | 任何兼容该请求/应答契约的端点(含自建、LiteLLM 透传等) |
|
|
99
|
+
| `model` | `jev-latest` | 请求体里的模型标识 |
|
|
100
|
+
| `apiKey` | — | 声明为 `role("secret")`:读取时被脱敏、表单里只写不回显 |
|
|
101
|
+
| `apiKeyEnv` | `TYPESAFE_API_KEY` | 凭据引用名;按「字面 key → 凭据服务 → 环境变量」顺序解析 |
|
|
102
|
+
| `mode` | `noul` | `noul`(是与否概率)或 `score`(分级打分) |
|
|
103
|
+
| `threshold` | `0.5` | `noul` 模式:概率 ≥ 该值保留 |
|
|
104
|
+
| `scoreMin` | `2` | `score` 模式阈值。注意 Jev 的 `score` 是 `Σ(层级序号 × 概率)`,范围是 0…层级数−1(默认 5 层 → 0…4),**不是 0–1** |
|
|
105
|
+
| `minKeep` | `1` | 整页被拒时至少保留几条 |
|
|
106
|
+
| `maxCandidates` | `20` | 单次请求最多判定多少条;超出部分**不判定、不剔除** |
|
|
107
|
+
| `maxTaskChars` | `2000` | 任务文本截断长度 |
|
|
108
|
+
| `timeoutMs` | `8000` | 请求超时 |
|
|
109
|
+
|
|
110
|
+
以上字段全部标记为 `.volatile()`——这是 DSH 设置平面**能够看到并即时生效**的前提条件。
|
|
111
|
+
|
|
112
|
+
### 设置页
|
|
113
|
+
|
|
114
|
+
插件自带一个设置卡片(**设置 → GitMemo**),可直接开关召回闸门,并填写端点、模型与 API key,
|
|
115
|
+
改动即时生效、无需重启。API key 通过凭据域写入,**不会作为明文配置项落盘**,表单也只写不回显。
|
|
116
|
+
开关暂存的是 `systemOne.enabled`:关闭后召回行为与门控存在前逐字节一致;需要点**保存**才会写入
|
|
117
|
+
(只拨开关是草稿)。未配置 `enabled` 时按开启处理,与该字段的宿主默认值一致。
|
|
118
|
+
|
|
119
|
+
### 已知取舍
|
|
120
|
+
|
|
121
|
+
- **英文优先。** Jev 的主要训练语言是英文,CJK 文本可用但官方标注准确率较低。门控的提问措辞固定为
|
|
122
|
+
英文,只有候选正文与任务文本可能是中文。
|
|
123
|
+
- **上下文上限。** 单次请求 64k tokens,其中 `state` + 最长问题合计 32k。`maxCandidates` 与
|
|
124
|
+
`maxTaskChars` 就是为守住这条线而存在的。
|
|
125
|
+
- **延迟在关键路径上。** 召回发生在每次仓库任务之前,门控会给 `mem_search` 增加一次网络往返
|
|
126
|
+
(实测约 0.4s 量级),因此 `timeoutMs` 默认 8s 且失败即放行。
|
|
127
|
+
- **数据外发。** 记忆摘要会离开本机。TypeSafe 目前**不提供** zero data retention;若要避免外发,
|
|
128
|
+
可把 `endpoint` 指向自建实现(如 MIT 许可的 `jeff`)或本地端点。
|
|
129
|
+
- **计费口径。** 按输入 token 计费($0.042 / 百万输入 token,输出免费),不是按次计费。
|
|
130
|
+
|
|
65
131
|
## 记忆存放位置与格式
|
|
66
132
|
|
|
67
133
|
`.mem` 仓库位于调用会话工作区的**项目根目录**(`git rev-parse --show-toplevel`,找不到时退回
|
|
@@ -78,7 +144,8 @@ bundle patch 自带合理默认值,可在 profile 的 `cordis.patch.yml` 中
|
|
|
78
144
|
- `.mem` 初始化在自己的 `main` 分支上;初始化时把 `.mem/` 与锁文件路径写入父仓库的
|
|
79
145
|
`.git/info/exclude`(绝不写入受版本控制的 `.gitignore`),且当父仓库已跟踪 `.mem` 内容时拒绝初始化。
|
|
80
146
|
- 每次写入都用独占创建生成全新文件(绝不覆盖),以带结构化 trailers 的 ADD 提交落库,并把代码
|
|
81
|
-
分支/SHA/相关路径记录在条目 front matter 中。
|
|
147
|
+
分支/SHA/相关路径记录在条目 front matter 中。front matter 固定携带 `kind`(`"task"` 或 `"topic"`);
|
|
148
|
+
topic 条目的 commit message 额外带 `GitMemo-Kind: topic` trailer。
|
|
82
149
|
|
|
83
150
|
整个记忆可以用普通 `git` 命令查看:
|
|
84
151
|
|
|
@@ -91,13 +158,14 @@ git -C .mem show <commit-hash>
|
|
|
91
158
|
|
|
92
159
|
1. **开工前 —— 搜索。** 仓库相关任务开始前提取 1–12 个中英文关键词 → `mem_search`。纯闲聊和通用问答无需搜索。
|
|
93
160
|
2. **结果预筛。** 根据 `title` / `summary` / `keywords` / `score` / `matched_keywords` 最多
|
|
94
|
-
`mem_read` 5
|
|
161
|
+
`mem_read` 5 条最相关记忆(`kind: "topic"` 的条目是该主题的聚合入口,优先读);用 `skip` + 返回的
|
|
162
|
+
`snapshot` 翻页。
|
|
95
163
|
3. **会话结束检查点 —— 唯一的写入路径。** 对话即将结束时,`mem_write` **每一条**已完成、与仓库
|
|
96
164
|
相关、且结论**有价值/可复用**(或用户明确要求记住)但还没有记忆的任务。绝不重复写已存在的条目。
|
|
97
165
|
纯问答、未完成任务、与仓库无关的工作、纯操作性的 git 动作一律不写。`keywords` 应选用与任务相关但未出现在 `title` / `summary` 中的词(中英文同义词皆可)——`title` / `summary` 已有的词本身就能被检索到,重复它们不会提高召回率。
|
|
98
|
-
4.
|
|
99
|
-
|
|
100
|
-
|
|
166
|
+
4. **知识保鲜(KEEP FRESH)。** 用户更正旧结论:有替代用 `mem_replace`(禁止先 delete 再 write),作废无替代用带 `reason` 的 `mem_delete`;本次会话的工作覆盖/推翻某条已存结论时同样主动处理,不必等用户指出。检索结果中新旧冲突时优先采信更新的条目(score 已含 recency 加成)。
|
|
167
|
+
5. **主题聚合页(TOPIC PAGE)。** 同一主题积累多条记忆、或需要「当前真相」入口时,写一条 `kind: "topic"` 聚合条目:summary 概括当下有效结论,content 用 `[[<commit-hash>]]` 链接证据条目并各配一句话状态;topic 条目靠 `mem_replace` 演进。
|
|
168
|
+
6. **子代理结果。** 是否形成一条会话级记忆,由根 Agent 汇总后决定。
|
|
101
169
|
|
|
102
170
|
## 开发
|
|
103
171
|
|