@mikode13/harness 11.0.1 → 11.2.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 (120) hide show
  1. package/README.md +186 -16
  2. package/dist/agent/domain/agent.d.ts +41 -3
  3. package/dist/agent/domain/agent.js.map +1 -1
  4. package/dist/agent/domain/approval.d.ts +20 -0
  5. package/dist/agent/domain/approval.js.map +1 -1
  6. package/dist/agent/domain/inbox.d.ts +42 -0
  7. package/dist/agent/domain/inbox.js +81 -0
  8. package/dist/agent/domain/inbox.js.map +1 -0
  9. package/dist/agent/domain/oneRunAtATime.d.ts +17 -0
  10. package/dist/agent/domain/oneRunAtATime.js +32 -0
  11. package/dist/agent/domain/oneRunAtATime.js.map +1 -0
  12. package/dist/agent/domain/runContext.d.ts +9 -0
  13. package/dist/agent/domain/runContext.js +5 -0
  14. package/dist/agent/domain/runContext.js.map +1 -1
  15. package/dist/agent/domain/session.d.ts +15 -0
  16. package/dist/agent/domain/session.js +80 -0
  17. package/dist/agent/domain/session.js.map +1 -0
  18. package/dist/engines/claude/infrastructure/model/claudeAgent.d.ts +6 -2
  19. package/dist/engines/claude/infrastructure/model/claudeAgent.js +20 -5
  20. package/dist/engines/claude/infrastructure/model/claudeAgent.js.map +1 -1
  21. package/dist/engines/codex/infrastructure/model/codexAgent.d.ts +5 -1
  22. package/dist/engines/codex/infrastructure/model/codexAgent.js +13 -2
  23. package/dist/engines/codex/infrastructure/model/codexAgent.js.map +1 -1
  24. package/dist/engines/domain/model/backgroundAgents.d.ts +5 -2
  25. package/dist/engines/domain/model/backgroundAgents.js +11 -3
  26. package/dist/engines/domain/model/backgroundAgents.js.map +1 -1
  27. package/dist/engines/domain/model/compactor.d.ts +40 -0
  28. package/dist/engines/domain/model/compactor.js +5 -0
  29. package/dist/engines/domain/model/compactor.js.map +1 -0
  30. package/dist/engines/domain/model/llmAgent.d.ts +53 -2
  31. package/dist/engines/domain/model/llmAgent.js +419 -24
  32. package/dist/engines/domain/model/llmAgent.js.map +1 -1
  33. package/dist/engines/domain/model/recentCompaction.d.ts +39 -0
  34. package/dist/engines/domain/model/recentCompaction.js +119 -0
  35. package/dist/engines/domain/model/recentCompaction.js.map +1 -0
  36. package/dist/engines/domain/model/stepContext.js +3 -0
  37. package/dist/engines/domain/model/stepContext.js.map +1 -1
  38. package/dist/engines/domain/model/triagedCompaction.d.ts +27 -0
  39. package/dist/engines/domain/model/triagedCompaction.js +60 -0
  40. package/dist/engines/domain/model/triagedCompaction.js.map +1 -0
  41. package/dist/factory/infrastructure/agentLLMFactory.d.ts +56 -15
  42. package/dist/factory/infrastructure/agentLLMFactory.js +144 -25
  43. package/dist/factory/infrastructure/agentLLMFactory.js.map +1 -1
  44. package/dist/index.d.ts +6 -2
  45. package/dist/index.js +3 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/llm/domain/contextTriage.d.ts +26 -0
  48. package/dist/llm/domain/contextTriage.js +3 -0
  49. package/dist/llm/domain/contextTriage.js.map +1 -0
  50. package/dist/llm/domain/llm.d.ts +18 -1
  51. package/dist/llm/domain/llm.js.map +1 -1
  52. package/dist/llm/domain/message.d.ts +18 -1
  53. package/dist/llm/domain/message.js +20 -0
  54. package/dist/llm/domain/message.js.map +1 -1
  55. package/dist/llm/infrastructure/claudeLLMClient.d.ts +4 -5
  56. package/dist/llm/infrastructure/claudeLLMClient.js +39 -13
  57. package/dist/llm/infrastructure/claudeLLMClient.js.map +1 -1
  58. package/dist/llm/infrastructure/jevContextTriage.d.ts +18 -0
  59. package/dist/llm/infrastructure/jevContextTriage.js +92 -0
  60. package/dist/llm/infrastructure/jevContextTriage.js.map +1 -0
  61. package/dist/llm/infrastructure/openAILLMClient.d.ts +4 -5
  62. package/dist/llm/infrastructure/openAILLMClient.js +20 -9
  63. package/dist/llm/infrastructure/openAILLMClient.js.map +1 -1
  64. package/dist/orchestration/domain/model/orchestratorAgent.d.ts +9 -1
  65. package/dist/orchestration/domain/model/orchestratorAgent.js +20 -3
  66. package/dist/orchestration/domain/model/orchestratorAgent.js.map +1 -1
  67. package/dist/recovery/domain/history.d.ts +10 -3
  68. package/dist/recovery/domain/history.js +1 -0
  69. package/dist/recovery/domain/history.js.map +1 -1
  70. package/dist/recovery/domain/recoveryStore.d.ts +14 -2
  71. package/dist/recovery/domain/recoveryStore.js.map +1 -1
  72. package/dist/recovery/infrastructure/fileRecoveryStore.d.ts +21 -2
  73. package/dist/recovery/infrastructure/fileRecoveryStore.js +58 -6
  74. package/dist/recovery/infrastructure/fileRecoveryStore.js.map +1 -1
  75. package/dist/recovery/infrastructure/folderClaims.d.ts +27 -0
  76. package/dist/recovery/infrastructure/folderClaims.js +124 -0
  77. package/dist/recovery/infrastructure/folderClaims.js.map +1 -0
  78. package/dist/shared/domain/session.d.ts +12 -0
  79. package/dist/shared/domain/session.js +2 -0
  80. package/dist/shared/domain/session.js.map +1 -0
  81. package/dist/tools/domain/preparedCall.d.ts +5 -2
  82. package/dist/tools/domain/preparedCall.js +7 -1
  83. package/dist/tools/domain/preparedCall.js.map +1 -1
  84. package/dist/tools/domain/readRegistry.d.ts +11 -0
  85. package/dist/tools/domain/readRegistry.js.map +1 -1
  86. package/dist/tools/infrastructure/agentAsTool.d.ts +6 -0
  87. package/dist/tools/infrastructure/agentAsTool.js +9 -0
  88. package/dist/tools/infrastructure/agentAsTool.js.map +1 -1
  89. package/dist/tools/infrastructure/commandTool.js +6 -1
  90. package/dist/tools/infrastructure/commandTool.js.map +1 -1
  91. package/dist/tools/infrastructure/exploreTool.js +2 -0
  92. package/dist/tools/infrastructure/exploreTool.js.map +1 -1
  93. package/dist/tools/infrastructure/fileTools.d.ts +2 -0
  94. package/dist/tools/infrastructure/fileTools.js +10 -1
  95. package/dist/tools/infrastructure/fileTools.js.map +1 -1
  96. package/dist/tools/infrastructure/removeWorktreeTool.d.ts +23 -0
  97. package/dist/tools/infrastructure/removeWorktreeTool.js +178 -0
  98. package/dist/tools/infrastructure/removeWorktreeTool.js.map +1 -0
  99. package/dist/tools/infrastructure/subagents.d.ts +3 -1
  100. package/dist/tools/infrastructure/subagents.js +2 -1
  101. package/dist/tools/infrastructure/subagents.js.map +1 -1
  102. package/dist/tools/infrastructure/trackedEdits.js +1 -0
  103. package/dist/tools/infrastructure/trackedEdits.js.map +1 -1
  104. package/dist/tools/infrastructure/workspaceWrites.d.ts +17 -1
  105. package/dist/tools/infrastructure/workspaceWrites.js +48 -17
  106. package/dist/tools/infrastructure/workspaceWrites.js.map +1 -1
  107. package/dist/tools/infrastructure/worktrees.d.ts +49 -0
  108. package/dist/tools/infrastructure/worktrees.js +154 -0
  109. package/dist/tools/infrastructure/worktrees.js.map +1 -0
  110. package/dist/tools/infrastructure/writeCeiling.d.ts +16 -0
  111. package/dist/tools/infrastructure/writeCeiling.js +49 -0
  112. package/dist/tools/infrastructure/writeCeiling.js.map +1 -0
  113. package/dist/tools/infrastructure/writeSession.d.ts +5 -1
  114. package/dist/tools/infrastructure/writeSession.js +7 -3
  115. package/dist/tools/infrastructure/writeSession.js.map +1 -1
  116. package/dist/workflow/domain/workflow.d.ts +3 -0
  117. package/dist/workflow/domain/workflow.js.map +1 -1
  118. package/dist/workflow/domain/workflowRunner.js +8 -2
  119. package/dist/workflow/domain/workflowRunner.js.map +1 -1
  120. package/package.json +2 -1
@@ -0,0 +1,32 @@
1
+ import { UnrecoverableError } from '#src/shared/domain/errors';
2
+ /**
3
+ * A run started on an agent instance while another run on it works. An instance continues one
4
+ * conversation, so two runs at once would each continue it from the same point, and one would
5
+ * silently drop the other.
6
+ */
7
+ export class RunInProgressError extends UnrecoverableError {
8
+ // The parameters keep the shape `withSpentTokens` copies a classified failure with.
9
+ constructor(message = 'The agent already has a run in progress', options = {
10
+ cause: 'An agent instance continues one conversation, one run at a time. Wait for the run in progress to end, or send the message to it through its inbox.',
11
+ }) {
12
+ super(message, options);
13
+ this.name = 'RunInProgressError';
14
+ }
15
+ }
16
+ /** Lets an agent instance work on one run at a time, and rejects a run that starts meanwhile. */
17
+ export class OneRunAtATime {
18
+ running = false;
19
+ /** Runs `work`, unless a run is already in progress. */
20
+ async run(work) {
21
+ if (this.running)
22
+ throw new RunInProgressError();
23
+ this.running = true;
24
+ try {
25
+ return await work();
26
+ }
27
+ finally {
28
+ this.running = false;
29
+ }
30
+ }
31
+ }
32
+ //# sourceMappingURL=oneRunAtATime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oneRunAtATime.js","sourceRoot":"","sources":["../../../src/agent/domain/oneRunAtATime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAI/D;;;;GAIG;AACH,MAAM,OAAO,kBAAmB,SAAQ,kBAAkB;IACzD,oFAAoF;IACpF,YACC,OAAO,GAAG,yCAAyC,EACnD,UAAmB;QAClB,KAAK,EACJ,oJAAoJ;KACrJ;QAED,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IAClC,CAAC;CACD;AAED,iGAAiG;AACjG,MAAM,OAAO,aAAa;IACjB,OAAO,GAAG,KAAK,CAAC;IAExB,wDAAwD;IACxD,KAAK,CAAC,GAAG,CAAI,IAAsB;QAClC,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,kBAAkB,EAAE,CAAC;QACjD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YACJ,OAAO,MAAM,IAAI,EAAE,CAAC;QACrB,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACtB,CAAC;IACF,CAAC;CACD","sourcesContent":["import { UnrecoverableError } from '#src/shared/domain/errors';\n\ntype Options = ConstructorParameters<typeof UnrecoverableError>[1];\n\n/**\n * A run started on an agent instance while another run on it works. An instance continues one\n * conversation, so two runs at once would each continue it from the same point, and one would\n * silently drop the other.\n */\nexport class RunInProgressError extends UnrecoverableError {\n\t// The parameters keep the shape `withSpentTokens` copies a classified failure with.\n\tconstructor(\n\t\tmessage = 'The agent already has a run in progress',\n\t\toptions: Options = {\n\t\t\tcause:\n\t\t\t\t'An agent instance continues one conversation, one run at a time. Wait for the run in progress to end, or send the message to it through its inbox.',\n\t\t},\n\t) {\n\t\tsuper(message, options);\n\t\tthis.name = 'RunInProgressError';\n\t}\n}\n\n/** Lets an agent instance work on one run at a time, and rejects a run that starts meanwhile. */\nexport class OneRunAtATime {\n\tprivate running = false;\n\n\t/** Runs `work`, unless a run is already in progress. */\n\tasync run<T>(work: () => Promise<T>): Promise<T> {\n\t\tif (this.running) throw new RunInProgressError();\n\t\tthis.running = true;\n\t\ttry {\n\t\t\treturn await work();\n\t\t} finally {\n\t\t\tthis.running = false;\n\t\t}\n\t}\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { RunOptions } from './agent.ts';
2
+ import type { Session } from '#src/shared/domain/session';
2
3
  export type RunEnd = 'completed' | 'failed' | 'cancelled';
3
4
  /**
4
5
  * What one top-level run shares with every agent and tool inside it, across all its roles,
@@ -10,6 +11,8 @@ export type RunEnd = 'completed' | 'failed' | 'cancelled';
10
11
  */
