@mikode13/harness 4.0.1 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +299 -17
- package/dist/agent/domain/agent.d.ts +32 -1
- package/dist/agent/domain/agent.js.map +1 -1
- package/dist/agent/domain/approval.d.ts +9 -0
- package/dist/agent/domain/approval.js.map +1 -1
- package/dist/agent/domain/runContext.d.ts +31 -0
- package/dist/agent/domain/runContext.js +47 -0
- package/dist/agent/domain/runContext.js.map +1 -0
- package/dist/diff/domain/unifiedDiff.d.ts +19 -0
- package/dist/diff/domain/unifiedDiff.js +166 -0
- package/dist/diff/domain/unifiedDiff.js.map +1 -0
- package/dist/engines/domain/model/historyFollower.d.ts +41 -0
- package/dist/engines/domain/model/historyFollower.js +158 -0
- package/dist/engines/domain/model/historyFollower.js.map +1 -0
- package/dist/engines/domain/model/llmAgent.d.ts +42 -4
- package/dist/engines/domain/model/llmAgent.js +287 -31
- package/dist/engines/domain/model/llmAgent.js.map +1 -1
- package/dist/factory/infrastructure/agentFactory.d.ts +14 -0
- package/dist/factory/infrastructure/agentFactory.js +20 -2
- package/dist/factory/infrastructure/agentFactory.js.map +1 -1
- package/dist/factory/infrastructure/agentLLMFactory.d.ts +119 -14
- package/dist/factory/infrastructure/agentLLMFactory.js +284 -57
- package/dist/factory/infrastructure/agentLLMFactory.js.map +1 -1
- package/dist/index.d.ts +13 -5
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/llm/domain/conversation.d.ts +44 -4
- package/dist/llm/domain/conversation.js +56 -7
- package/dist/llm/domain/conversation.js.map +1 -1
- package/dist/llm/domain/llm.d.ts +3 -1
- package/dist/llm/domain/llm.js.map +1 -1
- package/dist/llm/domain/tool.d.ts +13 -0
- package/dist/llm/domain/tool.js +12 -1
- package/dist/llm/domain/tool.js.map +1 -1
- package/dist/llm/infrastructure/claudeLLMClient.d.ts +3 -2
- package/dist/llm/infrastructure/claudeLLMClient.js +38 -10
- package/dist/llm/infrastructure/claudeLLMClient.js.map +1 -1
- package/dist/llm/infrastructure/openAILLMClient.d.ts +2 -1
- package/dist/llm/infrastructure/openAILLMClient.js +67 -17
- package/dist/llm/infrastructure/openAILLMClient.js.map +1 -1
- package/dist/orchestration/domain/model/orchestratorAgent.d.ts +17 -3
- package/dist/orchestration/domain/model/orchestratorAgent.js +65 -8
- package/dist/orchestration/domain/model/orchestratorAgent.js.map +1 -1
- package/dist/recovery/domain/fileChanges.d.ts +31 -0
- package/dist/recovery/domain/fileChanges.js +48 -0
- package/dist/recovery/domain/fileChanges.js.map +1 -0
- package/dist/recovery/domain/history.d.ts +114 -0
- package/dist/recovery/domain/history.js +62 -0
- package/dist/recovery/domain/history.js.map +1 -0
- package/dist/recovery/domain/recoveryStore.d.ts +233 -0
- package/dist/recovery/domain/recoveryStore.js +32 -0
- package/dist/recovery/domain/recoveryStore.js.map +1 -0
- package/dist/recovery/domain/retention.d.ts +33 -0
- package/dist/recovery/domain/retention.js +90 -0
- package/dist/recovery/domain/retention.js.map +1 -0
- package/dist/recovery/domain/runChanges.d.ts +37 -0
- package/dist/recovery/domain/runChanges.js +109 -0
- package/dist/recovery/domain/runChanges.js.map +1 -0
- package/dist/recovery/domain/runTree.d.ts +32 -0
- package/dist/recovery/domain/runTree.js +90 -0
- package/dist/recovery/domain/runTree.js.map +1 -0
- package/dist/recovery/infrastructure/createHistory.d.ts +11 -0
- package/dist/recovery/infrastructure/createHistory.js +17 -0
- package/dist/recovery/infrastructure/createHistory.js.map +1 -0
- package/dist/recovery/infrastructure/fileRecoveryStore.d.ts +133 -0
- package/dist/recovery/infrastructure/fileRecoveryStore.js +1043 -0
- package/dist/recovery/infrastructure/fileRecoveryStore.js.map +1 -0
- package/dist/recovery/infrastructure/workspaceFiles.d.ts +30 -0
- package/dist/recovery/infrastructure/workspaceFiles.js +125 -0
- package/dist/recovery/infrastructure/workspaceFiles.js.map +1 -0
- package/dist/tools/domain/accessPolicy.d.ts +30 -0
- package/dist/tools/domain/accessPolicy.js +11 -0
- package/dist/tools/domain/accessPolicy.js.map +1 -0
- package/dist/tools/domain/commands.d.ts +93 -0
- package/dist/tools/domain/commands.js +191 -0
- package/dist/tools/domain/commands.js.map +1 -0
- package/dist/tools/domain/editResponse.d.ts +14 -0
- package/dist/tools/domain/editResponse.js +79 -0
- package/dist/tools/domain/editResponse.js.map +1 -0
- package/dist/tools/domain/fileEdits.d.ts +64 -0
- package/dist/tools/domain/fileEdits.js +21 -0
- package/dist/tools/domain/fileEdits.js.map +1 -0
- package/dist/tools/domain/lineLength.d.ts +7 -0
- package/dist/tools/domain/lineLength.js +26 -0
- package/dist/tools/domain/lineLength.js.map +1 -0
- package/dist/tools/domain/preparedCall.d.ts +44 -0
- package/dist/tools/domain/preparedCall.js +26 -0
- package/dist/tools/domain/preparedCall.js.map +1 -0
- package/dist/tools/domain/readRegistry.d.ts +46 -0
- package/dist/tools/domain/readRegistry.js +62 -0
- package/dist/tools/domain/readRegistry.js.map +1 -0
- package/dist/tools/domain/textLines.d.ts +26 -0
- package/dist/tools/domain/textLines.js +44 -0
- package/dist/tools/domain/textLines.js.map +1 -0
- package/dist/tools/domain/tool.d.ts +14 -0
- package/dist/tools/domain/tool.js +7 -1
- package/dist/tools/domain/tool.js.map +1 -1
- package/dist/tools/domain/v4aPatch.d.ts +17 -0
- package/dist/tools/domain/v4aPatch.js +236 -0
- package/dist/tools/domain/v4aPatch.js.map +1 -0
- package/dist/tools/infrastructure/boundedWorkspace.d.ts +11 -2
- package/dist/tools/infrastructure/boundedWorkspace.js +9 -1
- package/dist/tools/infrastructure/boundedWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/commandCheckpoint.d.ts +55 -0
- package/dist/tools/infrastructure/commandCheckpoint.js +178 -0
- package/dist/tools/infrastructure/commandCheckpoint.js.map +1 -0
- package/dist/tools/infrastructure/commandProcess.d.ts +47 -0
- package/dist/tools/infrastructure/commandProcess.js +217 -0
- package/dist/tools/infrastructure/commandProcess.js.map +1 -0
- package/dist/tools/infrastructure/commandTool.d.ts +36 -0
- package/dist/tools/infrastructure/commandTool.js +285 -0
- package/dist/tools/infrastructure/commandTool.js.map +1 -0
- package/dist/tools/infrastructure/createWorkspace.d.ts +10 -0
- package/dist/tools/infrastructure/createWorkspace.js +11 -3
- package/dist/tools/infrastructure/createWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/defineTool.d.ts +18 -2
- package/dist/tools/infrastructure/defineTool.js +52 -6
- package/dist/tools/infrastructure/defineTool.js.map +1 -1
- package/dist/tools/infrastructure/editFormats.d.ts +22 -0
- package/dist/tools/infrastructure/editFormats.js +243 -0
- package/dist/tools/infrastructure/editFormats.js.map +1 -0
- package/dist/tools/infrastructure/fileEditor.d.ts +64 -0
- package/dist/tools/infrastructure/fileEditor.js +306 -0
- package/dist/tools/infrastructure/fileEditor.js.map +1 -0
- package/dist/tools/infrastructure/fileTools.d.ts +81 -0
- package/dist/tools/infrastructure/fileTools.js +152 -0
- package/dist/tools/infrastructure/fileTools.js.map +1 -0
- package/dist/tools/infrastructure/gitIgnoreRules.d.ts +15 -0
- package/dist/tools/infrastructure/gitIgnoreRules.js +74 -0
- package/dist/tools/infrastructure/gitIgnoreRules.js.map +1 -0
- package/dist/tools/infrastructure/gitWorkspace.d.ts +1 -1
- package/dist/tools/infrastructure/gitWorkspace.js +1 -1
- package/dist/tools/infrastructure/gitWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/ignoreFileChanges.d.ts +14 -0
- package/dist/tools/infrastructure/ignoreFileChanges.js +62 -0
- package/dist/tools/infrastructure/ignoreFileChanges.js.map +1 -0
- package/dist/tools/infrastructure/policyWorkspace.d.ts +52 -0
- package/dist/tools/infrastructure/policyWorkspace.js +32 -0
- package/dist/tools/infrastructure/policyWorkspace.js.map +1 -0
- package/dist/tools/infrastructure/ripgrepWorkspace.d.ts +2 -1
- package/dist/tools/infrastructure/ripgrepWorkspace.js +1 -1
- package/dist/tools/infrastructure/ripgrepWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/rootsAccessPolicy.d.ts +100 -0
- package/dist/tools/infrastructure/rootsAccessPolicy.js +301 -0
- package/dist/tools/infrastructure/rootsAccessPolicy.js.map +1 -0
- package/dist/tools/infrastructure/runProcess.d.ts +4 -1
- package/dist/tools/infrastructure/runProcess.js +4 -2
- package/dist/tools/infrastructure/runProcess.js.map +1 -1
- package/dist/tools/infrastructure/secretPaths.d.ts +8 -0
- package/dist/tools/infrastructure/secretPaths.js +76 -0
- package/dist/tools/infrastructure/secretPaths.js.map +1 -0
- package/dist/tools/infrastructure/showChangesTool.d.ts +12 -0
- package/dist/tools/infrastructure/showChangesTool.js +44 -0
- package/dist/tools/infrastructure/showChangesTool.js.map +1 -0
- package/dist/tools/infrastructure/trackedEdits.d.ts +33 -0
- package/dist/tools/infrastructure/trackedEdits.js +70 -0
- package/dist/tools/infrastructure/trackedEdits.js.map +1 -0
- package/dist/tools/infrastructure/trackedReadFile.d.ts +21 -0
- package/dist/tools/infrastructure/trackedReadFile.js +79 -0
- package/dist/tools/infrastructure/trackedReadFile.js.map +1 -0
- package/dist/tools/infrastructure/workspaceTools.d.ts +34 -0
- package/dist/tools/infrastructure/workspaceTools.js +69 -40
- package/dist/tools/infrastructure/workspaceTools.js.map +1 -1
- package/dist/tools/infrastructure/workspaceWrites.d.ts +23 -0
- package/dist/tools/infrastructure/workspaceWrites.js +42 -0
- package/dist/tools/infrastructure/workspaceWrites.js.map +1 -0
- package/dist/tools/infrastructure/writeSession.d.ts +35 -0
- package/dist/tools/infrastructure/writeSession.js +81 -0
- package/dist/tools/infrastructure/writeSession.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { readDecision, } from '#src/agent/domain/approval';
|
|
2
2
|
import { ignoreProgress, } from '#src/agent/domain/agent';
|
|
3
|
+
import { RunContext, runContextOf, withRunContext, } from '#src/agent/domain/runContext';
|
|
3
4
|
import { InvalidAgentConfigError, RecoverableError, UnrecoverableError, withSpentTokens, } from '#src/shared/domain/errors';
|
|
4
|
-
import { classifyHostFailure, classifyProviderFailure, describeFailure, treatErrors, } from '#src/shared/domain/providerFailure';
|
|
5
|
+
import { classifyHostFailure, classifyLocalFailure, classifyProviderFailure, describeFailure, treatErrors, } from '#src/shared/domain/providerFailure';
|
|
5
6
|
import { Conversation } from '#src/llm/domain/conversation';
|
|
7
|
+
import { asNative, nativeOf } from '#src/llm/domain/tool';
|
|
8
|
+
import { prepareCall, ToolExecutionError, } from '#src/tools/domain/preparedCall';
|
|
9
|
+
import { ReadRegistry } from '#src/tools/domain/readRegistry';
|
|
10
|
+
import { InvalidToolInputError } from '#src/tools/domain/tool';
|
|
11
|
+
import { isAbortError } from '#src/shared/domain/isAbortError';
|
|
6
12
|
import { addTokens } from '#src/shared/domain/tokens';
|
|
13
|
+
import { followHistory, transcriptOf, undoNote, } from "./historyFollower.js";
|
|
7
14
|
function describePart(part) {
|
|
8
15
|
switch (part.type) {
|
|
9
16
|
case 'text':
|
|
@@ -24,16 +31,49 @@ function describePart(part) {
|
|
|
24
31
|
return undefined;
|
|
25
32
|
}
|
|
26
33
|
}
|
|
27
|
-
function narrate(part, callback) {
|
|
34
|
+
function narrate(part, callback, summary, exitCode) {
|
|
28
35
|
const event = describePart(part);
|
|
29
|
-
if (event)
|
|
30
|
-
|
|
36
|
+
if (!event)
|
|
37
|
+
return;
|
|
38
|
+
if (event.type === 'tool') {
|
|
39
|
+
if (summary !== undefined)
|
|
40
|
+
event.summary = summary;
|
|
41
|
+
if (exitCode !== undefined)
|
|
42
|
+
event.exitCode = exitCode;
|
|
43
|
+
}
|
|
44
|
+
emit(event, callback);
|
|
31
45
|
}
|
|
32
46
|
function emit(event, callback) {
|
|
33
47
|
treatErrors(() => {
|
|
34
48
|
callback(event);
|
|
35
49
|
}, classifyHostFailure, 'LLM agent progress callback failed');
|
|
36
50
|
}
|
|
51
|
+
/** `value` with the keys of every object sorted, so equal inputs serialize alike. */
|
|
52
|
+
function canonical(value) {
|
|
53
|
+
if (Array.isArray(value))
|
|
54
|
+
return value.map(canonical);
|
|
55
|
+
if (typeof value !== 'object' || value === null)
|
|
56
|
+
return value;
|
|
57
|
+
return Object.fromEntries(Object.entries(value)
|
|
58
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
59
|
+
.map(([key, inner]) => [key, canonical(inner)]));
|
|
60
|
+
}
|
|
61
|
+
// A model that asks for exactly the same calls this many times in a row is stuck: it already
|
|
62
|
+
// has what they return, and running them again changes nothing.
|
|
63
|
+
const maxRepeatedSteps = 5;
|
|
64
|
+
/** How many steps in a row have asked for exactly the same tool calls, with the same input. */
|
|
65
|
+
class RepeatedCalls {
|
|
66
|
+
last;
|
|
67
|
+
times = 0;
|
|
68
|
+
count(calls) {
|
|
69
|
+
// Keys sorted at every level: the same input with its properties in another order is the
|
|
70
|
+
// same call. Arrays, and the order of the calls, keep theirs.
|
|
71
|
+
const key = JSON.stringify(calls.map(call => [call.name, canonical(call.input)]));
|
|
72
|
+
this.times = key === this.last ? this.times + 1 : 1;
|
|
73
|
+
this.last = key;
|
|
74
|
+
return this.times;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
37
77
|
/**
|
|
38
78
|
* An agent whose conversation is owned by MiKode: every run sends the whole context to a
|
|
39
79
|
* stateless `LLMClient`. Within a run the model may call the agent's tools; the agent runs them
|
|
@@ -48,7 +88,14 @@ export class LLMAgent {
|
|
|
48
88
|
toolDefinitions;
|
|
49
89
|
maxSteps;
|
|
50
90
|
autoApprove;
|
|
51
|
-
|
|
91
|
+
logger;
|
|
92
|
+
history;
|
|
93
|
+
summarizer;
|
|
94
|
+
// The latest move through the history this conversation has followed.
|
|
95
|
+
seenRevision = 0;
|
|
96
|
+
// What this conversation has seen of each file, so an edit starts from a version it read.
|
|
97
|
+
reads = new ReadRegistry();
|
|
98
|
+
constructor({ llmClient, messages, tools = [], maxSteps = 65, autoApprove = false, logger, history, summarizer, }) {
|
|
52
99
|
if (!Number.isInteger(maxSteps) || maxSteps < 1) {
|
|
53
100
|
throw new InvalidAgentConfigError(`maxSteps must be a positive integer; got ${String(maxSteps)}`);
|
|
54
101
|
}
|
|
@@ -56,24 +103,88 @@ export class LLMAgent {
|
|
|
56
103
|
this.conversation = new Conversation(messages);
|
|
57
104
|
this.maxSteps = maxSteps;
|
|
58
105
|
this.autoApprove = autoApprove;
|
|
106
|
+
this.logger = logger;
|
|
107
|
+
this.history = history;
|
|
108
|
+
this.summarizer = summarizer;
|
|
59
109
|
this.tools = new Map(tools.map(tool => [tool.name, tool]));
|
|
60
110
|
if (this.tools.size !== tools.length) {
|
|
61
111
|
// The model calls tools by name, so a second one with the same name could never run.
|
|
62
112
|
throw new InvalidAgentConfigError('Two tools share a name; each name must be unique');
|
|
63
113
|
}
|
|
64
114
|
// The client only describes the tools to the model; running them stays with the agent.
|
|
65
|
-
this.toolDefinitions = tools.map(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
115
|
+
this.toolDefinitions = tools.map(tool => {
|
|
116
|
+
const definition = {
|
|
117
|
+
name: tool.name,
|
|
118
|
+
description: tool.description,
|
|
119
|
+
inputSchema: tool.inputSchema,
|
|
120
|
+
};
|
|
121
|
+
const native = nativeOf(tool);
|
|
122
|
+
if (native === undefined)
|
|
123
|
+
return definition;
|
|
124
|
+
// Checked now, not on the first call: an agent its client cannot serve is a setup error.
|
|
125
|
+
if (llmClient.supportsNative?.(native) !== true) {
|
|
126
|
+
throw new InvalidAgentConfigError(`The tool "${tool.name}" is the native "${native}" tool, which this model client cannot declare`);
|
|
127
|
+
}
|
|
128
|
+
return asNative(definition, native);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
async followHistory(history) {
|
|
132
|
+
try {
|
|
133
|
+
return await followHistory(this.conversation, history, this.seenRevision);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
throw classifyLocalFailure(error, 'The workspace history could not be read');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Asks the summarizer what the undone turns tried and what went wrong. A summary is a help,
|
|
141
|
+
* not a need: one that fails is reported and the plain note is used instead.
|
|
142
|
+
*/
|
|
143
|
+
async summarizeUndone(followed, signal) {
|
|
144
|
+
if (!this.summarizer)
|
|
145
|
+
return { called: false };
|
|
146
|
+
const reasons = followed.revisions.flatMap(revision => revision.reason ? [revision.reason] : []);
|
|
147
|
+
const prompt = [
|
|
148
|
+
'The user undid the work in the conversation below and moved the workspace back to before it.',
|
|
149
|
+
reasons.length > 0 ? `Their reason: ${reasons.map(reason => `«${reason}»`).join(' ')}` : '',
|
|
150
|
+
'In at most five short lines, say what was tried, why it went wrong or why the user went back, and what could be done better. Plain text, no preamble.',
|
|
151
|
+
'',
|
|
152
|
+
transcriptOf(this.conversation, followed.undone),
|
|
153
|
+
].join('\n');
|
|
154
|
+
let response;
|
|
155
|
+
try {
|
|
156
|
+
response = await this.summarizer.send({ context: [{ role: 'user', content: [{ type: 'text', text: prompt }] }], tools: [] }, signal);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (isAbortError(error))
|
|
160
|
+
throw error;
|
|
161
|
+
this.warnSummaryFailed(describeFailure(error));
|
|
162
|
+
return { called: true };
|
|
163
|
+
}
|
|
164
|
+
const usage = response.usage ? { usage: response.usage } : {};
|
|
165
|
+
// A refused or cut summary is not one: the model would read it as what was tried.
|
|
166
|
+
if (response.stopReason !== 'completed') {
|
|
167
|
+
this.warnSummaryFailed(`the model stopped with "${response.stopReason}"`);
|
|
168
|
+
return { ...usage, called: true };
|
|
169
|
+
}
|
|
170
|
+
const text = response.message.content
|
|
171
|
+
.filter(part => part.type === 'text')
|
|
172
|
+
.map(part => part.text)
|
|
173
|
+
.join('\n')
|
|
174
|
+
.trim();
|
|
175
|
+
return { ...(text ? { text } : {}), ...usage, called: true };
|
|
70
176
|
}
|
|
71
|
-
|
|
177
|
+
warnSummaryFailed(why) {
|
|
178
|
+
treatErrors(() => {
|
|
179
|
+
this.logger?.warn(`The summary of the undone turns failed: ${why}`);
|
|
180
|
+
}, classifyHostFailure, 'LLM agent logger failed');
|
|
181
|
+
}
|
|
182
|
+
async llmCall(runMessages, after, signal) {
|
|
72
183
|
let response;
|
|
73
184
|
try {
|
|
74
185
|
// Sent as a copy, so what the run records is what the agent built, whatever the client does.
|
|
75
186
|
response = await this.llmClient.send({
|
|
76
|
-
context: [...this.conversation.
|
|
187
|
+
context: [...this.conversation.contextAfter(after), ...structuredClone(runMessages)],
|
|
77
188
|
tools: this.toolDefinitions,
|
|
78
189
|
}, signal);
|
|
79
190
|
}
|
|
@@ -95,7 +206,7 @@ export class LLMAgent {
|
|
|
95
206
|
* place. Only a `destructive` call is asked about: git can undo a `mutating` one. A throwing
|
|
96
207
|
* approver ends the run, as any host callback does.
|
|
97
208
|
*/
|
|
98
|
-
async denial(call, risk, signal, approve) {
|
|
209
|
+
async denial(call, { risk, command }, signal, approve) {
|
|
99
210
|
if (this.autoApprove || risk !== 'destructive')
|
|
100
211
|
return undefined;
|
|
101
212
|
const retry = 'Do not retry the same call; choose another way, or ask the user.';
|
|
@@ -108,7 +219,14 @@ export class LLMAgent {
|
|
|
108
219
|
const input = structuredClone(call.input);
|
|
109
220
|
// Read inside the boundary: an untyped approver can answer anything, and a bad answer
|
|
110
221
|
// is its failure, which must carry the run's tokens like any other.
|
|
111
|
-
|
|
222
|
+
const request = {
|
|
223
|
+
tool: call.name,
|
|
224
|
+
input,
|
|
225
|
+
risk,
|
|
226
|
+
// A copy too: the approver must not be able to change what runs.
|
|
227
|
+
...(command ? { command: structuredClone(command) } : {}),
|
|
228
|
+
};
|
|
229
|
+
decision = readDecision(await approve(request, signal));
|
|
112
230
|
}
|
|
113
231
|
catch (error) {
|
|
114
232
|
// An approver that gives up on a cancellation, whatever it throws, did not fail.
|
|
@@ -127,8 +245,9 @@ export class LLMAgent {
|
|
|
127
245
|
* result, so the model can correct itself. Only a cancellation, or a failing approver,
|
|
128
246
|
* escapes, whatever error the tool turned it into.
|
|
129
247
|
*/
|
|
130
|
-
async runTool(call, { signal, onProgress: callback = ignoreProgress, approve }, effects) {
|
|
248
|
+
async runTool(call, { signal, onProgress: callback = ignoreProgress, approve }, effects, toolCall) {
|
|
131
249
|
const result = { type: 'toolResult', callId: call.id, name: call.name };
|
|
250
|
+
signal.throwIfAborted();
|
|
132
251
|
const tool = this.tools.get(call.name);
|
|
133
252
|
if (!tool) {
|
|
134
253
|
return {
|
|
@@ -140,33 +259,68 @@ export class LLMAgent {
|
|
|
140
259
|
denied: false,
|
|
141
260
|
};
|
|
142
261
|
}
|
|
143
|
-
let
|
|
262
|
+
let summary;
|
|
144
263
|
try {
|
|
145
|
-
|
|
264
|
+
// This is deliberately before preparation and approval. A consumer-supplied
|
|
265
|
+
// summarizer is host code, and a failed one must never leave an ambiguous call that
|
|
266
|
+
// could be replayed by RetryingAgent.
|
|
267
|
+
summary = tool.summarize?.(call.input);
|
|
146
268
|
}
|
|
147
269
|
catch (error) {
|
|
148
|
-
|
|
270
|
+
signal.throwIfAborted();
|
|
271
|
+
if (error instanceof InvalidToolInputError) {
|
|
272
|
+
return {
|
|
273
|
+
result: { ...result, output: describeFailure(error), isError: true },
|
|
274
|
+
denied: false,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
throw classifyHostFailure(error, 'The tool call summarizer failed');
|
|
278
|
+
}
|
|
279
|
+
let prepared;
|
|
280
|
+
try {
|
|
281
|
+
prepared = await prepareCall(tool, call.input, signal, toolCall);
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
signal.throwIfAborted();
|
|
285
|
+
// A call that cannot be prepared, or whose tool cannot judge it, does not run; the
|
|
286
|
+
// model reads why, such as a refused path, and can correct itself.
|
|
149
287
|
return {
|
|
150
288
|
result: { ...result, output: describeFailure(error), isError: true },
|
|
151
289
|
denied: false,
|
|
290
|
+
...(summary === undefined ? {} : { summary }),
|
|
152
291
|
};
|
|
153
292
|
}
|
|
154
|
-
|
|
293
|
+
// Preparing may have finished after a cancellation it did not notice; nobody is asked to
|
|
294
|
+
// approve a call in a run that has already stopped.
|
|
295
|
+
signal.throwIfAborted();
|
|
296
|
+
const denial = await this.denial(call, prepared, signal, approve);
|
|
155
297
|
if (denial !== undefined) {
|
|
156
|
-
return {
|
|
298
|
+
return {
|
|
299
|
+
result: { ...result, output: denial, isError: true },
|
|
300
|
+
denied: true,
|
|
301
|
+
...(summary === undefined ? {} : { summary }),
|
|
302
|
+
};
|
|
157
303
|
}
|
|
158
304
|
// Deciding took at least one await, and the run may have been cancelled meanwhile.
|
|
159
305
|
signal.throwIfAborted();
|
|
160
306
|
// Announced only once it will run: a missing, failing-to-judge or denied call never is.
|
|
161
|
-
|
|
307
|
+
emit({
|
|
308
|
+
type: 'tool',
|
|
309
|
+
id: call.id,
|
|
310
|
+
name: call.name,
|
|
311
|
+
status: 'in_progress',
|
|
312
|
+
...(summary === undefined ? {} : { summary }),
|
|
313
|
+
}, callback);
|
|
162
314
|
// Checked again at the last moment: the consumer may cancel on the announcement itself.
|
|
163
315
|
signal.throwIfAborted();
|
|
164
316
|
// Set before `execute`, so a tool that fails halfway still counts: it may have had effects.
|
|
165
317
|
effects.toolRan = true;
|
|
166
318
|
try {
|
|
167
319
|
return {
|
|
168
|
-
result: { ...result, output: await
|
|
320
|
+
result: { ...result, output: await prepared.run(signal), isError: false },
|
|
169
321
|
denied: false,
|
|
322
|
+
...(summary === undefined ? {} : { summary }),
|
|
323
|
+
...(prepared.diff === undefined ? {} : { diff: prepared.diff }),
|
|
170
324
|
};
|
|
171
325
|
}
|
|
172
326
|
catch (error) {
|
|
@@ -174,11 +328,15 @@ export class LLMAgent {
|
|
|
174
328
|
return {
|
|
175
329
|
result: { ...result, output: describeFailure(error), isError: true },
|
|
176
330
|
denied: false,
|
|
331
|
+
...(summary === undefined ? {} : { summary }),
|
|
332
|
+
...(error instanceof ToolExecutionError && error.exitCode !== undefined
|
|
333
|
+
? { exitCode: error.exitCode }
|
|
334
|
+
: {}),
|
|
177
335
|
};
|
|
178
336
|
}
|
|
179
337
|
}
|
|
180
338
|
/** One at a time and in order, so their effects and their narration never interleave. */
|
|
181
|
-
async runTools(calls, options, effects) {
|
|
339
|
+
async runTools(calls, options, effects, toolCall) {
|
|
182
340
|
const { signal, onProgress: callback = ignoreProgress } = options;
|
|
183
341
|
const results = [];
|
|
184
342
|
for (const call of calls) {
|
|
@@ -187,16 +345,76 @@ export class LLMAgent {
|
|
|
187
345
|
signal.throwIfAborted();
|
|
188
346
|
// `runTool` announces the call only once it is allowed to run, so a consumer never
|
|
189
347
|
// shows a call as running early, nor while the user is still being asked.
|
|
190
|
-
const { result, denied } = await this.runTool(call, options, effects);
|
|
191
|
-
if (denied)
|
|
192
|
-
emit({
|
|
348
|
+
const { result, denied, diff, summary, exitCode } = await this.runTool(call, options, effects, toolCall);
|
|
349
|
+
if (denied) {
|
|
350
|
+
emit({
|
|
351
|
+
type: 'tool',
|
|
352
|
+
id: call.id,
|
|
353
|
+
name: call.name,
|
|
354
|
+
status: 'denied',
|
|
355
|
+
...(summary === undefined ? {} : { summary }),
|
|
356
|
+
}, callback);
|
|
357
|
+
}
|
|
358
|
+
// The diff of a change it made, for the person watching; only once it was made.
|
|
359
|
+
else if (diff !== undefined) {
|
|
360
|
+
emit({
|
|
361
|
+
type: 'tool',
|
|
362
|
+
id: call.id,
|
|
363
|
+
name: call.name,
|
|
364
|
+
status: 'completed',
|
|
365
|
+
diff,
|
|
366
|
+
...(summary === undefined ? {} : { summary }),
|
|
367
|
+
}, callback);
|
|
368
|
+
}
|
|
193
369
|
else
|
|
194
|
-
narrate(result, callback);
|
|
370
|
+
narrate(result, callback, summary, exitCode);
|
|
195
371
|
results.push(result);
|
|
196
372
|
}
|
|
197
373
|
return { role: 'tool', content: results };
|
|
198
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Runs inside the context of the run that reached it, or in one of its own that it ends with
|
|
377
|
+
* the run: completed, failed or cancelled. Only a run that owns its context names the history
|
|
378
|
+
* run it recorded, since the run is over only when that context ends.
|
|
379
|
+
*/
|
|
199
380
|
async run(prompt, options) {
|
|
381
|
+
const inherited = runContextOf(options);
|
|
382
|
+
if (inherited)
|
|
383
|
+
return this.runSteps(prompt, options, inherited);
|
|
384
|
+
const context = new RunContext();
|
|
385
|
+
let end = 'failed';
|
|
386
|
+
let response;
|
|
387
|
+
try {
|
|
388
|
+
response = await this.runSteps(prompt, withRunContext(options, context), context);
|
|
389
|
+
end = 'completed';
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
if (isAbortError(error))
|
|
393
|
+
end = 'cancelled';
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
396
|
+
finally {
|
|
397
|
+
await this.finishContext(context, end);
|
|
398
|
+
}
|
|
399
|
+
// Read once the run ended: a run that changed nothing left the history then.
|
|
400
|
+
const { runId } = context.historyRun;
|
|
401
|
+
return runId ? { ...response, runId } : response;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* What the run started ends here, but its result stands: the changes it recorded are already
|
|
405
|
+
* on disk, so a record that could not be closed is reported, not turned into a failure.
|
|
406
|
+
*/
|
|
407
|
+
async finishContext(context, end) {
|
|
408
|
+
try {
|
|
409
|
+
await context.finish(end);
|
|
410
|
+
}
|
|
411
|
+
catch (error) {
|
|
412
|
+
treatErrors(() => {
|
|
413
|
+
this.logger?.warn(`The run could not close its records: ${describeFailure(error)}`);
|
|
414
|
+
}, classifyHostFailure, 'LLM agent logger failed');
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
async runSteps(prompt, options, context) {
|
|
200
418
|
const { signal, onProgress: callback = ignoreProgress } = options;
|
|
201
419
|
const start = Date.now();
|
|
202
420
|
const runMessages = [{ role: 'user', content: [{ type: 'text', text: prompt }] }];
|
|
@@ -205,9 +423,36 @@ export class LLMAgent {
|
|
|
205
423
|
let unreported = false;
|
|
206
424
|
// Per run, not per instance: what one run executed says nothing about another.
|
|
207
425
|
const effects = { toolRan: false };
|
|
426
|
+
// The turn this one follows: the last recorded, unless the workspace moved since.
|
|
427
|
+
let after = this.conversation.currentTurn;
|
|
428
|
+
let followed;
|
|
208
429
|
try {
|
|
430
|
+
if (this.history) {
|
|
431
|
+
followed = await this.followHistory(this.history);
|
|
432
|
+
after = followed.turn;
|
|
433
|
+
// The files may no longer hold what the conversation saw of them.
|
|
434
|
+
if (followed.revisions.length > 0)
|
|
435
|
+
this.reads.clear();
|
|
436
|
+
if (followed.undone.length > 0) {
|
|
437
|
+
const summary = await this.summarizeUndone(followed, signal);
|
|
438
|
+
tokens = addTokens(tokens, summary.usage);
|
|
439
|
+
unreported ||= summary.called && !summary.usage;
|
|
440
|
+
const note = await undoNote({
|
|
441
|
+
conversation: this.conversation,
|
|
442
|
+
history: this.history,
|
|
443
|
+
followed,
|
|
444
|
+
...(summary.text ? { summary: summary.text } : {}),
|
|
445
|
+
}).catch((error) => {
|
|
446
|
+
throw classifyLocalFailure(error, 'The workspace history could not be read');
|
|
447
|
+
});
|
|
448
|
+
runMessages[0]?.content.unshift({ type: 'text', text: note });
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// After following the history, which may have made every earlier read stale.
|
|
452
|
+
const reads = this.reads.begin();
|
|
453
|
+
const repeats = new RepeatedCalls();
|
|
209
454
|
for (let step = 1; step <= this.maxSteps; step++) {
|
|
210
|
-
const response = await this.llmCall(runMessages, signal);
|
|
455
|
+
const response = await this.llmCall(runMessages, after, signal);
|
|
211
456
|
tokens = addTokens(tokens, response.usage);
|
|
212
457
|
unreported ||= !response.usage;
|
|
213
458
|
runMessages.push(response.message);
|
|
@@ -218,8 +463,13 @@ export class LLMAgent {
|
|
|
218
463
|
}
|
|
219
464
|
const calls = response.message.content.filter(part => part.type === 'toolCall');
|
|
220
465
|
if (calls.length === 0) {
|
|
221
|
-
// Recorded only now, so a failed run leaves no tool call without its result
|
|
222
|
-
|
|
466
|
+
// Recorded only now, so a failed run leaves no tool call without its result, and a
|
|
467
|
+
// note about what was undone is given again to the next run.
|
|
468
|
+
this.conversation.addRunAfter(after, runMessages, context.historyRun);
|
|
469
|
+
// With the turns that read them, and only then: a failed run is not remembered.
|
|
470
|
+
reads.commit();
|
|
471
|
+
if (followed)
|
|
472
|
+
this.seenRevision = followed.latestRevision;
|
|
223
473
|
return {
|
|
224
474
|
// Only the final answer: text from earlier steps was narrated as it came.
|
|
225
475
|
response: response.message.content
|
|
@@ -230,9 +480,15 @@ export class LLMAgent {
|
|
|
230
480
|
duration: (Date.now() - start) / 1000,
|
|
231
481
|
};
|
|
232
482
|
}
|
|
483
|
+
// Before running them again: the model has already seen what they return.
|
|
484
|
+
if (repeats.count(calls) >= maxRepeatedSteps) {
|
|
485
|
+
throw new UnrecoverableError('The LLM repeated the same tool calls', {
|
|
486
|
+
cause: `The model asked for the same tool calls ${String(maxRepeatedSteps)} times in a row.`,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
233
489
|
// On the last step no call is left to send the results to, so the tools do not run.
|
|
234
490
|
if (step < this.maxSteps) {
|
|
235
|
-
runMessages.push(await this.runTools(calls, options, effects));
|
|
491
|
+
runMessages.push(await this.runTools(calls, options, effects, { run: context, reads }));
|
|
236
492
|
}
|
|
237
493
|
}
|
|
238
494
|
throw new UnrecoverableError('The LLM did not finish within its step limit', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llmAgent.js","sourceRoot":"","sources":["../../../../src/engines/domain/model/llmAgent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ApprovalDecision,\n\ttype Approver,\n\ttype ToolRisk,\n\treadDecision,\n} from '#src/agent/domain/approval';\nimport {\n\ttype Agent,\n\ttype AgentResponse,\n\ttype Callback,\n\ttype ProgressEvent,\n\ttype RunOptions,\n\tignoreProgress,\n} from '#src/agent/domain/agent';\nimport {\n\tInvalidAgentConfigError,\n\tRecoverableError,\n\tUnrecoverableError,\n\twithSpentTokens,\n} from '#src/shared/domain/errors';\nimport {\n\tclassifyHostFailure,\n\tclassifyProviderFailure,\n\tdescribeFailure,\n\ttreatErrors,\n} from '#src/shared/domain/providerFailure';\nimport { Conversation } from '#src/llm/domain/conversation';\nimport type { LLMClient, LLMResponse } from '#src/llm/domain/llm';\nimport type { Message, MessagePart, ToolCallPart, ToolResultPart } from '#src/llm/domain/message';\nimport type { ToolDefinition } from '#src/llm/domain/tool';\nimport type { Tool } from '#src/tools/domain/tool';\nimport { addTokens, type Tokens } from '#src/shared/domain/tokens';\n\nfunction describePart(part: MessagePart): ProgressEvent | undefined {\n\tswitch (part.type) {\n\t\tcase 'text':\n\t\t\treturn { type: 'agentMessage', message: part.text };\n\t\tcase 'reasoning':\n\t\t\treturn { type: 'reasoning', message: part.text };\n\t\tcase 'toolCall':\n\t\t\treturn { type: 'tool', id: part.id, name: part.name, status: 'in_progress' };\n\t\tcase 'toolResult':\n\t\t\treturn {\n\t\t\t\ttype: 'tool',\n\t\t\t\tid: part.callId,\n\t\t\t\tname: part.name,\n\t\t\t\tstatus: part.isError ? 'error' : 'completed',\n\t\t\t};\n\t\tcase 'providerData':\n\t\t\t// Opaque by design: its readable side, if any, arrives as a reasoning part.\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Whether a run reached a tool's `execute`. A missing tool or a denied call never does, so it\n * has no effect a retry could repeat.\n */\ninterface RunEffects {\n\ttoolRan: boolean;\n}\n\nfunction narrate(part: MessagePart, callback: Callback): void {\n\tconst event = describePart(part);\n\tif (event) emit(event, callback);\n}\n\nfunction emit(event: ProgressEvent, callback: Callback): void {\n\ttreatErrors(\n\t\t() => {\n\t\t\tcallback(event);\n\t\t},\n\t\tclassifyHostFailure,\n\t\t'LLM agent progress callback failed',\n\t);\n}\n\n/**\n * An agent whose conversation is owned by MiKode: every run sends the whole context to a\n * stateless `LLMClient`. Within a run the model may call the agent's tools; the agent runs them\n * and sends their results back until the model answers without calling one. Turn boundaries\n * are the consumer's to emit, as with the other engines; this agent only narrates what the\n * model produced and what its tools did.\n */\nexport class LLMAgent implements Agent {\n\tprivate readonly llmClient: LLMClient;\n\tprivate readonly conversation: Conversation;\n\tprivate readonly tools: Map<string, Tool>;\n\tprivate readonly toolDefinitions: ToolDefinition[];\n\tprivate readonly maxSteps: number;\n\tprivate readonly autoApprove: boolean;\n\n\tconstructor({\n\t\tllmClient,\n\t\tmessages,\n\t\ttools = [],\n\t\tmaxSteps = 25,\n\t\tautoApprove = false,\n\t}: {\n\t\tllmClient: LLMClient;\n\t\tmessages?: Message[];\n\t\ttools?: Tool[];\n\t\t/** How many calls to the model one run may make before it fails. */\n\t\tmaxSteps?: number;\n\t\t/** Runs every tool call without asking, `destructive` ones included. Meant for CI. */\n\t\tautoApprove?: boolean;\n\t}) {\n\t\tif (!Number.isInteger(maxSteps) || maxSteps < 1) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`maxSteps must be a positive integer; got ${String(maxSteps)}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.llmClient = llmClient;\n\t\tthis.conversation = new Conversation(messages);\n\t\tthis.maxSteps = maxSteps;\n\t\tthis.autoApprove = autoApprove;\n\t\tthis.tools = new Map(tools.map(tool => [tool.name, tool]));\n\t\tif (this.tools.size !== tools.length) {\n\t\t\t// The model calls tools by name, so a second one with the same name could never run.\n\t\t\tthrow new InvalidAgentConfigError('Two tools share a name; each name must be unique');\n\t\t}\n\t\t// The client only describes the tools to the model; running them stays with the agent.\n\t\tthis.toolDefinitions = tools.map(({ name, description, inputSchema }) => ({\n\t\t\tname,\n\t\t\tdescription,\n\t\t\tinputSchema,\n\t\t}));\n\t}\n\n\tprivate async llmCall(runMessages: Message[], signal: AbortSignal): Promise<LLMResponse> {\n\t\tlet response: LLMResponse;\n\t\ttry {\n\t\t\t// Sent as a copy, so what the run records is what the agent built, whatever the client does.\n\t\t\tresponse = await this.llmClient.send(\n\t\t\t\t{\n\t\t\t\t\tcontext: [...this.conversation.getContext(), ...structuredClone(runMessages)],\n\t\t\t\t\ttools: this.toolDefinitions,\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow classifyProviderFailure(error, 'The LLM call failed');\n\t\t}\n\n\t\tif (response.stopReason !== 'completed') {\n\t\t\tthrow new UnrecoverableError('The LLM stopped before completing its answer', {\n\t\t\t\tcause: `The model stopped with \"${response.stopReason}\".`,\n\t\t\t\t// The call was billed even though its answer is unusable.\n\t\t\t\ttokens: response.usage,\n\t\t\t\tusageUnreported: !response.usage,\n\t\t\t});\n\t\t}\n\n\t\treturn response;\n\t}\n\n\t/**\n\t * Undefined when the call may run; otherwise why it may not, which the model receives in its\n\t * place. Only a `destructive` call is asked about: git can undo a `mutating` one. A throwing\n\t * approver ends the run, as any host callback does.\n\t */\n\tprivate async denial(\n\t\tcall: ToolCallPart,\n\t\trisk: ToolRisk,\n\t\tsignal: AbortSignal,\n\t\tapprove: Approver | undefined,\n\t): Promise<string | undefined> {\n\t\tif (this.autoApprove || risk !== 'destructive') return undefined;\n\n\t\tconst retry = 'Do not retry the same call; choose another way, or ask the user.';\n\t\tif (!approve) {\n\t\t\treturn `The call to \"${call.name}\" was denied: it is destructive, and no one was asked to allow it. ${retry}`;\n\t\t}\n\n\t\tlet decision: ApprovalDecision;\n\t\ttry {\n\t\t\t// A copy, so what runs and what the conversation keeps is exactly what was approved.\n\t\t\tconst input: unknown = structuredClone(call.input);\n\t\t\t// Read inside the boundary: an untyped approver can answer anything, and a bad answer\n\t\t\t// is its failure, which must carry the run's tokens like any other.\n\t\t\tdecision = readDecision(await approve({ tool: call.name, input, risk }, signal));\n\t\t} catch (error) {\n\t\t\t// An approver that gives up on a cancellation, whatever it throws, did not fail.\n\t\t\tsignal.throwIfAborted();\n\t\t\tthrow classifyHostFailure(error, 'The tool call approver failed');\n\t\t}\n\t\t// The user may cancel the run while they are being asked.\n\t\tsignal.throwIfAborted();\n\t\tif (decision.approved) return undefined;\n\n\t\tconst reason = decision.reason ? ` Their reason: ${decision.reason}` : '';\n\t\treturn `The user denied the call to \"${call.name}\".${reason} ${retry}`;\n\t}\n\n\t/**\n\t * Always answers the call: a missing tool, a denied call or a failing one becomes an error\n\t * result, so the model can correct itself. Only a cancellation, or a failing approver,\n\t * escapes, whatever error the tool turned it into.\n\t */\n\tprivate async runTool(\n\t\tcall: ToolCallPart,\n\t\t{ signal, onProgress: callback = ignoreProgress, approve }: RunOptions,\n\t\teffects: RunEffects,\n\t): Promise<{ result: ToolResultPart; denied: boolean }> {\n\t\tconst result = { type: 'toolResult' as const, callId: call.id, name: call.name };\n\t\tconst tool = this.tools.get(call.name);\n\t\tif (!tool) {\n\t\t\treturn {\n\t\t\t\tresult: {\n\t\t\t\t\t...result,\n\t\t\t\t\toutput: `There is no tool named \"${call.name}\". Available tools: ${[...this.tools.keys()].join(', ') || 'none'}.`,\n\t\t\t\t\tisError: true,\n\t\t\t\t},\n\t\t\t\tdenied: false,\n\t\t\t};\n\t\t}\n\n\t\tlet risk: ToolRisk;\n\t\ttry {\n\t\t\trisk = tool.risk(call.input);\n\t\t} catch (error) {\n\t\t\t// A tool that cannot judge its own call is a failing tool, and the call does not run.\n\t\t\treturn {\n\t\t\t\tresult: { ...result, output: describeFailure(error), isError: true },\n\t\t\t\tdenied: false,\n\t\t\t};\n\t\t}\n\n\t\tconst denial = await this.denial(call, risk, signal, approve);\n\t\tif (denial !== undefined) {\n\t\t\treturn { result: { ...result, output: denial, isError: true }, denied: true };\n\t\t}\n\n\t\t// Deciding took at least one await, and the run may have been cancelled meanwhile.\n\t\tsignal.throwIfAborted();\n\t\t// Announced only once it will run: a missing, failing-to-judge or denied call never is.\n\t\tnarrate(call, callback);\n\t\t// Checked again at the last moment: the consumer may cancel on the announcement itself.\n\t\tsignal.throwIfAborted();\n\t\t// Set before `execute`, so a tool that fails halfway still counts: it may have had effects.\n\t\teffects.toolRan = true;\n\t\ttry {\n\t\t\treturn {\n\t\t\t\tresult: { ...result, output: await tool.execute(call.input, signal), isError: false },\n\t\t\t\tdenied: false,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn {\n\t\t\t\tresult: { ...result, output: describeFailure(error), isError: true },\n\t\t\t\tdenied: false,\n\t\t\t};\n\t\t}\n\t}\n\n\t/** One at a time and in order, so their effects and their narration never interleave. */\n\tprivate async runTools(\n\t\tcalls: ToolCallPart[],\n\t\toptions: RunOptions,\n\t\teffects: RunEffects,\n\t): Promise<Message> {\n\t\tconst { signal, onProgress: callback = ignoreProgress } = options;\n\t\tconst results: MessagePart[] = [];\n\t\tfor (const call of calls) {\n\t\t\t// A call before this one may have ignored the cancellation; this one must not start,\n\t\t\t// nor be announced as running.\n\t\t\tsignal.throwIfAborted();\n\t\t\t// `runTool` announces the call only once it is allowed to run, so a consumer never\n\t\t\t// shows a call as running early, nor while the user is still being asked.\n\t\t\tconst { result, denied } = await this.runTool(call, options, effects);\n\t\t\tif (denied) emit({ type: 'tool', id: call.id, name: call.name, status: 'denied' }, callback);\n\t\t\telse narrate(result, callback);\n\t\t\tresults.push(result);\n\t\t}\n\n\t\treturn { role: 'tool', content: results };\n\t}\n\n\tasync run(prompt: string, options: RunOptions): Promise<AgentResponse> {\n\t\tconst { signal, onProgress: callback = ignoreProgress } = options;\n\t\tconst start = Date.now();\n\t\tconst runMessages: Message[] = [{ role: 'user', content: [{ type: 'text', text: prompt }] }];\n\t\tlet tokens: Tokens | undefined;\n\t\t// Once one call went unreported the run's total is unknown, however many report later.\n\t\tlet unreported = false;\n\t\t// Per run, not per instance: what one run executed says nothing about another.\n\t\tconst effects: RunEffects = { toolRan: false };\n\n\t\ttry {\n\t\t\tfor (let step = 1; step <= this.maxSteps; step++) {\n\t\t\t\tconst response = await this.llmCall(runMessages, signal);\n\t\t\t\ttokens = addTokens(tokens, response.usage);\n\t\t\t\tunreported ||= !response.usage;\n\t\t\t\trunMessages.push(response.message);\n\n\t\t\t\t// Tool calls are narrated as they start, in `runTools`, and never if they do not run.\n\t\t\t\tfor (const part of response.message.content) {\n\t\t\t\t\tif (part.type !== 'toolCall') narrate(part, callback);\n\t\t\t\t}\n\n\t\t\t\tconst calls = response.message.content.filter(part => part.type === 'toolCall');\n\t\t\t\tif (calls.length === 0) {\n\t\t\t\t\t// Recorded only now, so a failed run leaves no tool call without its result.\n\t\t\t\t\tthis.conversation.addRun(runMessages);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t// Only the final answer: text from earlier steps was narrated as it came.\n\t\t\t\t\t\tresponse: response.message.content\n\t\t\t\t\t\t\t.filter(part => part.type === 'text')\n\t\t\t\t\t\t\t.map(part => part.text)\n\t\t\t\t\t\t\t.join('\\n'),\n\t\t\t\t\t\ttokens: unreported ? undefined : tokens,\n\t\t\t\t\t\tduration: (Date.now() - start) / 1000,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// On the last step no call is left to send the results to, so the tools do not run.\n\t\t\t\tif (step < this.maxSteps) {\n\t\t\t\t\trunMessages.push(await this.runTools(calls, options, effects));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new UnrecoverableError('The LLM did not finish within its step limit', {\n\t\t\t\tcause: `The model was still calling tools after ${String(this.maxSteps)} steps.`,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlet failure = error;\n\t\t\tif (effects.toolRan && error instanceof RecoverableError) {\n\t\t\t\t// RetryingAgent would run the whole prompt again, and with it every tool this run\n\t\t\t\t// already executed, so a failure after one ran must not invite a retry.\n\t\t\t\tconst unrecoverable = new UnrecoverableError(error.message, {\n\t\t\t\t\tcause: error.cause,\n\t\t\t\t\ttokens: error.tokens,\n\t\t\t\t\tusageUnreported: error.usageUnreported,\n\t\t\t\t});\n\t\t\t\tunrecoverable.stack = error.stack;\n\t\t\t\tfailure = unrecoverable;\n\t\t\t}\n\n\t\t\t// The run spent the tokens of every step before the one that failed.\n\t\t\tthrow withSpentTokens(failure, tokens, unreported);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"llmAgent.js","sourceRoot":"","sources":["../../../../src/engines/domain/model/llmAgent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ApprovalDecision,\n\ttype ApprovalRequest,\n\ttype Approver,\n\treadDecision,\n} from '#src/agent/domain/approval';\nimport {\n\ttype Agent,\n\ttype AgentResponse,\n\ttype Callback,\n\ttype ProgressEvent,\n\ttype RunOptions,\n\tignoreProgress,\n} from '#src/agent/domain/agent';\nimport {\n\ttype RunEnd,\n\tRunContext,\n\trunContextOf,\n\twithRunContext,\n} from '#src/agent/domain/runContext';\nimport {\n\tInvalidAgentConfigError,\n\tRecoverableError,\n\tUnrecoverableError,\n\twithSpentTokens,\n} from '#src/shared/domain/errors';\nimport {\n\tclassifyHostFailure,\n\tclassifyLocalFailure,\n\tclassifyProviderFailure,\n\tdescribeFailure,\n\ttreatErrors,\n} from '#src/shared/domain/providerFailure';\nimport { Conversation } from '#src/llm/domain/conversation';\nimport type { LLMClient, LLMResponse } from '#src/llm/domain/llm';\nimport type { Message, MessagePart, ToolCallPart, ToolResultPart } from '#src/llm/domain/message';\nimport { asNative, nativeOf, type ToolDefinition } from '#src/llm/domain/tool';\nimport {\n\ttype AgentTool,\n\ttype PreparedCall,\n\tprepareCall,\n\tToolExecutionError,\n} from '#src/tools/domain/preparedCall';\nimport { ReadRegistry, type ToolCallContext } from '#src/tools/domain/readRegistry';\nimport { InvalidToolInputError } from '#src/tools/domain/tool';\nimport { isAbortError } from '#src/shared/domain/isAbortError';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport { addTokens, type Tokens } from '#src/shared/domain/tokens';\nimport {\n\ttype Followed,\n\tfollowHistory,\n\ttype HistoryReader,\n\ttranscriptOf,\n\tundoNote,\n} from './historyFollower.ts';\n\nfunction describePart(part: MessagePart): ProgressEvent | undefined {\n\tswitch (part.type) {\n\t\tcase 'text':\n\t\t\treturn { type: 'agentMessage', message: part.text };\n\t\tcase 'reasoning':\n\t\t\treturn { type: 'reasoning', message: part.text };\n\t\tcase 'toolCall':\n\t\t\treturn { type: 'tool', id: part.id, name: part.name, status: 'in_progress' };\n\t\tcase 'toolResult':\n\t\t\treturn {\n\t\t\t\ttype: 'tool',\n\t\t\t\tid: part.callId,\n\t\t\t\tname: part.name,\n\t\t\t\tstatus: part.isError ? 'error' : 'completed',\n\t\t\t};\n\t\tcase 'providerData':\n\t\t\t// Opaque by design: its readable side, if any, arrives as a reasoning part.\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Whether a run reached a tool's `execute`. A missing tool or a denied call never does, so it\n * has no effect a retry could repeat.\n */\ninterface RunEffects {\n\ttoolRan: boolean;\n}\n\nfunction narrate(part: MessagePart, callback: Callback, summary?: string, exitCode?: number): void {\n\tconst event = describePart(part);\n\tif (!event) return;\n\tif (event.type === 'tool') {\n\t\tif (summary !== undefined) event.summary = summary;\n\t\tif (exitCode !== undefined) event.exitCode = exitCode;\n\t}\n\temit(event, callback);\n}\n\nfunction emit(event: ProgressEvent, callback: Callback): void {\n\ttreatErrors(\n\t\t() => {\n\t\t\tcallback(event);\n\t\t},\n\t\tclassifyHostFailure,\n\t\t'LLM agent progress callback failed',\n\t);\n}\n\n/** `value` with the keys of every object sorted, so equal inputs serialize alike. */\nfunction canonical(value: unknown): unknown {\n\tif (Array.isArray(value)) return value.map(canonical);\n\tif (typeof value !== 'object' || value === null) return value;\n\treturn Object.fromEntries(\n\t\tObject.entries(value)\n\t\t\t.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t\t.map(([key, inner]) => [key, canonical(inner)]),\n\t);\n}\n\n// A model that asks for exactly the same calls this many times in a row is stuck: it already\n// has what they return, and running them again changes nothing.\nconst maxRepeatedSteps = 5;\n\n/** How many steps in a row have asked for exactly the same tool calls, with the same input. */\nclass RepeatedCalls {\n\tprivate last: string | undefined;\n\tprivate times = 0;\n\n\tcount(calls: readonly ToolCallPart[]): number {\n\t\t// Keys sorted at every level: the same input with its properties in another order is the\n\t\t// same call. Arrays, and the order of the calls, keep theirs.\n\t\tconst key = JSON.stringify(calls.map(call => [call.name, canonical(call.input)]));\n\t\tthis.times = key === this.last ? this.times + 1 : 1;\n\t\tthis.last = key;\n\t\treturn this.times;\n\t}\n}\n\n/**\n * An agent whose conversation is owned by MiKode: every run sends the whole context to a\n * stateless `LLMClient`. Within a run the model may call the agent's tools; the agent runs them\n * and sends their results back until the model answers without calling one. Turn boundaries\n * are the consumer's to emit, as with the other engines; this agent only narrates what the\n * model produced and what its tools did.\n */\nexport class LLMAgent implements Agent {\n\tprivate readonly llmClient: LLMClient;\n\tprivate readonly conversation: Conversation;\n\tprivate readonly tools: Map<string, AgentTool>;\n\tprivate readonly toolDefinitions: ToolDefinition[];\n\tprivate readonly maxSteps: number;\n\tprivate readonly autoApprove: boolean;\n\tprivate readonly logger: ILogger | undefined;\n\tprivate readonly history: HistoryReader | undefined;\n\tprivate readonly summarizer: LLMClient | undefined;\n\t// The latest move through the history this conversation has followed.\n\tprivate seenRevision = 0;\n\t// What this conversation has seen of each file, so an edit starts from a version it read.\n\tprivate readonly reads = new ReadRegistry();\n\n\tconstructor({\n\t\tllmClient,\n\t\tmessages,\n\t\ttools = [],\n\t\tmaxSteps = 65,\n\t\tautoApprove = false,\n\t\tlogger,\n\t\thistory,\n\t\tsummarizer,\n\t}: {\n\t\tllmClient: LLMClient;\n\t\tmessages?: Message[];\n\t\ttools?: AgentTool[];\n\t\t/** How many calls to the model one run may make before it fails. Defaults to 65. */\n\t\tmaxSteps?: number;\n\t\t/** Runs every tool call without asking, `destructive` ones included. Meant for CI. */\n\t\tautoApprove?: boolean;\n\t\t/** Where a failure the agent absorbs is reported. The factories always pass one. */\n\t\tlogger?: ILogger;\n\t\t/**\n\t\t * The history of the workspace this agent writes to. With it, each run first follows the\n\t\t * moves the user made through that history: the conversation goes back with the\n\t\t * workspace, and the model is told what was undone.\n\t\t */\n\t\thistory?: HistoryReader;\n\t\t/**\n\t\t * A cheap model that summarizes what the undone turns tried and what went wrong. Without\n\t\t * one, the model is told what those turns asked, word for word.\n\t\t */\n\t\tsummarizer?: LLMClient;\n\t}) {\n\t\tif (!Number.isInteger(maxSteps) || maxSteps < 1) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`maxSteps must be a positive integer; got ${String(maxSteps)}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.llmClient = llmClient;\n\t\tthis.conversation = new Conversation(messages);\n\t\tthis.maxSteps = maxSteps;\n\t\tthis.autoApprove = autoApprove;\n\t\tthis.logger = logger;\n\t\tthis.history = history;\n\t\tthis.summarizer = summarizer;\n\t\tthis.tools = new Map(tools.map(tool => [tool.name, tool]));\n\t\tif (this.tools.size !== tools.length) {\n\t\t\t// The model calls tools by name, so a second one with the same name could never run.\n\t\t\tthrow new InvalidAgentConfigError('Two tools share a name; each name must be unique');\n\t\t}\n\t\t// The client only describes the tools to the model; running them stays with the agent.\n\t\tthis.toolDefinitions = tools.map(tool => {\n\t\t\tconst definition = {\n\t\t\t\tname: tool.name,\n\t\t\t\tdescription: tool.description,\n\t\t\t\tinputSchema: tool.inputSchema,\n\t\t\t};\n\t\t\tconst native = nativeOf(tool);\n\t\t\tif (native === undefined) return definition;\n\t\t\t// Checked now, not on the first call: an agent its client cannot serve is a setup error.\n\t\t\tif (llmClient.supportsNative?.(native) !== true) {\n\t\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t\t`The tool \"${tool.name}\" is the native \"${native}\" tool, which this model client cannot declare`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn asNative(definition, native);\n\t\t});\n\t}\n\n\tprivate async followHistory(history: HistoryReader): Promise<Followed> {\n\t\ttry {\n\t\t\treturn await followHistory(this.conversation, history, this.seenRevision);\n\t\t} catch (error) {\n\t\t\tthrow classifyLocalFailure(error, 'The workspace history could not be read');\n\t\t}\n\t}\n\n\t/**\n\t * Asks the summarizer what the undone turns tried and what went wrong. A summary is a help,\n\t * not a need: one that fails is reported and the plain note is used instead.\n\t */\n\tprivate async summarizeUndone(\n\t\tfollowed: Followed,\n\t\tsignal: AbortSignal,\n\t): Promise<{ text?: string; usage?: Tokens; called: boolean }> {\n\t\tif (!this.summarizer) return { called: false };\n\t\tconst reasons = followed.revisions.flatMap(revision =>\n\t\t\trevision.reason ? [revision.reason] : [],\n\t\t);\n\t\tconst prompt = [\n\t\t\t'The user undid the work in the conversation below and moved the workspace back to before it.',\n\t\t\treasons.length > 0 ? `Their reason: ${reasons.map(reason => `«${reason}»`).join(' ')}` : '',\n\t\t\t'In at most five short lines, say what was tried, why it went wrong or why the user went back, and what could be done better. Plain text, no preamble.',\n\t\t\t'',\n\t\t\ttranscriptOf(this.conversation, followed.undone),\n\t\t].join('\\n');\n\n\t\tlet response: LLMResponse;\n\t\ttry {\n\t\t\tresponse = await this.summarizer.send(\n\t\t\t\t{ context: [{ role: 'user', content: [{ type: 'text', text: prompt }] }], tools: [] },\n\t\t\t\tsignal,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (isAbortError(error)) throw error;\n\t\t\tthis.warnSummaryFailed(describeFailure(error));\n\t\t\treturn { called: true };\n\t\t}\n\n\t\tconst usage = response.usage ? { usage: response.usage } : {};\n\t\t// A refused or cut summary is not one: the model would read it as what was tried.\n\t\tif (response.stopReason !== 'completed') {\n\t\t\tthis.warnSummaryFailed(`the model stopped with \"${response.stopReason}\"`);\n\t\t\treturn { ...usage, called: true };\n\t\t}\n\t\tconst text = response.message.content\n\t\t\t.filter(part => part.type === 'text')\n\t\t\t.map(part => part.text)\n\t\t\t.join('\\n')\n\t\t\t.trim();\n\t\treturn { ...(text ? { text } : {}), ...usage, called: true };\n\t}\n\n\tprivate warnSummaryFailed(why: string): void {\n\t\ttreatErrors(\n\t\t\t() => {\n\t\t\t\tthis.logger?.warn(`The summary of the undone turns failed: ${why}`);\n\t\t\t},\n\t\t\tclassifyHostFailure,\n\t\t\t'LLM agent logger failed',\n\t\t);\n\t}\n\n\tprivate async llmCall(\n\t\trunMessages: Message[],\n\t\tafter: number | undefined,\n\t\tsignal: AbortSignal,\n\t): Promise<LLMResponse> {\n\t\tlet response: LLMResponse;\n\t\ttry {\n\t\t\t// Sent as a copy, so what the run records is what the agent built, whatever the client does.\n\t\t\tresponse = await this.llmClient.send(\n\t\t\t\t{\n\t\t\t\t\tcontext: [...this.conversation.contextAfter(after), ...structuredClone(runMessages)],\n\t\t\t\t\ttools: this.toolDefinitions,\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow classifyProviderFailure(error, 'The LLM call failed');\n\t\t}\n\n\t\tif (response.stopReason !== 'completed') {\n\t\t\tthrow new UnrecoverableError('The LLM stopped before completing its answer', {\n\t\t\t\tcause: `The model stopped with \"${response.stopReason}\".`,\n\t\t\t\t// The call was billed even though its answer is unusable.\n\t\t\t\ttokens: response.usage,\n\t\t\t\tusageUnreported: !response.usage,\n\t\t\t});\n\t\t}\n\n\t\treturn response;\n\t}\n\n\t/**\n\t * Undefined when the call may run; otherwise why it may not, which the model receives in its\n\t * place. Only a `destructive` call is asked about: git can undo a `mutating` one. A throwing\n\t * approver ends the run, as any host callback does.\n\t */\n\tprivate async denial(\n\t\tcall: ToolCallPart,\n\t\t{ risk, command }: PreparedCall,\n\t\tsignal: AbortSignal,\n\t\tapprove: Approver | undefined,\n\t): Promise<string | undefined> {\n\t\tif (this.autoApprove || risk !== 'destructive') return undefined;\n\n\t\tconst retry = 'Do not retry the same call; choose another way, or ask the user.';\n\t\tif (!approve) {\n\t\t\treturn `The call to \"${call.name}\" was denied: it is destructive, and no one was asked to allow it. ${retry}`;\n\t\t}\n\n\t\tlet decision: ApprovalDecision;\n\t\ttry {\n\t\t\t// A copy, so what runs and what the conversation keeps is exactly what was approved.\n\t\t\tconst input: unknown = structuredClone(call.input);\n\t\t\t// Read inside the boundary: an untyped approver can answer anything, and a bad answer\n\t\t\t// is its failure, which must carry the run's tokens like any other.\n\t\t\tconst request: ApprovalRequest = {\n\t\t\t\ttool: call.name,\n\t\t\t\tinput,\n\t\t\t\trisk,\n\t\t\t\t// A copy too: the approver must not be able to change what runs.\n\t\t\t\t...(command ? { command: structuredClone(command) } : {}),\n\t\t\t};\n\t\t\tdecision = readDecision(await approve(request, signal));\n\t\t} catch (error) {\n\t\t\t// An approver that gives up on a cancellation, whatever it throws, did not fail.\n\t\t\tsignal.throwIfAborted();\n\t\t\tthrow classifyHostFailure(error, 'The tool call approver failed');\n\t\t}\n\t\t// The user may cancel the run while they are being asked.\n\t\tsignal.throwIfAborted();\n\t\tif (decision.approved) return undefined;\n\n\t\tconst reason = decision.reason ? ` Their reason: ${decision.reason}` : '';\n\t\treturn `The user denied the call to \"${call.name}\".${reason} ${retry}`;\n\t}\n\n\t/**\n\t * Always answers the call: a missing tool, a denied call or a failing one becomes an error\n\t * result, so the model can correct itself. Only a cancellation, or a failing approver,\n\t * escapes, whatever error the tool turned it into.\n\t */\n\tprivate async runTool(\n\t\tcall: ToolCallPart,\n\t\t{ signal, onProgress: callback = ignoreProgress, approve }: RunOptions,\n\t\teffects: RunEffects,\n\t\ttoolCall: ToolCallContext,\n\t): Promise<{\n\t\tresult: ToolResultPart;\n\t\tdenied: boolean;\n\t\tdiff?: string;\n\t\tsummary?: string;\n\t\texitCode?: number;\n\t}> {\n\t\tconst result = { type: 'toolResult' as const, callId: call.id, name: call.name };\n\t\tsignal.throwIfAborted();\n\t\tconst tool = this.tools.get(call.name);\n\t\tif (!tool) {\n\t\t\treturn {\n\t\t\t\tresult: {\n\t\t\t\t\t...result,\n\t\t\t\t\toutput: `There is no tool named \"${call.name}\". Available tools: ${[...this.tools.keys()].join(', ') || 'none'}.`,\n\t\t\t\t\tisError: true,\n\t\t\t\t},\n\t\t\t\tdenied: false,\n\t\t\t};\n\t\t}\n\n\t\tlet summary: string | undefined;\n\t\ttry {\n\t\t\t// This is deliberately before preparation and approval. A consumer-supplied\n\t\t\t// summarizer is host code, and a failed one must never leave an ambiguous call that\n\t\t\t// could be replayed by RetryingAgent.\n\t\t\tsummary = tool.summarize?.(call.input);\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\tif (error instanceof InvalidToolInputError) {\n\t\t\t\treturn {\n\t\t\t\t\tresult: { ...result, output: describeFailure(error), isError: true },\n\t\t\t\t\tdenied: false,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow classifyHostFailure(error, 'The tool call summarizer failed');\n\t\t}\n\n\t\tlet prepared: PreparedCall;\n\t\ttry {\n\t\t\tprepared = await prepareCall(tool, call.input, signal, toolCall);\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\t// A call that cannot be prepared, or whose tool cannot judge it, does not run; the\n\t\t\t// model reads why, such as a refused path, and can correct itself.\n\t\t\treturn {\n\t\t\t\tresult: { ...result, output: describeFailure(error), isError: true },\n\t\t\t\tdenied: false,\n\t\t\t\t...(summary === undefined ? {} : { summary }),\n\t\t\t};\n\t\t}\n\n\t\t// Preparing may have finished after a cancellation it did not notice; nobody is asked to\n\t\t// approve a call in a run that has already stopped.\n\t\tsignal.throwIfAborted();\n\t\tconst denial = await this.denial(call, prepared, signal, approve);\n\t\tif (denial !== undefined) {\n\t\t\treturn {\n\t\t\t\tresult: { ...result, output: denial, isError: true },\n\t\t\t\tdenied: true,\n\t\t\t\t...(summary === undefined ? {} : { summary }),\n\t\t\t};\n\t\t}\n\n\t\t// Deciding took at least one await, and the run may have been cancelled meanwhile.\n\t\tsignal.throwIfAborted();\n\t\t// Announced only once it will run: a missing, failing-to-judge or denied call never is.\n\t\temit(\n\t\t\t{\n\t\t\t\ttype: 'tool',\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tstatus: 'in_progress',\n\t\t\t\t...(summary === undefined ? {} : { summary }),\n\t\t\t},\n\t\t\tcallback,\n\t\t);\n\t\t// Checked again at the last moment: the consumer may cancel on the announcement itself.\n\t\tsignal.throwIfAborted();\n\t\t// Set before `execute`, so a tool that fails halfway still counts: it may have had effects.\n\t\teffects.toolRan = true;\n\t\ttry {\n\t\t\treturn {\n\t\t\t\tresult: { ...result, output: await prepared.run(signal), isError: false },\n\t\t\t\tdenied: false,\n\t\t\t\t...(summary === undefined ? {} : { summary }),\n\t\t\t\t...(prepared.diff === undefined ? {} : { diff: prepared.diff }),\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn {\n\t\t\t\tresult: { ...result, output: describeFailure(error), isError: true },\n\t\t\t\tdenied: false,\n\t\t\t\t...(summary === undefined ? {} : { summary }),\n\t\t\t\t...(error instanceof ToolExecutionError && error.exitCode !== undefined\n\t\t\t\t\t? { exitCode: error.exitCode }\n\t\t\t\t\t: {}),\n\t\t\t};\n\t\t}\n\t}\n\n\t/** One at a time and in order, so their effects and their narration never interleave. */\n\tprivate async runTools(\n\t\tcalls: ToolCallPart[],\n\t\toptions: RunOptions,\n\t\teffects: RunEffects,\n\t\ttoolCall: ToolCallContext,\n\t): Promise<Message> {\n\t\tconst { signal, onProgress: callback = ignoreProgress } = options;\n\t\tconst results: MessagePart[] = [];\n\t\tfor (const call of calls) {\n\t\t\t// A call before this one may have ignored the cancellation; this one must not start,\n\t\t\t// nor be announced as running.\n\t\t\tsignal.throwIfAborted();\n\t\t\t// `runTool` announces the call only once it is allowed to run, so a consumer never\n\t\t\t// shows a call as running early, nor while the user is still being asked.\n\t\t\tconst { result, denied, diff, summary, exitCode } = await this.runTool(\n\t\t\t\tcall,\n\t\t\t\toptions,\n\t\t\t\teffects,\n\t\t\t\ttoolCall,\n\t\t\t);\n\t\t\tif (denied) {\n\t\t\t\temit(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'tool',\n\t\t\t\t\t\tid: call.id,\n\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\tstatus: 'denied',\n\t\t\t\t\t\t...(summary === undefined ? {} : { summary }),\n\t\t\t\t\t},\n\t\t\t\t\tcallback,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// The diff of a change it made, for the person watching; only once it was made.\n\t\t\telse if (diff !== undefined) {\n\t\t\t\temit(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'tool',\n\t\t\t\t\t\tid: call.id,\n\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\tdiff,\n\t\t\t\t\t\t...(summary === undefined ? {} : { summary }),\n\t\t\t\t\t},\n\t\t\t\t\tcallback,\n\t\t\t\t);\n\t\t\t} else narrate(result, callback, summary, exitCode);\n\t\t\tresults.push(result);\n\t\t}\n\n\t\treturn { role: 'tool', content: results };\n\t}\n\n\t/**\n\t * Runs inside the context of the run that reached it, or in one of its own that it ends with\n\t * the run: completed, failed or cancelled. Only a run that owns its context names the history\n\t * run it recorded, since the run is over only when that context ends.\n\t */\n\tasync run(prompt: string, options: RunOptions): Promise<AgentResponse> {\n\t\tconst inherited = runContextOf(options);\n\t\tif (inherited) return this.runSteps(prompt, options, inherited);\n\n\t\tconst context = new RunContext();\n\t\tlet end: RunEnd = 'failed';\n\t\tlet response: AgentResponse;\n\t\ttry {\n\t\t\tresponse = await this.runSteps(prompt, withRunContext(options, context), context);\n\t\t\tend = 'completed';\n\t\t} catch (error) {\n\t\t\tif (isAbortError(error)) end = 'cancelled';\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tawait this.finishContext(context, end);\n\t\t}\n\t\t// Read once the run ended: a run that changed nothing left the history then.\n\t\tconst { runId } = context.historyRun;\n\t\treturn runId ? { ...response, runId } : response;\n\t}\n\n\t/**\n\t * What the run started ends here, but its result stands: the changes it recorded are already\n\t * on disk, so a record that could not be closed is reported, not turned into a failure.\n\t */\n\tprivate async finishContext(context: RunContext, end: RunEnd): Promise<void> {\n\t\ttry {\n\t\t\tawait context.finish(end);\n\t\t} catch (error) {\n\t\t\ttreatErrors(\n\t\t\t\t() => {\n\t\t\t\t\tthis.logger?.warn(`The run could not close its records: ${describeFailure(error)}`);\n\t\t\t\t},\n\t\t\t\tclassifyHostFailure,\n\t\t\t\t'LLM agent logger failed',\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async runSteps(\n\t\tprompt: string,\n\t\toptions: RunOptions,\n\t\tcontext: RunContext,\n\t): Promise<AgentResponse> {\n\t\tconst { signal, onProgress: callback = ignoreProgress } = options;\n\t\tconst start = Date.now();\n\t\tconst runMessages: Message[] = [{ role: 'user', content: [{ type: 'text', text: prompt }] }];\n\t\tlet tokens: Tokens | undefined;\n\t\t// Once one call went unreported the run's total is unknown, however many report later.\n\t\tlet unreported = false;\n\t\t// Per run, not per instance: what one run executed says nothing about another.\n\t\tconst effects: RunEffects = { toolRan: false };\n\t\t// The turn this one follows: the last recorded, unless the workspace moved since.\n\t\tlet after = this.conversation.currentTurn;\n\t\tlet followed: Followed | undefined;\n\n\t\ttry {\n\t\t\tif (this.history) {\n\t\t\t\tfollowed = await this.followHistory(this.history);\n\t\t\t\tafter = followed.turn;\n\t\t\t\t// The files may no longer hold what the conversation saw of them.\n\t\t\t\tif (followed.revisions.length > 0) this.reads.clear();\n\t\t\t\tif (followed.undone.length > 0) {\n\t\t\t\t\tconst summary = await this.summarizeUndone(followed, signal);\n\t\t\t\t\ttokens = addTokens(tokens, summary.usage);\n\t\t\t\t\tunreported ||= summary.called && !summary.usage;\n\t\t\t\t\tconst note = await undoNote({\n\t\t\t\t\t\tconversation: this.conversation,\n\t\t\t\t\t\thistory: this.history,\n\t\t\t\t\t\tfollowed,\n\t\t\t\t\t\t...(summary.text ? { summary: summary.text } : {}),\n\t\t\t\t\t}).catch((error: unknown) => {\n\t\t\t\t\t\tthrow classifyLocalFailure(error, 'The workspace history could not be read');\n\t\t\t\t\t});\n\t\t\t\t\trunMessages[0]?.content.unshift({ type: 'text', text: note });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// After following the history, which may have made every earlier read stale.\n\t\t\tconst reads = this.reads.begin();\n\t\t\tconst repeats = new RepeatedCalls();\n\t\t\tfor (let step = 1; step <= this.maxSteps; step++) {\n\t\t\t\tconst response = await this.llmCall(runMessages, after, signal);\n\t\t\t\ttokens = addTokens(tokens, response.usage);\n\t\t\t\tunreported ||= !response.usage;\n\t\t\t\trunMessages.push(response.message);\n\n\t\t\t\t// Tool calls are narrated as they start, in `runTools`, and never if they do not run.\n\t\t\t\tfor (const part of response.message.content) {\n\t\t\t\t\tif (part.type !== 'toolCall') narrate(part, callback);\n\t\t\t\t}\n\n\t\t\t\tconst calls = response.message.content.filter(part => part.type === 'toolCall');\n\t\t\t\tif (calls.length === 0) {\n\t\t\t\t\t// Recorded only now, so a failed run leaves no tool call without its result, and a\n\t\t\t\t\t// note about what was undone is given again to the next run.\n\t\t\t\t\tthis.conversation.addRunAfter(after, runMessages, context.historyRun);\n\t\t\t\t\t// With the turns that read them, and only then: a failed run is not remembered.\n\t\t\t\t\treads.commit();\n\t\t\t\t\tif (followed) this.seenRevision = followed.latestRevision;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t// Only the final answer: text from earlier steps was narrated as it came.\n\t\t\t\t\t\tresponse: response.message.content\n\t\t\t\t\t\t\t.filter(part => part.type === 'text')\n\t\t\t\t\t\t\t.map(part => part.text)\n\t\t\t\t\t\t\t.join('\\n'),\n\t\t\t\t\t\ttokens: unreported ? undefined : tokens,\n\t\t\t\t\t\tduration: (Date.now() - start) / 1000,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Before running them again: the model has already seen what they return.\n\t\t\t\tif (repeats.count(calls) >= maxRepeatedSteps) {\n\t\t\t\t\tthrow new UnrecoverableError('The LLM repeated the same tool calls', {\n\t\t\t\t\t\tcause: `The model asked for the same tool calls ${String(maxRepeatedSteps)} times in a row.`,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// On the last step no call is left to send the results to, so the tools do not run.\n\t\t\t\tif (step < this.maxSteps) {\n\t\t\t\t\trunMessages.push(await this.runTools(calls, options, effects, { run: context, reads }));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new UnrecoverableError('The LLM did not finish within its step limit', {\n\t\t\t\tcause: `The model was still calling tools after ${String(this.maxSteps)} steps.`,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlet failure = error;\n\t\t\tif (effects.toolRan && error instanceof RecoverableError) {\n\t\t\t\t// RetryingAgent would run the whole prompt again, and with it every tool this run\n\t\t\t\t// already executed, so a failure after one ran must not invite a retry.\n\t\t\t\tconst unrecoverable = new UnrecoverableError(error.message, {\n\t\t\t\t\tcause: error.cause,\n\t\t\t\t\ttokens: error.tokens,\n\t\t\t\t\tusageUnreported: error.usageUnreported,\n\t\t\t\t});\n\t\t\t\tunrecoverable.stack = error.stack;\n\t\t\t\tfailure = unrecoverable;\n\t\t\t}\n\n\t\t\t// The run spent the tokens of every step before the one that failed.\n\t\t\tthrow withSpentTokens(failure, tokens, unreported);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -2,6 +2,20 @@ import type { Agent } from '#src/agent/domain/agent';
|
|
|
2
2
|
import type { ILogger } from '#src/shared/domain/logger';
|
|
3
3
|
import { type AgentModel, type AgentProvider, type CreateOrchestratorOptions, type ReasoningEffort } from './types.ts';
|
|
4
4
|
export declare function isAgentProvider(value: string): value is AgentProvider;
|
|
5
|
+
/** The models each provider's Agent SDK accepts. */
|
|
6
|
+
export declare const agentModels: {
|
|
7
|
+
readonly anthropic: readonly ["haiku", "sonnet", "opus", "fable"];
|
|
8
|
+
readonly openai: readonly ["gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-luna", "gpt-5.6-terra"];
|
|
9
|
+
};
|
|
10
|
+
/** The reasoning efforts each provider's Agent SDK accepts. */
|
|
11
|
+
export declare const agentReasoningEfforts: {
|
|
12
|
+
readonly anthropic: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
13
|
+
readonly openai: readonly ["low", "medium", "high", "xhigh", "max", "ultra"];
|
|
14
|
+
};
|
|
15
|
+
/** Narrows a model to one accepted by the selected provider's Agent SDK. */
|
|
16
|
+
export declare function isModelOf<Provider extends AgentProvider>(provider: Provider, value: string): value is (typeof agentModels)[Provider][number];
|
|
17
|
+
/** Narrows a reasoning effort to one accepted by the selected provider's Agent SDK. */
|
|
18
|
+
export declare function isReasoningEffortOf<Provider extends AgentProvider>(provider: Provider, value: string): value is (typeof agentReasoningEfforts)[Provider][number];
|
|
5
19
|
export interface CreateAgentOptions {
|
|
6
20
|
/** Defaults to `'opus'` on Anthropic and `'gpt-5.6-sol'` on OpenAI. */
|
|
7
21
|
model?: AgentModel;
|