@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,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunHandle internals: a bounded-replay broadcast and an awaitable
|
|
3
|
+
* handle (`then` delegates to `result`). Not consuming events never
|
|
4
|
+
* blocks the run. Subscribers attached while the run streams receive
|
|
5
|
+
* every event live; a LATE subscriber gets the retained replay window —
|
|
6
|
+
* bounded by payload bytes so a verbose run cannot hold its whole
|
|
7
|
+
* output in memory a second time (the capped raw transcript already
|
|
8
|
+
* lives on the result).
|
|
9
|
+
*/
|
|
10
|
+
import { AsyncQueue } from "../core/async-queue.js";
|
|
11
|
+
import { AGENT_EVENT_TYPE } from "../core/run.js";
|
|
12
|
+
const DEFAULT_REPLAY_BUDGET_BYTES = 4 * 1024 * 1024;
|
|
13
|
+
const EVENT_BASE_COST_BYTES = 64;
|
|
14
|
+
function replayCost(event) {
|
|
15
|
+
if (event.type === AGENT_EVENT_TYPE.output) {
|
|
16
|
+
return EVENT_BASE_COST_BYTES + event.chunk.length;
|
|
17
|
+
}
|
|
18
|
+
if (event.type === AGENT_EVENT_TYPE.message) {
|
|
19
|
+
return EVENT_BASE_COST_BYTES + event.text.length;
|
|
20
|
+
}
|
|
21
|
+
return EVENT_BASE_COST_BYTES;
|
|
22
|
+
}
|
|
23
|
+
export class EventBroadcast {
|
|
24
|
+
replayBudgetBytes;
|
|
25
|
+
eventCost;
|
|
26
|
+
history = [];
|
|
27
|
+
historyStart = 0;
|
|
28
|
+
retainedBytes = 0;
|
|
29
|
+
subscribers = new Set();
|
|
30
|
+
ended = false;
|
|
31
|
+
constructor(replayBudgetBytes = DEFAULT_REPLAY_BUDGET_BYTES, eventCost = replayCost) {
|
|
32
|
+
this.replayBudgetBytes = replayBudgetBytes;
|
|
33
|
+
this.eventCost = eventCost;
|
|
34
|
+
}
|
|
35
|
+
push(event) {
|
|
36
|
+
if (this.ended) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.history.push(event);
|
|
40
|
+
this.retainedBytes += this.eventCost(event);
|
|
41
|
+
this.evictOverBudget();
|
|
42
|
+
for (const queue of this.subscribers) {
|
|
43
|
+
queue.push(event);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** The most recent event always survives, however large. */
|
|
47
|
+
evictOverBudget() {
|
|
48
|
+
while (this.retainedBytes > this.replayBudgetBytes &&
|
|
49
|
+
this.historyStart < this.history.length - 1) {
|
|
50
|
+
const evicted = this.history[this.historyStart];
|
|
51
|
+
if (evicted === undefined) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
this.retainedBytes -= this.eventCost(evicted);
|
|
55
|
+
this.historyStart += 1;
|
|
56
|
+
}
|
|
57
|
+
if (this.historyStart > 0 && this.historyStart * 2 >= this.history.length) {
|
|
58
|
+
this.history = this.history.slice(this.historyStart);
|
|
59
|
+
this.historyStart = 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
end() {
|
|
63
|
+
this.ended = true;
|
|
64
|
+
for (const queue of this.subscribers) {
|
|
65
|
+
queue.end();
|
|
66
|
+
}
|
|
67
|
+
this.subscribers.clear();
|
|
68
|
+
}
|
|
69
|
+
get events() {
|
|
70
|
+
return {
|
|
71
|
+
[Symbol.asyncIterator]: () => {
|
|
72
|
+
const queue = new AsyncQueue();
|
|
73
|
+
for (const event of this.history.slice(this.historyStart)) {
|
|
74
|
+
queue.push(event);
|
|
75
|
+
}
|
|
76
|
+
if (this.ended) {
|
|
77
|
+
queue.end();
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.subscribers.add(queue);
|
|
81
|
+
}
|
|
82
|
+
return queue[Symbol.asyncIterator]();
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export function createRunHandle(runId, broadcast, result) {
|
|
88
|
+
// A consumer may only iterate events; keep its rejection observed.
|
|
89
|
+
result.catch(() => { });
|
|
90
|
+
return {
|
|
91
|
+
runId,
|
|
92
|
+
events: broadcast.events,
|
|
93
|
+
result,
|
|
94
|
+
// biome-ignore lint/suspicious/noThenProperty: RunHandle is deliberately awaitable — `await handle` is the documented shorthand for `await handle.result`.
|
|
95
|
+
then: (onFulfilled, onRejected) => result.then(onFulfilled, onRejected),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyed handler record dispatch (design principle 7): key presence
|
|
3
|
+
* declares support; absence is a typed `invalid_input`, enforced here
|
|
4
|
+
* for every dispatch site (sandbox argv, auth materials, skill sources,
|
|
5
|
+
* MCP transports). The record's mapped type proves the handler at key K
|
|
6
|
+
* takes the K-narrowed variant; the widening casts in this module are
|
|
7
|
+
* the ONE place that correlation is asserted instead of proven to the
|
|
8
|
+
* compiler.
|
|
9
|
+
*/
|
|
10
|
+
export declare function keyedHandler<Wide>(record: object, key: string): Wide | null;
|
|
11
|
+
/**
|
|
12
|
+
* Dispatch over a TOTAL keyed record: the caller proves (via `satisfies`
|
|
13
|
+
* on a mapped registry type) that every key of the discriminant union is
|
|
14
|
+
* present, so lookup by a variant's kind always succeeds and no typed
|
|
15
|
+
* "unsupported" arm exists.
|
|
16
|
+
*/
|
|
17
|
+
export declare function totalKeyedHandler<Wide>(record: object, key: string): Wide;
|
|
18
|
+
export declare function requireKeyedHandler<Wide>(record: object, key: string, agentId: string, what: string): Wide;
|
|
19
|
+
//# sourceMappingURL=keyed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyed.d.ts","sourceRoot":"","sources":["../../src/kernel/keyed.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAG3E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAEzE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EACtC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,IAAI,CAWN"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyed handler record dispatch (design principle 7): key presence
|
|
3
|
+
* declares support; absence is a typed `invalid_input`, enforced here
|
|
4
|
+
* for every dispatch site (sandbox argv, auth materials, skill sources,
|
|
5
|
+
* MCP transports). The record's mapped type proves the handler at key K
|
|
6
|
+
* takes the K-narrowed variant; the widening casts in this module are
|
|
7
|
+
* the ONE place that correlation is asserted instead of proven to the
|
|
8
|
+
* compiler.
|
|
9
|
+
*/
|
|
10
|
+
import { AGENT_ERROR_CODE, AgentError } from "../core/error.js";
|
|
11
|
+
export function keyedHandler(record, key) {
|
|
12
|
+
const handler = record[key];
|
|
13
|
+
return handler ?? null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Dispatch over a TOTAL keyed record: the caller proves (via `satisfies`
|
|
17
|
+
* on a mapped registry type) that every key of the discriminant union is
|
|
18
|
+
* present, so lookup by a variant's kind always succeeds and no typed
|
|
19
|
+
* "unsupported" arm exists.
|
|
20
|
+
*/
|
|
21
|
+
export function totalKeyedHandler(record, key) {
|
|
22
|
+
return record[key];
|
|
23
|
+
}
|
|
24
|
+
export function requireKeyedHandler(record, key, agentId, what) {
|
|
25
|
+
const handler = keyedHandler(record, key);
|
|
26
|
+
if (handler === null) {
|
|
27
|
+
throw new AgentError({
|
|
28
|
+
code: AGENT_ERROR_CODE.invalidInput,
|
|
29
|
+
message: `Agent "${agentId}" does not support ${what}`,
|
|
30
|
+
data: { reason: `unsupported: ${what}` },
|
|
31
|
+
agentId,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return handler;
|
|
35
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { LoginHandle, LoginHandler, LoginRequest } from "../auth/login.js";
|
|
2
|
+
import type { HostContext } from "../host/context.js";
|
|
3
|
+
type StartLoginInput = {
|
|
4
|
+
readonly agentId: string;
|
|
5
|
+
readonly request: LoginRequest;
|
|
6
|
+
readonly ctx: HostContext;
|
|
7
|
+
readonly handler: LoginHandler;
|
|
8
|
+
/** Caller cancellation; `null` when the caller passed no signal. */
|
|
9
|
+
readonly callerSignal: AbortSignal | null;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Drive a login handler's generator: tee each event to the broadcast, return
|
|
13
|
+
* the outcome, and end the stream in `finally`. The run plane's `RunDriver`
|
|
14
|
+
* earns a class (timers, guards, abort); login is a linear flow, so it is a
|
|
15
|
+
* function. Errors cross the boundary as `AgentError`, stamped with the agent
|
|
16
|
+
* id the handler could not know.
|
|
17
|
+
*/
|
|
18
|
+
export declare function startLogin(input: StartLoginInput): LoginHandle;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/kernel/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,WAAW,EACX,YAAY,EAEZ,YAAY,EACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,KAAK,eAAe,GAAG;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;CAC3C,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,CAW9D"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { AGENT_ERROR_CODE, AgentError, isAgentError } from "../core/error.js";
|
|
2
|
+
import { redactSecrets } from "../core/redact.js";
|
|
3
|
+
import { EventBroadcast } from "./handle.js";
|
|
4
|
+
/**
|
|
5
|
+
* Drive a login handler's generator: tee each event to the broadcast, return
|
|
6
|
+
* the outcome, and end the stream in `finally`. The run plane's `RunDriver`
|
|
7
|
+
* earns a class (timers, guards, abort); login is a linear flow, so it is a
|
|
8
|
+
* function. Errors cross the boundary as `AgentError`, stamped with the agent
|
|
9
|
+
* id the handler could not know.
|
|
10
|
+
*/
|
|
11
|
+
export function startLogin(input) {
|
|
12
|
+
const broadcast = new EventBroadcast();
|
|
13
|
+
const result = driveLogin(input, broadcast);
|
|
14
|
+
// A consumer may only iterate events; keep its rejection observed.
|
|
15
|
+
result.catch(() => { });
|
|
16
|
+
return {
|
|
17
|
+
events: broadcast.events,
|
|
18
|
+
result,
|
|
19
|
+
// biome-ignore lint/suspicious/noThenProperty: LoginHandle mirrors RunHandle — `await handle` delegates to `result`.
|
|
20
|
+
then: (onFulfilled, onRejected) => result.then(onFulfilled, onRejected),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function driveLogin(input, broadcast) {
|
|
24
|
+
const ctx = {
|
|
25
|
+
location: input.ctx.location,
|
|
26
|
+
// Login's only stop source is the caller signal — its total timeout lives in
|
|
27
|
+
// the handler and there are no guards. So, unlike `RunDriver` (which owns a
|
|
28
|
+
// controller to merge caller + timeout + guard trips into one signal), the
|
|
29
|
+
// driver funnels the caller signal straight through. A never-aborting signal
|
|
30
|
+
// keeps `ctx.signal` always live when the caller passed none — mirroring
|
|
31
|
+
// `RunContext.signal` — so handlers never branch on its presence.
|
|
32
|
+
signal: input.callerSignal ?? new AbortController().signal,
|
|
33
|
+
env: input.ctx.env,
|
|
34
|
+
exec: input.ctx.exec,
|
|
35
|
+
clock: input.ctx.clock,
|
|
36
|
+
};
|
|
37
|
+
try {
|
|
38
|
+
const generator = input.handler(input.request, ctx);
|
|
39
|
+
let step = await generator.next();
|
|
40
|
+
while (!step.done) {
|
|
41
|
+
broadcast.push(step.value);
|
|
42
|
+
step = await generator.next();
|
|
43
|
+
}
|
|
44
|
+
return step.value;
|
|
45
|
+
}
|
|
46
|
+
catch (thrown) {
|
|
47
|
+
throw toLoginError(input.agentId, thrown);
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
broadcast.end();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function toLoginError(agentId, thrown) {
|
|
54
|
+
if (isAgentError(thrown)) {
|
|
55
|
+
return thrown.agentId === null ? withAgentId(thrown, agentId) : thrown;
|
|
56
|
+
}
|
|
57
|
+
const message = thrown instanceof Error ? thrown.message : String(thrown);
|
|
58
|
+
return new AgentError({
|
|
59
|
+
code: AGENT_ERROR_CODE.failed,
|
|
60
|
+
message: redactSecrets(message),
|
|
61
|
+
data: { exitCode: null, stdoutTail: null, stderrTail: null },
|
|
62
|
+
cause: thrown,
|
|
63
|
+
agentId,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function withAgentId(error, agentId) {
|
|
67
|
+
return new AgentError({
|
|
68
|
+
code: error.code,
|
|
69
|
+
message: error.message,
|
|
70
|
+
data: error.data,
|
|
71
|
+
agentId,
|
|
72
|
+
cause: error.cause,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbound run options (rule 1: `?` = "use the documented default"),
|
|
3
|
+
* normalized exactly once into the resolved twins (rule 2) — agent
|
|
4
|
+
* definitions only ever see the resolved types.
|
|
5
|
+
*/
|
|
6
|
+
import { type EnvPatch } from "../core/env.js";
|
|
7
|
+
import type { GuardFactory } from "./guard.js";
|
|
8
|
+
export declare const GRANT_KIND: {
|
|
9
|
+
readonly shell: "shell";
|
|
10
|
+
readonly tool: "tool";
|
|
11
|
+
};
|
|
12
|
+
export type Grant = {
|
|
13
|
+
kind: typeof GRANT_KIND.shell;
|
|
14
|
+
command: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: typeof GRANT_KIND.tool;
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const SANDBOX_MODE: {
|
|
20
|
+
readonly full: "full";
|
|
21
|
+
readonly readOnly: "read-only";
|
|
22
|
+
};
|
|
23
|
+
export type SandboxMode = (typeof SANDBOX_MODE)[keyof typeof SANDBOX_MODE];
|
|
24
|
+
export type Sandbox = {
|
|
25
|
+
mode: typeof SANDBOX_MODE.full;
|
|
26
|
+
} | {
|
|
27
|
+
mode: typeof SANDBOX_MODE.readOnly;
|
|
28
|
+
grants?: Grant[];
|
|
29
|
+
};
|
|
30
|
+
export type ResolvedSandbox = {
|
|
31
|
+
mode: typeof SANDBOX_MODE.full;
|
|
32
|
+
} | {
|
|
33
|
+
mode: typeof SANDBOX_MODE.readOnly;
|
|
34
|
+
grants: Grant[];
|
|
35
|
+
};
|
|
36
|
+
/** Omission means no limit: the kernel never imposes an unasked timeout. */
|
|
37
|
+
export type Limits = {
|
|
38
|
+
totalMs?: number;
|
|
39
|
+
idleMs?: number;
|
|
40
|
+
guards?: GuardFactory[];
|
|
41
|
+
};
|
|
42
|
+
export type ResolvedLimits = {
|
|
43
|
+
totalMs: number | null;
|
|
44
|
+
idleMs: number | null;
|
|
45
|
+
guards: GuardFactory[];
|
|
46
|
+
};
|
|
47
|
+
type BaseRunOptions = {
|
|
48
|
+
prompt: string;
|
|
49
|
+
workspace: string;
|
|
50
|
+
model?: string;
|
|
51
|
+
effort?: string;
|
|
52
|
+
sandbox?: Sandbox;
|
|
53
|
+
env?: EnvPatch;
|
|
54
|
+
limits?: Limits;
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
};
|
|
57
|
+
export type RunOptions = BaseRunOptions & {
|
|
58
|
+
contract?: never;
|
|
59
|
+
};
|
|
60
|
+
export type ResolvedRunOptions = {
|
|
61
|
+
prompt: string;
|
|
62
|
+
workspace: string;
|
|
63
|
+
model: string | null;
|
|
64
|
+
effort: string | null;
|
|
65
|
+
sandbox: ResolvedSandbox;
|
|
66
|
+
env: EnvPatch;
|
|
67
|
+
limits: ResolvedLimits;
|
|
68
|
+
};
|
|
69
|
+
export declare function resolveSandbox(sandbox: Sandbox | undefined): ResolvedSandbox;
|
|
70
|
+
export declare function resolveLimits(limits: Limits | undefined): ResolvedLimits;
|
|
71
|
+
export declare function resolveRunOptions(options: RunOptions): ResolvedRunOptions;
|
|
72
|
+
export {};
|
|
73
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/kernel/options.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAO,MAAM,UAAU;;;CAGb,CAAC;AAEX,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,OAAO,UAAU,CAAC,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE3E,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,OAAO,YAAY,CAAC,IAAI,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,YAAY,CAAC,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC;AAE7D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,OAAO,YAAY,CAAC,IAAI,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,YAAY,CAAC,QAAQ,CAAC;IAAC,MAAM,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC;AAE5D,4EAA4E;AAC5E,MAAM,MAAM,MAAM,GAAG;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,eAAe,CAAC;IACzB,GAAG,EAAE,QAAQ,CAAC;IACd,MAAM,EAAE,cAAc,CAAC;CACxB,CAAC;AAEF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,eAAe,CAQ5E;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAMxE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,kBAAkB,CAUzE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbound run options (rule 1: `?` = "use the documented default"),
|
|
3
|
+
* normalized exactly once into the resolved twins (rule 2) — agent
|
|
4
|
+
* definitions only ever see the resolved types.
|
|
5
|
+
*/
|
|
6
|
+
import { EMPTY_ENV_PATCH } from "../core/env.js";
|
|
7
|
+
export const GRANT_KIND = {
|
|
8
|
+
shell: "shell",
|
|
9
|
+
tool: "tool",
|
|
10
|
+
};
|
|
11
|
+
export const SANDBOX_MODE = {
|
|
12
|
+
full: "full",
|
|
13
|
+
readOnly: "read-only",
|
|
14
|
+
};
|
|
15
|
+
export function resolveSandbox(sandbox) {
|
|
16
|
+
if (sandbox === undefined) {
|
|
17
|
+
return { mode: SANDBOX_MODE.full };
|
|
18
|
+
}
|
|
19
|
+
if (sandbox.mode === SANDBOX_MODE.full) {
|
|
20
|
+
return { mode: SANDBOX_MODE.full };
|
|
21
|
+
}
|
|
22
|
+
return { mode: SANDBOX_MODE.readOnly, grants: sandbox.grants ?? [] };
|
|
23
|
+
}
|
|
24
|
+
export function resolveLimits(limits) {
|
|
25
|
+
return {
|
|
26
|
+
totalMs: limits?.totalMs ?? null,
|
|
27
|
+
idleMs: limits?.idleMs ?? null,
|
|
28
|
+
guards: limits?.guards ?? [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function resolveRunOptions(options) {
|
|
32
|
+
return {
|
|
33
|
+
prompt: options.prompt,
|
|
34
|
+
workspace: options.workspace,
|
|
35
|
+
model: options.model ?? null,
|
|
36
|
+
effort: options.effort ?? null,
|
|
37
|
+
sandbox: resolveSandbox(options.sandbox),
|
|
38
|
+
env: options.env ?? EMPTY_ENV_PATCH,
|
|
39
|
+
limits: resolveLimits(options.limits),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run driver: drives an adapter generator exactly once, brackets the
|
|
3
|
+
* stream with `started`/`ended`, tees every event to the handle,
|
|
4
|
+
* telemetry, and the guard observers, and enforces limits centrally by
|
|
5
|
+
* tripping one internal abort. Adapters implement exactly one behavior:
|
|
6
|
+
* stop on abort.
|
|
7
|
+
*/
|
|
8
|
+
import type { Ports } from "../core/ports.js";
|
|
9
|
+
import type { RunHandle } from "../core/run.js";
|
|
10
|
+
import type { AgentDefinition } from "./definition.js";
|
|
11
|
+
import type { ResolvedRunOptions } from "./options.js";
|
|
12
|
+
export type StartRunInput = {
|
|
13
|
+
definition: AgentDefinition;
|
|
14
|
+
options: ResolvedRunOptions;
|
|
15
|
+
callerSignal: AbortSignal | null;
|
|
16
|
+
env: Record<string, string>;
|
|
17
|
+
ports: Ports;
|
|
18
|
+
};
|
|
19
|
+
export declare function startRun(input: StartRunInput): RunHandle;
|
|
20
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/kernel/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,KAAK,EAAU,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,KAAK,EAIV,SAAS,EAEV,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,iBAAiB,CAAC;AAGnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASvD,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,eAAe,CAAC;IAC5B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AA4QF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAExD"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run driver: drives an adapter generator exactly once, brackets the
|
|
3
|
+
* stream with `started`/`ended`, tees every event to the handle,
|
|
4
|
+
* telemetry, and the guard observers, and enforces limits centrally by
|
|
5
|
+
* tripping one internal abort. Adapters implement exactly one behavior:
|
|
6
|
+
* stop on abort.
|
|
7
|
+
*/
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
|
+
import { AGENT_ERROR_CODE, AgentError, isAgentError, TIMEOUT_KIND, withRunIdentity, } from "../core/error.js";
|
|
10
|
+
import { redactSecrets } from "../core/redact.js";
|
|
11
|
+
import { RUN_EVENT_TYPE, RUN_OUTCOME } from "../core/run.js";
|
|
12
|
+
import { createRunHandle, EventBroadcast } from "./handle.js";
|
|
13
|
+
const GUARD_POLL_MS = 1_000;
|
|
14
|
+
const RUN_TRIP_KIND = {
|
|
15
|
+
timeout: "timeout",
|
|
16
|
+
limit: "limit",
|
|
17
|
+
cancelled: "cancelled",
|
|
18
|
+
};
|
|
19
|
+
function scopedLogger(logger, runId) {
|
|
20
|
+
return {
|
|
21
|
+
log: (level, message, data) => logger.log(level, `[run ${runId}] ${message}`, data),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
class RunDriver {
|
|
25
|
+
input;
|
|
26
|
+
runId = randomUUID();
|
|
27
|
+
broadcast = new EventBroadcast();
|
|
28
|
+
controller = new AbortController();
|
|
29
|
+
guards;
|
|
30
|
+
cancels = [];
|
|
31
|
+
cancelIdle = null;
|
|
32
|
+
tripReason = null;
|
|
33
|
+
agentStarted = false;
|
|
34
|
+
settled = false;
|
|
35
|
+
startedAtMs;
|
|
36
|
+
constructor(input) {
|
|
37
|
+
this.input = input;
|
|
38
|
+
this.startedAtMs = input.ports.clock.now();
|
|
39
|
+
this.guards = input.options.limits.guards.map((factory) => factory({ clock: input.ports.clock }));
|
|
40
|
+
}
|
|
41
|
+
start() {
|
|
42
|
+
this.installCallerSignal();
|
|
43
|
+
this.installTimers();
|
|
44
|
+
return createRunHandle(this.runId, this.broadcast, this.execute());
|
|
45
|
+
}
|
|
46
|
+
trip(reason) {
|
|
47
|
+
if (this.tripReason !== null || this.settled) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.tripReason = reason;
|
|
51
|
+
this.controller.abort();
|
|
52
|
+
}
|
|
53
|
+
installCallerSignal() {
|
|
54
|
+
const signal = this.input.callerSignal;
|
|
55
|
+
if (signal === null) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const cancel = () => this.trip({
|
|
59
|
+
kind: RUN_TRIP_KIND.cancelled,
|
|
60
|
+
reason: typeof signal.reason === "string" ? signal.reason : null,
|
|
61
|
+
});
|
|
62
|
+
if (signal.aborted) {
|
|
63
|
+
cancel();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
signal.addEventListener("abort", cancel, { once: true });
|
|
67
|
+
this.cancels.push(() => signal.removeEventListener("abort", cancel));
|
|
68
|
+
}
|
|
69
|
+
installTimers() {
|
|
70
|
+
const { clock } = this.input.ports;
|
|
71
|
+
const { totalMs, idleMs } = this.input.options.limits;
|
|
72
|
+
if (totalMs !== null) {
|
|
73
|
+
this.cancels.push(clock.setTimeout(() => this.trip({
|
|
74
|
+
kind: RUN_TRIP_KIND.timeout,
|
|
75
|
+
timeoutKind: TIMEOUT_KIND.total,
|
|
76
|
+
limitMs: totalMs,
|
|
77
|
+
}), totalMs));
|
|
78
|
+
}
|
|
79
|
+
if (idleMs !== null) {
|
|
80
|
+
this.resetIdleTimer(idleMs);
|
|
81
|
+
}
|
|
82
|
+
if (this.guards.length > 0) {
|
|
83
|
+
this.scheduleGuardPoll();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
resetIdleTimer(idleMs) {
|
|
87
|
+
this.cancelIdle?.();
|
|
88
|
+
this.cancelIdle = this.input.ports.clock.setTimeout(() => this.trip({
|
|
89
|
+
kind: RUN_TRIP_KIND.timeout,
|
|
90
|
+
timeoutKind: TIMEOUT_KIND.idle,
|
|
91
|
+
limitMs: idleMs,
|
|
92
|
+
}), idleMs);
|
|
93
|
+
}
|
|
94
|
+
scheduleGuardPoll() {
|
|
95
|
+
const poll = () => {
|
|
96
|
+
if (this.settled || this.tripReason !== null) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.checkGuards();
|
|
100
|
+
this.cancels.push(this.input.ports.clock.setTimeout(poll, GUARD_POLL_MS));
|
|
101
|
+
};
|
|
102
|
+
this.cancels.push(this.input.ports.clock.setTimeout(poll, GUARD_POLL_MS));
|
|
103
|
+
}
|
|
104
|
+
checkGuards() {
|
|
105
|
+
for (const guard of this.guards) {
|
|
106
|
+
const violation = guard.violation();
|
|
107
|
+
if (violation !== null) {
|
|
108
|
+
this.trip({ kind: RUN_TRIP_KIND.limit, violation });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
emit(event) {
|
|
114
|
+
this.broadcast.push(event);
|
|
115
|
+
this.input.ports.telemetry.emit({
|
|
116
|
+
runId: this.runId,
|
|
117
|
+
agentId: this.input.definition.id,
|
|
118
|
+
event,
|
|
119
|
+
});
|
|
120
|
+
for (const guard of this.guards) {
|
|
121
|
+
guard.observe(event);
|
|
122
|
+
}
|
|
123
|
+
this.checkGuards();
|
|
124
|
+
}
|
|
125
|
+
emitAgentEvent(event) {
|
|
126
|
+
this.agentStarted = true;
|
|
127
|
+
const idleMs = this.input.options.limits.idleMs;
|
|
128
|
+
if (idleMs !== null) {
|
|
129
|
+
this.resetIdleTimer(idleMs);
|
|
130
|
+
}
|
|
131
|
+
this.emit(event);
|
|
132
|
+
}
|
|
133
|
+
async execute() {
|
|
134
|
+
const { definition, options, env, ports } = this.input;
|
|
135
|
+
this.emit({ type: RUN_EVENT_TYPE.started, model: options.model });
|
|
136
|
+
const ctx = {
|
|
137
|
+
signal: this.controller.signal,
|
|
138
|
+
env,
|
|
139
|
+
exec: ports.exec,
|
|
140
|
+
http: ports.http,
|
|
141
|
+
clock: ports.clock,
|
|
142
|
+
logger: scopedLogger(ports.logger, this.runId),
|
|
143
|
+
};
|
|
144
|
+
try {
|
|
145
|
+
const generator = definition.run(options, ctx);
|
|
146
|
+
let step = await generator.next();
|
|
147
|
+
while (!step.done) {
|
|
148
|
+
this.emitAgentEvent(step.value);
|
|
149
|
+
step = await generator.next();
|
|
150
|
+
}
|
|
151
|
+
if (this.tripReason !== null) {
|
|
152
|
+
throw this.errorFromTrip(this.tripReason);
|
|
153
|
+
}
|
|
154
|
+
const result = this.buildResult(step.value);
|
|
155
|
+
this.emit({ type: RUN_EVENT_TYPE.ended, outcome: RUN_OUTCOME.completed });
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
catch (thrown) {
|
|
159
|
+
const error = this.toAgentError(thrown);
|
|
160
|
+
this.emit({
|
|
161
|
+
type: RUN_EVENT_TYPE.ended,
|
|
162
|
+
outcome: error.code === AGENT_ERROR_CODE.cancelled
|
|
163
|
+
? RUN_OUTCOME.cancelled
|
|
164
|
+
: RUN_OUTCOME.failed,
|
|
165
|
+
});
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
this.settled = true;
|
|
170
|
+
this.cancelIdle?.();
|
|
171
|
+
for (const cancel of this.cancels.splice(0)) {
|
|
172
|
+
cancel();
|
|
173
|
+
}
|
|
174
|
+
this.broadcast.end();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
buildResult(outcome) {
|
|
178
|
+
const endedAtMs = this.input.ports.clock.now();
|
|
179
|
+
return {
|
|
180
|
+
runId: this.runId,
|
|
181
|
+
text: outcome.text,
|
|
182
|
+
agentId: this.input.definition.id,
|
|
183
|
+
model: outcome.model ?? this.input.options.model,
|
|
184
|
+
timing: {
|
|
185
|
+
startedAt: new Date(this.startedAtMs).toISOString(),
|
|
186
|
+
endedAt: new Date(endedAtMs).toISOString(),
|
|
187
|
+
durationMs: endedAtMs - this.startedAtMs,
|
|
188
|
+
},
|
|
189
|
+
exit: outcome.exit,
|
|
190
|
+
raw: outcome.raw,
|
|
191
|
+
usage: outcome.usage,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
identity() {
|
|
195
|
+
return {
|
|
196
|
+
runId: this.runId,
|
|
197
|
+
agentId: this.input.definition.id,
|
|
198
|
+
started: this.agentStarted,
|
|
199
|
+
durationMs: this.input.ports.clock.now() - this.startedAtMs,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
errorFromTrip(trip) {
|
|
203
|
+
if (trip.kind === RUN_TRIP_KIND.timeout) {
|
|
204
|
+
return new AgentError({
|
|
205
|
+
code: AGENT_ERROR_CODE.timeout,
|
|
206
|
+
message: `Run exceeded its ${trip.timeoutKind} timeout of ${trip.limitMs}ms`,
|
|
207
|
+
data: { kind: trip.timeoutKind, limitMs: trip.limitMs },
|
|
208
|
+
...this.identity(),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (trip.kind === RUN_TRIP_KIND.limit) {
|
|
212
|
+
return new AgentError({
|
|
213
|
+
code: AGENT_ERROR_CODE.limit,
|
|
214
|
+
message: `Guard "${trip.violation.guardId}" tripped: ${trip.violation.reason}`,
|
|
215
|
+
data: { violation: trip.violation },
|
|
216
|
+
...this.identity(),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return new AgentError({
|
|
220
|
+
code: AGENT_ERROR_CODE.cancelled,
|
|
221
|
+
message: "Run was cancelled",
|
|
222
|
+
data: { reason: trip.reason },
|
|
223
|
+
...this.identity(),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
toAgentError(thrown) {
|
|
227
|
+
if (this.tripReason !== null) {
|
|
228
|
+
return this.errorFromTrip(this.tripReason);
|
|
229
|
+
}
|
|
230
|
+
if (isAgentError(thrown)) {
|
|
231
|
+
return withRunIdentity(thrown, this.identity());
|
|
232
|
+
}
|
|
233
|
+
const message = thrown instanceof Error ? thrown.message : String(thrown);
|
|
234
|
+
return new AgentError({
|
|
235
|
+
code: AGENT_ERROR_CODE.failed,
|
|
236
|
+
message: redactSecrets(message),
|
|
237
|
+
data: { exitCode: null, stdoutTail: null, stderrTail: null },
|
|
238
|
+
cause: thrown,
|
|
239
|
+
...this.identity(),
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export function startRun(input) {
|
|
244
|
+
return new RunDriver(input).start();
|
|
245
|
+
}
|