@mikode13/harness 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +170 -0
  3. package/dist/agent/domain/agent.d.ts +63 -0
  4. package/dist/agent/domain/agent.d.ts.map +1 -0
  5. package/dist/agent/domain/agent.js +2 -0
  6. package/dist/agent/domain/agent.js.map +1 -0
  7. package/dist/agent/domain/errors.d.ts +13 -0
  8. package/dist/agent/domain/errors.d.ts.map +1 -0
  9. package/dist/agent/domain/errors.js +15 -0
  10. package/dist/agent/domain/errors.js.map +1 -0
  11. package/dist/agent/domain/providerFailure.d.ts +20 -0
  12. package/dist/agent/domain/providerFailure.d.ts.map +1 -0
  13. package/dist/agent/domain/providerFailure.js +84 -0
  14. package/dist/agent/domain/providerFailure.js.map +1 -0
  15. package/dist/engines/claude/infrastructure/model/claudeAgent.d.ts +17 -0
  16. package/dist/engines/claude/infrastructure/model/claudeAgent.d.ts.map +1 -0
  17. package/dist/engines/claude/infrastructure/model/claudeAgent.js +225 -0
  18. package/dist/engines/claude/infrastructure/model/claudeAgent.js.map +1 -0
  19. package/dist/engines/codex/infrastructure/model/codexAgent.d.ts +19 -0
  20. package/dist/engines/codex/infrastructure/model/codexAgent.d.ts.map +1 -0
  21. package/dist/engines/codex/infrastructure/model/codexAgent.js +119 -0
  22. package/dist/engines/codex/infrastructure/model/codexAgent.js.map +1 -0
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +9 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/orchestration/domain/interface/validator.d.ts +4 -0
  28. package/dist/orchestration/domain/interface/validator.d.ts.map +1 -0
  29. package/dist/orchestration/domain/interface/validator.js +2 -0
  30. package/dist/orchestration/domain/interface/validator.js.map +1 -0
  31. package/dist/orchestration/domain/model/orchestratorAgent.d.ts +14 -0
  32. package/dist/orchestration/domain/model/orchestratorAgent.d.ts.map +1 -0
  33. package/dist/orchestration/domain/model/orchestratorAgent.js +157 -0
  34. package/dist/orchestration/domain/model/orchestratorAgent.js.map +1 -0
  35. package/dist/orchestration/domain/model/reviewerDecision.d.ts +7 -0
  36. package/dist/orchestration/domain/model/reviewerDecision.d.ts.map +1 -0
  37. package/dist/orchestration/domain/model/reviewerDecision.js +2 -0
  38. package/dist/orchestration/domain/model/reviewerDecision.js.map +1 -0
  39. package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.d.ts +6 -0
  40. package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.d.ts.map +1 -0
  41. package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.js +12 -0
  42. package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.js.map +1 -0
  43. package/dist/retry/domain/model/retryingAgent.d.ts +8 -0
  44. package/dist/retry/domain/model/retryingAgent.d.ts.map +1 -0
  45. package/dist/retry/domain/model/retryingAgent.js +38 -0
  46. package/dist/retry/domain/model/retryingAgent.js.map +1 -0
  47. package/dist/shared/domain/isAbortError.d.ts +2 -0
  48. package/dist/shared/domain/isAbortError.d.ts.map +1 -0
  49. package/dist/shared/domain/isAbortError.js +4 -0
  50. package/dist/shared/domain/isAbortError.js.map +1 -0
  51. package/dist/shared/domain/logger.d.ts +6 -0
  52. package/dist/shared/domain/logger.d.ts.map +1 -0
  53. package/dist/shared/domain/logger.js +2 -0
  54. package/dist/shared/domain/logger.js.map +1 -0
  55. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,44 @@
