@mikode13/harness 3.0.0 → 4.0.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.
Files changed (59) hide show
  1. package/README.md +109 -9
  2. package/dist/agent/domain/agent.d.ts +23 -3
  3. package/dist/agent/domain/agent.js +2 -1
  4. package/dist/agent/domain/agent.js.map +1 -1
  5. package/dist/agent/domain/approval.d.ts +44 -0
  6. package/dist/agent/domain/approval.js +23 -0
  7. package/dist/agent/domain/approval.js.map +1 -0
  8. package/dist/engines/claude/infrastructure/model/claudeAgent.d.ts +2 -2
  9. package/dist/engines/claude/infrastructure/model/claudeAgent.js +4 -3
  10. package/dist/engines/claude/infrastructure/model/claudeAgent.js.map +1 -1
  11. package/dist/engines/codex/infrastructure/model/codexAgent.d.ts +2 -2
  12. package/dist/engines/codex/infrastructure/model/codexAgent.js +4 -4
  13. package/dist/engines/codex/infrastructure/model/codexAgent.js.map +1 -1
  14. package/dist/engines/domain/model/llmAgent.d.ts +15 -5
  15. package/dist/engines/domain/model/llmAgent.js +109 -26
  16. package/dist/engines/domain/model/llmAgent.js.map +1 -1
  17. package/dist/factory/infrastructure/agentFactory.js +1 -1
  18. package/dist/factory/infrastructure/agentFactory.js.map +1 -1
  19. package/dist/factory/infrastructure/agentLLMFactory.d.ts +14 -7
  20. package/dist/factory/infrastructure/agentLLMFactory.js +11 -9
  21. package/dist/factory/infrastructure/agentLLMFactory.js.map +1 -1
  22. package/dist/index.d.ts +10 -2
  23. package/dist/index.js +6 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/llm/domain/errors.d.ts +1 -1
  26. package/dist/llm/domain/errors.js +1 -1
  27. package/dist/llm/domain/errors.js.map +1 -1
  28. package/dist/llm/infrastructure/claudeLLMClient.js +2 -2
  29. package/dist/llm/infrastructure/claudeLLMClient.js.map +1 -1
  30. package/dist/llm/infrastructure/openAILLMClient.js +2 -2
  31. package/dist/llm/infrastructure/openAILLMClient.js.map +1 -1
  32. package/dist/orchestration/domain/model/instructedAgent.d.ts +2 -2
  33. package/dist/orchestration/domain/model/instructedAgent.js +2 -2
  34. package/dist/orchestration/domain/model/instructedAgent.js.map +1 -1
  35. package/dist/orchestration/domain/model/orchestratorAgent.d.ts +2 -2
  36. package/dist/orchestration/domain/model/orchestratorAgent.js +10 -10
  37. package/dist/orchestration/domain/model/orchestratorAgent.js.map +1 -1
  38. package/dist/retry/domain/model/retryingAgent.d.ts +2 -2
  39. package/dist/retry/domain/model/retryingAgent.js +4 -4
  40. package/dist/retry/domain/model/retryingAgent.js.map +1 -1
  41. package/dist/shared/domain/errors.js.map +1 -0
  42. package/dist/shared/domain/providerFailure.js.map +1 -0
  43. package/dist/tools/domain/tool.d.ts +6 -0
  44. package/dist/tools/domain/tool.js.map +1 -1
  45. package/dist/tools/infrastructure/createWorkspace.d.ts +2 -1
  46. package/dist/tools/infrastructure/createWorkspace.js +4 -3
  47. package/dist/tools/infrastructure/createWorkspace.js.map +1 -1
  48. package/dist/tools/infrastructure/defineTool.d.ts +7 -1
  49. package/dist/tools/infrastructure/defineTool.js +12 -2
  50. package/dist/tools/infrastructure/defineTool.js.map +1 -1
  51. package/dist/tools/infrastructure/workspaceTools.js +3 -0
  52. package/dist/tools/infrastructure/workspaceTools.js.map +1 -1
  53. package/package.json +7 -4
  54. package/dist/agent/domain/errors.js.map +0 -1
  55. package/dist/agent/domain/providerFailure.js.map +0 -1
  56. /package/dist/{agent → shared}/domain/errors.d.ts +0 -0
  57. /package/dist/{agent → shared}/domain/errors.js +0 -0
  58. /package/dist/{agent → shared}/domain/providerFailure.d.ts +0 -0
  59. /package/dist/{agent → shared}/domain/providerFailure.js +0 -0
@@ -1,4 +1,4 @@
1
- import type { Agent, AgentResponse, Callback } from '#src/agent/domain/agent';
1
+ import { type Agent, type AgentResponse, type RunOptions } from '#src/agent/domain/agent';
2
2
  import type { LLMClient } from '#src/llm/domain/llm';
3
3
  import type { Message } from '#src/llm/domain/message';
4
4
  import type { Tool } from '#src/tools/domain/tool';