11
12
  export declare class RunContext {
12
13
  private readonly finishers;
14
+ /** The session the run belongs to, which every agent inside it answers with. */
15
+ readonly session: Session;
13
16
  /**
14
17
  * The run the workspace's history recorded for this run, once it first wrote. The object is
15
18
  * shared, not copied: a turn recorded before the first write still learns its run.
@@ -17,6 +20,7 @@ export declare class RunContext {
17
20
  readonly historyRun: {
18
21
  runId?: string;
19
22
  };
23
+ constructor(session: Session);
20
24
  /** Ends something the run started, when the run ends. */
21
25
  onFinish(finisher: (end: RunEnd) => Promise<void>): void;
22
26
  /**
@@ -41,6 +45,11 @@ export interface Delegation {
41
45
  /** Which of the agents that call started, from 1. */
42
46
  readonly subagent: number;
43
47
  readonly depth: number;
48
+ /**
49
+ * The folders it may write in, as real paths, so it never writes more than the agents that
50
+ * delegated to it: empty when it may write nowhere, absent when none set a limit.
51
+ */
52
+ readonly writeCeiling?: readonly string[];
44
53
  }
45
54
  /** The call that started the agent these options reach, if another agent's tool did. */
46
55
  export declare function delegationOf(options: RunOptions): Delegation | undefined;
@@ -8,11 +8,16 @@
8
8
  */
