orbit-agent-runtime 0.8.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/CHANGELOG.md +750 -0
- package/LICENSE +201 -0
- package/README.md +492 -0
- package/README.zh-CN.md +389 -0
- package/benchmarks/README.md +24 -0
- package/benchmarks/gateway.mjs +68 -0
- package/benchmarks/pae.mjs +90 -0
- package/benchmarks/replay.mjs +51 -0
- package/benchmarks/run-all.mjs +24 -0
- package/benchmarks/wal.mjs +50 -0
- package/bin/orbit.mjs +523 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/demo-deepseek.d.ts +2 -0
- package/dist/demo-deepseek.d.ts.map +1 -0
- package/dist/demo-deepseek.js +66 -0
- package/dist/demo-deepseek.js.map +1 -0
- package/dist/demo-host.d.ts +2 -0
- package/dist/demo-host.d.ts.map +1 -0
- package/dist/demo-host.js +98 -0
- package/dist/demo-host.js.map +1 -0
- package/dist/demo-replay.d.ts +2 -0
- package/dist/demo-replay.d.ts.map +1 -0
- package/dist/demo-replay.js +68 -0
- package/dist/demo-replay.js.map +1 -0
- package/dist/src/core/orbitRuntimeHost.d.ts +349 -0
- package/dist/src/core/orbitRuntimeHost.d.ts.map +1 -0
- package/dist/src/core/orbitRuntimeHost.js +706 -0
- package/dist/src/core/orbitRuntimeHost.js.map +1 -0
- package/dist/src/index.d.ts +92 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +226 -0
- package/dist/src/index.js.map +1 -0
- package/dist/test/audit_chain.test.d.ts +2 -0
- package/dist/test/audit_chain.test.d.ts.map +1 -0
- package/dist/test/audit_chain.test.js +283 -0
- package/dist/test/audit_chain.test.js.map +1 -0
- package/dist/test/channel_hub.test.d.ts +2 -0
- package/dist/test/channel_hub.test.d.ts.map +1 -0
- package/dist/test/channel_hub.test.js +66 -0
- package/dist/test/channel_hub.test.js.map +1 -0
- package/dist/test/cordis_adapter.test.d.ts +2 -0
- package/dist/test/cordis_adapter.test.d.ts.map +1 -0
- package/dist/test/cordis_adapter.test.js +280 -0
- package/dist/test/cordis_adapter.test.js.map +1 -0
- package/dist/test/cost_routing.test.d.ts +2 -0
- package/dist/test/cost_routing.test.d.ts.map +1 -0
- package/dist/test/cost_routing.test.js +31 -0
- package/dist/test/cost_routing.test.js.map +1 -0
- package/dist/test/domain_transaction.test.d.ts +2 -0
- package/dist/test/domain_transaction.test.d.ts.map +1 -0
- package/dist/test/domain_transaction.test.js +351 -0
- package/dist/test/domain_transaction.test.js.map +1 -0
- package/dist/test/file_channel.test.d.ts +2 -0
- package/dist/test/file_channel.test.d.ts.map +1 -0
- package/dist/test/file_channel.test.js +179 -0
- package/dist/test/file_channel.test.js.map +1 -0
- package/dist/test/gateway.test.d.ts +2 -0
- package/dist/test/gateway.test.d.ts.map +1 -0
- package/dist/test/gateway.test.js +548 -0
- package/dist/test/gateway.test.js.map +1 -0
- package/dist/test/governance_profile.test.d.ts +2 -0
- package/dist/test/governance_profile.test.d.ts.map +1 -0
- package/dist/test/governance_profile.test.js +214 -0
- package/dist/test/governance_profile.test.js.map +1 -0
- package/dist/test/governance_schema.test.d.ts +2 -0
- package/dist/test/governance_schema.test.d.ts.map +1 -0
- package/dist/test/governance_schema.test.js +200 -0
- package/dist/test/governance_schema.test.js.map +1 -0
- package/dist/test/host_integration.test.d.ts +2 -0
- package/dist/test/host_integration.test.d.ts.map +1 -0
- package/dist/test/host_integration.test.js +104 -0
- package/dist/test/host_integration.test.js.map +1 -0
- package/dist/test/host_journal_persistence.test.d.ts +2 -0
- package/dist/test/host_journal_persistence.test.d.ts.map +1 -0
- package/dist/test/host_journal_persistence.test.js +367 -0
- package/dist/test/host_journal_persistence.test.js.map +1 -0
- package/dist/test/impact_domain.test.d.ts +2 -0
- package/dist/test/impact_domain.test.d.ts.map +1 -0
- package/dist/test/impact_domain.test.js +48 -0
- package/dist/test/impact_domain.test.js.map +1 -0
- package/dist/test/injected_clock.test.d.ts +13 -0
- package/dist/test/injected_clock.test.d.ts.map +1 -0
- package/dist/test/injected_clock.test.js +200 -0
- package/dist/test/injected_clock.test.js.map +1 -0
- package/dist/test/isolation_domain.test.d.ts +2 -0
- package/dist/test/isolation_domain.test.d.ts.map +1 -0
- package/dist/test/isolation_domain.test.js +302 -0
- package/dist/test/isolation_domain.test.js.map +1 -0
- package/dist/test/journal_wal.test.d.ts +2 -0
- package/dist/test/journal_wal.test.d.ts.map +1 -0
- package/dist/test/journal_wal.test.js +622 -0
- package/dist/test/journal_wal.test.js.map +1 -0
- package/dist/test/mcp_adapter.test.d.ts +2 -0
- package/dist/test/mcp_adapter.test.d.ts.map +1 -0
- package/dist/test/mcp_adapter.test.js +440 -0
- package/dist/test/mcp_adapter.test.js.map +1 -0
- package/dist/test/openai_compat_channel.test.d.ts +2 -0
- package/dist/test/openai_compat_channel.test.d.ts.map +1 -0
- package/dist/test/openai_compat_channel.test.js +325 -0
- package/dist/test/openai_compat_channel.test.js.map +1 -0
- package/dist/test/openapi_adapter.test.d.ts +2 -0
- package/dist/test/openapi_adapter.test.d.ts.map +1 -0
- package/dist/test/openapi_adapter.test.js +270 -0
- package/dist/test/openapi_adapter.test.js.map +1 -0
- package/dist/test/orbit_cli.test.d.ts +2 -0
- package/dist/test/orbit_cli.test.d.ts.map +1 -0
- package/dist/test/orbit_cli.test.js +137 -0
- package/dist/test/orbit_cli.test.js.map +1 -0
- package/dist/test/pact_verifier.test.d.ts +2 -0
- package/dist/test/pact_verifier.test.d.ts.map +1 -0
- package/dist/test/pact_verifier.test.js +41 -0
- package/dist/test/pact_verifier.test.js.map +1 -0
- package/dist/test/pae_adapter.test.d.ts +2 -0
- package/dist/test/pae_adapter.test.d.ts.map +1 -0
- package/dist/test/pae_adapter.test.js +469 -0
- package/dist/test/pae_adapter.test.js.map +1 -0
- package/dist/test/plugin_sandbox_guard.test.d.ts +2 -0
- package/dist/test/plugin_sandbox_guard.test.d.ts.map +1 -0
- package/dist/test/plugin_sandbox_guard.test.js +57 -0
- package/dist/test/plugin_sandbox_guard.test.js.map +1 -0
- package/dist/test/rate_limit_behavior.test.d.ts +2 -0
- package/dist/test/rate_limit_behavior.test.d.ts.map +1 -0
- package/dist/test/rate_limit_behavior.test.js +85 -0
- package/dist/test/rate_limit_behavior.test.js.map +1 -0
- package/dist/test/replay_compat.test.d.ts +2 -0
- package/dist/test/replay_compat.test.d.ts.map +1 -0
- package/dist/test/replay_compat.test.js +1122 -0
- package/dist/test/replay_compat.test.js.map +1 -0
- package/dist/test/replay_engine.test.d.ts +2 -0
- package/dist/test/replay_engine.test.d.ts.map +1 -0
- package/dist/test/replay_engine.test.js +85 -0
- package/dist/test/replay_engine.test.js.map +1 -0
- package/dist/test/shell_channel.test.d.ts +2 -0
- package/dist/test/shell_channel.test.d.ts.map +1 -0
- package/dist/test/shell_channel.test.js +173 -0
- package/dist/test/shell_channel.test.js.map +1 -0
- package/dist/test/teardown_isolation.test.d.ts +10 -0
- package/dist/test/teardown_isolation.test.d.ts.map +1 -0
- package/dist/test/teardown_isolation.test.js +279 -0
- package/dist/test/teardown_isolation.test.js.map +1 -0
- package/dist/test/token_budget.test.d.ts +2 -0
- package/dist/test/token_budget.test.d.ts.map +1 -0
- package/dist/test/token_budget.test.js +113 -0
- package/dist/test/token_budget.test.js.map +1 -0
- package/dist/test/trace_journal.test.d.ts +2 -0
- package/dist/test/trace_journal.test.d.ts.map +1 -0
- package/dist/test/trace_journal.test.js +43 -0
- package/dist/test/trace_journal.test.js.map +1 -0
- package/dist/test/trace_journal_persistence.test.d.ts +2 -0
- package/dist/test/trace_journal_persistence.test.d.ts.map +1 -0
- package/dist/test/trace_journal_persistence.test.js +175 -0
- package/dist/test/trace_journal_persistence.test.js.map +1 -0
- package/dist/test/trace_persistence.test.d.ts +2 -0
- package/dist/test/trace_persistence.test.d.ts.map +1 -0
- package/dist/test/trace_persistence.test.js +216 -0
- package/dist/test/trace_persistence.test.js.map +1 -0
- package/dist/test/trip_protector.test.d.ts +2 -0
- package/dist/test/trip_protector.test.d.ts.map +1 -0
- package/dist/test/trip_protector.test.js +42 -0
- package/dist/test/trip_protector.test.js.map +1 -0
- package/examples/README.md +34 -0
- package/examples/cli-record-replay.mjs +74 -0
- package/examples/custom-channel.mjs +102 -0
- package/examples/js-pae-plugin.mjs +128 -0
- package/examples/mcp-adapter.mjs +102 -0
- package/package.json +60 -0
- package/src/core/orbitRuntimeHost.ts +853 -0
- package/src/index.ts +256 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const node_test_1 = require("node:test");
|
|
40
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
41
|
+
const node_fs_1 = require("node:fs");
|
|
42
|
+
const os = __importStar(require("node:os"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const index_1 = require("../src/index");
|
|
45
|
+
async function tempTracePath(name) {
|
|
46
|
+
const dir = await node_fs_1.promises.mkdtemp(path.join(os.tmpdir(), "orbit-tracej-"));
|
|
47
|
+
return path.join(dir, name);
|
|
48
|
+
}
|
|
49
|
+
function journalWithEntries() {
|
|
50
|
+
const journal = new index_1.TraceJournal();
|
|
51
|
+
journal.append({ entryClass: "boot", traceMarkId: "t1", factPayload: { stage: "channels" } });
|
|
52
|
+
journal.append({
|
|
53
|
+
entryClass: "guard.trip",
|
|
54
|
+
traceMarkId: "t2",
|
|
55
|
+
pluginUnitId: "p1",
|
|
56
|
+
agentBoxId: "box-1",
|
|
57
|
+
factPayload: { reason: "quota" }
|
|
58
|
+
});
|
|
59
|
+
return journal;
|
|
60
|
+
}
|
|
61
|
+
(0, node_test_1.test)("trace checkpoint: save + load roundtrips the audit journal intact", async () => {
|
|
62
|
+
const file = await tempTracePath("audit.jsonl");
|
|
63
|
+
const original = journalWithEntries();
|
|
64
|
+
strict_1.default.equal(await (0, index_1.saveTraceJournal)(original, file), 2);
|
|
65
|
+
const loaded = await (0, index_1.loadTraceJournal)(file);
|
|
66
|
+
strict_1.default.deepEqual(loaded.snapshot(), original.snapshot());
|
|
67
|
+
strict_1.default.equal(loaded.byTraceMark("t2").length, 1);
|
|
68
|
+
strict_1.default.equal(loaded.byAgentBox("box-1").length, 1);
|
|
69
|
+
strict_1.default.equal(loaded.byPluginUnit("p1").length, 1);
|
|
70
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
71
|
+
});
|
|
72
|
+
(0, node_test_1.test)("trace checkpoint: file format is JSONL with a header line", async () => {
|
|
73
|
+
const file = await tempTracePath("audit.jsonl");
|
|
74
|
+
await (0, index_1.saveTraceJournal)(journalWithEntries(), file);
|
|
75
|
+
const lines = (await node_fs_1.promises.readFile(file, "utf8")).split("\n").filter((l) => l.trim() !== "");
|
|
76
|
+
strict_1.default.equal(lines.length, 3);
|
|
77
|
+
strict_1.default.deepEqual(JSON.parse(lines[0]), { magic: "orbit-trace", version: 1, entryCount: 2 });
|
|
78
|
+
const first = JSON.parse(lines[1]);
|
|
79
|
+
strict_1.default.equal(first.entryClass, "boot");
|
|
80
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
81
|
+
});
|
|
82
|
+
(0, node_test_1.test)("trace checkpoint: save creates parent directories and leaves no .tmp behind", async () => {
|
|
83
|
+
const dir = await node_fs_1.promises.mkdtemp(path.join(os.tmpdir(), "orbit-tracej-dir-"));
|
|
84
|
+
const file = path.join(dir, "nested", "deep", "audit.jsonl");
|
|
85
|
+
await (0, index_1.saveTraceJournal)(journalWithEntries(), file);
|
|
86
|
+
strict_1.default.deepEqual(await node_fs_1.promises.readdir(path.dirname(file)), ["audit.jsonl"]);
|
|
87
|
+
await node_fs_1.promises.rm(dir, { recursive: true, force: true });
|
|
88
|
+
});
|
|
89
|
+
(0, node_test_1.test)("trace checkpoint: an empty journal roundtrips as empty", async () => {
|
|
90
|
+
const file = await tempTracePath("empty.jsonl");
|
|
91
|
+
strict_1.default.equal(await (0, index_1.saveTraceJournal)(new index_1.TraceJournal(), file), 0);
|
|
92
|
+
const loaded = await (0, index_1.loadTraceJournal)(file);
|
|
93
|
+
strict_1.default.equal(loaded.entries().length, 0);
|
|
94
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
95
|
+
});
|
|
96
|
+
(0, node_test_1.test)("trace checkpoint: a missing file throws TraceFileInvalidError", async () => {
|
|
97
|
+
await strict_1.default.rejects((0, index_1.loadTraceJournal)(path.join(os.tmpdir(), "orbit-tracej-nope.jsonl")), (err) => {
|
|
98
|
+
strict_1.default.ok(err instanceof index_1.TraceFileInvalidError);
|
|
99
|
+
strict_1.default.match(err.message, /not found/);
|
|
100
|
+
return true;
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
(0, node_test_1.test)("trace checkpoint: foreign files are rejected (bad magic)", async () => {
|
|
104
|
+
const file = await tempTracePath("foreign.jsonl");
|
|
105
|
+
await node_fs_1.promises.writeFile(file, '{"hello":"world"}\n', "utf8");
|
|
106
|
+
await strict_1.default.rejects((0, index_1.loadTraceJournal)(file), (err) => {
|
|
107
|
+
strict_1.default.ok(err instanceof index_1.TraceFileInvalidError);
|
|
108
|
+
strict_1.default.match(err.message, /bad magic/);
|
|
109
|
+
return true;
|
|
110
|
+
});
|
|
111
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
112
|
+
});
|
|
113
|
+
(0, node_test_1.test)("trace checkpoint: an entryCount mismatch is rejected", async () => {
|
|
114
|
+
const file = await tempTracePath("mismatch.jsonl");
|
|
115
|
+
await (0, index_1.saveTraceJournal)(journalWithEntries(), file);
|
|
116
|
+
const lines = (await node_fs_1.promises.readFile(file, "utf8")).split("\n").filter((l) => l.trim() !== "");
|
|
117
|
+
lines[0] = JSON.stringify({ magic: "orbit-trace", version: 1, entryCount: 99 });
|
|
118
|
+
await node_fs_1.promises.writeFile(file, `${lines.join("\n")}\n`, "utf8");
|
|
119
|
+
await strict_1.default.rejects((0, index_1.loadTraceJournal)(file), (err) => {
|
|
120
|
+
strict_1.default.ok(err instanceof index_1.TraceFileInvalidError);
|
|
121
|
+
strict_1.default.match(err.message, /entryCount/);
|
|
122
|
+
return true;
|
|
123
|
+
});
|
|
124
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
125
|
+
});
|
|
126
|
+
(0, node_test_1.test)("trace checkpoint: an unsupported version is rejected", async () => {
|
|
127
|
+
const file = await tempTracePath("future.jsonl");
|
|
128
|
+
await node_fs_1.promises.writeFile(file, `${JSON.stringify({ magic: "orbit-trace", version: 99, entryCount: 0 })}\n`, "utf8");
|
|
129
|
+
await strict_1.default.rejects((0, index_1.loadTraceJournal)(file), (err) => {
|
|
130
|
+
strict_1.default.ok(err instanceof index_1.TraceFileInvalidError);
|
|
131
|
+
strict_1.default.match(err.message, /unsupported trace version/);
|
|
132
|
+
return true;
|
|
133
|
+
});
|
|
134
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
135
|
+
});
|
|
136
|
+
(0, node_test_1.test)("trace checkpoint: malformed entry lines are rejected with line numbers", async () => {
|
|
137
|
+
const file = await tempTracePath("broken.jsonl");
|
|
138
|
+
await node_fs_1.promises.writeFile(file, '{"magic":"orbit-trace","version":1,"entryCount":1}\nnot-json\n', "utf8");
|
|
139
|
+
await strict_1.default.rejects((0, index_1.loadTraceJournal)(file), (err) => {
|
|
140
|
+
strict_1.default.ok(err instanceof index_1.TraceFileInvalidError);
|
|
141
|
+
strict_1.default.equal(err.lineNo, 2);
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
144
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
145
|
+
});
|
|
146
|
+
(0, node_test_1.test)("trace checkpoint: an entry missing factPayload is rejected", async () => {
|
|
147
|
+
const file = await tempTracePath("nopayload.jsonl");
|
|
148
|
+
const lines = [
|
|
149
|
+
JSON.stringify({ magic: "orbit-trace", version: 1, entryCount: 1 }),
|
|
150
|
+
JSON.stringify({ entryUid: "u1", entryClass: "boot", occurredAt: 1, traceMarkId: "t1" })
|
|
151
|
+
];
|
|
152
|
+
await node_fs_1.promises.writeFile(file, `${lines.join("\n")}\n`, "utf8");
|
|
153
|
+
await strict_1.default.rejects((0, index_1.loadTraceJournal)(file), (err) => {
|
|
154
|
+
strict_1.default.ok(err instanceof index_1.TraceFileInvalidError);
|
|
155
|
+
strict_1.default.match(err.message, /factPayload/);
|
|
156
|
+
return true;
|
|
157
|
+
});
|
|
158
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
159
|
+
});
|
|
160
|
+
(0, node_test_1.test)("trace checkpoint: every entry is preserved (not just the last one)", async () => {
|
|
161
|
+
const file = await tempTracePath("many.jsonl");
|
|
162
|
+
const journal = new index_1.TraceJournal();
|
|
163
|
+
for (let i = 0; i < 25; i += 1) {
|
|
164
|
+
journal.append({ entryClass: `class-${i}`, traceMarkId: `t${i}`, factPayload: { i } });
|
|
165
|
+
}
|
|
166
|
+
await (0, index_1.saveTraceJournal)(journal, file);
|
|
167
|
+
const loaded = await (0, index_1.loadTraceJournal)(file);
|
|
168
|
+
strict_1.default.equal(loaded.entries().length, 25);
|
|
169
|
+
loaded.entries().forEach((entry, i) => {
|
|
170
|
+
strict_1.default.equal(entry.entryClass, `class-${i}`);
|
|
171
|
+
strict_1.default.deepEqual(entry.factPayload, { i });
|
|
172
|
+
});
|
|
173
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
174
|
+
});
|
|
175
|
+
//# sourceMappingURL=trace_journal_persistence.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace_journal_persistence.test.js","sourceRoot":"","sources":["../../test/trace_journal_persistence.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace_persistence.test.d.ts","sourceRoot":"","sources":["../../test/trace_persistence.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const node_test_1 = require("node:test");
|
|
40
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
41
|
+
const node_fs_1 = require("node:fs");
|
|
42
|
+
const os = __importStar(require("node:os"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const core_hub_1 = require("@orbit/core-hub");
|
|
45
|
+
const core_hub_2 = require("@orbit/core-hub");
|
|
46
|
+
const core_hub_3 = require("@orbit/core-hub");
|
|
47
|
+
const infra_common_1 = require("@orbit/infra-common");
|
|
48
|
+
const infra_common_2 = require("@orbit/infra-common");
|
|
49
|
+
async function tempTracePath(name) {
|
|
50
|
+
const dir = await node_fs_1.promises.mkdtemp(path.join(os.tmpdir(), "orbit-trace-"));
|
|
51
|
+
return path.join(dir, name);
|
|
52
|
+
}
|
|
53
|
+
function journalWithCalls() {
|
|
54
|
+
const journal = new core_hub_1.RecordJournal();
|
|
55
|
+
journal.append({
|
|
56
|
+
channelKind: infra_common_2.ChannelKind.LLM_ACCESS,
|
|
57
|
+
funcName: "chatRound",
|
|
58
|
+
inputDigest: (0, infra_common_1.digestInputs)("hello"),
|
|
59
|
+
outputSnapshot: "hello-back",
|
|
60
|
+
durationMs: 320
|
|
61
|
+
});
|
|
62
|
+
journal.append({
|
|
63
|
+
channelKind: infra_common_2.ChannelKind.FILE_SYSTEM,
|
|
64
|
+
funcName: "readTextFile",
|
|
65
|
+
inputDigest: (0, infra_common_1.digestInputs)("a.txt"),
|
|
66
|
+
outputSnapshot: "file-content",
|
|
67
|
+
durationMs: 2
|
|
68
|
+
});
|
|
69
|
+
return journal;
|
|
70
|
+
}
|
|
71
|
+
(0, node_test_1.test)("persistence: save + load roundtrips a journal intact", async () => {
|
|
72
|
+
const file = await tempTracePath("trace.jsonl");
|
|
73
|
+
const original = journalWithCalls();
|
|
74
|
+
const count = await (0, core_hub_3.saveRecordJournal)(original, file);
|
|
75
|
+
strict_1.default.equal(count, 2);
|
|
76
|
+
const loaded = await (0, core_hub_3.loadRecordJournal)(file);
|
|
77
|
+
strict_1.default.equal(loaded.size(), 2);
|
|
78
|
+
const engine = new core_hub_2.ReplayEngine(loaded);
|
|
79
|
+
const out = engine.replayCall(infra_common_2.ChannelKind.LLM_ACCESS, "chatRound", (0, infra_common_1.digestInputs)("hello"), 0);
|
|
80
|
+
strict_1.default.equal(out, "hello-back");
|
|
81
|
+
const fileOut = engine.replayCall(infra_common_2.ChannelKind.FILE_SYSTEM, "readTextFile", (0, infra_common_1.digestInputs)("a.txt"), 1);
|
|
82
|
+
strict_1.default.equal(fileOut, "file-content");
|
|
83
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
84
|
+
});
|
|
85
|
+
(0, node_test_1.test)("persistence: file format is JSONL with a header line", async () => {
|
|
86
|
+
const file = await tempTracePath("trace.jsonl");
|
|
87
|
+
await (0, core_hub_3.saveRecordJournal)(journalWithCalls(), file);
|
|
88
|
+
const lines = (await node_fs_1.promises.readFile(file, "utf8")).split("\n").filter((l) => l.trim() !== "");
|
|
89
|
+
strict_1.default.equal(lines.length, 3);
|
|
90
|
+
const header = JSON.parse(lines[0]);
|
|
91
|
+
strict_1.default.deepEqual(header, { magic: "orbit-trace", version: 1, recordCount: 2 });
|
|
92
|
+
const first = JSON.parse(lines[1]);
|
|
93
|
+
strict_1.default.equal(first.funcName, "chatRound");
|
|
94
|
+
strict_1.default.equal(first.orderIndex, 0);
|
|
95
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
96
|
+
});
|
|
97
|
+
(0, node_test_1.test)("persistence: save creates parent directories and is atomic (no .tmp left behind)", async () => {
|
|
98
|
+
const dir = await node_fs_1.promises.mkdtemp(path.join(os.tmpdir(), "orbit-trace-dir-"));
|
|
99
|
+
const file = path.join(dir, "nested", "deep", "trace.jsonl");
|
|
100
|
+
await (0, core_hub_3.saveRecordJournal)(journalWithCalls(), file);
|
|
101
|
+
const entries = await node_fs_1.promises.readdir(path.dirname(file));
|
|
102
|
+
strict_1.default.deepEqual(entries, ["trace.jsonl"]);
|
|
103
|
+
await node_fs_1.promises.rm(dir, { recursive: true, force: true });
|
|
104
|
+
});
|
|
105
|
+
(0, node_test_1.test)("persistence: empty journal saves and loads back empty", async () => {
|
|
106
|
+
const file = await tempTracePath("empty.jsonl");
|
|
107
|
+
await (0, core_hub_3.saveRecordJournal)(new core_hub_1.RecordJournal(), file);
|
|
108
|
+
const loaded = await (0, core_hub_3.loadRecordJournal)(file);
|
|
109
|
+
strict_1.default.equal(loaded.size(), 0);
|
|
110
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
111
|
+
});
|
|
112
|
+
(0, node_test_1.test)("persistence: missing file throws TraceFileInvalidError", async () => {
|
|
113
|
+
await strict_1.default.rejects((0, core_hub_3.loadRecordJournal)(path.join(os.tmpdir(), "orbit-trace-nope.jsonl")), (err) => {
|
|
114
|
+
strict_1.default.ok(err instanceof core_hub_3.TraceFileInvalidError);
|
|
115
|
+
strict_1.default.match(err.message, /not found/);
|
|
116
|
+
return true;
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
(0, node_test_1.test)("persistence: non-trace files are rejected (bad magic)", async () => {
|
|
120
|
+
const file = await tempTracePath("foreign.jsonl");
|
|
121
|
+
await node_fs_1.promises.writeFile(file, '{"hello":"world"}\n', "utf8");
|
|
122
|
+
await strict_1.default.rejects((0, core_hub_3.loadRecordJournal)(file), (err) => {
|
|
123
|
+
strict_1.default.ok(err instanceof core_hub_3.TraceFileInvalidError);
|
|
124
|
+
strict_1.default.match(err.message, /bad magic/);
|
|
125
|
+
return true;
|
|
126
|
+
});
|
|
127
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
128
|
+
});
|
|
129
|
+
(0, node_test_1.test)("persistence: recordCount mismatch is rejected", async () => {
|
|
130
|
+
const file = await tempTracePath("mismatch.jsonl");
|
|
131
|
+
const original = journalWithCalls();
|
|
132
|
+
await (0, core_hub_3.saveRecordJournal)(original, file);
|
|
133
|
+
const lines = (await node_fs_1.promises.readFile(file, "utf8")).split("\n").filter((l) => l.trim() !== "");
|
|
134
|
+
const header = JSON.parse(lines[0]);
|
|
135
|
+
header.recordCount = 99;
|
|
136
|
+
lines[0] = JSON.stringify(header);
|
|
137
|
+
await node_fs_1.promises.writeFile(file, `${lines.join("\n")}\n`, "utf8");
|
|
138
|
+
await strict_1.default.rejects((0, core_hub_3.loadRecordJournal)(file), (err) => {
|
|
139
|
+
strict_1.default.ok(err instanceof core_hub_3.TraceFileInvalidError);
|
|
140
|
+
strict_1.default.match(err.message, /recordCount/);
|
|
141
|
+
return true;
|
|
142
|
+
});
|
|
143
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
144
|
+
});
|
|
145
|
+
(0, node_test_1.test)("persistence: tampered record content is caught by replay digest", async () => {
|
|
146
|
+
const file = await tempTracePath("tampered.jsonl");
|
|
147
|
+
await (0, core_hub_3.saveRecordJournal)(journalWithCalls(), file);
|
|
148
|
+
const lines = (await node_fs_1.promises.readFile(file, "utf8")).split("\n").filter((l) => l.trim() !== "");
|
|
149
|
+
const record = JSON.parse(lines[1]);
|
|
150
|
+
record.outputSnapshot = "tampered";
|
|
151
|
+
lines[1] = JSON.stringify(record);
|
|
152
|
+
await node_fs_1.promises.writeFile(file, `${lines.join("\n")}\n`, "utf8");
|
|
153
|
+
// Structural load succeeds; the tampering surfaces at replay as a drift.
|
|
154
|
+
const loaded = await (0, core_hub_3.loadRecordJournal)(file);
|
|
155
|
+
const engine = new core_hub_2.ReplayEngine(loaded);
|
|
156
|
+
const out = engine.replayCall(infra_common_2.ChannelKind.LLM_ACCESS, "chatRound", (0, infra_common_1.digestInputs)("hello"), 0);
|
|
157
|
+
strict_1.default.equal(out, "tampered");
|
|
158
|
+
const report = engine.reconcile(journalWithCalls().snapshot(), loaded.snapshot());
|
|
159
|
+
strict_1.default.equal(report.digestChainConsistent, false);
|
|
160
|
+
strict_1.default.equal(report.driftAtOrderIndex, 0);
|
|
161
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
162
|
+
});
|
|
163
|
+
(0, node_test_1.test)("persistence: orderIndex discontinuity is rejected", async () => {
|
|
164
|
+
const file = await tempTracePath("gap.jsonl");
|
|
165
|
+
const lines = [
|
|
166
|
+
JSON.stringify({ magic: "orbit-trace", version: 1, recordCount: 2 }),
|
|
167
|
+
JSON.stringify({
|
|
168
|
+
entryUid: "a",
|
|
169
|
+
orderIndex: 0,
|
|
170
|
+
channelKind: infra_common_2.ChannelKind.LLM_ACCESS,
|
|
171
|
+
funcName: "chatRound",
|
|
172
|
+
inputDigest: "d0",
|
|
173
|
+
outputSnapshot: "x",
|
|
174
|
+
durationMs: 1
|
|
175
|
+
}),
|
|
176
|
+
JSON.stringify({
|
|
177
|
+
entryUid: "b",
|
|
178
|
+
orderIndex: 5,
|
|
179
|
+
channelKind: infra_common_2.ChannelKind.LLM_ACCESS,
|
|
180
|
+
funcName: "chatRound",
|
|
181
|
+
inputDigest: "d1",
|
|
182
|
+
outputSnapshot: "y",
|
|
183
|
+
durationMs: 1
|
|
184
|
+
})
|
|
185
|
+
];
|
|
186
|
+
await node_fs_1.promises.writeFile(file, `${lines.join("\n")}\n`, "utf8");
|
|
187
|
+
await strict_1.default.rejects((0, core_hub_3.loadRecordJournal)(file), (err) => {
|
|
188
|
+
strict_1.default.ok(err instanceof core_hub_3.TraceFileInvalidError);
|
|
189
|
+
strict_1.default.match(err.message, /continuity/);
|
|
190
|
+
return true;
|
|
191
|
+
});
|
|
192
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
193
|
+
});
|
|
194
|
+
(0, node_test_1.test)("persistence: malformed JSON lines are rejected with line numbers", async () => {
|
|
195
|
+
const file = await tempTracePath("broken.jsonl");
|
|
196
|
+
await node_fs_1.promises.writeFile(file, '{"magic":"orbit-trace","version":1,"recordCount":1}\nnot-json\n', "utf8");
|
|
197
|
+
await strict_1.default.rejects((0, core_hub_3.loadRecordJournal)(file), (err) => {
|
|
198
|
+
strict_1.default.ok(err instanceof core_hub_3.TraceFileInvalidError);
|
|
199
|
+
strict_1.default.equal(err.lineNo, 2);
|
|
200
|
+
return true;
|
|
201
|
+
});
|
|
202
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
203
|
+
});
|
|
204
|
+
(0, node_test_1.test)("persistence: a truncated (half-written) file fails recordCount validation", async () => {
|
|
205
|
+
const file = await tempTracePath("truncated.jsonl");
|
|
206
|
+
await (0, core_hub_3.saveRecordJournal)(journalWithCalls(), file);
|
|
207
|
+
const lines = (await node_fs_1.promises.readFile(file, "utf8")).split("\n").filter((l) => l.trim() !== "");
|
|
208
|
+
await node_fs_1.promises.writeFile(file, `${lines.slice(0, 2).join("\n")}\n`, "utf8"); // header + 1 of 2 records
|
|
209
|
+
await strict_1.default.rejects((0, core_hub_3.loadRecordJournal)(file), (err) => {
|
|
210
|
+
strict_1.default.ok(err instanceof core_hub_3.TraceFileInvalidError);
|
|
211
|
+
strict_1.default.match(err.message, /recordCount/);
|
|
212
|
+
return true;
|
|
213
|
+
});
|
|
214
|
+
await node_fs_1.promises.rm(path.dirname(file), { recursive: true, force: true });
|
|
215
|
+
});
|
|
216
|
+
//# sourceMappingURL=trace_persistence.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace_persistence.test.js","sourceRoot":"","sources":["../../test/trace_persistence.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trip_protector.test.d.ts","sourceRoot":"","sources":["../../test/trip_protector.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const core_hub_1 = require("@orbit/core-hub");
|
|
9
|
+
const infra_common_1 = require("@orbit/infra-common");
|
|
10
|
+
(0, node_test_1.test)("连续失败达到阈值触发跳闸并快速拦截", async () => {
|
|
11
|
+
const trip = new core_hub_1.TripProtector(2, 10000);
|
|
12
|
+
const fail = async () => {
|
|
13
|
+
throw new Error("boom");
|
|
14
|
+
};
|
|
15
|
+
await strict_1.default.rejects(trip.execWithProtect(fail));
|
|
16
|
+
await strict_1.default.rejects(trip.execWithProtect(fail));
|
|
17
|
+
strict_1.default.equal(trip.snapshot().state, infra_common_1.TripState.TRIPPED);
|
|
18
|
+
await strict_1.default.rejects(trip.execWithProtect(fail), /trip protector active/);
|
|
19
|
+
});
|
|
20
|
+
(0, node_test_1.test)("冷却后进入探测,单次成功即恢复", async () => {
|
|
21
|
+
const trip = new core_hub_1.TripProtector(1, 30);
|
|
22
|
+
await strict_1.default.rejects(trip.execWithProtect(async () => {
|
|
23
|
+
throw new Error("boom");
|
|
24
|
+
}));
|
|
25
|
+
strict_1.default.equal(trip.snapshot().state, infra_common_1.TripState.TRIPPED);
|
|
26
|
+
await new Promise((resolve) => setTimeout(resolve, 40));
|
|
27
|
+
const ok = await trip.execWithProtect(async () => "ok");
|
|
28
|
+
strict_1.default.equal(ok, "ok");
|
|
29
|
+
strict_1.default.equal(trip.snapshot().state, infra_common_1.TripState.NORMAL);
|
|
30
|
+
});
|
|
31
|
+
(0, node_test_1.test)("成功后重置失败计数", async () => {
|
|
32
|
+
const trip = new core_hub_1.TripProtector(3, 10000);
|
|
33
|
+
const fail = async () => {
|
|
34
|
+
throw new Error("x");
|
|
35
|
+
};
|
|
36
|
+
await strict_1.default.rejects(trip.execWithProtect(fail));
|
|
37
|
+
await strict_1.default.rejects(trip.execWithProtect(fail));
|
|
38
|
+
await trip.execWithProtect(async () => "ok");
|
|
39
|
+
await strict_1.default.rejects(trip.execWithProtect(fail));
|
|
40
|
+
strict_1.default.equal(trip.snapshot().state, infra_common_1.TripState.NORMAL);
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=trip_protector.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trip_protector.test.js","sourceRoot":"","sources":["../../test/trip_protector.test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAiC;AACjC,gEAAwC;AACxC,8CAAgD;AAChD,sDAAgD;AAEhD,IAAA,gBAAI,EAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;IACnC,MAAM,IAAI,GAAG,IAAI,wBAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,KAAK,IAAqB,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC;IACF,MAAM,gBAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,MAAM,gBAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,gBAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,wBAAS,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,gBAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,uBAAuB,CAAC,CAAC;AAC5E,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;IACjC,MAAM,IAAI,GAAG,IAAI,wBAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtC,MAAM,gBAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,IAAI,EAAE;QACnD,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC,CAAC;IACJ,gBAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,wBAAS,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;IACxD,gBAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACvB,gBAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,wBAAS,CAAC,MAAM,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IAC3B,MAAM,IAAI,GAAG,IAAI,wBAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,KAAK,IAAqB,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC;IACF,MAAM,gBAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,MAAM,gBAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,gBAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,gBAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,wBAAS,CAAC,MAAM,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Run each example with a plain `node` — no build step, no extra dependencies:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# 1. a custom deterministic channel: wire it in, record, replay byte-identically
|
|
7
|
+
node examples/custom-channel.mjs
|
|
8
|
+
|
|
9
|
+
# 2. a JS plugin adapter (PAE, L0): foreign in-process tools through the gateway
|
|
10
|
+
node examples/js-pae-plugin.mjs
|
|
11
|
+
|
|
12
|
+
# 3. an MCP adapter (PAE, L2): a real stdio child process, handshake-discovered
|
|
13
|
+
node examples/mcp-adapter.mjs
|
|
14
|
+
|
|
15
|
+
# 4. the orbit CLI record → replay → diff loop, driven exactly as a user would
|
|
16
|
+
node examples/cli-record-replay.mjs
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Example | Shows |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `custom-channel.mjs` | Implementing `IChannelProvider`, registering it, and proving the record → replay loop is byte-identical — plus drift detection when a call is tampered with |
|
|
22
|
+
| `js-pae-plugin.mjs` | Mapping plain JS functions onto the capability contract via `JsPaeAdapter`; the adapter surface becomes a governed channel whose output replays verbatim |
|
|
23
|
+
| `mcp-adapter.mjs` | Spawning a real MCP server child, `initialize` → `tools/list` handshake, recorded call, then replay **after the peer is dead** (the frozen output is injected, the child is never re-entered) |
|
|
24
|
+
| `cli-record-replay.mjs` | The three-command reproducibility story: `orbit record` → `orbit replay` (zero channel calls) → `orbit diff` (digest-chain reconciliation) |
|
|
25
|
+
|
|
26
|
+
The imports use relative paths so the examples run inside the repository;
|
|
27
|
+
after `npm i orbit-agent-runtime` they become plain package imports:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import { OrbitRuntimeHost, ChannelKind } from "orbit-agent-runtime";
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Every example exits non-zero on any failed assertion, so they can be used as
|
|
34
|
+
smoke checks in CI (`node examples/custom-channel.mjs && ...`).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 4 — the orbit CLI record → replay → diff loop.
|
|
3
|
+
*
|
|
4
|
+
* The CLI is the reproducibility story in three commands: record a script
|
|
5
|
+
* against a live kernel, replay the trace with zero channel calls, and diff
|
|
6
|
+
* two traces to locate the first digest-chain breakpoint.
|
|
7
|
+
*
|
|
8
|
+
* This file drives the CLI exactly as a user would, showing every command's
|
|
9
|
+
* output. Run: node examples/cli-record-replay.mjs
|
|
10
|
+
*/
|
|
11
|
+
import { spawnSync } from "node:child_process";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import * as fs from "node:fs";
|
|
14
|
+
import * as path from "node:path";
|
|
15
|
+
import * as os from "node:os";
|
|
16
|
+
|
|
17
|
+
const REPO = path.resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
18
|
+
const ORBIT = path.join(REPO, "bin", "orbit.mjs");
|
|
19
|
+
|
|
20
|
+
/** A small agent script exercising both the LLM and the KV channel. */
|
|
21
|
+
const AGENT_SCRIPT = `
|
|
22
|
+
export default async (ctx) => {
|
|
23
|
+
const a = await ctx.llm.chat("hello orbit");
|
|
24
|
+
const b = await ctx.call(ctx.ChannelKind.MEM_KV_STORE, "readEntry", "alpha");
|
|
25
|
+
const c = await ctx.call(ctx.ChannelKind.LLM_ACCESS, "chatRound", a);
|
|
26
|
+
return { a, b, c };
|
|
27
|
+
};
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
function run(args, label) {
|
|
31
|
+
console.log(`\n$ orbit ${args.join(" ")}`);
|
|
32
|
+
const res = spawnSync(process.execPath, [ORBIT, ...args], { cwd: REPO, encoding: "utf8" });
|
|
33
|
+
if (res.status !== 0) {
|
|
34
|
+
console.error(res.stderr || res.stdout);
|
|
35
|
+
process.exit(res.status ?? 1);
|
|
36
|
+
}
|
|
37
|
+
console.log((res.stdout || "").trim().split("\n").slice(0, 8).join("\n"));
|
|
38
|
+
return res.stdout;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function main() {
|
|
42
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "orbit-example-"));
|
|
43
|
+
const script = path.join(dir, "agent.mjs");
|
|
44
|
+
const traceA = path.join(dir, "a.jsonl");
|
|
45
|
+
const traceB = path.join(dir, "b.jsonl");
|
|
46
|
+
fs.writeFileSync(script, AGENT_SCRIPT, "utf8");
|
|
47
|
+
|
|
48
|
+
console.log("=== example 4 · orbit CLI record → replay → diff ===");
|
|
49
|
+
console.log(`[trace] temp dir: ${dir}`);
|
|
50
|
+
|
|
51
|
+
// 1) Record: run the script against a live kernel, capture every channel
|
|
52
|
+
// call into a trace file.
|
|
53
|
+
run(["record", script, "--out", traceA], "record");
|
|
54
|
+
|
|
55
|
+
// 2) Replay: re-run the recorded script with ZERO real channel calls and
|
|
56
|
+
// reconcile the replayed chain against the original.
|
|
57
|
+
const replayOut = run(["replay", traceA], "replay");
|
|
58
|
+
|
|
59
|
+
// 3) Diff: a trace compared with itself must be perfectly consistent.
|
|
60
|
+
const diffOut = run(["diff", traceA, traceA], "diff");
|
|
61
|
+
|
|
62
|
+
if (!/consistent|identical|一致/i.test(replayOut + diffOut)) {
|
|
63
|
+
console.error("FAIL: replay/diff did not report a consistent chain");
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
68
|
+
console.log("\nOK — record → replay → diff loop closed with a consistent chain");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main().catch((err) => {
|
|
72
|
+
console.error(err);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|