@haikeilabs/agentware 0.2.1 → 0.4.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/dist/kei/index.d.ts +1 -0
- package/dist/kei/index.d.ts.map +1 -1
- package/dist/kei/index.js +1 -0
- package/dist/kei/runtimeLink.d.ts +19 -5
- package/dist/kei/runtimeLink.d.ts.map +1 -1
- package/dist/kei/runtimeLink.js +69 -18
- package/dist/kei/runtimeLinkRuntime.d.ts +26 -0
- package/dist/kei/runtimeLinkRuntime.d.ts.map +1 -0
- package/dist/kei/runtimeLinkRuntime.js +401 -0
- package/dist/middleware/middleware.js +1 -1
- package/package.json +1 -1
package/dist/kei/index.d.ts
CHANGED
package/dist/kei/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kei/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kei/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC"}
|
package/dist/kei/index.js
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* RuntimeLink contract: the harness → Agentware → kei-connector-runtime heartbeat.
|
|
3
3
|
*
|
|
4
4
|
* TypeScript mirror of the Go reference `go/kei/runtimelink` for
|
|
5
|
-
* `docs/specs/runtime-heartbeat-liveness.md` (HAI-141).
|
|
5
|
+
* `docs/specs/runtime-heartbeat-liveness.md` (HAI-141). This module defines
|
|
6
6
|
* configuration, status, identity, failure classes, the child's JSONL wire
|
|
7
|
-
* events, and redacted lifecycle events.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* catalog.
|
|
7
|
+
* events, and redacted lifecycle events. Process supervision is implemented
|
|
8
|
+
* in `runtimeLinkRuntime.ts`. The only heartbeat path is harness → RuntimeLink
|
|
9
|
+
* → kei-connector-runtime; Agentware does not call the catalog itself.
|
|
11
10
|
*
|
|
12
11
|
* All three SDK languages share `testing/contracts/runtime-link`. Durations
|
|
13
12
|
* are milliseconds here (`intervalMs`), seconds in Python, and
|
|
@@ -171,6 +170,19 @@ export interface RuntimeIdentity {
|
|
|
171
170
|
status: string;
|
|
172
171
|
bindingStatus: string;
|
|
173
172
|
runtimeVersion: string;
|
|
173
|
+
/**
|
|
174
|
+
* The installation's default agent from whoami; undefined when the runtime
|
|
175
|
+
* reports none (older runtimes omit it). A harness reads its agent from
|
|
176
|
+
* here and must not require an agent-ID env var.
|
|
177
|
+
*/
|
|
178
|
+
defaultAgentId?: string;
|
|
179
|
+
/** Agents assigned to the installation; empty when the runtime reports none. */
|
|
180
|
+
agents: AssignedAgent[];
|
|
181
|
+
}
|
|
182
|
+
/** One agent assigned to a runtime installation. */
|
|
183
|
+
export interface AssignedAgent {
|
|
184
|
+
agentId: string;
|
|
185
|
+
isDefault: boolean;
|
|
174
186
|
}
|
|
175
187
|
export type ChildLineErrorKind = "line_too_long" | "malformed" | "contract_mismatch";
|
|
176
188
|
/** A child line the SDK must drop and count. */
|
|
@@ -195,6 +207,8 @@ export interface TerminalEvent {
|
|
|
195
207
|
export type ChildEvent = {
|
|
196
208
|
kind: "identity";
|
|
197
209
|
identity: RuntimeIdentity;
|
|
210
|
+
/** Malformed agent entries dropped from the event; counted like dropped lines. */
|
|
211
|
+
droppedAgents: number;
|
|
198
212
|
} | {
|
|
199
213
|
kind: "beat";
|
|
200
214
|
beat: BeatEvent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeLink.d.ts","sourceRoot":"","sources":["../../src/kei/runtimeLink.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runtimeLink.d.ts","sourceRoot":"","sources":["../../src/kei/runtimeLink.ts"],"names":[],"mappings":"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"}
|
package/dist/kei/runtimeLink.js
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* RuntimeLink contract: the harness → Agentware → kei-connector-runtime heartbeat.
|
|
3
3
|
*
|
|
4
4
|
* TypeScript mirror of the Go reference `go/kei/runtimelink` for
|
|
5
|
-
* `docs/specs/runtime-heartbeat-liveness.md` (HAI-141).
|
|
5
|
+
* `docs/specs/runtime-heartbeat-liveness.md` (HAI-141). This module defines
|
|
6
6
|
* configuration, status, identity, failure classes, the child's JSONL wire
|
|
7
|
-
* events, and redacted lifecycle events.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* catalog.
|
|
7
|
+
* events, and redacted lifecycle events. Process supervision is implemented
|
|
8
|
+
* in `runtimeLinkRuntime.ts`. The only heartbeat path is harness → RuntimeLink
|
|
9
|
+
* → kei-connector-runtime; Agentware does not call the catalog itself.
|
|
11
10
|
*
|
|
12
11
|
* All three SDK languages share `testing/contracts/runtime-link`. Durations
|
|
13
12
|
* are milliseconds here (`intervalMs`), seconds in Python, and
|
|
@@ -410,6 +409,57 @@ class FieldReader {
|
|
|
410
409
|
return v;
|
|
411
410
|
}
|
|
412
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* Fill identity.defaultAgentId and identity.agents from the optional agent_id
|
|
414
|
+
* and agents fields. Older runtimes omit both, so absence is not an error; a
|
|
415
|
+
* malformed agent_id, agents list, or entry is dropped and counted rather than
|
|
416
|
+
* failing the whole identity. When agent_id is absent, the first entry marked
|
|
417
|
+
* is_default supplies it. Returns the number of dropped values.
|
|
418
|
+
*/
|
|
419
|
+
function parseAgents(raw, identity) {
|
|
420
|
+
let dropped = 0;
|
|
421
|
+
if (Object.hasOwn(raw, "agent_id")) {
|
|
422
|
+
const v = raw.agent_id;
|
|
423
|
+
if (typeof v === "string" && ID_RE.test(v))
|
|
424
|
+
identity.defaultAgentId = v;
|
|
425
|
+
else
|
|
426
|
+
dropped++;
|
|
427
|
+
}
|
|
428
|
+
if (!Object.hasOwn(raw, "agents"))
|
|
429
|
+
return dropped;
|
|
430
|
+
const entries = raw.agents;
|
|
431
|
+
if (!Array.isArray(entries))
|
|
432
|
+
return dropped + 1;
|
|
433
|
+
for (const entry of entries) {
|
|
434
|
+
const agent = parseAgentEntry(entry);
|
|
435
|
+
if (!agent) {
|
|
436
|
+
dropped++;
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
identity.agents.push(agent);
|
|
440
|
+
if (identity.defaultAgentId === undefined && agent.isDefault) {
|
|
441
|
+
identity.defaultAgentId = agent.agentId;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return dropped;
|
|
445
|
+
}
|
|
446
|
+
/** Read one {agent_id, is_default} entry; is_default is false when absent. */
|
|
447
|
+
function parseAgentEntry(entry) {
|
|
448
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
const e = entry;
|
|
452
|
+
const agentId = e.agent_id;
|
|
453
|
+
if (typeof agentId !== "string" || !ID_RE.test(agentId))
|
|
454
|
+
return undefined;
|
|
455
|
+
let isDefault = false;
|
|
456
|
+
if (Object.hasOwn(e, "is_default")) {
|
|
457
|
+
if (typeof e.is_default !== "boolean")
|
|
458
|
+
return undefined;
|
|
459
|
+
isDefault = e.is_default;
|
|
460
|
+
}
|
|
461
|
+
return { agentId, isDefault };
|
|
462
|
+
}
|
|
413
463
|
const encoder = new TextEncoder();
|
|
414
464
|
const decoder = new TextDecoder();
|
|
415
465
|
/**
|
|
@@ -445,20 +495,21 @@ export function parseChildLine(line) {
|
|
|
445
495
|
throw new ChildLineError("malformed", "event");
|
|
446
496
|
const f = new FieldReader(obj);
|
|
447
497
|
switch (obj.event) {
|
|
448
|
-
case "identity":
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
runtimeVersion: f.id("runtime_version", false),
|
|
460
|
-
},
|
|
498
|
+
case "identity": {
|
|
499
|
+
const identity = {
|
|
500
|
+
runId: f.id("run_id", true),
|
|
501
|
+
installationId: f.id("installation_id", true),
|
|
502
|
+
orgId: f.id("org_id", true),
|
|
503
|
+
workspaceId: f.id("workspace_id", false),
|
|
504
|
+
platform: f.id("platform", false),
|
|
505
|
+
status: f.id("status", false),
|
|
506
|
+
bindingStatus: f.id("binding_status", false),
|
|
507
|
+
runtimeVersion: f.id("runtime_version", false),
|
|
508
|
+
agents: [],
|
|
461
509
|
};
|
|
510
|
+
const droppedAgents = parseAgents(obj, identity);
|
|
511
|
+
return { kind: "identity", identity, droppedAgents };
|
|
512
|
+
}
|
|
462
513
|
case "beat": {
|
|
463
514
|
const runId = f.id("run_id", true);
|
|
464
515
|
const seq = f.integer("seq", false, 0, MAX_SEQ);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type RuntimeLink, type RuntimeLinkConfig } from "./runtimeLink.js";
|
|
2
|
+
export interface RuntimeChild {
|
|
3
|
+
readonly stdout: AsyncIterable<Uint8Array | string>;
|
|
4
|
+
readonly exitCode: Promise<number>;
|
|
5
|
+
kill(signal?: "SIGTERM" | "SIGKILL"): void;
|
|
6
|
+
}
|
|
7
|
+
/** Injectable process boundary for tests and embedders. */
|
|
8
|
+
export interface RuntimeChildFactory {
|
|
9
|
+
start(command: string, args: readonly string[], env: Readonly<Record<string, string>>): RuntimeChild;
|
|
10
|
+
}
|
|
11
|
+
export interface RuntimeLinkOptions {
|
|
12
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
13
|
+
childFactory?: RuntimeChildFactory;
|
|
14
|
+
now?: () => Date;
|
|
15
|
+
random?: () => number;
|
|
16
|
+
sdkVersion?: string;
|
|
17
|
+
sdkInstanceId?: string;
|
|
18
|
+
audit?: (event: Readonly<Record<string, unknown>>) => void | Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/** Node process implementation. stderr is drained and discarded; never surfaced to audit or logs. */
|
|
21
|
+
export declare class NodeRuntimeChildFactory implements RuntimeChildFactory {
|
|
22
|
+
start(command: string, args: readonly string[], env: Readonly<Record<string, string>>): RuntimeChild;
|
|
23
|
+
}
|
|
24
|
+
/** Create a supervisor that owns the harness → kei-connector-runtime process and heartbeat boundary. */
|
|
25
|
+
export declare function newRuntimeLink(config: RuntimeLinkConfig, options?: RuntimeLinkOptions): RuntimeLink;
|
|
26
|
+
//# sourceMappingURL=runtimeLinkRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtimeLinkRuntime.d.ts","sourceRoot":"","sources":["../../src/kei/runtimeLinkRuntime.ts"],"names":[],"mappings":"AAIA,OAAO,EAYL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC;CAC5C;AAED,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,KAAK,CACH,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACpC,YAAY,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACnD,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E;AAED,qGAAqG;AACrG,qBAAa,uBAAwB,YAAW,mBAAmB;IACjE,KAAK,CACH,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACpC,YAAY;CA8BhB;AAWD,wGAAwG;AACxG,wBAAgB,cAAc,CAC5B,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,kBAAuB,GAC/B,WAAW,CAEb"}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { createReadStream } from "node:fs";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { CHILD_ENV_ALLOWLIST, RUNTIME_LINK_SDK_LANG, linkEventToWire, normalizeRuntimeLinkConfig, parseChildLine, waitBackoff, } from "./runtimeLink.js";
|
|
6
|
+
/** Node process implementation. stderr is drained and discarded; never surfaced to audit or logs. */
|
|
7
|
+
export class NodeRuntimeChildFactory {
|
|
8
|
+
start(command, args, env) {
|
|
9
|
+
const child = spawn(command, [...args], {
|
|
10
|
+
env: { ...env },
|
|
11
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
12
|
+
detached: process.platform !== "win32",
|
|
13
|
+
});
|
|
14
|
+
const stdout = child.stdout;
|
|
15
|
+
if (!stdout)
|
|
16
|
+
throw new Error("runtime stdout unavailable");
|
|
17
|
+
const exitCode = new Promise((resolve) => {
|
|
18
|
+
child.once("error", () => resolve(1));
|
|
19
|
+
child.once("close", (code) => resolve(code ?? 1));
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
stdout: (async function* () {
|
|
23
|
+
for await (const chunk of stdout)
|
|
24
|
+
yield chunk;
|
|
25
|
+
})(),
|
|
26
|
+
exitCode,
|
|
27
|
+
kill: (signal = "SIGTERM") => {
|
|
28
|
+
if (process.platform !== "win32" && child.pid) {
|
|
29
|
+
try {
|
|
30
|
+
process.kill(-child.pid, signal);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
child.kill(signal);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
child.kill(signal);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const SDK_VERSION = "0.2.1";
|
|
44
|
+
const OUTCOME_FAILURE = {
|
|
45
|
+
catalog_unreachable: "catalog_unreachable",
|
|
46
|
+
catalog_timeout: "catalog_timeout",
|
|
47
|
+
catalog_error: "catalog_error",
|
|
48
|
+
catalog_backpressure: "catalog_backpressure",
|
|
49
|
+
catalog_rejected: "contract_mismatch",
|
|
50
|
+
};
|
|
51
|
+
/** Create a supervisor that owns the harness → kei-connector-runtime process and heartbeat boundary. */
|
|
52
|
+
export function newRuntimeLink(config, options = {}) {
|
|
53
|
+
return new RuntimeLinkImpl(normalizeRuntimeLinkConfig(config), options);
|
|
54
|
+
}
|
|
55
|
+
class RuntimeLinkImpl {
|
|
56
|
+
config;
|
|
57
|
+
options;
|
|
58
|
+
eventsQueue = [];
|
|
59
|
+
waiters = [];
|
|
60
|
+
controller = new AbortController();
|
|
61
|
+
sdkId;
|
|
62
|
+
state;
|
|
63
|
+
reason;
|
|
64
|
+
identityValue;
|
|
65
|
+
runId = "";
|
|
66
|
+
lastBeatAt;
|
|
67
|
+
lastCatalogOkAt;
|
|
68
|
+
consecutiveFails = 0;
|
|
69
|
+
restarts = 0;
|
|
70
|
+
started = false;
|
|
71
|
+
stopped = false;
|
|
72
|
+
supervisor;
|
|
73
|
+
child;
|
|
74
|
+
constructor(config, options) {
|
|
75
|
+
this.config = config;
|
|
76
|
+
this.options = options;
|
|
77
|
+
this.state = config.enabled ? "disabled" : "disabled";
|
|
78
|
+
this.sdkId = options.sdkInstanceId ?? randomUUID();
|
|
79
|
+
}
|
|
80
|
+
async start(signal) {
|
|
81
|
+
if (this.started || this.stopped || !this.config.enabled)
|
|
82
|
+
return;
|
|
83
|
+
this.started = true;
|
|
84
|
+
if (signal?.aborted) {
|
|
85
|
+
await this.stop();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
signal?.addEventListener("abort", () => {
|
|
89
|
+
void this.stop();
|
|
90
|
+
}, { once: true });
|
|
91
|
+
this.supervisor = this.supervise();
|
|
92
|
+
// Starting is non-blocking; only config errors can reject.
|
|
93
|
+
}
|
|
94
|
+
async stop() {
|
|
95
|
+
if (this.stopped) {
|
|
96
|
+
await this.withTimeout(this.supervisor);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.stopped = true;
|
|
100
|
+
this.controller.abort(new Error("RuntimeLink stopped"));
|
|
101
|
+
this.transition("stopped");
|
|
102
|
+
this.child?.kill("SIGTERM");
|
|
103
|
+
await this.withTimeout(this.supervisor);
|
|
104
|
+
this.child = undefined;
|
|
105
|
+
for (const resolve of this.waiters.splice(0))
|
|
106
|
+
resolve({ done: true, value: undefined });
|
|
107
|
+
}
|
|
108
|
+
status() {
|
|
109
|
+
return {
|
|
110
|
+
state: this.state,
|
|
111
|
+
reason: this.reason,
|
|
112
|
+
lastBeatAt: this.lastBeatAt,
|
|
113
|
+
lastCatalogOkAt: this.lastCatalogOkAt,
|
|
114
|
+
consecutiveFails: this.consecutiveFails,
|
|
115
|
+
runId: this.runId,
|
|
116
|
+
restarts: this.restarts,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
identity() {
|
|
120
|
+
return this.identityValue && { ...this.identityValue };
|
|
121
|
+
}
|
|
122
|
+
events() {
|
|
123
|
+
const queue = this.eventsQueue;
|
|
124
|
+
const waiters = this.waiters;
|
|
125
|
+
return {
|
|
126
|
+
[Symbol.asyncIterator]() {
|
|
127
|
+
return {
|
|
128
|
+
next: () => queue.length
|
|
129
|
+
? Promise.resolve({ done: false, value: queue.shift() })
|
|
130
|
+
: new Promise((resolve) => waiters.push(resolve)),
|
|
131
|
+
return: () => Promise.resolve({ done: true, value: undefined }),
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async supervise() {
|
|
137
|
+
while (!this.controller.signal.aborted) {
|
|
138
|
+
if (this.restarts > 0) {
|
|
139
|
+
this.transition("reconnecting");
|
|
140
|
+
try {
|
|
141
|
+
await waitBackoff(this.config.restart, this.restarts - 1, {
|
|
142
|
+
signal: this.controller.signal,
|
|
143
|
+
random: this.options.random,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (this.controller.signal.aborted)
|
|
151
|
+
return;
|
|
152
|
+
this.transition("starting");
|
|
153
|
+
let failure = "runtime_unavailable";
|
|
154
|
+
try {
|
|
155
|
+
failure = await this.runChild();
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
if (this.controller.signal.aborted)
|
|
159
|
+
return;
|
|
160
|
+
failure =
|
|
161
|
+
e instanceof BinaryFailure
|
|
162
|
+
? "config_invalid"
|
|
163
|
+
: "runtime_unresponsive";
|
|
164
|
+
}
|
|
165
|
+
if (this.controller.signal.aborted || this.state === "terminal")
|
|
166
|
+
return;
|
|
167
|
+
this.restarts++;
|
|
168
|
+
this.consecutiveFails++;
|
|
169
|
+
this.reason = failure;
|
|
170
|
+
if (failure === "config_invalid" ||
|
|
171
|
+
failure === "contract_mismatch" ||
|
|
172
|
+
failure === "installation_unauthorized") {
|
|
173
|
+
this.transition("terminal", failure);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
this.transition("degraded", failure);
|
|
177
|
+
if (this.restarts >= 5) {
|
|
178
|
+
this.transition("terminal", "runtime_crashloop");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async runChild() {
|
|
184
|
+
await this.verifyBinary();
|
|
185
|
+
const env = this.childEnv();
|
|
186
|
+
const factory = this.options.childFactory ?? new NodeRuntimeChildFactory();
|
|
187
|
+
const child = factory.start(this.config.binary.path, ["runtime", "heartbeat", "--output", "jsonl"], env);
|
|
188
|
+
this.child = child;
|
|
189
|
+
let identitySeen = false;
|
|
190
|
+
let heartbeatDeadline = Date.now() + this.config.beatTimeoutMs;
|
|
191
|
+
const lines = this.consume(child.stdout);
|
|
192
|
+
const abortPromise = new Promise((_, reject) => {
|
|
193
|
+
if (this.controller.signal.aborted)
|
|
194
|
+
reject(this.controller.signal.reason);
|
|
195
|
+
else
|
|
196
|
+
this.controller.signal.addEventListener("abort", () => reject(this.controller.signal.reason), { once: true });
|
|
197
|
+
});
|
|
198
|
+
try {
|
|
199
|
+
while (!this.controller.signal.aborted) {
|
|
200
|
+
const remaining = identitySeen
|
|
201
|
+
? Math.max(1, heartbeatDeadline - Date.now())
|
|
202
|
+
: this.config.graceMs;
|
|
203
|
+
let timer;
|
|
204
|
+
const next = await Promise.race([
|
|
205
|
+
lines.next(),
|
|
206
|
+
new Promise((_, reject) => {
|
|
207
|
+
timer = setTimeout(() => reject(new Error("runtime heartbeat timeout")), remaining);
|
|
208
|
+
}),
|
|
209
|
+
abortPromise,
|
|
210
|
+
]).finally(() => {
|
|
211
|
+
if (timer)
|
|
212
|
+
clearTimeout(timer);
|
|
213
|
+
});
|
|
214
|
+
if (next.done) {
|
|
215
|
+
const code = await child.exitCode;
|
|
216
|
+
const failure = code === 2
|
|
217
|
+
? "contract_mismatch"
|
|
218
|
+
: code === 3
|
|
219
|
+
? "installation_unauthorized"
|
|
220
|
+
: code >= 4
|
|
221
|
+
? "config_invalid"
|
|
222
|
+
: "runtime_unavailable";
|
|
223
|
+
if (failure === "contract_mismatch" ||
|
|
224
|
+
failure === "installation_unauthorized" ||
|
|
225
|
+
failure === "config_invalid") {
|
|
226
|
+
this.transition("terminal", failure);
|
|
227
|
+
}
|
|
228
|
+
return failure;
|
|
229
|
+
}
|
|
230
|
+
let ev;
|
|
231
|
+
try {
|
|
232
|
+
ev = parseChildLine(next.value);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
this.consecutiveFails++;
|
|
236
|
+
if (error instanceof Error &&
|
|
237
|
+
error.message.includes("contract_mismatch"))
|
|
238
|
+
this.reason = "contract_mismatch";
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (ev.kind === "identity") {
|
|
242
|
+
this.identityValue = ev.identity;
|
|
243
|
+
this.consecutiveFails += ev.droppedAgents;
|
|
244
|
+
this.runId = ev.identity.runId;
|
|
245
|
+
identitySeen = true;
|
|
246
|
+
heartbeatDeadline = Date.now() + this.config.beatTimeoutMs;
|
|
247
|
+
this.transition("connected");
|
|
248
|
+
}
|
|
249
|
+
else if (ev.kind === "beat") {
|
|
250
|
+
this.runId = ev.beat.runId || this.runId;
|
|
251
|
+
this.lastBeatAt = this.options.now?.() ?? new Date();
|
|
252
|
+
heartbeatDeadline = Date.now() + this.config.beatTimeoutMs;
|
|
253
|
+
if (ev.beat.outcome === "ok") {
|
|
254
|
+
this.lastCatalogOkAt = this.lastBeatAt;
|
|
255
|
+
this.consecutiveFails = 0;
|
|
256
|
+
if (this.state !== "connected")
|
|
257
|
+
this.transition("connected");
|
|
258
|
+
}
|
|
259
|
+
else if (ev.beat.outcome === "unauthorized") {
|
|
260
|
+
this.transition("terminal", "installation_unauthorized");
|
|
261
|
+
return "installation_unauthorized";
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
this.consecutiveFails++;
|
|
265
|
+
this.transition("degraded", OUTCOME_FAILURE[ev.beat.outcome] ?? "runtime_unavailable");
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else if (ev.kind === "terminal") {
|
|
269
|
+
const reason = ev.terminal.reason === "unauthorized"
|
|
270
|
+
? "installation_unauthorized"
|
|
271
|
+
: ev.terminal.reason === "contract"
|
|
272
|
+
? "contract_mismatch"
|
|
273
|
+
: "runtime_unavailable";
|
|
274
|
+
this.transition("terminal", reason);
|
|
275
|
+
return reason;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return "runtime_unavailable";
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
child.kill("SIGTERM");
|
|
282
|
+
this.child = undefined;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async *consume(source) {
|
|
286
|
+
const decoder = new TextDecoder();
|
|
287
|
+
let pending = "";
|
|
288
|
+
for await (const chunk of source) {
|
|
289
|
+
if (this.controller.signal.aborted)
|
|
290
|
+
return;
|
|
291
|
+
pending +=
|
|
292
|
+
typeof chunk === "string"
|
|
293
|
+
? chunk
|
|
294
|
+
: decoder.decode(chunk, { stream: true });
|
|
295
|
+
let idx;
|
|
296
|
+
while ((idx = pending.indexOf("\n")) >= 0) {
|
|
297
|
+
yield pending.slice(0, idx + 1);
|
|
298
|
+
pending = pending.slice(idx + 1);
|
|
299
|
+
}
|
|
300
|
+
if (new TextEncoder().encode(pending).length > 4097)
|
|
301
|
+
pending = " ".repeat(4098);
|
|
302
|
+
}
|
|
303
|
+
if (pending)
|
|
304
|
+
yield pending;
|
|
305
|
+
}
|
|
306
|
+
childEnv() {
|
|
307
|
+
const source = this.options.env ?? process.env;
|
|
308
|
+
const out = {};
|
|
309
|
+
for (const key of CHILD_ENV_ALLOWLIST) {
|
|
310
|
+
const value = source[key];
|
|
311
|
+
if (value !== undefined)
|
|
312
|
+
out[key] = value;
|
|
313
|
+
}
|
|
314
|
+
out.KEI_AGENTWARE_SDK_LANG = RUNTIME_LINK_SDK_LANG;
|
|
315
|
+
out.KEI_AGENTWARE_SDK_VERSION = this.options.sdkVersion ?? SDK_VERSION;
|
|
316
|
+
out.KEI_RUNTIME_CONTROL_PLANE_URL = this.config.controlPlaneUrl;
|
|
317
|
+
out.KEI_HARNESS_KIND = this.config.harness.kind;
|
|
318
|
+
out.KEI_HARNESS_VERSION = this.config.harness.version;
|
|
319
|
+
out.KEI_DEPLOYMENT_ENV = this.config.harness.deploymentEnv;
|
|
320
|
+
return out;
|
|
321
|
+
}
|
|
322
|
+
async verifyBinary() {
|
|
323
|
+
const expected = this.config.binary.sha256;
|
|
324
|
+
if (!expected)
|
|
325
|
+
return;
|
|
326
|
+
const hash = createHash("sha256");
|
|
327
|
+
try {
|
|
328
|
+
for await (const chunk of createReadStream(this.config.binary.path))
|
|
329
|
+
hash.update(chunk);
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
throw new BinaryFailure();
|
|
333
|
+
}
|
|
334
|
+
if (hash.digest("hex") !== expected)
|
|
335
|
+
throw new BinaryFailure();
|
|
336
|
+
}
|
|
337
|
+
transition(state, reason) {
|
|
338
|
+
if (this.state === state && this.reason === reason)
|
|
339
|
+
return;
|
|
340
|
+
this.state = state;
|
|
341
|
+
this.reason = reason;
|
|
342
|
+
const name = {
|
|
343
|
+
starting: "runtime.link.started",
|
|
344
|
+
connected: "runtime.link.connected",
|
|
345
|
+
degraded: "runtime.link.degraded",
|
|
346
|
+
reconnecting: "runtime.link.reconnecting",
|
|
347
|
+
terminal: "runtime.link.terminal",
|
|
348
|
+
stopped: "runtime.link.stopped",
|
|
349
|
+
}[state];
|
|
350
|
+
if (!name)
|
|
351
|
+
return;
|
|
352
|
+
const event = {
|
|
353
|
+
name,
|
|
354
|
+
at: this.options.now?.() ?? new Date(),
|
|
355
|
+
state,
|
|
356
|
+
reason: reason ?? "",
|
|
357
|
+
runId: this.runId,
|
|
358
|
+
seq: Date.now(),
|
|
359
|
+
sdkInstanceId: this.sdkId,
|
|
360
|
+
harness: {
|
|
361
|
+
kind: this.config.harness.kind,
|
|
362
|
+
version: this.config.harness.version,
|
|
363
|
+
deploymentEnv: this.config.harness.deploymentEnv,
|
|
364
|
+
sdkLang: RUNTIME_LINK_SDK_LANG,
|
|
365
|
+
sdkVersion: this.options.sdkVersion ?? SDK_VERSION,
|
|
366
|
+
},
|
|
367
|
+
restarts: this.restarts,
|
|
368
|
+
consecutiveFails: this.consecutiveFails,
|
|
369
|
+
};
|
|
370
|
+
try {
|
|
371
|
+
const safe = linkEventToWire(event);
|
|
372
|
+
if (this.waiters.length)
|
|
373
|
+
this.waiters.shift()({ done: false, value: event });
|
|
374
|
+
else {
|
|
375
|
+
if (this.eventsQueue.length >= 64)
|
|
376
|
+
this.eventsQueue.shift();
|
|
377
|
+
this.eventsQueue.push(event);
|
|
378
|
+
}
|
|
379
|
+
if (this.options.audit)
|
|
380
|
+
void Promise.resolve(this.options.audit(safe)).catch(() => undefined);
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
/* audit/event serialization must fail closed without leaking arbitrary input */
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async withTimeout(task) {
|
|
387
|
+
if (!task)
|
|
388
|
+
return;
|
|
389
|
+
let timer;
|
|
390
|
+
await Promise.race([
|
|
391
|
+
task,
|
|
392
|
+
new Promise((resolve) => {
|
|
393
|
+
timer = setTimeout(resolve, this.config.stopTimeoutMs);
|
|
394
|
+
}),
|
|
395
|
+
]);
|
|
396
|
+
if (timer)
|
|
397
|
+
clearTimeout(timer);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
class BinaryFailure extends Error {
|
|
401
|
+
}
|
|
@@ -9,7 +9,7 @@ export class MiddlewareImpl {
|
|
|
9
9
|
execute(toolName, args, caller) {
|
|
10
10
|
const decision = this.evaluator
|
|
11
11
|
? this.evaluator.evaluate(toolName, args, caller)
|
|
12
|
-
: { action: Action.
|
|
12
|
+
: { action: Action.DENY, rule: "default", reason: "no policy configured; default deny", timestamp: new Date() };
|
|
13
13
|
if (this.auditor) {
|
|
14
14
|
this.auditor.record({
|
|
15
15
|
session_id: caller.session_id || "",
|