9
9
  export class RunContext {
10
10
  finishers = [];
11
+ /** The session the run belongs to, which every agent inside it answers with. */
12
+ session;
11
13
  /**
12
14
  * The run the workspace's history recorded for this run, once it first wrote. The object is
13
15
  * shared, not copied: a turn recorded before the first write still learns its run.
14
16
  */
15
17
  historyRun = {};
18
+ constructor(session) {
19
+ this.session = session;
20
+ }
16
21
  /** Ends something the run started, when the run ends. */
17
22
  onFinish(finisher) {
18
23
  this.finishers.push(finisher);
@@ -1 +1 @@
1
- {"version":3,"file":"runContext.js","sourceRoot":"","sources":["../../../src/agent/domain/runContext.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,MAAM,OAAO,UAAU;IACL,SAAS,GAAuC,EAAE,CAAC;IAEpE;;;OAGG;IACM,UAAU,GAAuB,EAAE,CAAC;IAE7C,yDAAyD;IACzD,QAAQ,CAAC,QAAwC;QAChD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,GAAW;QACvB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC;gBACJ,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACF,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;CACD;AAED,MAAM,aAAa,GAAG,MAAM,CAAC,2BAA2B,CAAC,CAAC;AAM1D,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAAC,OAAmB;IAC/C,OAAQ,OAAgC,CAAC,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,OAAmB,EAAE,OAAmB;IACtE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,OAAO,EAA0B,CAAC;AACzE,CAAC;AAgBD,MAAM,aAAa,GAAG,MAAM,CAAC,2BAA2B,CAAC,CAAC;AAM1D,wFAAwF;AACxF,MAAM,UAAU,YAAY,CAAC,OAAmB;IAC/C,OAAQ,OAA+B,CAAC,aAAa,CAAC,CAAC;AACxD,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAAC,OAAmB,EAAE,UAAsB;IACzE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,UAAU,EAAyB,CAAC;AAC3E,CAAC","sourcesContent":["import type { RunOptions } from './agent.ts';\n\nexport type RunEnd = 'completed' | 'failed' | 'cancelled';\n\n/**\n * What one top-level run shares with every agent and tool inside it, across all its roles,\n * rounds and retries, such as the record of what it wrote. Whatever a tool starts for the run\n * registers how to end it, and the agent that created the context ends it with the run.\n *\n * Internal: it travels in `RunOptions` under a symbol, so decorators, which pass the options on\n * whole, carry it without knowing it exists, and no consumer can see or set it.\n */\nexport class RunContext {\n\tprivate readonly finishers: ((end: RunEnd) => Promise<void>)[] = [];\n\n\t/**\n\t * The run the workspace's history recorded for this run, once it first wrote. The object is\n\t * shared, not copied: a turn recorded before the first write still learns its run.\n\t */\n\treadonly historyRun: { runId?: string } = {};\n\n\t/** Ends something the run started, when the run ends. */\n\tonFinish(finisher: (end: RunEnd) => Promise<void>): void {\n\t\tthis.finishers.push(finisher);\n\t}\n\n\t/**\n\t * Ends everything registered, all of it even when one fails, and then throws the first\n\t * failure.\n\t */\n\tasync finish(end: RunEnd): Promise<void> {\n\t\tconst failures: unknown[] = [];\n\t\tfor (const finisher of this.finishers.splice(0)) {\n\t\t\ttry {\n\t\t\t\tawait finisher(end);\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t}\n\t\tif (failures.length > 0) throw failures[0];\n\t}\n}\n\nconst runContextKey = Symbol('mikode-harness.runContext');\n\ninterface ContextualRunOptions extends RunOptions {\n\t[runContextKey]?: RunContext;\n}\n\n/** The context of the run these options belong to, if an outer agent created one. */\nexport function runContextOf(options: RunOptions): RunContext | undefined {\n\treturn (options as ContextualRunOptions)[runContextKey];\n}\n\n/** The same options, carrying `context` for every agent the run reaches. */\nexport function withRunContext(options: RunOptions, context: RunContext): RunOptions {\n\treturn { ...options, [runContextKey]: context } as ContextualRunOptions;\n}\n\n/**\n * Where an agent another agent's tool started runs: the call that started it, and how many\n * delegations deep it is, 1 for an agent the top-level agent started.\n */\nexport interface Delegation {\n\t/** The name of the tool that started it, such as `explore` or a specialist's. */\n\treadonly tool: string;\n\t/** The `id` of that call's `tool` events. */\n\treadonly callId: string;\n\t/** Which of the agents that call started, from 1. */\n\treadonly subagent: number;\n\treadonly depth: number;\n}\n\nconst delegationKey = Symbol('mikode-harness.delegation');\n\ninterface DelegatedRunOptions extends RunOptions {\n\t[delegationKey]?: Delegation;\n}\n\n/** The call that started the agent these options reach, if another agent's tool did. */\nexport function delegationOf(options: RunOptions): Delegation | undefined {\n\treturn (options as DelegatedRunOptions)[delegationKey];\n}\n\n/** The same options, for an agent `delegation` started. */\nexport function withDelegation(options: RunOptions, delegation: Delegation): RunOptions {\n\treturn { ...options, [delegationKey]: delegation } as DelegatedRunOptions;\n}\n"]}
1
+ {"version":3,"file":"runContext.js","sourceRoot":"","sources":["../../../src/agent/domain/runContext.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,MAAM,OAAO,UAAU;IACL,SAAS,GAAuC,EAAE,CAAC;IAEpE,gFAAgF;IACvE,OAAO,CAAU;IAE1B;;;OAGG;IACM,UAAU,GAAuB,EAAE,CAAC;IAE7C,YAAY,OAAgB;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,yDAAyD;IACzD,QAAQ,CAAC,QAAwC;QAChD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,GAAW;QACvB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC;gBACJ,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACF,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;CACD;AAED,MAAM,aAAa,GAAG,MAAM,CAAC,2BAA2B,CAAC,CAAC;AAM1D,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAAC,OAAmB;IAC/C,OAAQ,OAAgC,CAAC,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,OAAmB,EAAE,OAAmB;IACtE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,OAAO,EAA0B,CAAC;AACzE,CAAC;AAqBD,MAAM,aAAa,GAAG,MAAM,CAAC,2BAA2B,CAAC,CAAC;AAM1D,wFAAwF;AACxF,MAAM,UAAU,YAAY,CAAC,OAAmB;IAC/C,OAAQ,OAA+B,CAAC,aAAa,CAAC,CAAC;AACxD,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAAC,OAAmB,EAAE,UAAsB;IACzE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,UAAU,EAAyB,CAAC;AAC3E,CAAC","sourcesContent":["import type { RunOptions } from './agent.ts';\nimport type { Session } from '#src/shared/domain/session';\n\nexport type RunEnd = 'completed' | 'failed' | 'cancelled';\n\n/**\n * What one top-level run shares with every agent and tool inside it, across all its roles,\n * rounds and retries, such as the record of what it wrote. Whatever a tool starts for the run\n * registers how to end it, and the agent that created the context ends it with the run.\n *\n * Internal: it travels in `RunOptions` under a symbol, so decorators, which pass the options on\n * whole, carry it without knowing it exists, and no consumer can see or set it.\n */\nexport class RunContext {\n\tprivate readonly finishers: ((end: RunEnd) => Promise<void>)[] = [];\n\n\t/** The session the run belongs to, which every agent inside it answers with. */\n\treadonly session: Session;\n\n\t/**\n\t * The run the workspace's history recorded for this run, once it first wrote. The object is\n\t * shared, not copied: a turn recorded before the first write still learns its run.\n\t */\n\treadonly historyRun: { runId?: string } = {};\n\n\tconstructor(session: Session) {\n\t\tthis.session = session;\n\t}\n\n\t/** Ends something the run started, when the run ends. */\n\tonFinish(finisher: (end: RunEnd) => Promise<void>): void {\n\t\tthis.finishers.push(finisher);\n\t}\n\n\t/**\n\t * Ends everything registered, all of it even when one fails, and then throws the first\n\t * failure.\n\t */\n\tasync finish(end: RunEnd): Promise<void> {\n\t\tconst failures: unknown[] = [];\n\t\tfor (const finisher of this.finishers.splice(0)) {\n\t\t\ttry {\n\t\t\t\tawait finisher(end);\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t}\n\t\tif (failures.length > 0) throw failures[0];\n\t}\n}\n\nconst runContextKey = Symbol('mikode-harness.runContext');\n\ninterface ContextualRunOptions extends RunOptions {\n\t[runContextKey]?: RunContext;\n}\n\n/** The context of the run these options belong to, if an outer agent created one. */\nexport function runContextOf(options: RunOptions): RunContext | undefined {\n\treturn (options as ContextualRunOptions)[runContextKey];\n}\n\n/** The same options, carrying `context` for every agent the run reaches. */\nexport function withRunContext(options: RunOptions, context: RunContext): RunOptions {\n\treturn { ...options, [runContextKey]: context } as ContextualRunOptions;\n}\n\n/**\n * Where an agent another agent's tool started runs: the call that started it, and how many\n * delegations deep it is, 1 for an agent the top-level agent started.\n */\nexport interface Delegation {\n\t/** The name of the tool that started it, such as `explore` or a specialist's. */\n\treadonly tool: string;\n\t/** The `id` of that call's `tool` events. */\n\treadonly callId: string;\n\t/** Which of the agents that call started, from 1. */\n\treadonly subagent: number;\n\treadonly depth: number;\n\t/**\n\t * The folders it may write in, as real paths, so it never writes more than the agents that\n\t * delegated to it: empty when it may write nowhere, absent when none set a limit.\n\t */\n\treadonly writeCeiling?: readonly string[];\n}\n\nconst delegationKey = Symbol('mikode-harness.delegation');\n\ninterface DelegatedRunOptions extends RunOptions {\n\t[delegationKey]?: Delegation;\n}\n\n/** The call that started the agent these options reach, if another agent's tool did. */\nexport function delegationOf(options: RunOptions): Delegation | undefined {\n\treturn (options as DelegatedRunOptions)[delegationKey];\n}\n\n/** The same options, for an agent `delegation` started. */\nexport function withDelegation(options: RunOptions, delegation: Delegation): RunOptions {\n\treturn { ...options, [delegationKey]: delegation } as DelegatedRunOptions;\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { RunOptions } from './agent.ts';
2
+ import type { Session } from '#src/shared/domain/session';
3
+ /**
4
+ * A session of its own, for an agent the consumer gave none: its id, such as `smart-hawk-4821`,
5
+ * is easier to read and say than a UUID, and unlikely to repeat in one workspace's history.
6
+ */
7
+ export declare function newSession(): Session;
8
+ /**
9
+ * The session a run belongs to: the outer run's, for an agent another agent started, or the one
10
+ * its options name. Absent when neither gives one, and the agent uses its own.
11
+ *
12
+ * @throws {UnrecoverableError} when the options name a session that is not an object, has no
13
+ * id, or has a name that is not text.
14
+ */
15
+ export declare function sessionOf(options: RunOptions): Session | undefined;
@@ -0,0 +1,80 @@
1
+ import { randomInt } from 'node:crypto';
2
+ import { UnrecoverableError } from '#src/shared/domain/errors';
3
+ import { runContextOf } from "./runContext.js";
4
+ // Short, plain and inoffensive in any pairing, so an id reads like a name.
5
+ // prettier-ignore
6
+ const adjectives = [
7
+ 'able', 'agile', 'amber', 'ample', 'azure', 'bold', 'brave', 'breezy', 'bright', 'brisk',
8
+ 'calm', 'candid', 'clever', 'cosmic', 'cozy', 'crisp', 'curious', 'daring', 'dawn', 'deft',
9
+ 'eager', 'early', 'easy', 'electric', 'epic', 'fair', 'fancy', 'fast', 'fearless', 'fine',
10
+ 'fluent', 'fresh', 'friendly', 'frosty', 'gentle', 'giant', 'glad', 'golden', 'grand',
11
+ 'green', 'happy', 'hardy', 'hearty', 'honest', 'humble', 'jolly', 'keen', 'kind', 'lively',
12
+ 'loyal', 'lucid', 'lucky', 'lunar', 'mellow', 'merry', 'mighty', 'misty', 'modest', 'neat',
13
+ 'nimble', 'noble', 'patient', 'peppy', 'plucky', 'polar', 'polite', 'proud', 'quick', 'quiet',
14
+ 'radiant', 'rapid', 'ready', 'regal', 'rosy', 'royal', 'rustic', 'sage', 'sandy', 'serene',
15
+ 'sharp', 'shiny', 'silent', 'silver', 'simple', 'sleek', 'smart', 'snowy', 'solar', 'solid',
16
+ 'sonic', 'spry', 'steady', 'stellar', 'sturdy', 'sunny', 'super', 'swift', 'tidy', 'tranquil',
17
+ 'true', 'trusty', 'upbeat', 'urban', 'valiant', 'vivid', 'warm', 'wise', 'witty', 'young',
18
+ 'zesty',
19
+ ];
20
+ // prettier-ignore
21
+ const animals = [
22
+ 'alpaca', 'badger', 'beaver', 'bison', 'bobcat', 'buffalo', 'camel', 'caribou', 'cheetah',
23
+ 'condor', 'cougar', 'coyote', 'crane', 'cricket', 'dingo', 'dolphin', 'dove', 'eagle',
24
+ 'egret', 'elk', 'falcon', 'ferret', 'finch', 'flamingo', 'fox', 'gazelle', 'gecko', 'gibbon',
25
+ 'giraffe', 'goose', 'gopher', 'gorilla', 'grouse', 'gull', 'hare', 'hawk', 'hedgehog',
26
+ 'heron', 'hippo', 'ibex', 'ibis', 'iguana', 'impala', 'jackal', 'jaguar', 'jay', 'kestrel',
27
+ 'kiwi', 'koala', 'lark', 'lemur', 'leopard', 'lion', 'llama', 'lynx', 'macaw', 'magpie',
28
+ 'manatee', 'marmot', 'marten', 'meerkat', 'mink', 'moose', 'narwhal', 'newt', 'ocelot',
29
+ 'orca', 'oriole', 'osprey', 'otter', 'owl', 'panda', 'panther', 'parrot', 'pelican',
30
+ 'penguin', 'puffin', 'puma', 'quail', 'rabbit', 'raccoon', 'raven', 'reindeer', 'robin',
31
+ 'salmon', 'seal', 'sparrow', 'squirrel', 'stork', 'swallow', 'swan', 'tapir', 'tiger',
32
+ 'toucan', 'trout', 'turtle', 'walrus', 'weasel', 'whale', 'wolf', 'wombat', 'wren', 'yak',
33
+ 'zebra',
34
+ ];
35
+ function pick(words) {
36
+ return words[randomInt(words.length)] ?? '';
37
+ }
38
+ /**
39
+ * A session of its own, for an agent the consumer gave none: its id, such as `smart-hawk-4821`,
40
+ * is easier to read and say than a UUID, and unlikely to repeat in one workspace's history.
41
+ */
42
+ export function newSession() {
43
+ return { id: `${pick(adjectives)}-${pick(animals)}-${String(randomInt(1000, 10000))}` };
44
+ }
45
+ /**
46
+ * The session a run belongs to: the outer run's, for an agent another agent started, or the one
47
+ * its options name. Absent when neither gives one, and the agent uses its own.
48
+ *
49
+ * @throws {UnrecoverableError} when the options name a session that is not an object, has no
50
+ * id, or has a name that is not text.
51
+ */
52
+ export function sessionOf(options) {
53
+ const inherited = runContextOf(options)?.session;
54
+ if (inherited)
55
+ return inherited;
56
+ // Read without trusting its type, as a JavaScript consumer can pass anything.
57
+ const { session } = options;
58
+ if (session === undefined)
59
+ return undefined;
60
+ if (typeof session !== 'object' || session === null) {
61
+ throw new UnrecoverableError('The run was given a session that is not an object', {
62
+ cause: 'RunOptions.session, when given, is { id, name? }.',
63
+ });
64
+ }
65
+ const { id, name } = session;
66
+ if (typeof id !== 'string' || id.trim() === '') {
67
+ throw new UnrecoverableError('The run was given a session without an id', {
68
+ cause: 'RunOptions.session needs an id that is not blank.',
69
+ });
70
+ }
71
+ if (name !== undefined && typeof name !== 'string') {
72
+ throw new UnrecoverableError('The run was given a session whose name is not text', {
73
+ cause: 'RunOptions.session.name, when given, is a string.',
74
+ });
75
+ }
76
+ // A copy, so a consumer changing its object later changes nothing recorded. A blank name is
77
+ // none: a host shows the id instead.
78
+ return name === undefined || name.trim() === '' ? { id } : { id, name };
79
+ }
80
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/agent/domain/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomInt } from 'node:crypto';\nimport { UnrecoverableError } from '#src/shared/domain/errors';\nimport type { RunOptions } from './agent.ts';\nimport type { Session } from '#src/shared/domain/session';\nimport { runContextOf } from './runContext.ts';\n\n// Short, plain and inoffensive in any pairing, so an id reads like a name.\n// prettier-ignore\nconst adjectives = [\n\t'able', 'agile', 'amber', 'ample', 'azure', 'bold', 'brave', 'breezy', 'bright', 'brisk',\n\t'calm', 'candid', 'clever', 'cosmic', 'cozy', 'crisp', 'curious', 'daring', 'dawn', 'deft',\n\t'eager', 'early', 'easy', 'electric', 'epic', 'fair', 'fancy', 'fast', 'fearless', 'fine',\n\t'fluent', 'fresh', 'friendly', 'frosty', 'gentle', 'giant', 'glad', 'golden', 'grand',\n\t'green', 'happy', 'hardy', 'hearty', 'honest', 'humble', 'jolly', 'keen', 'kind', 'lively',\n\t'loyal', 'lucid', 'lucky', 'lunar', 'mellow', 'merry', 'mighty', 'misty', 'modest', 'neat',\n\t'nimble', 'noble', 'patient', 'peppy', 'plucky', 'polar', 'polite', 'proud', 'quick', 'quiet',\n\t'radiant', 'rapid', 'ready', 'regal', 'rosy', 'royal', 'rustic', 'sage', 'sandy', 'serene',\n\t'sharp', 'shiny', 'silent', 'silver', 'simple', 'sleek', 'smart', 'snowy', 'solar', 'solid',\n\t'sonic', 'spry', 'steady', 'stellar', 'sturdy', 'sunny', 'super', 'swift', 'tidy', 'tranquil',\n\t'true', 'trusty', 'upbeat', 'urban', 'valiant', 'vivid', 'warm', 'wise', 'witty', 'young',\n\t'zesty',\n];\n\n// prettier-ignore\nconst animals = [\n\t'alpaca', 'badger', 'beaver', 'bison', 'bobcat', 'buffalo', 'camel', 'caribou', 'cheetah',\n\t'condor', 'cougar', 'coyote', 'crane', 'cricket', 'dingo', 'dolphin', 'dove', 'eagle',\n\t'egret', 'elk', 'falcon', 'ferret', 'finch', 'flamingo', 'fox', 'gazelle', 'gecko', 'gibbon',\n\t'giraffe', 'goose', 'gopher', 'gorilla', 'grouse', 'gull', 'hare', 'hawk', 'hedgehog',\n\t'heron', 'hippo', 'ibex', 'ibis', 'iguana', 'impala', 'jackal', 'jaguar', 'jay', 'kestrel',\n\t'kiwi', 'koala', 'lark', 'lemur', 'leopard', 'lion', 'llama', 'lynx', 'macaw', 'magpie',\n\t'manatee', 'marmot', 'marten', 'meerkat', 'mink', 'moose', 'narwhal', 'newt', 'ocelot',\n\t'orca', 'oriole', 'osprey', 'otter', 'owl', 'panda', 'panther', 'parrot', 'pelican',\n\t'penguin', 'puffin', 'puma', 'quail', 'rabbit', 'raccoon', 'raven', 'reindeer', 'robin',\n\t'salmon', 'seal', 'sparrow', 'squirrel', 'stork', 'swallow', 'swan', 'tapir', 'tiger',\n\t'toucan', 'trout', 'turtle', 'walrus', 'weasel', 'whale', 'wolf', 'wombat', 'wren', 'yak',\n\t'zebra',\n];\n\nfunction pick(words: readonly string[]): string {\n\treturn words[randomInt(words.length)] ?? '';\n}\n\n/**\n * A session of its own, for an agent the consumer gave none: its id, such as `smart-hawk-4821`,\n * is easier to read and say than a UUID, and unlikely to repeat in one workspace's history.\n */\nexport function newSession(): Session {\n\treturn { id: `${pick(adjectives)}-${pick(animals)}-${String(randomInt(1000, 10000))}` };\n}\n\n/**\n * The session a run belongs to: the outer run's, for an agent another agent started, or the one\n * its options name. Absent when neither gives one, and the agent uses its own.\n *\n * @throws {UnrecoverableError} when the options name a session that is not an object, has no\n * id, or has a name that is not text.\n */\nexport function sessionOf(options: RunOptions): Session | undefined {\n\tconst inherited = runContextOf(options)?.session;\n\tif (inherited) return inherited;\n\t// Read without trusting its type, as a JavaScript consumer can pass anything.\n\tconst { session } = options as { session?: unknown };\n\tif (session === undefined) return undefined;\n\tif (typeof session !== 'object' || session === null) {\n\t\tthrow new UnrecoverableError('The run was given a session that is not an object', {\n\t\t\tcause: 'RunOptions.session, when given, is { id, name? }.',\n\t\t});\n\t}\n\tconst { id, name } = session as { id?: unknown; name?: unknown };\n\tif (typeof id !== 'string' || id.trim() === '') {\n\t\tthrow new UnrecoverableError('The run was given a session without an id', {\n\t\t\tcause: 'RunOptions.session needs an id that is not blank.',\n\t\t});\n\t}\n\tif (name !== undefined && typeof name !== 'string') {\n\t\tthrow new UnrecoverableError('The run was given a session whose name is not text', {\n\t\t\tcause: 'RunOptions.session.name, when given, is a string.',\n\t\t});\n\t}\n\t// A copy, so a consumer changing its object later changes nothing recorded. A blank name is\n\t// none: a host shows the id instead.\n\treturn name === undefined || name.trim() === '' ? { id } : { id, name };\n}\n"]}
@@ -8,15 +8,19 @@ export declare class ClaudeAgent implements Agent {
8
8
  private model;
9
9
  private autoApprove;
10
10
  private reasoningEffort;
11
- private sessionId?;
11
+ private providerSessionId?;
12
+ private readonly session;
12
13
  private logger;
14
+ private readonly runs;
13
15
  constructor({ model, autoApprove, reasoningEffort, logger, }: {
14
16
  model: string;
15
17
  autoApprove?: boolean;
16
18
  reasoningEffort?: string;
17
19
  logger: ILogger;
18
20
  });
19
- run(prompt: string, { signal, onProgress: callback }: RunOptions): Promise<AgentResponse>;
21
+ /** @throws {RunInProgressError} when another run on it is still working. */
22
+ run(prompt: string, options: RunOptions): Promise<AgentResponse>;
23
+ private runAlone;
20
24
  private parseResponse;
21
25
  private handleSystemMessage;
22
26
  private handleAssistantMessage;
@@ -2,6 +2,8 @@ import { query } from '@anthropic-ai/claude-agent-sdk';
2
2
  import { ignoreProgress, } from '#src/agent/domain/agent';
3
3
  import { InvalidAgentConfigError, RecoverableError, UnrecoverableError, withSpentTokens, } from '#src/shared/domain/errors';
4
4
  import { classifiedProviderStream, classifyHostFailure, classifyLocalFailure, classifyProviderFailure, treatErrors, } from '#src/shared/domain/providerFailure';
5
+ import { OneRunAtATime } from '#src/agent/domain/oneRunAtATime';
6
+ import { newSession, sessionOf } from '#src/agent/domain/session';
5
7
  import { isOneOf } from '#src/shared/domain/isOneOf';
6
8
  import { claudeModelIds } from '#src/llm/infrastructure/claudeModelIds';
7
9
  // The SDK types `model` as a plain string, so this list is maintained by hand. Each is sent as
@@ -118,8 +120,12 @@ export class ClaudeAgent {
118
120
  model;
119
121
  autoApprove;
120
122
  reasoningEffort;
121
- sessionId;
123
+ // The SDK's own session, which its runs resume; not the consumer's `Session`.
124
+ providerSessionId;
125
+ session = newSession();
122
126
  logger;
127
+ // Its session goes on from one run to the next, so two at once would fork it.
128
+ runs = new OneRunAtATime();
123
129
  // `model` and `reasoningEffort` are untyped on purpose: this adapter is the one that knows
124
130
  // what Claude supports, so it validates them instead of trusting the caller.
125
131
  constructor({ model, autoApprove = false, reasoningEffort = 'high', logger, }) {
@@ -134,7 +140,13 @@ export class ClaudeAgent {
134
140
  this.reasoningEffort = reasoningEffort;
135
141
  this.logger = logger;
136
142
  }
137
- async run(prompt, { signal, onProgress: callback = ignoreProgress }) {
143
+ /** @throws {RunInProgressError} when another run on it is still working. */
144
+ run(prompt, options) {
145
+ return this.runs.run(() => this.runAlone(prompt, options));
146
+ }
147
+ async runAlone(prompt, options) {
148
+ const { signal, onProgress: callback = ignoreProgress } = options;
149
+ const session = sessionOf(options) ?? this.session;
138
150
  signal.throwIfAborted();
139
151
  const start = Date.now();
140
152
  let stream;
@@ -146,7 +158,7 @@ export class ClaudeAgent {
146
158
  model: claudeModelIds[this.model],
147
159
  maxTurns: 3,
148
160
  cwd: process.cwd(),
149
- resume: this.sessionId,
161
+ resume: this.providerSessionId,
150
162
  ...(this.autoApprove
151
163
  ? {
152
164
  permissionMode: 'bypassPermissions',
@@ -164,7 +176,10 @@ export class ClaudeAgent {
164
176
  };
165
177
  signal.addEventListener('abort', closeStream, { once: true });
166
178
  try {
167
- return await this.parseResponse(stream, signal, callback, start);
179
+ return {
180
+ ...(await this.parseResponse(stream, signal, callback, start)),
181
+ session: { ...session },
182
+ };
168
183
  }
169
184
  finally {
170
185
  signal.removeEventListener('abort', closeStream);
@@ -180,7 +195,7 @@ export class ClaudeAgent {
180
195
  try {
181
196
  const messages = classifiedProviderStream(stream, 'Claude stream ended unexpectedly');
182
197
  for await (const message of messages) {
183
- this.sessionId ??= message.session_id;
198
+ this.providerSessionId ??= message.session_id;
184
199
  try {
185
200
  switch (message.type) {
186
201
  case 'assistant':
@@ -1 +1 @@
1
- {"version":3,"file":"claudeAgent.js","sourceRoot":"","sources":["../../../../../src/engines/claude/infrastructure/model/claudeAgent.ts"],"names":[],"mappings":"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","sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport type {\n\tNonNullableUsage,\n\tEffortLevel,\n\tQuery,\n\tSDKAssistantMessage,\n\tSDKMessage,\n\tSDKResultSuccess,\n\tSDKUserMessage,\n} from '@anthropic-ai/claude-agent-sdk';\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\tclassifiedProviderStream,\n\tclassifyHostFailure,\n\tclassifyLocalFailure,\n\tclassifyProviderFailure,\n\ttreatErrors,\n} from '#src/shared/domain/providerFailure';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport type { Tokens } from '#src/shared/domain/tokens';\nimport { isOneOf } from '#src/shared/domain/isOneOf';\nimport { claudeModelIds } from '#src/llm/infrastructure/claudeModelIds';\n\n// The SDK types `model` as a plain string, so this list is maintained by hand. Each is sent as\n// the ID `claudeModelIds` pins, not as the alias, which the Agent SDK would resolve its own way.\nexport const claudeModels = [\n\t'haiku',\n\t'sonnet',\n\t'opus',\n\t'fable',\n] as const satisfies readonly (keyof typeof claudeModelIds)[];\nexport type ClaudeModel = (typeof claudeModels)[number];\n\nexport const claudeReasoningEfforts = [\n\t'low',\n\t'medium',\n\t'high',\n\t'xhigh',\n\t'max',\n] as const satisfies readonly EffortLevel[];\nexport type ClaudeReasoningEffort = (typeof claudeReasoningEfforts)[number];\n\ntype SDKSystemMessage = Extract<SDKMessage, { type: 'system' }>;\n\ninterface PendingTool {\n\tname: string;\n\tinput: Record<string, unknown>;\n\tserver?: string;\n}\n\ninterface ToolResultBlock {\n\ttype: string;\n\ttool_use_id: string;\n\tis_error?: boolean;\n\tcontent?: unknown;\n}\n\n// Claude reports its cache counters apart from input_tokens already.\nfunction toTokens(usage: NonNullableUsage): Tokens {\n\treturn {\n\t\tinputTokens: usage.input_tokens,\n\t\treadCacheTokens: usage.cache_read_input_tokens,\n\t\twrittenCacheTokens: usage.cache_creation_input_tokens,\n\t\toutputTokens: usage.output_tokens,\n\t};\n}\n\nfunction emitProgress(callback: Callback, event: ProgressEvent): void {\n\ttry {\n\t\tcallback(event);\n\t} catch (error) {\n\t\tthrow classifyHostFailure(error, 'Claude progress callback failed');\n\t}\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n\nfunction stringValue(value: unknown): string | undefined {\n\treturn typeof value === 'string' ? value : undefined;\n}\n\nfunction toolResultBlock(value: unknown): ToolResultBlock | undefined {\n\tconst block = asRecord(value);\n\tif (!block || typeof block.type !== 'string' || typeof block.tool_use_id !== 'string') {\n\t\treturn undefined;\n\t}\n\n\treturn block as unknown as ToolResultBlock;\n}\n\nfunction toolResultId(value: unknown): string | undefined {\n\treturn toolResultBlock(value)?.tool_use_id;\n}\n\nfunction fileChange(\n\tname: 'Edit' | 'Write',\n\ttool: PendingTool,\n\toutput: unknown,\n): ProgressEvent | undefined {\n\tconst inputPath = stringValue(tool.input.file_path);\n\tconst outputPath = stringValue(asRecord(output)?.filePath);\n\tconst path = outputPath ?? inputPath;\n\tif (!path) return undefined;\n\n\tconst kind =\n\t\tname === 'Write' && stringValue(asRecord(output)?.type) === 'create' ? 'add' : 'update';\n\treturn { type: 'fileChange', changes: [{ path, kind }] };\n}\n\nfunction todoList(tool: PendingTool): ProgressEvent | undefined {\n\tif (!Array.isArray(tool.input.todos)) return undefined;\n\n\tconst items = tool.input.todos.flatMap(todo => {\n\t\tconst item = asRecord(todo);\n\t\tconst text = stringValue(item?.content);\n\t\tconst status = stringValue(item?.status);\n\t\treturn text && status ? [{ text, completed: status === 'completed' }] : [];\n\t});\n\n\treturn { type: 'todoList', items };\n}\n\nfunction mcpTool(tool: PendingTool, result: ToolResultBlock): ProgressEvent | undefined {\n\tconst server = tool.server;\n\tconst toolName = tool.name.startsWith('mcp__')\n\t\t? tool.name.slice('mcp__'.length).split('__').slice(1).join('__')\n\t\t: tool.name;\n\tif (!server || !toolName) return undefined;\n\n\treturn {\n\t\ttype: 'mcpTool',\n\t\tserver,\n\t\ttool: toolName,\n\t\tstatus: result.is_error ? 'failed' : 'completed',\n\t};\n}\n\n// Tools without narration (Read, Grep, Task, ...) are a presentation choice, not an unknown:\n// the tool set is open-ended, so warning here would only produce noise.\nfunction describeCompletedTool(\n\ttool: PendingTool,\n\tresult: ToolResultBlock,\n\toutput: unknown,\n): ProgressEvent | undefined {\n\tif (tool.name === 'Bash') {\n\t\tconst exitCode = asRecord(output)?.exitCode ?? asRecord(output)?.exit_code;\n\t\treturn {\n\t\t\ttype: 'command',\n\t\t\tcommand: stringValue(tool.input.command) ?? '',\n\t\t\t...(typeof exitCode === 'number' ? { exitCode } : {}),\n\t\t};\n\t}\n\n\tif (tool.name === 'WebSearch') {\n\t\tconst query = stringValue(tool.input.query);\n\t\treturn query ? { type: 'search', query } : undefined;\n\t}\n\n\tif (tool.name === 'Edit' || tool.name === 'Write') {\n\t\treturn result.is_error ? undefined : fileChange(tool.name, tool, output);\n\t}\n\n\tif (tool.name === 'TodoWrite') {\n\t\treturn result.is_error ? undefined : todoList(tool);\n\t}\n\n\tif (tool.name.startsWith('mcp__') || tool.server) {\n\t\treturn mcpTool(tool, result);\n\t}\n\n\treturn undefined;\n}\n\nexport class ClaudeAgent implements Agent {\n\tprivate model: ClaudeModel;\n\tprivate autoApprove: boolean;\n\tprivate reasoningEffort: ClaudeReasoningEffort;\n\tprivate sessionId?: string;\n\tprivate logger: ILogger;\n\n\t// `model` and `reasoningEffort` are untyped on purpose: this adapter is the one that knows\n\t// what Claude supports, so it validates them instead of trusting the caller.\n\tconstructor({\n\t\tmodel,\n\t\tautoApprove = false,\n\t\treasoningEffort = 'high',\n\t\tlogger,\n\t}: {\n\t\tmodel: string;\n\t\tautoApprove?: boolean;\n\t\treasoningEffort?: string;\n\t\tlogger: ILogger;\n\t}) {\n\t\tif (!isOneOf(claudeModels, model)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${model}\" is not a Claude model; expected one of: ${claudeModels.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (!isOneOf(claudeReasoningEfforts, reasoningEffort)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${reasoningEffort}\" is not a Claude reasoning effort; expected one of: ${claudeReasoningEfforts.join(', ')}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.model = model;\n\t\tthis.autoApprove = autoApprove;\n\t\tthis.reasoningEffort = reasoningEffort;\n\t\tthis.logger = logger;\n\t}\n\n\tasync run(\n\t\tprompt: string,\n\t\t{ signal, onProgress: callback = ignoreProgress }: RunOptions,\n\t): Promise<AgentResponse> {\n\t\tsignal.throwIfAborted();\n\t\tconst start = Date.now();\n\n\t\tlet stream: Query;\n\n\t\ttry {\n\t\t\tstream = query({\n\t\t\t\tprompt,\n\t\t\t\toptions: {\n\t\t\t\t\teffort: this.reasoningEffort,\n\t\t\t\t\tmodel: claudeModelIds[this.model],\n\t\t\t\t\tmaxTurns: 3,\n\t\t\t\t\tcwd: process.cwd(),\n\t\t\t\t\tresume: this.sessionId,\n\t\t\t\t\t...(this.autoApprove\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpermissionMode: 'bypassPermissions' as const,\n\t\t\t\t\t\t\t\tallowDangerouslySkipPermissions: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow classifyProviderFailure(error, 'Claude refused the request');\n\t\t}\n\n\t\tconst closeStream = () => {\n\t\t\tstream.close();\n\t\t};\n\t\tsignal.addEventListener('abort', closeStream, { once: true });\n\n\t\ttry {\n\t\t\treturn await this.parseResponse(stream, signal, callback, start);\n\t\t} finally {\n\t\t\tsignal.removeEventListener('abort', closeStream);\n\t\t}\n\t}\n\n\tprivate async parseResponse(\n\t\tstream: Query,\n\t\tsignal: AbortSignal,\n\t\tcallback: Callback,\n\t\tstart: number,\n\t): Promise<AgentResponse> {\n\t\tconst lines: string[] = [];\n\t\tlet resultMessage: SDKResultSuccess | undefined;\n\t\tconst pendingTools = new Map<string, PendingTool>();\n\n\t\t// Once Claude sent an assistant message, the provider answered: a failure after that\n\t\t// without usage leaves the run's count unknown, unlike one that never got an answer.\n\t\tlet answered = false;\n\n\t\ttry {\n\t\t\tconst messages = classifiedProviderStream(stream, 'Claude stream ended unexpectedly');\n\n\t\t\tfor await (const message of messages) {\n\t\t\t\tthis.sessionId ??= message.session_id;\n\n\t\t\t\ttry {\n\t\t\t\t\tswitch (message.type) {\n\t\t\t\t\t\tcase 'assistant':\n\t\t\t\t\t\t\tanswered = true;\n\t\t\t\t\t\t\tthis.handleAssistantMessage(message, pendingTools, callback);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'user':\n\t\t\t\t\t\t\tthis.handleUserMessage(message, pendingTools, callback);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'result':\n\t\t\t\t\t\t\tif (message.subtype === 'success') {\n\t\t\t\t\t\t\t\tlines.push(message.result);\n\t\t\t\t\t\t\t\tresultMessage = message;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow new RecoverableError('Claude sdk error', {\n\t\t\t\t\t\t\t\t\tcause: [message.stop_reason, message.terminal_reason, ...message.errors].join(\n\t\t\t\t\t\t\t\t\t\t',',\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t// A failed result still reports what the turn spent.\n\t\t\t\t\t\t\t\t\ttokens: toTokens(message.usage),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'system':\n\t\t\t\t\t\t\tthis.handleSystemMessage(message);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t// Known messages with nothing to narrate or report.\n\t\t\t\t\t\tcase 'stream_event':\n\t\t\t\t\t\tcase 'tool_progress':\n\t\t\t\t\t\tcase 'tool_use_summary':\n\t\t\t\t\t\tcase 'auth_status':\n\t\t\t\t\t\tcase 'rate_limit_event':\n\t\t\t\t\t\tcase 'prompt_suggestion':\n\t\t\t\t\t\tcase 'conversation_reset':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t// `never` breaks the build when an SDK upgrade adds a message type; the\n\t\t\t\t\t\t\t// warning covers a CLI binary that is newer than the types.\n\t\t\t\t\t\t\tconst unknownMessage: never = message;\n\t\t\t\t\t\t\tthis.warn(unknownMessage, 'Unknown Claude message type');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow classifyLocalFailure(error, 'Claude failed while mapping progress');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsignal.throwIfAborted();\n\n\t\t\tif (!resultMessage) {\n\t\t\t\t// The turn's work stands; only its accounting is missing.\n\t\t\t\tthis.warn('Claude ended a turn without a result message; its usage is unknown');\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// A failed result reports the turn's usage itself.\n\t\t\tconst reported =\n\t\t\t\t(error instanceof RecoverableError || error instanceof UnrecoverableError) &&\n\t\t\t\terror.tokens !== undefined;\n\t\t\tthrow answered && !reported ? withSpentTokens(error, undefined, true) : error;\n\t\t}\n\n\t\treturn {\n\t\t\tresponse: lines.join('\\n'),\n\t\t\ttokens: resultMessage && toTokens(resultMessage.usage),\n\t\t\t// Measured here, like the other engines, so it exists even without a result message.\n\t\t\tduration: (Date.now() - start) / 1000,\n\t\t};\n\t}\n\n\tprivate handleSystemMessage(message: SDKSystemMessage): void {\n\t\tswitch (message.subtype) {\n\t\t\t// Failures the SDK handled without failing the turn: only a warning makes them visible.\n\t\t\tcase 'api_retry':\n\t\t\tcase 'model_refusal_fallback':\n\t\t\tcase 'model_refusal_no_fallback':\n\t\t\tcase 'permission_denied':\n\t\t\tcase 'mirror_error':\n\t\t\t\tthis.warn(message, 'Claude reported a failure without failing the turn');\n\t\t\t\treturn;\n\t\t\t// Known messages with nothing to narrate or report.\n\t\t\tcase 'init':\n\t\t\tcase 'compact_boundary':\n\t\t\tcase 'status':\n\t\t\tcase 'control_request_progress':\n\t\t\tcase 'local_command_output':\n\t\t\tcase 'hook_started':\n\t\t\tcase 'hook_progress':\n\t\t\tcase 'hook_response':\n\t\t\tcase 'plugin_install':\n\t\t\tcase 'task_notification':\n\t\t\tcase 'task_started':\n\t\t\tcase 'task_updated':\n\t\t\tcase 'task_progress':\n\t\t\tcase 'background_tasks_changed':\n\t\t\tcase 'thinking_tokens':\n\t\t\tcase 'session_state_changed':\n\t\t\tcase 'worker_shutting_down':\n\t\t\tcase 'commands_changed':\n\t\t\tcase 'notification':\n\t\t\tcase 'files_persisted':\n\t\t\tcase 'memory_recall':\n\t\t\tcase 'elicitation_complete':\n\t\t\tcase 'informational':\n\t\t\t\treturn;\n\t\t\tdefault: {\n\t\t\t\tconst unknownMessage: never = message;\n\t\t\t\tthis.warn(unknownMessage, 'Unknown Claude system message');\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleAssistantMessage(\n\t\tmessage: SDKAssistantMessage,\n\t\tpendingTools: Map<string, PendingTool>,\n\t\tcallback: Callback,\n\t): void {\n\t\tfor (const block of message.message.content) {\n\t\t\tswitch (block.type) {\n\t\t\t\tcase 'text':\n\t\t\t\t\temitProgress(callback, { type: 'agentMessage', message: block.text });\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'thinking':\n\t\t\t\t\temitProgress(callback, { type: 'reasoning', message: block.thinking });\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'tool_use':\n\t\t\t\tcase 'server_tool_use':\n\t\t\t\tcase 'mcp_tool_use': {\n\t\t\t\t\tconst input = asRecord(block.input);\n\t\t\t\t\tif (input) {\n\t\t\t\t\t\tpendingTools.set(block.id, {\n\t\t\t\t\t\t\tname: block.name === 'web_search' ? 'WebSearch' : block.name,\n\t\t\t\t\t\t\tinput,\n\t\t\t\t\t\t\t...('server_name' in block && typeof block.server_name === 'string'\n\t\t\t\t\t\t\t\t? { server: block.server_name }\n\t\t\t\t\t\t\t\t: parseMcpServer(block.name)),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'web_search_tool_result':\n\t\t\t\tcase 'web_fetch_tool_result':\n\t\t\t\tcase 'advisor_tool_result':\n\t\t\t\tcase 'code_execution_tool_result':\n\t\t\t\tcase 'bash_code_execution_tool_result':\n\t\t\t\tcase 'text_editor_code_execution_tool_result':\n\t\t\t\tcase 'tool_search_tool_result':\n\t\t\t\tcase 'mcp_tool_result':\n\t\t\t\t\tthis.handleCompletedTool(block, pendingTools, callback);\n\t\t\t\t\tbreak;\n\t\t\t\t// Known blocks with nothing to narrate.\n\t\t\t\tcase 'redacted_thinking':\n\t\t\t\tcase 'container_upload':\n\t\t\t\tcase 'compaction':\n\t\t\t\tcase 'fallback':\n\t\t\t\t\tbreak;\n\t\t\t\tdefault: {\n\t\t\t\t\tconst unknownBlock: never = block;\n\t\t\t\t\tthis.warn(unknownBlock, 'Unknown Claude content block');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleUserMessage(\n\t\tmessage: SDKUserMessage,\n\t\tpendingTools: Map<string, PendingTool>,\n\t\tcallback: Callback,\n\t): void {\n\t\tif (!Array.isArray(message.message.content)) return;\n\n\t\tfor (const block of message.message.content) {\n\t\t\tthis.handleCompletedTool(block, pendingTools, callback, message.tool_use_result);\n\t\t}\n\t}\n\n\tprivate handleCompletedTool(\n\t\tblock: unknown,\n\t\tpendingTools: Map<string, PendingTool>,\n\t\tcallback: Callback,\n\t\toutput?: unknown,\n\t): void {\n\t\tconst id = toolResultId(block);\n\t\tif (!id) return;\n\n\t\tconst tool = pendingTools.get(id);\n\t\tif (!tool) return;\n\n\t\tpendingTools.delete(id);\n\t\tconst result = toolResultBlock(block);\n\t\tif (!result) return;\n\n\t\tconst description = describeCompletedTool(tool, result, output ?? result.content);\n\t\tif (description) emitProgress(callback, description);\n\t}\n\n\tprivate warn(...args: unknown[]): void {\n\t\ttreatErrors(\n\t\t\t() => {\n\t\t\t\tthis.logger.warn(...args);\n\t\t\t},\n\t\t\tclassifyHostFailure,\n\t\t\t'Claude logger failed while reporting progress',\n\t\t);\n\t}\n}\n\nfunction parseMcpServer(name: string): { server: string } | undefined {\n\tif (!name.startsWith('mcp__')) return undefined;\n\n\tconst server = name.slice('mcp__'.length).split('__')[0];\n\treturn server ? { server } : undefined;\n}\n"]}
1
+ {"version":3,"file":"claudeAgent.js","sourceRoot":"","sources":["../../../../../src/engines/claude/infrastructure/model/claudeAgent.ts"],"names":[],"mappings":"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","sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport type {\n\tNonNullableUsage,\n\tEffortLevel,\n\tQuery,\n\tSDKAssistantMessage,\n\tSDKMessage,\n\tSDKResultSuccess,\n\tSDKUserMessage,\n} from '@anthropic-ai/claude-agent-sdk';\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\tclassifiedProviderStream,\n\tclassifyHostFailure,\n\tclassifyLocalFailure,\n\tclassifyProviderFailure,\n\ttreatErrors,\n} from '#src/shared/domain/providerFailure';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport type { Tokens } from '#src/shared/domain/tokens';\nimport { OneRunAtATime } from '#src/agent/domain/oneRunAtATime';\nimport { newSession, sessionOf } from '#src/agent/domain/session';\nimport { isOneOf } from '#src/shared/domain/isOneOf';\nimport { claudeModelIds } from '#src/llm/infrastructure/claudeModelIds';\n\n// The SDK types `model` as a plain string, so this list is maintained by hand. Each is sent as\n// the ID `claudeModelIds` pins, not as the alias, which the Agent SDK would resolve its own way.\nexport const claudeModels = [\n\t'haiku',\n\t'sonnet',\n\t'opus',\n\t'fable',\n] as const satisfies readonly (keyof typeof claudeModelIds)[];\nexport type ClaudeModel = (typeof claudeModels)[number];\n\nexport const claudeReasoningEfforts = [\n\t'low',\n\t'medium',\n\t'high',\n\t'xhigh',\n\t'max',\n] as const satisfies readonly EffortLevel[];\nexport type ClaudeReasoningEffort = (typeof claudeReasoningEfforts)[number];\n\ntype SDKSystemMessage = Extract<SDKMessage, { type: 'system' }>;\n\ninterface PendingTool {\n\tname: string;\n\tinput: Record<string, unknown>;\n\tserver?: string;\n}\n\ninterface ToolResultBlock {\n\ttype: string;\n\ttool_use_id: string;\n\tis_error?: boolean;\n\tcontent?: unknown;\n}\n\n// Claude reports its cache counters apart from input_tokens already.\nfunction toTokens(usage: NonNullableUsage): Tokens {\n\treturn {\n\t\tinputTokens: usage.input_tokens,\n\t\treadCacheTokens: usage.cache_read_input_tokens,\n\t\twrittenCacheTokens: usage.cache_creation_input_tokens,\n\t\toutputTokens: usage.output_tokens,\n\t};\n}\n\nfunction emitProgress(callback: Callback, event: ProgressEvent): void {\n\ttry {\n\t\tcallback(event);\n\t} catch (error) {\n\t\tthrow classifyHostFailure(error, 'Claude progress callback failed');\n\t}\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n\nfunction stringValue(value: unknown): string | undefined {\n\treturn typeof value === 'string' ? value : undefined;\n}\n\nfunction toolResultBlock(value: unknown): ToolResultBlock | undefined {\n\tconst block = asRecord(value);\n\tif (!block || typeof block.type !== 'string' || typeof block.tool_use_id !== 'string') {\n\t\treturn undefined;\n\t}\n\n\treturn block as unknown as ToolResultBlock;\n}\n\nfunction toolResultId(value: unknown): string | undefined {\n\treturn toolResultBlock(value)?.tool_use_id;\n}\n\nfunction fileChange(\n\tname: 'Edit' | 'Write',\n\ttool: PendingTool,\n\toutput: unknown,\n): ProgressEvent | undefined {\n\tconst inputPath = stringValue(tool.input.file_path);\n\tconst outputPath = stringValue(asRecord(output)?.filePath);\n\tconst path = outputPath ?? inputPath;\n\tif (!path) return undefined;\n\n\tconst kind =\n\t\tname === 'Write' && stringValue(asRecord(output)?.type) === 'create' ? 'add' : 'update';\n\treturn { type: 'fileChange', changes: [{ path, kind }] };\n}\n\nfunction todoList(tool: PendingTool): ProgressEvent | undefined {\n\tif (!Array.isArray(tool.input.todos)) return undefined;\n\n\tconst items = tool.input.todos.flatMap(todo => {\n\t\tconst item = asRecord(todo);\n\t\tconst text = stringValue(item?.content);\n\t\tconst status = stringValue(item?.status);\n\t\treturn text && status ? [{ text, completed: status === 'completed' }] : [];\n\t});\n\n\treturn { type: 'todoList', items };\n}\n\nfunction mcpTool(tool: PendingTool, result: ToolResultBlock): ProgressEvent | undefined {\n\tconst server = tool.server;\n\tconst toolName = tool.name.startsWith('mcp__')\n\t\t? tool.name.slice('mcp__'.length).split('__').slice(1).join('__')\n\t\t: tool.name;\n\tif (!server || !toolName) return undefined;\n\n\treturn {\n\t\ttype: 'mcpTool',\n\t\tserver,\n\t\ttool: toolName,\n\t\tstatus: result.is_error ? 'failed' : 'completed',\n\t};\n}\n\n// Tools without narration (Read, Grep, Task, ...) are a presentation choice, not an unknown:\n// the tool set is open-ended, so warning here would only produce noise.\nfunction describeCompletedTool(\n\ttool: PendingTool,\n\tresult: ToolResultBlock,\n\toutput: unknown,\n): ProgressEvent | undefined {\n\tif (tool.name === 'Bash') {\n\t\tconst exitCode = asRecord(output)?.exitCode ?? asRecord(output)?.exit_code;\n\t\treturn {\n\t\t\ttype: 'command',\n\t\t\tcommand: stringValue(tool.input.command) ?? '',\n\t\t\t...(typeof exitCode === 'number' ? { exitCode } : {}),\n\t\t};\n\t}\n\n\tif (tool.name === 'WebSearch') {\n\t\tconst query = stringValue(tool.input.query);\n\t\treturn query ? { type: 'search', query } : undefined;\n\t}\n\n\tif (tool.name === 'Edit' || tool.name === 'Write') {\n\t\treturn result.is_error ? undefined : fileChange(tool.name, tool, output);\n\t}\n\n\tif (tool.name === 'TodoWrite') {\n\t\treturn result.is_error ? undefined : todoList(tool);\n\t}\n\n\tif (tool.name.startsWith('mcp__') || tool.server) {\n\t\treturn mcpTool(tool, result);\n\t}\n\n\treturn undefined;\n}\n\nexport class ClaudeAgent implements Agent {\n\tprivate model: ClaudeModel;\n\tprivate autoApprove: boolean;\n\tprivate reasoningEffort: ClaudeReasoningEffort;\n\t// The SDK's own session, which its runs resume; not the consumer's `Session`.\n\tprivate providerSessionId?: string;\n\tprivate readonly session = newSession();\n\tprivate logger: ILogger;\n\t// Its session goes on from one run to the next, so two at once would fork it.\n\tprivate readonly runs = new OneRunAtATime();\n\n\t// `model` and `reasoningEffort` are untyped on purpose: this adapter is the one that knows\n\t// what Claude supports, so it validates them instead of trusting the caller.\n\tconstructor({\n\t\tmodel,\n\t\tautoApprove = false,\n\t\treasoningEffort = 'high',\n\t\tlogger,\n\t}: {\n\t\tmodel: string;\n\t\tautoApprove?: boolean;\n\t\treasoningEffort?: string;\n\t\tlogger: ILogger;\n\t}) {\n\t\tif (!isOneOf(claudeModels, model)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${model}\" is not a Claude model; expected one of: ${claudeModels.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (!isOneOf(claudeReasoningEfforts, reasoningEffort)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${reasoningEffort}\" is not a Claude reasoning effort; expected one of: ${claudeReasoningEfforts.join(', ')}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.model = model;\n\t\tthis.autoApprove = autoApprove;\n\t\tthis.reasoningEffort = reasoningEffort;\n\t\tthis.logger = logger;\n\t}\n\n\t/** @throws {RunInProgressError} when another run on it is still working. */\n\trun(prompt: string, options: RunOptions): Promise<AgentResponse> {\n\t\treturn this.runs.run(() => this.runAlone(prompt, options));\n\t}\n\n\tprivate async runAlone(prompt: string, options: RunOptions): Promise<AgentResponse> {\n\t\tconst { signal, onProgress: callback = ignoreProgress } = options;\n\t\tconst session = sessionOf(options) ?? this.session;\n\t\tsignal.throwIfAborted();\n\t\tconst start = Date.now();\n\n\t\tlet stream: Query;\n\n\t\ttry {\n\t\t\tstream = query({\n\t\t\t\tprompt,\n\t\t\t\toptions: {\n\t\t\t\t\teffort: this.reasoningEffort,\n\t\t\t\t\tmodel: claudeModelIds[this.model],\n\t\t\t\t\tmaxTurns: 3,\n\t\t\t\t\tcwd: process.cwd(),\n\t\t\t\t\tresume: this.providerSessionId,\n\t\t\t\t\t...(this.autoApprove\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpermissionMode: 'bypassPermissions' as const,\n\t\t\t\t\t\t\t\tallowDangerouslySkipPermissions: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow classifyProviderFailure(error, 'Claude refused the request');\n\t\t}\n\n\t\tconst closeStream = () => {\n\t\t\tstream.close();\n\t\t};\n\t\tsignal.addEventListener('abort', closeStream, { once: true });\n\n\t\ttry {\n\t\t\treturn {\n\t\t\t\t...(await this.parseResponse(stream, signal, callback, start)),\n\t\t\t\tsession: { ...session },\n\t\t\t};\n\t\t} finally {\n\t\t\tsignal.removeEventListener('abort', closeStream);\n\t\t}\n\t}\n\n\tprivate async parseResponse(\n\t\tstream: Query,\n\t\tsignal: AbortSignal,\n\t\tcallback: Callback,\n\t\tstart: number,\n\t): Promise<AgentResponse> {\n\t\tconst lines: string[] = [];\n\t\tlet resultMessage: SDKResultSuccess | undefined;\n\t\tconst pendingTools = new Map<string, PendingTool>();\n\n\t\t// Once Claude sent an assistant message, the provider answered: a failure after that\n\t\t// without usage leaves the run's count unknown, unlike one that never got an answer.\n\t\tlet answered = false;\n\n\t\ttry {\n\t\t\tconst messages = classifiedProviderStream(stream, 'Claude stream ended unexpectedly');\n\n\t\t\tfor await (const message of messages) {\n\t\t\t\tthis.providerSessionId ??= message.session_id;\n\n\t\t\t\ttry {\n\t\t\t\t\tswitch (message.type) {\n\t\t\t\t\t\tcase 'assistant':\n\t\t\t\t\t\t\tanswered = true;\n\t\t\t\t\t\t\tthis.handleAssistantMessage(message, pendingTools, callback);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'user':\n\t\t\t\t\t\t\tthis.handleUserMessage(message, pendingTools, callback);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'result':\n\t\t\t\t\t\t\tif (message.subtype === 'success') {\n\t\t\t\t\t\t\t\tlines.push(message.result);\n\t\t\t\t\t\t\t\tresultMessage = message;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow new RecoverableError('Claude sdk error', {\n\t\t\t\t\t\t\t\t\tcause: [message.stop_reason, message.terminal_reason, ...message.errors].join(\n\t\t\t\t\t\t\t\t\t\t',',\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t// A failed result still reports what the turn spent.\n\t\t\t\t\t\t\t\t\ttokens: toTokens(message.usage),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'system':\n\t\t\t\t\t\t\tthis.handleSystemMessage(message);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t// Known messages with nothing to narrate or report.\n\t\t\t\t\t\tcase 'stream_event':\n\t\t\t\t\t\tcase 'tool_progress':\n\t\t\t\t\t\tcase 'tool_use_summary':\n\t\t\t\t\t\tcase 'auth_status':\n\t\t\t\t\t\tcase 'rate_limit_event':\n\t\t\t\t\t\tcase 'prompt_suggestion':\n\t\t\t\t\t\tcase 'conversation_reset':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t// `never` breaks the build when an SDK upgrade adds a message type; the\n\t\t\t\t\t\t\t// warning covers a CLI binary that is newer than the types.\n\t\t\t\t\t\t\tconst unknownMessage: never = message;\n\t\t\t\t\t\t\tthis.warn(unknownMessage, 'Unknown Claude message type');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow classifyLocalFailure(error, 'Claude failed while mapping progress');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsignal.throwIfAborted();\n\n\t\t\tif (!resultMessage) {\n\t\t\t\t// The turn's work stands; only its accounting is missing.\n\t\t\t\tthis.warn('Claude ended a turn without a result message; its usage is unknown');\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// A failed result reports the turn's usage itself.\n\t\t\tconst reported =\n\t\t\t\t(error instanceof RecoverableError || error instanceof UnrecoverableError) &&\n\t\t\t\terror.tokens !== undefined;\n\t\t\tthrow answered && !reported ? withSpentTokens(error, undefined, true) : error;\n\t\t}\n\n\t\treturn {\n\t\t\tresponse: lines.join('\\n'),\n\t\t\ttokens: resultMessage && toTokens(resultMessage.usage),\n\t\t\t// Measured here, like the other engines, so it exists even without a result message.\n\t\t\tduration: (Date.now() - start) / 1000,\n\t\t};\n\t}\n\n\tprivate handleSystemMessage(message: SDKSystemMessage): void {\n\t\tswitch (message.subtype) {\n\t\t\t// Failures the SDK handled without failing the turn: only a warning makes them visible.\n\t\t\tcase 'api_retry':\n\t\t\tcase 'model_refusal_fallback':\n\t\t\tcase 'model_refusal_no_fallback':\n\t\t\tcase 'permission_denied':\n\t\t\tcase 'mirror_error':\n\t\t\t\tthis.warn(message, 'Claude reported a failure without failing the turn');\n\t\t\t\treturn;\n\t\t\t// Known messages with nothing to narrate or report.\n\t\t\tcase 'init':\n\t\t\tcase 'compact_boundary':\n\t\t\tcase 'status':\n\t\t\tcase 'control_request_progress':\n\t\t\tcase 'local_command_output':\n\t\t\tcase 'hook_started':\n\t\t\tcase 'hook_progress':\n\t\t\tcase 'hook_response':\n\t\t\tcase 'plugin_install':\n\t\t\tcase 'task_notification':\n\t\t\tcase 'task_started':\n\t\t\tcase 'task_updated':\n\t\t\tcase 'task_progress':\n\t\t\tcase 'background_tasks_changed':\n\t\t\tcase 'thinking_tokens':\n\t\t\tcase 'session_state_changed':\n\t\t\tcase 'worker_shutting_down':\n\t\t\tcase 'commands_changed':\n\t\t\tcase 'notification':\n\t\t\tcase 'files_persisted':\n\t\t\tcase 'memory_recall':\n\t\t\tcase 'elicitation_complete':\n\t\t\tcase 'informational':\n\t\t\t\treturn;\n\t\t\tdefault: {\n\t\t\t\tconst unknownMessage: never = message;\n\t\t\t\tthis.warn(unknownMessage, 'Unknown Claude system message');\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleAssistantMessage(\n\t\tmessage: SDKAssistantMessage,\n\t\tpendingTools: Map<string, PendingTool>,\n\t\tcallback: Callback,\n\t): void {\n\t\tfor (const block of message.message.content) {\n\t\t\tswitch (block.type) {\n\t\t\t\tcase 'text':\n\t\t\t\t\temitProgress(callback, { type: 'agentMessage', message: block.text });\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'thinking':\n\t\t\t\t\temitProgress(callback, { type: 'reasoning', message: block.thinking });\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'tool_use':\n\t\t\t\tcase 'server_tool_use':\n\t\t\t\tcase 'mcp_tool_use': {\n\t\t\t\t\tconst input = asRecord(block.input);\n\t\t\t\t\tif (input) {\n\t\t\t\t\t\tpendingTools.set(block.id, {\n\t\t\t\t\t\t\tname: block.name === 'web_search' ? 'WebSearch' : block.name,\n\t\t\t\t\t\t\tinput,\n\t\t\t\t\t\t\t...('server_name' in block && typeof block.server_name === 'string'\n\t\t\t\t\t\t\t\t? { server: block.server_name }\n\t\t\t\t\t\t\t\t: parseMcpServer(block.name)),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'web_search_tool_result':\n\t\t\t\tcase 'web_fetch_tool_result':\n\t\t\t\tcase 'advisor_tool_result':\n\t\t\t\tcase 'code_execution_tool_result':\n\t\t\t\tcase 'bash_code_execution_tool_result':\n\t\t\t\tcase 'text_editor_code_execution_tool_result':\n\t\t\t\tcase 'tool_search_tool_result':\n\t\t\t\tcase 'mcp_tool_result':\n\t\t\t\t\tthis.handleCompletedTool(block, pendingTools, callback);\n\t\t\t\t\tbreak;\n\t\t\t\t// Known blocks with nothing to narrate.\n\t\t\t\tcase 'redacted_thinking':\n\t\t\t\tcase 'container_upload':\n\t\t\t\tcase 'compaction':\n\t\t\t\tcase 'fallback':\n\t\t\t\t\tbreak;\n\t\t\t\tdefault: {\n\t\t\t\t\tconst unknownBlock: never = block;\n\t\t\t\t\tthis.warn(unknownBlock, 'Unknown Claude content block');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleUserMessage(\n\t\tmessage: SDKUserMessage,\n\t\tpendingTools: Map<string, PendingTool>,\n\t\tcallback: Callback,\n\t): void {\n\t\tif (!Array.isArray(message.message.content)) return;\n\n\t\tfor (const block of message.message.content) {\n\t\t\tthis.handleCompletedTool(block, pendingTools, callback, message.tool_use_result);\n\t\t}\n\t}\n\n\tprivate handleCompletedTool(\n\t\tblock: unknown,\n\t\tpendingTools: Map<string, PendingTool>,\n\t\tcallback: Callback,\n\t\toutput?: unknown,\n\t): void {\n\t\tconst id = toolResultId(block);\n\t\tif (!id) return;\n\n\t\tconst tool = pendingTools.get(id);\n\t\tif (!tool) return;\n\n\t\tpendingTools.delete(id);\n\t\tconst result = toolResultBlock(block);\n\t\tif (!result) return;\n\n\t\tconst description = describeCompletedTool(tool, result, output ?? result.content);\n\t\tif (description) emitProgress(callback, description);\n\t}\n\n\tprivate warn(...args: unknown[]): void {\n\t\ttreatErrors(\n\t\t\t() => {\n\t\t\t\tthis.logger.warn(...args);\n\t\t\t},\n\t\t\tclassifyHostFailure,\n\t\t\t'Claude logger failed while reporting progress',\n\t\t);\n\t}\n}\n\nfunction parseMcpServer(name: string): { server: string } | undefined {\n\tif (!name.startsWith('mcp__')) return undefined;\n\n\tconst server = name.slice('mcp__'.length).split('__')[0];\n\treturn server ? { server } : undefined;\n}\n"]}
@@ -7,12 +7,16 @@ export type CodexReasoningEffort = (typeof codexReasoningEfforts)[number];
7
7
  export declare class CodexAgent implements Agent {
8
8
  private thread;
9
9
  private logger;
10
+ private readonly session;
11
+ private readonly runs;
10
12
  constructor({ model, autoApprove, reasoningEffort, logger, }: {
11
13
  model: string;
12
14
  autoApprove?: boolean;
13
15
  reasoningEffort?: string;
14
16
  logger: ILogger;
15
17
  });
16
- run(prompt: string, { signal, onProgress: callback }: RunOptions): Promise<AgentResponse>;
18
+ /** @throws {RunInProgressError} when another run on it is still working. */
19
+ run(prompt: string, options: RunOptions): Promise<AgentResponse>;
20
+ private runAlone;
17
21
  private parseResponse;
18
22
  }
@@ -2,6 +2,8 @@ import { Codex, } from '@openai/codex-sdk';
2
2
  import { ignoreProgress, } from '#src/agent/domain/agent';
3
3
  import { InvalidAgentConfigError, RecoverableError, UnrecoverableError, withSpentTokens, } from '#src/shared/domain/errors';
4
4
  import { classifiedProviderStream, classifyHostFailure, classifyLocalFailure, classifyProviderFailure, describeFailure, treatErrors, } from '#src/shared/domain/providerFailure';
5
+ import { OneRunAtATime } from '#src/agent/domain/oneRunAtATime';
6
+ import { newSession, sessionOf } from '#src/agent/domain/session';
5
7
  import { isOneOf } from '#src/shared/domain/isOneOf';
6
8
  // The SDK types `model` as a plain string, so this list is maintained by hand.
7
9
  export const codexModels = ['gpt-6-astra', 'gpt-5.6-sol', 'gpt-5.6-luna', 'gpt-5.6-terra'];
@@ -66,6 +68,9 @@ function toTokens(usage) {
66
68
  export class CodexAgent {
67
69
  thread;
68
70
  logger;
71
+ session = newSession();
72
+ // Its thread goes on from one run to the next, so two at once would fork it.
73
+ runs = new OneRunAtATime();
69
74
  // `model` and `reasoningEffort` are untyped on purpose: this adapter is the one that knows
70
75
  // what Codex supports, so it validates them instead of trusting the caller.
71
76
  constructor({ model, autoApprove = false, reasoningEffort = 'high', logger, }) {
@@ -100,7 +105,13 @@ export class CodexAgent {
100
105
  }
101
106
  this.logger = logger;
102
107
  }
103
- async run(prompt, { signal, onProgress: callback = ignoreProgress }) {
108
+ /** @throws {RunInProgressError} when another run on it is still working. */
109
+ run(prompt, options) {
110
+ return this.runs.run(() => this.runAlone(prompt, options));
111
+ }
112
+ async runAlone(prompt, options) {
113
+ const { signal, onProgress: callback = ignoreProgress } = options;
114
+ const session = sessionOf(options) ?? this.session;
104
115
  const start = Date.now();
105
116
  let turn;
106
117
  try {
@@ -109,7 +120,7 @@ export class CodexAgent {
109
120
  catch (error) {
110
121
  throw classifyProviderFailure(error, 'Codex refused the request');
111
122
  }
112
- return await this.parseResponse(turn, callback, start);
123
+ return { ...(await this.parseResponse(turn, callback, start)), session: { ...session } };
113
124
  }
114
125
  async parseResponse(turn, callback, start) {
115
126
  const lines = [];
@@ -1 +1 @@
1
- {"version":3,"file":"codexAgent.js","sourceRoot":"","sources":["../../../../../src/engines/codex/infrastructure/model/codexAgent.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAML,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIN,cAAc,GAGd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACN,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACN,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,EACf,WAAW,GACX,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,CAAU,CAAC;AAGpG,gGAAgG;AAChG,iGAAiG;AACjG,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACpC,KAAK;IACL,QAAQ;IACR,MAAM;IACN,OAAO;IACP,KAAK;IACL,OAAO;CAC4C,CAAC;AAOrD,SAAS,kBAAkB,CAAC,KAAkB;IAC7C,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;QACzB,MAAM,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAE9E,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa;QAC/B,MAAM,IAAI,kBAAkB,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAE5F,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC;IAEvD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,IAAgB,EAAE,MAAe;IACtD,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,eAAe;YACnB,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACrD,KAAK,WAAW;YACf,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QAClD,KAAK,mBAAmB;YACvB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7E,KAAK,YAAY;YAChB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9C,KAAK,aAAa;YACjB,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACtD,KAAK,eAAe,CAAC,CAAC,CAAC;YACtB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,gBAAgB,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3E,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QACvF,CAAC;QACD,KAAK,WAAW;YACf,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAChD,KAAK,OAAO;YACX,MAAM,IAAI,gBAAgB,CAAC,mCAAmC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1F;YACC,WAAW,CACV,GAAG,EAAE;gBACJ,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC/B,CAAC,EACD,mBAAmB,EACnB,8CAA8C,CAC9C,CAAC;YACF,OAAO,SAAS,CAAC;IACnB,CAAC;AACF,CAAC;AAED,2EAA2E;AAC3E,SAAS,QAAQ,CAAC,KAAY;IAC7B,OAAO;QACN,WAAW,EAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC,wBAAwB;QAC5F,eAAe,EAAE,KAAK,CAAC,mBAAmB;QAC1C,kBAAkB,EAAE,KAAK,CAAC,wBAAwB;QAClD,YAAY,EAAE,KAAK,CAAC,aAAa;KACjC,CAAC;AACH,CAAC;AAED,MAAM,OAAO,UAAU;IACd,MAAM,CAAS;IACf,MAAM,CAAU;IAExB,2FAA2F;IAC3F,4EAA4E;IAC5E,YAAY,EACX,KAAK,EACL,WAAW,GAAG,KAAK,EACnB,eAAe,GAAG,MAAM,EACxB,MAAM,GAMN;QACA,wFAAwF;QACxF,kCAAkC;QAClC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,uBAAuB,CAChC,IAAI,KAAK,4CAA4C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7E,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,eAAe,CAAC,EAAE,CAAC;YACtD,MAAM,IAAI,uBAAuB,CAChC,IAAI,eAAe,uDAAuD,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5G,CAAC;QACH,CAAC;QACD,4CAA4C;QAC5C,IAAI,KAAK,KAAK,cAAc,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;YAC7D,MAAM,IAAI,uBAAuB,CAChC,8DAA8D,CAC9D,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,WAAW,CAAC;gBAC7B,KAAK;gBACL,oBAAoB,EAAE,eAAe;gBACrC,GAAG,CAAC,WAAW;oBACd,CAAC,CAAC,EAAE,cAAc,EAAE,OAAgB,EAAE,WAAW,EAAE,oBAA6B,EAAE;oBAClF,CAAC,CAAC,EAAE,CAAC;aACN,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,gFAAgF;YAChF,gFAAgF;YAChF,MAAM,IAAI,kBAAkB,CAAC,yCAAyC,EAAE;gBACvE,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC;aAC7B,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,GAAG,CACR,MAAc,EACd,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,GAAG,cAAc,EAAc;QAE7D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,IAAkB,CAAC;QAEvB,IAAI,CAAC;YACJ,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,uBAAuB,CAAC,KAAK,EAAE,2BAA2B,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IAEO,KAAK,CAAC,aAAa,CAC1B,IAAkB,EAClB,QAAkB,EAClB,KAAa;QAEb,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,KAAK,GAAsB,SAAS,CAAC;QAEzC,yFAAyF;QACzF,uEAAuE;QACvE,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,wBAAwB,CAAC,IAAI,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAC;YAExF,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAClC,qFAAqF;gBACrF,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;oBAAE,QAAQ,GAAG,IAAI,CAAC;gBACpD,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;oBACrC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;oBACpB,SAAS;gBACV,CAAC;gBAED,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;gBAEvC,IAAI,CAAC,IAAI;oBAAE,SAAS;gBAEpB,IAAI,WAAsC,CAAC;gBAC3C,IAAI,CAAC;oBACJ,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC/C,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,MAAM,oBAAoB,CAAC,KAAK,EAAE,qCAAqC,CAAC,CAAC;gBAC1E,CAAC;gBAED,IAAI,WAAW,EAAE,CAAC;oBACjB,IAAI,CAAC;wBACJ,QAAQ,CAAC,WAAW,CAAC,CAAC;oBACvB,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBAChB,MAAM,mBAAmB,CAAC,KAAK,EAAE,gCAAgC,CAAC,CAAC;oBACpE,CAAC;gBACF,CAAC;gBACD,IAAI,WAAW,EAAE,IAAI,KAAK,cAAc;oBAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC3E,CAAC;YAED,IAAI,CAAC,KAAK,EAAE,CAAC;gBACZ,0DAA0D;gBAC1D,WAAW,CACV,GAAG,EAAE;oBACJ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;gBAChE,CAAC,EACD,mBAAmB,EACnB,mDAAmD,CACnD,CAAC;YACH,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,KAAK;gBAAE,MAAM,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YACzD,MAAM,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAClE,CAAC;QAED,OAAO;YACN,yDAAyD;YACzD,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;YAC1B,MAAM,EAAE,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC;YAChC,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI;SACrC,CAAC;IACH,CAAC;CACD","sourcesContent":["import {\n\tCodex,\n\ttype ModelReasoningEffort,\n\ttype Thread,\n\ttype ThreadEvent,\n\ttype ThreadItem,\n\ttype Usage,\n} from '@openai/codex-sdk';\nimport {\n\ttype Agent,\n\ttype AgentResponse,\n\ttype Callback,\n\tignoreProgress,\n\ttype ProgressEvent,\n\ttype RunOptions,\n} from '#src/agent/domain/agent';\nimport {\n\tInvalidAgentConfigError,\n\tRecoverableError,\n\tUnrecoverableError,\n\twithSpentTokens,\n} from '#src/shared/domain/errors';\nimport {\n\tclassifiedProviderStream,\n\tclassifyHostFailure,\n\tclassifyLocalFailure,\n\tclassifyProviderFailure,\n\tdescribeFailure,\n\ttreatErrors,\n} from '#src/shared/domain/providerFailure';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport type { Tokens } from '#src/shared/domain/tokens';\nimport { isOneOf } from '#src/shared/domain/isOneOf';\n\n// The SDK types `model` as a plain string, so this list is maintained by hand.\nexport const codexModels = ['gpt-6-astra', 'gpt-5.6-sol', 'gpt-5.6-luna', 'gpt-5.6-terra'] as const;\nexport type CodexModel = (typeof codexModels)[number];\n\n// The efforts Codex's model catalog lists; the SDK also types 'minimal' and 'persistent', which\n// none of the models above supports. `satisfies` only proves this is a subset of the SDK's type,\n// so an SDK upgrade that adds an effort has to be reconciled here by hand.\nexport const codexReasoningEfforts = [\n\t'low',\n\t'medium',\n\t'high',\n\t'xhigh',\n\t'max',\n\t'ultra',\n] as const satisfies readonly ModelReasoningEffort[];\nexport type CodexReasoningEffort = (typeof codexReasoningEfforts)[number];\n\ninterface StreamedTurn {\n\tevents: AsyncGenerator<ThreadEvent>;\n}\n\nfunction convertEventToItem(event: ThreadEvent): ThreadItem | undefined {\n\tif (event.type === 'error')\n\t\tthrow new UnrecoverableError('Codex stream error', { cause: event.message });\n\n\tif (event.type === 'turn.failed')\n\t\tthrow new UnrecoverableError('Turn failed from codex sdk', { cause: event.error.message });\n\n\tif (event.type === 'item.completed') return event.item;\n\n\treturn undefined;\n}\n\nfunction describeItem(item: ThreadItem, logger: ILogger): ProgressEvent | undefined {\n\tswitch (item.type) {\n\t\tcase 'agent_message':\n\t\t\treturn { type: 'agentMessage', message: item.text };\n\t\tcase 'reasoning':\n\t\t\treturn { type: 'reasoning', message: item.text };\n\t\tcase 'command_execution':\n\t\t\treturn { type: 'command', command: item.command, exitCode: item.exit_code };\n\t\tcase 'web_search':\n\t\t\treturn { type: 'search', query: item.query };\n\t\tcase 'file_change':\n\t\t\treturn { type: 'fileChange', changes: item.changes };\n\t\tcase 'mcp_tool_call': {\n\t\t\tif (item.error) {\n\t\t\t\tthrow new RecoverableError('skill failed', { cause: item.error.message });\n\t\t\t}\n\t\t\treturn { type: 'mcpTool', server: item.server, tool: item.tool, status: item.status };\n\t\t}\n\t\tcase 'todo_list':\n\t\t\treturn { type: 'todoList', items: item.items };\n\t\tcase 'error':\n\t\t\tthrow new RecoverableError('error while using the codex tools', { cause: item.message });\n\t\tdefault:\n\t\t\ttreatErrors(\n\t\t\t\t() => {\n\t\t\t\t\tlogger.warn(item, 'new type');\n\t\t\t\t},\n\t\t\t\tclassifyHostFailure,\n\t\t\t\t'Codex logger failed while reporting progress',\n\t\t\t);\n\t\t\treturn undefined;\n\t}\n}\n\n// Codex counts cached tokens inside input_tokens; Tokens keeps them apart.\nfunction toTokens(usage: Usage): Tokens {\n\treturn {\n\t\tinputTokens: usage.input_tokens - usage.cached_input_tokens - usage.cache_write_input_tokens,\n\t\treadCacheTokens: usage.cached_input_tokens,\n\t\twrittenCacheTokens: usage.cache_write_input_tokens,\n\t\toutputTokens: usage.output_tokens,\n\t};\n}\n\nexport class CodexAgent implements Agent {\n\tprivate thread: Thread;\n\tprivate logger: ILogger;\n\n\t// `model` and `reasoningEffort` are untyped on purpose: this adapter is the one that knows\n\t// what Codex supports, so it validates them instead of trusting the caller.\n\tconstructor({\n\t\tmodel,\n\t\tautoApprove = false,\n\t\treasoningEffort = 'high',\n\t\tlogger,\n\t}: {\n\t\tmodel: string;\n\t\tautoApprove?: boolean;\n\t\treasoningEffort?: string;\n\t\tlogger: ILogger;\n\t}) {\n\t\t// Checked before the SDK is involved: an unsupported value is the caller's mistake, not\n\t\t// a configuration Codex rejected.\n\t\tif (!isOneOf(codexModels, model)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${model}\" is not a Codex model; expected one of: ${codexModels.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (!isOneOf(codexReasoningEfforts, reasoningEffort)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${reasoningEffort}\" is not a Codex reasoning effort; expected one of: ${codexReasoningEfforts.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\t// The one per-model gap in Codex's catalog.\n\t\tif (model === 'gpt-5.6-luna' && reasoningEffort === 'ultra') {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t'\"gpt-5.6-luna\" does not support the \"ultra\" reasoning effort',\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tconst sdk = new Codex();\n\t\t\tthis.thread = sdk.startThread({\n\t\t\t\tmodel,\n\t\t\t\tmodelReasoningEffort: reasoningEffort,\n\t\t\t\t...(autoApprove\n\t\t\t\t\t? { approvalPolicy: 'never' as const, sandboxMode: 'danger-full-access' as const }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t// Not recoverable, unlike a request: a thread the SDK refused to open at all is\n\t\t\t// rejected configuration, and running the same constructor again cannot fix it.\n\t\t\tthrow new UnrecoverableError('Codex rejected the thread configuration', {\n\t\t\t\tcause: describeFailure(error),\n\t\t\t});\n\t\t}\n\n\t\tthis.logger = logger;\n\t}\n\n\tasync run(\n\t\tprompt: string,\n\t\t{ signal, onProgress: callback = ignoreProgress }: RunOptions,\n\t): Promise<AgentResponse> {\n\t\tconst start = Date.now();\n\t\tlet turn: StreamedTurn;\n\n\t\ttry {\n\t\t\tturn = await this.thread.runStreamed(prompt, { signal });\n\t\t} catch (error) {\n\t\t\tthrow classifyProviderFailure(error, 'Codex refused the request');\n\t\t}\n\n\t\treturn await this.parseResponse(turn, callback, start);\n\t}\n\n\tprivate async parseResponse(\n\t\tturn: StreamedTurn,\n\t\tcallback: Callback,\n\t\tstart: number,\n\t): Promise<AgentResponse> {\n\t\tconst lines: string[] = [];\n\t\tlet usage: Usage | undefined = undefined;\n\n\t\t// Once Codex produced an item, the provider answered: a failure after that without usage\n\t\t// leaves the run's count unknown, unlike one that never got an answer.\n\t\tlet answered = false;\n\n\t\ttry {\n\t\t\tconst events = classifiedProviderStream(turn.events, 'Codex stream ended unexpectedly');\n\n\t\t\tfor await (const event of events) {\n\t\t\t\t// A `turn.failed` alone may be a quota or authentication failure with no model work.\n\t\t\t\tif (event.type.startsWith('item.')) answered = true;\n\t\t\t\tif (event.type === 'turn.completed') {\n\t\t\t\t\tusage = event.usage;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst item = convertEventToItem(event);\n\n\t\t\t\tif (!item) continue;\n\n\t\t\t\tlet description: ProgressEvent | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tdescription = describeItem(item, this.logger);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow classifyLocalFailure(error, 'Codex failed while mapping progress');\n\t\t\t\t}\n\n\t\t\t\tif (description) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcallback(description);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow classifyHostFailure(error, 'Codex progress callback failed');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (description?.type === 'agentMessage') lines.push(description.message);\n\t\t\t}\n\n\t\t\tif (!usage) {\n\t\t\t\t// The turn's work stands; only its accounting is missing.\n\t\t\t\ttreatErrors(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.logger.warn('Codex ended a turn without reporting usage');\n\t\t\t\t\t},\n\t\t\t\t\tclassifyHostFailure,\n\t\t\t\t\t'Codex logger failed while reporting missing usage',\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (usage) throw withSpentTokens(error, toTokens(usage));\n\t\t\tthrow answered ? withSpentTokens(error, undefined, true) : error;\n\t\t}\n\n\t\treturn {\n\t\t\t// Empty when the turn only ran commands or edited files.\n\t\t\tresponse: lines.join('\\n'),\n\t\t\ttokens: usage && toTokens(usage),\n\t\t\tduration: (Date.now() - start) / 1000,\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"codexAgent.js","sourceRoot":"","sources":["../../../../../src/engines/codex/infrastructure/model/codexAgent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tCodex,\n\ttype ModelReasoningEffort,\n\ttype Thread,\n\ttype ThreadEvent,\n\ttype ThreadItem,\n\ttype Usage,\n} from '@openai/codex-sdk';\nimport {\n\ttype Agent,\n\ttype AgentResponse,\n\ttype Callback,\n\tignoreProgress,\n\ttype ProgressEvent,\n\ttype RunOptions,\n} from '#src/agent/domain/agent';\nimport {\n\tInvalidAgentConfigError,\n\tRecoverableError,\n\tUnrecoverableError,\n\twithSpentTokens,\n} from '#src/shared/domain/errors';\nimport {\n\tclassifiedProviderStream,\n\tclassifyHostFailure,\n\tclassifyLocalFailure,\n\tclassifyProviderFailure,\n\tdescribeFailure,\n\ttreatErrors,\n} from '#src/shared/domain/providerFailure';\nimport type { ILogger } from '#src/shared/domain/logger';\nimport type { Tokens } from '#src/shared/domain/tokens';\nimport { OneRunAtATime } from '#src/agent/domain/oneRunAtATime';\nimport { newSession, sessionOf } from '#src/agent/domain/session';\nimport { isOneOf } from '#src/shared/domain/isOneOf';\n\n// The SDK types `model` as a plain string, so this list is maintained by hand.\nexport const codexModels = ['gpt-6-astra', 'gpt-5.6-sol', 'gpt-5.6-luna', 'gpt-5.6-terra'] as const;\nexport type CodexModel = (typeof codexModels)[number];\n\n// The efforts Codex's model catalog lists; the SDK also types 'minimal' and 'persistent', which\n// none of the models above supports. `satisfies` only proves this is a subset of the SDK's type,\n// so an SDK upgrade that adds an effort has to be reconciled here by hand.\nexport const codexReasoningEfforts = [\n\t'low',\n\t'medium',\n\t'high',\n\t'xhigh',\n\t'max',\n\t'ultra',\n] as const satisfies readonly ModelReasoningEffort[];\nexport type CodexReasoningEffort = (typeof codexReasoningEfforts)[number];\n\ninterface StreamedTurn {\n\tevents: AsyncGenerator<ThreadEvent>;\n}\n\nfunction convertEventToItem(event: ThreadEvent): ThreadItem | undefined {\n\tif (event.type === 'error')\n\t\tthrow new UnrecoverableError('Codex stream error', { cause: event.message });\n\n\tif (event.type === 'turn.failed')\n\t\tthrow new UnrecoverableError('Turn failed from codex sdk', { cause: event.error.message });\n\n\tif (event.type === 'item.completed') return event.item;\n\n\treturn undefined;\n}\n\nfunction describeItem(item: ThreadItem, logger: ILogger): ProgressEvent | undefined {\n\tswitch (item.type) {\n\t\tcase 'agent_message':\n\t\t\treturn { type: 'agentMessage', message: item.text };\n\t\tcase 'reasoning':\n\t\t\treturn { type: 'reasoning', message: item.text };\n\t\tcase 'command_execution':\n\t\t\treturn { type: 'command', command: item.command, exitCode: item.exit_code };\n\t\tcase 'web_search':\n\t\t\treturn { type: 'search', query: item.query };\n\t\tcase 'file_change':\n\t\t\treturn { type: 'fileChange', changes: item.changes };\n\t\tcase 'mcp_tool_call': {\n\t\t\tif (item.error) {\n\t\t\t\tthrow new RecoverableError('skill failed', { cause: item.error.message });\n\t\t\t}\n\t\t\treturn { type: 'mcpTool', server: item.server, tool: item.tool, status: item.status };\n\t\t}\n\t\tcase 'todo_list':\n\t\t\treturn { type: 'todoList', items: item.items };\n\t\tcase 'error':\n\t\t\tthrow new RecoverableError('error while using the codex tools', { cause: item.message });\n\t\tdefault:\n\t\t\ttreatErrors(\n\t\t\t\t() => {\n\t\t\t\t\tlogger.warn(item, 'new type');\n\t\t\t\t},\n\t\t\t\tclassifyHostFailure,\n\t\t\t\t'Codex logger failed while reporting progress',\n\t\t\t);\n\t\t\treturn undefined;\n\t}\n}\n\n// Codex counts cached tokens inside input_tokens; Tokens keeps them apart.\nfunction toTokens(usage: Usage): Tokens {\n\treturn {\n\t\tinputTokens: usage.input_tokens - usage.cached_input_tokens - usage.cache_write_input_tokens,\n\t\treadCacheTokens: usage.cached_input_tokens,\n\t\twrittenCacheTokens: usage.cache_write_input_tokens,\n\t\toutputTokens: usage.output_tokens,\n\t};\n}\n\nexport class CodexAgent implements Agent {\n\tprivate thread: Thread;\n\tprivate logger: ILogger;\n\tprivate readonly session = newSession();\n\t// Its thread goes on from one run to the next, so two at once would fork it.\n\tprivate readonly runs = new OneRunAtATime();\n\n\t// `model` and `reasoningEffort` are untyped on purpose: this adapter is the one that knows\n\t// what Codex supports, so it validates them instead of trusting the caller.\n\tconstructor({\n\t\tmodel,\n\t\tautoApprove = false,\n\t\treasoningEffort = 'high',\n\t\tlogger,\n\t}: {\n\t\tmodel: string;\n\t\tautoApprove?: boolean;\n\t\treasoningEffort?: string;\n\t\tlogger: ILogger;\n\t}) {\n\t\t// Checked before the SDK is involved: an unsupported value is the caller's mistake, not\n\t\t// a configuration Codex rejected.\n\t\tif (!isOneOf(codexModels, model)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${model}\" is not a Codex model; expected one of: ${codexModels.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (!isOneOf(codexReasoningEfforts, reasoningEffort)) {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t`\"${reasoningEffort}\" is not a Codex reasoning effort; expected one of: ${codexReasoningEfforts.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\t// The one per-model gap in Codex's catalog.\n\t\tif (model === 'gpt-5.6-luna' && reasoningEffort === 'ultra') {\n\t\t\tthrow new InvalidAgentConfigError(\n\t\t\t\t'\"gpt-5.6-luna\" does not support the \"ultra\" reasoning effort',\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tconst sdk = new Codex();\n\t\t\tthis.thread = sdk.startThread({\n\t\t\t\tmodel,\n\t\t\t\tmodelReasoningEffort: reasoningEffort,\n\t\t\t\t...(autoApprove\n\t\t\t\t\t? { approvalPolicy: 'never' as const, sandboxMode: 'danger-full-access' as const }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t// Not recoverable, unlike a request: a thread the SDK refused to open at all is\n\t\t\t// rejected configuration, and running the same constructor again cannot fix it.\n\t\t\tthrow new UnrecoverableError('Codex rejected the thread configuration', {\n\t\t\t\tcause: describeFailure(error),\n\t\t\t});\n\t\t}\n\n\t\tthis.logger = logger;\n\t}\n\n\t/** @throws {RunInProgressError} when another run on it is still working. */\n\trun(prompt: string, options: RunOptions): Promise<AgentResponse> {\n\t\treturn this.runs.run(() => this.runAlone(prompt, options));\n\t}\n\n\tprivate async runAlone(prompt: string, options: RunOptions): Promise<AgentResponse> {\n\t\tconst { signal, onProgress: callback = ignoreProgress } = options;\n\t\tconst session = sessionOf(options) ?? this.session;\n\t\tconst start = Date.now();\n\t\tlet turn: StreamedTurn;\n\n\t\ttry {\n\t\t\tturn = await this.thread.runStreamed(prompt, { signal });\n\t\t} catch (error) {\n\t\t\tthrow classifyProviderFailure(error, 'Codex refused the request');\n\t\t}\n\n\t\treturn { ...(await this.parseResponse(turn, callback, start)), session: { ...session } };\n\t}\n\n\tprivate async parseResponse(\n\t\tturn: StreamedTurn,\n\t\tcallback: Callback,\n\t\tstart: number,\n\t): Promise<AgentResponse> {\n\t\tconst lines: string[] = [];\n\t\tlet usage: Usage | undefined = undefined;\n\n\t\t// Once Codex produced an item, the provider answered: a failure after that without usage\n\t\t// leaves the run's count unknown, unlike one that never got an answer.\n\t\tlet answered = false;\n\n\t\ttry {\n\t\t\tconst events = classifiedProviderStream(turn.events, 'Codex stream ended unexpectedly');\n\n\t\t\tfor await (const event of events) {\n\t\t\t\t// A `turn.failed` alone may be a quota or authentication failure with no model work.\n\t\t\t\tif (event.type.startsWith('item.')) answered = true;\n\t\t\t\tif (event.type === 'turn.completed') {\n\t\t\t\t\tusage = event.usage;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst item = convertEventToItem(event);\n\n\t\t\t\tif (!item) continue;\n\n\t\t\t\tlet description: ProgressEvent | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tdescription = describeItem(item, this.logger);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow classifyLocalFailure(error, 'Codex failed while mapping progress');\n\t\t\t\t}\n\n\t\t\t\tif (description) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcallback(description);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow classifyHostFailure(error, 'Codex progress callback failed');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (description?.type === 'agentMessage') lines.push(description.message);\n\t\t\t}\n\n\t\t\tif (!usage) {\n\t\t\t\t// The turn's work stands; only its accounting is missing.\n\t\t\t\ttreatErrors(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.logger.warn('Codex ended a turn without reporting usage');\n\t\t\t\t\t},\n\t\t\t\t\tclassifyHostFailure,\n\t\t\t\t\t'Codex logger failed while reporting missing usage',\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (usage) throw withSpentTokens(error, toTokens(usage));\n\t\t\tthrow answered ? withSpentTokens(error, undefined, true) : error;\n\t\t}\n\n\t\treturn {\n\t\t\t// Empty when the turn only ran commands or edited files.\n\t\t\tresponse: lines.join('\\n'),\n\t\t\ttokens: usage && toTokens(usage),\n\t\t\tduration: (Date.now() - start) / 1000,\n\t\t};\n\t}\n}\n"]}