memorix 1.1.7 → 1.1.8
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/CHANGELOG.md +13 -0
- package/CLAUDE.md +6 -1
- package/README.md +21 -0
- package/README.zh-CN.md +21 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +730 -150
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/index.html +201 -201
- package/dist/dashboard/static/style.css +3584 -3584
- package/dist/index.js +15 -8
- package/dist/index.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +13 -0
- package/dist/memcode-runtime/package.json +4 -4
- package/dist/sdk.js +15 -8
- package/dist/sdk.js.map +1 -1
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +18 -0
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/SETUP.md +10 -0
- package/docs/dev-log/progress.txt +35 -26
- package/package.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/commands/agent-integrations.ts +623 -0
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/cleanup.ts +255 -255
- package/src/cli/commands/doctor.ts +23 -0
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +66 -66
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest-commit.ts +153 -153
- package/src/cli/commands/ingest-image.ts +73 -73
- package/src/cli/commands/ingest-log.ts +180 -180
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +96 -96
- package/src/cli/commands/message.ts +121 -121
- package/src/cli/commands/poll.ts +70 -70
- package/src/cli/commands/purge-all-memory.ts +85 -85
- package/src/cli/commands/purge-project-memory.ts +83 -83
- package/src/cli/commands/reasoning.ts +132 -132
- package/src/cli/commands/repair.ts +60 -0
- package/src/cli/commands/retention.ts +108 -108
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/setup.ts +3 -3
- package/src/cli/commands/skills.ts +123 -123
- package/src/cli/commands/task.ts +192 -192
- package/src/cli/commands/transfer.ts +73 -73
- package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/Panels.tsx +632 -632
- package/src/cli/tui/Sidebar.tsx +179 -179
- package/src/cli/tui/chat-service.ts +742 -742
- package/src/cli/tui/data.ts +547 -547
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/theme.ts +178 -178
- package/src/cli/tui/use-mouse.ts +157 -157
- package/src/cli/tui/useNavigation.ts +56 -56
- package/src/cli/update-checker.ts +211 -211
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/codegraph/context-pack.ts +5 -1
- package/src/codegraph/lite-provider.ts +5 -1
- package/src/codegraph/project-context.ts +5 -1
- package/src/compact/token-budget.ts +74 -74
- package/src/config/behavior.ts +59 -59
- package/src/dashboard/project-classification.ts +64 -64
- package/src/dashboard/static/index.html +201 -201
- package/src/dashboard/static/style.css +3584 -3584
- package/src/embedding/fastembed-provider.ts +142 -142
- package/src/embedding/transformers-provider.ts +111 -111
- package/src/git/extractor.ts +209 -209
- package/src/git/hooks-path.ts +85 -85
- package/src/git/noise-filter.ts +210 -210
- package/src/hooks/installers/index.ts +4 -4
- package/src/hooks/official-skills.ts +1 -1
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/rules/memorix-agent-rules.md +2 -2
- package/src/hooks/significance-filter.ts +250 -250
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/provider.ts +885 -885
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/auto-relations.ts +107 -107
- package/src/memory/consolidation.ts +302 -302
- package/src/memory/disclosure-policy.ts +141 -141
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/formation/extract.ts +361 -361
- package/src/memory/formation/index.ts +417 -417
- package/src/memory/formation/resolve.ts +344 -344
- package/src/memory/formation/types.ts +315 -315
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/refs.ts +94 -94
- package/src/memory/retention.ts +433 -433
- package/src/memory/secret-filter.ts +79 -79
- package/src/memory/session.ts +523 -523
- package/src/multimodal/image-loader.ts +143 -143
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/spawn-helper.ts +286 -286
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/context-compact.ts +188 -188
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +380 -380
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/orchestrate/verify-gate.ts +219 -219
- package/src/orchestrate/worktree.ts +232 -232
- package/src/project/aliases.ts +374 -374
- package/src/project/detector.ts +268 -268
- package/src/rules/adapters/claude-code.ts +99 -99
- package/src/rules/adapters/codex.ts +97 -97
- package/src/rules/adapters/copilot.ts +124 -124
- package/src/rules/adapters/cursor.ts +114 -114
- package/src/rules/adapters/kiro.ts +126 -126
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/adapters/windsurf.ts +83 -83
- package/src/rules/syncer.ts +235 -235
- package/src/sdk.ts +327 -327
- package/src/search/intent-detector.ts +289 -289
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/file-lock.ts +100 -100
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/obs-store.ts +255 -255
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/store/session-store.ts +259 -259
- package/src/store/sqlite-store.ts +339 -339
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +167 -167
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- package/src/wiki/generator.ts +237 -237
- package/src/wiki/knowledge-graph.ts +334 -334
- package/src/wiki/types.ts +85 -85
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
- package/src/workspace/workflow-sync.ts +131 -131
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pipeline Tracing — Phase 6g: Structured event logging.
|
|
3
|
-
*
|
|
4
|
-
* Writes trace events to SQLite for observability and debugging.
|
|
5
|
-
* Built-in pruning retains only the last N pipelines (pays D9 debt).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type Database from 'better-sqlite3';
|
|
9
|
-
|
|
10
|
-
// ── Types ──────────────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
export type TraceEventType =
|
|
13
|
-
| 'plan' | 'materialize' | 'dispatch' | 'complete' | 'fail'
|
|
14
|
-
| 'retry' | 'timeout' | 'stale' | 'replan' | 'worktree:create'
|
|
15
|
-
| 'worktree:merge' | 'worktree:cleanup' | 'pipeline:start' | 'pipeline:end';
|
|
16
|
-
|
|
17
|
-
export interface TraceEvent {
|
|
18
|
-
pipelineId: string;
|
|
19
|
-
timestamp: number;
|
|
20
|
-
type: TraceEventType;
|
|
21
|
-
taskId?: string;
|
|
22
|
-
agent?: string;
|
|
23
|
-
detail: string;
|
|
24
|
-
durationMs?: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ── Schema ─────────────────────────────────────────────────────────
|
|
28
|
-
|
|
29
|
-
const CREATE_TABLE_SQL = `
|
|
30
|
-
CREATE TABLE IF NOT EXISTS pipeline_traces (
|
|
31
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
-
pipeline_id TEXT NOT NULL,
|
|
33
|
-
timestamp INTEGER NOT NULL,
|
|
34
|
-
type TEXT NOT NULL,
|
|
35
|
-
task_id TEXT,
|
|
36
|
-
agent TEXT,
|
|
37
|
-
detail TEXT NOT NULL,
|
|
38
|
-
duration_ms INTEGER
|
|
39
|
-
)
|
|
40
|
-
`;
|
|
41
|
-
|
|
42
|
-
const CREATE_INDEX_SQL = `
|
|
43
|
-
CREATE INDEX IF NOT EXISTS idx_pipeline_traces_pipeline
|
|
44
|
-
ON pipeline_traces (pipeline_id, timestamp)
|
|
45
|
-
`;
|
|
46
|
-
|
|
47
|
-
// ── Init ───────────────────────────────────────────────────────────
|
|
48
|
-
|
|
49
|
-
export function initTraceTable(db: Database.Database): void {
|
|
50
|
-
db.exec(CREATE_TABLE_SQL);
|
|
51
|
-
db.exec(CREATE_INDEX_SQL);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ── Write ──────────────────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
let _insertStmt: Database.Statement | null = null;
|
|
57
|
-
|
|
58
|
-
export function writeTrace(db: Database.Database, event: TraceEvent): void {
|
|
59
|
-
if (!_insertStmt) {
|
|
60
|
-
_insertStmt = db.prepare(`
|
|
61
|
-
INSERT INTO pipeline_traces (pipeline_id, timestamp, type, task_id, agent, detail, duration_ms)
|
|
62
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
63
|
-
`);
|
|
64
|
-
}
|
|
65
|
-
_insertStmt.run(
|
|
66
|
-
event.pipelineId,
|
|
67
|
-
event.timestamp,
|
|
68
|
-
event.type,
|
|
69
|
-
event.taskId ?? null,
|
|
70
|
-
event.agent ?? null,
|
|
71
|
-
event.detail,
|
|
72
|
-
event.durationMs ?? null,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ── Read ───────────────────────────────────────────────────────────
|
|
77
|
-
|
|
78
|
-
export function getTraces(db: Database.Database, pipelineId: string): TraceEvent[] {
|
|
79
|
-
const rows = db.prepare(
|
|
80
|
-
'SELECT * FROM pipeline_traces WHERE pipeline_id = ? ORDER BY timestamp ASC',
|
|
81
|
-
).all(pipelineId) as Array<{
|
|
82
|
-
pipeline_id: string; timestamp: number; type: string;
|
|
83
|
-
task_id: string | null; agent: string | null; detail: string;
|
|
84
|
-
duration_ms: number | null;
|
|
85
|
-
}>;
|
|
86
|
-
|
|
87
|
-
return rows.map(r => ({
|
|
88
|
-
pipelineId: r.pipeline_id,
|
|
89
|
-
timestamp: r.timestamp,
|
|
90
|
-
type: r.type as TraceEventType,
|
|
91
|
-
taskId: r.task_id ?? undefined,
|
|
92
|
-
agent: r.agent ?? undefined,
|
|
93
|
-
detail: r.detail,
|
|
94
|
-
durationMs: r.duration_ms ?? undefined,
|
|
95
|
-
}));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ── Prune ──────────────────────────────────────────────────────────
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Remove traces from old pipelines, keeping only the last `keepPipelines`.
|
|
102
|
-
*/
|
|
103
|
-
export function pruneOldTraces(db: Database.Database, keepPipelines: number = 20): number {
|
|
104
|
-
// Two-step approach: find pipelines to keep, then delete the rest.
|
|
105
|
-
// SQLite doesn't allow aggregate + ORDER BY + LIMIT in a subquery easily.
|
|
106
|
-
const kept = db.prepare(`
|
|
107
|
-
SELECT pipeline_id FROM (
|
|
108
|
-
SELECT pipeline_id, MAX(timestamp) AS latest
|
|
109
|
-
FROM pipeline_traces
|
|
110
|
-
GROUP BY pipeline_id
|
|
111
|
-
ORDER BY latest DESC
|
|
112
|
-
LIMIT ?
|
|
113
|
-
)
|
|
114
|
-
`).all(keepPipelines) as Array<{ pipeline_id: string }>;
|
|
115
|
-
|
|
116
|
-
if (kept.length === 0) return 0;
|
|
117
|
-
|
|
118
|
-
const keepIds = kept.map(r => r.pipeline_id);
|
|
119
|
-
const placeholders = keepIds.map(() => '?').join(',');
|
|
120
|
-
const result = db.prepare(
|
|
121
|
-
`DELETE FROM pipeline_traces WHERE pipeline_id NOT IN (${placeholders})`,
|
|
122
|
-
).run(...keepIds);
|
|
123
|
-
return result.changes;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Reset the cached prepared statement (for testing or DB handle changes).
|
|
128
|
-
*/
|
|
129
|
-
export function resetTraceCache(): void {
|
|
130
|
-
_insertStmt = null;
|
|
131
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline Tracing — Phase 6g: Structured event logging.
|
|
3
|
+
*
|
|
4
|
+
* Writes trace events to SQLite for observability and debugging.
|
|
5
|
+
* Built-in pruning retains only the last N pipelines (pays D9 debt).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type Database from 'better-sqlite3';
|
|
9
|
+
|
|
10
|
+
// ── Types ──────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
export type TraceEventType =
|
|
13
|
+
| 'plan' | 'materialize' | 'dispatch' | 'complete' | 'fail'
|
|
14
|
+
| 'retry' | 'timeout' | 'stale' | 'replan' | 'worktree:create'
|
|
15
|
+
| 'worktree:merge' | 'worktree:cleanup' | 'pipeline:start' | 'pipeline:end';
|
|
16
|
+
|
|
17
|
+
export interface TraceEvent {
|
|
18
|
+
pipelineId: string;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
type: TraceEventType;
|
|
21
|
+
taskId?: string;
|
|
22
|
+
agent?: string;
|
|
23
|
+
detail: string;
|
|
24
|
+
durationMs?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ── Schema ─────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
const CREATE_TABLE_SQL = `
|
|
30
|
+
CREATE TABLE IF NOT EXISTS pipeline_traces (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
pipeline_id TEXT NOT NULL,
|
|
33
|
+
timestamp INTEGER NOT NULL,
|
|
34
|
+
type TEXT NOT NULL,
|
|
35
|
+
task_id TEXT,
|
|
36
|
+
agent TEXT,
|
|
37
|
+
detail TEXT NOT NULL,
|
|
38
|
+
duration_ms INTEGER
|
|
39
|
+
)
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const CREATE_INDEX_SQL = `
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_pipeline_traces_pipeline
|
|
44
|
+
ON pipeline_traces (pipeline_id, timestamp)
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
// ── Init ───────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
export function initTraceTable(db: Database.Database): void {
|
|
50
|
+
db.exec(CREATE_TABLE_SQL);
|
|
51
|
+
db.exec(CREATE_INDEX_SQL);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── Write ──────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
let _insertStmt: Database.Statement | null = null;
|
|
57
|
+
|
|
58
|
+
export function writeTrace(db: Database.Database, event: TraceEvent): void {
|
|
59
|
+
if (!_insertStmt) {
|
|
60
|
+
_insertStmt = db.prepare(`
|
|
61
|
+
INSERT INTO pipeline_traces (pipeline_id, timestamp, type, task_id, agent, detail, duration_ms)
|
|
62
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
63
|
+
`);
|
|
64
|
+
}
|
|
65
|
+
_insertStmt.run(
|
|
66
|
+
event.pipelineId,
|
|
67
|
+
event.timestamp,
|
|
68
|
+
event.type,
|
|
69
|
+
event.taskId ?? null,
|
|
70
|
+
event.agent ?? null,
|
|
71
|
+
event.detail,
|
|
72
|
+
event.durationMs ?? null,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ── Read ───────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
export function getTraces(db: Database.Database, pipelineId: string): TraceEvent[] {
|
|
79
|
+
const rows = db.prepare(
|
|
80
|
+
'SELECT * FROM pipeline_traces WHERE pipeline_id = ? ORDER BY timestamp ASC',
|
|
81
|
+
).all(pipelineId) as Array<{
|
|
82
|
+
pipeline_id: string; timestamp: number; type: string;
|
|
83
|
+
task_id: string | null; agent: string | null; detail: string;
|
|
84
|
+
duration_ms: number | null;
|
|
85
|
+
}>;
|
|
86
|
+
|
|
87
|
+
return rows.map(r => ({
|
|
88
|
+
pipelineId: r.pipeline_id,
|
|
89
|
+
timestamp: r.timestamp,
|
|
90
|
+
type: r.type as TraceEventType,
|
|
91
|
+
taskId: r.task_id ?? undefined,
|
|
92
|
+
agent: r.agent ?? undefined,
|
|
93
|
+
detail: r.detail,
|
|
94
|
+
durationMs: r.duration_ms ?? undefined,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── Prune ──────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Remove traces from old pipelines, keeping only the last `keepPipelines`.
|
|
102
|
+
*/
|
|
103
|
+
export function pruneOldTraces(db: Database.Database, keepPipelines: number = 20): number {
|
|
104
|
+
// Two-step approach: find pipelines to keep, then delete the rest.
|
|
105
|
+
// SQLite doesn't allow aggregate + ORDER BY + LIMIT in a subquery easily.
|
|
106
|
+
const kept = db.prepare(`
|
|
107
|
+
SELECT pipeline_id FROM (
|
|
108
|
+
SELECT pipeline_id, MAX(timestamp) AS latest
|
|
109
|
+
FROM pipeline_traces
|
|
110
|
+
GROUP BY pipeline_id
|
|
111
|
+
ORDER BY latest DESC
|
|
112
|
+
LIMIT ?
|
|
113
|
+
)
|
|
114
|
+
`).all(keepPipelines) as Array<{ pipeline_id: string }>;
|
|
115
|
+
|
|
116
|
+
if (kept.length === 0) return 0;
|
|
117
|
+
|
|
118
|
+
const keepIds = kept.map(r => r.pipeline_id);
|
|
119
|
+
const placeholders = keepIds.map(() => '?').join(',');
|
|
120
|
+
const result = db.prepare(
|
|
121
|
+
`DELETE FROM pipeline_traces WHERE pipeline_id NOT IN (${placeholders})`,
|
|
122
|
+
).run(...keepIds);
|
|
123
|
+
return result.changes;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Reset the cached prepared statement (for testing or DB handle changes).
|
|
128
|
+
*/
|
|
129
|
+
export function resetTraceCache(): void {
|
|
130
|
+
_insertStmt = null;
|
|
131
|
+
}
|
|
@@ -1,155 +1,155 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt Builder — Constructs agent prompts for orchestrated task execution.
|
|
3
|
-
*
|
|
4
|
-
* Builds a structured prompt that includes:
|
|
5
|
-
* 1. Role and task description
|
|
6
|
-
* 2. Handoff context from previous agents (if any)
|
|
7
|
-
* 3. Memorix tool usage instructions
|
|
8
|
-
* 4. Completion criteria
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { TeamTaskRow } from '../team/team-store.js';
|
|
12
|
-
import { isPlannerTask } from './planner.js';
|
|
13
|
-
|
|
14
|
-
export interface HandoffContext {
|
|
15
|
-
fromAgent: string;
|
|
16
|
-
fromTaskId?: string;
|
|
17
|
-
fromRole?: string;
|
|
18
|
-
summary: string;
|
|
19
|
-
context: string;
|
|
20
|
-
outputFiles?: string[];
|
|
21
|
-
keyDecisions?: string[];
|
|
22
|
-
openQuestions?: string[];
|
|
23
|
-
/** @deprecated Use outputFiles instead */
|
|
24
|
-
filesModified?: string[];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface PromptInput {
|
|
28
|
-
task: TeamTaskRow;
|
|
29
|
-
handoffs: HandoffContext[];
|
|
30
|
-
agentId: string;
|
|
31
|
-
projectId: string;
|
|
32
|
-
projectDir: string;
|
|
33
|
-
/** Phase 6d: Ledger context for pipeline progress */
|
|
34
|
-
ledgerContext?: string;
|
|
35
|
-
/** Phase 6d: Task position in pipeline (0-indexed) */
|
|
36
|
-
taskIndex?: number;
|
|
37
|
-
/** Phase 6d: Total tasks in pipeline */
|
|
38
|
-
totalTasks?: number;
|
|
39
|
-
/** Phase 7: Lesson context from Memorix (advisory) */
|
|
40
|
-
lessonContext?: string;
|
|
41
|
-
/** Phase 7: Goal verification — acceptance criteria for this task */
|
|
42
|
-
goals?: string[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function buildAgentPrompt(input: PromptInput): string {
|
|
46
|
-
const sections: string[] = [];
|
|
47
|
-
|
|
48
|
-
// 1. Role assignment
|
|
49
|
-
sections.push([
|
|
50
|
-
`You are an autonomous coding agent working on project "${input.projectId}".`,
|
|
51
|
-
`Coordinator agent ID (for reference only, NOT your identity): ${input.agentId}`,
|
|
52
|
-
`Working directory: ${input.projectDir}`,
|
|
53
|
-
].join('\n'));
|
|
54
|
-
|
|
55
|
-
// 2. Task description
|
|
56
|
-
sections.push([
|
|
57
|
-
'## Your Task',
|
|
58
|
-
'',
|
|
59
|
-
`Task ID: ${input.task.task_id}`,
|
|
60
|
-
`Description: ${input.task.description}`,
|
|
61
|
-
input.task.metadata ? `Metadata: ${input.task.metadata}` : '',
|
|
62
|
-
].filter(Boolean).join('\n'));
|
|
63
|
-
|
|
64
|
-
// 3. Ledger context (Phase 6d — pipeline progress)
|
|
65
|
-
if (input.ledgerContext) {
|
|
66
|
-
sections.push(input.ledgerContext);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Phase 7: Lesson injection (advisory)
|
|
70
|
-
if (input.lessonContext) {
|
|
71
|
-
sections.push(input.lessonContext);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Phase 7: Goal verification — acceptance criteria
|
|
75
|
-
if (input.goals && input.goals.length > 0) {
|
|
76
|
-
sections.push([
|
|
77
|
-
'## Acceptance Criteria',
|
|
78
|
-
'',
|
|
79
|
-
'Your work will be verified against these goals:',
|
|
80
|
-
...input.goals.map((g, i) => `${i + 1}. ${g}`),
|
|
81
|
-
'',
|
|
82
|
-
'Ensure ALL criteria are satisfied before finishing.',
|
|
83
|
-
].join('\n'));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// 4. Handoff context from previous agents
|
|
87
|
-
if (input.handoffs.length > 0) {
|
|
88
|
-
const handoffLines = input.handoffs.map((h, i) => {
|
|
89
|
-
const lines = [
|
|
90
|
-
`### Handoff ${i + 1} (from ${h.fromAgent}${h.fromRole ? ` [${h.fromRole}]` : ''})`,
|
|
91
|
-
`Summary: ${h.summary}`,
|
|
92
|
-
`Context: ${h.context}`,
|
|
93
|
-
];
|
|
94
|
-
const files = h.outputFiles ?? h.filesModified;
|
|
95
|
-
if (files?.length) lines.push(`Files: ${files.join(', ')}`);
|
|
96
|
-
if (h.keyDecisions?.length) lines.push(`Key decisions: ${h.keyDecisions.join('; ')}`);
|
|
97
|
-
if (h.openQuestions?.length) lines.push(`Open questions: ${h.openQuestions.join('; ')}`);
|
|
98
|
-
return lines.filter(Boolean).join('\n');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
sections.push([
|
|
102
|
-
'## Context from Previous Agents',
|
|
103
|
-
'',
|
|
104
|
-
'The following handoff artifacts were left by agents who worked on related tasks.',
|
|
105
|
-
'Use this context to avoid re-doing work and to understand the current state.',
|
|
106
|
-
'',
|
|
107
|
-
...handoffLines,
|
|
108
|
-
].join('\n'));
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// 4. Memorix tool instructions
|
|
112
|
-
const plannerMeta = isPlannerTask(input.task.metadata);
|
|
113
|
-
const isAutonomous = !!plannerMeta;
|
|
114
|
-
// Structured plan tasks (plannerType='plan') output JSON only — the coordinator materializes.
|
|
115
|
-
// They must NOT call team_task create, or tasks get double-created.
|
|
116
|
-
// Review tasks and decomposition tasks still need team_task create for fix/follow-up tasks.
|
|
117
|
-
const isStructuredPlan = plannerMeta?.plannerType === 'plan';
|
|
118
|
-
|
|
119
|
-
const taskInstruction = isAutonomous && !isStructuredPlan
|
|
120
|
-
? '5. You have FULL ACCESS to `team_task action="create"` for creating subtasks. Follow the instructions in your task description.'
|
|
121
|
-
: isStructuredPlan
|
|
122
|
-
? '5. Do NOT call `team_task` — output ONLY the structured JSON plan as specified. The coordinator will materialize tasks from your JSON output.'
|
|
123
|
-
: '5. Focus on completing the work. Do NOT call `team_task` — the orchestrator manages task state.';
|
|
124
|
-
|
|
125
|
-
const creationRule = isAutonomous && !isStructuredPlan
|
|
126
|
-
? '8. Create tasks as instructed in your task description. Respect the task budget and include proper dependencies.'
|
|
127
|
-
: isStructuredPlan
|
|
128
|
-
? '8. Output ONLY the JSON plan inside a ```json code fence. Do NOT create tasks directly — the system will parse your JSON and create them automatically.'
|
|
129
|
-
: '8. Do NOT create new tasks unless the original task explicitly requires subtask decomposition.';
|
|
130
|
-
|
|
131
|
-
sections.push([
|
|
132
|
-
'## Instructions',
|
|
133
|
-
'',
|
|
134
|
-
'1. Start by calling `memorix_session_start` to bind to this project.',
|
|
135
|
-
'2. Use the agentId returned by `memorix_session_start` as YOUR identity for any identity-bearing calls (e.g. `memorix_handoff` fromAgentId). Do NOT use the coordinator agent ID above — that belongs to the orchestrator, not to you.',
|
|
136
|
-
'3. Call `memorix_poll` to check for any additional context or messages.',
|
|
137
|
-
`4. Work on the task described above. The task is already claimed and managed by the orchestrator.`,
|
|
138
|
-
taskInstruction,
|
|
139
|
-
'6. If you want to leave context for the next agent, call `memorix_handoff` with a summary of what you did.',
|
|
140
|
-
'7. Use `memorix_store` to save any important discoveries, decisions, or gotchas.',
|
|
141
|
-
creationRule,
|
|
142
|
-
].join('\n'));
|
|
143
|
-
|
|
144
|
-
// 5. Completion criteria
|
|
145
|
-
sections.push([
|
|
146
|
-
'## Completion Criteria',
|
|
147
|
-
'',
|
|
148
|
-
'- Exit with code 0 when the task is successfully completed.',
|
|
149
|
-
'- Exit with a non-zero code if you cannot complete the task.',
|
|
150
|
-
'- The orchestrator will determine task success/failure based on your exit code.',
|
|
151
|
-
'- You do NOT need to mark the task as completed or failed — that is handled automatically.',
|
|
152
|
-
].join('\n'));
|
|
153
|
-
|
|
154
|
-
return sections.join('\n\n');
|
|
155
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Builder — Constructs agent prompts for orchestrated task execution.
|
|
3
|
+
*
|
|
4
|
+
* Builds a structured prompt that includes:
|
|
5
|
+
* 1. Role and task description
|
|
6
|
+
* 2. Handoff context from previous agents (if any)
|
|
7
|
+
* 3. Memorix tool usage instructions
|
|
8
|
+
* 4. Completion criteria
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { TeamTaskRow } from '../team/team-store.js';
|
|
12
|
+
import { isPlannerTask } from './planner.js';
|
|
13
|
+
|
|
14
|
+
export interface HandoffContext {
|
|
15
|
+
fromAgent: string;
|
|
16
|
+
fromTaskId?: string;
|
|
17
|
+
fromRole?: string;
|
|
18
|
+
summary: string;
|
|
19
|
+
context: string;
|
|
20
|
+
outputFiles?: string[];
|
|
21
|
+
keyDecisions?: string[];
|
|
22
|
+
openQuestions?: string[];
|
|
23
|
+
/** @deprecated Use outputFiles instead */
|
|
24
|
+
filesModified?: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PromptInput {
|
|
28
|
+
task: TeamTaskRow;
|
|
29
|
+
handoffs: HandoffContext[];
|
|
30
|
+
agentId: string;
|
|
31
|
+
projectId: string;
|
|
32
|
+
projectDir: string;
|
|
33
|
+
/** Phase 6d: Ledger context for pipeline progress */
|
|
34
|
+
ledgerContext?: string;
|
|
35
|
+
/** Phase 6d: Task position in pipeline (0-indexed) */
|
|
36
|
+
taskIndex?: number;
|
|
37
|
+
/** Phase 6d: Total tasks in pipeline */
|
|
38
|
+
totalTasks?: number;
|
|
39
|
+
/** Phase 7: Lesson context from Memorix (advisory) */
|
|
40
|
+
lessonContext?: string;
|
|
41
|
+
/** Phase 7: Goal verification — acceptance criteria for this task */
|
|
42
|
+
goals?: string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function buildAgentPrompt(input: PromptInput): string {
|
|
46
|
+
const sections: string[] = [];
|
|
47
|
+
|
|
48
|
+
// 1. Role assignment
|
|
49
|
+
sections.push([
|
|
50
|
+
`You are an autonomous coding agent working on project "${input.projectId}".`,
|
|
51
|
+
`Coordinator agent ID (for reference only, NOT your identity): ${input.agentId}`,
|
|
52
|
+
`Working directory: ${input.projectDir}`,
|
|
53
|
+
].join('\n'));
|
|
54
|
+
|
|
55
|
+
// 2. Task description
|
|
56
|
+
sections.push([
|
|
57
|
+
'## Your Task',
|
|
58
|
+
'',
|
|
59
|
+
`Task ID: ${input.task.task_id}`,
|
|
60
|
+
`Description: ${input.task.description}`,
|
|
61
|
+
input.task.metadata ? `Metadata: ${input.task.metadata}` : '',
|
|
62
|
+
].filter(Boolean).join('\n'));
|
|
63
|
+
|
|
64
|
+
// 3. Ledger context (Phase 6d — pipeline progress)
|
|
65
|
+
if (input.ledgerContext) {
|
|
66
|
+
sections.push(input.ledgerContext);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Phase 7: Lesson injection (advisory)
|
|
70
|
+
if (input.lessonContext) {
|
|
71
|
+
sections.push(input.lessonContext);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Phase 7: Goal verification — acceptance criteria
|
|
75
|
+
if (input.goals && input.goals.length > 0) {
|
|
76
|
+
sections.push([
|
|
77
|
+
'## Acceptance Criteria',
|
|
78
|
+
'',
|
|
79
|
+
'Your work will be verified against these goals:',
|
|
80
|
+
...input.goals.map((g, i) => `${i + 1}. ${g}`),
|
|
81
|
+
'',
|
|
82
|
+
'Ensure ALL criteria are satisfied before finishing.',
|
|
83
|
+
].join('\n'));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 4. Handoff context from previous agents
|
|
87
|
+
if (input.handoffs.length > 0) {
|
|
88
|
+
const handoffLines = input.handoffs.map((h, i) => {
|
|
89
|
+
const lines = [
|
|
90
|
+
`### Handoff ${i + 1} (from ${h.fromAgent}${h.fromRole ? ` [${h.fromRole}]` : ''})`,
|
|
91
|
+
`Summary: ${h.summary}`,
|
|
92
|
+
`Context: ${h.context}`,
|
|
93
|
+
];
|
|
94
|
+
const files = h.outputFiles ?? h.filesModified;
|
|
95
|
+
if (files?.length) lines.push(`Files: ${files.join(', ')}`);
|
|
96
|
+
if (h.keyDecisions?.length) lines.push(`Key decisions: ${h.keyDecisions.join('; ')}`);
|
|
97
|
+
if (h.openQuestions?.length) lines.push(`Open questions: ${h.openQuestions.join('; ')}`);
|
|
98
|
+
return lines.filter(Boolean).join('\n');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
sections.push([
|
|
102
|
+
'## Context from Previous Agents',
|
|
103
|
+
'',
|
|
104
|
+
'The following handoff artifacts were left by agents who worked on related tasks.',
|
|
105
|
+
'Use this context to avoid re-doing work and to understand the current state.',
|
|
106
|
+
'',
|
|
107
|
+
...handoffLines,
|
|
108
|
+
].join('\n'));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 4. Memorix tool instructions
|
|
112
|
+
const plannerMeta = isPlannerTask(input.task.metadata);
|
|
113
|
+
const isAutonomous = !!plannerMeta;
|
|
114
|
+
// Structured plan tasks (plannerType='plan') output JSON only — the coordinator materializes.
|
|
115
|
+
// They must NOT call team_task create, or tasks get double-created.
|
|
116
|
+
// Review tasks and decomposition tasks still need team_task create for fix/follow-up tasks.
|
|
117
|
+
const isStructuredPlan = plannerMeta?.plannerType === 'plan';
|
|
118
|
+
|
|
119
|
+
const taskInstruction = isAutonomous && !isStructuredPlan
|
|
120
|
+
? '5. You have FULL ACCESS to `team_task action="create"` for creating subtasks. Follow the instructions in your task description.'
|
|
121
|
+
: isStructuredPlan
|
|
122
|
+
? '5. Do NOT call `team_task` — output ONLY the structured JSON plan as specified. The coordinator will materialize tasks from your JSON output.'
|
|
123
|
+
: '5. Focus on completing the work. Do NOT call `team_task` — the orchestrator manages task state.';
|
|
124
|
+
|
|
125
|
+
const creationRule = isAutonomous && !isStructuredPlan
|
|
126
|
+
? '8. Create tasks as instructed in your task description. Respect the task budget and include proper dependencies.'
|
|
127
|
+
: isStructuredPlan
|
|
128
|
+
? '8. Output ONLY the JSON plan inside a ```json code fence. Do NOT create tasks directly — the system will parse your JSON and create them automatically.'
|
|
129
|
+
: '8. Do NOT create new tasks unless the original task explicitly requires subtask decomposition.';
|
|
130
|
+
|
|
131
|
+
sections.push([
|
|
132
|
+
'## Instructions',
|
|
133
|
+
'',
|
|
134
|
+
'1. Start by calling `memorix_session_start` to bind to this project.',
|
|
135
|
+
'2. Use the agentId returned by `memorix_session_start` as YOUR identity for any identity-bearing calls (e.g. `memorix_handoff` fromAgentId). Do NOT use the coordinator agent ID above — that belongs to the orchestrator, not to you.',
|
|
136
|
+
'3. Call `memorix_poll` to check for any additional context or messages.',
|
|
137
|
+
`4. Work on the task described above. The task is already claimed and managed by the orchestrator.`,
|
|
138
|
+
taskInstruction,
|
|
139
|
+
'6. If you want to leave context for the next agent, call `memorix_handoff` with a summary of what you did.',
|
|
140
|
+
'7. Use `memorix_store` to save any important discoveries, decisions, or gotchas.',
|
|
141
|
+
creationRule,
|
|
142
|
+
].join('\n'));
|
|
143
|
+
|
|
144
|
+
// 5. Completion criteria
|
|
145
|
+
sections.push([
|
|
146
|
+
'## Completion Criteria',
|
|
147
|
+
'',
|
|
148
|
+
'- Exit with code 0 when the task is successfully completed.',
|
|
149
|
+
'- Exit with a non-zero code if you cannot complete the task.',
|
|
150
|
+
'- The orchestrator will determine task success/failure based on your exit code.',
|
|
151
|
+
'- You do NOT need to mark the task as completed or failed — that is handled automatically.',
|
|
152
|
+
].join('\n'));
|
|
153
|
+
|
|
154
|
+
return sections.join('\n\n');
|
|
155
|
+
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RingBuffer — Bounded line buffer for agent process output.
|
|
3
|
-
*
|
|
4
|
-
* Captures the last N lines of stdout/stderr without unbounded memory growth.
|
|
5
|
-
* Used by agent adapters to provide tail output for diagnostics.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export class RingBuffer {
|
|
9
|
-
private lines: string[] = [];
|
|
10
|
-
|
|
11
|
-
constructor(private maxLines: number = 50) {}
|
|
12
|
-
|
|
13
|
-
push(text: string): void {
|
|
14
|
-
for (const line of text.split('\n')) {
|
|
15
|
-
if (line.trim()) {
|
|
16
|
-
this.lines.push(line);
|
|
17
|
-
if (this.lines.length > this.maxLines) this.lines.shift();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
getLines(): string[] {
|
|
23
|
-
return [...this.lines];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
toString(): string {
|
|
27
|
-
return this.lines.join('\n');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
get length(): number {
|
|
31
|
-
return this.lines.length;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
clear(): void {
|
|
35
|
-
this.lines = [];
|
|
36
|
-
}
|
|
37
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* RingBuffer — Bounded line buffer for agent process output.
|
|
3
|
+
*
|
|
4
|
+
* Captures the last N lines of stdout/stderr without unbounded memory growth.
|
|
5
|
+
* Used by agent adapters to provide tail output for diagnostics.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class RingBuffer {
|
|
9
|
+
private lines: string[] = [];
|
|
10
|
+
|
|
11
|
+
constructor(private maxLines: number = 50) {}
|
|
12
|
+
|
|
13
|
+
push(text: string): void {
|
|
14
|
+
for (const line of text.split('\n')) {
|
|
15
|
+
if (line.trim()) {
|
|
16
|
+
this.lines.push(line);
|
|
17
|
+
if (this.lines.length > this.maxLines) this.lines.shift();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getLines(): string[] {
|
|
23
|
+
return [...this.lines];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toString(): string {
|
|
27
|
+
return this.lines.join('\n');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get length(): number {
|
|
31
|
+
return this.lines.length;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
clear(): void {
|
|
35
|
+
this.lines = [];
|
|
36
|
+
}
|
|
37
|
+
}
|