@dynamicagents/plugins 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/dist/claude-code/cards.d.ts +4 -0
- package/dist/claude-code/cards.js +22 -0
- package/dist/claude-code/config.d.ts +10 -83
- package/dist/claude-code/config.js +0 -2
- package/dist/claude-code/credentials.d.ts +32 -50
- package/dist/claude-code/credentials.js +115 -74
- package/dist/claude-code/daemon/index.d.ts +24 -0
- package/dist/claude-code/daemon/index.js +203 -0
- package/dist/claude-code/egress.d.ts +35 -117
- package/dist/claude-code/egress.js +80 -325
- package/dist/claude-code/events.d.ts +14 -17
- package/dist/claude-code/events.js +19 -15
- package/dist/claude-code/harness-wire.d.ts +45 -0
- package/dist/claude-code/harness-wire.js +47 -0
- package/dist/claude-code/index.d.ts +19 -29
- package/dist/claude-code/index.js +17 -25
- package/dist/claude-code/language-model.d.ts +19 -0
- package/dist/claude-code/language-model.js +71 -0
- package/dist/claude-code/model.d.ts +77 -70
- package/dist/claude-code/model.js +328 -304
- package/dist/claude-code/placeholder.d.ts +12 -0
- package/dist/claude-code/placeholder.js +12 -0
- package/dist/claude-code/spec.d.ts +4 -4
- package/dist/claude-code/spec.js +4 -4
- package/dist/claude-code/verified.d.ts +1 -1
- package/dist/claude-code/verified.js +1 -1
- package/dist/computer/client.d.ts +88 -0
- package/dist/computer/client.js +6 -0
- package/dist/computer/context.d.ts +7 -7
- package/dist/computer/context.js +14 -18
- package/dist/computer/gate.d.ts +4 -23
- package/dist/computer/gate.js +1 -37
- package/dist/computer/index.d.ts +44 -43
- package/dist/computer/index.js +29 -50
- package/dist/computer/paths.d.ts +5 -27
- package/dist/computer/paths.js +7 -30
- package/dist/computer/proxy.d.ts +17 -31
- package/dist/computer/proxy.js +9 -44
- package/dist/computer/render.d.ts +3 -40
- package/dist/computer/render.js +3 -36
- package/dist/computer/sandbox.d.ts +55 -0
- package/dist/computer/sandbox.js +236 -0
- package/dist/computer/shell.d.ts +36 -0
- package/dist/computer/shell.js +41 -0
- package/dist/computer/tools-exec.js +3 -9
- package/dist/computer/tools-file.d.ts +1 -1
- package/dist/computer/tools-file.js +1 -1
- package/dist/{repo → repo-github}/checkout.d.ts +3 -4
- package/dist/{repo → repo-github}/checkout.js +3 -4
- package/dist/{repo → repo-github}/context.d.ts +14 -32
- package/dist/{repo → repo-github}/context.js +46 -81
- package/dist/{repo → repo-github}/index.d.ts +30 -13
- package/dist/{repo → repo-github}/index.js +25 -6
- package/dist/repo-github/mcp.d.ts +95 -0
- package/dist/repo-github/mcp.js +107 -0
- package/dist/repo-github/sandbox-egress.d.ts +68 -0
- package/dist/repo-github/sandbox-egress.js +272 -0
- package/dist/repo-github/sandbox-git.d.ts +30 -0
- package/dist/repo-github/sandbox-git.js +113 -0
- package/dist/{repo → repo-github}/tools-checks.js +43 -4
- package/dist/{repo → repo-github}/tools-clone.js +2 -21
- package/dist/{repo → repo-github}/tools-pr.d.ts +0 -1
- package/dist/{repo → repo-github}/tools-pr.js +85 -20
- package/dist/{repo → repo-github}/tools-review.d.ts +6 -0
- package/dist/{repo → repo-github}/tools-review.js +62 -176
- package/dist/{repo → repo-github}/url.d.ts +11 -0
- package/dist/{repo → repo-github}/url.js +12 -1
- package/dist/{workspace → sandbox}/advisory.d.ts +16 -35
- package/dist/{workspace → sandbox}/advisory.js +2 -29
- package/dist/sandbox/agent-exec.d.ts +31 -0
- package/dist/sandbox/agent-exec.js +62 -0
- package/dist/sandbox/ca-trust.d.ts +9 -0
- package/dist/sandbox/ca-trust.js +21 -0
- package/dist/sandbox/constants.d.ts +22 -0
- package/dist/sandbox/constants.js +22 -0
- package/dist/sandbox/daemon/composite.d.ts +9 -0
- package/dist/sandbox/daemon/composite.js +35 -0
- package/dist/sandbox/daemon/index.d.ts +47 -0
- package/dist/sandbox/daemon/index.js +116 -0
- package/dist/sandbox/egress.d.ts +81 -0
- package/dist/sandbox/egress.js +109 -0
- package/dist/sandbox/exec.d.ts +57 -0
- package/dist/sandbox/exec.js +52 -0
- package/dist/sandbox/format.d.ts +2 -0
- package/dist/sandbox/format.js +7 -0
- package/dist/sandbox/header.d.ts +50 -0
- package/dist/sandbox/header.js +94 -0
- package/dist/sandbox/index.d.ts +17 -0
- package/dist/sandbox/index.js +17 -0
- package/dist/{workspace/install.d.ts → sandbox/install-plan.d.ts} +10 -1
- package/dist/{workspace/install.js → sandbox/install-plan.js} +22 -4
- package/dist/sandbox/name.d.ts +27 -0
- package/dist/sandbox/name.js +32 -0
- package/dist/sandbox/object.d.ts +244 -0
- package/dist/sandbox/object.js +1139 -0
- package/dist/scratch/index.d.ts +1 -9
- package/dist/scratch/index.js +2 -18
- package/package.json +26 -22
- package/dist/claude-code/github.d.ts +0 -39
- package/dist/claude-code/github.js +0 -82
- package/dist/claude-code/run.d.ts +0 -474
- package/dist/claude-code/run.js +0 -901
- package/dist/claude-code/session.d.ts +0 -131
- package/dist/claude-code/session.js +0 -285
- package/dist/workspace/ca-trust.d.ts +0 -95
- package/dist/workspace/ca-trust.js +0 -312
- package/dist/workspace/container-deps.d.ts +0 -54
- package/dist/workspace/container-deps.js +0 -224
- package/dist/workspace/container-fault.d.ts +0 -38
- package/dist/workspace/container-fault.js +0 -73
- package/dist/workspace/exec.d.ts +0 -94
- package/dist/workspace/exec.js +0 -153
- package/dist/workspace/format.d.ts +0 -36
- package/dist/workspace/format.js +0 -57
- package/dist/workspace/git-host.d.ts +0 -79
- package/dist/workspace/git-host.js +0 -226
- package/dist/workspace/git-identity.d.ts +0 -57
- package/dist/workspace/git-identity.js +0 -147
- package/dist/workspace/index.d.ts +0 -49
- package/dist/workspace/index.js +0 -58
- package/dist/workspace/install-job.d.ts +0 -121
- package/dist/workspace/install-job.js +0 -866
- package/dist/workspace/object.d.ts +0 -502
- package/dist/workspace/object.js +0 -1427
- package/dist/workspace/open.d.ts +0 -95
- package/dist/workspace/open.js +0 -63
- package/dist/workspace/read.d.ts +0 -16
- package/dist/workspace/read.js +0 -22
- package/dist/workspace/shell.d.ts +0 -45
- package/dist/workspace/shell.js +0 -80
- package/dist/workspace/sync.d.ts +0 -111
- package/dist/workspace/sync.js +0 -124
- package/dist/workspace/wake.d.ts +0 -19
- package/dist/workspace/wake.js +0 -10
- /package/dist/{repo → repo-github}/tools-checks.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-clone.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-worktree.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-worktree.js +0 -0
- /package/dist/{repo → repo-github}/tools-worktrees.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-worktrees.js +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** The host the CLI is pointed at by `ANTHROPIC_BASE_URL`, which the sandbox intercepts. */
|
|
2
|
+
export const ANTHROPIC_PLACEHOLDER_HOST = "anthropic.harness.internal";
|
|
3
|
+
const END = "claude-code-end:";
|
|
4
|
+
const NOTE = "claude-code-note:";
|
|
5
|
+
const SESSION = "claude-code-session:";
|
|
6
|
+
export function encodeRunEnd(end) {
|
|
7
|
+
return `${END}${JSON.stringify(end)}`;
|
|
8
|
+
}
|
|
9
|
+
/** The end in `text`, or `undefined` for a string the daemon did not write — the harness's own `container_lost`, say. */
|
|
10
|
+
export function decodeRunEnd(text) {
|
|
11
|
+
return decode(END, text);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One transcript note, as one message's only text part.
|
|
15
|
+
*
|
|
16
|
+
* The daemon makes the note (`./events.ts` `toProgress`) rather than sending
|
|
17
|
+
* the event, because a card clips its sections and an event does not: a tool's
|
|
18
|
+
* output is whatever the tool printed, and the harness stores every message in
|
|
19
|
+
* a row of the object's SQLite.
|
|
20
|
+
*/
|
|
21
|
+
export function encodeNote(note) {
|
|
22
|
+
return `${NOTE}${JSON.stringify(note)}`;
|
|
23
|
+
}
|
|
24
|
+
export function decodeNote(text) {
|
|
25
|
+
return decode(NOTE, text);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The CLI's session id, as its own message: the handle a host records the
|
|
29
|
+
* moment the `init` line names it, since a session that dies before its end
|
|
30
|
+
* reports no other.
|
|
31
|
+
*/
|
|
32
|
+
export function encodeSessionId(sessionId) {
|
|
33
|
+
return `${SESSION}${JSON.stringify(sessionId)}`;
|
|
34
|
+
}
|
|
35
|
+
export function decodeSessionId(text) {
|
|
36
|
+
return decode(SESSION, text);
|
|
37
|
+
}
|
|
38
|
+
function decode(prefix, text) {
|
|
39
|
+
if (!text?.startsWith(prefix))
|
|
40
|
+
return undefined;
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(text.slice(prefix.length));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -17,19 +17,15 @@
|
|
|
17
17
|
* an agent loop to drive: the session *is* the sub-agent's model —
|
|
18
18
|
* {@link claudeCodeModel} — and Think's recovery drives that. A host binds
|
|
19
19
|
* {@link CLAUDE_CODE_AGENT} to a `SubAgent` class whose `getModel()` returns
|
|
20
|
-
* one, and adds the `prepare` and `settle` that claim and release a
|
|
20
|
+
* one, and adds the `prepare` and `settle` that claim and release a sandbox.
|
|
21
21
|
*
|
|
22
22
|
* ## The credential never enters the container
|
|
23
23
|
*
|
|
24
|
-
* The session is launched with a placeholder
|
|
25
|
-
*
|
|
26
|
-
* Worker side,
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* It can **also** restrict which hosts the container may reach, but that is
|
|
30
|
-
* `restrictToHosts` and it is **off unless a deployment sets it** — so do not
|
|
31
|
-
* read it as a boundary that exists by default. The containment that always
|
|
32
|
-
* holds is the credential swap.
|
|
24
|
+
* The session is launched with a placeholder and a placeholder host. The
|
|
25
|
+
* sandbox's egress rule, {@link claudeCodeEgress}, swaps in a real
|
|
26
|
+
* credential on the Worker side, leased from the pool the sandbox object holds
|
|
27
|
+
* ({@link credentialHost}). The image's daemon runs
|
|
28
|
+
* `@dynamicagents/plugins/claude-code/daemon`'s CLI.
|
|
33
29
|
*
|
|
34
30
|
* ## The 5-hour and weekly limits are routed around, not predicted
|
|
35
31
|
*
|
|
@@ -37,35 +33,29 @@
|
|
|
37
33
|
* guess about a bucket nobody can read, and it only moves when a run *ends* — so
|
|
38
34
|
* it caps nothing, it only refuses to start.
|
|
39
35
|
*
|
|
40
|
-
* The
|
|
36
|
+
* The egress sees Anthropic's actual response, which is the one place the
|
|
41
37
|
* bucket announces itself. So the credential is a **pool**: the first usable
|
|
42
38
|
* entry is used, a refusal marks it spent until its reset and advances the lead,
|
|
43
39
|
* and the client's own retry — prompted by a rewritten `retry-after` — lands on
|
|
44
|
-
* the next one. When every entry is spent the
|
|
45
|
-
*
|
|
46
|
-
* {@link file://./credentials.ts}.
|
|
40
|
+
* the next one. When every entry is spent the run fails cleanly with the reset
|
|
41
|
+
* time. See {@link file://./credentials.ts}.
|
|
47
42
|
*
|
|
48
43
|
* ## Requires
|
|
49
44
|
*
|
|
50
|
-
* One or more `claude setup-token` credentials
|
|
51
|
-
* installed at a pinned version
|
|
52
|
-
* policy is `{ mode: "http-gateway" }` and which supplies a
|
|
53
|
-
* {@link CredentialStore}. See the README.
|
|
45
|
+
* One or more `claude setup-token` credentials and a `/sandbox` image with the
|
|
46
|
+
* CLI installed at a pinned version. See the README.
|
|
54
47
|
*/
|
|
55
|
-
export { claudeCodeModel } from "./model.js";
|
|
56
|
-
export type { ClaudeCodeModelOptions, SessionEnd, SessionOutcome, SessionRecord
|
|
57
|
-
export {
|
|
58
|
-
export type {
|
|
48
|
+
export { claudeCodeModel, CONTAINER_LOST_PROMPT, DEFAULT_TIMEOUT_MS } from "./model.js";
|
|
49
|
+
export type { ClaudeCodeModelOptions, SandboxRuns, SessionEnd, SessionOutcome, SessionRecord } from "./model.js";
|
|
50
|
+
export { ANTHROPIC_HOST, claudeCodeEgress, credentialHost } from "./egress.js";
|
|
51
|
+
export type { ClaudeCodeEgressOptions, CredentialLease } from "./egress.js";
|
|
52
|
+
export { ANTHROPIC_PLACEHOLDER_HOST } from "./harness-wire.js";
|
|
53
|
+
export { CREDENTIAL_PLACEHOLDER } from "./placeholder.js";
|
|
59
54
|
export { CLAUDE_CODE_AGENT, CLAUDE_CODE_WRITE_INPUT, type ClaudeCodeInput } from "./spec.js";
|
|
60
|
-
export { ANTHROPIC_HOST, claudeCodeEgress } from "./egress.js";
|
|
61
55
|
export { VERIFIED_CLAUDE_CODE_VERSION } from "./verified.js";
|
|
62
|
-
export
|
|
63
|
-
export { GITHUB_HOSTS, GITHUB_TOKEN_PLACEHOLDER } from "./github.js";
|
|
64
|
-
export { credentialPool, readRefusal, readRateLimitEvent } from "./credentials.js";
|
|
56
|
+
export { credentialPool, readRefusal } from "./credentials.js";
|
|
65
57
|
export type { CredentialPool, CredentialPoolConfig, CredentialState, CredentialStore, Lead, Refusal } from "./credentials.js";
|
|
66
|
-
export { buildLaunch, CLAUDE_EXEC_PREFIX, CREDENTIAL_PLACEHOLDER, execIdFor, followUpExecIdFor, freshCursor } from "./run.js";
|
|
67
|
-
export type { DrainCursor, DrainOptions, DrainOutcome, Launch, LaunchOptions, SessionRuntime } from "./run.js";
|
|
68
58
|
export { parseStream, toProgress, RATE_LIMIT_OK } from "./events.js";
|
|
69
59
|
export type { ClaudeCodeEvent, ClaudeCodeResult, ClaudeCodeUsage, RateLimitInfo } from "./events.js";
|
|
70
|
-
export { DEFAULT_PERMISSION_MODE
|
|
60
|
+
export { DEFAULT_PERMISSION_MODE } from "./config.js";
|
|
71
61
|
export type { ClaudeCodeConfig, EffortLevel, PermissionMode } from "./config.js";
|
|
@@ -17,19 +17,15 @@
|
|
|
17
17
|
* an agent loop to drive: the session *is* the sub-agent's model —
|
|
18
18
|
* {@link claudeCodeModel} — and Think's recovery drives that. A host binds
|
|
19
19
|
* {@link CLAUDE_CODE_AGENT} to a `SubAgent` class whose `getModel()` returns
|
|
20
|
-
* one, and adds the `prepare` and `settle` that claim and release a
|
|
20
|
+
* one, and adds the `prepare` and `settle` that claim and release a sandbox.
|
|
21
21
|
*
|
|
22
22
|
* ## The credential never enters the container
|
|
23
23
|
*
|
|
24
|
-
* The session is launched with a placeholder
|
|
25
|
-
*
|
|
26
|
-
* Worker side,
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* It can **also** restrict which hosts the container may reach, but that is
|
|
30
|
-
* `restrictToHosts` and it is **off unless a deployment sets it** — so do not
|
|
31
|
-
* read it as a boundary that exists by default. The containment that always
|
|
32
|
-
* holds is the credential swap.
|
|
24
|
+
* The session is launched with a placeholder and a placeholder host. The
|
|
25
|
+
* sandbox's egress rule, {@link claudeCodeEgress}, swaps in a real
|
|
26
|
+
* credential on the Worker side, leased from the pool the sandbox object holds
|
|
27
|
+
* ({@link credentialHost}). The image's daemon runs
|
|
28
|
+
* `@dynamicagents/plugins/claude-code/daemon`'s CLI.
|
|
33
29
|
*
|
|
34
30
|
* ## The 5-hour and weekly limits are routed around, not predicted
|
|
35
31
|
*
|
|
@@ -37,28 +33,24 @@
|
|
|
37
33
|
* guess about a bucket nobody can read, and it only moves when a run *ends* — so
|
|
38
34
|
* it caps nothing, it only refuses to start.
|
|
39
35
|
*
|
|
40
|
-
* The
|
|
36
|
+
* The egress sees Anthropic's actual response, which is the one place the
|
|
41
37
|
* bucket announces itself. So the credential is a **pool**: the first usable
|
|
42
38
|
* entry is used, a refusal marks it spent until its reset and advances the lead,
|
|
43
39
|
* and the client's own retry — prompted by a rewritten `retry-after` — lands on
|
|
44
|
-
* the next one. When every entry is spent the
|
|
45
|
-
*
|
|
46
|
-
* {@link file://./credentials.ts}.
|
|
40
|
+
* the next one. When every entry is spent the run fails cleanly with the reset
|
|
41
|
+
* time. See {@link file://./credentials.ts}.
|
|
47
42
|
*
|
|
48
43
|
* ## Requires
|
|
49
44
|
*
|
|
50
|
-
* One or more `claude setup-token` credentials
|
|
51
|
-
* installed at a pinned version
|
|
52
|
-
* policy is `{ mode: "http-gateway" }` and which supplies a
|
|
53
|
-
* {@link CredentialStore}. See the README.
|
|
45
|
+
* One or more `claude setup-token` credentials and a `/sandbox` image with the
|
|
46
|
+
* CLI installed at a pinned version. See the README.
|
|
54
47
|
*/
|
|
55
|
-
export { claudeCodeModel } from "./model.js";
|
|
56
|
-
export {
|
|
48
|
+
export { claudeCodeModel, CONTAINER_LOST_PROMPT, DEFAULT_TIMEOUT_MS } from "./model.js";
|
|
49
|
+
export { ANTHROPIC_HOST, claudeCodeEgress, credentialHost } from "./egress.js";
|
|
50
|
+
export { ANTHROPIC_PLACEHOLDER_HOST } from "./harness-wire.js";
|
|
51
|
+
export { CREDENTIAL_PLACEHOLDER } from "./placeholder.js";
|
|
57
52
|
export { CLAUDE_CODE_AGENT, CLAUDE_CODE_WRITE_INPUT } from "./spec.js";
|
|
58
|
-
export { ANTHROPIC_HOST, claudeCodeEgress } from "./egress.js";
|
|
59
53
|
export { VERIFIED_CLAUDE_CODE_VERSION } from "./verified.js";
|
|
60
|
-
export {
|
|
61
|
-
export { credentialPool, readRefusal, readRateLimitEvent } from "./credentials.js";
|
|
62
|
-
export { buildLaunch, CLAUDE_EXEC_PREFIX, CREDENTIAL_PLACEHOLDER, execIdFor, followUpExecIdFor, freshCursor } from "./run.js";
|
|
54
|
+
export { credentialPool, readRefusal } from "./credentials.js";
|
|
63
55
|
export { parseStream, toProgress, RATE_LIMIT_OK } from "./events.js";
|
|
64
|
-
export { DEFAULT_PERMISSION_MODE
|
|
56
|
+
export { DEFAULT_PERMISSION_MODE } from "./config.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
/**
|
|
3
|
+
* A run whose only output is its report, as a sub-agent's model.
|
|
4
|
+
*
|
|
5
|
+
* Both Claude Code models are this: the session is the whole turn, so the
|
|
6
|
+
* stream carries nothing but the report, and Think's stall watchdog is off, so
|
|
7
|
+
* a silent stream is not cut.
|
|
8
|
+
*/
|
|
9
|
+
/** The provider interface this implements, read off `ai` rather than imported. */
|
|
10
|
+
export type LanguageModelV3 = Extract<LanguageModel, {
|
|
11
|
+
specificationVersion: "v3";
|
|
12
|
+
}>;
|
|
13
|
+
export type CallOptions = Parameters<LanguageModelV3["doStream"]>[0];
|
|
14
|
+
export declare function reportingModel(modelId: string, run: (call: CallOptions) => Promise<string>): LanguageModelV3;
|
|
15
|
+
/**
|
|
16
|
+
* The task: the last user message's text. On a continued turn the prompt ends
|
|
17
|
+
* with the interrupted assistant message, so the last message is not it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function lastUserText(prompt: CallOptions["prompt"]): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** Zeroed: the session's tokens are the CLI's context, not this conversation's. */
|
|
2
|
+
const USAGE = {
|
|
3
|
+
inputTokens: {
|
|
4
|
+
total: 0,
|
|
5
|
+
noCache: 0,
|
|
6
|
+
cacheRead: 0,
|
|
7
|
+
cacheWrite: 0
|
|
8
|
+
},
|
|
9
|
+
outputTokens: { total: 0, text: 0, reasoning: 0 }
|
|
10
|
+
};
|
|
11
|
+
export function reportingModel(modelId, run) {
|
|
12
|
+
return {
|
|
13
|
+
specificationVersion: "v3",
|
|
14
|
+
provider: "claude-code",
|
|
15
|
+
modelId,
|
|
16
|
+
supportedUrls: {},
|
|
17
|
+
async doStream(call) {
|
|
18
|
+
// The stream is returned at once and the session runs inside it, so
|
|
19
|
+
// nothing waits on a promise for the length of a session.
|
|
20
|
+
const stream = new ReadableStream({
|
|
21
|
+
async start(controller) {
|
|
22
|
+
controller.enqueue({ type: "stream-start", warnings: [] });
|
|
23
|
+
try {
|
|
24
|
+
const text = await run(call);
|
|
25
|
+
controller.enqueue({ type: "text-start", id: "report" });
|
|
26
|
+
controller.enqueue({
|
|
27
|
+
type: "text-delta",
|
|
28
|
+
id: "report",
|
|
29
|
+
delta: text
|
|
30
|
+
});
|
|
31
|
+
controller.enqueue({ type: "text-end", id: "report" });
|
|
32
|
+
controller.enqueue({
|
|
33
|
+
type: "finish",
|
|
34
|
+
usage: USAGE,
|
|
35
|
+
finishReason: { unified: "stop", raw: undefined }
|
|
36
|
+
});
|
|
37
|
+
controller.close();
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
controller.error(err);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return { stream };
|
|
45
|
+
},
|
|
46
|
+
async doGenerate(call) {
|
|
47
|
+
const text = await run(call);
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text }],
|
|
50
|
+
finishReason: { unified: "stop", raw: undefined },
|
|
51
|
+
usage: USAGE,
|
|
52
|
+
warnings: []
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The task: the last user message's text. On a continued turn the prompt ends
|
|
59
|
+
* with the interrupted assistant message, so the last message is not it.
|
|
60
|
+
*/
|
|
61
|
+
export function lastUserText(prompt) {
|
|
62
|
+
for (let i = prompt.length - 1; i >= 0; i--) {
|
|
63
|
+
const message = prompt[i];
|
|
64
|
+
if (message.role !== "user")
|
|
65
|
+
continue;
|
|
66
|
+
return message.content
|
|
67
|
+
.map((part) => (part.type === "text" ? part.text : ""))
|
|
68
|
+
.join("");
|
|
69
|
+
}
|
|
70
|
+
throw new Error("claude-code: the run has no task — no user message");
|
|
71
|
+
}
|
|
@@ -1,31 +1,9 @@
|
|
|
1
|
-
import type { LanguageModel } from "ai";
|
|
2
1
|
import type { ArtifactEntryDetail } from "@dynamicagents/core/artifacts";
|
|
3
|
-
import type {
|
|
2
|
+
import type { PollResult } from "../sandbox/object.js";
|
|
3
|
+
import type { EffortLevel, PermissionMode } from "./config.js";
|
|
4
4
|
import type { ClaudeCodeResult, RateLimitInfo } from "./events.js";
|
|
5
|
-
import { type
|
|
6
|
-
/**
|
|
7
|
-
* A Claude Code session as a sub-agent's **model**.
|
|
8
|
-
*
|
|
9
|
-
* Claude Code brings its own tools, its own loop and its own context, so there
|
|
10
|
-
* is nothing for Think to drive but the one call that runs it — and making that
|
|
11
|
-
* call the model is what puts the session under Think's recovery. A turn cut by
|
|
12
|
-
* an eviction or a deploy is continued; the continuation calls `doStream`
|
|
13
|
-
* again, and every step below it has already taken is stored, so it resumes
|
|
14
|
-
* where it was: the session is re-attached from its cursor, and a report
|
|
15
|
-
* already made is emitted again rather than made again.
|
|
16
|
-
*
|
|
17
|
-
* ## The report is the only text
|
|
18
|
-
*
|
|
19
|
-
* A run's result is what its assistant messages say, so narration streamed as
|
|
20
|
-
* text would become the result and bury the report. What the session says as
|
|
21
|
-
* it works goes to the parent as notes instead, through `note`. Nothing else is
|
|
22
|
-
* streamed at all: Think's stall watchdog is off, so a silent stream is not cut.
|
|
23
|
-
*/
|
|
24
|
-
/** The provider interface this implements, read off `ai` rather than imported. */
|
|
25
|
-
type LanguageModelV3 = Extract<LanguageModel, {
|
|
26
|
-
specificationVersion: "v3";
|
|
27
|
-
}>;
|
|
28
|
-
/** How one exec of a session ended. */
|
|
5
|
+
import { type LanguageModelV3 } from "./language-model.js";
|
|
6
|
+
/** How one turn of a session ended. */
|
|
29
7
|
export interface SessionEnd {
|
|
30
8
|
exitCode: number;
|
|
31
9
|
/** Absent when the process died without ever emitting a `result` line. */
|
|
@@ -35,13 +13,13 @@ export interface SessionEnd {
|
|
|
35
13
|
/** The subscription bucket as the client last reported it, if it did. */
|
|
36
14
|
rateLimit?: RateLimitInfo;
|
|
37
15
|
/**
|
|
38
|
-
* The Claude Code session id, from the `init` line by way of the
|
|
39
|
-
*
|
|
16
|
+
* The Claude Code session id, from the `init` line by way of the daemon's
|
|
17
|
+
* parser.
|
|
40
18
|
*
|
|
41
19
|
* Here as well as on `result` because the sessions worth continuing are often
|
|
42
|
-
* the ones with no result: a session ended by its time limit
|
|
43
|
-
*
|
|
44
|
-
*
|
|
20
|
+
* the ones with no result: a session ended by its time limit or a cancel
|
|
21
|
+
* reports none, and this is then the only handle to the conversation it got
|
|
22
|
+
* half-way through.
|
|
45
23
|
*/
|
|
46
24
|
sessionId?: string;
|
|
47
25
|
}
|
|
@@ -69,60 +47,82 @@ export interface SessionOutcome {
|
|
|
69
47
|
/** The follow-up's end, when `followUp` asked for one. */
|
|
70
48
|
followUp?: SessionEnd;
|
|
71
49
|
}
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
|
|
50
|
+
/**
|
|
51
|
+
* A Claude Code session in a sandbox, as a sub-agent's model.
|
|
52
|
+
*
|
|
53
|
+
* Claude Code brings its own tools, its own loop and its own context, so there
|
|
54
|
+
* is nothing for Think to drive but the one call that runs it — and making that
|
|
55
|
+
* call the model is what puts the session under Think's recovery. The report
|
|
56
|
+
* is its only text: what the session says as it works goes to the parent as
|
|
57
|
+
* notes, through `note`. Every step's outcome is kept in the sub-agent's
|
|
58
|
+
* storage, so a recovered turn picks up where it was. What can be lost:
|
|
59
|
+
*
|
|
60
|
+
* - **Nothing streams.** The session runs as a harness operation the sandbox
|
|
61
|
+
* keeps, and this polls it. A poll is short, so a reset of either object
|
|
62
|
+
* costs one poll, and Think's recovery of this turn polls the same operation.
|
|
63
|
+
* - **A lost container resumes the session.** The operation settles as
|
|
64
|
+
* `container_lost`, and this submits the next attempt to the same harness
|
|
65
|
+
* session, whose CLI conversation the harness kept: the session is told what
|
|
66
|
+
* happened, not briefed again.
|
|
67
|
+
*/
|
|
68
|
+
/** The sandbox RPCs a run uses. */
|
|
69
|
+
export interface SandboxRuns {
|
|
70
|
+
createRun(runId: string, options: {
|
|
71
|
+
cwd: string;
|
|
72
|
+
forkOf?: string;
|
|
73
|
+
continues?: string;
|
|
74
|
+
}): Promise<{
|
|
75
|
+
sessionId: string;
|
|
76
|
+
created: boolean;
|
|
77
|
+
}>;
|
|
78
|
+
submit(runId: string, text: string, operationId: string): Promise<{
|
|
79
|
+
operationId: string;
|
|
80
|
+
accepted: boolean;
|
|
81
|
+
}>;
|
|
82
|
+
poll(runId: string, operationId: string, waitMs?: number, from?: number): Promise<PollResult>;
|
|
83
|
+
stopRun(runId: string): Promise<{
|
|
84
|
+
stopped: boolean;
|
|
85
|
+
}>;
|
|
75
86
|
}
|
|
76
87
|
export interface ClaudeCodeModelOptions {
|
|
77
|
-
config: ClaudeCodeConfig;
|
|
78
88
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* object through a new stub rather than one held from the last.
|
|
89
|
+
* The sandbox the run is in. Called again after a failed call, so each call
|
|
90
|
+
* should reach the object through a new stub.
|
|
82
91
|
*/
|
|
83
|
-
|
|
92
|
+
sandbox: () => SandboxRuns;
|
|
84
93
|
/** The sub-agent's own storage, where every step's outcome is kept. */
|
|
85
94
|
storage: DurableObjectStorage;
|
|
86
|
-
/** The sub-agent's name, which is the run's id
|
|
95
|
+
/** The sub-agent's name, which is the run's id in the sandbox. */
|
|
87
96
|
runId: string;
|
|
88
|
-
/** The checkout
|
|
97
|
+
/** The checkout, under the sandbox's `/workspace`. */
|
|
89
98
|
dir: string;
|
|
90
|
-
/**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* This run's mode, over {@link file://./config.ts ClaudeCodeConfig.permissionMode}.
|
|
97
|
-
*
|
|
98
|
-
* A planning run is a writing session under `plan` with a `jsonSchema`: it
|
|
99
|
-
* reads, edits nothing, and answers through `StructuredOutput` rather than an
|
|
100
|
-
* approval nobody is there to give. Carrying the plan out is a later run that
|
|
101
|
-
* resumes it with `fork` under the config's mode — the CLI takes a new
|
|
102
|
-
* `--permission-mode` on `--resume` — so the plan's own conversation stays
|
|
103
|
-
* whole for an edit.
|
|
104
|
-
*/
|
|
99
|
+
/** The CLI's model. Unset, the daemon's. */
|
|
100
|
+
model?: string;
|
|
101
|
+
effort?: EffortLevel;
|
|
102
|
+
/** A JSON schema the daemon was built with, by name, that the answer must match. */
|
|
103
|
+
schema?: string;
|
|
104
|
+
/** `plan` runs read-only and answers to {@link schema}; anything else is the daemon's mode. */
|
|
105
105
|
permissionMode?: PermissionMode;
|
|
106
106
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* Resolved by the host, in `prepare`, against whatever it recorded through
|
|
111
|
-
* {@link ClaudeCodeModelOptions.onSession}: which conversations exist in a
|
|
112
|
-
* workspace, and which of them a caller may continue, are the host's
|
|
113
|
-
* questions. The run's prompt is then the next user turn — its `brief` hook
|
|
114
|
-
* is the place to say what changed and nothing the session already holds.
|
|
107
|
+
* Another run in this sandbox whose conversation this one carries on: as more
|
|
108
|
+
* of it, or with `fork`, as a new branch of it. Its prompt is then the next
|
|
109
|
+
* user turn.
|
|
115
110
|
*/
|
|
116
111
|
resume?: {
|
|
117
|
-
|
|
112
|
+
run: string;
|
|
118
113
|
fork?: boolean;
|
|
119
114
|
};
|
|
120
115
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
|
|
116
|
+
* How long a session may run, from its first submission, before it is
|
|
117
|
+
* stopped. Default {@link DEFAULT_TIMEOUT_MS}.
|
|
118
|
+
*/
|
|
119
|
+
timeoutMs?: number;
|
|
120
|
+
/**
|
|
121
|
+
* File one note on the parent's transcript. `at` is when the daemon read the
|
|
122
|
+
* line it came from: a poll files a batch at once, so the filing time would
|
|
123
|
+
* give a tool's call and its result the same moment.
|
|
124
124
|
*/
|
|
125
|
-
note: (key: string, text: string, detail?: ArtifactEntryDetail) => Promise<void>;
|
|
125
|
+
note: (key: string, text: string, detail?: ArtifactEntryDetail, at?: number) => Promise<void>;
|
|
126
126
|
/**
|
|
127
127
|
* The session's handle, as soon as there is one and again when the session
|
|
128
128
|
* ends — see {@link SessionRecord}.
|
|
@@ -148,5 +148,12 @@ export interface ClaudeCodeModelOptions {
|
|
|
148
148
|
/** The text the parent receives. Run once, and kept. */
|
|
149
149
|
report: (outcome: SessionOutcome) => Promise<string>;
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Three hours: a ceiling on a session that has stopped making progress, not a
|
|
153
|
+
* budget for one that is. No timer in the sandbox races it, since the
|
|
154
|
+
* container's idle stop never fires while an operation is open.
|
|
155
|
+
*/
|
|
156
|
+
export declare const DEFAULT_TIMEOUT_MS: number;
|
|
157
|
+
/** What a session is told when it resumes in a new container. */
|
|
158
|
+
export declare const CONTAINER_LOST_PROMPT: string;
|
|
151
159
|
export declare function claudeCodeModel(options: ClaudeCodeModelOptions): LanguageModelV3;
|
|
152
|
-
export {};
|