@oyasmi/pipiclaw 0.3.5 → 0.5.0
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 +3 -0
- package/LICENSE +184 -0
- package/README.md +267 -230
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +158 -76
- package/dist/agent.js.map +1 -1
- package/dist/command-extension.d.ts.map +1 -1
- package/dist/command-extension.js.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js.map +1 -1
- package/dist/context.d.ts +18 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +26 -2
- package/dist/context.js.map +1 -1
- package/dist/delivery.d.ts.map +1 -1
- package/dist/delivery.js +11 -14
- package/dist/delivery.js.map +1 -1
- package/dist/dingtalk.d.ts.map +1 -1
- package/dist/dingtalk.js +26 -26
- package/dist/dingtalk.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +5 -8
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-json.d.ts +7 -0
- package/dist/llm-json.d.ts.map +1 -0
- package/dist/llm-json.js +77 -0
- package/dist/llm-json.js.map +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js.map +1 -1
- package/dist/markdown-sections.d.ts +6 -0
- package/dist/markdown-sections.d.ts.map +1 -0
- package/dist/markdown-sections.js +34 -0
- package/dist/markdown-sections.js.map +1 -0
- package/dist/memory-candidates.d.ts +21 -0
- package/dist/memory-candidates.d.ts.map +1 -0
- package/dist/memory-candidates.js +126 -0
- package/dist/memory-candidates.js.map +1 -0
- package/dist/memory-consolidation.d.ts.map +1 -1
- package/dist/memory-consolidation.js +28 -49
- package/dist/memory-consolidation.js.map +1 -1
- package/dist/memory-files.d.ts +3 -0
- package/dist/memory-files.d.ts.map +1 -1
- package/dist/memory-files.js +51 -0
- package/dist/memory-files.js.map +1 -1
- package/dist/memory-lifecycle.d.ts +9 -0
- package/dist/memory-lifecycle.d.ts.map +1 -1
- package/dist/memory-lifecycle.js +67 -2
- package/dist/memory-lifecycle.js.map +1 -1
- package/dist/memory-recall.d.ts +29 -0
- package/dist/memory-recall.d.ts.map +1 -0
- package/dist/memory-recall.js +218 -0
- package/dist/memory-recall.js.map +1 -0
- package/dist/model-utils.d.ts.map +1 -1
- package/dist/model-utils.js.map +1 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/prompt-builder.d.ts.map +1 -1
- package/dist/prompt-builder.js +7 -2
- package/dist/prompt-builder.js.map +1 -1
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +0 -1
- package/dist/sandbox.js.map +1 -1
- package/dist/session-memory-files.d.ts +2 -0
- package/dist/session-memory-files.d.ts.map +1 -0
- package/dist/session-memory-files.js +2 -0
- package/dist/session-memory-files.js.map +1 -0
- package/dist/session-memory.d.ts +22 -0
- package/dist/session-memory.d.ts.map +1 -0
- package/dist/session-memory.js +274 -0
- package/dist/session-memory.js.map +1 -0
- package/dist/shell-escape.d.ts.map +1 -1
- package/dist/shell-escape.js.map +1 -1
- package/dist/sidecar-worker.d.ts +27 -0
- package/dist/sidecar-worker.d.ts.map +1 -0
- package/dist/sidecar-worker.js +105 -0
- package/dist/sidecar-worker.js.map +1 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +2 -3
- package/dist/store.js.map +1 -1
- package/dist/sub-agents.d.ts +10 -0
- package/dist/sub-agents.d.ts.map +1 -1
- package/dist/sub-agents.js +132 -10
- package/dist/sub-agents.js.map +1 -1
- package/dist/tools/attach.d.ts.map +1 -1
- package/dist/tools/attach.js.map +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/subagent.d.ts +6 -0
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +127 -12
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/truncate.d.ts.map +1 -1
- package/dist/tools/truncate.js.map +1 -1
- package/dist/tools/write-content.d.ts.map +1 -1
- package/dist/tools/write-content.js.map +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js.map +1 -1
- package/docs/improve-memory/design.md +537 -0
- package/docs/improve-memory/interfaces-and-tests.md +473 -0
- package/docs/improve-memory/spec.md +357 -0
- package/docs/memory-rfc.md +297 -0
- package/docs/proj-review.md +188 -0
- package/docs/subagent/pi-subagent-analyse.txt +190 -0
- package/docs/subagent/pi-subagent-design.txt +266 -0
- package/docs/subagent/pi-subagent-phase1-plan.txt +529 -0
- package/docs/test-supplementation-plan.md +553 -0
- package/package.json +71 -53
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Api, Model } from "@mariozechner/pi-ai";
|
|
2
|
+
import { type MemoryCandidate, type MemoryCandidateCache } from "./memory-candidates.js";
|
|
3
|
+
export interface RecallRequest {
|
|
4
|
+
query: string;
|
|
5
|
+
workspaceDir: string;
|
|
6
|
+
channelDir: string;
|
|
7
|
+
allowedSources?: MemoryCandidate["source"][];
|
|
8
|
+
maxCandidates: number;
|
|
9
|
+
maxInjected: number;
|
|
10
|
+
maxChars: number;
|
|
11
|
+
rerankWithModel: boolean;
|
|
12
|
+
autoRerank?: boolean;
|
|
13
|
+
model: Model<Api>;
|
|
14
|
+
resolveApiKey: (model: Model<Api>) => Promise<string>;
|
|
15
|
+
candidateCache?: MemoryCandidateCache;
|
|
16
|
+
}
|
|
17
|
+
export interface RecalledMemory {
|
|
18
|
+
source: MemoryCandidate["source"];
|
|
19
|
+
path: string;
|
|
20
|
+
title: string;
|
|
21
|
+
content: string;
|
|
22
|
+
score: number;
|
|
23
|
+
}
|
|
24
|
+
export interface RecallResult {
|
|
25
|
+
items: RecalledMemory[];
|
|
26
|
+
renderedText: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function recallRelevantMemory(request: RecallRequest): Promise<RecallResult>;
|
|
29
|
+
//# sourceMappingURL=memory-recall.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-recall.d.ts","sourceRoot":"","sources":["../src/memory-recall.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAGhH,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACrB;AAsMD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAkDxF"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { parseJsonObject } from "./llm-json.js";
|
|
2
|
+
import { buildMemoryCandidates } from "./memory-candidates.js";
|
|
3
|
+
import { runSidecarTask } from "./sidecar-worker.js";
|
|
4
|
+
const RERANK_SYSTEM_PROMPT = `You are selecting which memory snippets are most relevant to the current user turn.
|
|
5
|
+
|
|
6
|
+
Return strict JSON only:
|
|
7
|
+
{
|
|
8
|
+
"selectedIds": ["candidate-id"]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
Rules:
|
|
12
|
+
- Select only snippets that are clearly useful for answering the current turn.
|
|
13
|
+
- Prefer current work state, constraints, active files, recent corrections, and durable decisions.
|
|
14
|
+
- If nothing is clearly useful, return an empty array.
|
|
15
|
+
- Do not rewrite the candidates. Only return candidate ids.`;
|
|
16
|
+
const HAN_REGEX = /\p{Script=Han}/u;
|
|
17
|
+
const TOKEN_PART_REGEX = /[\p{Script=Han}]+|[\p{L}\p{N}_./-]+/gu;
|
|
18
|
+
const MEMORY_RECALL_RERANK_TIMEOUT_MS = 5_000;
|
|
19
|
+
function containsHanText(text) {
|
|
20
|
+
return HAN_REGEX.test(text);
|
|
21
|
+
}
|
|
22
|
+
function tokenizeHanPart(part) {
|
|
23
|
+
const chars = Array.from(part);
|
|
24
|
+
const tokens = [];
|
|
25
|
+
for (const size of [2, 3]) {
|
|
26
|
+
if (chars.length < size) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
for (let index = 0; index <= chars.length - size; index++) {
|
|
30
|
+
tokens.push(chars.slice(index, index + size).join(""));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return tokens;
|
|
34
|
+
}
|
|
35
|
+
function tokenize(text) {
|
|
36
|
+
const parts = text.toLowerCase().match(TOKEN_PART_REGEX) ?? [];
|
|
37
|
+
const tokens = [];
|
|
38
|
+
for (const part of parts) {
|
|
39
|
+
if (containsHanText(part)) {
|
|
40
|
+
tokens.push(...tokenizeHanPart(part));
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (part.length >= 2) {
|
|
44
|
+
tokens.push(part);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return Array.from(new Set(tokens));
|
|
48
|
+
}
|
|
49
|
+
function computeTokenOverlapScore(queryTokens, text, weight) {
|
|
50
|
+
const haystack = new Set(tokenize(text));
|
|
51
|
+
let score = 0;
|
|
52
|
+
for (const token of queryTokens) {
|
|
53
|
+
if (haystack.has(token)) {
|
|
54
|
+
score += weight;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return score;
|
|
58
|
+
}
|
|
59
|
+
function computeRecencyBoost(timestamp) {
|
|
60
|
+
if (!timestamp)
|
|
61
|
+
return 0;
|
|
62
|
+
const timestampMs = Date.parse(timestamp);
|
|
63
|
+
if (!Number.isFinite(timestampMs))
|
|
64
|
+
return 0;
|
|
65
|
+
const ageMs = Date.now() - timestampMs;
|
|
66
|
+
const dayMs = 24 * 60 * 60 * 1000;
|
|
67
|
+
if (ageMs <= dayMs)
|
|
68
|
+
return 8;
|
|
69
|
+
if (ageMs <= 7 * dayMs)
|
|
70
|
+
return 5;
|
|
71
|
+
if (ageMs <= 30 * dayMs)
|
|
72
|
+
return 2;
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
function scoreCandidate(queryTokens, candidate) {
|
|
76
|
+
let score = candidate.priority;
|
|
77
|
+
score += computeTokenOverlapScore(queryTokens, candidate.title, 10);
|
|
78
|
+
score += computeTokenOverlapScore(queryTokens, candidate.content, 3);
|
|
79
|
+
score += computeTokenOverlapScore(queryTokens, candidate.path, 6);
|
|
80
|
+
score += computeRecencyBoost(candidate.timestamp);
|
|
81
|
+
return score;
|
|
82
|
+
}
|
|
83
|
+
function buildFallbackCandidates(request, candidates, existing) {
|
|
84
|
+
if (!containsHanText(request.query) && existing.length > 0) {
|
|
85
|
+
return existing;
|
|
86
|
+
}
|
|
87
|
+
const seen = new Set(existing.map(({ candidate }) => candidate.id));
|
|
88
|
+
const seeded = [...existing];
|
|
89
|
+
const limit = Math.max(request.maxCandidates, request.maxInjected);
|
|
90
|
+
for (const candidate of candidates
|
|
91
|
+
.filter((item) => item.source === "channel-session" || item.source === "channel-memory")
|
|
92
|
+
.sort((a, b) => b.priority - a.priority || a.title.localeCompare(b.title))) {
|
|
93
|
+
if (seen.has(candidate.id)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
seeded.push({ candidate, score: candidate.priority });
|
|
97
|
+
seen.add(candidate.id);
|
|
98
|
+
if (seeded.length >= limit) {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return seeded;
|
|
103
|
+
}
|
|
104
|
+
async function rerankCandidates(request, candidates) {
|
|
105
|
+
if ((!request.rerankWithModel && !request.autoRerank) || candidates.length <= request.maxInjected) {
|
|
106
|
+
return candidates;
|
|
107
|
+
}
|
|
108
|
+
const renderedCandidates = candidates
|
|
109
|
+
.map(({ candidate, score }) => {
|
|
110
|
+
const clippedContent = candidate.content.length > 300 ? `${candidate.content.slice(0, 300)}...` : candidate.content;
|
|
111
|
+
return [
|
|
112
|
+
`id: ${candidate.id}`,
|
|
113
|
+
`source: ${candidate.source}`,
|
|
114
|
+
`title: ${candidate.title}`,
|
|
115
|
+
`path: ${candidate.path}`,
|
|
116
|
+
`score: ${score}`,
|
|
117
|
+
`content: ${clippedContent}`,
|
|
118
|
+
].join("\n");
|
|
119
|
+
})
|
|
120
|
+
.join("\n\n---\n\n");
|
|
121
|
+
try {
|
|
122
|
+
const result = await runSidecarTask({
|
|
123
|
+
name: "memory-recall-rerank",
|
|
124
|
+
model: request.model,
|
|
125
|
+
resolveApiKey: request.resolveApiKey,
|
|
126
|
+
systemPrompt: RERANK_SYSTEM_PROMPT,
|
|
127
|
+
prompt: `User turn:\n${request.query.trim()}\n\nCandidates:\n${renderedCandidates}`,
|
|
128
|
+
timeoutMs: MEMORY_RECALL_RERANK_TIMEOUT_MS,
|
|
129
|
+
parse: (text) => {
|
|
130
|
+
const parsed = parseJsonObject(text);
|
|
131
|
+
return Array.isArray(parsed.selectedIds)
|
|
132
|
+
? parsed.selectedIds.filter((id) => typeof id === "string" && id.trim().length > 0)
|
|
133
|
+
: [];
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
const selectedIds = new Set(result.output);
|
|
137
|
+
if (selectedIds.size === 0) {
|
|
138
|
+
return candidates;
|
|
139
|
+
}
|
|
140
|
+
const selected = candidates.filter(({ candidate }) => selectedIds.has(candidate.id));
|
|
141
|
+
return selected.length > 0 ? selected : candidates;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return candidates;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function renderRecallResult(items, maxChars) {
|
|
148
|
+
if (items.length === 0) {
|
|
149
|
+
return "";
|
|
150
|
+
}
|
|
151
|
+
const lines = ["<runtime_context>", "Relevant context for this turn:"];
|
|
152
|
+
for (const item of items) {
|
|
153
|
+
lines.push("");
|
|
154
|
+
lines.push(`[${item.source}/${item.title}]`);
|
|
155
|
+
lines.push(`Path: ${item.path}`);
|
|
156
|
+
lines.push(item.content);
|
|
157
|
+
}
|
|
158
|
+
lines.push("</runtime_context>");
|
|
159
|
+
const rendered = lines.join("\n");
|
|
160
|
+
if (rendered.length <= maxChars) {
|
|
161
|
+
return rendered;
|
|
162
|
+
}
|
|
163
|
+
const clippedLines = ["<runtime_context>", "Relevant context for this turn:"];
|
|
164
|
+
let usedChars = clippedLines.join("\n").length + "</runtime_context>".length + 2;
|
|
165
|
+
for (const item of items) {
|
|
166
|
+
const block = ["", `[${item.source}/${item.title}]`, `Path: ${item.path}`, item.content].join("\n");
|
|
167
|
+
if (usedChars + block.length > maxChars) {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
clippedLines.push("", `[${item.source}/${item.title}]`, `Path: ${item.path}`, item.content);
|
|
171
|
+
usedChars += block.length;
|
|
172
|
+
}
|
|
173
|
+
clippedLines.push("</runtime_context>");
|
|
174
|
+
return clippedLines.join("\n");
|
|
175
|
+
}
|
|
176
|
+
export async function recallRelevantMemory(request) {
|
|
177
|
+
const query = request.query.trim();
|
|
178
|
+
if (!query) {
|
|
179
|
+
return { items: [], renderedText: "" };
|
|
180
|
+
}
|
|
181
|
+
const candidates = await buildMemoryCandidates({
|
|
182
|
+
workspaceDir: request.workspaceDir,
|
|
183
|
+
channelDir: request.channelDir,
|
|
184
|
+
cache: request.candidateCache,
|
|
185
|
+
});
|
|
186
|
+
const filteredCandidates = request.allowedSources?.length
|
|
187
|
+
? candidates.filter((candidate) => request.allowedSources?.includes(candidate.source))
|
|
188
|
+
: candidates;
|
|
189
|
+
if (filteredCandidates.length === 0) {
|
|
190
|
+
return { items: [], renderedText: "" };
|
|
191
|
+
}
|
|
192
|
+
const queryTokens = tokenize(query);
|
|
193
|
+
const scored = filteredCandidates
|
|
194
|
+
.map((candidate) => ({ candidate, score: scoreCandidate(queryTokens, candidate) }))
|
|
195
|
+
.filter(({ score }) => score > 0)
|
|
196
|
+
.sort((a, b) => b.score - a.score || a.candidate.title.localeCompare(b.candidate.title));
|
|
197
|
+
const shortlist = buildFallbackCandidates(request, filteredCandidates, scored)
|
|
198
|
+
.sort((a, b) => b.score - a.score ||
|
|
199
|
+
b.candidate.priority - a.candidate.priority ||
|
|
200
|
+
a.candidate.title.localeCompare(b.candidate.title))
|
|
201
|
+
.slice(0, Math.max(request.maxCandidates, request.maxInjected));
|
|
202
|
+
if (shortlist.length === 0) {
|
|
203
|
+
return { items: [], renderedText: "" };
|
|
204
|
+
}
|
|
205
|
+
const reranked = await rerankCandidates(request, shortlist);
|
|
206
|
+
const items = reranked.slice(0, request.maxInjected).map(({ candidate, score }) => ({
|
|
207
|
+
source: candidate.source,
|
|
208
|
+
path: candidate.path,
|
|
209
|
+
title: candidate.title,
|
|
210
|
+
content: candidate.content,
|
|
211
|
+
score,
|
|
212
|
+
}));
|
|
213
|
+
return {
|
|
214
|
+
items,
|
|
215
|
+
renderedText: renderRecallResult(items, request.maxChars),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=memory-recall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-recall.js","sourceRoot":"","sources":["../src/memory-recall.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api, Model } from \"@mariozechner/pi-ai\";\nimport { parseJsonObject } from \"./llm-json.js\";\nimport { buildMemoryCandidates, type MemoryCandidate, type MemoryCandidateCache } from \"./memory-candidates.js\";\nimport { runSidecarTask } from \"./sidecar-worker.js\";\n\nexport interface RecallRequest {\n\tquery: string;\n\tworkspaceDir: string;\n\tchannelDir: string;\n\tallowedSources?: MemoryCandidate[\"source\"][];\n\tmaxCandidates: number;\n\tmaxInjected: number;\n\tmaxChars: number;\n\trerankWithModel: boolean;\n\tautoRerank?: boolean;\n\tmodel: Model<Api>;\n\tresolveApiKey: (model: Model<Api>) => Promise<string>;\n\tcandidateCache?: MemoryCandidateCache;\n}\n\nexport interface RecalledMemory {\n\tsource: MemoryCandidate[\"source\"];\n\tpath: string;\n\ttitle: string;\n\tcontent: string;\n\tscore: number;\n}\n\nexport interface RecallResult {\n\titems: RecalledMemory[];\n\trenderedText: string;\n}\n\nconst RERANK_SYSTEM_PROMPT = `You are selecting which memory snippets are most relevant to the current user turn.\n\nReturn strict JSON only:\n{\n \"selectedIds\": [\"candidate-id\"]\n}\n\nRules:\n- Select only snippets that are clearly useful for answering the current turn.\n- Prefer current work state, constraints, active files, recent corrections, and durable decisions.\n- If nothing is clearly useful, return an empty array.\n- Do not rewrite the candidates. Only return candidate ids.`;\n\nconst HAN_REGEX = /\\p{Script=Han}/u;\nconst TOKEN_PART_REGEX = /[\\p{Script=Han}]+|[\\p{L}\\p{N}_./-]+/gu;\nconst MEMORY_RECALL_RERANK_TIMEOUT_MS = 5_000;\n\nfunction containsHanText(text: string): boolean {\n\treturn HAN_REGEX.test(text);\n}\n\nfunction tokenizeHanPart(part: string): string[] {\n\tconst chars = Array.from(part);\n\tconst tokens: string[] = [];\n\tfor (const size of [2, 3]) {\n\t\tif (chars.length < size) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (let index = 0; index <= chars.length - size; index++) {\n\t\t\ttokens.push(chars.slice(index, index + size).join(\"\"));\n\t\t}\n\t}\n\treturn tokens;\n}\n\nfunction tokenize(text: string): string[] {\n\tconst parts = text.toLowerCase().match(TOKEN_PART_REGEX) ?? [];\n\tconst tokens: string[] = [];\n\tfor (const part of parts) {\n\t\tif (containsHanText(part)) {\n\t\t\ttokens.push(...tokenizeHanPart(part));\n\t\t\tcontinue;\n\t\t}\n\t\tif (part.length >= 2) {\n\t\t\ttokens.push(part);\n\t\t}\n\t}\n\treturn Array.from(new Set(tokens));\n}\n\nfunction computeTokenOverlapScore(queryTokens: string[], text: string, weight: number): number {\n\tconst haystack = new Set(tokenize(text));\n\tlet score = 0;\n\tfor (const token of queryTokens) {\n\t\tif (haystack.has(token)) {\n\t\t\tscore += weight;\n\t\t}\n\t}\n\treturn score;\n}\n\nfunction computeRecencyBoost(timestamp: string | undefined): number {\n\tif (!timestamp) return 0;\n\tconst timestampMs = Date.parse(timestamp);\n\tif (!Number.isFinite(timestampMs)) return 0;\n\n\tconst ageMs = Date.now() - timestampMs;\n\tconst dayMs = 24 * 60 * 60 * 1000;\n\tif (ageMs <= dayMs) return 8;\n\tif (ageMs <= 7 * dayMs) return 5;\n\tif (ageMs <= 30 * dayMs) return 2;\n\treturn 0;\n}\n\nfunction scoreCandidate(queryTokens: string[], candidate: MemoryCandidate): number {\n\tlet score = candidate.priority;\n\tscore += computeTokenOverlapScore(queryTokens, candidate.title, 10);\n\tscore += computeTokenOverlapScore(queryTokens, candidate.content, 3);\n\tscore += computeTokenOverlapScore(queryTokens, candidate.path, 6);\n\tscore += computeRecencyBoost(candidate.timestamp);\n\treturn score;\n}\n\nfunction buildFallbackCandidates(\n\trequest: RecallRequest,\n\tcandidates: MemoryCandidate[],\n\texisting: Array<{ candidate: MemoryCandidate; score: number }>,\n): Array<{ candidate: MemoryCandidate; score: number }> {\n\tif (!containsHanText(request.query) && existing.length > 0) {\n\t\treturn existing;\n\t}\n\n\tconst seen = new Set(existing.map(({ candidate }) => candidate.id));\n\tconst seeded = [...existing];\n\tconst limit = Math.max(request.maxCandidates, request.maxInjected);\n\n\tfor (const candidate of candidates\n\t\t.filter((item) => item.source === \"channel-session\" || item.source === \"channel-memory\")\n\t\t.sort((a, b) => b.priority - a.priority || a.title.localeCompare(b.title))) {\n\t\tif (seen.has(candidate.id)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseeded.push({ candidate, score: candidate.priority });\n\t\tseen.add(candidate.id);\n\t\tif (seeded.length >= limit) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn seeded;\n}\n\nasync function rerankCandidates(\n\trequest: RecallRequest,\n\tcandidates: Array<{ candidate: MemoryCandidate; score: number }>,\n): Promise<Array<{ candidate: MemoryCandidate; score: number }>> {\n\tif ((!request.rerankWithModel && !request.autoRerank) || candidates.length <= request.maxInjected) {\n\t\treturn candidates;\n\t}\n\n\tconst renderedCandidates = candidates\n\t\t.map(({ candidate, score }) => {\n\t\t\tconst clippedContent =\n\t\t\t\tcandidate.content.length > 300 ? `${candidate.content.slice(0, 300)}...` : candidate.content;\n\t\t\treturn [\n\t\t\t\t`id: ${candidate.id}`,\n\t\t\t\t`source: ${candidate.source}`,\n\t\t\t\t`title: ${candidate.title}`,\n\t\t\t\t`path: ${candidate.path}`,\n\t\t\t\t`score: ${score}`,\n\t\t\t\t`content: ${clippedContent}`,\n\t\t\t].join(\"\\n\");\n\t\t})\n\t\t.join(\"\\n\\n---\\n\\n\");\n\n\ttry {\n\t\tconst result = await runSidecarTask({\n\t\t\tname: \"memory-recall-rerank\",\n\t\t\tmodel: request.model,\n\t\t\tresolveApiKey: request.resolveApiKey,\n\t\t\tsystemPrompt: RERANK_SYSTEM_PROMPT,\n\t\t\tprompt: `User turn:\\n${request.query.trim()}\\n\\nCandidates:\\n${renderedCandidates}`,\n\t\t\ttimeoutMs: MEMORY_RECALL_RERANK_TIMEOUT_MS,\n\t\t\tparse: (text) => {\n\t\t\t\tconst parsed = parseJsonObject(text) as { selectedIds?: unknown };\n\t\t\t\treturn Array.isArray(parsed.selectedIds)\n\t\t\t\t\t? parsed.selectedIds.filter((id): id is string => typeof id === \"string\" && id.trim().length > 0)\n\t\t\t\t\t: [];\n\t\t\t},\n\t\t});\n\n\t\tconst selectedIds = new Set(result.output);\n\t\tif (selectedIds.size === 0) {\n\t\t\treturn candidates;\n\t\t}\n\n\t\tconst selected = candidates.filter(({ candidate }) => selectedIds.has(candidate.id));\n\t\treturn selected.length > 0 ? selected : candidates;\n\t} catch {\n\t\treturn candidates;\n\t}\n}\n\nfunction renderRecallResult(items: RecalledMemory[], maxChars: number): string {\n\tif (items.length === 0) {\n\t\treturn \"\";\n\t}\n\n\tconst lines: string[] = [\"<runtime_context>\", \"Relevant context for this turn:\"];\n\tfor (const item of items) {\n\t\tlines.push(\"\");\n\t\tlines.push(`[${item.source}/${item.title}]`);\n\t\tlines.push(`Path: ${item.path}`);\n\t\tlines.push(item.content);\n\t}\n\tlines.push(\"</runtime_context>\");\n\n\tconst rendered = lines.join(\"\\n\");\n\tif (rendered.length <= maxChars) {\n\t\treturn rendered;\n\t}\n\n\tconst clippedLines = [\"<runtime_context>\", \"Relevant context for this turn:\"];\n\tlet usedChars = clippedLines.join(\"\\n\").length + \"</runtime_context>\".length + 2;\n\tfor (const item of items) {\n\t\tconst block = [\"\", `[${item.source}/${item.title}]`, `Path: ${item.path}`, item.content].join(\"\\n\");\n\t\tif (usedChars + block.length > maxChars) {\n\t\t\tbreak;\n\t\t}\n\t\tclippedLines.push(\"\", `[${item.source}/${item.title}]`, `Path: ${item.path}`, item.content);\n\t\tusedChars += block.length;\n\t}\n\tclippedLines.push(\"</runtime_context>\");\n\treturn clippedLines.join(\"\\n\");\n}\n\nexport async function recallRelevantMemory(request: RecallRequest): Promise<RecallResult> {\n\tconst query = request.query.trim();\n\tif (!query) {\n\t\treturn { items: [], renderedText: \"\" };\n\t}\n\n\tconst candidates = await buildMemoryCandidates({\n\t\tworkspaceDir: request.workspaceDir,\n\t\tchannelDir: request.channelDir,\n\t\tcache: request.candidateCache,\n\t});\n\tconst filteredCandidates = request.allowedSources?.length\n\t\t? candidates.filter((candidate) => request.allowedSources?.includes(candidate.source))\n\t\t: candidates;\n\tif (filteredCandidates.length === 0) {\n\t\treturn { items: [], renderedText: \"\" };\n\t}\n\n\tconst queryTokens = tokenize(query);\n\tconst scored = filteredCandidates\n\t\t.map((candidate) => ({ candidate, score: scoreCandidate(queryTokens, candidate) }))\n\t\t.filter(({ score }) => score > 0)\n\t\t.sort((a, b) => b.score - a.score || a.candidate.title.localeCompare(b.candidate.title));\n\n\tconst shortlist = buildFallbackCandidates(request, filteredCandidates, scored)\n\t\t.sort(\n\t\t\t(a, b) =>\n\t\t\t\tb.score - a.score ||\n\t\t\t\tb.candidate.priority - a.candidate.priority ||\n\t\t\t\ta.candidate.title.localeCompare(b.candidate.title),\n\t\t)\n\t\t.slice(0, Math.max(request.maxCandidates, request.maxInjected));\n\n\tif (shortlist.length === 0) {\n\t\treturn { items: [], renderedText: \"\" };\n\t}\n\n\tconst reranked = await rerankCandidates(request, shortlist);\n\tconst items = reranked.slice(0, request.maxInjected).map(({ candidate, score }) => ({\n\t\tsource: candidate.source,\n\t\tpath: candidate.path,\n\t\ttitle: candidate.title,\n\t\tcontent: candidate.content,\n\t\tscore,\n\t}));\n\n\treturn {\n\t\titems,\n\t\trenderedText: renderRecallResult(items, request.maxChars),\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-utils.d.ts","sourceRoot":"","sources":["../src/model-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAY,KAAK,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAK5D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAE9D;AAED,wBAAgB,4BAA4B,CAC3C,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAC3B;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CA2C5C;AAED,wBAAgB,eAAe,CAC9B,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EACpC,KAAK,GAAE,MAAW,GAChB,MAAM,CAkBR;AAED,wBAAgB,mBAAmB,CAClC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,uBAAuB,GACtC,KAAK,CAAC,GAAG,CAAC,CAmBZ"
|
|
1
|
+
{"version":3,"file":"model-utils.d.ts","sourceRoot":"","sources":["../src/model-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAY,KAAK,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAK5D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAE9D;AAED,wBAAgB,4BAA4B,CAC3C,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAC3B;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CA2C5C;AAED,wBAAgB,eAAe,CAC9B,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EACpC,KAAK,GAAE,MAAW,GAChB,MAAM,CAkBR;AAED,wBAAgB,mBAAmB,CAClC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,uBAAuB,GACtC,KAAK,CAAC,GAAG,CAAC,CAmBZ"}
|
package/dist/model-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-utils.js","sourceRoot":"","sources":["../src/model-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,QAAQ,EAAc,MAAM,qBAAqB,CAAC;AAIrE,sFAAsF;AACtF,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;AAEhE,MAAM,UAAU,oBAAoB,CAAC,KAAiB
|
|
1
|
+
{"version":3,"file":"model-utils.js","sourceRoot":"","sources":["../src/model-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Api, getModel, type Model } from \"@mariozechner/pi-ai\";\nimport type { ModelRegistry } from \"@mariozechner/pi-coding-agent\";\nimport type { PipiclawSettingsManager } from \"./context.js\";\n\n// Default model - will be overridden by ModelRegistry if custom models are configured\nconst defaultModel = getModel(\"anthropic\", \"claude-sonnet-4-5\");\n\nexport function formatModelReference(model: Model<Api>): string {\n\treturn `${model.provider}/${model.id}`;\n}\n\nexport function findExactModelReferenceMatch(\n\tmodelReference: string,\n\tavailableModels: Model<Api>[],\n): { match?: Model<Api>; ambiguous: boolean } {\n\tconst trimmedReference = modelReference.trim();\n\tif (!trimmedReference) {\n\t\treturn { ambiguous: false };\n\t}\n\n\tconst normalizedReference = trimmedReference.toLowerCase();\n\n\tconst canonicalMatches = availableModels.filter(\n\t\t(model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,\n\t);\n\tif (canonicalMatches.length === 1) {\n\t\treturn { match: canonicalMatches[0], ambiguous: false };\n\t}\n\tif (canonicalMatches.length > 1) {\n\t\treturn { ambiguous: true };\n\t}\n\n\tconst slashIndex = trimmedReference.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = trimmedReference.substring(0, slashIndex).trim();\n\t\tconst modelId = trimmedReference.substring(slashIndex + 1).trim();\n\t\tif (provider && modelId) {\n\t\t\tconst providerMatches = availableModels.filter(\n\t\t\t\t(model) =>\n\t\t\t\t\tmodel.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\t\tmodel.id.toLowerCase() === modelId.toLowerCase(),\n\t\t\t);\n\t\t\tif (providerMatches.length === 1) {\n\t\t\t\treturn { match: providerMatches[0], ambiguous: false };\n\t\t\t}\n\t\t\tif (providerMatches.length > 1) {\n\t\t\t\treturn { ambiguous: true };\n\t\t\t}\n\t\t}\n\t}\n\n\tconst idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n\tif (idMatches.length === 1) {\n\t\treturn { match: idMatches[0], ambiguous: false };\n\t}\n\n\treturn { ambiguous: idMatches.length > 1 };\n}\n\nexport function formatModelList(\n\tmodels: Model<Api>[],\n\tcurrentModel: Model<Api> | undefined,\n\tlimit: number = 20,\n): string {\n\tconst refs = models\n\t\t.slice()\n\t\t.sort((a, b) => formatModelReference(a).localeCompare(formatModelReference(b)))\n\t\t.map((model) => {\n\t\t\tconst ref = formatModelReference(model);\n\t\t\tconst marker =\n\t\t\t\tcurrentModel && currentModel.provider === model.provider && currentModel.id === model.id\n\t\t\t\t\t? \" (current)\"\n\t\t\t\t\t: \"\";\n\t\t\treturn `- \\`${ref}\\`${marker}`;\n\t\t});\n\n\tif (refs.length <= limit) {\n\t\treturn refs.join(\"\\n\");\n\t}\n\n\treturn `${refs.slice(0, limit).join(\"\\n\")}\\n- ... and ${refs.length - limit} more`;\n}\n\nexport function resolveInitialModel(\n\tmodelRegistry: ModelRegistry,\n\tsettingsManager: PipiclawSettingsManager,\n): Model<Api> {\n\tconst savedProvider = settingsManager.getDefaultProvider();\n\tconst savedModelId = settingsManager.getDefaultModel();\n\tconst availableModels = modelRegistry.getAvailable();\n\tif (savedProvider && savedModelId) {\n\t\tconst savedModel = modelRegistry.find(savedProvider, savedModelId);\n\t\tif (\n\t\t\tsavedModel &&\n\t\t\tavailableModels.some((model) => model.provider === savedModel.provider && model.id === savedModel.id)\n\t\t) {\n\t\t\treturn savedModel;\n\t\t}\n\t}\n\n\tif (availableModels.length > 0) {\n\t\treturn availableModels[0];\n\t}\n\n\treturn defaultModel;\n}\n"]}
|
package/dist/paths.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,aAAa,CAAC;AACnC,eAAO,MAAM,YAAY,QAAmC,CAAC;AAC7D,eAAO,MAAM,aAAa,QAAkC,CAAC;AAC7D,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAChD,eAAO,MAAM,cAAc,QAA2C,CAAC;AACvE,eAAO,MAAM,mBAAmB,QAAqC,CAAC;AACtE,eAAO,MAAM,gBAAgB,QAAkC,CAAC;AAChE,eAAO,MAAM,kBAAkB,QAAoC,CAAC;AACpE,eAAO,MAAM,oBAAoB,QAAsC,CAAC"
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,aAAa,CAAC;AACnC,eAAO,MAAM,YAAY,QAAmC,CAAC;AAC7D,eAAO,MAAM,aAAa,QAAkC,CAAC;AAC7D,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAChD,eAAO,MAAM,cAAc,QAA2C,CAAC;AACvE,eAAO,MAAM,mBAAmB,QAAqC,CAAC;AACtE,eAAO,MAAM,gBAAgB,QAAkC,CAAC;AAChE,eAAO,MAAM,kBAAkB,QAAoC,CAAC;AACpE,eAAO,MAAM,oBAAoB,QAAsC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,yBAAyB;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,uBAAuB,CACtC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,EAC5B,OAAO,GAAE,yBAA8B,GACrC,MAAM,
|
|
1
|
+
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,yBAAyB;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,uBAAuB,CACtC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,EAC5B,OAAO,GAAE,yBAA8B,GACrC,MAAM,CAyJR"}
|
package/dist/prompt-builder.js
CHANGED
|
@@ -35,6 +35,7 @@ ${workspacePath}/
|
|
|
35
35
|
├── skills/ # Global CLI tools you create
|
|
36
36
|
├── events/ # Scheduled events
|
|
37
37
|
└── ${channelId}/ # This channel
|
|
38
|
+
├── SESSION.md # Channel working memory (runtime-managed, read on demand)
|
|
38
39
|
├── MEMORY.md # Channel durable memory (read on demand, runtime-managed)
|
|
39
40
|
├── HISTORY.md # Channel summarized history (read on demand, runtime-managed)
|
|
40
41
|
├── log.jsonl # Raw message archive (cold storage)
|
|
@@ -79,12 +80,16 @@ Memory files are not preloaded into session context. Read them explicitly when m
|
|
|
79
80
|
### Files
|
|
80
81
|
- Workspace memory: ${workspacePath}/MEMORY.md
|
|
81
82
|
Stable shared background memory. Admin-managed. Read on demand.
|
|
83
|
+
- Channel session memory: ${channelPath}/SESSION.md
|
|
84
|
+
Current working state for this channel. Runtime-managed. Read on demand. Prefer this when current task state matters.
|
|
82
85
|
- Channel memory: ${channelPath}/MEMORY.md
|
|
83
|
-
Durable channel memory. Runtime-managed via consolidation.
|
|
86
|
+
Durable channel memory. Runtime-managed via consolidation. Prefer this for stable facts, decisions, preferences, and medium-horizon open loops.
|
|
84
87
|
- Channel history: ${channelPath}/HISTORY.md
|
|
85
88
|
Summarized older channel history. Runtime-managed. Read on demand. Do not maintain this file manually during normal work.
|
|
86
89
|
|
|
87
90
|
### Runtime Behavior
|
|
91
|
+
- The runtime may inject a small amount of relevant memory context from SESSION.md / MEMORY.md / HISTORY.md into a turn when it is clearly useful.
|
|
92
|
+
- SESSION.md is the primary runtime-managed working-state artifact for current active work.
|
|
88
93
|
- The runtime automatically consolidates channel MEMORY.md and HISTORY.md before compaction or session trimming.
|
|
89
94
|
- Workspace MEMORY.md is not updated by normal runtime consolidation.
|
|
90
95
|
|
|
@@ -92,7 +97,7 @@ Memory files are not preloaded into session context. Read them explicitly when m
|
|
|
92
97
|
- ${channelPath}/log.jsonl is a raw archive. It is not normal memory and is not proactively loaded.
|
|
93
98
|
- ${channelPath}/context.jsonl is a raw session archive. It is not normal memory and is not proactively loaded.
|
|
94
99
|
|
|
95
|
-
When a task depends on prior decisions, preferences, or long-running work,
|
|
100
|
+
When a task depends on prior decisions, preferences, or long-running work, prefer SESSION.md first for current state, then MEMORY.md, then HISTORY.md.`);
|
|
96
101
|
sections.push(`## System Configuration Log
|
|
97
102
|
Maintain ${workspacePath}/SYSTEM.md to log all environment modifications:
|
|
98
103
|
- Installed packages (apk add, npm install, pip install)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,uBAAuB,CACtC,aAAqB,EACrB,SAAiB,EACjB,aAA4B,EAC5B,
|
|
1
|
+
{"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,uBAAuB,CACtC,aAAqB,EACrB,SAAiB,EACjB,aAA4B,EAC5B,UAAqC,EAAE;IAEvC,MAAM,WAAW,GAAG,GAAG,aAAa,IAAI,SAAS,EAAE,CAAC;IACpD,MAAM,aAAa,GAAG,GAAG,aAAa,aAAa,CAAC;IACpD,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,KAAK,QAAQ,CAAC;IAEjD,MAAM,cAAc,GAAG,QAAQ;QAC9B,CAAC,CAAC;;;uCAGmC;QACrC,CAAC,CAAC;4BACwB,OAAO,CAAC,GAAG,EAAE;uCACF,CAAC;IAEvC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;EAab,cAAc;;;EAGd,aAAa;;;;;;;MAOT,SAAS;;;;;;;0DAO2C,CAAC,CAAC;IAE3D,QAAQ,CAAC,IAAI,CAAC;wHACyG,aAAa;;;;;;sCAM/F,SAAS;;;;;qCAKV,SAAS;;;;;qCAKT,SAAS,qEAAqE,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,QAAQ;;;;;;;6BAOtI,aAAa;;;;;;;gCAOV,CAAC,CAAC;IAEjC,QAAQ,CAAC,IAAI,CAAC;;;;sBAIO,aAAa;;4BAEP,WAAW;;oBAEnB,WAAW;;qBAEV,WAAW;;;;;;;;;;IAU5B,WAAW;IACX,WAAW;;uJAEwI,CAAC,CAAC;IAExJ,QAAQ,CAAC,IAAI,CAAC;WACJ,aAAa;;;;;;sDAM8B,CAAC,CAAC;IAEvD,QAAQ,CAAC,IAAI,CAAC;;;;;;;wDAOyC,CAAC,CAAC;IAEzD,QAAQ,CAAC,IAAI,CAAC;;;;6CAI8B,aAAa;EACxD,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,qCAAqC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,uCAAuC;;;;;;;;;;;;;;;;;;;;;uFAqBvC,CAAC,CAAC;IAExF,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC","sourcesContent":["import type { SandboxConfig } from \"./sandbox.js\";\n\nexport interface AppendSystemPromptOptions {\n\tsubAgentList?: string;\n}\n\nexport function buildAppendSystemPrompt(\n\tworkspacePath: string,\n\tchannelId: string,\n\tsandboxConfig: SandboxConfig,\n\toptions: AppendSystemPromptOptions = {},\n): string {\n\tconst channelPath = `${workspacePath}/${channelId}`;\n\tconst subAgentsPath = `${workspacePath}/sub-agents`;\n\tconst isDocker = sandboxConfig.type === \"docker\";\n\n\tconst envDescription = isDocker\n\t\t? `You are running inside a Docker container (Alpine Linux).\n- Bash working directory: / (use cd or absolute paths)\n- Install tools with: apk add <package>\n- Your changes persist across sessions`\n\t\t: `You are running directly on the host machine.\n- Bash working directory: ${process.cwd()}\n- Be careful with system modifications`;\n\n\tconst sections: string[] = [];\n\n\tsections.push(`## Pipiclaw Runtime\nYou are running inside Pipiclaw, a DingTalk-oriented runtime built on top of pi.\n\n## Context\n- For current date/time, use: date\n- You have access to the active session context for this session.\n- Raw transcript files are cold storage. Do not assume they are preloaded.\n\n## Formatting\nUse Markdown for formatting. DingTalk AI Card supports basic Markdown:\nBold: **text**, Italic: *text*, Code: \\`code\\`, Block: \\`\\`\\`code\\`\\`\\`, Links: [text](url)\n\n## Environment\n${envDescription}\n\n## Workspace Layout\n${workspacePath}/\n├── SOUL.md # Your identity/personality (read-only)\n├── AGENTS.md # Custom behavior instructions (read-only)\n├── MEMORY.md # Stable workspace memory (admin-managed, read on demand)\n├── sub-agents/ # Predefined sub-agent definitions\n├── skills/ # Global CLI tools you create\n├── events/ # Scheduled events\n└── ${channelId}/ # This channel\n ├── SESSION.md # Channel working memory (runtime-managed, read on demand)\n ├── MEMORY.md # Channel durable memory (read on demand, runtime-managed)\n ├── HISTORY.md # Channel summarized history (read on demand, runtime-managed)\n ├── log.jsonl # Raw message archive (cold storage)\n ├── context.jsonl # Raw session archive (cold storage)\n ├── scratch/ # Your working directory\n └── skills/ # Channel-specific tools`);\n\n\tsections.push(`## Events\nYou can schedule events that wake you up at specific times or when external things happen. Events are JSON files in \\`${workspacePath}/events/\\`.\n\n### Event Types\n\n**Immediate** - Triggers as soon as harness sees the file.\n\\`\\`\\`json\n{\"type\": \"immediate\", \"channelId\": \"${channelId}\", \"text\": \"New event occurred\"}\n\\`\\`\\`\n\n**One-shot** - Triggers once at a specific time.\n\\`\\`\\`json\n{\"type\": \"one-shot\", \"channelId\": \"${channelId}\", \"text\": \"Reminder\", \"at\": \"2025-12-15T09:00:00+08:00\"}\n\\`\\`\\`\n\n**Periodic** - Triggers on a cron schedule.\n\\`\\`\\`json\n{\"type\": \"periodic\", \"channelId\": \"${channelId}\", \"text\": \"Check inbox\", \"schedule\": \"0 9 * * 1-5\", \"timezone\": \"${Intl.DateTimeFormat().resolvedOptions().timeZone}\"}\n\\`\\`\\`\n\n### Cron Format\n\\`minute hour day-of-month month day-of-week\\`\n\n### Creating Events\nCreate a JSON file under \\`${workspacePath}/events/\\` with the appropriate event payload.\nPrefer the file tools for creating or editing the event file. Use shell commands only when they are the clearest option.\n\n### Silent Completion\nFor periodic events where there's nothing to report, respond with just \\`[SILENT]\\`. This deletes the status message. Use this to avoid spam when periodic checks find nothing.\n\n### Limits\nMaximum 5 events can be queued.`);\n\n\tsections.push(`## Memory\nMemory files are not preloaded into session context. Read them explicitly when memory or history matters.\n\n### Files\n- Workspace memory: ${workspacePath}/MEMORY.md\n Stable shared background memory. Admin-managed. Read on demand.\n- Channel session memory: ${channelPath}/SESSION.md\n Current working state for this channel. Runtime-managed. Read on demand. Prefer this when current task state matters.\n- Channel memory: ${channelPath}/MEMORY.md\n Durable channel memory. Runtime-managed via consolidation. Prefer this for stable facts, decisions, preferences, and medium-horizon open loops.\n- Channel history: ${channelPath}/HISTORY.md\n Summarized older channel history. Runtime-managed. Read on demand. Do not maintain this file manually during normal work.\n\n### Runtime Behavior\n- The runtime may inject a small amount of relevant memory context from SESSION.md / MEMORY.md / HISTORY.md into a turn when it is clearly useful.\n- SESSION.md is the primary runtime-managed working-state artifact for current active work.\n- The runtime automatically consolidates channel MEMORY.md and HISTORY.md before compaction or session trimming.\n- Workspace MEMORY.md is not updated by normal runtime consolidation.\n\n### Cold Storage\n- ${channelPath}/log.jsonl is a raw archive. It is not normal memory and is not proactively loaded.\n- ${channelPath}/context.jsonl is a raw session archive. It is not normal memory and is not proactively loaded.\n\nWhen a task depends on prior decisions, preferences, or long-running work, prefer SESSION.md first for current state, then MEMORY.md, then HISTORY.md.`);\n\n\tsections.push(`## System Configuration Log\nMaintain ${workspacePath}/SYSTEM.md to log all environment modifications:\n- Installed packages (apk add, npm install, pip install)\n- Environment variables set\n- Config files modified\n- Skill dependencies installed\n\nUpdate this file whenever you modify the environment.`);\n\n\tsections.push(`## Tools\n- read: Read files\n- edit: Surgical file edits\n- write: Create or overwrite files when needed\n- bash: Run shell commands and external programs\n- subagent: Delegate a focused task to a sub-agent with its own isolated context\n\nEach tool requires a \"label\" parameter (shown to user).`);\n\n\tsections.push(`## Sub-Agents\nYou have a \\`subagent\\` tool for delegating focused work to a separate agent with an isolated context window.\n\n### Predefined Sub-Agents\nPredefined sub-agent definitions live in \\`${subAgentsPath}/\\`.\n${options.subAgentList ? `Available predefined sub-agents:\\n${options.subAgentList}` : \"Available predefined sub-agents: none\"}\n\n### Temporary Inline Sub-Agents\nIf no predefined sub-agent fits, you may define a temporary inline sub-agent directly in the \\`subagent\\` tool call by providing a focused \\`systemPrompt\\` plus optional tools, model, and budget settings.\n\nUse sub-agents when:\n- The task can be decomposed into a focused sub-problem\n- You need a fresh context for heavy file reading, shell work, or review\n- A specialized role would produce better results\n- The main conversation has grown long and you want to offload a bounded task\n\nDo not use sub-agents when:\n- The task is simple and direct\n- The task depends heavily on the full current conversation state\n- The task requires frequent user confirmation\n\nImportant rules:\n- Sub-agents cannot see your conversation history unless you include the needed context in \\`task\\`\n- The runtime injects a small fixed execution context (workspace path, channel id, sandbox), but you must still include task-specific context yourself\n- Sub-agents do not receive the \\`subagent\\` tool, so they cannot create nested agents\n- Prefer predefined sub-agents when one clearly fits\n- Use temporary inline sub-agents only when that extra flexibility is genuinely useful`);\n\n\treturn sections.join(\"\\n\\n\");\n}\n"]}
|
package/dist/sandbox.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAc5D;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B1E;AAoBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAK9D;AAED,MAAM,WAAW,QAAQ;IACxB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAElE;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3C;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb"
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAc5D;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B1E;AAoBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAK9D;AAED,MAAM,WAAW,QAAQ;IACxB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAElE;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3C;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb"}
|
package/dist/sandbox.js
CHANGED
package/dist/sandbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"child_process\";\nimport { shellEscape } from \"./shell-escape.js\";\n\nexport type SandboxConfig = { type: \"host\" } | { type: \"docker\"; container: string };\n\nexport function parseSandboxArg(value: string): SandboxConfig {\n\tif (value === \"host\") {\n\t\treturn { type: \"host\" };\n\t}\n\tif (value.startsWith(\"docker:\")) {\n\t\tconst container = value.slice(\"docker:\".length);\n\t\tif (!container) {\n\t\t\tconsole.error(\"Error: docker sandbox requires container name (e.g., docker:pipiclaw-sandbox)\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn { type: \"docker\", container };\n\t}\n\tconsole.error(`Error: Invalid sandbox type '${value}'. Use 'host' or 'docker:<container-name>'`);\n\tprocess.exit(1);\n}\n\nexport async function validateSandbox(config: SandboxConfig): Promise<void> {\n\tif (config.type === \"host\") {\n\t\treturn;\n\t}\n\n\t// Check if Docker is available\n\ttry {\n\t\tawait execSimple(\"docker\", [\"--version\"]);\n\t} catch {\n\t\tconsole.error(\"Error: Docker is not installed or not in PATH\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Check if container exists and is running\n\ttry {\n\t\tconst result = await execSimple(\"docker\", [\"inspect\", \"-f\", \"{{.State.Running}}\", config.container]);\n\t\tif (result.trim() !== \"true\") {\n\t\t\tconsole.error(`Error: Container '${config.container}' is not running.`);\n\t\t\tconsole.error(`Start it with: docker start ${config.container}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t} catch {\n\t\tconsole.error(`Error: Container '${config.container}' does not exist.`);\n\t\tconsole.error(\"Create it with: ./docker.sh create <data-dir>\");\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(` Docker container '${config.container}' is running.`);\n}\n\nfunction execSimple(cmd: string, args: string[]): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tchild.stdout?.on(\"data\", (d) => {\n\t\t\tstdout += d;\n\t\t});\n\t\tchild.stderr?.on(\"data\", (d) => {\n\t\t\tstderr += d;\n\t\t});\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (code === 0) resolve(stdout);\n\t\t\telse reject(new Error(stderr || `Exit code ${code}`));\n\t\t});\n\t});\n}\n\n/**\n * Create an executor that runs commands either on host or in Docker container\n */\nexport function createExecutor(config: SandboxConfig): Executor {\n\tif (config.type === \"host\") {\n\t\treturn new HostExecutor();\n\t}\n\treturn new DockerExecutor(config.container);\n}\n\nexport interface Executor {\n\t/**\n\t * Execute a bash command\n\t */\n\texec(command: string, options?: ExecOptions): Promise<ExecResult>;\n\n\t/**\n\t * Get the workspace path prefix for this executor\n\t * Host: returns the actual path\n\t * Docker: returns /workspace\n\t */\n\tgetWorkspacePath(hostPath: string): string;\n}\n\nexport interface ExecOptions {\n\ttimeout?: number;\n\tsignal?: AbortSignal;\n\tstdin?: string;\n}\n\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n}\n\nclass HostExecutor implements Executor {\n\tasync exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst shell = process.platform === \"win32\" ? \"cmd\" : \"sh\";\n\t\t\tconst shellArgs = process.platform === \"win32\" ? [\"/c\"] : [\"-c\"];\n\t\t\tconst child = (() => {\n\t\t\t\ttry {\n\t\t\t\t\treturn spawn(shell, [...shellArgs, command], {\n\t\t\t\t\t\tdetached: true,\n\t\t\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\treject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t})();\n\n\t\t\tif (!child) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet stdout = \"\";\n\t\t\tlet stderr = \"\";\n\t\t\tlet timedOut = false;\n\t\t\tlet settled = false;\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (options?.signal) {\n\t\t\t\t\toptions.signal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst rejectOnce = (err: Error) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tcleanup();\n\t\t\t\treject(err);\n\t\t\t};\n\n\t\t\tconst resolveOnce = (result: ExecResult) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tcleanup();\n\t\t\t\tresolve(result);\n\t\t\t};\n\n\t\t\tconst timeoutHandle =\n\t\t\t\toptions?.timeout && options.timeout > 0\n\t\t\t\t\t? setTimeout(() => {\n\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\tkillProcessTree(child.pid!);\n\t\t\t\t\t\t}, options.timeout * 1000)\n\t\t\t\t\t: undefined;\n\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\tif (options?.signal) {\n\t\t\t\tif (options.signal.aborted) {\n\t\t\t\t\tonAbort();\n\t\t\t\t} else {\n\t\t\t\t\toptions.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchild.stdout?.on(\"data\", (data) => {\n\t\t\t\tstdout += data.toString();\n\t\t\t\tif (stdout.length > 10 * 1024 * 1024) {\n\t\t\t\t\tstdout = stdout.slice(0, 10 * 1024 * 1024);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (data) => {\n\t\t\t\tstderr += data.toString();\n\t\t\t\tif (stderr.length > 10 * 1024 * 1024) {\n\t\t\t\t\tstderr = stderr.slice(0, 10 * 1024 * 1024);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\trejectOnce(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\n\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\trejectOnce(new Error(`${stdout}\\n${stderr}\\nCommand aborted`.trim()));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (timedOut) {\n\t\t\t\t\trejectOnce(\n\t\t\t\t\t\tnew Error(`${stdout}\\n${stderr}\\nCommand timed out after ${options?.timeout} seconds`.trim()),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresolveOnce({ stdout, stderr, code: code ?? 0 });\n\t\t\t});\n\n\t\t\tif (options?.stdin !== undefined) {\n\t\t\t\tchild.stdin?.on(\"error\", (err) => {\n\t\t\t\t\tif ((err as NodeJS.ErrnoException).code === \"EPIPE\") return;\n\t\t\t\t\trejectOnce(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t});\n\t\t\t\tchild.stdin?.end(options.stdin);\n\t\t\t} else {\n\t\t\t\tchild.stdin?.end();\n\t\t\t}\n\t\t});\n\t}\n\n\tgetWorkspacePath(hostPath: string): string {\n\t\treturn hostPath;\n\t}\n}\n\nclass DockerExecutor implements Executor {\n\tconstructor(private container: string) {}\n\n\tasync exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n\t\t// Wrap command for docker exec\n\t\tconst interactive = options?.stdin !== undefined ? \"-i \" : \"\";\n\t\tconst dockerCmd = `docker exec ${interactive}${this.container} sh -c ${shellEscape(command)}`;\n\t\tconst hostExecutor = new HostExecutor();\n\t\treturn hostExecutor.exec(dockerCmd, options);\n\t}\n\n\tgetWorkspacePath(_hostPath: string): string {\n\t\t// Docker container sees /workspace\n\t\treturn \"/workspace\";\n\t}\n}\n\nfunction killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\ttry {\n\t\t\tspawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\tdetached: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t} else {\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"child_process\";\nimport { shellEscape } from \"./shell-escape.js\";\n\nexport type SandboxConfig = { type: \"host\" } | { type: \"docker\"; container: string };\n\nexport function parseSandboxArg(value: string): SandboxConfig {\n\tif (value === \"host\") {\n\t\treturn { type: \"host\" };\n\t}\n\tif (value.startsWith(\"docker:\")) {\n\t\tconst container = value.slice(\"docker:\".length);\n\t\tif (!container) {\n\t\t\tconsole.error(\"Error: docker sandbox requires container name (e.g., docker:pipiclaw-sandbox)\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn { type: \"docker\", container };\n\t}\n\tconsole.error(`Error: Invalid sandbox type '${value}'. Use 'host' or 'docker:<container-name>'`);\n\tprocess.exit(1);\n}\n\nexport async function validateSandbox(config: SandboxConfig): Promise<void> {\n\tif (config.type === \"host\") {\n\t\treturn;\n\t}\n\n\t// Check if Docker is available\n\ttry {\n\t\tawait execSimple(\"docker\", [\"--version\"]);\n\t} catch {\n\t\tconsole.error(\"Error: Docker is not installed or not in PATH\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Check if container exists and is running\n\ttry {\n\t\tconst result = await execSimple(\"docker\", [\"inspect\", \"-f\", \"{{.State.Running}}\", config.container]);\n\t\tif (result.trim() !== \"true\") {\n\t\t\tconsole.error(`Error: Container '${config.container}' is not running.`);\n\t\t\tconsole.error(`Start it with: docker start ${config.container}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t} catch {\n\t\tconsole.error(`Error: Container '${config.container}' does not exist.`);\n\t\tconsole.error(\"Create it with: ./docker.sh create <data-dir>\");\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(` Docker container '${config.container}' is running.`);\n}\n\nfunction execSimple(cmd: string, args: string[]): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tchild.stdout?.on(\"data\", (d) => {\n\t\t\tstdout += d;\n\t\t});\n\t\tchild.stderr?.on(\"data\", (d) => {\n\t\t\tstderr += d;\n\t\t});\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (code === 0) resolve(stdout);\n\t\t\telse reject(new Error(stderr || `Exit code ${code}`));\n\t\t});\n\t});\n}\n\n/**\n * Create an executor that runs commands either on host or in Docker container\n */\nexport function createExecutor(config: SandboxConfig): Executor {\n\tif (config.type === \"host\") {\n\t\treturn new HostExecutor();\n\t}\n\treturn new DockerExecutor(config.container);\n}\n\nexport interface Executor {\n\t/**\n\t * Execute a bash command\n\t */\n\texec(command: string, options?: ExecOptions): Promise<ExecResult>;\n\n\t/**\n\t * Get the workspace path prefix for this executor\n\t * Host: returns the actual path\n\t * Docker: returns /workspace\n\t */\n\tgetWorkspacePath(hostPath: string): string;\n}\n\nexport interface ExecOptions {\n\ttimeout?: number;\n\tsignal?: AbortSignal;\n\tstdin?: string;\n}\n\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n}\n\nclass HostExecutor implements Executor {\n\tasync exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst shell = process.platform === \"win32\" ? \"cmd\" : \"sh\";\n\t\t\tconst shellArgs = process.platform === \"win32\" ? [\"/c\"] : [\"-c\"];\n\t\t\tconst child = (() => {\n\t\t\t\ttry {\n\t\t\t\t\treturn spawn(shell, [...shellArgs, command], {\n\t\t\t\t\t\tdetached: true,\n\t\t\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\treject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t})();\n\n\t\t\tif (!child) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet stdout = \"\";\n\t\t\tlet stderr = \"\";\n\t\t\tlet timedOut = false;\n\t\t\tlet settled = false;\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (options?.signal) {\n\t\t\t\t\toptions.signal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst rejectOnce = (err: Error) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tcleanup();\n\t\t\t\treject(err);\n\t\t\t};\n\n\t\t\tconst resolveOnce = (result: ExecResult) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tcleanup();\n\t\t\t\tresolve(result);\n\t\t\t};\n\n\t\t\tconst timeoutHandle =\n\t\t\t\toptions?.timeout && options.timeout > 0\n\t\t\t\t\t? setTimeout(() => {\n\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\tkillProcessTree(child.pid!);\n\t\t\t\t\t\t}, options.timeout * 1000)\n\t\t\t\t\t: undefined;\n\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\tif (options?.signal) {\n\t\t\t\tif (options.signal.aborted) {\n\t\t\t\t\tonAbort();\n\t\t\t\t} else {\n\t\t\t\t\toptions.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchild.stdout?.on(\"data\", (data) => {\n\t\t\t\tstdout += data.toString();\n\t\t\t\tif (stdout.length > 10 * 1024 * 1024) {\n\t\t\t\t\tstdout = stdout.slice(0, 10 * 1024 * 1024);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (data) => {\n\t\t\t\tstderr += data.toString();\n\t\t\t\tif (stderr.length > 10 * 1024 * 1024) {\n\t\t\t\t\tstderr = stderr.slice(0, 10 * 1024 * 1024);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\trejectOnce(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\n\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\trejectOnce(new Error(`${stdout}\\n${stderr}\\nCommand aborted`.trim()));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (timedOut) {\n\t\t\t\t\trejectOnce(\n\t\t\t\t\t\tnew Error(`${stdout}\\n${stderr}\\nCommand timed out after ${options?.timeout} seconds`.trim()),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresolveOnce({ stdout, stderr, code: code ?? 0 });\n\t\t\t});\n\n\t\t\tif (options?.stdin !== undefined) {\n\t\t\t\tchild.stdin?.on(\"error\", (err) => {\n\t\t\t\t\tif ((err as NodeJS.ErrnoException).code === \"EPIPE\") return;\n\t\t\t\t\trejectOnce(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t});\n\t\t\t\tchild.stdin?.end(options.stdin);\n\t\t\t} else {\n\t\t\t\tchild.stdin?.end();\n\t\t\t}\n\t\t});\n\t}\n\n\tgetWorkspacePath(hostPath: string): string {\n\t\treturn hostPath;\n\t}\n}\n\nclass DockerExecutor implements Executor {\n\tconstructor(private container: string) {}\n\n\tasync exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n\t\t// Wrap command for docker exec\n\t\tconst interactive = options?.stdin !== undefined ? \"-i \" : \"\";\n\t\tconst dockerCmd = `docker exec ${interactive}${this.container} sh -c ${shellEscape(command)}`;\n\t\tconst hostExecutor = new HostExecutor();\n\t\treturn hostExecutor.exec(dockerCmd, options);\n\t}\n\n\tgetWorkspacePath(_hostPath: string): string {\n\t\t// Docker container sees /workspace\n\t\treturn \"/workspace\";\n\t}\n}\n\nfunction killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\ttry {\n\t\t\tspawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\tdetached: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t} else {\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-memory-files.d.ts","sourceRoot":"","sources":["../src/session-memory-files.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-memory-files.js","sourceRoot":"","sources":["../src/session-memory-files.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,mBAAmB,CAAC","sourcesContent":["export {\n\tensureChannelMemoryFiles,\n\tensureChannelMemoryFilesSync,\n\tgetChannelSessionPath,\n\treadChannelSession,\n\trewriteChannelSession,\n} from \"./memory-files.js\";\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
|
2
|
+
import type { Api, Model } from "@mariozechner/pi-ai";
|
|
3
|
+
export interface SessionMemoryState {
|
|
4
|
+
title: string;
|
|
5
|
+
currentState: string[];
|
|
6
|
+
userIntent: string[];
|
|
7
|
+
activeFiles: string[];
|
|
8
|
+
decisions: string[];
|
|
9
|
+
constraints: string[];
|
|
10
|
+
errorsAndCorrections: string[];
|
|
11
|
+
nextSteps: string[];
|
|
12
|
+
worklog: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface SessionMemoryUpdateOptions {
|
|
15
|
+
channelDir: string;
|
|
16
|
+
messages: AgentMessage[];
|
|
17
|
+
model: Model<Api>;
|
|
18
|
+
resolveApiKey: (model: Model<Api>) => Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function renderSessionMemory(state: SessionMemoryState): string;
|
|
21
|
+
export declare function updateChannelSessionMemory(options: SessionMemoryUpdateOptions): Promise<SessionMemoryState>;
|
|
22
|
+
//# sourceMappingURL=session-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-memory.d.ts","sourceRoot":"","sources":["../src/session-memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,GAAG,EAAW,KAAK,EAAE,MAAM,qBAAqB,CAAC;AA2C/D,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,0BAA0B;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AA0LD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAyBrE;AAcD,wBAAsB,0BAA0B,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA4BjH"}
|