@@ -15,20 +15,30 @@ export declare class LLMAgent implements Agent {
15
15
  private readonly tools;
16
16
  private readonly toolDefinitions;
17
17
  private readonly maxSteps;
18
- constructor({ llmClient, messages, tools, maxSteps, }: {
18
+ private readonly autoApprove;
19
+ constructor({ llmClient, messages, tools, maxSteps, autoApprove, }: {
19
20
  llmClient: LLMClient;
20
21
  messages?: Message[];
21
22
  tools?: Tool[];
22
23
  /** How many calls to the model one run may make before it fails. */
23
24
  maxSteps?: number;
25
+ /** Runs every tool call without asking, `destructive` ones included. Meant for CI. */
26
+ autoApprove?: boolean;
24
27
  });
25
28
  private llmCall;
26
29
  /**
27
- * Always answers the call: a missing tool or a failing one becomes an error result, so the
28
- * model can correct itself. Only a cancellation escapes, whatever error the tool turned it into.
30
+ * Undefined when the call may run; otherwise why it may not, which the model receives in its
31
+ * place. Only a `destructive` call is asked about: git can undo a `mutating` one. A throwing
32
+ * approver ends the run, as any host callback does.
33
+ */
34
+ private denial;
35
+ /**
36
+ * Always answers the call: a missing tool, a denied call or a failing one becomes an error
37
+ * result, so the model can correct itself. Only a cancellation, or a failing approver,
38
+ * escapes, whatever error the tool turned it into.
29
39
  */
30
40
  private runTool;
31
41
  /** One at a time and in order, so their effects and their narration never interleave. */
32
42
  private runTools;
33
- run(prompt: string, signal: AbortSignal, callback: Callback): Promise<AgentResponse>;
43
+ run(prompt: string, options: RunOptions): Promise<AgentResponse>;
34
44
  }
@@ -1,5 +1,6 @@
1
- import { InvalidAgentConfigError, RecoverableError, UnrecoverableError, withSpentTokens, } from '#src/agent/domain/errors';
2
- import { classifyHostFailure, classifyProviderFailure, describeFailure, treatErrors, } from '#src/agent/domain/providerFailure';
1
+ import { ignoreProgress, } from '#src/agent/domain/agent';
2
+ import { InvalidAgentConfigError, RecoverableError, UnrecoverableError, withSpentTokens, } from '#src/shared/domain/errors';
3
+ import { classifyHostFailure, classifyProviderFailure, describeFailure, treatErrors, } from '#src/shared/domain/providerFailure';
3
4
  import { Conversation } from '#src/llm/domain/conversation';
4
5
  import { addTokens } from '#src/shared/domain/tokens';
5
6
  function describePart(part) {
@@ -22,11 +23,25 @@ function describePart(part) {
22
23
  return undefined;
23
24
  }
24
25
  }
26
+ /** Only an answer whose `approved` is a boolean is one; anything else is the approver failing. */
27
+ function readDecision(answer) {
28
+ if (typeof answer !== 'object' || answer === null) {
29
+ throw new TypeError('The approver answered without a decision');
30
+ }
31
+ const { approved, reason } = answer;
32
+ if (typeof approved !== 'boolean') {
33
+ throw new TypeError('The approver answered without a boolean `approved`');
34
+ }
35
+ return approved
36
+ ? { approved }
37
+ : { approved, reason: typeof reason === 'string' ? reason : undefined };
38
+ }
25
39
  function narrate(part, callback) {
26
40
  const event = describePart(part);
27
- if (!event) {
28
- return;
29
- }
41
+ if (event)
42
+ emit(event, callback);
43
+ }
44
+ function emit(event, callback) {
30
45
  treatErrors(() => {
31
46
  callback(event);
32
47
  }, classifyHostFailure, 'LLM agent progress callback failed');
@@ -44,13 +59,15 @@ export class LLMAgent {
44
59
  tools;
45
60
  toolDefinitions;
46
61
  maxSteps;
47
- constructor({ llmClient, messages, tools = [], maxSteps = 25, }) {
62
+ autoApprove;
63
+ constructor({ llmClient, messages, tools = [], maxSteps = 25, autoApprove = false, }) {
48
64
  if (!Number.isInteger(maxSteps) || maxSteps < 1) {
49
65
  throw new InvalidAgentConfigError(`maxSteps must be a positive integer; got ${String(maxSteps)}`);
50
66
  }
51
67
  this.llmClient = llmClient;
52
68
  this.conversation = new Conversation(messages);
53
69
  this.maxSteps = maxSteps;
70
+ this.autoApprove = autoApprove;
54
71
  this.tools = new Map(tools.map(tool => [tool.name, tool]));
55
72
  if (this.tools.size !== tools.length) {
56
73
  // The model calls tools by name, so a second one with the same name could never run.
@@ -86,51 +103,120 @@ export class LLMAgent {
86
103
  return response;
87
104
  }
88
105
  /**
89
- * Always answers the call: a missing tool or a failing one becomes an error result, so the
90
- * model can correct itself. Only a cancellation escapes, whatever error the tool turned it into.
106
+ * Undefined when the call may run; otherwise why it may not, which the model receives in its
107
+ * place. Only a `destructive` call is asked about: git can undo a `mutating` one. A throwing
108
+ * approver ends the run, as any host callback does.
91
109
  */
92
- async runTool(call, signal) {
110
+ async denial(call, risk, signal, approve) {
111
+ if (this.autoApprove || risk !== 'destructive')
112
+ return undefined;
113
+ const retry = 'Do not retry the same call; choose another way, or ask the user.';
114
+ if (!approve) {
115
+ return `The call to "${call.name}" was denied: it is destructive, and no one was asked to allow it. ${retry}`;
116
+ }
117
+ let decision;
118
+ try {
119
+ // A copy, so what runs and what the conversation keeps is exactly what was approved.
120
+ const input = structuredClone(call.input);
121
+ // Read inside the boundary: an untyped approver can answer anything, and a bad answer
122
+ // is its failure, which must carry the run's tokens like any other.
123
+ decision = readDecision(await approve({ tool: call.name, input, risk }, signal));
124
+ }
125
+ catch (error) {
126
+ // An approver that gives up on a cancellation, whatever it throws, did not fail.
127
+ signal.throwIfAborted();
128
+ throw classifyHostFailure(error, 'The tool call approver failed');
129
+ }
130
+ // The user may cancel the run while they are being asked.
131
+ signal.throwIfAborted();
132
+ if (decision.approved)
133
+ return undefined;
134
+ const reason = decision.reason ? ` Their reason: ${decision.reason}` : '';
135
+ return `The user denied the call to "${call.name}".${reason} ${retry}`;
136
+ }
137
+ /**
138
+ * Always answers the call: a missing tool, a denied call or a failing one becomes an error
139
+ * result, so the model can correct itself. Only a cancellation, or a failing approver,
140
+ * escapes, whatever error the tool turned it into.
141
+ */
142
+ async runTool(call, { signal, onProgress: callback = ignoreProgress, approve }, effects) {
93
143
  const result = { type: 'toolResult', callId: call.id, name: call.name };
94
144
  const tool = this.tools.get(call.name);
95
145
  if (!tool) {
96
146
  return {
97
- ...result,
98
- output: `There is no tool named "${call.name}". Available tools: ${[...this.tools.keys()].join(', ') || 'none'}.`,
99
- isError: true,
147
+ result: {
148
+ ...result,
149
+ output: `There is no tool named "${call.name}". Available tools: ${[...this.tools.keys()].join(', ') || 'none'}.`,
150
+ isError: true,
151
+ },
152
+ denied: false,
153
+ };
154
+ }
155
+ let risk;
156
+ try {
157
+ risk = tool.risk(call.input);
158
+ }
159
+ catch (error) {
160
+ // A tool that cannot judge its own call is a failing tool, and the call does not run.
161
+ return {
162
+ result: { ...result, output: describeFailure(error), isError: true },
163
+ denied: false,
100
164
  };
101
165
  }
166
+ const denial = await this.denial(call, risk, signal, approve);
167
+ if (denial !== undefined) {
168
+ return { result: { ...result, output: denial, isError: true }, denied: true };
169
+ }
170
+ // Deciding took at least one await, and the run may have been cancelled meanwhile.
171
+ signal.throwIfAborted();
172
+ // Announced only once it will run: a missing, failing-to-judge or denied call never is.
173
+ narrate(call, callback);
102
174
  // Checked again at the last moment: the consumer may cancel on the announcement itself.
103
175
  signal.throwIfAborted();
176
+ // Set before `execute`, so a tool that fails halfway still counts: it may have had effects.
177
+ effects.toolRan = true;
104
178
  try {
105
- return { ...result, output: await tool.execute(call.input, signal), isError: false };
179
+ return {
180
+ result: { ...result, output: await tool.execute(call.input, signal), isError: false },
181
+ denied: false,
182
+ };
106
183
  }
107
184
  catch (error) {
108
185
  signal.throwIfAborted();
109
- return { ...result, output: describeFailure(error), isError: true };
186
+ return {
187
+ result: { ...result, output: describeFailure(error), isError: true },
188
+ denied: false,
189
+ };
110
190
  }
111
191
  }
112
192
  /** One at a time and in order, so their effects and their narration never interleave. */
113
- async runTools(calls, signal, callback) {
193
+ async runTools(calls, options, effects) {
194
+ const { signal, onProgress: callback = ignoreProgress } = options;
114
195
  const results = [];
115
196
  for (const call of calls) {
116
197
  // A call before this one may have ignored the cancellation; this one must not start,
117
198
  // nor be announced as running.
118
199
  signal.throwIfAborted();
119
- // Announced only as its turn comes, so a consumer never shows a call as running early.
120
- narrate(call, callback);
121
- const result = await this.runTool(call, signal);
122
- narrate(result, callback);
200
+ // `runTool` announces the call only once it is allowed to run, so a consumer never
201
+ // shows a call as running early, nor while the user is still being asked.
202
+ const { result, denied } = await this.runTool(call, options, effects);
203
+ if (denied)
204
+ emit({ type: 'tool', id: call.id, name: call.name, status: 'denied' }, callback);
205
+ else
206
+ narrate(result, callback);
123
207
  results.push(result);
124
208
  }
125
209
  return { role: 'tool', content: results };
126
210
  }
127
- async run(prompt, signal, callback) {
211
+ async run(prompt, options) {
212
+ const { signal, onProgress: callback = ignoreProgress } = options;
128
213
  const start = Date.now();
129
214
  const runMessages = [{ role: 'user', content: [{ type: 'text', text: prompt }] }];
130
215
  let tokens;
131
216
  // Once one call went unreported the run's total is unknown, however many report later.
132
217
  let unreported = false;
133
- let toolRan = false;
218
+ // Per run, not per instance: what one run executed says nothing about another.
219
+ const effects = { toolRan: false };
134
220
  try {
135
221
  for (let step = 1; step <= this.maxSteps; step++) {
136
222
  const response = await this.llmCall(runMessages, signal);
@@ -158,10 +244,7 @@ export class LLMAgent {
158
244
  }
159
245
  // On the last step no call is left to send the results to, so the tools do not run.
160
246
  if (step < this.maxSteps) {
161
- // Only a call to a tool the agent has reaches `execute`; a missing one has no
162
- // effect a retry could repeat.
163
- toolRan ||= calls.some(call => this.tools.has(call.name));
164
- runMessages.push(await this.runTools(calls, signal, callback));
247
+ runMessages.push(await this.runTools(calls, options, effects));
165
248
  }
166
249
  }
167
250
  throw new UnrecoverableError('The LLM did not finish within its step limit', {
@@ -170,7 +253,7 @@ export class LLMAgent {
170
253
  }
171
254
  catch (error) {
172
255
  let failure = error;
173
- if (toolRan && error instanceof RecoverableError) {
256
+ if (effects.toolRan && error instanceof RecoverableError) {
174
257
  // RetryingAgent would run the whole prompt again, and with it every tool this run
175
258
  // already executed, so a failure after one ran must not invite a retry.
176
259
  const unrecoverable = new UnrecoverableError(error.message, {
@@ -1 +1 @@
1
- {"version":3,"file":"llmAgent.js","sourceRoot":"","sources":["../../../../src/engines/domain/model/llmAgent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Agent, AgentResponse, Callback, ProgressEvent } from '#src/agent/domain/agent';\nimport {\n\tInvalidAgentConfigError,\n\tRecoverableError,\n\tUnrecoverableError,\n\twithSpentTokens,\n} from '#src/agent/domain/errors';\nimport {\n\tclassifyHostFailure,\n\tclassifyProviderFailure,\n\tdescribeFailure,\n\ttreatErrors,\n} from '#src/agent/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\nfunction narrate(part: MessagePart, callback: Callback): void {\n\tconst event = describePart(part);\n\tif (!event) {\n\t\treturn;\n\t}\n\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\n\tconstructor({\n\t\tllmClient,\n\t\tmessages,\n\t\ttools = [],\n\t\tmaxSteps = 25,\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}) {\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.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 * Always answers the call: a missing tool or a failing one becomes an error result, so the\n\t * model can correct itself. Only a cancellation escapes, whatever error the tool turned it into.\n\t */\n\tprivate async runTool(call: ToolCallPart, signal: AbortSignal): Promise<ToolResultPart> {\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\t...result,\n\t\t\t\toutput: `There is no tool named \"${call.name}\". Available tools: ${[...this.tools.keys()].join(', ') || 'none'}.`,\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\n\t\t// Checked again at the last moment: the consumer may cancel on the announcement itself.\n\t\tsignal.throwIfAborted();\n\t\ttry {\n\t\t\treturn { ...result, output: await tool.execute(call.input, signal), isError: false };\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn { ...result, output: describeFailure(error), isError: true };\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\tsignal: AbortSignal,\n\t\tcallback: Callback,\n\t): Promise<Message> {\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// Announced only as its turn comes, so a consumer never shows a call as running early.\n\t\t\tnarrate(call, callback);\n\t\t\tconst result = await this.runTool(call, signal);\n\t\t\tnarrate(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, signal: AbortSignal, callback: Callback): Promise<AgentResponse> {\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\tlet 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\t// Only a call to a tool the agent has reaches `execute`; a missing one has no\n\t\t\t\t\t// effect a retry could repeat.\n\t\t\t\t\ttoolRan ||= calls.some(call => this.tools.has(call.name));\n\t\t\t\t\trunMessages.push(await this.runTools(calls, signal, callback));\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 (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 type { ApprovalDecision, Approver, ToolRisk } 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/** Only an answer whose `approved` is a boolean is one; anything else is the approver failing. */\nfunction readDecision(answer: unknown): ApprovalDecision {\n\tif (typeof answer !== 'object' || answer === null) {\n\t\tthrow new TypeError('The approver answered without a decision');\n\t}\n\tconst { approved, reason } = answer as { approved?: unknown; reason?: unknown };\n\tif (typeof approved !== 'boolean') {\n\t\tthrow new TypeError('The approver answered without a boolean `approved`');\n\t}\n\n\treturn approved\n\t\t? { approved }\n\t\t: { approved, reason: typeof reason === 'string' ? reason : undefined };\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,4 +1,4 @@
1
- import { InvalidAgentConfigError } from '#src/agent/domain/errors';
1
+ import { InvalidAgentConfigError } from '#src/shared/domain/errors';
2
2
  import { ClaudeAgent } from '#src/engines/claude/infrastructure/model/claudeAgent';
3
3
  import { CodexAgent } from '#src/engines/codex/infrastructure/model/codexAgent';
4
4
  import { InstructedAgent } from '#src/orchestration/domain/model/instructedAgent';
@@ -1 +1 @@
1
- {"version":3,"file":"agentFactory.js","sourceRoot":"","sources":["../../../src/factory/infrastructure/agentFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Agent } from '#src/agent/domain/agent';\nimport { InvalidAgentConfigError } from '#src/agent/domain/errors';\nimport { ClaudeAgent } from '#src/engines/claude/infrastructure/model/claudeAgent';\nimport { CodexAgent } from '#src/engines/codex/infrastructure/model/codexAgent';\nimport { InstructedAgent } from '#src/orchestration/domain/model/instructedAgent';\nimport {\n\texecutorInstructions,\n\tOrchestratorAgent,\n\tplannerInstructions,\n\treviewerInstructions,\n} from '#src/orchestration/domain/model/orchestratorAgent';\nimport { ReviewerDecisionValidator } from '#src/orchestration/infrastructure/model/reviewerDecisionValidator';\nimport { RetryingAgent } from '#src/retry/domain/model/retryingAgent';\nimport { isOneOf } from '#src/shared/domain/isOneOf';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport { Logger } from '#src/shared/infrastructure/logger';\nimport {\n\tagentProviders,\n\ttype AgentModel,\n\ttype AgentProvider,\n\ttype CreateOrchestratorOptions,\n\ttype ReasoningEffort,\n} from './types.ts';\n\nexport function isAgentProvider(value: string): value is AgentProvider {\n\treturn isOneOf(agentProviders, value);\n}\n\nexport interface CreateAgentOptions {\n\t/** Defaults to `'opus'` on Anthropic and `'gpt-5.6-sol'` on OpenAI. */\n\tmodel?: AgentModel;\n\t/** Defaults to `'high'`. */\n\treasoningEffort?: ReasoningEffort;\n\t/** Maps to the provider's permission-bypass mode. Defaults to `false`. */\n\tautoApprove?: boolean;\n\t/** Defaults to warnings on stderr. */\n\tlogger?: ILogger;\n}\n\nconst defaultModels = {\n\tanthropic: 'opus',\n\topenai: 'gpt-5.6-sol',\n} as const satisfies Record<AgentProvider, AgentModel>;\n\n/**\n * Builds the agent for a provider on its Agent SDK — Claude Code for Anthropic, Codex for\n * OpenAI — already wrapped in the harness's retry policy.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider, or a model or reasoning effort\n * the provider does not support.\n * @throws {UnrecoverableError} when Codex cannot be set up, for example because its CLI binary\n * is missing.\n */\nexport function createAgent(\n\tprovider: AgentProvider,\n\t{ model, reasoningEffort, autoApprove, logger = new Logger() }: CreateAgentOptions = {},\n): Agent {\n\tlet engine: Agent;\n\n\tswitch (provider) {\n\t\tcase 'anthropic':\n\t\t\tengine = new ClaudeAgent({\n\t\t\t\tmodel: model ?? defaultModels.anthropic,\n\t\t\t\treasoningEffort,\n\t\t\t\tautoApprove,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'openai':\n\t\t\tengine = new CodexAgent({\n\t\t\t\tmodel: model ?? defaultModels.openai,\n\t\t\t\treasoningEffort,\n\t\t\t\tautoApprove,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\t// Reachable from untyped input that skipped `isAgentProvider`.\n\t\t\tconst unknownProvider: never = provider;\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${String(unknownProvider)}\" is not an agent provider; expected one of: ${agentProviders.join(', ')}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn new RetryingAgent({ inner: engine, logger });\n}\n\nexport interface Role {\n\tprovider: AgentProvider;\n\tmodel: AgentModel;\n\treasoningEffort: ReasoningEffort;\n}\n\n// A stronger model plans and reviews; a cheaper one executes the plan. Every model and effort\n// here is one both the Agent SDKs and the model APIs accept, so either path can run a role.\nconst orchestratorRoles = {\n\tdefault: {\n\t\tplanner: { provider: 'openai', model: 'gpt-5.6-sol', reasoningEffort: 'high' },\n\t\texecutor: { provider: 'openai', model: 'gpt-5.6-luna', reasoningEffort: 'xhigh' },\n\t\treviewer: { provider: 'anthropic', model: 'opus', reasoningEffort: 'high' },\n\t},\n\tanthropic: {\n\t\tplanner: { provider: 'anthropic', model: 'opus', reasoningEffort: 'high' },\n\t\texecutor: { provider: 'anthropic', model: 'sonnet', reasoningEffort: 'xhigh' },\n\t\treviewer: { provider: 'anthropic', model: 'opus', reasoningEffort: 'high' },\n\t},\n\topenai: {\n\t\tplanner: { provider: 'openai', model: 'gpt-5.6-sol', reasoningEffort: 'high' },\n\t\texecutor: { provider: 'openai', model: 'gpt-5.6-luna', reasoningEffort: 'xhigh' },\n\t\treviewer: { provider: 'openai', model: 'gpt-5.6-sol', reasoningEffort: 'high' },\n\t},\n} as const satisfies Record<\n\tAgentProvider | 'default',\n\tRecord<'planner' | 'executor' | 'reviewer', Role>\n>;\n\n/**\n * The roles for `provider`, or the default mix without one.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider.\n */\nexport function orchestratorRolesFor(\n\tprovider: AgentProvider | undefined,\n): Record<'planner' | 'executor' | 'reviewer', Role> {\n\tif (provider !== undefined && !isAgentProvider(provider)) {\n\t\tthrow new InvalidAgentConfigError(\n\t\t\t`\"${String(provider)}\" is not an agent provider; expected one of: ${agentProviders.join(', ')}`,\n\t\t);\n\t}\n\n\treturn orchestratorRoles[provider ?? 'default'];\n}\n\n/**\n * Builds the planner → executor → reviewer workflow, each role an agent from `createAgent`.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider.\n * @throws {UnrecoverableError} when an OpenAI role cannot be set up, for example because the\n * Codex CLI binary is missing.\n */\nexport function createOrchestrator({\n\tprovider,\n\tautoApprove,\n\tsystemPrompts = {},\n\tlogger = new Logger(),\n}: CreateOrchestratorOptions = {}): Agent {\n\tconst roles = orchestratorRolesFor(provider);\n\tconst agentFor = ({ provider, model, reasoningEffort }: Role, instructions: string) =>\n\t\tnew InstructedAgent({\n\t\t\tinner: createAgent(provider, { model, reasoningEffort, autoApprove, logger }),\n\t\t\tinstructions,\n\t\t});\n\n\treturn new OrchestratorAgent({\n\t\tplannerAgent: agentFor(roles.planner, systemPrompts.planner ?? plannerInstructions),\n\t\texecutorAgent: agentFor(roles.executor, systemPrompts.executor ?? executorInstructions),\n\t\treviewerAgent: agentFor(roles.reviewer, systemPrompts.reviewer ?? reviewerInstructions),\n\t\treviewerDecisionValidator: new ReviewerDecisionValidator(),\n\t\tlogger,\n\t});\n}\n"]}
1
+ {"version":3,"file":"agentFactory.js","sourceRoot":"","sources":["../../../src/factory/infrastructure/agentFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Agent } from '#src/agent/domain/agent';\nimport { InvalidAgentConfigError } from '#src/shared/domain/errors';\nimport { ClaudeAgent } from '#src/engines/claude/infrastructure/model/claudeAgent';\nimport { CodexAgent } from '#src/engines/codex/infrastructure/model/codexAgent';\nimport { InstructedAgent } from '#src/orchestration/domain/model/instructedAgent';\nimport {\n\texecutorInstructions,\n\tOrchestratorAgent,\n\tplannerInstructions,\n\treviewerInstructions,\n} from '#src/orchestration/domain/model/orchestratorAgent';\nimport { ReviewerDecisionValidator } from '#src/orchestration/infrastructure/model/reviewerDecisionValidator';\nimport { RetryingAgent } from '#src/retry/domain/model/retryingAgent';\nimport { isOneOf } from '#src/shared/domain/isOneOf';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport { Logger } from '#src/shared/infrastructure/logger';\nimport {\n\tagentProviders,\n\ttype AgentModel,\n\ttype AgentProvider,\n\ttype CreateOrchestratorOptions,\n\ttype ReasoningEffort,\n} from './types.ts';\n\nexport function isAgentProvider(value: string): value is AgentProvider {\n\treturn isOneOf(agentProviders, value);\n}\n\nexport interface CreateAgentOptions {\n\t/** Defaults to `'opus'` on Anthropic and `'gpt-5.6-sol'` on OpenAI. */\n\tmodel?: AgentModel;\n\t/** Defaults to `'high'`. */\n\treasoningEffort?: ReasoningEffort;\n\t/** Maps to the provider's permission-bypass mode. Defaults to `false`. */\n\tautoApprove?: boolean;\n\t/** Defaults to warnings on stderr. */\n\tlogger?: ILogger;\n}\n\nconst defaultModels = {\n\tanthropic: 'opus',\n\topenai: 'gpt-5.6-sol',\n} as const satisfies Record<AgentProvider, AgentModel>;\n\n/**\n * Builds the agent for a provider on its Agent SDK — Claude Code for Anthropic, Codex for\n * OpenAI — already wrapped in the harness's retry policy.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider, or a model or reasoning effort\n * the provider does not support.\n * @throws {UnrecoverableError} when Codex cannot be set up, for example because its CLI binary\n * is missing.\n */\nexport function createAgent(\n\tprovider: AgentProvider,\n\t{ model, reasoningEffort, autoApprove, logger = new Logger() }: CreateAgentOptions = {},\n): Agent {\n\tlet engine: Agent;\n\n\tswitch (provider) {\n\t\tcase 'anthropic':\n\t\t\tengine = new ClaudeAgent({\n\t\t\t\tmodel: model ?? defaultModels.anthropic,\n\t\t\t\treasoningEffort,\n\t\t\t\tautoApprove,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'openai':\n\t\t\tengine = new CodexAgent({\n\t\t\t\tmodel: model ?? defaultModels.openai,\n\t\t\t\treasoningEffort,\n\t\t\t\tautoApprove,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\t// Reachable from untyped input that skipped `isAgentProvider`.\n\t\t\tconst unknownProvider: never = provider;\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${String(unknownProvider)}\" is not an agent provider; expected one of: ${agentProviders.join(', ')}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn new RetryingAgent({ inner: engine, logger });\n}\n\nexport interface Role {\n\tprovider: AgentProvider;\n\tmodel: AgentModel;\n\treasoningEffort: ReasoningEffort;\n}\n\n// A stronger model plans and reviews; a cheaper one executes the plan. Every model and effort\n// here is one both the Agent SDKs and the model APIs accept, so either path can run a role.\nconst orchestratorRoles = {\n\tdefault: {\n\t\tplanner: { provider: 'openai', model: 'gpt-5.6-sol', reasoningEffort: 'high' },\n\t\texecutor: { provider: 'openai', model: 'gpt-5.6-luna', reasoningEffort: 'xhigh' },\n\t\treviewer: { provider: 'anthropic', model: 'opus', reasoningEffort: 'high' },\n\t},\n\tanthropic: {\n\t\tplanner: { provider: 'anthropic', model: 'opus', reasoningEffort: 'high' },\n\t\texecutor: { provider: 'anthropic', model: 'sonnet', reasoningEffort: 'xhigh' },\n\t\treviewer: { provider: 'anthropic', model: 'opus', reasoningEffort: 'high' },\n\t},\n\topenai: {\n\t\tplanner: { provider: 'openai', model: 'gpt-5.6-sol', reasoningEffort: 'high' },\n\t\texecutor: { provider: 'openai', model: 'gpt-5.6-luna', reasoningEffort: 'xhigh' },\n\t\treviewer: { provider: 'openai', model: 'gpt-5.6-sol', reasoningEffort: 'high' },\n\t},\n} as const satisfies Record<\n\tAgentProvider | 'default',\n\tRecord<'planner' | 'executor' | 'reviewer', Role>\n>;\n\n/**\n * The roles for `provider`, or the default mix without one.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider.\n */\nexport function orchestratorRolesFor(\n\tprovider: AgentProvider | undefined,\n): Record<'planner' | 'executor' | 'reviewer', Role> {\n\tif (provider !== undefined && !isAgentProvider(provider)) {\n\t\tthrow new InvalidAgentConfigError(\n\t\t\t`\"${String(provider)}\" is not an agent provider; expected one of: ${agentProviders.join(', ')}`,\n\t\t);\n\t}\n\n\treturn orchestratorRoles[provider ?? 'default'];\n}\n\n/**\n * Builds the planner → executor → reviewer workflow, each role an agent from `createAgent`.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider.\n * @throws {UnrecoverableError} when an OpenAI role cannot be set up, for example because the\n * Codex CLI binary is missing.\n */\nexport function createOrchestrator({\n\tprovider,\n\tautoApprove,\n\tsystemPrompts = {},\n\tlogger = new Logger(),\n}: CreateOrchestratorOptions = {}): Agent {\n\tconst roles = orchestratorRolesFor(provider);\n\tconst agentFor = ({ provider, model, reasoningEffort }: Role, instructions: string) =>\n\t\tnew InstructedAgent({\n\t\t\tinner: createAgent(provider, { model, reasoningEffort, autoApprove, logger }),\n\t\t\tinstructions,\n\t\t});\n\n\treturn new OrchestratorAgent({\n\t\tplannerAgent: agentFor(roles.planner, systemPrompts.planner ?? plannerInstructions),\n\t\texecutorAgent: agentFor(roles.executor, systemPrompts.executor ?? executorInstructions),\n\t\treviewerAgent: agentFor(roles.reviewer, systemPrompts.reviewer ?? reviewerInstructions),\n\t\treviewerDecisionValidator: new ReviewerDecisionValidator(),\n\t\tlogger,\n\t});\n}\n"]}
@@ -14,27 +14,34 @@ export interface CreateLLMAgentOptions {
14
14
  systemPrompt: string;
15
15
  /** The tools the model may call. Defaults to none. */
16
16
  tools?: Tool[];
17
+ /**
18
+ * Runs every tool call without asking, `destructive` ones included, for CI where no one can
19
+ * answer. Without it, a `destructive` call goes to the run's `approve`, or is denied.
20
+ */
21
+ autoApprove?: boolean;
17
22
  /** Defaults to warnings on stderr. */
18
23
  logger?: ILogger;
19
24
  }
20
25
  /**
21
26
  * Builds an agent whose conversation MiKode owns, on a provider's model API, already wrapped in
22
- * the harness's retry policy. Internal while #23 reaches parity with the Agent SDK engines: it
23
- * is not exported from `src/index.ts`. Its tools only read, so it has no `autoApprove`.
27
+ * the harness's retry policy. It needs the provider's API key and bills per token, where
28
+ * `createAgent` uses the Agent SDK's login. Each tool judges the risk of each call; a
29
+ * `destructive` one runs only when the run's `approve` allows it, or with `autoApprove`.
24
30
  *
25
- * @throws {InvalidAgentConfigError} for an unknown provider, or a model or reasoning effort its
26
- * client does not support.
31
+ * @throws {InvalidAgentConfigError} for an unknown provider, a model or reasoning effort its
32
+ * client does not support, or two tools that share a name.
27
33
  * @throws {UnrecoverableError} when the client cannot be set up, for example because
28
34
  * `OPENAI_API_KEY` is missing. The Anthropic SDK resolves credentials lazily, so a missing
29
35
  * `ANTHROPIC_API_KEY` fails the first run instead, with an `UnrecoverableError`.
30
36
  */
31
- export declare function createLLMAgent(provider: AgentProvider, { model, reasoningEffort, systemPrompt, tools, logger }: CreateLLMAgentOptions): Agent;
37
+ export declare function createLLMAgent(provider: AgentProvider, { model, reasoningEffort, systemPrompt, tools, autoApprove, logger, }: CreateLLMAgentOptions): Agent;
32
38
  /**
33
39
  * Builds the planner → executor → reviewer workflow with the planner and reviewer on the model
34
40
  * APIs, from `createLLMAgent`, each holding its role's instructions, or `systemPrompts`, as its
35
41
  * system prompt, with the read-only repository tools for the current working directory. The
36
- * executor stays on its Agent SDK, from `createAgent`, until an agent of ours can change files; `autoApprove` reaches
37
- * only it. Asynchronous because finding the program that reads the repository is.
42
+ * executor stays on its Agent SDK, from `createAgent`, until an agent of ours can change files;
43
+ * `autoApprove` reaches only it. Asynchronous because finding the program that reads the
44
+ * repository is.
38
45
  *
39
46
  * @throws {InvalidAgentConfigError} for an unknown provider.
40
47
  * @throws {UnrecoverableError} when a role cannot be set up, for example because
@@ -1,4 +1,4 @@
1
- import { InvalidAgentConfigError } from '#src/agent/domain/errors';
1
+ import { InvalidAgentConfigError } from '#src/shared/domain/errors';
2
2
  import { LLMAgent } from '#src/engines/domain/model/llmAgent';
3
3
  import { ClaudeLLMClient } from '#src/llm/infrastructure/claudeLLMClient';
4
4
  import { OpenAILLMClient } from '#src/llm/infrastructure/openAILLMClient';
@@ -17,16 +17,17 @@ const defaultLLMAgentModels = {
17
17
  };
18
18
  /**
19
19
  * Builds an agent whose conversation MiKode owns, on a provider's model API, already wrapped in
20
- * the harness's retry policy. Internal while #23 reaches parity with the Agent SDK engines: it
21
- * is not exported from `src/index.ts`. Its tools only read, so it has no `autoApprove`.
20
+ * the harness's retry policy. It needs the provider's API key and bills per token, where
21
+ * `createAgent` uses the Agent SDK's login. Each tool judges the risk of each call; a
22
+ * `destructive` one runs only when the run's `approve` allows it, or with `autoApprove`.
22
23
  *
23
- * @throws {InvalidAgentConfigError} for an unknown provider, or a model or reasoning effort its
24
- * client does not support.
24
+ * @throws {InvalidAgentConfigError} for an unknown provider, a model or reasoning effort its
25
+ * client does not support, or two tools that share a name.
25
26
  * @throws {UnrecoverableError} when the client cannot be set up, for example because
26
27
  * `OPENAI_API_KEY` is missing. The Anthropic SDK resolves credentials lazily, so a missing
27
28
  * `ANTHROPIC_API_KEY` fails the first run instead, with an `UnrecoverableError`.
28
29
  */
29
- export function createLLMAgent(provider, { model, reasoningEffort, systemPrompt, tools, logger = new Logger() }) {
30
+ export function createLLMAgent(provider, { model, reasoningEffort, systemPrompt, tools, autoApprove, logger = new Logger(), }) {
30
31
  let llmClient;
31
32
  switch (provider) {
32
33
  case 'anthropic':
@@ -53,7 +54,7 @@ export function createLLMAgent(provider, { model, reasoningEffort, systemPrompt,
53
54
  }
54
55
  // LLMAgent records nothing from a failed call, so the original prompt is the whole story.
55
56
  return new RetryingAgent({
56
- inner: new LLMAgent({ llmClient, tools }),
57
+ inner: new LLMAgent({ llmClient, tools, autoApprove }),
57
58
  logger,
58
59
  noteFailures: false,
59
60
  });
@@ -65,8 +66,9 @@ const repositoryGuidance = 'Paths are relative to the repository root. Start wit
65
66
  * Builds the planner → executor → reviewer workflow with the planner and reviewer on the model
66
67
  * APIs, from `createLLMAgent`, each holding its role's instructions, or `systemPrompts`, as its
67
68
  * system prompt, with the read-only repository tools for the current working directory. The
68
- * executor stays on its Agent SDK, from `createAgent`, until an agent of ours can change files; `autoApprove` reaches
69
- * only it. Asynchronous because finding the program that reads the repository is.
69
+ * executor stays on its Agent SDK, from `createAgent`, until an agent of ours can change files;
70
+ * `autoApprove` reaches only it. Asynchronous because finding the program that reads the
71
+ * repository is.
70
72
  *
71
73
  * @throws {InvalidAgentConfigError} for an unknown provider.
72
74
  * @throws {UnrecoverableError} when a role cannot be set up, for example because
@@ -1 +1 @@
1
- {"version":3,"file":"agentLLMFactory.js","sourceRoot":"","sources":["../../../src/factory/infrastructure/agentLLMFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Agent } from '#src/agent/domain/agent';\nimport { InvalidAgentConfigError } from '#src/agent/domain/errors';\nimport { LLMAgent } from '#src/engines/domain/model/llmAgent';\nimport type { LLMClient } from '#src/llm/domain/llm';\nimport { ClaudeLLMClient } from '#src/llm/infrastructure/claudeLLMClient';\nimport { OpenAILLMClient } from '#src/llm/infrastructure/openAILLMClient';\nimport { InstructedAgent } from '#src/orchestration/domain/model/instructedAgent';\nimport {\n\texecutorInstructions,\n\tOrchestratorAgent,\n\tplannerInstructions,\n\treviewerInstructions,\n} from '#src/orchestration/domain/model/orchestratorAgent';\nimport { ReviewerDecisionValidator } from '#src/orchestration/infrastructure/model/reviewerDecisionValidator';\nimport { RetryingAgent } from '#src/retry/domain/model/retryingAgent';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport { Logger } from '#src/shared/infrastructure/logger';\nimport type { Tool } from '#src/tools/domain/tool';\nimport { createWorkspace } from '#src/tools/infrastructure/createWorkspace';\nimport { createWorkspaceTools } from '#src/tools/infrastructure/workspaceTools';\nimport { createAgent, orchestratorRolesFor, type Role } from './agentFactory.ts';\nimport {\n\tagentProviders,\n\ttype AgentModel,\n\ttype AgentProvider,\n\ttype CreateOrchestratorOptions,\n\ttype ReasoningEffort,\n} from './types.ts';\n\nexport interface CreateLLMAgentOptions {\n\t/**\n\t * Defaults to `'sonnet'` on Anthropic and `'gpt-5.6-luna'` on OpenAI. The provider's client\n\t * rejects a model it does not support.\n\t */\n\tmodel?: AgentModel;\n\t/** Defaults to `'high'`. The provider's client rejects an effort it does not support. */\n\treasoningEffort?: ReasoningEffort;\n\t/** Sent as the model's instructions on every call. */\n\tsystemPrompt: string;\n\t/** The tools the model may call. Defaults to none. */\n\ttools?: Tool[];\n\t/** Defaults to warnings on stderr. */\n\tlogger?: ILogger;\n}\n\nconst defaultLLMAgentModels = {\n\tanthropic: 'sonnet',\n\topenai: 'gpt-5.6-luna',\n} as const satisfies Record<AgentProvider, AgentModel>;\n\n/**\n * Builds an agent whose conversation MiKode owns, on a provider's model API, already wrapped in\n * the harness's retry policy. Internal while #23 reaches parity with the Agent SDK engines: it\n * is not exported from `src/index.ts`. Its tools only read, so it has no `autoApprove`.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider, or a model or reasoning effort its\n * client does not support.\n * @throws {UnrecoverableError} when the client cannot be set up, for example because\n * `OPENAI_API_KEY` is missing. The Anthropic SDK resolves credentials lazily, so a missing\n * `ANTHROPIC_API_KEY` fails the first run instead, with an `UnrecoverableError`.\n */\nexport function createLLMAgent(\n\tprovider: AgentProvider,\n\t{ model, reasoningEffort, systemPrompt, tools, logger = new Logger() }: CreateLLMAgentOptions,\n): Agent {\n\tlet llmClient: LLMClient;\n\n\tswitch (provider) {\n\t\tcase 'anthropic':\n\t\t\tllmClient = new ClaudeLLMClient({\n\t\t\t\tmodel: model ?? defaultLLMAgentModels.anthropic,\n\t\t\t\treasoningEffort,\n\t\t\t\tsystemPrompt,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'openai':\n\t\t\tllmClient = new OpenAILLMClient({\n\t\t\t\tmodel: model ?? defaultLLMAgentModels.openai,\n\t\t\t\treasoningEffort,\n\t\t\t\tsystemPrompt,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\t// Reachable from untyped input.\n\t\t\tconst unknownProvider: never = provider;\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${String(unknownProvider)}\" is not an agent provider; expected one of: ${agentProviders.join(', ')}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// LLMAgent records nothing from a failed call, so the original prompt is the whole story.\n\treturn new RetryingAgent({\n\t\tinner: new LLMAgent({ llmClient, tools }),\n\t\tlogger,\n\t\tnoteFailures: false,\n\t});\n}\n\n// Sent on every call after the role's instructions, so it stays short: it only says how to find\n// one's way around the repository without reading all of it.\nconst repositoryGuidance =\n\t'Paths are relative to the repository root. Start with AGENTS.md and the architecture document it links to learn where things live, then read only the files your task needs.';\n\n/**\n * Builds the planner → executor → reviewer workflow with the planner and reviewer on the model\n * APIs, from `createLLMAgent`, each holding its role's instructions, or `systemPrompts`, as its\n * system prompt, with the read-only repository tools for the current working directory. The\n * executor stays on its Agent SDK, from `createAgent`, until an agent of ours can change files; `autoApprove` reaches\n * only it. Asynchronous because finding the program that reads the repository is.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider.\n * @throws {UnrecoverableError} when a role cannot be set up, for example because\n * `OPENAI_API_KEY` or the Codex CLI binary is missing, or when no program can read the\n * repository.\n */\nexport async function createLLMOrchestrator({\n\tprovider,\n\tautoApprove,\n\tsystemPrompts = {},\n\tlogger = new Logger(),\n}: CreateOrchestratorOptions = {}): Promise<Agent> {\n\tconst roles = orchestratorRolesFor(provider);\n\tconst tools = createWorkspaceTools(await createWorkspace({ root: process.cwd(), logger }));\n\tconst llmAgentFor = ({ provider, model, reasoningEffort }: Role, systemPrompt: string) =>\n\t\tcreateLLMAgent(provider, { model, reasoningEffort, systemPrompt, tools, logger });\n\t// A caller's own prompt replaces the whole of ours, guidance included.\n\tconst withGuidance = (instructions: string) => `${instructions}\\n\\n${repositoryGuidance}`;\n\n\treturn new OrchestratorAgent({\n\t\tplannerAgent: llmAgentFor(\n\t\t\troles.planner,\n\t\t\tsystemPrompts.planner ?? withGuidance(plannerInstructions),\n\t\t),\n\t\texecutorAgent: new InstructedAgent({\n\t\t\tinner: createAgent(roles.executor.provider, {\n\t\t\t\tmodel: roles.executor.model,\n\t\t\t\treasoningEffort: roles.executor.reasoningEffort,\n\t\t\t\tautoApprove,\n\t\t\t\tlogger,\n\t\t\t}),\n\t\t\tinstructions: systemPrompts.executor ?? executorInstructions,\n\t\t}),\n\t\treviewerAgent: llmAgentFor(\n\t\t\troles.reviewer,\n\t\t\tsystemPrompts.reviewer ?? withGuidance(reviewerInstructions),\n\t\t),\n\t\treviewerDecisionValidator: new ReviewerDecisionValidator(),\n\t\tlogger,\n\t});\n}\n"]}
1
+ {"version":3,"file":"agentLLMFactory.js","sourceRoot":"","sources":["../../../src/factory/infrastructure/agentLLMFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Agent } from '#src/agent/domain/agent';\nimport { InvalidAgentConfigError } from '#src/shared/domain/errors';\nimport { LLMAgent } from '#src/engines/domain/model/llmAgent';\nimport type { LLMClient } from '#src/llm/domain/llm';\nimport { ClaudeLLMClient } from '#src/llm/infrastructure/claudeLLMClient';\nimport { OpenAILLMClient } from '#src/llm/infrastructure/openAILLMClient';\nimport { InstructedAgent } from '#src/orchestration/domain/model/instructedAgent';\nimport {\n\texecutorInstructions,\n\tOrchestratorAgent,\n\tplannerInstructions,\n\treviewerInstructions,\n} from '#src/orchestration/domain/model/orchestratorAgent';\nimport { ReviewerDecisionValidator } from '#src/orchestration/infrastructure/model/reviewerDecisionValidator';\nimport { RetryingAgent } from '#src/retry/domain/model/retryingAgent';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport { Logger } from '#src/shared/infrastructure/logger';\nimport type { Tool } from '#src/tools/domain/tool';\nimport { createWorkspace } from '#src/tools/infrastructure/createWorkspace';\nimport { createWorkspaceTools } from '#src/tools/infrastructure/workspaceTools';\nimport { createAgent, orchestratorRolesFor, type Role } from './agentFactory.ts';\nimport {\n\tagentProviders,\n\ttype AgentModel,\n\ttype AgentProvider,\n\ttype CreateOrchestratorOptions,\n\ttype ReasoningEffort,\n} from './types.ts';\n\nexport interface CreateLLMAgentOptions {\n\t/**\n\t * Defaults to `'sonnet'` on Anthropic and `'gpt-5.6-luna'` on OpenAI. The provider's client\n\t * rejects a model it does not support.\n\t */\n\tmodel?: AgentModel;\n\t/** Defaults to `'high'`. The provider's client rejects an effort it does not support. */\n\treasoningEffort?: ReasoningEffort;\n\t/** Sent as the model's instructions on every call. */\n\tsystemPrompt: string;\n\t/** The tools the model may call. Defaults to none. */\n\ttools?: Tool[];\n\t/**\n\t * Runs every tool call without asking, `destructive` ones included, for CI where no one can\n\t * answer. Without it, a `destructive` call goes to the run's `approve`, or is denied.\n\t */\n\tautoApprove?: boolean;\n\t/** Defaults to warnings on stderr. */\n\tlogger?: ILogger;\n}\n\nconst defaultLLMAgentModels = {\n\tanthropic: 'sonnet',\n\topenai: 'gpt-5.6-luna',\n} as const satisfies Record<AgentProvider, AgentModel>;\n\n/**\n * Builds an agent whose conversation MiKode owns, on a provider's model API, already wrapped in\n * the harness's retry policy. It needs the provider's API key and bills per token, where\n * `createAgent` uses the Agent SDK's login. Each tool judges the risk of each call; a\n * `destructive` one runs only when the run's `approve` allows it, or with `autoApprove`.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider, a model or reasoning effort its\n * client does not support, or two tools that share a name.\n * @throws {UnrecoverableError} when the client cannot be set up, for example because\n * `OPENAI_API_KEY` is missing. The Anthropic SDK resolves credentials lazily, so a missing\n * `ANTHROPIC_API_KEY` fails the first run instead, with an `UnrecoverableError`.\n */\nexport function createLLMAgent(\n\tprovider: AgentProvider,\n\t{\n\t\tmodel,\n\t\treasoningEffort,\n\t\tsystemPrompt,\n\t\ttools,\n\t\tautoApprove,\n\t\tlogger = new Logger(),\n\t}: CreateLLMAgentOptions,\n): Agent {\n\tlet llmClient: LLMClient;\n\n\tswitch (provider) {\n\t\tcase 'anthropic':\n\t\t\tllmClient = new ClaudeLLMClient({\n\t\t\t\tmodel: model ?? defaultLLMAgentModels.anthropic,\n\t\t\t\treasoningEffort,\n\t\t\t\tsystemPrompt,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'openai':\n\t\t\tllmClient = new OpenAILLMClient({\n\t\t\t\tmodel: model ?? defaultLLMAgentModels.openai,\n\t\t\t\treasoningEffort,\n\t\t\t\tsystemPrompt,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\t// Reachable from untyped input.\n\t\t\tconst unknownProvider: never = provider;\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${String(unknownProvider)}\" is not an agent provider; expected one of: ${agentProviders.join(', ')}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// LLMAgent records nothing from a failed call, so the original prompt is the whole story.\n\treturn new RetryingAgent({\n\t\tinner: new LLMAgent({ llmClient, tools, autoApprove }),\n\t\tlogger,\n\t\tnoteFailures: false,\n\t});\n}\n\n// Sent on every call after the role's instructions, so it stays short: it only says how to find\n// one's way around the repository without reading all of it.\nconst repositoryGuidance =\n\t'Paths are relative to the repository root. Start with AGENTS.md and the architecture document it links to learn where things live, then read only the files your task needs.';\n\n/**\n * Builds the planner → executor → reviewer workflow with the planner and reviewer on the model\n * APIs, from `createLLMAgent`, each holding its role's instructions, or `systemPrompts`, as its\n * system prompt, with the read-only repository tools for the current working directory. The\n * executor stays on its Agent SDK, from `createAgent`, until an agent of ours can change files;\n * `autoApprove` reaches only it. Asynchronous because finding the program that reads the\n * repository is.\n *\n * @throws {InvalidAgentConfigError} for an unknown provider.\n * @throws {UnrecoverableError} when a role cannot be set up, for example because\n * `OPENAI_API_KEY` or the Codex CLI binary is missing, or when no program can read the\n * repository.\n */\nexport async function createLLMOrchestrator({\n\tprovider,\n\tautoApprove,\n\tsystemPrompts = {},\n\tlogger = new Logger(),\n}: CreateOrchestratorOptions = {}): Promise<Agent> {\n\tconst roles = orchestratorRolesFor(provider);\n\tconst tools = createWorkspaceTools(await createWorkspace({ root: process.cwd(), logger }));\n\tconst llmAgentFor = ({ provider, model, reasoningEffort }: Role, systemPrompt: string) =>\n\t\tcreateLLMAgent(provider, { model, reasoningEffort, systemPrompt, tools, logger });\n\t// A caller's own prompt replaces the whole of ours, guidance included.\n\tconst withGuidance = (instructions: string) => `${instructions}\\n\\n${repositoryGuidance}`;\n\n\treturn new OrchestratorAgent({\n\t\tplannerAgent: llmAgentFor(\n\t\t\troles.planner,\n\t\t\tsystemPrompts.planner ?? withGuidance(plannerInstructions),\n\t\t),\n\t\texecutorAgent: new InstructedAgent({\n\t\t\tinner: createAgent(roles.executor.provider, {\n\t\t\t\tmodel: roles.executor.model,\n\t\t\t\treasoningEffort: roles.executor.reasoningEffort,\n\t\t\t\tautoApprove,\n\t\t\t\tlogger,\n\t\t\t}),\n\t\t\tinstructions: systemPrompts.executor ?? executorInstructions,\n\t\t}),\n\t\treviewerAgent: llmAgentFor(\n\t\t\troles.reviewer,\n\t\t\tsystemPrompts.reviewer ?? withGuidance(reviewerInstructions),\n\t\t),\n\t\treviewerDecisionValidator: new ReviewerDecisionValidator(),\n\t\tlogger,\n\t});\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  export type { ILogger } from './shared/domain/logger.ts';
2
2
  export { createAgent, createOrchestrator, isAgentProvider, type CreateAgentOptions, } from './factory/infrastructure/agentFactory.ts';
3
+ export { createLLMAgent, createLLMOrchestrator, type CreateLLMAgentOptions, } from './factory/infrastructure/agentLLMFactory.ts';
3
4
  export { agentProviders, type AgentModel, type AgentProvider, type CreateOrchestratorOptions, type ReasoningEffort, } from './factory/infrastructure/types.ts';
4
- export { type Agent, type AgentResponse, type Callback, type ProgressEvent, } from './agent/domain/agent.ts';
5
- export { InvalidAgentConfigError, RecoverableError, UnrecoverableError, } from './agent/domain/errors.ts';
5
+ export { type Agent, type AgentResponse, type Callback, type ProgressEvent, type RunOptions, } from './agent/domain/agent.ts';
6
+ export { InvalidAgentConfigError, RecoverableError, UnrecoverableError, } from './shared/domain/errors.ts';
6
7
  export { isAbortError } from './shared/domain/isAbortError.ts';
7
8
  export type { Tokens } from './shared/domain/tokens.ts';
9
+ export { rememberApprovals, type ApprovalDecision, type ApprovalRequest, type Approver, type RememberableDecision, type ToolRisk, } from './agent/domain/approval.ts';
10
+ export type { JSONSchema, ToolDefinition } from './llm/domain/tool.ts';
11
+ export type { Tool } from './tools/domain/tool.ts';
12
+ export type { TextMatch, Workspace } from './tools/domain/workspace.ts';
13
+ export { defineTool } from './tools/infrastructure/defineTool.ts';
14
+ export { createWorkspace } from './tools/infrastructure/createWorkspace.ts';
15
+ export { createWorkspaceTools } from './tools/infrastructure/workspaceTools.ts';
package/dist/index.js CHANGED
@@ -1,6 +1,11 @@
1
1
  export { createAgent, createOrchestrator, isAgentProvider, } from "./factory/infrastructure/agentFactory.js";
2
+ export { createLLMAgent, createLLMOrchestrator, } from "./factory/infrastructure/agentLLMFactory.js";
2
3
  export { agentProviders, } from "./factory/infrastructure/types.js";
3
4
  export {} from "./agent/domain/agent.js";
4
- export { InvalidAgentConfigError, RecoverableError, UnrecoverableError, } from "./agent/domain/errors.js";
5
+ export { InvalidAgentConfigError, RecoverableError, UnrecoverableError, } from "./shared/domain/errors.js";
5
6
  export { isAbortError } from "./shared/domain/isAbortError.js";
7
+ export { rememberApprovals, } from "./agent/domain/approval.js";
8
+ export { defineTool } from "./tools/infrastructure/defineTool.js";
9
+ export { createWorkspace } from "./tools/infrastructure/createWorkspace.js";
10
+ export { createWorkspaceTools } from "./tools/infrastructure/workspaceTools.js";
6
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,WAAW,EACX,kBAAkB,EAClB,eAAe,GAEf,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACN,cAAc,GAKd,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAKN,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACN,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC","sourcesContent":["export type { ILogger } from './shared/domain/logger.ts';\nexport {\n\tcreateAgent,\n\tcreateOrchestrator,\n\tisAgentProvider,\n\ttype CreateAgentOptions,\n} from './factory/infrastructure/agentFactory.ts';\nexport {\n\tagentProviders,\n\ttype AgentModel,\n\ttype AgentProvider,\n\ttype CreateOrchestratorOptions,\n\ttype ReasoningEffort,\n} from './factory/infrastructure/types.ts';\nexport {\n\ttype Agent,\n\ttype AgentResponse,\n\ttype Callback,\n\ttype ProgressEvent,\n} from './agent/domain/agent.ts';\nexport {\n\tInvalidAgentConfigError,\n\tRecoverableError,\n\tUnrecoverableError,\n} from './agent/domain/errors.ts';\nexport { isAbortError } from './shared/domain/isAbortError.ts';\nexport type { Tokens } from './shared/domain/tokens.ts';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,WAAW,EACX,kBAAkB,EAClB,eAAe,GAEf,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACN,cAAc,EACd,qBAAqB,GAErB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,cAAc,GAKd,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAMN,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACN,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EACN,iBAAiB,GAMjB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC","sourcesContent":["export type { ILogger } from './shared/domain/logger.ts';\nexport {\n\tcreateAgent,\n\tcreateOrchestrator,\n\tisAgentProvider,\n\ttype CreateAgentOptions,\n} from './factory/infrastructure/agentFactory.ts';\nexport {\n\tcreateLLMAgent,\n\tcreateLLMOrchestrator,\n\ttype CreateLLMAgentOptions,\n} from './factory/infrastructure/agentLLMFactory.ts';\nexport {\n\tagentProviders,\n\ttype AgentModel,\n\ttype AgentProvider,\n\ttype CreateOrchestratorOptions,\n\ttype ReasoningEffort,\n} from './factory/infrastructure/types.ts';\nexport {\n\ttype Agent,\n\ttype AgentResponse,\n\ttype Callback,\n\ttype ProgressEvent,\n\ttype RunOptions,\n} from './agent/domain/agent.ts';\nexport {\n\tInvalidAgentConfigError,\n\tRecoverableError,\n\tUnrecoverableError,\n} from './shared/domain/errors.ts';\nexport { isAbortError } from './shared/domain/isAbortError.ts';\nexport type { Tokens } from './shared/domain/tokens.ts';\nexport {\n\trememberApprovals,\n\ttype ApprovalDecision,\n\ttype ApprovalRequest,\n\ttype Approver,\n\ttype RememberableDecision,\n\ttype ToolRisk,\n} from './agent/domain/approval.ts';\nexport type { JSONSchema, ToolDefinition } from './llm/domain/tool.ts';\nexport type { Tool } from './tools/domain/tool.ts';\nexport type { TextMatch, Workspace } from './tools/domain/workspace.ts';\nexport { defineTool } from './tools/infrastructure/defineTool.ts';\nexport { createWorkspace } from './tools/infrastructure/createWorkspace.ts';\nexport { createWorkspaceTools } from './tools/infrastructure/workspaceTools.ts';\n"]}
@@ -1,4 +1,4 @@
1
- import { UnrecoverableError } from '#src/agent/domain/errors';
1
+ import { UnrecoverableError } from '#src/shared/domain/errors';
2
2
  /** The context no longer fits the model's window; the agent must compact before sending again. */
3
3
  export declare class MaxContextError extends UnrecoverableError {
4
4
  }
@@ -1,4 +1,4 @@
1
- import { UnrecoverableError } from '#src/agent/domain/errors';
1
+ import { UnrecoverableError } from '#src/shared/domain/errors';
2
2
  /** The context no longer fits the model's window; the agent must compact before sending again. */
3
3
  export class MaxContextError extends UnrecoverableError {
4
4
  }