codemini-cli 0.5.10 → 0.5.11
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/OPERATIONS.md +242 -242
- package/README.md +588 -588
- package/codemini-web/dist/assets/{highlighted-body-OFNGDK62-7HL7yft8.js → highlighted-body-OFNGDK62-CANOG7Xg.js} +1 -1
- package/codemini-web/dist/assets/{index-BK75hMb2.js → index-B71xykPM.js} +108 -108
- package/codemini-web/dist/assets/index-Dkq1DdDX.css +2 -0
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-Z_w7M93P.js +1 -0
- package/codemini-web/dist/index.html +23 -23
- package/codemini-web/lib/approval-manager.js +32 -32
- package/codemini-web/lib/runtime-bridge.js +17 -11
- package/codemini-web/server.js +534 -205
- package/deployment.md +212 -212
- package/package.json +1 -1
- package/skills/brainstorm/SKILL.md +77 -77
- package/skills/codemini.skills.json +40 -40
- package/skills/grill-me/SKILL.md +30 -30
- package/skills/superpowers-lite/SKILL.md +82 -82
- package/src/cli.js +74 -74
- package/src/commands/chat.js +210 -210
- package/src/commands/run.js +313 -313
- package/src/commands/skill.js +438 -304
- package/src/commands/web.js +57 -57
- package/src/core/agent-loop.js +980 -980
- package/src/core/ast.js +309 -307
- package/src/core/chat-runtime.js +6261 -6253
- package/src/core/command-evaluator.js +72 -72
- package/src/core/command-loader.js +311 -311
- package/src/core/command-policy.js +301 -301
- package/src/core/command-risk.js +156 -156
- package/src/core/config-store.js +289 -289
- package/src/core/constants.js +18 -1
- package/src/core/context-compact.js +365 -365
- package/src/core/default-system-prompt.js +114 -107
- package/src/core/dream-audit.js +105 -105
- package/src/core/dream-consolidate.js +229 -229
- package/src/core/dream-evaluator.js +185 -185
- package/src/core/fff-adapter.js +383 -383
- package/src/core/memory-store.js +543 -543
- package/src/core/project-index.js +737 -548
- package/src/core/project-instructions.js +98 -98
- package/src/core/provider/anthropic.js +514 -514
- package/src/core/provider/openai-compatible.js +501 -501
- package/src/core/reflect-skill.js +178 -178
- package/src/core/reply-language.js +40 -40
- package/src/core/session-store.js +474 -474
- package/src/core/shell-profile.js +237 -237
- package/src/core/shell.js +323 -323
- package/src/core/soul.js +69 -69
- package/src/core/system-prompt-composer.js +52 -52
- package/src/core/tool-args.js +199 -154
- package/src/core/tool-output.js +184 -184
- package/src/core/tool-result-store.js +206 -206
- package/src/core/tools.js +3024 -2893
- package/src/core/version.js +11 -11
- package/src/tui/chat-app.js +5171 -5171
- package/src/tui/tool-activity/presenters/misc.js +30 -30
- package/src/tui/tool-activity/presenters/system.js +20 -20
- package/templates/project-requirements/report-shell.html +582 -582
- package/codemini-web/dist/assets/index-BSdIdn3L.css +0 -2
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-Dg9qh8mg.js +0 -1
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
import { createChatCompletion } from './provider/index.js';
|
|
2
|
-
|
|
3
|
-
const EVAL_TIMEOUT_MS = 30000;
|
|
4
|
-
|
|
5
|
-
const SYSTEM_PROMPT = `You are a memory consolidation evaluator for a coding assistant. You receive a batch of inbox items (tool errors, observations, etc.) and decide for each one:
|
|
6
|
-
|
|
7
|
-
1. **keep or discard** — Does this contain a reusable, durable insight? Discard transient errors, one-off issues, and noise.
|
|
8
|
-
2. **scope** — "global" for cross-project knowledge (e.g., "WSL bash exec does not support cd"), "project" for project-specific context (e.g., "this project uses vitest for testing").
|
|
9
|
-
3. **kind** — One of: pattern, observation, correction, decision, failure
|
|
10
|
-
4. **content** — A refined, actionable sentence describing the insight. NOT the raw error text.
|
|
11
|
-
5. **summary** — A short label (under 80 chars) for quick scanning.
|
|
12
|
-
6. **confidence** — 0.5–1.0 based on how certain and durable the insight is.
|
|
13
|
-
|
|
14
|
-
Respond with valid JSON only, no markdown fences:
|
|
15
|
-
{"results":[{"id":"<inbox-id>","action":"keep","scope":"global|project","kind":"pattern|observation|correction|decision|failure","content":"...","summary":"...","confidence":0.8},{"id":"<inbox-id>","action":"discard","reason":"..."}]}
|
|
16
|
-
|
|
17
|
-
Rules:
|
|
18
|
-
- Raw tool error messages are NOT insights by themselves. Only keep if they reveal a reusable lesson.
|
|
19
|
-
- "exit 127", "command not found", "permission denied", "blocked by policy" → always discard (transient/config issues)
|
|
20
|
-
- A repeated pattern across multiple errors → keep as a "pattern" or "correction"
|
|
21
|
-
- Project-specific paths, file names, or commands → scope "project"
|
|
22
|
-
- General coding/environment knowledge → scope "global"
|
|
23
|
-
- If in doubt, discard. Memory is expensive; only promote what future sessions will genuinely benefit from.`;
|
|
24
|
-
|
|
25
|
-
const MAINTENANCE_SYSTEM_PROMPT = `You are maintaining an existing persistent memory bucket for a coding assistant.
|
|
26
|
-
|
|
27
|
-
Your job:
|
|
28
|
-
1. Merge duplicates and near-duplicates.
|
|
29
|
-
2. Summarize clusters into fewer, higher-signal memories.
|
|
30
|
-
3. Remove stale, contradictory, trivial, or overly specific noise.
|
|
31
|
-
4. Preserve important exact commands, file paths, preferences, and constraints.
|
|
32
|
-
5. Keep memories scoped exactly to the bucket you receive.
|
|
33
|
-
|
|
34
|
-
Respond with valid JSON only, no markdown fences:
|
|
35
|
-
{"items":[{"kind":"preference|workflow|pattern|observation|correction|decision|failure|architecture|module|note","content":"durable memory text","summary":"under 80 chars","confidence":0.5,"pinned":false,"lifecycle":"longterm|operational"}],"archives":[{"source_ids":["mem_..."],"reason":"merged|stale|duplicate|noise|contradiction"}]}
|
|
36
|
-
|
|
37
|
-
Rules:
|
|
38
|
-
- Prefer fewer, clearer items, but do not collapse unrelated facts.
|
|
39
|
-
- User preferences belong in user memory and should not become project rules.
|
|
40
|
-
- Project conventions belong in project memory and should not become user preferences.
|
|
41
|
-
- Global memory is only for reusable cross-project/tool/environment knowledge.
|
|
42
|
-
- If a pinned item is still valid, keep it.
|
|
43
|
-
- Return at least one item if the input has useful durable content.`;
|
|
44
|
-
|
|
45
|
-
function parseResults(text) {
|
|
46
|
-
try {
|
|
47
|
-
const json = JSON.parse(text);
|
|
48
|
-
if (!json?.results || !Array.isArray(json.results)) return [];
|
|
49
|
-
return json.results.map((r) => ({
|
|
50
|
-
id: String(r.id || ''),
|
|
51
|
-
action: r.action === 'keep' ? 'keep' : 'discard',
|
|
52
|
-
scope: r.scope === 'project' ? 'project' : 'global',
|
|
53
|
-
kind: ['pattern', 'observation', 'correction', 'decision', 'failure'].includes(r.kind) ? r.kind : 'observation',
|
|
54
|
-
content: String(r.content || '').slice(0, 300),
|
|
55
|
-
summary: String(r.summary || '').slice(0, 120),
|
|
56
|
-
confidence: Math.min(1, Math.max(0.5, Number(r.confidence) || 0.7)),
|
|
57
|
-
reason: String(r.reason || '')
|
|
58
|
-
}));
|
|
59
|
-
} catch {
|
|
60
|
-
return [];
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* 用 LLM 批量评估 inbox 条目,决定保留/丢弃、scope、内容提炼。
|
|
66
|
-
* @param {{ entries: Array, config: object, workspaceRoot?: string }} params
|
|
67
|
-
* @returns {Promise<Array<{ id, action, scope?, kind?, content?, summary?, confidence?, reason? }>>}
|
|
68
|
-
*/
|
|
69
|
-
export async function evaluateInboxBatch({ entries, config, workspaceRoot }) {
|
|
70
|
-
if (!entries || entries.length === 0) return [];
|
|
71
|
-
|
|
72
|
-
const batch = entries.map((e) => ({
|
|
73
|
-
id: e.id,
|
|
74
|
-
type: e.type || '',
|
|
75
|
-
source: e.source || '',
|
|
76
|
-
summary: (e.summary || '').slice(0, 150),
|
|
77
|
-
details: (e.details || '').slice(0, 400)
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
const result = await createChatCompletion({
|
|
82
|
-
sdkProvider: config?.sdk?.provider,
|
|
83
|
-
baseUrl: config?.gateway?.base_url,
|
|
84
|
-
apiKey: config?.gateway?.api_key,
|
|
85
|
-
model: config?.model?.name,
|
|
86
|
-
messages: [
|
|
87
|
-
{ role: 'system', content: SYSTEM_PROMPT },
|
|
88
|
-
{
|
|
89
|
-
role: 'user',
|
|
90
|
-
content: `Evaluate these ${batch.length} inbox items. Workspace: ${workspaceRoot || process.cwd()}\n\n${JSON.stringify(batch, null, 2)}`
|
|
91
|
-
}
|
|
92
|
-
],
|
|
93
|
-
temperature: 0,
|
|
94
|
-
timeoutMs: EVAL_TIMEOUT_MS
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const text = result?.text || '';
|
|
98
|
-
const parsed = parseResults(text);
|
|
99
|
-
/* 确保每个 entry 都有结果,LLM 没返回的一律 discard */
|
|
100
|
-
const covered = new Set(parsed.map((r) => r.id));
|
|
101
|
-
for (const entry of entries) {
|
|
102
|
-
if (!covered.has(entry.id)) {
|
|
103
|
-
parsed.push({
|
|
104
|
-
id: entry.id,
|
|
105
|
-
action: 'discard',
|
|
106
|
-
reason: 'LLM did not return a result for this entry'
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return parsed;
|
|
111
|
-
} catch {
|
|
112
|
-
/* LLM 调用失败 → 全部 discard(fail-safe) */
|
|
113
|
-
return entries.map((e) => ({
|
|
114
|
-
id: e.id,
|
|
115
|
-
action: 'discard',
|
|
116
|
-
reason: 'LLM evaluation failed'
|
|
117
|
-
}));
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function parseMaintenanceResult(text) {
|
|
122
|
-
try {
|
|
123
|
-
const json = JSON.parse(text);
|
|
124
|
-
const items = Array.isArray(json?.items) ? json.items : [];
|
|
125
|
-
const archives = Array.isArray(json?.archives) ? json.archives : [];
|
|
126
|
-
return {
|
|
127
|
-
items: items
|
|
128
|
-
.map((item) => ({
|
|
129
|
-
kind: String(item.kind || 'note').slice(0, 40),
|
|
130
|
-
content: String(item.content || '').slice(0, 600),
|
|
131
|
-
summary: String(item.summary || item.content || '').slice(0, 120),
|
|
132
|
-
confidence: Math.min(1, Math.max(0.5, Number(item.confidence) || 0.8)),
|
|
133
|
-
pinned: item.pinned === true,
|
|
134
|
-
lifecycle: ['longterm', 'operational'].includes(String(item.lifecycle || '')) ? String(item.lifecycle) : undefined
|
|
135
|
-
}))
|
|
136
|
-
.filter((item) => item.content.trim()),
|
|
137
|
-
archives: archives.map((archive) => ({
|
|
138
|
-
source_ids: Array.isArray(archive.source_ids) ? archive.source_ids.map((id) => String(id)).filter(Boolean) : [],
|
|
139
|
-
reason: String(archive.reason || '').slice(0, 160)
|
|
140
|
-
}))
|
|
141
|
-
};
|
|
142
|
-
} catch {
|
|
143
|
-
return { items: [], archives: [] };
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export async function evaluateMemoryMaintenance({ scope, items, config, workspaceRoot }) {
|
|
148
|
-
const sourceItems = Array.isArray(items) ? items : [];
|
|
149
|
-
if (sourceItems.length === 0) return { items: [], archives: [] };
|
|
150
|
-
|
|
151
|
-
const compactItems = sourceItems.map((item) => ({
|
|
152
|
-
id: item.id,
|
|
153
|
-
kind: item.kind,
|
|
154
|
-
content: String(item.content || '').slice(0, 600),
|
|
155
|
-
summary: String(item.summary || '').slice(0, 160),
|
|
156
|
-
confidence: item.confidence,
|
|
157
|
-
pinned: item.pinned === true,
|
|
158
|
-
lifecycle: item.lifecycle || ''
|
|
159
|
-
}));
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const result = await createChatCompletion({
|
|
163
|
-
sdkProvider: config?.sdk?.provider,
|
|
164
|
-
baseUrl: config?.gateway?.base_url,
|
|
165
|
-
apiKey: config?.gateway?.api_key,
|
|
166
|
-
model: config?.model?.name,
|
|
167
|
-
messages: [
|
|
168
|
-
{ role: 'system', content: MAINTENANCE_SYSTEM_PROMPT },
|
|
169
|
-
{
|
|
170
|
-
role: 'user',
|
|
171
|
-
content: `Maintain this ${scope} memory bucket. Workspace: ${workspaceRoot || process.cwd()}\n\n${JSON.stringify(compactItems, null, 2)}`
|
|
172
|
-
}
|
|
173
|
-
],
|
|
174
|
-
temperature: 0,
|
|
175
|
-
timeoutMs: EVAL_TIMEOUT_MS
|
|
176
|
-
});
|
|
177
|
-
return parseMaintenanceResult(result?.text || '');
|
|
178
|
-
} catch (error) {
|
|
179
|
-
return {
|
|
180
|
-
items: sourceItems,
|
|
181
|
-
archives: [],
|
|
182
|
-
error: String(error?.message || error || 'memory maintenance failed')
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
}
|
|
1
|
+
import { createChatCompletion } from './provider/index.js';
|
|
2
|
+
|
|
3
|
+
const EVAL_TIMEOUT_MS = 30000;
|
|
4
|
+
|
|
5
|
+
const SYSTEM_PROMPT = `You are a memory consolidation evaluator for a coding assistant. You receive a batch of inbox items (tool errors, observations, etc.) and decide for each one:
|
|
6
|
+
|
|
7
|
+
1. **keep or discard** — Does this contain a reusable, durable insight? Discard transient errors, one-off issues, and noise.
|
|
8
|
+
2. **scope** — "global" for cross-project knowledge (e.g., "WSL bash exec does not support cd"), "project" for project-specific context (e.g., "this project uses vitest for testing").
|
|
9
|
+
3. **kind** — One of: pattern, observation, correction, decision, failure
|
|
10
|
+
4. **content** — A refined, actionable sentence describing the insight. NOT the raw error text.
|
|
11
|
+
5. **summary** — A short label (under 80 chars) for quick scanning.
|
|
12
|
+
6. **confidence** — 0.5–1.0 based on how certain and durable the insight is.
|
|
13
|
+
|
|
14
|
+
Respond with valid JSON only, no markdown fences:
|
|
15
|
+
{"results":[{"id":"<inbox-id>","action":"keep","scope":"global|project","kind":"pattern|observation|correction|decision|failure","content":"...","summary":"...","confidence":0.8},{"id":"<inbox-id>","action":"discard","reason":"..."}]}
|
|
16
|
+
|
|
17
|
+
Rules:
|
|
18
|
+
- Raw tool error messages are NOT insights by themselves. Only keep if they reveal a reusable lesson.
|
|
19
|
+
- "exit 127", "command not found", "permission denied", "blocked by policy" → always discard (transient/config issues)
|
|
20
|
+
- A repeated pattern across multiple errors → keep as a "pattern" or "correction"
|
|
21
|
+
- Project-specific paths, file names, or commands → scope "project"
|
|
22
|
+
- General coding/environment knowledge → scope "global"
|
|
23
|
+
- If in doubt, discard. Memory is expensive; only promote what future sessions will genuinely benefit from.`;
|
|
24
|
+
|
|
25
|
+
const MAINTENANCE_SYSTEM_PROMPT = `You are maintaining an existing persistent memory bucket for a coding assistant.
|
|
26
|
+
|
|
27
|
+
Your job:
|
|
28
|
+
1. Merge duplicates and near-duplicates.
|
|
29
|
+
2. Summarize clusters into fewer, higher-signal memories.
|
|
30
|
+
3. Remove stale, contradictory, trivial, or overly specific noise.
|
|
31
|
+
4. Preserve important exact commands, file paths, preferences, and constraints.
|
|
32
|
+
5. Keep memories scoped exactly to the bucket you receive.
|
|
33
|
+
|
|
34
|
+
Respond with valid JSON only, no markdown fences:
|
|
35
|
+
{"items":[{"kind":"preference|workflow|pattern|observation|correction|decision|failure|architecture|module|note","content":"durable memory text","summary":"under 80 chars","confidence":0.5,"pinned":false,"lifecycle":"longterm|operational"}],"archives":[{"source_ids":["mem_..."],"reason":"merged|stale|duplicate|noise|contradiction"}]}
|
|
36
|
+
|
|
37
|
+
Rules:
|
|
38
|
+
- Prefer fewer, clearer items, but do not collapse unrelated facts.
|
|
39
|
+
- User preferences belong in user memory and should not become project rules.
|
|
40
|
+
- Project conventions belong in project memory and should not become user preferences.
|
|
41
|
+
- Global memory is only for reusable cross-project/tool/environment knowledge.
|
|
42
|
+
- If a pinned item is still valid, keep it.
|
|
43
|
+
- Return at least one item if the input has useful durable content.`;
|
|
44
|
+
|
|
45
|
+
function parseResults(text) {
|
|
46
|
+
try {
|
|
47
|
+
const json = JSON.parse(text);
|
|
48
|
+
if (!json?.results || !Array.isArray(json.results)) return [];
|
|
49
|
+
return json.results.map((r) => ({
|
|
50
|
+
id: String(r.id || ''),
|
|
51
|
+
action: r.action === 'keep' ? 'keep' : 'discard',
|
|
52
|
+
scope: r.scope === 'project' ? 'project' : 'global',
|
|
53
|
+
kind: ['pattern', 'observation', 'correction', 'decision', 'failure'].includes(r.kind) ? r.kind : 'observation',
|
|
54
|
+
content: String(r.content || '').slice(0, 300),
|
|
55
|
+
summary: String(r.summary || '').slice(0, 120),
|
|
56
|
+
confidence: Math.min(1, Math.max(0.5, Number(r.confidence) || 0.7)),
|
|
57
|
+
reason: String(r.reason || '')
|
|
58
|
+
}));
|
|
59
|
+
} catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 用 LLM 批量评估 inbox 条目,决定保留/丢弃、scope、内容提炼。
|
|
66
|
+
* @param {{ entries: Array, config: object, workspaceRoot?: string }} params
|
|
67
|
+
* @returns {Promise<Array<{ id, action, scope?, kind?, content?, summary?, confidence?, reason? }>>}
|
|
68
|
+
*/
|
|
69
|
+
export async function evaluateInboxBatch({ entries, config, workspaceRoot }) {
|
|
70
|
+
if (!entries || entries.length === 0) return [];
|
|
71
|
+
|
|
72
|
+
const batch = entries.map((e) => ({
|
|
73
|
+
id: e.id,
|
|
74
|
+
type: e.type || '',
|
|
75
|
+
source: e.source || '',
|
|
76
|
+
summary: (e.summary || '').slice(0, 150),
|
|
77
|
+
details: (e.details || '').slice(0, 400)
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const result = await createChatCompletion({
|
|
82
|
+
sdkProvider: config?.sdk?.provider,
|
|
83
|
+
baseUrl: config?.gateway?.base_url,
|
|
84
|
+
apiKey: config?.gateway?.api_key,
|
|
85
|
+
model: config?.model?.name,
|
|
86
|
+
messages: [
|
|
87
|
+
{ role: 'system', content: SYSTEM_PROMPT },
|
|
88
|
+
{
|
|
89
|
+
role: 'user',
|
|
90
|
+
content: `Evaluate these ${batch.length} inbox items. Workspace: ${workspaceRoot || process.cwd()}\n\n${JSON.stringify(batch, null, 2)}`
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
temperature: 0,
|
|
94
|
+
timeoutMs: EVAL_TIMEOUT_MS
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const text = result?.text || '';
|
|
98
|
+
const parsed = parseResults(text);
|
|
99
|
+
/* 确保每个 entry 都有结果,LLM 没返回的一律 discard */
|
|
100
|
+
const covered = new Set(parsed.map((r) => r.id));
|
|
101
|
+
for (const entry of entries) {
|
|
102
|
+
if (!covered.has(entry.id)) {
|
|
103
|
+
parsed.push({
|
|
104
|
+
id: entry.id,
|
|
105
|
+
action: 'discard',
|
|
106
|
+
reason: 'LLM did not return a result for this entry'
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return parsed;
|
|
111
|
+
} catch {
|
|
112
|
+
/* LLM 调用失败 → 全部 discard(fail-safe) */
|
|
113
|
+
return entries.map((e) => ({
|
|
114
|
+
id: e.id,
|
|
115
|
+
action: 'discard',
|
|
116
|
+
reason: 'LLM evaluation failed'
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function parseMaintenanceResult(text) {
|
|
122
|
+
try {
|
|
123
|
+
const json = JSON.parse(text);
|
|
124
|
+
const items = Array.isArray(json?.items) ? json.items : [];
|
|
125
|
+
const archives = Array.isArray(json?.archives) ? json.archives : [];
|
|
126
|
+
return {
|
|
127
|
+
items: items
|
|
128
|
+
.map((item) => ({
|
|
129
|
+
kind: String(item.kind || 'note').slice(0, 40),
|
|
130
|
+
content: String(item.content || '').slice(0, 600),
|
|
131
|
+
summary: String(item.summary || item.content || '').slice(0, 120),
|
|
132
|
+
confidence: Math.min(1, Math.max(0.5, Number(item.confidence) || 0.8)),
|
|
133
|
+
pinned: item.pinned === true,
|
|
134
|
+
lifecycle: ['longterm', 'operational'].includes(String(item.lifecycle || '')) ? String(item.lifecycle) : undefined
|
|
135
|
+
}))
|
|
136
|
+
.filter((item) => item.content.trim()),
|
|
137
|
+
archives: archives.map((archive) => ({
|
|
138
|
+
source_ids: Array.isArray(archive.source_ids) ? archive.source_ids.map((id) => String(id)).filter(Boolean) : [],
|
|
139
|
+
reason: String(archive.reason || '').slice(0, 160)
|
|
140
|
+
}))
|
|
141
|
+
};
|
|
142
|
+
} catch {
|
|
143
|
+
return { items: [], archives: [] };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function evaluateMemoryMaintenance({ scope, items, config, workspaceRoot }) {
|
|
148
|
+
const sourceItems = Array.isArray(items) ? items : [];
|
|
149
|
+
if (sourceItems.length === 0) return { items: [], archives: [] };
|
|
150
|
+
|
|
151
|
+
const compactItems = sourceItems.map((item) => ({
|
|
152
|
+
id: item.id,
|
|
153
|
+
kind: item.kind,
|
|
154
|
+
content: String(item.content || '').slice(0, 600),
|
|
155
|
+
summary: String(item.summary || '').slice(0, 160),
|
|
156
|
+
confidence: item.confidence,
|
|
157
|
+
pinned: item.pinned === true,
|
|
158
|
+
lifecycle: item.lifecycle || ''
|
|
159
|
+
}));
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const result = await createChatCompletion({
|
|
163
|
+
sdkProvider: config?.sdk?.provider,
|
|
164
|
+
baseUrl: config?.gateway?.base_url,
|
|
165
|
+
apiKey: config?.gateway?.api_key,
|
|
166
|
+
model: config?.model?.name,
|
|
167
|
+
messages: [
|
|
168
|
+
{ role: 'system', content: MAINTENANCE_SYSTEM_PROMPT },
|
|
169
|
+
{
|
|
170
|
+
role: 'user',
|
|
171
|
+
content: `Maintain this ${scope} memory bucket. Workspace: ${workspaceRoot || process.cwd()}\n\n${JSON.stringify(compactItems, null, 2)}`
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
temperature: 0,
|
|
175
|
+
timeoutMs: EVAL_TIMEOUT_MS
|
|
176
|
+
});
|
|
177
|
+
return parseMaintenanceResult(result?.text || '');
|
|
178
|
+
} catch (error) {
|
|
179
|
+
return {
|
|
180
|
+
items: sourceItems,
|
|
181
|
+
archives: [],
|
|
182
|
+
error: String(error?.message || error || 'memory maintenance failed')
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|