@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.
- package/LICENSE +44 -0
- package/README.md +170 -0
- package/dist/agent/domain/agent.d.ts +63 -0
- package/dist/agent/domain/agent.d.ts.map +1 -0
- package/dist/agent/domain/agent.js +2 -0
- package/dist/agent/domain/agent.js.map +1 -0
- package/dist/agent/domain/errors.d.ts +13 -0
- package/dist/agent/domain/errors.d.ts.map +1 -0
- package/dist/agent/domain/errors.js +15 -0
- package/dist/agent/domain/errors.js.map +1 -0
- package/dist/agent/domain/providerFailure.d.ts +20 -0
- package/dist/agent/domain/providerFailure.d.ts.map +1 -0
- package/dist/agent/domain/providerFailure.js +84 -0
- package/dist/agent/domain/providerFailure.js.map +1 -0
- package/dist/engines/claude/infrastructure/model/claudeAgent.d.ts +17 -0
- package/dist/engines/claude/infrastructure/model/claudeAgent.d.ts.map +1 -0
- package/dist/engines/claude/infrastructure/model/claudeAgent.js +225 -0
- package/dist/engines/claude/infrastructure/model/claudeAgent.js.map +1 -0
- package/dist/engines/codex/infrastructure/model/codexAgent.d.ts +19 -0
- package/dist/engines/codex/infrastructure/model/codexAgent.d.ts.map +1 -0
- package/dist/engines/codex/infrastructure/model/codexAgent.js +119 -0
- package/dist/engines/codex/infrastructure/model/codexAgent.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestration/domain/interface/validator.d.ts +4 -0
- package/dist/orchestration/domain/interface/validator.d.ts.map +1 -0
- package/dist/orchestration/domain/interface/validator.js +2 -0
- package/dist/orchestration/domain/interface/validator.js.map +1 -0
- package/dist/orchestration/domain/model/orchestratorAgent.d.ts +14 -0
- package/dist/orchestration/domain/model/orchestratorAgent.d.ts.map +1 -0
- package/dist/orchestration/domain/model/orchestratorAgent.js +157 -0
- package/dist/orchestration/domain/model/orchestratorAgent.js.map +1 -0
- package/dist/orchestration/domain/model/reviewerDecision.d.ts +7 -0
- package/dist/orchestration/domain/model/reviewerDecision.d.ts.map +1 -0
- package/dist/orchestration/domain/model/reviewerDecision.js +2 -0
- package/dist/orchestration/domain/model/reviewerDecision.js.map +1 -0
- package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.d.ts +6 -0
- package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.d.ts.map +1 -0
- package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.js +12 -0
- package/dist/orchestration/infrastructure/model/reviewerDecisionValidator.js.map +1 -0
- package/dist/retry/domain/model/retryingAgent.d.ts +8 -0
- package/dist/retry/domain/model/retryingAgent.d.ts.map +1 -0
- package/dist/retry/domain/model/retryingAgent.js +38 -0
- package/dist/retry/domain/model/retryingAgent.js.map +1 -0
- package/dist/shared/domain/isAbortError.d.ts +2 -0
- package/dist/shared/domain/isAbortError.d.ts.map +1 -0
- package/dist/shared/domain/isAbortError.js +4 -0
- package/dist/shared/domain/isAbortError.js.map +1 -0
- package/dist/shared/domain/logger.d.ts +6 -0
- package/dist/shared/domain/logger.d.ts.map +1 -0
- package/dist/shared/domain/logger.js +2 -0
- package/dist/shared/domain/logger.js.map +1 -0
- 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 @@
|
|
|
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"}
|