@alpacakit/agents 0.1.0-beta.19
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 +21 -0
- package/README.md +224 -0
- package/dist/agents/builtin.d.ts +19 -0
- package/dist/agents/builtin.d.ts.map +1 -0
- package/dist/agents/builtin.js +14 -0
- package/dist/agents/claude.d.ts +20 -0
- package/dist/agents/claude.d.ts.map +1 -0
- package/dist/agents/claude.js +480 -0
- package/dist/agents/codex.d.ts +19 -0
- package/dist/agents/codex.d.ts.map +1 -0
- package/dist/agents/codex.js +355 -0
- package/dist/agents/openai-compatible/config.d.ts +16 -0
- package/dist/agents/openai-compatible/config.d.ts.map +1 -0
- package/dist/agents/openai-compatible/config.js +160 -0
- package/dist/agents/openai-compatible/engine.d.ts +18 -0
- package/dist/agents/openai-compatible/engine.d.ts.map +1 -0
- package/dist/agents/openai-compatible/engine.js +10 -0
- package/dist/agents/openai-compatible/fetch-engine.d.ts +38 -0
- package/dist/agents/openai-compatible/fetch-engine.d.ts.map +1 -0
- package/dist/agents/openai-compatible/fetch-engine.js +216 -0
- package/dist/agents/openai-compatible/pi/engine.d.ts +32 -0
- package/dist/agents/openai-compatible/pi/engine.d.ts.map +1 -0
- package/dist/agents/openai-compatible/pi/engine.js +98 -0
- package/dist/agents/openai-compatible/pi/module.d.ts +87 -0
- package/dist/agents/openai-compatible/pi/module.d.ts.map +1 -0
- package/dist/agents/openai-compatible/pi/module.js +43 -0
- package/dist/agents/openai-compatible/pi/sandbox.d.ts +25 -0
- package/dist/agents/openai-compatible/pi/sandbox.d.ts.map +1 -0
- package/dist/agents/openai-compatible/pi/sandbox.js +69 -0
- package/dist/agents/openai-compatible/pi/session.d.ts +17 -0
- package/dist/agents/openai-compatible/pi/session.d.ts.map +1 -0
- package/dist/agents/openai-compatible/pi/session.js +354 -0
- package/dist/agents/openai-compatible/response.d.ts +19 -0
- package/dist/agents/openai-compatible/response.d.ts.map +1 -0
- package/dist/agents/openai-compatible/response.js +203 -0
- package/dist/agents/openai-compatible/types.d.ts +34 -0
- package/dist/agents/openai-compatible/types.d.ts.map +1 -0
- package/dist/agents/openai-compatible/types.js +1 -0
- package/dist/agents/openai-compatible.d.ts +12 -0
- package/dist/agents/openai-compatible.d.ts.map +1 -0
- package/dist/agents/openai-compatible.js +45 -0
- package/dist/auth/login-probe.d.ts +21 -0
- package/dist/auth/login-probe.d.ts.map +1 -0
- package/dist/auth/login-probe.js +47 -0
- package/dist/auth/login.d.ts +79 -0
- package/dist/auth/login.d.ts.map +1 -0
- package/dist/auth/login.js +9 -0
- package/dist/auth/material.d.ts +87 -0
- package/dist/auth/material.d.ts.map +1 -0
- package/dist/auth/material.js +59 -0
- package/dist/auth/profile-store.d.ts +14 -0
- package/dist/auth/profile-store.d.ts.map +1 -0
- package/dist/auth/profile-store.js +101 -0
- package/dist/auth/secrets.d.ts +14 -0
- package/dist/auth/secrets.d.ts.map +1 -0
- package/dist/auth/secrets.js +40 -0
- package/dist/codex/app-server.d.ts +30 -0
- package/dist/codex/app-server.d.ts.map +1 -0
- package/dist/codex/app-server.js +322 -0
- package/dist/codex/index.d.ts +3 -0
- package/dist/codex/index.d.ts.map +1 -0
- package/dist/codex/index.js +1 -0
- package/dist/codex/protocol.d.ts +124 -0
- package/dist/codex/protocol.d.ts.map +1 -0
- package/dist/codex/protocol.js +283 -0
- package/dist/config/agent-config-validation.d.ts +22 -0
- package/dist/config/agent-config-validation.d.ts.map +1 -0
- package/dist/config/agent-config-validation.js +31 -0
- package/dist/config/agent-configs.d.ts +37 -0
- package/dist/config/agent-configs.d.ts.map +1 -0
- package/dist/config/agent-configs.js +214 -0
- package/dist/config/compose.d.ts +10 -0
- package/dist/config/compose.d.ts.map +1 -0
- package/dist/config/compose.js +89 -0
- package/dist/config/config.d.ts +21 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +33 -0
- package/dist/config/errors.d.ts +45 -0
- package/dist/config/errors.d.ts.map +1 -0
- package/dist/config/errors.js +37 -0
- package/dist/config/extension.d.ts +3 -0
- package/dist/config/extension.d.ts.map +1 -0
- package/dist/config/extension.js +1 -0
- package/dist/config/ids.d.ts +8 -0
- package/dist/config/ids.d.ts.map +1 -0
- package/dist/config/ids.js +4 -0
- package/dist/config/index.d.ts +12 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/model.d.ts +105 -0
- package/dist/config/model.d.ts.map +1 -0
- package/dist/config/model.js +1 -0
- package/dist/config/paths.d.ts +7 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +10 -0
- package/dist/config/schema.d.ts +59 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +83 -0
- package/dist/config/store.d.ts +34 -0
- package/dist/config/store.d.ts.map +1 -0
- package/dist/config/store.js +420 -0
- package/dist/config/support.d.ts +14 -0
- package/dist/config/support.d.ts.map +1 -0
- package/dist/config/support.js +32 -0
- package/dist/config/values.d.ts +21 -0
- package/dist/config/values.d.ts.map +1 -0
- package/dist/config/values.js +22 -0
- package/dist/config/xdg.d.ts +20 -0
- package/dist/config/xdg.d.ts.map +1 -0
- package/dist/config/xdg.js +23 -0
- package/dist/core/async-queue.d.ts +14 -0
- package/dist/core/async-queue.d.ts.map +1 -0
- package/dist/core/async-queue.js +46 -0
- package/dist/core/env.d.ts +19 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/env.js +39 -0
- package/dist/core/error.d.ts +121 -0
- package/dist/core/error.d.ts.map +1 -0
- package/dist/core/error.js +88 -0
- package/dist/core/fs.d.ts +16 -0
- package/dist/core/fs.d.ts.map +1 -0
- package/dist/core/fs.js +30 -0
- package/dist/core/json.d.ts +20 -0
- package/dist/core/json.d.ts.map +1 -0
- package/dist/core/json.js +42 -0
- package/dist/core/node-ports.d.ts +9 -0
- package/dist/core/node-ports.d.ts.map +1 -0
- package/dist/core/node-ports.js +135 -0
- package/dist/core/ports.d.ts +71 -0
- package/dist/core/ports.d.ts.map +1 -0
- package/dist/core/ports.js +19 -0
- package/dist/core/redact.d.ts +8 -0
- package/dist/core/redact.d.ts.map +1 -0
- package/dist/core/redact.js +66 -0
- package/dist/core/run.d.ts +125 -0
- package/dist/core/run.d.ts.map +1 -0
- package/dist/core/run.js +27 -0
- package/dist/core/values.d.ts +12 -0
- package/dist/core/values.d.ts.map +1 -0
- package/dist/core/values.js +9 -0
- package/dist/corpus/failure-corpus.d.ts +21 -0
- package/dist/corpus/failure-corpus.d.ts.map +1 -0
- package/dist/corpus/failure-corpus.js +89 -0
- package/dist/fleet/fleet.d.ts +120 -0
- package/dist/fleet/fleet.d.ts.map +1 -0
- package/dist/fleet/fleet.js +409 -0
- package/dist/fleet/policy.d.ts +45 -0
- package/dist/fleet/policy.d.ts.map +1 -0
- package/dist/fleet/policy.js +50 -0
- package/dist/fleet/store.d.ts +28 -0
- package/dist/fleet/store.d.ts.map +1 -0
- package/dist/fleet/store.js +225 -0
- package/dist/host/capabilities.d.ts +146 -0
- package/dist/host/capabilities.d.ts.map +1 -0
- package/dist/host/capabilities.js +59 -0
- package/dist/host/context.d.ts +29 -0
- package/dist/host/context.d.ts.map +1 -0
- package/dist/host/context.js +11 -0
- package/dist/host/github-dir.d.ts +16 -0
- package/dist/host/github-dir.d.ts.map +1 -0
- package/dist/host/github-dir.js +164 -0
- package/dist/host/mcp-list.d.ts +12 -0
- package/dist/host/mcp-list.d.ts.map +1 -0
- package/dist/host/mcp-list.js +122 -0
- package/dist/host/requirement-ref.d.ts +12 -0
- package/dist/host/requirement-ref.d.ts.map +1 -0
- package/dist/host/requirement-ref.js +40 -0
- package/dist/host/run-command.d.ts +27 -0
- package/dist/host/run-command.d.ts.map +1 -0
- package/dist/host/run-command.js +66 -0
- package/dist/host/validate-spec.d.ts +10 -0
- package/dist/host/validate-spec.d.ts.map +1 -0
- package/dist/host/validate-spec.js +69 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/kernel/classify.d.ts +44 -0
- package/dist/kernel/classify.d.ts.map +1 -0
- package/dist/kernel/classify.js +136 -0
- package/dist/kernel/cli-agent.d.ts +62 -0
- package/dist/kernel/cli-agent.d.ts.map +1 -0
- package/dist/kernel/cli-agent.js +281 -0
- package/dist/kernel/cli-login.d.ts +13 -0
- package/dist/kernel/cli-login.d.ts.map +1 -0
- package/dist/kernel/cli-login.js +199 -0
- package/dist/kernel/definition.d.ts +41 -0
- package/dist/kernel/definition.d.ts.map +1 -0
- package/dist/kernel/definition.js +13 -0
- package/dist/kernel/env-template.d.ts +17 -0
- package/dist/kernel/env-template.d.ts.map +1 -0
- package/dist/kernel/env-template.js +78 -0
- package/dist/kernel/facets.d.ts +58 -0
- package/dist/kernel/facets.d.ts.map +1 -0
- package/dist/kernel/facets.js +102 -0
- package/dist/kernel/guard.d.ts +24 -0
- package/dist/kernel/guard.d.ts.map +1 -0
- package/dist/kernel/guard.js +69 -0
- package/dist/kernel/handle.d.ts +29 -0
- package/dist/kernel/handle.d.ts.map +1 -0
- package/dist/kernel/handle.js +97 -0
- package/dist/kernel/keyed.d.ts +19 -0
- package/dist/kernel/keyed.d.ts.map +1 -0
- package/dist/kernel/keyed.js +35 -0
- package/dist/kernel/login.d.ts +20 -0
- package/dist/kernel/login.d.ts.map +1 -0
- package/dist/kernel/login.js +74 -0
- package/dist/kernel/options.d.ts +73 -0
- package/dist/kernel/options.d.ts.map +1 -0
- package/dist/kernel/options.js +41 -0
- package/dist/kernel/run.d.ts +20 -0
- package/dist/kernel/run.d.ts.map +1 -0
- package/dist/kernel/run.js +245 -0
- package/dist/kernel/runtime.d.ts +48 -0
- package/dist/kernel/runtime.d.ts.map +1 -0
- package/dist/kernel/runtime.js +108 -0
- package/dist/keyring/index.d.ts +2 -0
- package/dist/keyring/index.d.ts.map +1 -0
- package/dist/keyring/index.js +1 -0
- package/dist/keyring/resolver.d.ts +9 -0
- package/dist/keyring/resolver.d.ts.map +1 -0
- package/dist/keyring/resolver.js +62 -0
- package/dist/run-agent.d.ts +19 -0
- package/dist/run-agent.d.ts.map +1 -0
- package/dist/run-agent.js +25 -0
- package/dist/structured/extract.d.ts +27 -0
- package/dist/structured/extract.d.ts.map +1 -0
- package/dist/structured/extract.js +188 -0
- package/dist/structured/run-structured.d.ts +83 -0
- package/dist/structured/run-structured.d.ts.map +1 -0
- package/dist/structured/run-structured.js +202 -0
- package/dist/structured/standard-schema.d.ts +34 -0
- package/dist/structured/standard-schema.d.ts.map +1 -0
- package/dist/structured/standard-schema.js +6 -0
- package/dist/testing/fake-agent.d.ts +32 -0
- package/dist/testing/fake-agent.d.ts.map +1 -0
- package/dist/testing/fake-agent.js +43 -0
- package/dist/testing/fake-clock.d.ts +8 -0
- package/dist/testing/fake-clock.d.ts.map +1 -0
- package/dist/testing/fake-clock.js +44 -0
- package/dist/testing/fake-exec.d.ts +26 -0
- package/dist/testing/fake-exec.d.ts.map +1 -0
- package/dist/testing/fake-exec.js +69 -0
- package/dist/testing/fake-secrets.d.ts +3 -0
- package/dist/testing/fake-secrets.d.ts.map +1 -0
- package/dist/testing/fake-secrets.js +5 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +9 -0
- package/package.json +75 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure classification (design "Errors"): the matcher contract, the
|
|
3
|
+
* combinators custom agents build on, cooldown-hint parsing, and the
|
|
4
|
+
* generic quota / auth free-text matchers shared by every agent
|
|
5
|
+
* (v1 F3/F5 signals, kept verbatim). Provider-specific matchers live on
|
|
6
|
+
* their adapter modules and enter via the blueprints' `classify` arrays.
|
|
7
|
+
*/
|
|
8
|
+
import { AGENT_ERROR_CODE, AUTH_FAILURE_REASON } from "../core/error.js";
|
|
9
|
+
function combinedText(evidence) {
|
|
10
|
+
return `${evidence.stderr}\n${evidence.stdout}`;
|
|
11
|
+
}
|
|
12
|
+
const ISO_TIMESTAMP = /\b(20\d{2}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)\b/;
|
|
13
|
+
const EPOCH_AFTER_RESET = /\b(?:reset|retry[- ]after)\b[^0-9]*(\d{10,13})\b/i;
|
|
14
|
+
const RETRY_AFTER_SECONDS = /retry[- ]after[: ]+(\d+)(?:\s*(?:seconds?|secs?|s))?/i;
|
|
15
|
+
const RELATIVE_IN_UNITS = /(?:try again|retry|reset)[^\n]*?\bin\s+(\d+)\s*(seconds?|secs?|minutes?|mins?|hours?|hrs?)/i;
|
|
16
|
+
function unitMultiplierMs(unit) {
|
|
17
|
+
if (unit.startsWith("hour") || unit.startsWith("hr")) {
|
|
18
|
+
return 3_600_000;
|
|
19
|
+
}
|
|
20
|
+
if (unit.startsWith("min")) {
|
|
21
|
+
return 60_000;
|
|
22
|
+
}
|
|
23
|
+
return 1_000;
|
|
24
|
+
}
|
|
25
|
+
export function parseEpochTimestamp(value) {
|
|
26
|
+
const ms = value >= 1e12 ? value : value * 1000;
|
|
27
|
+
return new Date(ms).toISOString();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Cooldown-time parsing (F3): ISO timestamps, epoch digits after
|
|
31
|
+
* reset/retry-after, "retry after N s", and relative "in N minutes".
|
|
32
|
+
*/
|
|
33
|
+
export function parseCooldownHint(text, now) {
|
|
34
|
+
const iso = text.match(ISO_TIMESTAMP);
|
|
35
|
+
if (iso?.[1] !== undefined) {
|
|
36
|
+
return iso[1];
|
|
37
|
+
}
|
|
38
|
+
const epoch = text.match(EPOCH_AFTER_RESET);
|
|
39
|
+
if (epoch?.[1] !== undefined) {
|
|
40
|
+
return parseEpochTimestamp(Number(epoch[1]));
|
|
41
|
+
}
|
|
42
|
+
const seconds = text.match(RETRY_AFTER_SECONDS);
|
|
43
|
+
if (seconds?.[1] !== undefined) {
|
|
44
|
+
return new Date(now + Number(seconds[1]) * 1000).toISOString();
|
|
45
|
+
}
|
|
46
|
+
const relative = text.match(RELATIVE_IN_UNITS);
|
|
47
|
+
if (relative?.[1] !== undefined && relative[2] !== undefined) {
|
|
48
|
+
return new Date(now + Number(relative[1]) * unitMultiplierMs(relative[2])).toISOString();
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/** Matcher combinator: classify as quota when the pattern matches. */
|
|
53
|
+
export function quotaIf(pattern) {
|
|
54
|
+
return (evidence) => {
|
|
55
|
+
const text = combinedText(evidence);
|
|
56
|
+
if (!pattern.test(text)) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
code: AGENT_ERROR_CODE.quota,
|
|
61
|
+
message: "Provider quota or rate limit reached",
|
|
62
|
+
data: { cooldownUntil: parseCooldownHint(text, evidence.now) },
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Matcher combinator: classify as capacity when the pattern matches. */
|
|
67
|
+
export function capacityIf(pattern) {
|
|
68
|
+
return (evidence) => {
|
|
69
|
+
const text = combinedText(evidence);
|
|
70
|
+
if (!pattern.test(text)) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
code: AGENT_ERROR_CODE.capacity,
|
|
75
|
+
message: "Provider is at capacity",
|
|
76
|
+
data: { cooldownUntil: parseCooldownHint(text, evidence.now) },
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const AUTH_REASON_MARKERS = [
|
|
81
|
+
[/\brefresh_token_reused\b/i, AUTH_FAILURE_REASON.refreshTokenReused],
|
|
82
|
+
[/\btoken_invalidated\b/i, AUTH_FAILURE_REASON.tokenInvalidated],
|
|
83
|
+
[/\binvalid api key\b/i, AUTH_FAILURE_REASON.invalidApiKey],
|
|
84
|
+
[/\binvalid token\b/i, AUTH_FAILURE_REASON.invalidToken],
|
|
85
|
+
[
|
|
86
|
+
/\bauth(?:entication)? invalid\b/i,
|
|
87
|
+
AUTH_FAILURE_REASON.authenticationFailed,
|
|
88
|
+
],
|
|
89
|
+
[/\bauthentication failed\b/i, AUTH_FAILURE_REASON.authenticationFailed],
|
|
90
|
+
[/not logged in|please log ?in/i, AUTH_FAILURE_REASON.notLoggedIn],
|
|
91
|
+
[/\bunauthorized\b/i, AUTH_FAILURE_REASON.unauthorized],
|
|
92
|
+
[/\bforbidden\b/i, AUTH_FAILURE_REASON.forbidden],
|
|
93
|
+
];
|
|
94
|
+
export function detectAuthReason(text) {
|
|
95
|
+
for (const [pattern, reason] of AUTH_REASON_MARKERS) {
|
|
96
|
+
if (pattern.test(text)) {
|
|
97
|
+
return reason;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return AUTH_FAILURE_REASON.unknown;
|
|
101
|
+
}
|
|
102
|
+
/** Matcher combinator: classify as auth when the pattern matches. */
|
|
103
|
+
export function authIf(pattern) {
|
|
104
|
+
return (evidence) => {
|
|
105
|
+
const text = combinedText(evidence);
|
|
106
|
+
const match = text.match(pattern);
|
|
107
|
+
if (match === null) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
code: AGENT_ERROR_CODE.auth,
|
|
112
|
+
message: "Agent credentials are missing or invalid",
|
|
113
|
+
data: { reason: detectAuthReason(text), detail: match[0] },
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/** v1 free-text signal lists, kept verbatim (lowercased substrings). */
|
|
118
|
+
const QUOTA_TEXT = /quota exhausted|quota is exhausted|rate limit|retry-after|retry after|try again in|too many requests|insufficient balance|usage limit/i;
|
|
119
|
+
const AUTH_TEXT = /authentication failed|auth invalid|invalid api key|invalid token|not logged in|please login|please log in|unauthorized|forbidden|refresh_token_reused|token_invalidated/i;
|
|
120
|
+
/**
|
|
121
|
+
* Shared matchers, consulted after agent-specific ones. Provider-specific
|
|
122
|
+
* structured quota and capacity text matchers live on built-in blueprints.
|
|
123
|
+
*/
|
|
124
|
+
export const sharedFailureMatchers = [
|
|
125
|
+
quotaIf(QUOTA_TEXT),
|
|
126
|
+
authIf(AUTH_TEXT),
|
|
127
|
+
];
|
|
128
|
+
export function classifyFailure(matchers, evidence) {
|
|
129
|
+
for (const matcher of matchers) {
|
|
130
|
+
const classified = matcher(evidence);
|
|
131
|
+
if (classified !== null) {
|
|
132
|
+
return classified;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI agent blueprint (design "Kernel"): the shared machinery for agents
|
|
3
|
+
* that are CLI subprocesses — command resolution, stdin prompt delivery,
|
|
4
|
+
* NDJSON line parsing, abort handling with SIGTERM→SIGKILL escalation,
|
|
5
|
+
* early-completion detection, and failure classification. `claude` and
|
|
6
|
+
* `codex` are built with this factory; a third-party adapter is the same
|
|
7
|
+
* ~20-line exercise.
|
|
8
|
+
*/
|
|
9
|
+
import type { LoginCapability } from "../auth/login.js";
|
|
10
|
+
import type { MaterialHandlers } from "../auth/material.js";
|
|
11
|
+
import type { AgentEvent, RunUsage } from "../core/run.js";
|
|
12
|
+
import type { DoctorCapability, McpCapability, SkillsCapability } from "../host/capabilities.js";
|
|
13
|
+
import { type FailureMatcher } from "./classify.js";
|
|
14
|
+
import type { AgentDefinition } from "./definition.js";
|
|
15
|
+
import type { ResolvedSandbox, SandboxMode } from "./options.js";
|
|
16
|
+
export type ArgContext = {
|
|
17
|
+
readonly model: string | null;
|
|
18
|
+
readonly effort: string | null;
|
|
19
|
+
readonly workspace: string;
|
|
20
|
+
};
|
|
21
|
+
export type OutputState = {
|
|
22
|
+
readonly stdout: string;
|
|
23
|
+
readonly stderr: string;
|
|
24
|
+
messages: readonly string[];
|
|
25
|
+
};
|
|
26
|
+
export type CliResultCapture = {
|
|
27
|
+
readonly text: string | null;
|
|
28
|
+
readonly usage: RunUsage | null;
|
|
29
|
+
};
|
|
30
|
+
/** Keyed handler record (principle 7): key presence = mode supported. */
|
|
31
|
+
export type SandboxArgBuilders = {
|
|
32
|
+
readonly [M in SandboxMode]?: (sandbox: Readonly<Extract<ResolvedSandbox, {
|
|
33
|
+
mode: M;
|
|
34
|
+
}>>, ctx: ArgContext) => readonly string[];
|
|
35
|
+
};
|
|
36
|
+
export type CliAgentBlueprint<Id extends string = string> = {
|
|
37
|
+
readonly id: Id;
|
|
38
|
+
readonly command: string;
|
|
39
|
+
readonly args: SandboxArgBuilders;
|
|
40
|
+
/** Parse one NDJSON stdout line into events; [] when none (rule 3). */
|
|
41
|
+
readonly parseLine?: (line: string) => readonly AgentEvent[];
|
|
42
|
+
/** Capture the final normalized text / usage from a result line. */
|
|
43
|
+
readonly parseResult?: (line: string) => CliResultCapture | null;
|
|
44
|
+
/** Early completion (E9): arm the grace timer when this returns true. */
|
|
45
|
+
readonly detectCompletion?: (line: string, state: OutputState) => boolean;
|
|
46
|
+
readonly completionGraceMs?: number;
|
|
47
|
+
/** Agent-specific matchers, consulted before the shared chain. */
|
|
48
|
+
readonly classify?: readonly FailureMatcher[];
|
|
49
|
+
/**
|
|
50
|
+
* Matchers scanned over exit-0 output (F6). Only unambiguous,
|
|
51
|
+
* structured signals belong here — free-text matchers on successful
|
|
52
|
+
* output would misclassify runs that merely talk about limits.
|
|
53
|
+
*/
|
|
54
|
+
readonly classifyOnSuccess?: readonly FailureMatcher[];
|
|
55
|
+
readonly auth?: MaterialHandlers;
|
|
56
|
+
readonly login?: LoginCapability;
|
|
57
|
+
readonly doctor?: DoctorCapability;
|
|
58
|
+
readonly skills?: SkillsCapability;
|
|
59
|
+
readonly mcp?: McpCapability;
|
|
60
|
+
};
|
|
61
|
+
export declare function defineCliAgent<const Id extends string>(blueprint: CliAgentBlueprint<Id>): AgentDefinition<Id>;
|
|
62
|
+
//# sourceMappingURL=cli-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-agent.d.ts","sourceRoot":"","sources":["../../src/kernel/cli-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI agent blueprint (design "Kernel"): the shared machinery for agents
|
|
3
|
+
* that are CLI subprocesses — command resolution, stdin prompt delivery,
|
|
4
|
+
* NDJSON line parsing, abort handling with SIGTERM→SIGKILL escalation,
|
|
5
|
+
* early-completion detection, and failure classification. `claude` and
|
|
6
|
+
* `codex` are built with this factory; a third-party adapter is the same
|
|
7
|
+
* ~20-line exercise.
|
|
8
|
+
*/
|
|
9
|
+
import { AGENT_ERROR_CODE, AgentError, NOT_AVAILABLE_CAUSE, } from "../core/error.js";
|
|
10
|
+
import { redactSecrets } from "../core/redact.js";
|
|
11
|
+
import { AGENT_EVENT_TYPE, RUN_COMPLETION_KIND } from "../core/run.js";
|
|
12
|
+
import { OUTPUT_CHANNEL, PROCESS_SIGNAL, } from "../core/values.js";
|
|
13
|
+
import { DOCTOR_CHECK_STATUS } from "../host/capabilities.js";
|
|
14
|
+
import { classifyFailure, sharedFailureMatchers, } from "./classify.js";
|
|
15
|
+
import { requireKeyedHandler } from "./keyed.js";
|
|
16
|
+
const SIGKILL_ESCALATION_MS = 5_000;
|
|
17
|
+
const DEFAULT_COMPLETION_GRACE_MS = 1_000;
|
|
18
|
+
const RAW_OUTPUT_CAP_BYTES = 10 * 1024 * 1024;
|
|
19
|
+
const OUTPUT_TAIL_CHARS = 2_000;
|
|
20
|
+
const CLASSIFIED_EVIDENCE_TAIL_CHARS = 2_000;
|
|
21
|
+
function appendCapped(current, text) {
|
|
22
|
+
const combined = current + text;
|
|
23
|
+
return combined.length > RAW_OUTPUT_CAP_BYTES
|
|
24
|
+
? combined.slice(combined.length - RAW_OUTPUT_CAP_BYTES)
|
|
25
|
+
: combined;
|
|
26
|
+
}
|
|
27
|
+
class CliOutput {
|
|
28
|
+
hooks;
|
|
29
|
+
stdout = "";
|
|
30
|
+
stderr = "";
|
|
31
|
+
resultText = null;
|
|
32
|
+
usage = null;
|
|
33
|
+
completionDetected = false;
|
|
34
|
+
messages = [];
|
|
35
|
+
pendingLine = "";
|
|
36
|
+
constructor(hooks) {
|
|
37
|
+
this.hooks = hooks;
|
|
38
|
+
}
|
|
39
|
+
append(channel, text) {
|
|
40
|
+
const events = [
|
|
41
|
+
{ type: AGENT_EVENT_TYPE.output, channel, chunk: text },
|
|
42
|
+
];
|
|
43
|
+
if (channel === OUTPUT_CHANNEL.stderr) {
|
|
44
|
+
this.stderr = appendCapped(this.stderr, text);
|
|
45
|
+
return events;
|
|
46
|
+
}
|
|
47
|
+
this.stdout = appendCapped(this.stdout, text);
|
|
48
|
+
this.pendingLine += text;
|
|
49
|
+
const lines = this.pendingLine.split(/\r?\n/);
|
|
50
|
+
this.pendingLine = lines.pop() ?? "";
|
|
51
|
+
for (const line of lines) {
|
|
52
|
+
events.push(...this.handleLine(line));
|
|
53
|
+
}
|
|
54
|
+
return events;
|
|
55
|
+
}
|
|
56
|
+
flush() {
|
|
57
|
+
const line = this.pendingLine;
|
|
58
|
+
this.pendingLine = "";
|
|
59
|
+
return this.handleLine(line);
|
|
60
|
+
}
|
|
61
|
+
handleLine(line) {
|
|
62
|
+
const trimmed = line.trim();
|
|
63
|
+
if (trimmed === "") {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const events = this.hooks.parseLine(trimmed);
|
|
67
|
+
for (const event of events) {
|
|
68
|
+
if (event.type === AGENT_EVENT_TYPE.message) {
|
|
69
|
+
this.messages.push(event.text);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const capture = this.hooks.parseResult(trimmed);
|
|
73
|
+
if (capture !== null) {
|
|
74
|
+
this.resultText = capture.text ?? this.resultText;
|
|
75
|
+
this.usage = capture.usage ?? this.usage;
|
|
76
|
+
}
|
|
77
|
+
if (!this.completionDetected) {
|
|
78
|
+
this.completionDetected = this.hooks.detectCompletion(trimmed, {
|
|
79
|
+
stdout: this.stdout,
|
|
80
|
+
stderr: this.stderr,
|
|
81
|
+
messages: this.messages,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return events;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The one seam where a classification becomes observable: yield the
|
|
89
|
+
* `failure_classified` evidence event onto the run stream, then throw
|
|
90
|
+
* the matching typed error. Event and error cannot drift apart because
|
|
91
|
+
* they are born here together.
|
|
92
|
+
*/
|
|
93
|
+
function* raiseClassifiedFailure(classified, agentId, evidence) {
|
|
94
|
+
const stdoutTail = redactSecrets(evidence.stdout.slice(-CLASSIFIED_EVIDENCE_TAIL_CHARS));
|
|
95
|
+
const stderrTail = redactSecrets(evidence.stderr.slice(-CLASSIFIED_EVIDENCE_TAIL_CHARS));
|
|
96
|
+
yield {
|
|
97
|
+
type: AGENT_EVENT_TYPE.failureClassified,
|
|
98
|
+
code: classified.code,
|
|
99
|
+
evidence: {
|
|
100
|
+
stdoutTail: stdoutTail === "" ? null : stdoutTail,
|
|
101
|
+
stderrTail: stderrTail === "" ? null : stderrTail,
|
|
102
|
+
exitCode: evidence.exitCode,
|
|
103
|
+
signal: evidence.signal,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
throw new AgentError({
|
|
107
|
+
...classified,
|
|
108
|
+
message: redactSecrets(classified.message),
|
|
109
|
+
agentId,
|
|
110
|
+
started: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function* finishCliRun(input) {
|
|
114
|
+
const { agentId, matchers, successMatchers, output, exit, completion, ctx } = input;
|
|
115
|
+
const completedByGrace = completion.kind === RUN_COMPLETION_KIND.earlyGrace;
|
|
116
|
+
if (ctx.signal.aborted) {
|
|
117
|
+
throw new AgentError({
|
|
118
|
+
code: AGENT_ERROR_CODE.cancelled,
|
|
119
|
+
message: "Run aborted",
|
|
120
|
+
data: { reason: null },
|
|
121
|
+
agentId,
|
|
122
|
+
started: true,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const evidence = {
|
|
126
|
+
stdout: output.stdout,
|
|
127
|
+
stderr: output.stderr,
|
|
128
|
+
exitCode: exit.code,
|
|
129
|
+
signal: exit.signal,
|
|
130
|
+
now: ctx.clock.now(),
|
|
131
|
+
};
|
|
132
|
+
if (completedByGrace || exit.code === 0) {
|
|
133
|
+
if (!completedByGrace) {
|
|
134
|
+
// F6: exit-0 output is still scanned with the blueprint's
|
|
135
|
+
// success-path matchers.
|
|
136
|
+
const classified = classifyFailure(successMatchers, evidence);
|
|
137
|
+
if (classified !== null) {
|
|
138
|
+
yield* raiseClassifiedFailure(classified, agentId, evidence);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
text: output.resultText ?? output.messages.join("\n"),
|
|
143
|
+
model: null,
|
|
144
|
+
exit: { code: exit.code, signal: exit.signal, completion },
|
|
145
|
+
raw: { stdout: output.stdout, stderr: output.stderr },
|
|
146
|
+
usage: output.usage,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const classified = classifyFailure(matchers, evidence);
|
|
150
|
+
if (classified !== null) {
|
|
151
|
+
yield* raiseClassifiedFailure(classified, agentId, evidence);
|
|
152
|
+
}
|
|
153
|
+
const stdoutTail = redactSecrets(output.stdout.slice(-OUTPUT_TAIL_CHARS));
|
|
154
|
+
const stderrTail = redactSecrets(output.stderr.slice(-OUTPUT_TAIL_CHARS));
|
|
155
|
+
throw new AgentError({
|
|
156
|
+
code: AGENT_ERROR_CODE.failed,
|
|
157
|
+
message: redactSecrets(`Agent "${agentId}" exited with code ${exit.code ?? "null"}${exit.signal === null ? "" : ` (signal ${exit.signal})`}`),
|
|
158
|
+
data: {
|
|
159
|
+
exitCode: exit.code,
|
|
160
|
+
stdoutTail: stdoutTail === "" ? null : stdoutTail,
|
|
161
|
+
stderrTail: stderrTail === "" ? null : stderrTail,
|
|
162
|
+
},
|
|
163
|
+
agentId,
|
|
164
|
+
started: true,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function buildRun(blueprint, hooks, matchers, successMatchers) {
|
|
168
|
+
const graceMs = blueprint.completionGraceMs ?? DEFAULT_COMPLETION_GRACE_MS;
|
|
169
|
+
return async function* run(options, ctx) {
|
|
170
|
+
const argBuilder = requireKeyedHandler(blueprint.args, options.sandbox.mode, blueprint.id, `sandbox mode "${options.sandbox.mode}"`);
|
|
171
|
+
const command = await ctx.exec.which(blueprint.command, ctx.env);
|
|
172
|
+
if (command === null) {
|
|
173
|
+
throw new AgentError({
|
|
174
|
+
code: AGENT_ERROR_CODE.notAvailable,
|
|
175
|
+
message: `Command "${blueprint.command}" was not found on PATH`,
|
|
176
|
+
data: { cause: NOT_AVAILABLE_CAUSE.notInstalled },
|
|
177
|
+
agentId: blueprint.id,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
const argv = argBuilder(options.sandbox, {
|
|
181
|
+
model: options.model,
|
|
182
|
+
effort: options.effort,
|
|
183
|
+
workspace: options.workspace,
|
|
184
|
+
});
|
|
185
|
+
const child = ctx.exec.spawn({
|
|
186
|
+
command,
|
|
187
|
+
args: [...argv],
|
|
188
|
+
cwd: options.workspace,
|
|
189
|
+
env: ctx.env,
|
|
190
|
+
stdin: options.prompt,
|
|
191
|
+
});
|
|
192
|
+
const output = new CliOutput(hooks);
|
|
193
|
+
const cancels = [];
|
|
194
|
+
let completion = { kind: RUN_COMPLETION_KIND.natural };
|
|
195
|
+
const completionTimer = { graceArmed: false };
|
|
196
|
+
const onAbort = () => {
|
|
197
|
+
child.kill(PROCESS_SIGNAL.sigterm);
|
|
198
|
+
cancels.push(ctx.clock.setTimeout(() => child.kill(PROCESS_SIGNAL.sigkill), SIGKILL_ESCALATION_MS));
|
|
199
|
+
};
|
|
200
|
+
if (ctx.signal.aborted) {
|
|
201
|
+
onAbort();
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
for await (const chunk of child.chunks) {
|
|
208
|
+
yield* output.append(chunk.channel, chunk.text);
|
|
209
|
+
if (output.completionDetected && !completionTimer.graceArmed) {
|
|
210
|
+
completionTimer.graceArmed = true;
|
|
211
|
+
cancels.push(ctx.clock.setTimeout(() => {
|
|
212
|
+
completion = { kind: RUN_COMPLETION_KIND.earlyGrace };
|
|
213
|
+
child.kill(PROCESS_SIGNAL.sigterm);
|
|
214
|
+
}, graceMs));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
yield* output.flush();
|
|
218
|
+
const exit = await child.exit;
|
|
219
|
+
return yield* finishCliRun({
|
|
220
|
+
agentId: blueprint.id,
|
|
221
|
+
matchers,
|
|
222
|
+
successMatchers,
|
|
223
|
+
output,
|
|
224
|
+
exit,
|
|
225
|
+
completion,
|
|
226
|
+
ctx,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
ctx.signal.removeEventListener("abort", onAbort);
|
|
231
|
+
for (const cancel of cancels.splice(0)) {
|
|
232
|
+
cancel();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
export function defineCliAgent(blueprint) {
|
|
238
|
+
const hooks = {
|
|
239
|
+
parseLine: blueprint.parseLine?.bind(blueprint) ?? (() => []),
|
|
240
|
+
parseResult: blueprint.parseResult?.bind(blueprint) ?? (() => null),
|
|
241
|
+
detectCompletion: blueprint.detectCompletion?.bind(blueprint) ?? (() => false),
|
|
242
|
+
};
|
|
243
|
+
const matchers = [...(blueprint.classify ?? []), ...sharedFailureMatchers];
|
|
244
|
+
const successMatchers = blueprint.classifyOnSuccess ?? [];
|
|
245
|
+
const doctor = blueprint.doctor ??
|
|
246
|
+
{
|
|
247
|
+
probe: async (ctx) => {
|
|
248
|
+
const command = await ctx.exec.which(blueprint.command, ctx.env);
|
|
249
|
+
return {
|
|
250
|
+
available: command !== null,
|
|
251
|
+
checks: [
|
|
252
|
+
{
|
|
253
|
+
id: "command-on-path",
|
|
254
|
+
status: command === null
|
|
255
|
+
? DOCTOR_CHECK_STATUS.fail
|
|
256
|
+
: DOCTOR_CHECK_STATUS.pass,
|
|
257
|
+
detail: command,
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
};
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
const definition = {
|
|
264
|
+
id: blueprint.id,
|
|
265
|
+
run: buildRun(blueprint, hooks, matchers, successMatchers),
|
|
266
|
+
doctor,
|
|
267
|
+
};
|
|
268
|
+
if (blueprint.auth !== undefined) {
|
|
269
|
+
definition.auth = { materials: blueprint.auth };
|
|
270
|
+
}
|
|
271
|
+
if (blueprint.login !== undefined) {
|
|
272
|
+
definition.login = blueprint.login;
|
|
273
|
+
}
|
|
274
|
+
if (blueprint.skills !== undefined) {
|
|
275
|
+
definition.skills = blueprint.skills;
|
|
276
|
+
}
|
|
277
|
+
if (blueprint.mcp !== undefined) {
|
|
278
|
+
definition.mcp = blueprint.mcp;
|
|
279
|
+
}
|
|
280
|
+
return definition;
|
|
281
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type LoginContext, type LoginRequest, type LoginRun } from "../auth/login.js";
|
|
2
|
+
import { type EnvPatch } from "../core/env.js";
|
|
3
|
+
type CliLoginCommandOptions = {
|
|
4
|
+
readonly command: string;
|
|
5
|
+
readonly args: readonly string[];
|
|
6
|
+
readonly envPatch: EnvPatch;
|
|
7
|
+
readonly request: Omit<LoginRequest, "signal">;
|
|
8
|
+
readonly ctx: LoginContext;
|
|
9
|
+
readonly timeoutMs?: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function cliLoginCommand(options: CliLoginCommandOptions): LoginRun;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=cli-login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-login.d.ts","sourceRoot":"","sources":["../../src/kernel/cli-login.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAIjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AA8B9D,KAAK,sBAAsB,GAAG;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC/C,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AA+FF,wBAAuB,eAAe,CACpC,OAAO,EAAE,sBAAsB,GAC9B,QAAQ,CA+GV"}
|