@di-code/coding-agent 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -10
- package/dist/core/context-builder.d.ts.map +1 -1
- package/dist/core/context-builder.js +6 -2
- package/dist/core/context-builder.js.map +1 -1
- package/dist/core/image-input.d.ts +1 -1
- package/dist/core/image-input.d.ts.map +1 -1
- package/dist/core/image-input.js +55 -10
- package/dist/core/image-input.js.map +1 -1
- package/dist/core/session/session-storage.d.ts.map +1 -1
- package/dist/core/session/session-storage.js +1 -0
- package/dist/core/session/session-storage.js.map +1 -1
- package/dist/core/session.d.ts +17 -2
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +89 -0
- package/dist/core/session.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +25 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -0
- package/dist/core/tools/edit-diff.js +136 -0
- package/dist/core/tools/edit-diff.js.map +1 -0
- package/dist/core/tools/edit.d.ts +13 -4
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +64 -30
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/read.d.ts +2 -2
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts +2 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/entry.js +9 -2
- package/dist/entry.js.map +1 -1
- package/dist/main.d.ts +3 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +34 -6
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive-components.d.ts +2 -0
- package/dist/modes/interactive-components.d.ts.map +1 -1
- package/dist/modes/interactive-components.js +40 -13
- package/dist/modes/interactive-components.js.map +1 -1
- package/dist/modes/interactive-diff.d.ts +8 -0
- package/dist/modes/interactive-diff.d.ts.map +1 -0
- package/dist/modes/interactive-diff.js +78 -0
- package/dist/modes/interactive-diff.js.map +1 -0
- package/dist/modes/interactive-layout.d.ts +4 -0
- package/dist/modes/interactive-layout.d.ts.map +1 -1
- package/dist/modes/interactive-layout.js +4 -0
- package/dist/modes/interactive-layout.js.map +1 -1
- package/dist/modes/interactive-state.d.ts +5 -0
- package/dist/modes/interactive-state.d.ts.map +1 -1
- package/dist/modes/interactive-state.js +64 -11
- package/dist/modes/interactive-state.js.map +1 -1
- package/dist/modes/interactive.d.ts +10 -0
- package/dist/modes/interactive.d.ts.map +1 -1
- package/dist/modes/interactive.js +190 -20
- package/dist/modes/interactive.js.map +1 -1
- package/dist/provider-onboarding.d.ts +8 -1
- package/dist/provider-onboarding.d.ts.map +1 -1
- package/dist/provider-onboarding.js +46 -23
- package/dist/provider-onboarding.js.map +1 -1
- package/dist/rpc-entry.js +1 -1
- package/dist/rpc-entry.js.map +1 -1
- package/dist/startup.d.ts +11 -3
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +216 -87
- package/dist/startup.js.map +1 -1
- package/package.json +5 -4
package/dist/core/session.js
CHANGED
|
@@ -6,6 +6,18 @@ import { createBashTool } from "./tools/bash.js";
|
|
|
6
6
|
import { createEditTool } from "./tools/edit.js";
|
|
7
7
|
import { createReadTool } from "./tools/read.js";
|
|
8
8
|
import { createWriteTool } from "./tools/write.js";
|
|
9
|
+
function defaultThinkingLevel(model) {
|
|
10
|
+
const efforts = model.reasoningEfforts;
|
|
11
|
+
if (!efforts || efforts.length === 0)
|
|
12
|
+
return undefined;
|
|
13
|
+
return efforts.includes("medium") ? "medium" : efforts[0];
|
|
14
|
+
}
|
|
15
|
+
function textFromUserMessage(message) {
|
|
16
|
+
return message.content
|
|
17
|
+
.filter((content) => content.type === "text")
|
|
18
|
+
.map((content) => content.text)
|
|
19
|
+
.join("");
|
|
20
|
+
}
|
|
9
21
|
export class AgentSession {
|
|
10
22
|
agent;
|
|
11
23
|
allowedRootValue;
|
|
@@ -14,6 +26,7 @@ export class AgentSession {
|
|
|
14
26
|
skills;
|
|
15
27
|
extensionHost;
|
|
16
28
|
model;
|
|
29
|
+
thinkingLevelValue;
|
|
17
30
|
sessionIdValue;
|
|
18
31
|
now;
|
|
19
32
|
compactionEnabledValue;
|
|
@@ -22,6 +35,7 @@ export class AgentSession {
|
|
|
22
35
|
usageTotals;
|
|
23
36
|
persistenceError;
|
|
24
37
|
promptActive = false;
|
|
38
|
+
steeringMessages = [];
|
|
25
39
|
sessionListeners = new Set();
|
|
26
40
|
constructor(options) {
|
|
27
41
|
this.allowedRootValue = options.allowedRoot;
|
|
@@ -30,6 +44,7 @@ export class AgentSession {
|
|
|
30
44
|
this.skills = structuredClone([...(options.skills ?? [])]);
|
|
31
45
|
this.extensionHost = options.extensionHost;
|
|
32
46
|
this.model = options.model;
|
|
47
|
+
this.thinkingLevelValue = defaultThinkingLevel(this.model);
|
|
33
48
|
this.sessionIdValue = options.sessionManager?.header.id ?? randomUUID();
|
|
34
49
|
this.now = options.now ?? Date.now;
|
|
35
50
|
this.contextBudget = resolveContextBudget(options.model);
|
|
@@ -59,6 +74,7 @@ export class AgentSession {
|
|
|
59
74
|
this.agent = new Agent({
|
|
60
75
|
provider: options.provider,
|
|
61
76
|
model: options.model,
|
|
77
|
+
thinkingLevel: this.thinkingLevelValue,
|
|
62
78
|
systemPrompt: options.systemPrompt,
|
|
63
79
|
sessionId: this.sessionIdValue,
|
|
64
80
|
tools: [
|
|
@@ -101,6 +117,13 @@ export class AgentSession {
|
|
|
101
117
|
await this.emitSession({ type: "usage_update", usage: this.usage });
|
|
102
118
|
});
|
|
103
119
|
this.agent.subscribe(async (event, signal) => {
|
|
120
|
+
if (event.type === "message_end" && event.message.role === "user") {
|
|
121
|
+
const queued = this.steeringMessages[0];
|
|
122
|
+
if (queued && textFromUserMessage(event.message) === queued.deliveredText) {
|
|
123
|
+
this.steeringMessages.shift();
|
|
124
|
+
await this.emitQueueUpdate();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
104
127
|
if (this.extensionHost)
|
|
105
128
|
await this.extensionHost.emit(event, signal);
|
|
106
129
|
await this.emitSession(event);
|
|
@@ -118,12 +141,21 @@ export class AgentSession {
|
|
|
118
141
|
get modelId() {
|
|
119
142
|
return this.model.id;
|
|
120
143
|
}
|
|
144
|
+
get providerId() {
|
|
145
|
+
return this.provider.id;
|
|
146
|
+
}
|
|
147
|
+
get thinkingLevel() {
|
|
148
|
+
return this.thinkingLevelValue;
|
|
149
|
+
}
|
|
121
150
|
get allowedRoot() {
|
|
122
151
|
return this.allowedRootValue;
|
|
123
152
|
}
|
|
124
153
|
get availableModels() {
|
|
125
154
|
return structuredClone(this.provider.models);
|
|
126
155
|
}
|
|
156
|
+
get availableSkills() {
|
|
157
|
+
return structuredClone(this.skills);
|
|
158
|
+
}
|
|
127
159
|
setModel(modelId) {
|
|
128
160
|
if (this.promptActive)
|
|
129
161
|
throw new Error("Cannot change model while AgentSession is processing a prompt.");
|
|
@@ -131,11 +163,43 @@ export class AgentSession {
|
|
|
131
163
|
if (!next)
|
|
132
164
|
throw new Error(`Unknown model "${modelId}" for provider "${this.provider.id}".`);
|
|
133
165
|
this.model = structuredClone(next);
|
|
166
|
+
this.thinkingLevelValue =
|
|
167
|
+
this.thinkingLevelValue !== undefined && this.model.reasoningEfforts?.includes(this.thinkingLevelValue)
|
|
168
|
+
? this.thinkingLevelValue
|
|
169
|
+
: defaultThinkingLevel(this.model);
|
|
134
170
|
this.agent.setModel(this.model);
|
|
171
|
+
this.agent.setThinkingLevel(this.thinkingLevelValue);
|
|
172
|
+
this.contextBudget = resolveContextBudget(this.model);
|
|
173
|
+
this.keepRecentTokens = Math.min(this.keepRecentTokens, Math.max(1, Math.min(20_000, Math.floor(this.contextBudget.triggerTokens / 2))));
|
|
174
|
+
return structuredClone(this.model);
|
|
175
|
+
}
|
|
176
|
+
setRuntime(provider, model) {
|
|
177
|
+
if (this.promptActive)
|
|
178
|
+
throw new Error("Cannot change runtime while AgentSession is processing a prompt.");
|
|
179
|
+
const configuredModel = provider.models.find((candidate) => candidate.id === model.id);
|
|
180
|
+
if (!configuredModel || configuredModel.provider !== provider.id || model.provider !== provider.id) {
|
|
181
|
+
throw new Error(`Model "${model.id}" does not belong to provider "${provider.id}".`);
|
|
182
|
+
}
|
|
183
|
+
this.provider = provider;
|
|
184
|
+
this.model = structuredClone(configuredModel);
|
|
185
|
+
this.thinkingLevelValue = defaultThinkingLevel(this.model);
|
|
186
|
+
this.agent.setRuntime(provider, this.model);
|
|
187
|
+
this.agent.setThinkingLevel(this.thinkingLevelValue);
|
|
135
188
|
this.contextBudget = resolveContextBudget(this.model);
|
|
136
189
|
this.keepRecentTokens = Math.min(this.keepRecentTokens, Math.max(1, Math.min(20_000, Math.floor(this.contextBudget.triggerTokens / 2))));
|
|
137
190
|
return structuredClone(this.model);
|
|
138
191
|
}
|
|
192
|
+
cycleThinkingLevel() {
|
|
193
|
+
if (this.promptActive)
|
|
194
|
+
throw new Error("Cannot change thinking level while AgentSession is processing a prompt.");
|
|
195
|
+
const efforts = this.model.reasoningEfforts;
|
|
196
|
+
if (!efforts || efforts.length === 0)
|
|
197
|
+
return undefined;
|
|
198
|
+
const currentIndex = this.thinkingLevelValue === undefined ? -1 : efforts.indexOf(this.thinkingLevelValue);
|
|
199
|
+
this.thinkingLevelValue = efforts[(currentIndex + 1) % efforts.length];
|
|
200
|
+
this.agent.setThinkingLevel(this.thinkingLevelValue);
|
|
201
|
+
return this.thinkingLevelValue;
|
|
202
|
+
}
|
|
139
203
|
get compactionEnabled() {
|
|
140
204
|
return this.compactionEnabledValue;
|
|
141
205
|
}
|
|
@@ -164,6 +228,25 @@ export class AgentSession {
|
|
|
164
228
|
async prompt(text, signal) {
|
|
165
229
|
return this.promptWithImages(text, [], signal);
|
|
166
230
|
}
|
|
231
|
+
/** Queues an instruction for the next provider request while this Session is running. */
|
|
232
|
+
async steer(text, signal) {
|
|
233
|
+
await this.steerWithImages(text, [], signal);
|
|
234
|
+
}
|
|
235
|
+
/** Queues provider-neutral text and image content for the active Agent run. */
|
|
236
|
+
async steerWithImages(text, images, signal) {
|
|
237
|
+
if (this.persistenceError !== undefined)
|
|
238
|
+
throw this.persistenceError;
|
|
239
|
+
if (!this.promptActive)
|
|
240
|
+
throw new Error("AgentSession is not processing a prompt.");
|
|
241
|
+
if (images.length > 0 && !this.model.input.includes("image")) {
|
|
242
|
+
throw new Error(`Model "${this.model.id}" does not support image input.`);
|
|
243
|
+
}
|
|
244
|
+
const prompt = await resolveSkillCommand(text, this.skills, signal);
|
|
245
|
+
const content = [{ type: "text", text: prompt }, ...structuredClone([...images])];
|
|
246
|
+
this.agent.steerWithContent(content);
|
|
247
|
+
this.steeringMessages.push({ displayText: text, deliveredText: prompt });
|
|
248
|
+
await this.emitQueueUpdate();
|
|
249
|
+
}
|
|
167
250
|
/** Sends one text prompt with explicitly supplied image attachments. */
|
|
168
251
|
async promptWithImages(text, images, signal) {
|
|
169
252
|
if (this.persistenceError !== undefined) {
|
|
@@ -210,6 +293,12 @@ export class AgentSession {
|
|
|
210
293
|
for (const listener of this.sessionListeners)
|
|
211
294
|
await listener(structuredClone(event));
|
|
212
295
|
}
|
|
296
|
+
async emitQueueUpdate() {
|
|
297
|
+
await this.emitSession({
|
|
298
|
+
type: "queue_update",
|
|
299
|
+
steering: this.steeringMessages.map((message) => message.displayText),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
213
302
|
addUsage(usage) {
|
|
214
303
|
this.usageTotals = {
|
|
215
304
|
requestCount: this.usageTotals.requestCount + 1,
|
package/dist/core/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n\tAgent,\n\ttype AgentListener,\n\ttype ContextBudget,\n\testimateContextTokens,\n\tgenerateCompactionSummary,\n\tprepareCompaction,\n\tresolveContextBudget,\n\tshouldCompact,\n} from \"@di-code/agent\";\nimport type { AssistantMessage, ImageContent, Message, Model, Provider, Usage, UserContent } from \"@di-code/ai\";\nimport type { ExtensionHost } from \"../extensions/runtime.ts\";\nimport { buildSessionContext } from \"./context-builder.ts\";\nimport type { SkillResource } from \"./resources/types.ts\";\nimport type { SessionManager } from \"./session/session-manager.ts\";\nimport type { SessionDiagnostic } from \"./session/types.ts\";\nimport { resolveSkillCommand } from \"./skill-command.ts\";\nimport { createBashTool } from \"./tools/bash.ts\";\nimport { createEditTool } from \"./tools/edit.ts\";\nimport { createReadTool } from \"./tools/read.ts\";\nimport { createWriteTool } from \"./tools/write.ts\";\n\nexport interface AgentSessionCompactionOptions {\n\treadonly enabled?: boolean;\n\treadonly keepRecentTokens?: number;\n}\n\nexport interface SessionUsage {\n\treadonly requestCount: number;\n\treadonly inputTokens: number;\n\treadonly outputTokens: number;\n\treadonly cacheReadTokens: number;\n\treadonly cacheWriteTokens: number;\n\treadonly totalTokens: number;\n\treadonly cost: Usage[\"cost\"];\n\treadonly estimatedContextTokens: number;\n\treadonly contextWindow: number;\n\treadonly reserveTokens: number;\n\treadonly triggerTokens: number;\n}\n\nexport interface AgentSessionOptions {\n\treadonly allowedRoot: string;\n\treadonly provider: Provider;\n\treadonly model: Model;\n\treadonly systemPrompt?: string;\n\treadonly skills?: readonly SkillResource[];\n\treadonly now?: () => number;\n\treadonly sessionManager?: SessionManager;\n\treadonly compaction?: AgentSessionCompactionOptions;\n\treadonly extensionHost?: ExtensionHost;\n}\n\nexport type AgentSessionEvent =\n\t| import(\"@di-code/agent\").AgentEvent\n\t| { type: \"compaction_start\"; reason: \"threshold\" | \"manual\" }\n\t| { type: \"compaction_end\"; reason: \"threshold\" | \"manual\"; success: boolean; errorMessage?: string }\n\t| { type: \"usage_update\"; usage: SessionUsage };\n\nexport type AgentSessionListener = (event: AgentSessionEvent) => void | Promise<void>;\n\nexport class AgentSession {\n\tprivate readonly agent: Agent;\n\tprivate readonly allowedRootValue: string;\n\tprivate readonly sessionManager?: SessionManager;\n\tprivate readonly provider: Provider;\n\tprivate readonly skills: readonly SkillResource[];\n\tprivate readonly extensionHost?: ExtensionHost;\n\tprivate model: Model;\n\tprivate readonly sessionIdValue: string;\n\tprivate readonly now: () => number;\n\tprivate compactionEnabledValue: boolean;\n\tprivate contextBudget: ContextBudget;\n\tprivate keepRecentTokens: number;\n\tprivate usageTotals: Omit<\n\t\tSessionUsage,\n\t\t\"estimatedContextTokens\" | \"contextWindow\" | \"reserveTokens\" | \"triggerTokens\"\n\t>;\n\tprivate persistenceError?: unknown;\n\tprivate promptActive = false;\n\tprivate readonly sessionListeners = new Set<AgentSessionListener>();\n\n\tconstructor(options: AgentSessionOptions) {\n\t\tthis.allowedRootValue = options.allowedRoot;\n\t\tthis.sessionManager = options.sessionManager;\n\t\tthis.provider = options.provider;\n\t\tthis.skills = structuredClone([...(options.skills ?? [])]);\n\t\tthis.extensionHost = options.extensionHost;\n\t\tthis.model = options.model;\n\t\tthis.sessionIdValue = options.sessionManager?.header.id ?? randomUUID();\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.contextBudget = resolveContextBudget(options.model);\n\t\tif (options.compaction?.enabled !== undefined && typeof options.compaction.enabled !== \"boolean\") {\n\t\t\tthrow new TypeError(\"compaction.enabled must be a boolean\");\n\t\t}\n\t\tthis.compactionEnabledValue = options.sessionManager !== undefined && options.compaction?.enabled !== false;\n\t\tconst defaultKeepRecentTokens = Math.max(1, Math.min(20_000, Math.floor(this.contextBudget.triggerTokens / 2)));\n\t\tthis.keepRecentTokens = options.compaction?.keepRecentTokens ?? defaultKeepRecentTokens;\n\t\tif (!Number.isInteger(this.keepRecentTokens) || this.keepRecentTokens <= 0) {\n\t\t\tthrow new RangeError(\"compaction.keepRecentTokens must be a positive integer\");\n\t\t}\n\t\tthis.usageTotals = {\n\t\t\trequestCount: 0,\n\t\t\tinputTokens: 0,\n\t\t\toutputTokens: 0,\n\t\t\tcacheReadTokens: 0,\n\t\t\tcacheWriteTokens: 0,\n\t\t\ttotalTokens: 0,\n\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t};\n\t\tfor (const message of options.sessionManager?.messages ?? []) {\n\t\t\tif (message.role === \"assistant\") this.addUsage(message.usage);\n\t\t}\n\t\tconst initialContext = options.sessionManager ? buildSessionContext(options.sessionManager.entries) : undefined;\n\t\tthis.agent = new Agent({\n\t\t\tprovider: options.provider,\n\t\t\tmodel: options.model,\n\t\t\tsystemPrompt: options.systemPrompt,\n\t\t\tsessionId: this.sessionIdValue,\n\t\t\ttools: [\n\t\t\t\tcreateReadTool(options.allowedRoot),\n\t\t\t\tcreateWriteTool(options.allowedRoot),\n\t\t\t\tcreateEditTool(options.allowedRoot),\n\t\t\t\tcreateBashTool(options.allowedRoot),\n\t\t\t\t...(this.extensionHost?.listTools().map((tool) => ({\n\t\t\t\t\tname: tool.name,\n\t\t\t\t\tdescription: tool.description,\n\t\t\t\t\tparameters: tool.parameters,\n\t\t\t\t\texecute: async (toolCallId: string, parameters: never, signal?: AbortSignal) => {\n\t\t\t\t\t\tconst result = await this.extensionHost?.runTool(tool.name, toolCallId, parameters, signal);\n\t\t\t\t\t\tif (result === undefined) throw new Error(`Extension tool \"${tool.name}\" is unavailable.`);\n\t\t\t\t\t\treturn [...result];\n\t\t\t\t\t},\n\t\t\t\t})) ?? []),\n\t\t\t],\n\t\t\tnow: this.now,\n\t\t\tinitialMessages: options.sessionManager?.messages,\n\t\t\tinitialContextMessages: initialContext?.messages,\n\t\t});\n\t\tthis.agent.subscribe(async (event) => {\n\t\t\tif (event.type !== \"message_end\" || this.sessionManager === undefined || this.persistenceError !== undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait this.sessionManager.appendMessage(event.message);\n\t\t\t} catch (cause) {\n\t\t\t\tthis.persistenceError = cause;\n\t\t\t\tthrow cause;\n\t\t\t}\n\t\t});\n\t\tthis.agent.subscribe(async (event) => {\n\t\t\tif (event.type !== \"message_end\" || event.message.role !== \"assistant\") return;\n\t\t\tthis.addUsage(event.message.usage);\n\t\t\tawait this.emitSession({ type: \"usage_update\", usage: this.usage });\n\t\t});\n\t\tthis.agent.subscribe(async (event, signal) => {\n\t\t\tif (this.extensionHost) await this.extensionHost.emit(event, signal);\n\t\t\tawait this.emitSession(event);\n\t\t});\n\t}\n\n\tget transcript(): readonly Message[] {\n\t\treturn this.agent.transcript;\n\t}\n\n\tget isStreaming(): boolean {\n\t\treturn this.promptActive;\n\t}\n\n\tget sessionId(): string {\n\t\treturn this.sessionIdValue;\n\t}\n\n\tget modelId(): string {\n\t\treturn this.model.id;\n\t}\n\n\tget allowedRoot(): string {\n\t\treturn this.allowedRootValue;\n\t}\n\n\tget availableModels(): readonly Model[] {\n\t\treturn structuredClone(this.provider.models);\n\t}\n\n\tsetModel(modelId: string): Model {\n\t\tif (this.promptActive) throw new Error(\"Cannot change model while AgentSession is processing a prompt.\");\n\t\tconst next = this.provider.models.find((model) => model.id === modelId);\n\t\tif (!next) throw new Error(`Unknown model \"${modelId}\" for provider \"${this.provider.id}\".`);\n\t\tthis.model = structuredClone(next);\n\t\tthis.agent.setModel(this.model);\n\t\tthis.contextBudget = resolveContextBudget(this.model);\n\t\tthis.keepRecentTokens = Math.min(\n\t\t\tthis.keepRecentTokens,\n\t\t\tMath.max(1, Math.min(20_000, Math.floor(this.contextBudget.triggerTokens / 2))),\n\t\t);\n\t\treturn structuredClone(this.model);\n\t}\n\n\tget compactionEnabled(): boolean {\n\t\treturn this.compactionEnabledValue;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): boolean {\n\t\tif (this.promptActive) throw new Error(\"Cannot change compaction while AgentSession is processing a prompt.\");\n\t\tthis.compactionEnabledValue = enabled && this.sessionManager !== undefined;\n\t\treturn this.compactionEnabledValue;\n\t}\n\n\tget sessionFile(): string | undefined {\n\t\treturn this.sessionManager?.filePath;\n\t}\n\n\tget sessionDiagnostics(): readonly SessionDiagnostic[] {\n\t\treturn this.sessionManager?.diagnostics ?? [];\n\t}\n\n\tget usage(): SessionUsage {\n\t\treturn {\n\t\t\t...this.usageTotals,\n\t\t\tcost: { ...this.usageTotals.cost },\n\t\t\testimatedContextTokens: estimateContextTokens(this.agent.contextMessages),\n\t\t\tcontextWindow: this.contextBudget.contextWindow,\n\t\t\treserveTokens: this.contextBudget.reserveTokens,\n\t\t\ttriggerTokens: this.contextBudget.triggerTokens,\n\t\t};\n\t}\n\n\tasync prompt(text: string, signal?: AbortSignal): Promise<AssistantMessage> {\n\t\treturn this.promptWithImages(text, [], signal);\n\t}\n\n\t/** Sends one text prompt with explicitly supplied image attachments. */\n\tasync promptWithImages(\n\t\ttext: string,\n\t\timages: readonly ImageContent[],\n\t\tsignal?: AbortSignal,\n\t): Promise<AssistantMessage> {\n\t\tif (this.persistenceError !== undefined) {\n\t\t\tthrow this.persistenceError;\n\t\t}\n\t\tif (this.promptActive) {\n\t\t\tthrow new Error(\"AgentSession is already processing a prompt.\");\n\t\t}\n\n\t\tthis.promptActive = true;\n\t\ttry {\n\t\t\tif (images.length > 0 && !this.model.input.includes(\"image\")) {\n\t\t\t\tthrow new Error(`Model \"${this.model.id}\" does not support image input.`);\n\t\t\t}\n\t\t\tconst prompt = await resolveSkillCommand(text, this.skills, signal);\n\t\t\tconst content: UserContent[] = [{ type: \"text\", text: prompt }, ...structuredClone([...images])];\n\t\t\tawait this.compactIfNeeded(content, signal);\n\t\t\treturn await this.agent.promptWithContent(content, signal);\n\t\t} finally {\n\t\t\tthis.promptActive = false;\n\t\t}\n\t}\n\n\tasync compact(signal?: AbortSignal): Promise<void> {\n\t\tif (this.promptActive) throw new Error(\"AgentSession is already processing a prompt.\");\n\t\tif (!this.sessionManager) throw new Error(\"Cannot compact without a persisted session.\");\n\t\tthis.promptActive = true;\n\t\ttry {\n\t\t\tawait this.compactNow(signal, \"manual\");\n\t\t} finally {\n\t\t\tthis.promptActive = false;\n\t\t}\n\t}\n\n\tsubscribe(listener: AgentListener): () => void {\n\t\treturn this.agent.subscribe(listener);\n\t}\n\n\tsubscribeSession(listener: AgentSessionListener): () => void {\n\t\tthis.sessionListeners.add(listener);\n\t\treturn () => this.sessionListeners.delete(listener);\n\t}\n\n\tprivate async emitSession(event: AgentSessionEvent): Promise<void> {\n\t\tfor (const listener of this.sessionListeners) await listener(structuredClone(event));\n\t}\n\n\tprivate addUsage(usage: Usage): void {\n\t\tthis.usageTotals = {\n\t\t\trequestCount: this.usageTotals.requestCount + 1,\n\t\t\tinputTokens: this.usageTotals.inputTokens + usage.input,\n\t\t\toutputTokens: this.usageTotals.outputTokens + usage.output,\n\t\t\tcacheReadTokens: this.usageTotals.cacheReadTokens + usage.cacheRead,\n\t\t\tcacheWriteTokens: this.usageTotals.cacheWriteTokens + usage.cacheWrite,\n\t\t\ttotalTokens: this.usageTotals.totalTokens + usage.totalTokens,\n\t\t\tcost: {\n\t\t\t\tinput: this.usageTotals.cost.input + usage.cost.input,\n\t\t\t\toutput: this.usageTotals.cost.output + usage.cost.output,\n\t\t\t\tcacheRead: this.usageTotals.cost.cacheRead + usage.cost.cacheRead,\n\t\t\t\tcacheWrite: this.usageTotals.cost.cacheWrite + usage.cost.cacheWrite,\n\t\t\t\ttotal: this.usageTotals.cost.total + usage.cost.total,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate async compactIfNeeded(content: readonly UserContent[], signal?: AbortSignal): Promise<void> {\n\t\tif (!this.compactionEnabledValue || !this.sessionManager) return;\n\n\t\tconst context = buildSessionContext(this.sessionManager.entries);\n\t\tconst pendingUser: Message = {\n\t\t\trole: \"user\",\n\t\t\tcontent: structuredClone([...content]),\n\t\t\ttimestamp: 0,\n\t\t};\n\t\tconst estimatedTokens = estimateContextTokens([...context.messages, pendingUser]);\n\t\tif (!shouldCompact(estimatedTokens, this.contextBudget)) return;\n\n\t\tawait this.compactNow(signal, \"threshold\");\n\t}\n\n\tprivate async compactNow(signal: AbortSignal | undefined, reason: \"threshold\" | \"manual\"): Promise<void> {\n\t\tif (!this.sessionManager) throw new Error(\"Cannot compact without a persisted session.\");\n\t\tconst context = buildSessionContext(this.sessionManager.entries);\n\t\tawait this.emitSession({ type: \"compaction_start\", reason });\n\t\tconst preparation = prepareCompaction(context.messages, this.keepRecentTokens);\n\t\tconst firstKeptEntryId = preparation ? context.sourceEntryIds[preparation.firstKeptMessageIndex] : undefined;\n\t\tif (!preparation || typeof firstKeptEntryId !== \"string\") {\n\t\t\tconst errorMessage =\n\t\t\t\treason === \"manual\"\n\t\t\t\t\t? \"No valid compaction cut point was found for the current session.\"\n\t\t\t\t\t: \"Context limit reached but no valid compaction cut point was found.\";\n\t\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: false, errorMessage });\n\t\t\tthrow new Error(errorMessage);\n\t\t}\n\n\t\tlet summary: string;\n\t\ttry {\n\t\t\tsummary = await generateCompactionSummary(preparation, this.provider, this.model, {\n\t\t\t\treserveTokens: this.contextBudget.reserveTokens,\n\t\t\t\tsignal,\n\t\t\t\tnow: this.now,\n\t\t\t\tonUsage: (usage) => this.addUsage(usage),\n\t\t\t});\n\t\t\tawait this.emitSession({ type: \"usage_update\", usage: this.usage });\n\t\t} catch (cause) {\n\t\t\tconst errorMessage = cause instanceof Error ? cause.message : String(cause);\n\t\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: false, errorMessage });\n\t\t\tthrow cause;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.sessionManager.appendSummary({\n\t\t\t\tsummary,\n\t\t\t\tfirstKeptEntryId,\n\t\t\t\ttokensBefore: preparation.tokensBefore,\n\t\t\t});\n\t\t} catch (cause) {\n\t\t\tthis.persistenceError = cause;\n\t\t\tconst errorMessage = cause instanceof Error ? cause.message : String(cause);\n\t\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: false, errorMessage });\n\t\t\tthrow cause;\n\t\t}\n\n\t\tthis.agent.replaceContext(buildSessionContext(this.sessionManager.entries).messages);\n\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: true });\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n\tAgent,\n\ttype AgentListener,\n\ttype ContextBudget,\n\testimateContextTokens,\n\tgenerateCompactionSummary,\n\tprepareCompaction,\n\tresolveContextBudget,\n\tshouldCompact,\n} from \"@di-code/agent\";\nimport type {\n\tAssistantMessage,\n\tImageContent,\n\tMessage,\n\tModel,\n\tProvider,\n\tThinkingLevel,\n\tUsage,\n\tUserContent,\n} from \"@di-code/ai\";\nimport type { ExtensionHost } from \"../extensions/runtime.ts\";\nimport { buildSessionContext } from \"./context-builder.ts\";\nimport type { SkillResource } from \"./resources/types.ts\";\nimport type { SessionManager } from \"./session/session-manager.ts\";\nimport type { SessionDiagnostic } from \"./session/types.ts\";\nimport { resolveSkillCommand } from \"./skill-command.ts\";\nimport { createBashTool } from \"./tools/bash.ts\";\nimport { createEditTool } from \"./tools/edit.ts\";\nimport { createReadTool } from \"./tools/read.ts\";\nimport { createWriteTool } from \"./tools/write.ts\";\n\nexport interface AgentSessionCompactionOptions {\n\treadonly enabled?: boolean;\n\treadonly keepRecentTokens?: number;\n}\n\nexport interface SessionUsage {\n\treadonly requestCount: number;\n\treadonly inputTokens: number;\n\treadonly outputTokens: number;\n\treadonly cacheReadTokens: number;\n\treadonly cacheWriteTokens: number;\n\treadonly totalTokens: number;\n\treadonly cost: Usage[\"cost\"];\n\treadonly estimatedContextTokens: number;\n\treadonly contextWindow: number;\n\treadonly reserveTokens: number;\n\treadonly triggerTokens: number;\n}\n\nexport interface AgentSessionOptions {\n\treadonly allowedRoot: string;\n\treadonly provider: Provider;\n\treadonly model: Model;\n\treadonly systemPrompt?: string;\n\treadonly skills?: readonly SkillResource[];\n\treadonly now?: () => number;\n\treadonly sessionManager?: SessionManager;\n\treadonly compaction?: AgentSessionCompactionOptions;\n\treadonly extensionHost?: ExtensionHost;\n}\n\nexport type AgentSessionEvent =\n\t| import(\"@di-code/agent\").AgentEvent\n\t| { type: \"compaction_start\"; reason: \"threshold\" | \"manual\" }\n\t| { type: \"compaction_end\"; reason: \"threshold\" | \"manual\"; success: boolean; errorMessage?: string }\n\t| { type: \"queue_update\"; steering: readonly string[] }\n\t| { type: \"usage_update\"; usage: SessionUsage };\n\nexport type AgentSessionListener = (event: AgentSessionEvent) => void | Promise<void>;\n\nfunction defaultThinkingLevel(model: Model): ThinkingLevel | undefined {\n\tconst efforts = model.reasoningEfforts;\n\tif (!efforts || efforts.length === 0) return undefined;\n\treturn efforts.includes(\"medium\") ? \"medium\" : efforts[0];\n}\n\nfunction textFromUserMessage(message: Extract<Message, { role: \"user\" }>): string {\n\treturn message.content\n\t\t.filter((content): content is Extract<UserContent, { type: \"text\" }> => content.type === \"text\")\n\t\t.map((content) => content.text)\n\t\t.join(\"\");\n}\n\nexport class AgentSession {\n\tprivate readonly agent: Agent;\n\tprivate readonly allowedRootValue: string;\n\tprivate readonly sessionManager?: SessionManager;\n\tprivate provider: Provider;\n\tprivate readonly skills: readonly SkillResource[];\n\tprivate readonly extensionHost?: ExtensionHost;\n\tprivate model: Model;\n\tprivate thinkingLevelValue?: ThinkingLevel;\n\tprivate readonly sessionIdValue: string;\n\tprivate readonly now: () => number;\n\tprivate compactionEnabledValue: boolean;\n\tprivate contextBudget: ContextBudget;\n\tprivate keepRecentTokens: number;\n\tprivate usageTotals: Omit<\n\t\tSessionUsage,\n\t\t\"estimatedContextTokens\" | \"contextWindow\" | \"reserveTokens\" | \"triggerTokens\"\n\t>;\n\tprivate persistenceError?: unknown;\n\tprivate promptActive = false;\n\tprivate readonly steeringMessages: Array<{ displayText: string; deliveredText: string }> = [];\n\tprivate readonly sessionListeners = new Set<AgentSessionListener>();\n\n\tconstructor(options: AgentSessionOptions) {\n\t\tthis.allowedRootValue = options.allowedRoot;\n\t\tthis.sessionManager = options.sessionManager;\n\t\tthis.provider = options.provider;\n\t\tthis.skills = structuredClone([...(options.skills ?? [])]);\n\t\tthis.extensionHost = options.extensionHost;\n\t\tthis.model = options.model;\n\t\tthis.thinkingLevelValue = defaultThinkingLevel(this.model);\n\t\tthis.sessionIdValue = options.sessionManager?.header.id ?? randomUUID();\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.contextBudget = resolveContextBudget(options.model);\n\t\tif (options.compaction?.enabled !== undefined && typeof options.compaction.enabled !== \"boolean\") {\n\t\t\tthrow new TypeError(\"compaction.enabled must be a boolean\");\n\t\t}\n\t\tthis.compactionEnabledValue = options.sessionManager !== undefined && options.compaction?.enabled !== false;\n\t\tconst defaultKeepRecentTokens = Math.max(1, Math.min(20_000, Math.floor(this.contextBudget.triggerTokens / 2)));\n\t\tthis.keepRecentTokens = options.compaction?.keepRecentTokens ?? defaultKeepRecentTokens;\n\t\tif (!Number.isInteger(this.keepRecentTokens) || this.keepRecentTokens <= 0) {\n\t\t\tthrow new RangeError(\"compaction.keepRecentTokens must be a positive integer\");\n\t\t}\n\t\tthis.usageTotals = {\n\t\t\trequestCount: 0,\n\t\t\tinputTokens: 0,\n\t\t\toutputTokens: 0,\n\t\t\tcacheReadTokens: 0,\n\t\t\tcacheWriteTokens: 0,\n\t\t\ttotalTokens: 0,\n\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t};\n\t\tfor (const message of options.sessionManager?.messages ?? []) {\n\t\t\tif (message.role === \"assistant\") this.addUsage(message.usage);\n\t\t}\n\t\tconst initialContext = options.sessionManager ? buildSessionContext(options.sessionManager.entries) : undefined;\n\t\tthis.agent = new Agent({\n\t\t\tprovider: options.provider,\n\t\t\tmodel: options.model,\n\t\t\tthinkingLevel: this.thinkingLevelValue,\n\t\t\tsystemPrompt: options.systemPrompt,\n\t\t\tsessionId: this.sessionIdValue,\n\t\t\ttools: [\n\t\t\t\tcreateReadTool(options.allowedRoot),\n\t\t\t\tcreateWriteTool(options.allowedRoot),\n\t\t\t\tcreateEditTool(options.allowedRoot),\n\t\t\t\tcreateBashTool(options.allowedRoot),\n\t\t\t\t...(this.extensionHost?.listTools().map((tool) => ({\n\t\t\t\t\tname: tool.name,\n\t\t\t\t\tdescription: tool.description,\n\t\t\t\t\tparameters: tool.parameters,\n\t\t\t\t\texecute: async (toolCallId: string, parameters: never, signal?: AbortSignal) => {\n\t\t\t\t\t\tconst result = await this.extensionHost?.runTool(tool.name, toolCallId, parameters, signal);\n\t\t\t\t\t\tif (result === undefined) throw new Error(`Extension tool \"${tool.name}\" is unavailable.`);\n\t\t\t\t\t\treturn [...result];\n\t\t\t\t\t},\n\t\t\t\t})) ?? []),\n\t\t\t],\n\t\t\tnow: this.now,\n\t\t\tinitialMessages: options.sessionManager?.messages,\n\t\t\tinitialContextMessages: initialContext?.messages,\n\t\t});\n\t\tthis.agent.subscribe(async (event) => {\n\t\t\tif (event.type !== \"message_end\" || this.sessionManager === undefined || this.persistenceError !== undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait this.sessionManager.appendMessage(event.message);\n\t\t\t} catch (cause) {\n\t\t\t\tthis.persistenceError = cause;\n\t\t\t\tthrow cause;\n\t\t\t}\n\t\t});\n\t\tthis.agent.subscribe(async (event) => {\n\t\t\tif (event.type !== \"message_end\" || event.message.role !== \"assistant\") return;\n\t\t\tthis.addUsage(event.message.usage);\n\t\t\tawait this.emitSession({ type: \"usage_update\", usage: this.usage });\n\t\t});\n\t\tthis.agent.subscribe(async (event, signal) => {\n\t\t\tif (event.type === \"message_end\" && event.message.role === \"user\") {\n\t\t\t\tconst queued = this.steeringMessages[0];\n\t\t\t\tif (queued && textFromUserMessage(event.message) === queued.deliveredText) {\n\t\t\t\t\tthis.steeringMessages.shift();\n\t\t\t\t\tawait this.emitQueueUpdate();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.extensionHost) await this.extensionHost.emit(event, signal);\n\t\t\tawait this.emitSession(event);\n\t\t});\n\t}\n\n\tget transcript(): readonly Message[] {\n\t\treturn this.agent.transcript;\n\t}\n\n\tget isStreaming(): boolean {\n\t\treturn this.promptActive;\n\t}\n\n\tget sessionId(): string {\n\t\treturn this.sessionIdValue;\n\t}\n\n\tget modelId(): string {\n\t\treturn this.model.id;\n\t}\n\n\tget providerId(): string {\n\t\treturn this.provider.id;\n\t}\n\n\tget thinkingLevel(): ThinkingLevel | undefined {\n\t\treturn this.thinkingLevelValue;\n\t}\n\n\tget allowedRoot(): string {\n\t\treturn this.allowedRootValue;\n\t}\n\n\tget availableModels(): readonly Model[] {\n\t\treturn structuredClone(this.provider.models);\n\t}\n\n\tget availableSkills(): readonly SkillResource[] {\n\t\treturn structuredClone(this.skills);\n\t}\n\n\tsetModel(modelId: string): Model {\n\t\tif (this.promptActive) throw new Error(\"Cannot change model while AgentSession is processing a prompt.\");\n\t\tconst next = this.provider.models.find((model) => model.id === modelId);\n\t\tif (!next) throw new Error(`Unknown model \"${modelId}\" for provider \"${this.provider.id}\".`);\n\t\tthis.model = structuredClone(next);\n\t\tthis.thinkingLevelValue =\n\t\t\tthis.thinkingLevelValue !== undefined && this.model.reasoningEfforts?.includes(this.thinkingLevelValue)\n\t\t\t\t? this.thinkingLevelValue\n\t\t\t\t: defaultThinkingLevel(this.model);\n\t\tthis.agent.setModel(this.model);\n\t\tthis.agent.setThinkingLevel(this.thinkingLevelValue);\n\t\tthis.contextBudget = resolveContextBudget(this.model);\n\t\tthis.keepRecentTokens = Math.min(\n\t\t\tthis.keepRecentTokens,\n\t\t\tMath.max(1, Math.min(20_000, Math.floor(this.contextBudget.triggerTokens / 2))),\n\t\t);\n\t\treturn structuredClone(this.model);\n\t}\n\n\tsetRuntime(provider: Provider, model: Model): Model {\n\t\tif (this.promptActive) throw new Error(\"Cannot change runtime while AgentSession is processing a prompt.\");\n\t\tconst configuredModel = provider.models.find((candidate) => candidate.id === model.id);\n\t\tif (!configuredModel || configuredModel.provider !== provider.id || model.provider !== provider.id) {\n\t\t\tthrow new Error(`Model \"${model.id}\" does not belong to provider \"${provider.id}\".`);\n\t\t}\n\t\tthis.provider = provider;\n\t\tthis.model = structuredClone(configuredModel);\n\t\tthis.thinkingLevelValue = defaultThinkingLevel(this.model);\n\t\tthis.agent.setRuntime(provider, this.model);\n\t\tthis.agent.setThinkingLevel(this.thinkingLevelValue);\n\t\tthis.contextBudget = resolveContextBudget(this.model);\n\t\tthis.keepRecentTokens = Math.min(\n\t\t\tthis.keepRecentTokens,\n\t\t\tMath.max(1, Math.min(20_000, Math.floor(this.contextBudget.triggerTokens / 2))),\n\t\t);\n\t\treturn structuredClone(this.model);\n\t}\n\n\tcycleThinkingLevel(): ThinkingLevel | undefined {\n\t\tif (this.promptActive) throw new Error(\"Cannot change thinking level while AgentSession is processing a prompt.\");\n\t\tconst efforts = this.model.reasoningEfforts;\n\t\tif (!efforts || efforts.length === 0) return undefined;\n\t\tconst currentIndex = this.thinkingLevelValue === undefined ? -1 : efforts.indexOf(this.thinkingLevelValue);\n\t\tthis.thinkingLevelValue = efforts[(currentIndex + 1) % efforts.length];\n\t\tthis.agent.setThinkingLevel(this.thinkingLevelValue);\n\t\treturn this.thinkingLevelValue;\n\t}\n\n\tget compactionEnabled(): boolean {\n\t\treturn this.compactionEnabledValue;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): boolean {\n\t\tif (this.promptActive) throw new Error(\"Cannot change compaction while AgentSession is processing a prompt.\");\n\t\tthis.compactionEnabledValue = enabled && this.sessionManager !== undefined;\n\t\treturn this.compactionEnabledValue;\n\t}\n\n\tget sessionFile(): string | undefined {\n\t\treturn this.sessionManager?.filePath;\n\t}\n\n\tget sessionDiagnostics(): readonly SessionDiagnostic[] {\n\t\treturn this.sessionManager?.diagnostics ?? [];\n\t}\n\n\tget usage(): SessionUsage {\n\t\treturn {\n\t\t\t...this.usageTotals,\n\t\t\tcost: { ...this.usageTotals.cost },\n\t\t\testimatedContextTokens: estimateContextTokens(this.agent.contextMessages),\n\t\t\tcontextWindow: this.contextBudget.contextWindow,\n\t\t\treserveTokens: this.contextBudget.reserveTokens,\n\t\t\ttriggerTokens: this.contextBudget.triggerTokens,\n\t\t};\n\t}\n\n\tasync prompt(text: string, signal?: AbortSignal): Promise<AssistantMessage> {\n\t\treturn this.promptWithImages(text, [], signal);\n\t}\n\n\t/** Queues an instruction for the next provider request while this Session is running. */\n\tasync steer(text: string, signal?: AbortSignal): Promise<void> {\n\t\tawait this.steerWithImages(text, [], signal);\n\t}\n\n\t/** Queues provider-neutral text and image content for the active Agent run. */\n\tasync steerWithImages(text: string, images: readonly ImageContent[], signal?: AbortSignal): Promise<void> {\n\t\tif (this.persistenceError !== undefined) throw this.persistenceError;\n\t\tif (!this.promptActive) throw new Error(\"AgentSession is not processing a prompt.\");\n\t\tif (images.length > 0 && !this.model.input.includes(\"image\")) {\n\t\t\tthrow new Error(`Model \"${this.model.id}\" does not support image input.`);\n\t\t}\n\t\tconst prompt = await resolveSkillCommand(text, this.skills, signal);\n\t\tconst content: UserContent[] = [{ type: \"text\", text: prompt }, ...structuredClone([...images])];\n\t\tthis.agent.steerWithContent(content);\n\t\tthis.steeringMessages.push({ displayText: text, deliveredText: prompt });\n\t\tawait this.emitQueueUpdate();\n\t}\n\n\t/** Sends one text prompt with explicitly supplied image attachments. */\n\tasync promptWithImages(\n\t\ttext: string,\n\t\timages: readonly ImageContent[],\n\t\tsignal?: AbortSignal,\n\t): Promise<AssistantMessage> {\n\t\tif (this.persistenceError !== undefined) {\n\t\t\tthrow this.persistenceError;\n\t\t}\n\t\tif (this.promptActive) {\n\t\t\tthrow new Error(\"AgentSession is already processing a prompt.\");\n\t\t}\n\n\t\tthis.promptActive = true;\n\t\ttry {\n\t\t\tif (images.length > 0 && !this.model.input.includes(\"image\")) {\n\t\t\t\tthrow new Error(`Model \"${this.model.id}\" does not support image input.`);\n\t\t\t}\n\t\t\tconst prompt = await resolveSkillCommand(text, this.skills, signal);\n\t\t\tconst content: UserContent[] = [{ type: \"text\", text: prompt }, ...structuredClone([...images])];\n\t\t\tawait this.compactIfNeeded(content, signal);\n\t\t\treturn await this.agent.promptWithContent(content, signal);\n\t\t} finally {\n\t\t\tthis.promptActive = false;\n\t\t}\n\t}\n\n\tasync compact(signal?: AbortSignal): Promise<void> {\n\t\tif (this.promptActive) throw new Error(\"AgentSession is already processing a prompt.\");\n\t\tif (!this.sessionManager) throw new Error(\"Cannot compact without a persisted session.\");\n\t\tthis.promptActive = true;\n\t\ttry {\n\t\t\tawait this.compactNow(signal, \"manual\");\n\t\t} finally {\n\t\t\tthis.promptActive = false;\n\t\t}\n\t}\n\n\tsubscribe(listener: AgentListener): () => void {\n\t\treturn this.agent.subscribe(listener);\n\t}\n\n\tsubscribeSession(listener: AgentSessionListener): () => void {\n\t\tthis.sessionListeners.add(listener);\n\t\treturn () => this.sessionListeners.delete(listener);\n\t}\n\n\tprivate async emitSession(event: AgentSessionEvent): Promise<void> {\n\t\tfor (const listener of this.sessionListeners) await listener(structuredClone(event));\n\t}\n\n\tprivate async emitQueueUpdate(): Promise<void> {\n\t\tawait this.emitSession({\n\t\t\ttype: \"queue_update\",\n\t\t\tsteering: this.steeringMessages.map((message) => message.displayText),\n\t\t});\n\t}\n\n\tprivate addUsage(usage: Usage): void {\n\t\tthis.usageTotals = {\n\t\t\trequestCount: this.usageTotals.requestCount + 1,\n\t\t\tinputTokens: this.usageTotals.inputTokens + usage.input,\n\t\t\toutputTokens: this.usageTotals.outputTokens + usage.output,\n\t\t\tcacheReadTokens: this.usageTotals.cacheReadTokens + usage.cacheRead,\n\t\t\tcacheWriteTokens: this.usageTotals.cacheWriteTokens + usage.cacheWrite,\n\t\t\ttotalTokens: this.usageTotals.totalTokens + usage.totalTokens,\n\t\t\tcost: {\n\t\t\t\tinput: this.usageTotals.cost.input + usage.cost.input,\n\t\t\t\toutput: this.usageTotals.cost.output + usage.cost.output,\n\t\t\t\tcacheRead: this.usageTotals.cost.cacheRead + usage.cost.cacheRead,\n\t\t\t\tcacheWrite: this.usageTotals.cost.cacheWrite + usage.cost.cacheWrite,\n\t\t\t\ttotal: this.usageTotals.cost.total + usage.cost.total,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate async compactIfNeeded(content: readonly UserContent[], signal?: AbortSignal): Promise<void> {\n\t\tif (!this.compactionEnabledValue || !this.sessionManager) return;\n\n\t\tconst context = buildSessionContext(this.sessionManager.entries);\n\t\tconst pendingUser: Message = {\n\t\t\trole: \"user\",\n\t\t\tcontent: structuredClone([...content]),\n\t\t\ttimestamp: 0,\n\t\t};\n\t\tconst estimatedTokens = estimateContextTokens([...context.messages, pendingUser]);\n\t\tif (!shouldCompact(estimatedTokens, this.contextBudget)) return;\n\n\t\tawait this.compactNow(signal, \"threshold\");\n\t}\n\n\tprivate async compactNow(signal: AbortSignal | undefined, reason: \"threshold\" | \"manual\"): Promise<void> {\n\t\tif (!this.sessionManager) throw new Error(\"Cannot compact without a persisted session.\");\n\t\tconst context = buildSessionContext(this.sessionManager.entries);\n\t\tawait this.emitSession({ type: \"compaction_start\", reason });\n\t\tconst preparation = prepareCompaction(context.messages, this.keepRecentTokens);\n\t\tconst firstKeptEntryId = preparation ? context.sourceEntryIds[preparation.firstKeptMessageIndex] : undefined;\n\t\tif (!preparation || typeof firstKeptEntryId !== \"string\") {\n\t\t\tconst errorMessage =\n\t\t\t\treason === \"manual\"\n\t\t\t\t\t? \"No valid compaction cut point was found for the current session.\"\n\t\t\t\t\t: \"Context limit reached but no valid compaction cut point was found.\";\n\t\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: false, errorMessage });\n\t\t\tthrow new Error(errorMessage);\n\t\t}\n\n\t\tlet summary: string;\n\t\ttry {\n\t\t\tsummary = await generateCompactionSummary(preparation, this.provider, this.model, {\n\t\t\t\treserveTokens: this.contextBudget.reserveTokens,\n\t\t\t\tsignal,\n\t\t\t\tnow: this.now,\n\t\t\t\tonUsage: (usage) => this.addUsage(usage),\n\t\t\t});\n\t\t\tawait this.emitSession({ type: \"usage_update\", usage: this.usage });\n\t\t} catch (cause) {\n\t\t\tconst errorMessage = cause instanceof Error ? cause.message : String(cause);\n\t\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: false, errorMessage });\n\t\t\tthrow cause;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.sessionManager.appendSummary({\n\t\t\t\tsummary,\n\t\t\t\tfirstKeptEntryId,\n\t\t\t\ttokensBefore: preparation.tokensBefore,\n\t\t\t});\n\t\t} catch (cause) {\n\t\t\tthis.persistenceError = cause;\n\t\t\tconst errorMessage = cause instanceof Error ? cause.message : String(cause);\n\t\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: false, errorMessage });\n\t\t\tthrow cause;\n\t\t}\n\n\t\tthis.agent.replaceContext(buildSessionContext(this.sessionManager.entries).messages);\n\t\tawait this.emitSession({ type: \"compaction_end\", reason, success: true });\n\t}\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentTool } from "@di-code/agent";
|
|
2
|
-
import { type Static, Type } from "@di-code/ai";
|
|
2
|
+
import { type Static, type ToolResultContent, Type } from "@di-code/ai";
|
|
3
3
|
export declare const DEFAULT_BASH_TIMEOUT_MS = 30000;
|
|
4
4
|
export declare const MAX_BASH_TIMEOUT_MS = 300000;
|
|
5
5
|
export declare const DEFAULT_BASH_MAX_OUTPUT_BYTES: number;
|
|
@@ -26,7 +26,7 @@ export interface BashToolOptions {
|
|
|
26
26
|
readonly operations?: BashOperations;
|
|
27
27
|
readonly maxOutputBytes?: number;
|
|
28
28
|
}
|
|
29
|
-
export type BashTool = AgentTool<typeof bashParameters>;
|
|
29
|
+
export type BashTool = AgentTool<typeof bashParameters, ToolResultContent[]>;
|
|
30
30
|
export interface ShellRuntime {
|
|
31
31
|
readonly executable: string;
|
|
32
32
|
readonly detached: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,KAAK,MAAM,
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,iBAAiB,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExE,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAC9C,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAC3C,eAAO,MAAM,6BAA6B,QAAY,CAAC;AAEvD,eAAO,MAAM,cAAc;;;EAGzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC9B,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACnF;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,cAAc,EAAE,iBAAiB,EAAE,CAAC,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;CACzC;AAoED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,YAAY,CAkB9F;AAyFD,wBAAgB,yBAAyB,IAAI,cAAc,CAE1D;AAaD,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAqC3F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAuC,IAAI,EAAE,MAAM,aAAa,CAAC;AAExE,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAC9C,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAC3C,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,IAAI,CAAC;AAEvD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IACtC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;CACpF,CAAC,CAAC;AAgDH,SAAS,aAAa,CAAC,SAAiB;IACvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,IAAI,SAAS,GAAG,mBAAmB,EAAE,CAAC;QACtF,MAAM,IAAI,KAAK,CAAC,8CAA8C,mBAAmB,EAAE,CAAC,CAAC;IACtF,CAAC;AACF,CAAC;AAED,SAAS,oBAAoB,CAAC,cAAsB;IACnD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC9D,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgB;IAI5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,OAAO;QACN,MAAM,CAAC,KAAK;YACX,MAAM,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;YACnC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;gBACnB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;gBAC1C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/B,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC;YACtB,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,GAAG,SAAS;gBAAE,SAAS,GAAG,IAAI,CAAC;QAChD,CAAC;QACD,QAAQ;YACP,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;YAC1C,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;QACzE,CAAC;KACD,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe;IAC9C,OAAO;QACN,uFAAuF;QACvF,kCAAkC;QAClC,4BAA4B;QAC5B,KAAK;QACL,OAAO;QACP,8BAA8B;QAC9B,wCAAwC;QACxC,iBAAiB;QACjB,yCAAyC;QACzC,yGAAyG;QACzG,QAAQ;KACR,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,WAA4B,OAAO,CAAC,QAAQ;IAC/E,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO;YACN,UAAU,EAAE,gBAAgB;YAC5B,QAAQ,EAAE,KAAK;YACf,WAAW,EACV,gLAAgL;YACjL,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC;SAC5G,CAAC;IACH,CAAC;IAED,OAAO;QACN,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,IAAI;QACd,WAAW,EACV,wKAAwK;QACzK,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC;KAClC,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,GAAW,EAAE,OAAuB;IAC5E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;YACvC,OAAO;QACR,CAAC;QAED,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE;YACnE,GAAG;YACH,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,WAAW,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,WAAsC,CAAC;QAE3C,MAAM,kBAAkB,GAAG,GAAS,EAAE;YACrC,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;gBAAE,WAAW,KAAK,eAAe,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAChF,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAS,EAAE;YAC1B,OAAO,GAAG,IAAI,CAAC;YACf,kBAAkB,EAAE,CAAC;QACtB,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC/B,QAAQ,GAAG,IAAI,CAAC;YAChB,kBAAkB,EAAE,CAAC;QACtB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAEtB,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;YAAE,OAAO,EAAE,CAAC;QACvC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,OAAO,GAAG,GAAS,EAAE;YAC1B,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7B,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;YAChC,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,KAAK,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAC3C,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAC9C,CAAC,KAAc,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CACjC,CAAC;QACH,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAA+B;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,KAA+B;IAC1E,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;YACnE,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,IAAI;SACjB,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAC3B,OAAO;IACR,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACR,IAAI,CAAC;YACJ,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACR,0EAA0E;QAC3E,CAAC;IACF,CAAC;AACF,CAAC;AAED,MAAM,UAAU,yBAAyB;IACxC,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,YAAY,CAAC,MAAsB,EAAE,MAAsB,EAAE,SAAwB;IAC7F,MAAM,MAAM,GAAe;QAC1B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,eAAe,EAAE,MAAM,CAAC,SAAS;QACjC,eAAe,EAAE,MAAM,CAAC,SAAS;KACjC,CAAC;IACF,OAAO,YAAY,MAAM,CAAC,IAAI,IAAI,SAAS,gBAAgB,MAAM,CAAC,IAAI,IAAI,SAAS,eAAe,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;AAC5H,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,WAAmB,EAAE,UAA2B,EAAE;IAChF,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,yBAAyB,EAAE,CAAC;IACrE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,6BAA6B,CAAC;IAC/E,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IACtC,oBAAoB,CAAC,cAAc,CAAC,CAAC;IAErC,OAAO;QACN,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,UAAU,EAAE,cAAc;QAC1B,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,MAAM;YAC5C,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YAC1D,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAClF,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,IAAI,uBAAuB,CAAC;YAClE,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,CAAC;YACxC,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YAE1D,MAAM,MAAM,GAAG,mBAAmB,CAAC,cAAc,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,mBAAmB,CAAC,cAAc,CAAC,CAAC;YACnD,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE;gBACrE,MAAM;gBACN,SAAS;gBACT,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;gBACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;aACzC,CAAC,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;YAC5F,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC;YAE7E,IAAI,SAAS,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;YACvE,IAAI,SAAS,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,SAAS,UAAU,MAAM,EAAE,CAAC,CAAC;YAChG,IAAI,SAAS,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,4BAA4B,SAAS,CAAC,QAAQ,IAAI,SAAS,OAAO,MAAM,EAAE,CAAC,CAAC;YAC7F,CAAC;YACD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { realpath } from \"node:fs/promises\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport type { AgentTool } from \"@di-code/agent\";\nimport { type Static, type ToolResultContent, Type } from \"@di-code/ai\";\n\nexport const DEFAULT_BASH_TIMEOUT_MS = 30_000;\nexport const MAX_BASH_TIMEOUT_MS = 300_000;\nexport const DEFAULT_BASH_MAX_OUTPUT_BYTES = 50 * 1024;\n\nexport const bashParameters = Type.Object({\n\tcommand: Type.String({ minLength: 1 }),\n\ttimeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: MAX_BASH_TIMEOUT_MS })),\n});\n\nexport type BashParameters = Static<typeof bashParameters>;\n\nexport interface BashRunOptions {\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs: number;\n\treadonly onStdout: (chunk: Buffer) => void;\n\treadonly onStderr: (chunk: Buffer) => void;\n}\n\nexport interface BashExecution {\n\treadonly exitCode: number | null;\n\treadonly timedOut: boolean;\n\treadonly aborted: boolean;\n}\n\nexport interface BashOperations {\n\trun(command: string, cwd: string, options: BashRunOptions): Promise<BashExecution>;\n}\n\nexport interface BashToolOptions {\n\treadonly operations?: BashOperations;\n\treadonly maxOutputBytes?: number;\n}\n\nexport type BashTool = AgentTool<typeof bashParameters>;\n\nexport interface ShellRuntime {\n\treadonly executable: string;\n\treadonly detached: boolean;\n\treadonly description: string;\n\targs(command: string): readonly string[];\n}\n\ninterface OutputSnapshot {\n\treadonly text: string;\n\treadonly truncated: boolean;\n}\n\ninterface BashStatus {\n\treadonly exitCode: number | null;\n\treadonly timedOut: boolean;\n\treadonly aborted: boolean;\n\treadonly stdoutTruncated: boolean;\n\treadonly stderrTruncated: boolean;\n}\n\nfunction assertTimeout(timeoutMs: number): void {\n\tif (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MAX_BASH_TIMEOUT_MS) {\n\t\tthrow new Error(`timeoutMs must be an integer between 1 and ${MAX_BASH_TIMEOUT_MS}`);\n\t}\n}\n\nfunction assertMaxOutputBytes(maxOutputBytes: number): void {\n\tif (!Number.isInteger(maxOutputBytes) || maxOutputBytes < 1) {\n\t\tthrow new Error(\"maxOutputBytes must be a positive integer\");\n\t}\n}\n\nfunction createOutputCapture(maxBytes: number): {\n\tappend(chunk: Buffer): void;\n\tsnapshot(): OutputSnapshot;\n} {\n\tconst chunks: Buffer[] = [];\n\tlet bytes = 0;\n\tlet truncated = false;\n\n\treturn {\n\t\tappend(chunk) {\n\t\t\tconst remaining = maxBytes - bytes;\n\t\t\tif (remaining > 0) {\n\t\t\t\tconst kept = chunk.subarray(0, remaining);\n\t\t\t\tchunks.push(Buffer.from(kept));\n\t\t\t\tbytes += kept.length;\n\t\t\t}\n\t\t\tif (chunk.length > remaining) truncated = true;\n\t\t},\n\t\tsnapshot() {\n\t\t\tconst decoder = new StringDecoder(\"utf8\");\n\t\t\treturn { text: decoder.write(Buffer.concat(chunks, bytes)), truncated };\n\t\t},\n\t};\n}\n\nfunction createPowerShellScript(command: string): string {\n\treturn [\n\t\t\"$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)\",\n\t\t\"$script:diCodeSucceeded = $false\",\n\t\t\"$script:diCodeExitCode = 0\",\n\t\t\"& {\",\n\t\tcommand,\n\t\t\"$script:diCodeSucceeded = $?\",\n\t\t\"$script:diCodeExitCode = $LASTEXITCODE\",\n\t\t\"} | Out-Default\",\n\t\t\"if ($script:diCodeSucceeded) { exit 0 }\",\n\t\t\"if ($script:diCodeExitCode -is [int] -and $script:diCodeExitCode -ne 0) { exit $script:diCodeExitCode }\",\n\t\t\"exit 1\",\n\t].join(\"\\n\");\n}\n\nexport function resolveShellRuntime(platform: NodeJS.Platform = process.platform): ShellRuntime {\n\tif (platform === \"win32\") {\n\t\treturn {\n\t\t\texecutable: \"powershell.exe\",\n\t\t\tdetached: false,\n\t\t\tdescription:\n\t\t\t\t\"Execute a Windows PowerShell command in the allowed root with timeout and bounded output. Use PowerShell syntax such as Get-ChildItem and Get-Content; do not use Bash syntax.\",\n\t\t\targs: (command) => [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\", createPowerShellScript(command)],\n\t\t};\n\t}\n\n\treturn {\n\t\texecutable: \"/bin/sh\",\n\t\tdetached: true,\n\t\tdescription:\n\t\t\t\"Execute a POSIX shell command using /bin/sh in the allowed root with timeout and bounded output. Use portable POSIX syntax; Bash-only extensions may not be available.\",\n\t\targs: (command) => [\"-c\", command],\n\t};\n}\n\nfunction waitForProcess(command: string, cwd: string, options: BashRunOptions): Promise<BashExecution> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (options.signal?.aborted) {\n\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst runtime = resolveShellRuntime();\n\t\tconst child = spawn(runtime.executable, [...runtime.args(command)], {\n\t\t\tcwd,\n\t\t\tdetached: runtime.detached,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\twindowsHide: true,\n\t\t});\n\n\t\tlet timedOut = false;\n\t\tlet aborted = false;\n\t\tlet settled = false;\n\t\tlet termination: Promise<void> | undefined;\n\n\t\tconst requestTermination = (): void => {\n\t\t\tif (child.pid !== undefined) termination ??= killProcessTree(child.pid, child);\n\t\t};\n\t\tconst onAbort = (): void => {\n\t\t\taborted = true;\n\t\t\trequestTermination();\n\t\t};\n\t\tconst timeout = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\trequestTermination();\n\t\t}, options.timeoutMs);\n\n\t\toptions.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tif (options.signal?.aborted) onAbort();\n\t\tchild.stdout.on(\"data\", options.onStdout);\n\t\tchild.stderr.on(\"data\", options.onStderr);\n\n\t\tconst cleanup = (): void => {\n\t\t\tclearTimeout(timeout);\n\t\t\toptions.signal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\t\tchild.once(\"error\", (error) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t});\n\t\tchild.once(\"close\", (exitCode) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tvoid (termination ?? Promise.resolve()).then(\n\t\t\t\t() => resolve({ exitCode, timedOut, aborted }),\n\t\t\t\t(error: unknown) => reject(error),\n\t\t\t);\n\t\t});\n\t});\n}\n\nfunction waitForChild(child: ReturnType<typeof spawn>): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tchild.once(\"error\", () => resolve());\n\t\tchild.once(\"close\", () => resolve());\n\t});\n}\n\nasync function killProcessTree(pid: number, child: ReturnType<typeof spawn>): Promise<void> {\n\tif (process.platform === \"win32\") {\n\t\tconst killer = spawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\tstdio: \"ignore\",\n\t\t\twindowsHide: true,\n\t\t});\n\t\tawait waitForChild(killer);\n\t\treturn;\n\t}\n\n\ttry {\n\t\tprocess.kill(-pid, \"SIGKILL\");\n\t} catch {\n\t\ttry {\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t} catch {\n\t\t\t// The process already exited between the timeout and termination request.\n\t\t}\n\t}\n}\n\nexport function createLocalBashOperations(): BashOperations {\n\treturn { run: waitForProcess };\n}\n\nfunction formatResult(stdout: OutputSnapshot, stderr: OutputSnapshot, execution: BashExecution): string {\n\tconst status: BashStatus = {\n\t\texitCode: execution.exitCode,\n\t\ttimedOut: execution.timedOut,\n\t\taborted: execution.aborted,\n\t\tstdoutTruncated: stdout.truncated,\n\t\tstderrTruncated: stderr.truncated,\n\t};\n\treturn `stdout:\\n${stdout.text || \"(empty)\"}\\n\\nstderr:\\n${stderr.text || \"(empty)\"}\\n\\nstatus: ${JSON.stringify(status)}`;\n}\n\nexport function createBashTool(allowedRoot: string, options: BashToolOptions = {}): BashTool {\n\tconst operations = options.operations ?? createLocalBashOperations();\n\tconst maxOutputBytes = options.maxOutputBytes ?? DEFAULT_BASH_MAX_OUTPUT_BYTES;\n\tconst runtime = resolveShellRuntime();\n\tassertMaxOutputBytes(maxOutputBytes);\n\n\treturn {\n\t\tname: \"bash\",\n\t\tdescription: runtime.description,\n\t\tparameters: bashParameters,\n\t\tasync execute(_toolCallId, parameters, signal): Promise<ToolResultContent[]> {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tif (parameters.command.length === 0) throw new Error(\"command must not be empty\");\n\t\t\tconst timeoutMs = parameters.timeoutMs ?? DEFAULT_BASH_TIMEOUT_MS;\n\t\t\tassertTimeout(timeoutMs);\n\t\t\tconst cwd = await realpath(allowedRoot);\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\tconst stdout = createOutputCapture(maxOutputBytes);\n\t\t\tconst stderr = createOutputCapture(maxOutputBytes);\n\t\t\tconst executionResult = await operations.run(parameters.command, cwd, {\n\t\t\t\tsignal,\n\t\t\t\ttimeoutMs,\n\t\t\t\tonStdout: (chunk) => stdout.append(chunk),\n\t\t\t\tonStderr: (chunk) => stderr.append(chunk),\n\t\t\t});\n\t\t\tconst execution = signal?.aborted ? { ...executionResult, aborted: true } : executionResult;\n\t\t\tconst output = formatResult(stdout.snapshot(), stderr.snapshot(), execution);\n\n\t\t\tif (execution.aborted) throw new Error(`Command aborted\\n\\n${output}`);\n\t\t\tif (execution.timedOut) throw new Error(`Command timed out after ${timeoutMs} ms\\n\\n${output}`);\n\t\t\tif (execution.exitCode !== 0) {\n\t\t\t\tthrow new Error(`Command exited with code ${execution.exitCode ?? \"unknown\"}\\n\\n${output}`);\n\t\t\t}\n\t\t\treturn [{ type: \"text\", text: output }];\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { realpath } from \"node:fs/promises\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport type { AgentTool } from \"@di-code/agent\";\nimport { type Static, type ToolResultContent, Type } from \"@di-code/ai\";\n\nexport const DEFAULT_BASH_TIMEOUT_MS = 30_000;\nexport const MAX_BASH_TIMEOUT_MS = 300_000;\nexport const DEFAULT_BASH_MAX_OUTPUT_BYTES = 50 * 1024;\n\nexport const bashParameters = Type.Object({\n\tcommand: Type.String({ minLength: 1 }),\n\ttimeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: MAX_BASH_TIMEOUT_MS })),\n});\n\nexport type BashParameters = Static<typeof bashParameters>;\n\nexport interface BashRunOptions {\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs: number;\n\treadonly onStdout: (chunk: Buffer) => void;\n\treadonly onStderr: (chunk: Buffer) => void;\n}\n\nexport interface BashExecution {\n\treadonly exitCode: number | null;\n\treadonly timedOut: boolean;\n\treadonly aborted: boolean;\n}\n\nexport interface BashOperations {\n\trun(command: string, cwd: string, options: BashRunOptions): Promise<BashExecution>;\n}\n\nexport interface BashToolOptions {\n\treadonly operations?: BashOperations;\n\treadonly maxOutputBytes?: number;\n}\n\nexport type BashTool = AgentTool<typeof bashParameters, ToolResultContent[]>;\n\nexport interface ShellRuntime {\n\treadonly executable: string;\n\treadonly detached: boolean;\n\treadonly description: string;\n\targs(command: string): readonly string[];\n}\n\ninterface OutputSnapshot {\n\treadonly text: string;\n\treadonly truncated: boolean;\n}\n\ninterface BashStatus {\n\treadonly exitCode: number | null;\n\treadonly timedOut: boolean;\n\treadonly aborted: boolean;\n\treadonly stdoutTruncated: boolean;\n\treadonly stderrTruncated: boolean;\n}\n\nfunction assertTimeout(timeoutMs: number): void {\n\tif (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MAX_BASH_TIMEOUT_MS) {\n\t\tthrow new Error(`timeoutMs must be an integer between 1 and ${MAX_BASH_TIMEOUT_MS}`);\n\t}\n}\n\nfunction assertMaxOutputBytes(maxOutputBytes: number): void {\n\tif (!Number.isInteger(maxOutputBytes) || maxOutputBytes < 1) {\n\t\tthrow new Error(\"maxOutputBytes must be a positive integer\");\n\t}\n}\n\nfunction createOutputCapture(maxBytes: number): {\n\tappend(chunk: Buffer): void;\n\tsnapshot(): OutputSnapshot;\n} {\n\tconst chunks: Buffer[] = [];\n\tlet bytes = 0;\n\tlet truncated = false;\n\n\treturn {\n\t\tappend(chunk) {\n\t\t\tconst remaining = maxBytes - bytes;\n\t\t\tif (remaining > 0) {\n\t\t\t\tconst kept = chunk.subarray(0, remaining);\n\t\t\t\tchunks.push(Buffer.from(kept));\n\t\t\t\tbytes += kept.length;\n\t\t\t}\n\t\t\tif (chunk.length > remaining) truncated = true;\n\t\t},\n\t\tsnapshot() {\n\t\t\tconst decoder = new StringDecoder(\"utf8\");\n\t\t\treturn { text: decoder.write(Buffer.concat(chunks, bytes)), truncated };\n\t\t},\n\t};\n}\n\nfunction createPowerShellScript(command: string): string {\n\treturn [\n\t\t\"$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)\",\n\t\t\"$script:diCodeSucceeded = $false\",\n\t\t\"$script:diCodeExitCode = 0\",\n\t\t\"& {\",\n\t\tcommand,\n\t\t\"$script:diCodeSucceeded = $?\",\n\t\t\"$script:diCodeExitCode = $LASTEXITCODE\",\n\t\t\"} | Out-Default\",\n\t\t\"if ($script:diCodeSucceeded) { exit 0 }\",\n\t\t\"if ($script:diCodeExitCode -is [int] -and $script:diCodeExitCode -ne 0) { exit $script:diCodeExitCode }\",\n\t\t\"exit 1\",\n\t].join(\"\\n\");\n}\n\nexport function resolveShellRuntime(platform: NodeJS.Platform = process.platform): ShellRuntime {\n\tif (platform === \"win32\") {\n\t\treturn {\n\t\t\texecutable: \"powershell.exe\",\n\t\t\tdetached: false,\n\t\t\tdescription:\n\t\t\t\t\"Execute a Windows PowerShell command in the allowed root with timeout and bounded output. Use PowerShell syntax such as Get-ChildItem and Get-Content; do not use Bash syntax.\",\n\t\t\targs: (command) => [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\", createPowerShellScript(command)],\n\t\t};\n\t}\n\n\treturn {\n\t\texecutable: \"/bin/sh\",\n\t\tdetached: true,\n\t\tdescription:\n\t\t\t\"Execute a POSIX shell command using /bin/sh in the allowed root with timeout and bounded output. Use portable POSIX syntax; Bash-only extensions may not be available.\",\n\t\targs: (command) => [\"-c\", command],\n\t};\n}\n\nfunction waitForProcess(command: string, cwd: string, options: BashRunOptions): Promise<BashExecution> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (options.signal?.aborted) {\n\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst runtime = resolveShellRuntime();\n\t\tconst child = spawn(runtime.executable, [...runtime.args(command)], {\n\t\t\tcwd,\n\t\t\tdetached: runtime.detached,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\twindowsHide: true,\n\t\t});\n\n\t\tlet timedOut = false;\n\t\tlet aborted = false;\n\t\tlet settled = false;\n\t\tlet termination: Promise<void> | undefined;\n\n\t\tconst requestTermination = (): void => {\n\t\t\tif (child.pid !== undefined) termination ??= killProcessTree(child.pid, child);\n\t\t};\n\t\tconst onAbort = (): void => {\n\t\t\taborted = true;\n\t\t\trequestTermination();\n\t\t};\n\t\tconst timeout = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\trequestTermination();\n\t\t}, options.timeoutMs);\n\n\t\toptions.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tif (options.signal?.aborted) onAbort();\n\t\tchild.stdout.on(\"data\", options.onStdout);\n\t\tchild.stderr.on(\"data\", options.onStderr);\n\n\t\tconst cleanup = (): void => {\n\t\t\tclearTimeout(timeout);\n\t\t\toptions.signal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\t\tchild.once(\"error\", (error) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t});\n\t\tchild.once(\"close\", (exitCode) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tvoid (termination ?? Promise.resolve()).then(\n\t\t\t\t() => resolve({ exitCode, timedOut, aborted }),\n\t\t\t\t(error: unknown) => reject(error),\n\t\t\t);\n\t\t});\n\t});\n}\n\nfunction waitForChild(child: ReturnType<typeof spawn>): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tchild.once(\"error\", () => resolve());\n\t\tchild.once(\"close\", () => resolve());\n\t});\n}\n\nasync function killProcessTree(pid: number, child: ReturnType<typeof spawn>): Promise<void> {\n\tif (process.platform === \"win32\") {\n\t\tconst killer = spawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\tstdio: \"ignore\",\n\t\t\twindowsHide: true,\n\t\t});\n\t\tawait waitForChild(killer);\n\t\treturn;\n\t}\n\n\ttry {\n\t\tprocess.kill(-pid, \"SIGKILL\");\n\t} catch {\n\t\ttry {\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t} catch {\n\t\t\t// The process already exited between the timeout and termination request.\n\t\t}\n\t}\n}\n\nexport function createLocalBashOperations(): BashOperations {\n\treturn { run: waitForProcess };\n}\n\nfunction formatResult(stdout: OutputSnapshot, stderr: OutputSnapshot, execution: BashExecution): string {\n\tconst status: BashStatus = {\n\t\texitCode: execution.exitCode,\n\t\ttimedOut: execution.timedOut,\n\t\taborted: execution.aborted,\n\t\tstdoutTruncated: stdout.truncated,\n\t\tstderrTruncated: stderr.truncated,\n\t};\n\treturn `stdout:\\n${stdout.text || \"(empty)\"}\\n\\nstderr:\\n${stderr.text || \"(empty)\"}\\n\\nstatus: ${JSON.stringify(status)}`;\n}\n\nexport function createBashTool(allowedRoot: string, options: BashToolOptions = {}): BashTool {\n\tconst operations = options.operations ?? createLocalBashOperations();\n\tconst maxOutputBytes = options.maxOutputBytes ?? DEFAULT_BASH_MAX_OUTPUT_BYTES;\n\tconst runtime = resolveShellRuntime();\n\tassertMaxOutputBytes(maxOutputBytes);\n\n\treturn {\n\t\tname: \"bash\",\n\t\tdescription: runtime.description,\n\t\tparameters: bashParameters,\n\t\tasync execute(_toolCallId, parameters, signal): Promise<ToolResultContent[]> {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tif (parameters.command.length === 0) throw new Error(\"command must not be empty\");\n\t\t\tconst timeoutMs = parameters.timeoutMs ?? DEFAULT_BASH_TIMEOUT_MS;\n\t\t\tassertTimeout(timeoutMs);\n\t\t\tconst cwd = await realpath(allowedRoot);\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\tconst stdout = createOutputCapture(maxOutputBytes);\n\t\t\tconst stderr = createOutputCapture(maxOutputBytes);\n\t\t\tconst executionResult = await operations.run(parameters.command, cwd, {\n\t\t\t\tsignal,\n\t\t\t\ttimeoutMs,\n\t\t\t\tonStdout: (chunk) => stdout.append(chunk),\n\t\t\t\tonStderr: (chunk) => stderr.append(chunk),\n\t\t\t});\n\t\t\tconst execution = signal?.aborted ? { ...executionResult, aborted: true } : executionResult;\n\t\t\tconst output = formatResult(stdout.snapshot(), stderr.snapshot(), execution);\n\n\t\t\tif (execution.aborted) throw new Error(`Command aborted\\n\\n${output}`);\n\t\t\tif (execution.timedOut) throw new Error(`Command timed out after ${timeoutMs} ms\\n\\n${output}`);\n\t\t\tif (execution.exitCode !== 0) {\n\t\t\t\tthrow new Error(`Command exited with code ${execution.exitCode ?? \"unknown\"}\\n\\n${output}`);\n\t\t\t}\n\t\t\treturn [{ type: \"text\", text: output }];\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface Edit {
|
|
2
|
+
readonly oldText: string;
|
|
3
|
+
readonly newText: string;
|
|
4
|
+
}
|
|
5
|
+
export interface EditDiffResult {
|
|
6
|
+
readonly diff: string;
|
|
7
|
+
readonly patch: string;
|
|
8
|
+
readonly firstChangedLine?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface EditDiffError {
|
|
11
|
+
readonly error: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function applyEditsToContent(content: string, edits: readonly Edit[], path: string): {
|
|
14
|
+
baseContent: string;
|
|
15
|
+
newContent: string;
|
|
16
|
+
};
|
|
17
|
+
/** Generate a standard unified patch for storage/export. */
|
|
18
|
+
export declare function generateUnifiedPatch(path: string, oldContent: string, newContent: string, contextLines?: number): string;
|
|
19
|
+
/** Generate the line-numbered display diff consumed by the interactive renderer. */
|
|
20
|
+
export declare function generateDiffString(oldContent: string, newContent: string, contextLines?: number): {
|
|
21
|
+
diff: string;
|
|
22
|
+
firstChangedLine: number | undefined;
|
|
23
|
+
};
|
|
24
|
+
export declare function computeEditsDiff(path: string, edits: readonly Edit[], cwd: string): Promise<EditDiffResult | EditDiffError>;
|
|
25
|
+
//# sourceMappingURL=edit-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-diff.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit-diff.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAqDD,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,IAAI,EAAE,MAAM,GACV;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAQ7C;AAED,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,MAAM,CAKnH;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,YAAY,SAAI,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAuDxD;AAED,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CAmBzC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { access, constants, readFile } from "node:fs/promises";
|
|
2
|
+
import * as Diff from "diff";
|
|
3
|
+
import { resolveAllowedFilePath } from "./path-boundary.js";
|
|
4
|
+
function normalizeToLF(text) {
|
|
5
|
+
return text.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
6
|
+
}
|
|
7
|
+
function stripBom(text) {
|
|
8
|
+
return text.startsWith("\uFEFF") ? text.slice(1) : text;
|
|
9
|
+
}
|
|
10
|
+
function findMatches(content, search) {
|
|
11
|
+
const matches = [];
|
|
12
|
+
let offset = 0;
|
|
13
|
+
while (offset <= content.length - search.length) {
|
|
14
|
+
const index = content.indexOf(search, offset);
|
|
15
|
+
if (index < 0)
|
|
16
|
+
break;
|
|
17
|
+
matches.push(index);
|
|
18
|
+
offset = index + 1;
|
|
19
|
+
}
|
|
20
|
+
return matches;
|
|
21
|
+
}
|
|
22
|
+
function matchEdits(content, edits, path) {
|
|
23
|
+
const matches = edits.map((edit, index) => {
|
|
24
|
+
if (edit.oldText.length === 0)
|
|
25
|
+
throw new Error(`oldText must not be empty in ${path}`);
|
|
26
|
+
const indexes = findMatches(content, edit.oldText);
|
|
27
|
+
if (indexes.length === 0) {
|
|
28
|
+
throw new Error(`Could not find edits[${index}] in ${path}. The oldText must match exactly.`);
|
|
29
|
+
}
|
|
30
|
+
if (indexes.length > 1) {
|
|
31
|
+
throw new Error(`Found ${indexes.length} occurrences of edits[${index}] in ${path}. Each oldText must be unique.`);
|
|
32
|
+
}
|
|
33
|
+
return { ...edit, matchIndex: indexes[0], matchLength: edit.oldText.length };
|
|
34
|
+
});
|
|
35
|
+
const ordered = [...matches].sort((left, right) => left.matchIndex - right.matchIndex);
|
|
36
|
+
for (let index = 1; index < ordered.length; index++) {
|
|
37
|
+
const previous = ordered[index - 1];
|
|
38
|
+
const current = ordered[index];
|
|
39
|
+
if (current.matchIndex < previous.matchIndex + previous.matchLength) {
|
|
40
|
+
throw new Error(`Edits overlap in ${path}. Merge overlapping regions into one edit.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return matches;
|
|
44
|
+
}
|
|
45
|
+
export function applyEditsToContent(content, edits, path) {
|
|
46
|
+
if (edits.length === 0)
|
|
47
|
+
throw new Error(`At least one edit is required for ${path}`);
|
|
48
|
+
const matched = matchEdits(content, edits, path).sort((left, right) => right.matchIndex - left.matchIndex);
|
|
49
|
+
let result = content;
|
|
50
|
+
for (const edit of matched) {
|
|
51
|
+
result = `${result.slice(0, edit.matchIndex)}${edit.newText}${result.slice(edit.matchIndex + edit.matchLength)}`;
|
|
52
|
+
}
|
|
53
|
+
return { baseContent: content, newContent: result };
|
|
54
|
+
}
|
|
55
|
+
/** Generate a standard unified patch for storage/export. */
|
|
56
|
+
export function generateUnifiedPatch(path, oldContent, newContent, contextLines = 4) {
|
|
57
|
+
return Diff.createTwoFilesPatch(path, path, oldContent, newContent, undefined, undefined, {
|
|
58
|
+
context: contextLines,
|
|
59
|
+
headerOptions: Diff.FILE_HEADERS_ONLY,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** Generate the line-numbered display diff consumed by the interactive renderer. */
|
|
63
|
+
export function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
64
|
+
const parts = Diff.diffLines(oldContent, newContent, { newlineIsToken: false });
|
|
65
|
+
const oldLines = oldContent.split("\n");
|
|
66
|
+
const newLines = newContent.split("\n");
|
|
67
|
+
const lineNumWidth = String(Math.max(oldLines.length, newLines.length)).length;
|
|
68
|
+
const output = [];
|
|
69
|
+
let oldLine = 1;
|
|
70
|
+
let newLine = 1;
|
|
71
|
+
let firstChangedLine;
|
|
72
|
+
let changedSeen = false;
|
|
73
|
+
for (let partIndex = 0; partIndex < parts.length; partIndex++) {
|
|
74
|
+
const part = parts[partIndex];
|
|
75
|
+
const lines = part.value.split("\n");
|
|
76
|
+
if (lines.at(-1) === "")
|
|
77
|
+
lines.pop();
|
|
78
|
+
if (part.removed) {
|
|
79
|
+
if (firstChangedLine === undefined && lines.length > 0)
|
|
80
|
+
firstChangedLine = newLine;
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
output.push(`-${String(oldLine).padStart(lineNumWidth, " ")} ${line}`);
|
|
83
|
+
oldLine += 1;
|
|
84
|
+
}
|
|
85
|
+
changedSeen = true;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (part.added) {
|
|
89
|
+
if (firstChangedLine === undefined && lines.length > 0)
|
|
90
|
+
firstChangedLine = newLine;
|
|
91
|
+
for (const line of lines) {
|
|
92
|
+
output.push(`+${String(newLine).padStart(lineNumWidth, " ")} ${line}`);
|
|
93
|
+
newLine += 1;
|
|
94
|
+
}
|
|
95
|
+
changedSeen = true;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const changedLater = parts.slice(partIndex + 1).some((candidate) => candidate.added || candidate.removed);
|
|
99
|
+
const visibleIndexes = !changedSeen && !changedLater
|
|
100
|
+
? lines.map((_line, index) => index)
|
|
101
|
+
: !changedSeen && changedLater
|
|
102
|
+
? lines.map((_line, index) => index).slice(-contextLines)
|
|
103
|
+
: changedSeen && changedLater
|
|
104
|
+
? lines.length <= contextLines * 2
|
|
105
|
+
? lines.map((_line, index) => index)
|
|
106
|
+
: [
|
|
107
|
+
...lines.map((_line, index) => index).slice(0, contextLines),
|
|
108
|
+
...lines.map((_line, index) => index).slice(-contextLines),
|
|
109
|
+
]
|
|
110
|
+
: lines.map((_line, index) => index).slice(0, contextLines);
|
|
111
|
+
for (const lineIndex of visibleIndexes) {
|
|
112
|
+
output.push(` ${String(newLine + lineIndex).padStart(lineNumWidth, " ")} ${lines[lineIndex]}`);
|
|
113
|
+
}
|
|
114
|
+
oldLine += lines.length;
|
|
115
|
+
newLine += lines.length;
|
|
116
|
+
}
|
|
117
|
+
return { diff: output.join("\n"), firstChangedLine };
|
|
118
|
+
}
|
|
119
|
+
export async function computeEditsDiff(path, edits, cwd) {
|
|
120
|
+
try {
|
|
121
|
+
const absolutePath = await resolveAllowedFilePath(path, cwd);
|
|
122
|
+
await access(absolutePath, constants.R_OK);
|
|
123
|
+
const rawContent = stripBom(await readFile(absolutePath, "utf8"));
|
|
124
|
+
const baseContent = normalizeToLF(rawContent);
|
|
125
|
+
const applied = applyEditsToContent(baseContent, edits.map((edit) => ({ oldText: normalizeToLF(edit.oldText), newText: normalizeToLF(edit.newText) })), path);
|
|
126
|
+
const display = generateDiffString(applied.baseContent, applied.newContent);
|
|
127
|
+
return {
|
|
128
|
+
...display,
|
|
129
|
+
patch: generateUnifiedPatch(path, applied.baseContent, applied.newContent),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (cause) {
|
|
133
|
+
return { error: cause instanceof Error ? cause.message : String(cause) };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=edit-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-diff.js","sourceRoot":"","sources":["../../../src/core/tools/edit-diff.ts"],"names":[],"mappings":"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","sourcesContent":["import { access, constants, readFile } from \"node:fs/promises\";\nimport * as Diff from \"diff\";\nimport { resolveAllowedFilePath } from \"./path-boundary.ts\";\n\nexport interface Edit {\n\treadonly oldText: string;\n\treadonly newText: string;\n}\n\nexport interface EditDiffResult {\n\treadonly diff: string;\n\treadonly patch: string;\n\treadonly firstChangedLine?: number;\n}\n\nexport interface EditDiffError {\n\treadonly error: string;\n}\n\ninterface MatchedEdit extends Edit {\n\treadonly matchIndex: number;\n\treadonly matchLength: number;\n}\n\nfunction normalizeToLF(text: string): string {\n\treturn text.replaceAll(\"\\r\\n\", \"\\n\").replaceAll(\"\\r\", \"\\n\");\n}\n\nfunction stripBom(text: string): string {\n\treturn text.startsWith(\"\\uFEFF\") ? text.slice(1) : text;\n}\n\nfunction findMatches(content: string, search: string): number[] {\n\tconst matches: number[] = [];\n\tlet offset = 0;\n\twhile (offset <= content.length - search.length) {\n\t\tconst index = content.indexOf(search, offset);\n\t\tif (index < 0) break;\n\t\tmatches.push(index);\n\t\toffset = index + 1;\n\t}\n\treturn matches;\n}\n\nfunction matchEdits(content: string, edits: readonly Edit[], path: string): MatchedEdit[] {\n\tconst matches = edits.map((edit, index) => {\n\t\tif (edit.oldText.length === 0) throw new Error(`oldText must not be empty in ${path}`);\n\t\tconst indexes = findMatches(content, edit.oldText);\n\t\tif (indexes.length === 0) {\n\t\t\tthrow new Error(`Could not find edits[${index}] in ${path}. The oldText must match exactly.`);\n\t\t}\n\t\tif (indexes.length > 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Found ${indexes.length} occurrences of edits[${index}] in ${path}. Each oldText must be unique.`,\n\t\t\t);\n\t\t}\n\t\treturn { ...edit, matchIndex: indexes[0], matchLength: edit.oldText.length };\n\t});\n\n\tconst ordered = [...matches].sort((left, right) => left.matchIndex - right.matchIndex);\n\tfor (let index = 1; index < ordered.length; index++) {\n\t\tconst previous = ordered[index - 1];\n\t\tconst current = ordered[index];\n\t\tif (current.matchIndex < previous.matchIndex + previous.matchLength) {\n\t\t\tthrow new Error(`Edits overlap in ${path}. Merge overlapping regions into one edit.`);\n\t\t}\n\t}\n\treturn matches;\n}\n\nexport function applyEditsToContent(\n\tcontent: string,\n\tedits: readonly Edit[],\n\tpath: string,\n): { baseContent: string; newContent: string } {\n\tif (edits.length === 0) throw new Error(`At least one edit is required for ${path}`);\n\tconst matched = matchEdits(content, edits, path).sort((left, right) => right.matchIndex - left.matchIndex);\n\tlet result = content;\n\tfor (const edit of matched) {\n\t\tresult = `${result.slice(0, edit.matchIndex)}${edit.newText}${result.slice(edit.matchIndex + edit.matchLength)}`;\n\t}\n\treturn { baseContent: content, newContent: result };\n}\n\n/** Generate a standard unified patch for storage/export. */\nexport function generateUnifiedPatch(path: string, oldContent: string, newContent: string, contextLines = 4): string {\n\treturn Diff.createTwoFilesPatch(path, path, oldContent, newContent, undefined, undefined, {\n\t\tcontext: contextLines,\n\t\theaderOptions: Diff.FILE_HEADERS_ONLY,\n\t});\n}\n\n/** Generate the line-numbered display diff consumed by the interactive renderer. */\nexport function generateDiffString(\n\toldContent: string,\n\tnewContent: string,\n\tcontextLines = 4,\n): { diff: string; firstChangedLine: number | undefined } {\n\tconst parts = Diff.diffLines(oldContent, newContent, { newlineIsToken: false });\n\tconst oldLines = oldContent.split(\"\\n\");\n\tconst newLines = newContent.split(\"\\n\");\n\tconst lineNumWidth = String(Math.max(oldLines.length, newLines.length)).length;\n\tconst output: string[] = [];\n\tlet oldLine = 1;\n\tlet newLine = 1;\n\tlet firstChangedLine: number | undefined;\n\tlet changedSeen = false;\n\tfor (let partIndex = 0; partIndex < parts.length; partIndex++) {\n\t\tconst part = parts[partIndex];\n\t\tconst lines = part.value.split(\"\\n\");\n\t\tif (lines.at(-1) === \"\") lines.pop();\n\t\tif (part.removed) {\n\t\t\tif (firstChangedLine === undefined && lines.length > 0) firstChangedLine = newLine;\n\t\t\tfor (const line of lines) {\n\t\t\t\toutput.push(`-${String(oldLine).padStart(lineNumWidth, \" \")} ${line}`);\n\t\t\t\toldLine += 1;\n\t\t\t}\n\t\t\tchangedSeen = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (part.added) {\n\t\t\tif (firstChangedLine === undefined && lines.length > 0) firstChangedLine = newLine;\n\t\t\tfor (const line of lines) {\n\t\t\t\toutput.push(`+${String(newLine).padStart(lineNumWidth, \" \")} ${line}`);\n\t\t\t\tnewLine += 1;\n\t\t\t}\n\t\t\tchangedSeen = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst changedLater = parts.slice(partIndex + 1).some((candidate) => candidate.added || candidate.removed);\n\t\tconst visibleIndexes =\n\t\t\t!changedSeen && !changedLater\n\t\t\t\t? lines.map((_line, index) => index)\n\t\t\t\t: !changedSeen && changedLater\n\t\t\t\t\t? lines.map((_line, index) => index).slice(-contextLines)\n\t\t\t\t\t: changedSeen && changedLater\n\t\t\t\t\t\t? lines.length <= contextLines * 2\n\t\t\t\t\t\t\t? lines.map((_line, index) => index)\n\t\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t\t...lines.map((_line, index) => index).slice(0, contextLines),\n\t\t\t\t\t\t\t\t\t...lines.map((_line, index) => index).slice(-contextLines),\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: lines.map((_line, index) => index).slice(0, contextLines);\n\t\tfor (const lineIndex of visibleIndexes) {\n\t\t\toutput.push(` ${String(newLine + lineIndex).padStart(lineNumWidth, \" \")} ${lines[lineIndex]}`);\n\t\t}\n\t\toldLine += lines.length;\n\t\tnewLine += lines.length;\n\t}\n\n\treturn { diff: output.join(\"\\n\"), firstChangedLine };\n}\n\nexport async function computeEditsDiff(\n\tpath: string,\n\tedits: readonly Edit[],\n\tcwd: string,\n): Promise<EditDiffResult | EditDiffError> {\n\ttry {\n\t\tconst absolutePath = await resolveAllowedFilePath(path, cwd);\n\t\tawait access(absolutePath, constants.R_OK);\n\t\tconst rawContent = stripBom(await readFile(absolutePath, \"utf8\"));\n\t\tconst baseContent = normalizeToLF(rawContent);\n\t\tconst applied = applyEditsToContent(\n\t\t\tbaseContent,\n\t\t\tedits.map((edit) => ({ oldText: normalizeToLF(edit.oldText), newText: normalizeToLF(edit.newText) })),\n\t\t\tpath,\n\t\t);\n\t\tconst display = generateDiffString(applied.baseContent, applied.newContent);\n\t\treturn {\n\t\t\t...display,\n\t\t\tpatch: generateUnifiedPatch(path, applied.baseContent, applied.newContent),\n\t\t};\n\t} catch (cause) {\n\t\treturn { error: cause instanceof Error ? cause.message : String(cause) };\n\t}\n}\n"]}
|