1
+ "Commons Clause" License Condition v1.0
2
+
3
+ The Software is provided to you by the Licensor under the License, as defined below,
4
+ subject to the following condition.
5
+
6
+ Without limiting other conditions in the License, the grant of rights under the License
7
+ will not include, and the License does not grant to you, the right to Sell the Software.
8
+
9
+ For purposes of the foregoing, "Sell" means practicing any or all of the rights granted
10
+ to you under the License to provide to third parties, for a fee or other consideration
11
+ (including without limitation fees for hosting or consulting/support services related
12
+ to the Software), a product or service whose value derives, entirely or substantially,
13
+ from the functionality of the Software.
14
+
15
+ Any license notice or attribution required by the License must also include this
16
+ Commons Clause License Condition notice.
17
+
18
+ Software: @mikode13/harness
19
+ License: MIT License
20
+ Licensor: MiKode13
21
+
22
+ MIT License
23
+
24
+ Copyright (c) 2026 MiKode13
25
+
26
+ Permission is hereby granted, free of charge, to any person obtaining a copy
27
+ of this software and associated documentation files (the "Software"), to deal
28
+ in the Software without restriction, including without limitation the rights
29
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30
+ copies of the Software, and to permit persons to whom the Software is
31
+ furnished to do so, subject to the Commons Clause License Condition above
32
+ and the following conditions:
33
+
34
+ The above copyright notice, this permission notice, and the Commons Clause
35
+ License Condition notice shall be included in all copies or substantial
36
+ portions of the Software.
37
+
38
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # @mikode13/harness
2
+
3
+ A small, hand-built agent harness in TypeScript. It coordinates OpenAI Codex and
4
+ Claude Agent SDK instances — as a single terminal chat, or as a multi-agent
5
+ plan → execute → review workflow — and is growing into the runtime that
6
+ coordinates specialized agents across MiKode projects.
7
+
8
+ ## Motivation
9
+
10
+ This project exists for three reasons, in this order:
11
+
12
+ 1. **Learning.** Understand how agent SDKs work internally — the agent loop,
13
+ messages, tool calls, cancellation, context continuity, and multi-agent
14
+ coordination — by building the fundamental parts personally instead of
15
+ consuming a framework. No LangGraph, no OpenAI Agents SDK as the engine;
16
+ those come later as comparison points, not as foundations.
17
+ 2. **A reusable base.** The harness is the substrate for a future chatbot and
18
+ for MiKode tooling: routing, typed tools, specialized agents, memory, and
19
+ validation layers will be added on top of it once real consumers need them.
20
+ 3. **Defining how AI works inside MiKode.** Standards, explicit per-agent
21
+ responsibilities and tools, traceability, and reproducible runs — following
22
+ the conventions of the `mikode-engineering` repository.
23
+
24
+ The project advances in small vertical slices: each abstraction must be justified
25
+ by a real problem before it is introduced, and no public API is stabilized until
26
+ there is at least one real consumer.
27
+
28
+ ## What it does today
29
+
30
+ An interactive terminal chat, backed by one `Agent` — a single engine, or a full
31
+ multi-agent workflow, chosen entirely by what gets wired up in `cli/cli.ts`; the
32
+ chat loop itself never knows the difference.
33
+
34
+ - **A provider-agnostic `Agent` contract** (`run(prompt, signal, callback)`) with
35
+ two real implementations, `CodexAgent` and `ClaudeAgent` — swapping one for the
36
+ other, anywhere in the composition, changes nothing else.
37
+ - **Conversation continuity for free** in both engines: Codex reuses one `Thread`
38
+ across turns; Claude resumes via a captured `session_id` — the engine keeps
39
+ context server-side either way.
40
+ - **`OrchestratorAgent`**: coordinates a planner, an executor, and a reviewer
41
+ (each an injected `Agent`) in a plan → execute → review loop. The reviewer's
42
+ decision is a Zod-validated structured `{decision, feedback}`, not free text —
43
+ a rejected or malformed decision retries with the reason fed back, bounded by
44
+ `maxAttempts`, converting to `UnrecoverableError` only once exhausted. A
45
+ malformed reviewer response retries only the reviewer call, not the whole
46
+ cycle. Because it implements `Agent` itself, the chat loop drives it exactly
47
+ like it drives a bare engine.
48
+ - **Live progress streaming**: every engine reports ongoing activity (tool
49
+ calls, searches, file changes, reasoning) through a typed `ProgressEvent`
50
+ callback, separate from the final response — so an agent's own words never
51
+ get mixed with narration of what it did to produce them, and a caller (the
52
+ CLI today, a future web UI) decides how to render it.
53
+ - **Retry policy** (`RetryingAgent`) wraps individual agents, not whole
54
+ workflows — a transient failure in one sub-agent is absorbed locally, without
55
+ redoing another sub-agent's already-successful work.
56
+ - Cancellation with `AbortController`/`AbortSignal`, shared between the prompt
57
+ and every agent call, all the way down through the orchestrator.
58
+
59
+ ## Where it is going
60
+
61
+ Remaining work (see `tasks.txt` for the actionable, dated list):
62
+
63
+ - Live streaming already ships; still open: type-while-thinking (respond to
64
+ new input without blocking on the current agent call), session persistence
65
+ across process restarts, and structured per-turn usage/duration logging.
66
+ - Terminal UX polish (bordered chat box, markdown rendering, user-friendly
67
+ error messages) — explicitly deferred until the above is solid.
68
+ - Dynamic routing (deciding which flow/agent a request needs, instead of
69
+ always running the fixed plan → execute → review workflow) — deliberately
70
+ built _after_ that fixed flow, not alongside it, so the routing decision
71
+ reuses a technique already proven on a simpler problem.
72
+
73
+ Deliberately out of scope for now: MCP, long-term memory, graph execution, and
74
+ file-based agent registries — each waits for a real need.
75
+
76
+ ## Adding an engine
77
+
78
+ A new provider only needs one thing to compose safely into everything above:
79
+ **it must only ever reject with `RecoverableError` or `UnrecoverableError`**
80
+ (`src/agent/domain/errors.ts`), never a raw SDK error. `RetryingAgent` and
81
+ `OrchestratorAgent` both decide what to do next by `instanceof`-checking
82
+ against those two types; anything else leaking through is treated as
83
+ unrecoverable and ends the run, because nothing above the adapter can tell
84
+ whether replaying it is safe. Wrap every call into the underlying SDK,
85
+ including failures the SDK itself doesn't model as a domain error (network
86
+ errors, malformed responses): `classifyProviderFailure` covers a single call,
87
+ `classifiedProviderStream` covers an SDK stream. Both are deliberately narrow —
88
+ the classification must not span your own item mapping, logging, or the
89
+ consumer callback, or a failure in the host is reported as a provider failure
90
+ and gets retried. Those host failures are instead classified as unrecoverable,
91
+ because the provider turn may already have produced side effects. See the doc
92
+ comment on `Agent` in `src/agent/domain/agent.ts`.
93
+
94
+ ## Install
95
+
96
+ ```sh
97
+ pnpm add @mikode13/harness
98
+ ```
99
+
100
+ An agent is composed, then driven; the package brings no I/O of its own:
101
+
102
+ ```ts
103
+ import {
104
+ ClaudeAgent,
105
+ RetryingAgent,
106
+ UnrecoverableError,
107
+ type ProgressEvent,
108
+ } from '@mikode13/harness';
109
+
110
+ const agent = new RetryingAgent(new ClaudeAgent('sonnet'));
111
+ const controller = new AbortController();
112
+
113
+ const render = (event: ProgressEvent) => {
114
+ if (event.type === 'agentMessage') process.stdout.write(event.message);
115
+ };
116
+
117
+ try {
118
+ const result = await agent.run('Summarize this repository.', controller.signal, render);
119
+ console.log(result?.duration, result?.inputTokens, result?.outputTokens);
120
+ } catch (error) {
121
+ if (error instanceof UnrecoverableError) console.error(error.message, error.cause);
122
+ }
123
+ ```
124
+
125
+ `ProgressEvent` is the public seam for live activity; rendering it is the
126
+ consumer's decision, not the harness's. `cli/progressEventFormatter.ts` is one
127
+ terminal-shaped implementation to copy from. Swapping `ClaudeAgent` for
128
+ `CodexAgent`, or for an `OrchestratorAgent` wrapping all three roles, changes
129
+ nothing else in the snippet above.
130
+
131
+ ## Tests
132
+
133
+ `pnpm test` runs the unit suite against deterministic fakes; it never contacts a
134
+ real provider. Provider-boundary correctness (SDK auth, request shape, model
135
+ availability) is not covered by an automated suite here — it surfaces through
136
+ actual usage and monitoring, not by scheduling calls to a live SDK on a timer.
137
+
138
+ ## Local development smoke test
139
+
140
+ `cli/` is a separate, unpublished workspace project — a development-only harness
141
+ runner (own `package.json`, not part of the `@mikode13/harness` package) that
142
+ exists solely to exercise the library manually while working in this repository:
143
+
144
+ ```sh
145
+ pnpm run dev
146
+ ```
147
+
148
+ Type your prompt at `>`. Press Ctrl+C while idle at the prompt to exit; pressing
149
+ it while an agent is running cancels only that turn and returns to the prompt.
150
+
151
+ `cli/cli.ts` currently enables `autoApprove` for its trusted backend agents.
152
+ This maps to each provider's permission-bypass mode and grants those processes
153
+ unrestricted command access. Keep it disabled when the host may receive untrusted
154
+ prompts, or provide an approval workflow from the entry point.
155
+
156
+ Real consumers (a future REST/WebSocket server, a chatbot UI) compose the
157
+ exported `Agent`, `OrchestratorAgent`, and other harness building blocks with
158
+ their own I/O and `ILogger` adapter. `ConversationLoop`/`IPromptEmitter` are not
159
+ part of the published package — they encode one specific interactive,
160
+ turn-by-turn consumption pattern (see `cli/`), not the harness seam itself; a
161
+ consumer that wants that same loop can use `cli/`'s implementation as a
162
+ reference rather than depend on it as a library.
163
+
164
+ ## License
165
+
166
+ This project is source-available under the MIT License with the
167
+ [Commons Clause License Condition v1.0](https://commonsclause.com/). See
168
+ [LICENSE](./LICENSE) for the complete text. It is not OSI open source: the Commons
169
+ Clause restricts selling the software or a service whose value derives substantially
170
+ from it.
@@ -0,0 +1,63 @@
1
+ export interface AgentResponse {
2
+ response: string;
3
+ inputTokens: number;
4
+ outputTokens: number;
5
+ duration: number;
6
+ }
7
+ export type Callback = (item: ProgressEvent) => void;
8
+ export type ProgressEvent = {
9
+ type: 'command';
10
+ command: string;
11
+ exitCode?: number;
12
+ } | {
13
+ type: 'reasoning';
14
+ message: string;
15
+ } | {
16
+ type: 'search';
17
+ query: string;
18
+ } | {
19
+ type: 'fileChange';
20
+ changes: {
21
+ path: string;
22
+ kind: 'add' | 'update' | 'delete';
23
+ }[];
24
+ } | {
25
+ type: 'mcpTool';
26
+ server: string;
27
+ tool: string;
28
+ status: string;
29
+ } | {
30
+ type: 'agentMessage';
31
+ message: string;
32
+ } | {
33
+ type: 'todoList';
34
+ items: {
35
+ text: string;
36
+ completed: boolean;
37
+ }[];
38
+ } | {
39
+ type: 'turnStarted';
40
+ } | {
41
+ type: 'turnEnded';
42
+ };
43
+ /**
44
+ * The contract every engine (CodexAgent, ClaudeAgent, future providers) and every
45
+ * decorator (RetryingAgent, OrchestratorAgent) is built against.
46
+ *
47
+ * Implementers MUST only ever reject with `RecoverableError` or `UnrecoverableError`
48
+ * (see ./errors.ts) — never a raw SDK error, a plain `Error`, or anything else leaked
49
+ * unclassified. Every consumer of `Agent` (RetryingAgent's retry decision,
50
+ * OrchestratorAgent's failure handling) `instanceof`-checks against those two types to
51
+ * decide what to do next; a leaked, unclassified error bypasses that decision
52
+ * entirely — it gets retried when it shouldn't be, or crashes a run that a retry
53
+ * would have recovered. Wrap every call into the underlying SDK so nothing escapes
54
+ * unclassified, including failures the SDK itself doesn't model as a domain error
55
+ * (network errors, malformed responses, etc.); `classifyProviderFailure` does this.
56
+ *
57
+ * Cancellation is the one exception: an `AbortError` must propagate unchanged, because
58
+ * consumers check for it before either error type.
59
+ */
60
+ export interface Agent {
61
+ run(prompt: string, signal: AbortSignal, callback: Callback): Promise<AgentResponse | undefined>;
62
+ }
63
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/agent/domain/agent.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IAErB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;AAErD,MAAM,MAAM,aAAa,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAA;KAAE,EAAE,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAEzB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,KAAK;IACrB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CACjG"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/agent/domain/agent.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ export declare class RecoverableError extends Error {
2
+ cause: string;
3
+ constructor(message: string, options: {
4
+ cause: string;
5
+ });
6
+ }
7
+ export declare class UnrecoverableError extends Error {
8
+ cause: string;
9
+ constructor(message: string, options: {
10
+ cause: string;
11
+ });
12
+ }
13
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/agent/domain/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAiB,SAAQ,KAAK;IACjC,KAAK,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;CAIvD;AACD,qBAAa,kBAAmB,SAAQ,KAAK;IACnC,KAAK,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;CAIvD"}
@@ -0,0 +1,15 @@
1
+ export class RecoverableError extends Error {
2
+ cause;
3
+ constructor(message, options) {
4
+ super(message, options);
5
+ this.cause = options.cause;
6
+ }
7
+ }
8
+ export class UnrecoverableError extends Error {
9
+ cause;
10
+ constructor(message, options) {
11
+ super(message, options);
12
+ this.cause = options.cause;
13
+ }
14
+ }
15
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/agent/domain/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACjC,KAAK,CAAS;IAEvB,YAAY,OAAe,EAAE,OAA0B;QACtD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,CAAC;CACD;AACD,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACnC,KAAK,CAAS;IAEvB,YAAY,OAAe,EAAE,OAA0B;QACtD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,CAAC;CACD"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Unclassified failures are transport-shaped, so recoverable is the useful default:
3
+ * `RetryingAgent` turns a persistent one into an `UnrecoverableError` on exhaustion, while
4
+ * the opposite default would make every transient blip fatal.
5
+ */
6
+ export declare function classifyProviderFailure(error: unknown, context: string): Error;
7
+ /** A host failure cannot be retried safely because the provider turn may already have side effects. */
8
+ export declare function classifyHostFailure(error: unknown, context: string): Error;
9
+ /** Preserves deliberate domain errors while making unexpected local failures fatal. */
10
+ export declare function classifyLocalFailure(error: unknown, context: string): Error;
11
+ /** The message alone: a stack or serialized object could expose unstable implementation details. */
12
+ export declare function describeFailure(error: unknown): string;
13
+ /**
14
+ * Classifies the stream itself and nothing else. Consuming an SDK stream inside a
15
+ * `try/catch` puts the loop body — item mapping, logging, the consumer callback — inside
16
+ * the provider boundary too, so a host failure gets reported as a recoverable provider
17
+ * failure and `RetryingAgent` replays a turn that already ran its side effects.
18
+ */
19
+ export declare function classifiedProviderStream<T>(stream: AsyncIterable<T>, context: string): AsyncGenerator<T>;
20
+ //# sourceMappingURL=providerFailure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providerFailure.d.ts","sourceRoot":"","sources":["../../../src/agent/domain/providerFailure.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAK9E;AAED,uGAAuG;AACvG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAK1E;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAK3E;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMtD;AAED;;;;;GAKG;AACH,wBAAuB,wBAAwB,CAAC,CAAC,EAChD,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,OAAO,EAAE,MAAM,GACb,cAAc,CAAC,CAAC,CAAC,CAsCnB"}
@@ -0,0 +1,84 @@
1
+ import { isAbortError } from "../../shared/domain/isAbortError.js";
2
+ import { RecoverableError, UnrecoverableError } from "./errors.js";
3
+ /**
4
+ * Unclassified failures are transport-shaped, so recoverable is the useful default:
5
+ * `RetryingAgent` turns a persistent one into an `UnrecoverableError` on exhaustion, while
6
+ * the opposite default would make every transient blip fatal.
7
+ */
8
+ export function classifyProviderFailure(error, context) {
9
+ if (isAbortError(error))
10
+ return error;
11
+ if (error instanceof RecoverableError || error instanceof UnrecoverableError)
12
+ return error;
13
+ return new RecoverableError(context, { cause: describeFailure(error) });
14
+ }
15
+ /** A host failure cannot be retried safely because the provider turn may already have side effects. */
16
+ export function classifyHostFailure(error, context) {
17
+ if (isAbortError(error))
18
+ return error;
19
+ if (error instanceof UnrecoverableError)
20
+ return error;
21
+ return new UnrecoverableError(context, { cause: describeFailure(error) });
22
+ }
23
+ /** Preserves deliberate domain errors while making unexpected local failures fatal. */
24
+ export function classifyLocalFailure(error, context) {
25
+ if (isAbortError(error))
26
+ return error;
27
+ if (error instanceof RecoverableError || error instanceof UnrecoverableError)
28
+ return error;
29
+ return new UnrecoverableError(context, { cause: describeFailure(error) });
30
+ }
31
+ /** The message alone: a stack or serialized object could expose unstable implementation details. */
32
+ export function describeFailure(error) {
33
+ if (error instanceof RecoverableError || error instanceof UnrecoverableError)
34
+ return error.cause;
35
+ if (error instanceof Error && error.message)
36
+ return error.message;
37
+ if (typeof error === 'string' && error)
38
+ return error;
39
+ return 'The provider failed without a description.';
40
+ }
41
+ /**
42
+ * Classifies the stream itself and nothing else. Consuming an SDK stream inside a
43
+ * `try/catch` puts the loop body — item mapping, logging, the consumer callback — inside
44
+ * the provider boundary too, so a host failure gets reported as a recoverable provider
45
+ * failure and `RetryingAgent` replays a turn that already ran its side effects.
46
+ */
47
+ export async function* classifiedProviderStream(stream, context) {
48
+ let events;
49
+ try {
50
+ events = stream[Symbol.asyncIterator]();
51
+ }
52
+ catch (error) {
53
+ throw classifyProviderFailure(error, context);
54
+ }
55
+ let completed = false;
56
+ try {
57
+ for (;;) {
58
+ let next;
59
+ try {
60
+ next = await events.next();
61
+ }
62
+ catch (error) {
63
+ throw classifyProviderFailure(error, context);
64
+ }
65
+ if (next.done) {
66
+ completed = true;
67
+ return;
68
+ }
69
+ yield next.value;
70
+ }
71
+ }
72
+ finally {
73
+ if (!completed) {
74
+ try {
75
+ await events.return?.();
76
+ }
77
+ catch {
78
+ // Cleanup is secondary to the failure that interrupted consumption. It must
79
+ // never replace a classified provider error or an unrecoverable host error.
80
+ }
81
+ }
82
+ }
83
+ }
84
+ //# sourceMappingURL=providerFailure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providerFailure.js","sourceRoot":"","sources":["../../../src/agent/domain/providerFailure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { EffortLevel } from '@anthropic-ai/claude-agent-sdk';
2
+ import type { Agent, AgentResponse, Callback } from '../../../../agent/domain/agent.ts';
3
+ type Model = 'sonnet' | 'opus' | 'haiku' | 'claude-fable-5';
4
+ export declare class ClaudeAgent implements Agent {
5
+ private model;
6
+ private autoApprove;
7
+ private reasoningEffort;
8
+ private sessionId?;
9
+ constructor(model: Model, autoApprove?: boolean, reasoningEffort?: EffortLevel);
10
+ run(prompt: string, signal: AbortSignal, callback: Callback): Promise<AgentResponse | undefined>;
11
+ private parseResponse;
12
+ private handleAssistantMessage;
13
+ private handleUserMessage;
14
+ private handleCompletedTool;
15
+ }
16
+ export {};
17
+ //# sourceMappingURL=claudeAgent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeAgent.d.ts","sourceRoot":"","sources":["../../../../../src/engines/claude/infrastructure/model/claudeAgent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,WAAW,EAKX,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACX,KAAK,EACL,aAAa,EACb,QAAQ,EAER,MAAM,mCAAmC,CAAC;AAS3C,KAAK,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;AA2H5D,qBAAa,WAAY,YAAW,KAAK;IACxC,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,eAAe,CAAc;IACrC,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEf,KAAK,EAAE,KAAK,EAAE,WAAW,UAAQ,EAAE,eAAe,GAAE,WAAoB;IAM9E,GAAG,CACR,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;YA+BvB,aAAa;IAiD3B,OAAO,CAAC,sBAAsB;IAsC9B,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,mBAAmB;CAmB3B"}