@openacp/cli 2026.328.2 → 2026.330.3
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/dist/{adapter-HGJENQCN.js → adapter-AWSI4GML.js} +4 -4
- package/dist/api-server-5VNYFWJE.js +7 -0
- package/dist/{api-server-WFB5K6FP.js → api-server-JLBDKCU4.js} +2 -2
- package/dist/{chunk-5TCXYDLR.js → chunk-237WYH6H.js} +26 -3
- package/dist/chunk-237WYH6H.js.map +1 -0
- package/dist/{chunk-E2SLHZAC.js → chunk-2HEFALTZ.js} +6 -6
- package/dist/{chunk-I53NEV3S.js → chunk-5WGVYX3C.js} +13 -3
- package/dist/chunk-5WGVYX3C.js.map +1 -0
- package/dist/{chunk-IXMIC4GQ.js → chunk-BTJHGSLM.js} +2 -2
- package/dist/{chunk-43JVXFYP.js → chunk-GEOXPGCO.js} +2 -2
- package/dist/{chunk-JUFN4XMB.js → chunk-KDU3ZEWT.js} +2 -2
- package/dist/{chunk-QWP76EBW.js → chunk-MITTQMGZ.js} +16 -9
- package/dist/chunk-MITTQMGZ.js.map +1 -0
- package/dist/{chunk-QBEQJFGL.js → chunk-MPGEHTGE.js} +3 -3
- package/dist/{chunk-4B6PCWQP.js → chunk-PA6MNBG4.js} +6 -2
- package/dist/chunk-PA6MNBG4.js.map +1 -0
- package/dist/{chunk-VD3QSMVY.js → chunk-QWVHCTCA.js} +2 -2
- package/dist/{chunk-NT6FYV27.js → chunk-TMVTSWVH.js} +2 -2
- package/dist/{chunk-6VR4GWOO.js → chunk-UCIZM5SW.js} +247 -70
- package/dist/chunk-UCIZM5SW.js.map +1 -0
- package/dist/chunk-UWH7KIAA.js +701 -0
- package/dist/chunk-UWH7KIAA.js.map +1 -0
- package/dist/{chunk-JOMDPFQ2.js → chunk-W4LK6WJP.js} +29 -4
- package/dist/chunk-W4LK6WJP.js.map +1 -0
- package/dist/{chunk-RXMWJHWH.js → chunk-XBZIHNKV.js} +733 -221
- package/dist/chunk-XBZIHNKV.js.map +1 -0
- package/dist/cli.js +63 -68
- package/dist/cli.js.map +1 -1
- package/dist/config-KN6NKKPF.js +20 -0
- package/dist/{config-editor-OU6PUY66.js → config-editor-76RVZS4B.js} +3 -3
- package/dist/context-NXXW62NJ.js +9 -0
- package/dist/{core-plugins-R2EVZAJV.js → core-plugins-BPZY7SEB.js} +9 -9
- package/dist/{daemon-DTA6KYYY.js → daemon-XFEMMJSZ.js} +3 -3
- package/dist/doctor-AV6AUO22.js +9 -0
- package/dist/index.d.ts +110 -44
- package/dist/index.js +8 -8
- package/dist/{main-RRSX5SRL.js → main-VEJCG5PY.js} +38 -30
- package/dist/main-VEJCG5PY.js.map +1 -0
- package/dist/{plugin-installer-5XHORMLS.js → plugin-installer-VSTYZSXC.js} +2 -2
- package/dist/{setup-OI6A3OXW.js → setup-DISPNDEK.js} +4 -5
- package/dist/setup-DISPNDEK.js.map +1 -0
- package/dist/speech-SG62JYIF.js +9 -0
- package/dist/telegram-L3YM6SQJ.js +7 -0
- package/dist/tunnel-HWJ27WDH.js +7 -0
- package/dist/{tunnel-service-I2NFUX3V.js → tunnel-service-ZMO4THKE.js} +88 -8
- package/dist/tunnel-service-ZMO4THKE.js.map +1 -0
- package/package.json +1 -1
- package/dist/api-server-DSUW637I.js +0 -7
- package/dist/chunk-4B6PCWQP.js.map +0 -1
- package/dist/chunk-5TCXYDLR.js.map +0 -1
- package/dist/chunk-6VR4GWOO.js.map +0 -1
- package/dist/chunk-I53NEV3S.js.map +0 -1
- package/dist/chunk-JOMDPFQ2.js.map +0 -1
- package/dist/chunk-QWP76EBW.js.map +0 -1
- package/dist/chunk-RXMWJHWH.js.map +0 -1
- package/dist/chunk-ZHGPZBS4.js +0 -49
- package/dist/chunk-ZHGPZBS4.js.map +0 -1
- package/dist/config-UCAFCS5W.js +0 -14
- package/dist/context-7MPU7RL5.js +0 -9
- package/dist/doctor-D723IB2I.js +0 -9
- package/dist/main-RRSX5SRL.js.map +0 -1
- package/dist/setup-OI6A3OXW.js.map +0 -1
- package/dist/speech-GB7PHVQZ.js +0 -9
- package/dist/telegram-UVIAXADE.js +0 -7
- package/dist/tunnel-4WNFC7GO.js +0 -7
- package/dist/tunnel-service-I2NFUX3V.js.map +0 -1
- /package/dist/{adapter-HGJENQCN.js.map → adapter-AWSI4GML.js.map} +0 -0
- /package/dist/{api-server-DSUW637I.js.map → api-server-5VNYFWJE.js.map} +0 -0
- /package/dist/{api-server-WFB5K6FP.js.map → api-server-JLBDKCU4.js.map} +0 -0
- /package/dist/{chunk-E2SLHZAC.js.map → chunk-2HEFALTZ.js.map} +0 -0
- /package/dist/{chunk-IXMIC4GQ.js.map → chunk-BTJHGSLM.js.map} +0 -0
- /package/dist/{chunk-43JVXFYP.js.map → chunk-GEOXPGCO.js.map} +0 -0
- /package/dist/{chunk-JUFN4XMB.js.map → chunk-KDU3ZEWT.js.map} +0 -0
- /package/dist/{chunk-QBEQJFGL.js.map → chunk-MPGEHTGE.js.map} +0 -0
- /package/dist/{chunk-VD3QSMVY.js.map → chunk-QWVHCTCA.js.map} +0 -0
- /package/dist/{chunk-NT6FYV27.js.map → chunk-TMVTSWVH.js.map} +0 -0
- /package/dist/{config-UCAFCS5W.js.map → config-KN6NKKPF.js.map} +0 -0
- /package/dist/{config-editor-OU6PUY66.js.map → config-editor-76RVZS4B.js.map} +0 -0
- /package/dist/{context-7MPU7RL5.js.map → context-NXXW62NJ.js.map} +0 -0
- /package/dist/{core-plugins-R2EVZAJV.js.map → core-plugins-BPZY7SEB.js.map} +0 -0
- /package/dist/{daemon-DTA6KYYY.js.map → daemon-XFEMMJSZ.js.map} +0 -0
- /package/dist/{doctor-D723IB2I.js.map → doctor-AV6AUO22.js.map} +0 -0
- /package/dist/{plugin-installer-5XHORMLS.js.map → plugin-installer-VSTYZSXC.js.map} +0 -0
- /package/dist/{speech-GB7PHVQZ.js.map → speech-SG62JYIF.js.map} +0 -0
- /package/dist/{telegram-UVIAXADE.js.map → telegram-L3YM6SQJ.js.map} +0 -0
- /package/dist/{tunnel-4WNFC7GO.js.map → tunnel-HWJ27WDH.js.map} +0 -0
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ContextManager,
|
|
3
|
+
EntireProvider
|
|
4
|
+
} from "./chunk-MITTQMGZ.js";
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_MAX_TOKENS,
|
|
7
|
+
TOKENS_PER_TURN_ESTIMATE
|
|
8
|
+
} from "./chunk-APS6UEFU.js";
|
|
9
|
+
|
|
10
|
+
// src/plugins/context/index.ts
|
|
11
|
+
import * as os from "os";
|
|
12
|
+
import * as path2 from "path";
|
|
13
|
+
|
|
14
|
+
// src/plugins/context/history/history-context-builder.ts
|
|
15
|
+
function selectLevel(turnCount) {
|
|
16
|
+
if (turnCount <= 10) return "full";
|
|
17
|
+
if (turnCount <= 25) return "balanced";
|
|
18
|
+
return "compact";
|
|
19
|
+
}
|
|
20
|
+
function estimateTokens(text) {
|
|
21
|
+
return Math.floor(text.length / 4);
|
|
22
|
+
}
|
|
23
|
+
function buildHistoryMarkdown(turns, mode) {
|
|
24
|
+
if (turns.length === 0) return "";
|
|
25
|
+
switch (mode) {
|
|
26
|
+
case "full":
|
|
27
|
+
return buildFull(turns);
|
|
28
|
+
case "balanced":
|
|
29
|
+
return buildBalanced(turns);
|
|
30
|
+
case "compact":
|
|
31
|
+
return buildCompact(turns);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function buildFull(turns) {
|
|
35
|
+
const out = [];
|
|
36
|
+
let userIndex = 0;
|
|
37
|
+
for (const turn of turns) {
|
|
38
|
+
if (turn.role === "user") {
|
|
39
|
+
userIndex++;
|
|
40
|
+
out.push(`**User [${userIndex}]:**`);
|
|
41
|
+
out.push(turn.content ?? "");
|
|
42
|
+
if (turn.attachments?.length) {
|
|
43
|
+
out.push(turn.attachments.map((a) => `[${a.type}: ${a.fileName}]`).join(" "));
|
|
44
|
+
}
|
|
45
|
+
out.push("");
|
|
46
|
+
} else if (turn.role === "assistant" && turn.steps?.length) {
|
|
47
|
+
out.push("**Assistant:**");
|
|
48
|
+
for (const step of turn.steps) {
|
|
49
|
+
out.push(renderStepFull(step));
|
|
50
|
+
}
|
|
51
|
+
if (turn.usage) {
|
|
52
|
+
const parts = [];
|
|
53
|
+
if (turn.usage.tokensUsed) parts.push(`${turn.usage.tokensUsed.toLocaleString()} tokens`);
|
|
54
|
+
if (turn.usage.cost) parts.push(`$${turn.usage.cost.amount.toFixed(4)}`);
|
|
55
|
+
if (parts.length) out.push(`**Usage**: ${parts.join(", ")}`);
|
|
56
|
+
}
|
|
57
|
+
out.push("");
|
|
58
|
+
out.push("---");
|
|
59
|
+
out.push("");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return out.join("\n");
|
|
63
|
+
}
|
|
64
|
+
function renderStepFull(step) {
|
|
65
|
+
switch (step.type) {
|
|
66
|
+
case "thinking":
|
|
67
|
+
return `> **Thinking**: ${step.content}
|
|
68
|
+
`;
|
|
69
|
+
case "text":
|
|
70
|
+
return `${step.content}
|
|
71
|
+
`;
|
|
72
|
+
case "tool_call":
|
|
73
|
+
return renderToolCallFull(step);
|
|
74
|
+
case "plan":
|
|
75
|
+
return renderPlan(step.entries);
|
|
76
|
+
case "image":
|
|
77
|
+
return `[Image: ${step.mimeType}]
|
|
78
|
+
`;
|
|
79
|
+
case "audio":
|
|
80
|
+
return `[Audio: ${step.mimeType}]
|
|
81
|
+
`;
|
|
82
|
+
case "resource":
|
|
83
|
+
return `[Resource: ${step.name}] ${step.uri}
|
|
84
|
+
`;
|
|
85
|
+
case "resource_link":
|
|
86
|
+
return `[Resource Link: ${step.name}] ${step.uri}
|
|
87
|
+
`;
|
|
88
|
+
case "mode_change":
|
|
89
|
+
return `*Mode changed to: ${step.modeId}*
|
|
90
|
+
`;
|
|
91
|
+
case "config_change":
|
|
92
|
+
return `*Config ${step.configId} set to: ${step.value}*
|
|
93
|
+
`;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function renderToolCallFull(step) {
|
|
97
|
+
const lines = [];
|
|
98
|
+
const loc = step.locations?.[0];
|
|
99
|
+
const locStr = loc ? loc.line ? `${loc.path}:${loc.line}` : loc.path : "";
|
|
100
|
+
if (step.diff) {
|
|
101
|
+
lines.push(`**[${step.name}]** \`${locStr || step.diff.path}\``);
|
|
102
|
+
lines.push("```diff");
|
|
103
|
+
if (step.diff.oldText) {
|
|
104
|
+
for (const line of step.diff.oldText.split("\n")) lines.push(`- ${line}`);
|
|
105
|
+
}
|
|
106
|
+
for (const line of step.diff.newText.split("\n")) lines.push(`+ ${line}`);
|
|
107
|
+
lines.push("```");
|
|
108
|
+
} else {
|
|
109
|
+
lines.push(`**[${step.name}]** \`${locStr}\``);
|
|
110
|
+
}
|
|
111
|
+
if (step.permission) {
|
|
112
|
+
lines.push(`*Permission: ${step.permission.outcome}*`);
|
|
113
|
+
}
|
|
114
|
+
lines.push("");
|
|
115
|
+
return lines.join("\n");
|
|
116
|
+
}
|
|
117
|
+
function renderPlan(entries) {
|
|
118
|
+
const lines = ["**Plan:**"];
|
|
119
|
+
for (const e of entries) {
|
|
120
|
+
const icon = e.status === "completed" || e.status === "done" ? "\u2705" : e.status === "in_progress" ? "\u{1F504}" : "\u2B1C";
|
|
121
|
+
lines.push(`${icon} ${e.content} (${e.priority})`);
|
|
122
|
+
}
|
|
123
|
+
lines.push("");
|
|
124
|
+
return lines.join("\n");
|
|
125
|
+
}
|
|
126
|
+
function buildBalanced(turns) {
|
|
127
|
+
const out = [];
|
|
128
|
+
let userIndex = 0;
|
|
129
|
+
for (const turn of turns) {
|
|
130
|
+
if (turn.role === "user") {
|
|
131
|
+
userIndex++;
|
|
132
|
+
out.push(`**User [${userIndex}]:**`);
|
|
133
|
+
out.push(turn.content ?? "");
|
|
134
|
+
out.push("");
|
|
135
|
+
} else if (turn.role === "assistant" && turn.steps?.length) {
|
|
136
|
+
out.push("**Assistant:**");
|
|
137
|
+
for (const step of turn.steps) {
|
|
138
|
+
if (step.type === "thinking") continue;
|
|
139
|
+
if (step.type === "text") {
|
|
140
|
+
out.push(step.content);
|
|
141
|
+
} else if (step.type === "tool_call") {
|
|
142
|
+
out.push(renderToolCallBalanced(step));
|
|
143
|
+
} else if (step.type === "plan") {
|
|
144
|
+
out.push(renderPlan(step.entries));
|
|
145
|
+
} else {
|
|
146
|
+
out.push(renderStepFull(step));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
out.push("");
|
|
150
|
+
out.push("---");
|
|
151
|
+
out.push("");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return out.join("\n");
|
|
155
|
+
}
|
|
156
|
+
function renderToolCallBalanced(step) {
|
|
157
|
+
const loc = step.locations?.[0];
|
|
158
|
+
const locStr = loc ? loc.line ? `${loc.path}:${loc.line}` : loc.path : "";
|
|
159
|
+
if (step.diff) {
|
|
160
|
+
const oldLines = step.diff.oldText?.split("\n").length ?? 0;
|
|
161
|
+
const newLines = step.diff.newText.split("\n").length;
|
|
162
|
+
return `- ${step.name} \`${locStr || step.diff.path}\` (-${oldLines}/+${newLines} lines)`;
|
|
163
|
+
}
|
|
164
|
+
return `- ${step.name} \`${locStr}\``;
|
|
165
|
+
}
|
|
166
|
+
function buildCompact(turns) {
|
|
167
|
+
const out = [];
|
|
168
|
+
let i = 0;
|
|
169
|
+
while (i < turns.length) {
|
|
170
|
+
const turn = turns[i];
|
|
171
|
+
if (turn.role === "user") {
|
|
172
|
+
const userText = (turn.content ?? "").slice(0, 100);
|
|
173
|
+
const nextTurn = turns[i + 1];
|
|
174
|
+
if (nextTurn?.role === "assistant" && nextTurn.steps?.length) {
|
|
175
|
+
const tools = nextTurn.steps.filter((s) => s.type === "tool_call").map((s) => s.name);
|
|
176
|
+
const texts = nextTurn.steps.filter((s) => s.type === "text").map((s) => s.content.slice(0, 80));
|
|
177
|
+
const parts = [];
|
|
178
|
+
if (tools.length) parts.push(tools.join(", "));
|
|
179
|
+
if (texts.length) parts.push(texts.join(" "));
|
|
180
|
+
out.push(`User: ${userText} \u2192 Assistant: ${parts.join(" | ")}`);
|
|
181
|
+
i += 2;
|
|
182
|
+
} else {
|
|
183
|
+
out.push(`User: ${userText}`);
|
|
184
|
+
i++;
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
i++;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return out.join("\n");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/plugins/context/history/history-provider.ts
|
|
194
|
+
var EMPTY_RESULT = {
|
|
195
|
+
markdown: "",
|
|
196
|
+
tokenEstimate: 0,
|
|
197
|
+
sessionCount: 0,
|
|
198
|
+
totalTurns: 0,
|
|
199
|
+
mode: "full",
|
|
200
|
+
truncated: false,
|
|
201
|
+
timeRange: { start: "", end: "" }
|
|
202
|
+
};
|
|
203
|
+
var HistoryProvider = class {
|
|
204
|
+
constructor(store, getSessionRecords) {
|
|
205
|
+
this.store = store;
|
|
206
|
+
this.getSessionRecords = getSessionRecords;
|
|
207
|
+
}
|
|
208
|
+
name = "local";
|
|
209
|
+
async isAvailable(_repoPath) {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
async listSessions(query) {
|
|
213
|
+
if (!this.isSupportedType(query.type)) {
|
|
214
|
+
return { sessions: [], estimatedTokens: 0 };
|
|
215
|
+
}
|
|
216
|
+
const candidates = await this.resolveCandidates(query);
|
|
217
|
+
const sessions = [];
|
|
218
|
+
let estimatedTokens = 0;
|
|
219
|
+
for (const record of candidates) {
|
|
220
|
+
const history = await this.store.read(record.sessionId);
|
|
221
|
+
if (!history) continue;
|
|
222
|
+
const turnCount = history.turns.length;
|
|
223
|
+
const tokenEstimate = turnCount * TOKENS_PER_TURN_ESTIMATE;
|
|
224
|
+
sessions.push(this.toSessionInfo(record, turnCount));
|
|
225
|
+
estimatedTokens += tokenEstimate;
|
|
226
|
+
}
|
|
227
|
+
return { sessions, estimatedTokens };
|
|
228
|
+
}
|
|
229
|
+
async buildContext(query, options) {
|
|
230
|
+
if (!this.isSupportedType(query.type)) {
|
|
231
|
+
return { ...EMPTY_RESULT };
|
|
232
|
+
}
|
|
233
|
+
const maxTokens = options?.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
234
|
+
const candidates = await this.resolveCandidates(query, options?.limit);
|
|
235
|
+
const loaded = [];
|
|
236
|
+
for (const record of candidates) {
|
|
237
|
+
const history = await this.store.read(record.sessionId);
|
|
238
|
+
if (history) {
|
|
239
|
+
loaded.push({ record, history });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (loaded.length === 0) {
|
|
243
|
+
return { ...EMPTY_RESULT };
|
|
244
|
+
}
|
|
245
|
+
const totalTurns = loaded.reduce((sum, s) => sum + s.history.turns.length, 0);
|
|
246
|
+
let mode = selectLevel(totalTurns);
|
|
247
|
+
let markdown = this.buildMergedMarkdown(loaded, mode, query);
|
|
248
|
+
let tokenEstimate = estimateTokens(markdown);
|
|
249
|
+
if (tokenEstimate > maxTokens && mode !== "compact") {
|
|
250
|
+
mode = "compact";
|
|
251
|
+
markdown = this.buildMergedMarkdown(loaded, mode, query);
|
|
252
|
+
tokenEstimate = estimateTokens(markdown);
|
|
253
|
+
}
|
|
254
|
+
let truncated = false;
|
|
255
|
+
let activeSessions = [...loaded];
|
|
256
|
+
while (tokenEstimate > maxTokens && activeSessions.length > 1) {
|
|
257
|
+
activeSessions = activeSessions.slice(0, activeSessions.length - 1);
|
|
258
|
+
markdown = this.buildMergedMarkdown(activeSessions, mode, query);
|
|
259
|
+
tokenEstimate = estimateTokens(markdown);
|
|
260
|
+
truncated = true;
|
|
261
|
+
}
|
|
262
|
+
const timeRange = this.computeTimeRange(activeSessions.map((s) => s.record));
|
|
263
|
+
return {
|
|
264
|
+
markdown,
|
|
265
|
+
tokenEstimate,
|
|
266
|
+
sessionCount: activeSessions.length,
|
|
267
|
+
totalTurns: activeSessions.reduce((sum, s) => sum + s.history.turns.length, 0),
|
|
268
|
+
mode,
|
|
269
|
+
truncated,
|
|
270
|
+
timeRange
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// ─── Private helpers ─────────────────────────────────────────────────────────
|
|
274
|
+
isSupportedType(type) {
|
|
275
|
+
return type === "session" || type === "latest";
|
|
276
|
+
}
|
|
277
|
+
async resolveCandidates(query, limit) {
|
|
278
|
+
const all = this.getSessionRecords();
|
|
279
|
+
if (query.type === "session") {
|
|
280
|
+
const found = all.find((r) => r.sessionId === query.value);
|
|
281
|
+
return found ? [found] : [];
|
|
282
|
+
}
|
|
283
|
+
const n = limit ?? (parseInt(query.value, 10) || 5);
|
|
284
|
+
const sorted = [...all].sort(
|
|
285
|
+
(a, b) => new Date(b.lastActiveAt).getTime() - new Date(a.lastActiveAt).getTime()
|
|
286
|
+
);
|
|
287
|
+
return sorted.slice(0, n);
|
|
288
|
+
}
|
|
289
|
+
toSessionInfo(record, turnCount) {
|
|
290
|
+
return {
|
|
291
|
+
checkpointId: "",
|
|
292
|
+
sessionIndex: "",
|
|
293
|
+
transcriptPath: "",
|
|
294
|
+
createdAt: record.createdAt,
|
|
295
|
+
endedAt: record.lastActiveAt,
|
|
296
|
+
branch: "",
|
|
297
|
+
agent: record.agentName,
|
|
298
|
+
turnCount,
|
|
299
|
+
filesTouched: [],
|
|
300
|
+
sessionId: record.sessionId
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
buildMergedMarkdown(sessions, mode, query) {
|
|
304
|
+
if (sessions.length === 0) return "";
|
|
305
|
+
const totalTurns = sessions.reduce((sum, s) => sum + s.history.turns.length, 0);
|
|
306
|
+
const title = query.type === "session" ? query.value : `latest ${sessions.length} sessions`;
|
|
307
|
+
const parts = [];
|
|
308
|
+
parts.push(`# Conversation History \u2014 ${title}`);
|
|
309
|
+
parts.push(`${sessions.length} sessions | ${totalTurns} turns | mode: ${mode}`);
|
|
310
|
+
parts.push("");
|
|
311
|
+
for (let i = 0; i < sessions.length; i++) {
|
|
312
|
+
const { record, history } = sessions[i];
|
|
313
|
+
const sessionMd = buildHistoryMarkdown(history.turns, mode);
|
|
314
|
+
parts.push(`## Session ${i + 1} \u2014 ${record.agentName} \xB7 ${record.sessionId} (${history.turns.length} turns)`);
|
|
315
|
+
parts.push("");
|
|
316
|
+
if (sessionMd) {
|
|
317
|
+
parts.push(sessionMd);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
parts.push(
|
|
321
|
+
"> **Note:** This conversation history may contain outdated information. Verify current state before acting on past context."
|
|
322
|
+
);
|
|
323
|
+
return parts.join("\n");
|
|
324
|
+
}
|
|
325
|
+
computeTimeRange(records) {
|
|
326
|
+
if (records.length === 0) return { start: "", end: "" };
|
|
327
|
+
const dates = records.map((r) => r.createdAt).filter(Boolean);
|
|
328
|
+
const ends = records.map((r) => r.lastActiveAt).filter(Boolean);
|
|
329
|
+
const start = dates.sort()[0] ?? "";
|
|
330
|
+
const end = ends.sort().reverse()[0] ?? "";
|
|
331
|
+
return { start, end };
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// src/plugins/context/history/history-recorder.ts
|
|
336
|
+
function toHistoryAttachment(att) {
|
|
337
|
+
return {
|
|
338
|
+
type: att.type,
|
|
339
|
+
fileName: att.fileName,
|
|
340
|
+
mimeType: att.mimeType,
|
|
341
|
+
size: att.size
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function extractDiff(content) {
|
|
345
|
+
if (!Array.isArray(content)) return null;
|
|
346
|
+
for (const item of content) {
|
|
347
|
+
if (item && typeof item === "object" && item.type === "diff") {
|
|
348
|
+
const d = item;
|
|
349
|
+
if (typeof d.path === "string" && typeof d.newText === "string") {
|
|
350
|
+
const result = {
|
|
351
|
+
path: d.path,
|
|
352
|
+
newText: d.newText
|
|
353
|
+
};
|
|
354
|
+
if (typeof d.oldText === "string") result.oldText = d.oldText;
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
function extractLocations(locations) {
|
|
362
|
+
if (!Array.isArray(locations)) return void 0;
|
|
363
|
+
const result = [];
|
|
364
|
+
for (const loc of locations) {
|
|
365
|
+
if (loc && typeof loc === "object" && typeof loc.path === "string") {
|
|
366
|
+
const entry = { path: loc.path };
|
|
367
|
+
if (typeof loc.line === "number") entry.line = loc.line;
|
|
368
|
+
result.push(entry);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return result.length > 0 ? result : void 0;
|
|
372
|
+
}
|
|
373
|
+
var IGNORED_TYPES = /* @__PURE__ */ new Set([
|
|
374
|
+
"session_end",
|
|
375
|
+
"error",
|
|
376
|
+
"system_message",
|
|
377
|
+
"commands_update",
|
|
378
|
+
"session_info_update",
|
|
379
|
+
"model_update",
|
|
380
|
+
"user_message_chunk",
|
|
381
|
+
"tts_strip"
|
|
382
|
+
]);
|
|
383
|
+
var HistoryRecorder = class {
|
|
384
|
+
constructor(store) {
|
|
385
|
+
this.store = store;
|
|
386
|
+
}
|
|
387
|
+
states = /* @__PURE__ */ new Map();
|
|
388
|
+
onBeforePrompt(sessionId, text, attachments) {
|
|
389
|
+
let state = this.states.get(sessionId);
|
|
390
|
+
if (!state) {
|
|
391
|
+
state = {
|
|
392
|
+
history: { version: 1, sessionId, turns: [] },
|
|
393
|
+
currentAssistantTurn: null
|
|
394
|
+
};
|
|
395
|
+
this.states.set(sessionId, state);
|
|
396
|
+
}
|
|
397
|
+
const userTurn = {
|
|
398
|
+
index: state.history.turns.length,
|
|
399
|
+
role: "user",
|
|
400
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
401
|
+
content: text
|
|
402
|
+
};
|
|
403
|
+
if (attachments && attachments.length > 0) {
|
|
404
|
+
userTurn.attachments = attachments.map(toHistoryAttachment);
|
|
405
|
+
}
|
|
406
|
+
state.history.turns.push(userTurn);
|
|
407
|
+
const assistantTurn = {
|
|
408
|
+
index: state.history.turns.length,
|
|
409
|
+
role: "assistant",
|
|
410
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
411
|
+
steps: []
|
|
412
|
+
};
|
|
413
|
+
state.history.turns.push(assistantTurn);
|
|
414
|
+
state.currentAssistantTurn = assistantTurn;
|
|
415
|
+
}
|
|
416
|
+
onAfterEvent(sessionId, event) {
|
|
417
|
+
const state = this.states.get(sessionId);
|
|
418
|
+
if (!state || !state.currentAssistantTurn) return;
|
|
419
|
+
const turn = state.currentAssistantTurn;
|
|
420
|
+
const steps = turn.steps;
|
|
421
|
+
if (IGNORED_TYPES.has(event.type)) return;
|
|
422
|
+
switch (event.type) {
|
|
423
|
+
case "text": {
|
|
424
|
+
const last = steps[steps.length - 1];
|
|
425
|
+
if (last && last.type === "text") {
|
|
426
|
+
last.content += event.content;
|
|
427
|
+
} else {
|
|
428
|
+
steps.push({ type: "text", content: event.content });
|
|
429
|
+
}
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
case "thought": {
|
|
433
|
+
const last = steps[steps.length - 1];
|
|
434
|
+
if (last && last.type === "thinking") {
|
|
435
|
+
last.content += event.content;
|
|
436
|
+
} else {
|
|
437
|
+
steps.push({ type: "thinking", content: event.content });
|
|
438
|
+
}
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
case "tool_call": {
|
|
442
|
+
const step = {
|
|
443
|
+
type: "tool_call",
|
|
444
|
+
id: event.id,
|
|
445
|
+
name: event.name,
|
|
446
|
+
status: event.status
|
|
447
|
+
};
|
|
448
|
+
if (event.kind) step.kind = event.kind;
|
|
449
|
+
steps.push(step);
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
case "tool_update": {
|
|
453
|
+
const existing = this.findToolCall(steps, event.id);
|
|
454
|
+
if (!existing) break;
|
|
455
|
+
existing.status = event.status;
|
|
456
|
+
if (event.rawInput !== void 0) existing.input = event.rawInput;
|
|
457
|
+
if (event.rawOutput !== void 0) existing.output = event.rawOutput;
|
|
458
|
+
if (event.content !== void 0) {
|
|
459
|
+
const diff = extractDiff(event.content);
|
|
460
|
+
if (diff) existing.diff = diff;
|
|
461
|
+
}
|
|
462
|
+
if (event.locations !== void 0) {
|
|
463
|
+
const locs = extractLocations(event.locations);
|
|
464
|
+
if (locs) existing.locations = locs;
|
|
465
|
+
}
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
case "plan": {
|
|
469
|
+
steps.push({
|
|
470
|
+
type: "plan",
|
|
471
|
+
entries: event.entries.map((e) => ({
|
|
472
|
+
content: e.content,
|
|
473
|
+
priority: e.priority,
|
|
474
|
+
status: e.status
|
|
475
|
+
}))
|
|
476
|
+
});
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case "usage": {
|
|
480
|
+
turn.usage = {};
|
|
481
|
+
if (event.tokensUsed !== void 0) turn.usage.tokensUsed = event.tokensUsed;
|
|
482
|
+
if (event.contextSize !== void 0) turn.usage.contextSize = event.contextSize;
|
|
483
|
+
if (event.cost) turn.usage.cost = event.cost;
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
case "image_content": {
|
|
487
|
+
steps.push({
|
|
488
|
+
type: "image",
|
|
489
|
+
mimeType: event.mimeType,
|
|
490
|
+
filePath: ""
|
|
491
|
+
});
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
case "audio_content": {
|
|
495
|
+
steps.push({
|
|
496
|
+
type: "audio",
|
|
497
|
+
mimeType: event.mimeType,
|
|
498
|
+
filePath: ""
|
|
499
|
+
});
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
case "resource_content": {
|
|
503
|
+
const step = {
|
|
504
|
+
type: "resource",
|
|
505
|
+
uri: event.uri,
|
|
506
|
+
name: event.name
|
|
507
|
+
};
|
|
508
|
+
if (event.text !== void 0) step.text = event.text;
|
|
509
|
+
steps.push(step);
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
case "resource_link": {
|
|
513
|
+
const step = {
|
|
514
|
+
type: "resource_link",
|
|
515
|
+
uri: event.uri,
|
|
516
|
+
name: event.name
|
|
517
|
+
};
|
|
518
|
+
if (event.title !== void 0) step.title = event.title;
|
|
519
|
+
if (event.description !== void 0)
|
|
520
|
+
step.description = event.description;
|
|
521
|
+
steps.push(step);
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
case "current_mode_update": {
|
|
525
|
+
steps.push({ type: "mode_change", modeId: event.modeId });
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
case "config_option_update": {
|
|
529
|
+
for (const opt of event.options) {
|
|
530
|
+
steps.push({
|
|
531
|
+
type: "config_change",
|
|
532
|
+
configId: opt.id,
|
|
533
|
+
value: String(opt.currentValue)
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
onPermissionResolved(sessionId, requestId, decision) {
|
|
541
|
+
const state = this.states.get(sessionId);
|
|
542
|
+
if (!state || !state.currentAssistantTurn) return;
|
|
543
|
+
const step = this.findToolCall(state.currentAssistantTurn.steps, requestId);
|
|
544
|
+
if (!step) return;
|
|
545
|
+
step.permission = { requested: true, outcome: decision };
|
|
546
|
+
}
|
|
547
|
+
async onTurnEnd(sessionId, stopReason) {
|
|
548
|
+
const state = this.states.get(sessionId);
|
|
549
|
+
if (!state || !state.currentAssistantTurn) return;
|
|
550
|
+
state.currentAssistantTurn.stopReason = stopReason;
|
|
551
|
+
state.currentAssistantTurn = null;
|
|
552
|
+
await this.store.write(state.history);
|
|
553
|
+
}
|
|
554
|
+
finalize(sessionId) {
|
|
555
|
+
this.states.delete(sessionId);
|
|
556
|
+
}
|
|
557
|
+
getState(sessionId) {
|
|
558
|
+
return this.states.get(sessionId);
|
|
559
|
+
}
|
|
560
|
+
findToolCall(steps, id) {
|
|
561
|
+
for (let i = steps.length - 1; i >= 0; i--) {
|
|
562
|
+
const s = steps[i];
|
|
563
|
+
if (s.type === "tool_call" && s.id === id) return s;
|
|
564
|
+
}
|
|
565
|
+
return void 0;
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
// src/plugins/context/history/history-store.ts
|
|
570
|
+
import fs from "fs";
|
|
571
|
+
import path from "path";
|
|
572
|
+
var HistoryStore = class {
|
|
573
|
+
constructor(dir) {
|
|
574
|
+
this.dir = dir;
|
|
575
|
+
}
|
|
576
|
+
async write(history) {
|
|
577
|
+
await fs.promises.mkdir(this.dir, { recursive: true });
|
|
578
|
+
const filePath = this.filePath(history.sessionId);
|
|
579
|
+
await fs.promises.writeFile(filePath, JSON.stringify(history, null, 2));
|
|
580
|
+
}
|
|
581
|
+
async read(sessionId) {
|
|
582
|
+
const filePath = this.filePath(sessionId);
|
|
583
|
+
try {
|
|
584
|
+
const raw = await fs.promises.readFile(filePath, "utf-8");
|
|
585
|
+
return JSON.parse(raw);
|
|
586
|
+
} catch {
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
async exists(sessionId) {
|
|
591
|
+
try {
|
|
592
|
+
await fs.promises.access(this.filePath(sessionId));
|
|
593
|
+
return true;
|
|
594
|
+
} catch {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
async list() {
|
|
599
|
+
try {
|
|
600
|
+
const files = await fs.promises.readdir(this.dir);
|
|
601
|
+
return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
|
|
602
|
+
} catch {
|
|
603
|
+
return [];
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
async delete(sessionId) {
|
|
607
|
+
try {
|
|
608
|
+
await fs.promises.unlink(this.filePath(sessionId));
|
|
609
|
+
} catch {
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
filePath(sessionId) {
|
|
613
|
+
return path.join(this.dir, `${sessionId}.json`);
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
// src/plugins/context/index.ts
|
|
618
|
+
var contextPlugin = {
|
|
619
|
+
name: "@openacp/context",
|
|
620
|
+
version: "1.0.0",
|
|
621
|
+
description: "Conversation context management with pluggable providers",
|
|
622
|
+
essential: false,
|
|
623
|
+
permissions: ["services:register", "middleware:register", "kernel:access"],
|
|
624
|
+
async install(ctx) {
|
|
625
|
+
const { settings, terminal } = ctx;
|
|
626
|
+
await settings.setAll({ enabled: true });
|
|
627
|
+
terminal.log.success("Context defaults saved");
|
|
628
|
+
},
|
|
629
|
+
async configure(ctx) {
|
|
630
|
+
const { terminal, settings } = ctx;
|
|
631
|
+
const current = await settings.getAll();
|
|
632
|
+
const toggle = await terminal.confirm({
|
|
633
|
+
message: `Context service is ${current.enabled !== false ? "enabled" : "disabled"}. Toggle?`,
|
|
634
|
+
initialValue: false
|
|
635
|
+
});
|
|
636
|
+
if (toggle) {
|
|
637
|
+
const newState = current.enabled === false;
|
|
638
|
+
await settings.set("enabled", newState);
|
|
639
|
+
terminal.log.success(`Context service ${newState ? "enabled" : "disabled"}`);
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
async uninstall(ctx, opts) {
|
|
643
|
+
if (opts.purge) {
|
|
644
|
+
await ctx.settings.clear();
|
|
645
|
+
ctx.terminal.log.success("Context settings cleared");
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
async setup(ctx) {
|
|
649
|
+
const historyDir = path2.join(os.homedir(), ".openacp", "history");
|
|
650
|
+
const store = new HistoryStore(historyDir);
|
|
651
|
+
const recorder = new HistoryRecorder(store);
|
|
652
|
+
const sessionManager = ctx.sessions;
|
|
653
|
+
const getRecords = () => sessionManager.listRecords();
|
|
654
|
+
const manager = new ContextManager();
|
|
655
|
+
manager.register(new HistoryProvider(store, getRecords));
|
|
656
|
+
manager.register(new EntireProvider());
|
|
657
|
+
ctx.registerService("context", manager);
|
|
658
|
+
ctx.registerMiddleware("agent:beforePrompt", {
|
|
659
|
+
priority: 200,
|
|
660
|
+
handler: async (payload, next) => {
|
|
661
|
+
recorder.onBeforePrompt(payload.sessionId, payload.text, payload.attachments);
|
|
662
|
+
return next();
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
ctx.registerMiddleware("agent:afterEvent", {
|
|
666
|
+
priority: 200,
|
|
667
|
+
handler: async (payload, next) => {
|
|
668
|
+
recorder.onAfterEvent(payload.sessionId, payload.event);
|
|
669
|
+
return next();
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
ctx.registerMiddleware("turn:end", {
|
|
673
|
+
priority: 200,
|
|
674
|
+
handler: async (payload, next) => {
|
|
675
|
+
await recorder.onTurnEnd(payload.sessionId, payload.stopReason);
|
|
676
|
+
return next();
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
ctx.registerMiddleware("permission:afterResolve", {
|
|
680
|
+
priority: 200,
|
|
681
|
+
handler: async (payload, next) => {
|
|
682
|
+
recorder.onPermissionResolved(payload.sessionId, payload.requestId, payload.decision);
|
|
683
|
+
return next();
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
ctx.registerMiddleware("session:afterDestroy", {
|
|
687
|
+
priority: 200,
|
|
688
|
+
handler: async (payload, next) => {
|
|
689
|
+
recorder.finalize(payload.sessionId);
|
|
690
|
+
return next();
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
ctx.log.info("Context service ready (local history + entire providers)");
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
var context_default = contextPlugin;
|
|
697
|
+
|
|
698
|
+
export {
|
|
699
|
+
context_default
|
|
700
|
+
};
|
|
701
|
+
//# sourceMappingURL=chunk-UWH7KIAA.js.map
|