@zanii/blackbox 0.0.0-stage → 0.1.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/LICENSE +202 -0
- package/README.md +109 -2
- package/dist/agents/index.d.ts +34 -0
- package/dist/agents/index.js +73 -0
- package/dist/analysis/detectors.d.ts +36 -0
- package/dist/analysis/detectors.js +339 -0
- package/dist/analysis/faults.d.ts +9 -0
- package/dist/analysis/faults.js +210 -0
- package/dist/analysis/index.d.ts +68 -0
- package/dist/analysis/index.js +388 -0
- package/dist/analysis/landing.d.ts +25 -0
- package/dist/analysis/landing.js +225 -0
- package/dist/analysis/memory.d.ts +13 -0
- package/dist/analysis/memory.js +33 -0
- package/dist/analysis/waste.d.ts +29 -0
- package/dist/analysis/waste.js +79 -0
- package/dist/approvals/index.d.ts +11 -0
- package/dist/approvals/index.js +27 -0
- package/dist/approvals/warnings.d.ts +2 -0
- package/dist/approvals/warnings.js +28 -0
- package/dist/attest/index.d.ts +17 -0
- package/dist/attest/index.js +106 -0
- package/dist/authority/index.d.ts +24 -0
- package/dist/authority/index.js +77 -0
- package/dist/billing/index.d.ts +99 -0
- package/dist/billing/index.js +174 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1019 -0
- package/dist/client/index.d.ts +146 -0
- package/dist/client/index.js +210 -0
- package/dist/compliance/index.d.ts +41 -0
- package/dist/compliance/index.js +96 -0
- package/dist/cost/index.d.ts +133 -0
- package/dist/cost/index.js +293 -0
- package/dist/directives/index.d.ts +35 -0
- package/dist/directives/index.js +80 -0
- package/dist/drills/index.d.ts +43 -0
- package/dist/drills/index.js +101 -0
- package/dist/duty/index.d.ts +21 -0
- package/dist/duty/index.js +68 -0
- package/dist/fleet/index.d.ts +141 -0
- package/dist/fleet/index.js +454 -0
- package/dist/hooks/ai-sdk.d.ts +42 -0
- package/dist/hooks/ai-sdk.js +62 -0
- package/dist/hooks/claude-agent-sdk.d.ts +14 -0
- package/dist/hooks/claude-agent-sdk.js +70 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/hooks/index.js +10 -0
- package/dist/hooks/langchain-agent.d.ts +69 -0
- package/dist/hooks/langchain-agent.js +163 -0
- package/dist/hooks/langchain.d.ts +41 -0
- package/dist/hooks/langchain.js +216 -0
- package/dist/hooks/langgraph-checkpoint.d.ts +12 -0
- package/dist/hooks/langgraph-checkpoint.js +73 -0
- package/dist/hooks/memory.d.ts +17 -0
- package/dist/hooks/memory.js +64 -0
- package/dist/hooks/openai-agents.d.ts +6 -0
- package/dist/hooks/openai-agents.js +40 -0
- package/dist/hooks/protect.d.ts +7 -0
- package/dist/hooks/protect.js +39 -0
- package/dist/hooks/providers.d.ts +16 -0
- package/dist/hooks/providers.js +149 -0
- package/dist/hooks/shared.d.ts +11 -0
- package/dist/hooks/shared.js +39 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +47 -0
- package/dist/investigate/index.d.ts +66 -0
- package/dist/investigate/index.js +119 -0
- package/dist/mcp-server/index.d.ts +85 -0
- package/dist/mcp-server/index.js +216 -0
- package/dist/mcp-wrap/index.d.ts +17 -0
- package/dist/mcp-wrap/index.js +170 -0
- package/dist/money/index.d.ts +114 -0
- package/dist/money/index.js +622 -0
- package/dist/occurrence/index.d.ts +108 -0
- package/dist/occurrence/index.js +168 -0
- package/dist/ocsf/index.d.ts +22 -0
- package/dist/ocsf/index.js +168 -0
- package/dist/otlp/index.d.ts +24 -0
- package/dist/otlp/index.js +143 -0
- package/dist/packs/index.d.ts +40 -0
- package/dist/packs/index.js +217 -0
- package/dist/policy/delta.d.ts +11 -0
- package/dist/policy/delta.js +39 -0
- package/dist/policy/drafts.d.ts +34 -0
- package/dist/policy/drafts.js +129 -0
- package/dist/policy/index.d.ts +47 -0
- package/dist/policy/index.js +154 -0
- package/dist/precog/index.d.ts +96 -0
- package/dist/precog/index.js +167 -0
- package/dist/precog/intervention.d.ts +22 -0
- package/dist/precog/intervention.js +44 -0
- package/dist/precog/normal.d.ts +31 -0
- package/dist/precog/normal.js +89 -0
- package/dist/preflight/index.d.ts +11 -0
- package/dist/preflight/index.js +19 -0
- package/dist/ratings/index.d.ts +21 -0
- package/dist/ratings/index.js +48 -0
- package/dist/reconcile/claude-code.d.ts +19 -0
- package/dist/reconcile/claude-code.js +220 -0
- package/dist/reconcile/codex.d.ts +5 -0
- package/dist/reconcile/codex.js +191 -0
- package/dist/reconcile/index.d.ts +19 -0
- package/dist/reconcile/index.js +50 -0
- package/dist/reconcile/record.d.ts +49 -0
- package/dist/reconcile/record.js +225 -0
- package/dist/reconcile/shared.d.ts +65 -0
- package/dist/reconcile/shared.js +113 -0
- package/dist/replay/index.d.ts +11 -0
- package/dist/replay/index.js +64 -0
- package/dist/replay/repair.d.ts +10 -0
- package/dist/replay/repair.js +62 -0
- package/dist/session/drain.d.ts +13 -0
- package/dist/session/drain.js +35 -0
- package/dist/session/index.d.ts +256 -0
- package/dist/session/index.js +658 -0
- package/dist/undo/index.d.ts +45 -0
- package/dist/undo/index.js +212 -0
- package/dist/verify/anchor.d.ts +54 -0
- package/dist/verify/anchor.js +77 -0
- package/dist/verify/chain.d.ts +27 -0
- package/dist/verify/chain.js +105 -0
- package/dist/verify/envelope.d.ts +28 -0
- package/dist/verify/envelope.js +55 -0
- package/dist/verify/index.d.ts +3 -0
- package/dist/verify/index.js +3 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/dist/weather/index.d.ts +24 -0
- package/dist/weather/index.js +45 -0
- package/dist/workspace-receipt/index.d.ts +15 -0
- package/dist/workspace-receipt/index.js +121 -0
- package/package.json +56 -3
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// A LangGraph.js checkpointer that records what it saves (spec/sdk.md §5.3, ideas R1, R2).
|
|
2
|
+
// Mirrors hooks/langgraph_checkpoint.py.
|
|
3
|
+
//
|
|
4
|
+
// const app = graph.compile({ checkpointer: blackboxCheckpointer(new MemorySaver(), session) });
|
|
5
|
+
//
|
|
6
|
+
// Every `put` is a `checkpoint.put` event and every `putWrites` a `checkpoint.writes` event: ids,
|
|
7
|
+
// the step, the source and channel names, never the values. The wrapper is the inner saver with
|
|
8
|
+
// two methods replaced (its prototype is the inner one, so `instanceof BaseCheckpointSaver` still
|
|
9
|
+
// holds): the SDK needs no LangGraph dependency.
|
|
10
|
+
import { stableEventId } from "../session/index.js";
|
|
11
|
+
import { neverThrow } from "./shared.js";
|
|
12
|
+
export function blackboxCheckpointer(inner, session) {
|
|
13
|
+
const emit = (type, name, data, key) => neverThrow(() => session.event(type, name, data, {
|
|
14
|
+
eventId: stableEventId("checkpoint", type, ...key),
|
|
15
|
+
}));
|
|
16
|
+
const where = (config) => {
|
|
17
|
+
const c = config?.configurable ?? {};
|
|
18
|
+
return Object.fromEntries(["thread_id", "checkpoint_ns", "checkpoint_id"]
|
|
19
|
+
.filter((k) => c[k] !== undefined && c[k] !== null)
|
|
20
|
+
.map((k) => [k, String(c[k])]));
|
|
21
|
+
};
|
|
22
|
+
// Every method runs on the inner saver itself, so its own state stays its own.
|
|
23
|
+
const wrapped = Object.create(inner);
|
|
24
|
+
let p = inner;
|
|
25
|
+
while (p && p !== Object.prototype) {
|
|
26
|
+
for (const name of Object.getOwnPropertyNames(p)) {
|
|
27
|
+
const v = inner[name];
|
|
28
|
+
if (name !== "constructor" &&
|
|
29
|
+
typeof v === "function" &&
|
|
30
|
+
!(name in wrapped && Object.hasOwn(wrapped, name)))
|
|
31
|
+
Object.defineProperty(wrapped, name, {
|
|
32
|
+
value: v.bind(inner),
|
|
33
|
+
writable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
p = Object.getPrototypeOf(p);
|
|
38
|
+
}
|
|
39
|
+
wrapped.put = async (config, checkpoint, metadata, versions) => {
|
|
40
|
+
const out = await inner.put(config, checkpoint, metadata, versions);
|
|
41
|
+
const w = where(config);
|
|
42
|
+
const m = (metadata ?? {});
|
|
43
|
+
const data = {
|
|
44
|
+
thread_id: w.thread_id ?? "",
|
|
45
|
+
checkpoint_ns: w.checkpoint_ns ?? "",
|
|
46
|
+
checkpoint_id: String(checkpoint?.id ?? ""),
|
|
47
|
+
...(w.checkpoint_id ? { parent_checkpoint_id: w.checkpoint_id } : {}),
|
|
48
|
+
...(Number.isSafeInteger(m.step) ? { step: m.step } : {}),
|
|
49
|
+
...(m.source ? { source: String(m.source) } : {}),
|
|
50
|
+
channels: Object.keys(versions ?? {}).sort(),
|
|
51
|
+
};
|
|
52
|
+
emit("checkpoint.put", data.source, data, [
|
|
53
|
+
data.thread_id,
|
|
54
|
+
data.checkpoint_ns,
|
|
55
|
+
data.checkpoint_id,
|
|
56
|
+
]);
|
|
57
|
+
return out;
|
|
58
|
+
};
|
|
59
|
+
wrapped.putWrites = async (config, writes, taskId) => {
|
|
60
|
+
await inner.putWrites(config, writes, taskId);
|
|
61
|
+
const w = where(config);
|
|
62
|
+
const channels = writes.map(([c]) => String(c));
|
|
63
|
+
emit("checkpoint.writes", undefined, {
|
|
64
|
+
...w,
|
|
65
|
+
task_id: taskId,
|
|
66
|
+
channels,
|
|
67
|
+
error: channels.includes("__error__"),
|
|
68
|
+
interrupt: channels.includes("__interrupt__"),
|
|
69
|
+
resume: channels.includes("__resume__"),
|
|
70
|
+
}, [w.thread_id ?? "", w.checkpoint_id ?? "", taskId, ...channels]);
|
|
71
|
+
};
|
|
72
|
+
return wrapped;
|
|
73
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface MemorySink {
|
|
2
|
+
memoryWrite(memoryId: string, summary?: string): void;
|
|
3
|
+
memoryRead(memoryIds: string[], query?: string): void;
|
|
4
|
+
memoryRevoke(memoryId: string, reason?: string): void;
|
|
5
|
+
}
|
|
6
|
+
export interface MemoryMethod {
|
|
7
|
+
/** The store's method name. */
|
|
8
|
+
method: string;
|
|
9
|
+
/** The memory ids a call touched, from its result and arguments. */
|
|
10
|
+
ids?: (result: unknown, args: unknown[]) => string[];
|
|
11
|
+
}
|
|
12
|
+
export interface TrackMemoryOptions {
|
|
13
|
+
write?: MemoryMethod;
|
|
14
|
+
read?: MemoryMethod;
|
|
15
|
+
revoke?: MemoryMethod;
|
|
16
|
+
}
|
|
17
|
+
export declare function trackMemory<T extends object>(store: T, sink: MemorySink, options?: TrackMemoryOptions): T;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Audit S10: a memory store, wrapped so its writes, reads and deletes are recorded for the Memory
|
|
2
|
+
// X-ray (spec/agents.md §1) without wiring memoryWrite / memoryRead / memoryRevoke by hand.
|
|
3
|
+
// Duck-typed; the defaults fit mem0-shaped stores (add / search / delete, `{results: [{id, memory}]}`).
|
|
4
|
+
// Mirrors sdks/python/src/zanii_blackbox/hooks/memory.py.
|
|
5
|
+
//
|
|
6
|
+
// const memory = trackMemory(new Memory(), session);
|
|
7
|
+
// await memory.add(messages, { userId }); // → memory.write, one per memory id
|
|
8
|
+
import { neverThrow } from "./shared.js";
|
|
9
|
+
/** Items with an `id`: an array, `{results: [...]}`, or one item. */
|
|
10
|
+
function itemsOf(result) {
|
|
11
|
+
if (Array.isArray(result))
|
|
12
|
+
return result;
|
|
13
|
+
const r = result;
|
|
14
|
+
if (r && Array.isArray(r.results))
|
|
15
|
+
return r.results;
|
|
16
|
+
if (r && typeof r === "object" && typeof r.id === "string")
|
|
17
|
+
return [r];
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
const idsOf = (result) => itemsOf(result)
|
|
21
|
+
.map((i) => i.id)
|
|
22
|
+
.filter((id) => typeof id === "string");
|
|
23
|
+
const DEFAULTS = {
|
|
24
|
+
write: { method: "add", ids: idsOf },
|
|
25
|
+
read: { method: "search", ids: idsOf },
|
|
26
|
+
// delete(memoryId): the id is the argument
|
|
27
|
+
revoke: { method: "delete", ids: (_r, args) => (typeof args[0] === "string" ? [args[0]] : []) },
|
|
28
|
+
};
|
|
29
|
+
export function trackMemory(store, sink, options = {}) {
|
|
30
|
+
const kinds = {
|
|
31
|
+
write: { ...DEFAULTS.write, ...options.write },
|
|
32
|
+
read: { ...DEFAULTS.read, ...options.read },
|
|
33
|
+
revoke: { ...DEFAULTS.revoke, ...options.revoke },
|
|
34
|
+
};
|
|
35
|
+
const record = (kind, result, args) => neverThrow(() => {
|
|
36
|
+
const ids = (kinds[kind].ids ?? idsOf)(result, args);
|
|
37
|
+
if (kind === "read") {
|
|
38
|
+
sink.memoryRead(ids, typeof args[0] === "string" ? args[0] : undefined);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const summaries = new Map(itemsOf(result).map((i) => [i.id, typeof i.memory === "string" ? i.memory : undefined]));
|
|
42
|
+
for (const id of ids)
|
|
43
|
+
if (kind === "write")
|
|
44
|
+
sink.memoryWrite(id, summaries.get(id)?.slice(0, 200));
|
|
45
|
+
else
|
|
46
|
+
sink.memoryRevoke(id);
|
|
47
|
+
});
|
|
48
|
+
return new Proxy(store, {
|
|
49
|
+
get(obj, prop, receiver) {
|
|
50
|
+
const value = Reflect.get(obj, prop, receiver);
|
|
51
|
+
const kind = Object.keys(kinds).find((k) => kinds[k].method === prop);
|
|
52
|
+
if (!kind || typeof value !== "function")
|
|
53
|
+
return value;
|
|
54
|
+
return (...args) => {
|
|
55
|
+
const result = value.apply(obj, args);
|
|
56
|
+
if (typeof result?.then === "function")
|
|
57
|
+
result.then((r) => record(kind, r, args), () => { });
|
|
58
|
+
else
|
|
59
|
+
record(kind, result, args);
|
|
60
|
+
return result;
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// OpenAI Agents SDK (JS) run hooks (spec/sdk.md §5). Mirrors hooks/openai_agents.py.
|
|
2
|
+
//
|
|
3
|
+
// const runner = new Runner(); attachBlackbox(runner, session); await runner.run(agent, "…");
|
|
4
|
+
//
|
|
5
|
+
// The JS SDK's hooks are events on the Runner (agent / handoff / tool); it has no model-call event,
|
|
6
|
+
// so model-call ids come from the gateway alone here.
|
|
7
|
+
import { neverThrow } from "./shared.js";
|
|
8
|
+
const nameOf = (x) => String(x?.name ?? "agent").slice(0, 256);
|
|
9
|
+
/** Audit K23: the SDK turns a tool's exception into this answer (its default error function), so a
|
|
10
|
+
* tool that failed isn't recorded as a success. */
|
|
11
|
+
const TOOL_ERROR = "An error occurred while running the tool.";
|
|
12
|
+
const failed = (result) => typeof result === "string" && result.startsWith(TOOL_ERROR);
|
|
13
|
+
export function attachBlackbox(runner, session) {
|
|
14
|
+
const on = (event, listener) => runner.on(event, ((...args) => neverThrow(() => listener(...args))));
|
|
15
|
+
on("agent_start", (_context, agent) => session.event("step", nameOf(agent), {}));
|
|
16
|
+
on("agent_handoff", (_context, from, to) => session.event("step", nameOf(to), { handoff_from: nameOf(from) }));
|
|
17
|
+
on("agent_tool_start", (_context, agent, tool, details) => {
|
|
18
|
+
const call = details
|
|
19
|
+
?.toolCall;
|
|
20
|
+
let args = call?.arguments;
|
|
21
|
+
try {
|
|
22
|
+
args = typeof args === "string" ? JSON.parse(args) : args;
|
|
23
|
+
}
|
|
24
|
+
catch { }
|
|
25
|
+
session.event("tool.call", nameOf(tool), {
|
|
26
|
+
agent: nameOf(agent),
|
|
27
|
+
...(call?.callId ? { call_id: call.callId } : {}),
|
|
28
|
+
...(args === undefined ? {} : { args }),
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
on("agent_tool_end", (_context, agent, tool, result, details) => {
|
|
32
|
+
const callId = details?.toolCall?.callId;
|
|
33
|
+
session.event("tool.result", nameOf(tool), {
|
|
34
|
+
ok: !failed(result),
|
|
35
|
+
agent: nameOf(agent),
|
|
36
|
+
...(callId ? { call_id: callId } : {}),
|
|
37
|
+
...(failed(result) ? { error: String(result).slice(0, 500) } : {}),
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const MANAGED_START = "<!-- blackbox:managed:start -->";
|
|
2
|
+
export declare const MANAGED_END = "<!-- blackbox:managed:end -->";
|
|
3
|
+
/** The managed block (markers included), or null when the text has none. */
|
|
4
|
+
export declare function managedBlock(text: string): string | null;
|
|
5
|
+
/** Why this file tool call must not run, or null. `current` is the file's text now (null when
|
|
6
|
+
* it doesn't exist). Tools: write_file {content}, edit_file {old_string, new_string}, delete. */
|
|
7
|
+
export declare function protectedEdit(current: string | null, tool: string, args: Record<string, unknown>): string | null;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Protected regions (spec/sdk.md §5.2, idea S5): a machine-managed block in a file the agent may
|
|
2
|
+
// edit (an AGENTS.md, a memory file), between `<!-- blackbox:managed:start -->` and
|
|
3
|
+
// `<!-- blackbox:managed:end -->`. A write, edit or delete that would change or remove it is
|
|
4
|
+
// refused before the tool runs. Mirrors protect.py.
|
|
5
|
+
export const MANAGED_START = "<!-- blackbox:managed:start -->";
|
|
6
|
+
export const MANAGED_END = "<!-- blackbox:managed:end -->";
|
|
7
|
+
/** The managed block (markers included), or null when the text has none. */
|
|
8
|
+
export function managedBlock(text) {
|
|
9
|
+
const i = text.indexOf(MANAGED_START);
|
|
10
|
+
const j = i < 0 ? -1 : text.indexOf(MANAGED_END, i);
|
|
11
|
+
return i < 0 || j < 0 ? null : text.slice(i, j + MANAGED_END.length);
|
|
12
|
+
}
|
|
13
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
14
|
+
/** Why this file tool call must not run, or null. `current` is the file's text now (null when
|
|
15
|
+
* it doesn't exist). Tools: write_file {content}, edit_file {old_string, new_string}, delete. */
|
|
16
|
+
export function protectedEdit(current, tool, args) {
|
|
17
|
+
const block = current === null ? null : managedBlock(current);
|
|
18
|
+
if (block === null)
|
|
19
|
+
return null;
|
|
20
|
+
const path = str(args.file_path) ?? str(args.path) ?? "the file";
|
|
21
|
+
const refuse = `blackbox: ${path} has a machine-managed block (between the blackbox:managed markers) that can't be changed or removed. The edit wasn't applied.`;
|
|
22
|
+
if (tool === "delete" || tool === "delete_file" || tool === "rm")
|
|
23
|
+
return `${refuse}`;
|
|
24
|
+
if (tool === "write_file") {
|
|
25
|
+
const content = str(args.content) ?? "";
|
|
26
|
+
return managedBlock(content) === block ? null : refuse;
|
|
27
|
+
}
|
|
28
|
+
if (tool === "edit_file") {
|
|
29
|
+
const oldText = str(args.old_string);
|
|
30
|
+
const newText = str(args.new_string) ?? "";
|
|
31
|
+
if (oldText === undefined || !current.includes(oldText))
|
|
32
|
+
return null; // the tool fails itself
|
|
33
|
+
const after = args.replace_all === true
|
|
34
|
+
? current.split(oldText).join(newText)
|
|
35
|
+
: current.replace(oldText, () => newText);
|
|
36
|
+
return managedBlock(after) === block ? null : refuse;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type EventSink } from "./shared.ts";
|
|
2
|
+
/** The ids a provider's response (or its first stream event) carries, as `llmCall` takes them:
|
|
3
|
+
* Anthropic, OpenAI and OpenAI-compatible APIs (by `object`), Gemini and Vertex (`responseId`), and
|
|
4
|
+
* Bedrock (the AWS SDK's `$metadata.requestId`) (audit K4). */
|
|
5
|
+
export declare function llmIdsOf(response: unknown): Record<string, string>;
|
|
6
|
+
/** `client.messages.create` and `.stream` report each model call to the session. */
|
|
7
|
+
export declare function wrapAnthropic<T extends object>(client: T, sink: EventSink): T;
|
|
8
|
+
/** `client.chat.completions.create` / `.stream` and `client.responses.create` / `.stream` report
|
|
9
|
+
* each model call. */
|
|
10
|
+
export declare function wrapOpenAI<T extends object>(client: T, sink: EventSink): T;
|
|
11
|
+
/** Audit K4: Google's `@google/genai` client (Gemini, and Vertex AI with `vertexai: true`):
|
|
12
|
+
* `models.generateContent` and `models.generateContentStream` report each model call. */
|
|
13
|
+
export declare function wrapGemini<T extends object>(client: T, sink: EventSink): T;
|
|
14
|
+
/** Audit K4: the AWS SDK's `BedrockRuntimeClient`: every `send(command)` (Converse, ConverseStream,
|
|
15
|
+
* InvokeModel, …) reports its request id, which the gateway records from `x-amzn-requestid`. */
|
|
16
|
+
export declare function wrapBedrock<T extends object>(client: T, sink: EventSink): T;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Audit S9 / S18: report model calls made with the official Anthropic and OpenAI clients, so the
|
|
2
|
+
// dual witness (spec/findings.md §2) works without the app calling llmCall by hand. Duck-typed: no
|
|
3
|
+
// dependency on either client. Mirrors sdks/python/src/zanii_blackbox/hooks/providers.py.
|
|
4
|
+
//
|
|
5
|
+
// const anthropic = wrapAnthropic(new Anthropic({ baseURL: gateway }), session);
|
|
6
|
+
// const openai = wrapOpenAI(new OpenAI({ baseURL: gateway }), session);
|
|
7
|
+
import { llmIds, neverThrow, providerOf } from "./shared.js";
|
|
8
|
+
/** The ids a provider's response (or its first stream event) carries, as `llmCall` takes them:
|
|
9
|
+
* Anthropic, OpenAI and OpenAI-compatible APIs (by `object`), Gemini and Vertex (`responseId`), and
|
|
10
|
+
* Bedrock (the AWS SDK's `$metadata.requestId`) (audit K4). */
|
|
11
|
+
export function llmIdsOf(response) {
|
|
12
|
+
const r = (response ?? {});
|
|
13
|
+
const google = r.responseId;
|
|
14
|
+
if (typeof google === "string" && ("candidates" in r || "usageMetadata" in r))
|
|
15
|
+
return {
|
|
16
|
+
provider: "gemini",
|
|
17
|
+
response_id: google,
|
|
18
|
+
...(typeof r.modelVersion === "string" ? { model: r.modelVersion } : {}),
|
|
19
|
+
};
|
|
20
|
+
const aws = r.$metadata?.requestId;
|
|
21
|
+
if (typeof aws === "string")
|
|
22
|
+
return { provider: "bedrock", request_id: aws };
|
|
23
|
+
// A stream event: Anthropic's message_start carries `message`, OpenAI's response.* `response`.
|
|
24
|
+
const inner = (typeof r.message === "object" && r.message) ||
|
|
25
|
+
(typeof r.response === "object" && r.response) ||
|
|
26
|
+
r;
|
|
27
|
+
const o = inner;
|
|
28
|
+
const id = typeof o.id === "string" ? o.id : undefined;
|
|
29
|
+
const provider = providerOf(id, typeof o.object === "string" ? o.object : undefined);
|
|
30
|
+
if (!provider)
|
|
31
|
+
return {};
|
|
32
|
+
const requestId = typeof r._request_id === "string"
|
|
33
|
+
? r._request_id
|
|
34
|
+
: typeof o._request_id === "string"
|
|
35
|
+
? o._request_id
|
|
36
|
+
: undefined;
|
|
37
|
+
return {
|
|
38
|
+
provider,
|
|
39
|
+
...llmIds(id, requestId, typeof o.model === "string" ? o.model : undefined, typeof o.object === "string" ? o.object : undefined),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** `client.messages.create` and `.stream` report each model call to the session. */
|
|
43
|
+
export function wrapAnthropic(client, sink) {
|
|
44
|
+
return wrap(client, [
|
|
45
|
+
["messages", "create"],
|
|
46
|
+
["messages", "stream"],
|
|
47
|
+
["messages", "parse"],
|
|
48
|
+
// audit K18: the beta namespace (structured output, tools in preview) goes to the same API
|
|
49
|
+
["beta", "messages", "create"],
|
|
50
|
+
["beta", "messages", "stream"],
|
|
51
|
+
["beta", "messages", "parse"],
|
|
52
|
+
], sink);
|
|
53
|
+
}
|
|
54
|
+
/** `client.chat.completions.create` / `.stream` and `client.responses.create` / `.stream` report
|
|
55
|
+
* each model call. */
|
|
56
|
+
export function wrapOpenAI(client, sink) {
|
|
57
|
+
return wrap(client, [
|
|
58
|
+
["chat", "completions", "create"],
|
|
59
|
+
["chat", "completions", "stream"],
|
|
60
|
+
["responses", "create"],
|
|
61
|
+
["responses", "stream"],
|
|
62
|
+
// audit K18: structured output and the beta namespace
|
|
63
|
+
["chat", "completions", "parse"],
|
|
64
|
+
["responses", "parse"],
|
|
65
|
+
["beta", "chat", "completions", "parse"],
|
|
66
|
+
["beta", "chat", "completions", "stream"],
|
|
67
|
+
], sink);
|
|
68
|
+
}
|
|
69
|
+
/** Audit K4: Google's `@google/genai` client (Gemini, and Vertex AI with `vertexai: true`):
|
|
70
|
+
* `models.generateContent` and `models.generateContentStream` report each model call. */
|
|
71
|
+
export function wrapGemini(client, sink) {
|
|
72
|
+
return wrap(client, [
|
|
73
|
+
["models", "generateContent"],
|
|
74
|
+
["models", "generateContentStream"],
|
|
75
|
+
], sink);
|
|
76
|
+
}
|
|
77
|
+
/** Audit K4: the AWS SDK's `BedrockRuntimeClient`: every `send(command)` (Converse, ConverseStream,
|
|
78
|
+
* InvokeModel, …) reports its request id, which the gateway records from `x-amzn-requestid`. */
|
|
79
|
+
export function wrapBedrock(client, sink) {
|
|
80
|
+
return wrap(client, [["send"]], sink);
|
|
81
|
+
}
|
|
82
|
+
/** The streaming helpers' promise of the final message, which carries the ids. */
|
|
83
|
+
const FINAL = ["finalMessage", "finalChatCompletion", "finalResponse"];
|
|
84
|
+
function wrap(target, paths, sink) {
|
|
85
|
+
return new Proxy(target, {
|
|
86
|
+
get(obj, prop, receiver) {
|
|
87
|
+
const value = Reflect.get(obj, prop, receiver);
|
|
88
|
+
const here = paths.filter((p) => p[0] === prop);
|
|
89
|
+
if (here.length === 0 || value === null || value === undefined)
|
|
90
|
+
return value;
|
|
91
|
+
if (here.some((p) => p.length === 1) && typeof value === "function")
|
|
92
|
+
return (...args) => {
|
|
93
|
+
const result = value.apply(obj, args);
|
|
94
|
+
neverThrow(() => observe(result, sink));
|
|
95
|
+
return result; // the client's own promise, untouched (e.g. APIPromise.withResponse())
|
|
96
|
+
};
|
|
97
|
+
return typeof value === "object"
|
|
98
|
+
? wrap(value, here.map((p) => p.slice(1)), sink)
|
|
99
|
+
: value;
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function observe(result, sink) {
|
|
104
|
+
const then = result?.then;
|
|
105
|
+
if (typeof then !== "function") {
|
|
106
|
+
seen(result, sink);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Registered before the caller's own await, so a stream is patched before it's iterated.
|
|
110
|
+
result.then((r) => neverThrow(() => seen(r, sink)), () => { });
|
|
111
|
+
}
|
|
112
|
+
function seen(result, sink) {
|
|
113
|
+
if (result === null || typeof result !== "object")
|
|
114
|
+
return;
|
|
115
|
+
// A streaming helper (e.g. messages.stream()): whatever way the app reads it, its final message
|
|
116
|
+
// resolves once the stream ends.
|
|
117
|
+
for (const name of FINAL) {
|
|
118
|
+
const final = result[name];
|
|
119
|
+
if (typeof final === "function") {
|
|
120
|
+
final.call(result).then((m) => neverThrow(() => report(llmIdsOf(m), sink)), () => { });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const iter = result[Symbol.asyncIterator];
|
|
125
|
+
if (typeof iter !== "function") {
|
|
126
|
+
report(llmIdsOf(result), sink);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// A stream: the ids come with its first event that has one; the stream itself is unchanged.
|
|
130
|
+
const original = iter.bind(result);
|
|
131
|
+
let reported = false;
|
|
132
|
+
result[Symbol.asyncIterator] = async function* () {
|
|
133
|
+
for await (const event of { [Symbol.asyncIterator]: original }) {
|
|
134
|
+
if (!reported)
|
|
135
|
+
neverThrow(() => {
|
|
136
|
+
const ids = llmIdsOf(event);
|
|
137
|
+
if (ids.provider) {
|
|
138
|
+
reported = true;
|
|
139
|
+
report(ids, sink);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
yield event;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function report(ids, sink) {
|
|
147
|
+
if (ids.provider)
|
|
148
|
+
sink.event("llm.call", ids.provider, { ...ids });
|
|
149
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** A BlackboxSession, or anything with the same `event` method. */
|
|
2
|
+
export interface EventSink {
|
|
3
|
+
event(type: string, name?: string, data?: Record<string, unknown>): void;
|
|
4
|
+
}
|
|
5
|
+
/** Runs a hook body; a hook must never break the framework it's attached to (spec/sdk.md §4). */
|
|
6
|
+
export declare function neverThrow(fn: () => void): void;
|
|
7
|
+
/** A provider's response id → the key the gateway records it under (spec/findings.md §2). */
|
|
8
|
+
export declare function llmIds(id: string | undefined, requestId?: string, model?: string,
|
|
9
|
+
/** An OpenAI-style `object` field: how an OpenAI-compatible API's own ids are told apart (K4). */
|
|
10
|
+
object?: string): Record<string, string>;
|
|
11
|
+
export declare function providerOf(id: string | undefined, object?: string): string | undefined;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// What both hook adapters share. Mirrors sdks/python/src/zanii_blackbox/hooks/shared.py.
|
|
2
|
+
/** Runs a hook body; a hook must never break the framework it's attached to (spec/sdk.md §4). */
|
|
3
|
+
export function neverThrow(fn) {
|
|
4
|
+
try {
|
|
5
|
+
fn();
|
|
6
|
+
}
|
|
7
|
+
catch { }
|
|
8
|
+
}
|
|
9
|
+
/** A provider's response id → the key the gateway records it under (spec/findings.md §2). */
|
|
10
|
+
export function llmIds(id, requestId, model,
|
|
11
|
+
/** An OpenAI-style `object` field: how an OpenAI-compatible API's own ids are told apart (K4). */
|
|
12
|
+
object) {
|
|
13
|
+
const ids = {};
|
|
14
|
+
if (id) {
|
|
15
|
+
if (id.startsWith("resp_") || object === "response")
|
|
16
|
+
ids.response_id = id;
|
|
17
|
+
else if (id.startsWith("chatcmpl") || object?.startsWith("chat.completion"))
|
|
18
|
+
ids.completion_id = id;
|
|
19
|
+
else
|
|
20
|
+
ids.message_id = id;
|
|
21
|
+
}
|
|
22
|
+
if (requestId)
|
|
23
|
+
ids.request_id = requestId;
|
|
24
|
+
if (model)
|
|
25
|
+
ids.model = model;
|
|
26
|
+
return ids;
|
|
27
|
+
}
|
|
28
|
+
export function providerOf(id, object) {
|
|
29
|
+
if (!id)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (id.startsWith("msg_"))
|
|
32
|
+
return "anthropic";
|
|
33
|
+
if (id.startsWith("resp_") || id.startsWith("chatcmpl"))
|
|
34
|
+
return "openai";
|
|
35
|
+
// audit K4: an OpenAI-compatible API (vLLM, Azure, Jais, …) with ids of its own
|
|
36
|
+
if (object === "response" || object?.startsWith("chat.completion"))
|
|
37
|
+
return "openai";
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export { causality, memoryXray } from "./agents/index.ts";
|
|
2
|
+
export { type DetectorOptions, detectors, fingerprint } from "./analysis/detectors.ts";
|
|
3
|
+
export { FAULTS, type Fault, faultOf } from "./analysis/faults.ts";
|
|
4
|
+
export { type AnalyzeOptions, analyze, type ClaimVerdict, type CriterionResult, checkFlightPlan, checkpointReplay, dualWitness, eventsOf, type Finding as AnalysisFinding, findingKey, type Landing, landing, OUTCOMES, type Outcome, type OutcomeRollup, rollup, type Severity, type WasteReason, type WasteReport, waste, } from "./analysis/index.ts";
|
|
5
|
+
export { type ApprovalFinding, approvalFindings } from "./approvals/index.ts";
|
|
6
|
+
export { textWarnings } from "./approvals/warnings.ts";
|
|
7
|
+
export { type Attestation, attest, isReadOnly, normalise, parseCommand } from "./attest/index.ts";
|
|
8
|
+
export { type AuthorityFinding, authorityAt, authorityTimeline, automationSurprise, type Mode as AuthorityMode, type Span as AuthoritySpan, } from "./authority/index.ts";
|
|
9
|
+
export { type Invoice, type InvoiceLine, invoice, loadPlans, type Plan, type Plans, renderTaxInvoice, stripeSignatureOk, type TaxInvoice, type TaxInvoiceInput, taxInvoice, } from "./billing/index.ts";
|
|
10
|
+
export { BlackboxApiError, type Client, type ClientOptions, client, type SessionQuery, } from "./client/index.ts";
|
|
11
|
+
export { complianceFacts, complianceReport, type Facts, type Framework, type Report as ComplianceReport, renderReport, } from "./compliance/index.ts";
|
|
12
|
+
export { type CallCost, type CostReport, callMicroUsd, effectivePrice, formatAed, type LoadedPrices, loadPrices, type ModelPrice, type PriceTable, priceCall, priceFor, promptTokens, requestsOf, sessionCost, type Tokens, toAedFils, tokensOf, } from "./cost/index.ts";
|
|
13
|
+
export { type Directive, type DirectiveItem, type DirectiveOptions, directives, fleetDirectives, } from "./directives/index.ts";
|
|
14
|
+
export { checkDrill, drillReport, type Fault as DrillFault } from "./drills/index.ts";
|
|
15
|
+
export { checkDuty, type DutyFinding, type DutyLimits, dutyFindings } from "./duty/index.ts";
|
|
16
|
+
export { aggregateFindings, airworthiness, type Collision, collisions, didFromSeed, type FindingGroup, incidentReport, logbook, type Summary, sessionSummary, signatureOf, signatures, signCertificate, verifyCertificate, } from "./fleet/index.ts";
|
|
17
|
+
export { attachBlackbox, BlackboxAgentHooks, BlackboxCallbackHandler, type BlackboxCallbacks, blackboxAgentHooks, blackboxCallbacks, blackboxMiddleware, type EventSink, llmIds, llmIdsOf, trackMemory, wrapAnthropic, wrapBedrock, wrapGemini, wrapOpenAI, } from "./hooks/index.ts";
|
|
18
|
+
export { type AgentSink, BlackboxStoppedError, blackboxAgentMiddleware, blackboxHitl, type HitlRequest, } from "./hooks/langchain-agent.ts";
|
|
19
|
+
export { blackboxCheckpointer } from "./hooks/langgraph-checkpoint.ts";
|
|
20
|
+
export { MANAGED_END, MANAGED_START, managedBlock, protectedEdit } from "./hooks/protect.ts";
|
|
21
|
+
export { type Investigation, investigation, renderInvestigation, } from "./investigate/index.ts";
|
|
22
|
+
export { type McpWrapOptions, mcpWrap } from "./mcp-wrap/index.ts";
|
|
23
|
+
export { type AmountUnit, anthropicStatement, type Baseline, baselines, type Connector, checkConnector, checkStatement, csvStatement, customStatement, decimalToMicroUsd, fuel, modelSpend, openaiStatement, pageParams, parseXml, reconcileBilling, requestFor, resolvePath, type Statement, } from "./money/index.ts";
|
|
24
|
+
export { filingPack, type OccurrenceFacts, type OccurrenceFramework, type OccurrenceReport, occurrenceFacts, occurrenceReport, renderOccurrence, } from "./occurrence/index.ts";
|
|
25
|
+
export { ingestOcsf, type OcsfEvent, type OcsfVersion, ocsfLine, toOcsf } from "./ocsf/index.ts";
|
|
26
|
+
export { toOtlp } from "./otlp/index.ts";
|
|
27
|
+
export { checkPack, corePack, type PackEntry, packFrameworks } from "./packs/index.ts";
|
|
28
|
+
export { type PolicyChange, type PolicyDelta, policyDelta } from "./policy/delta.ts";
|
|
29
|
+
export { type Draft, type DraftGroup, policyDrafts } from "./policy/drafts.ts";
|
|
30
|
+
export { audited, type CompiledPolicy, compilePolicy, type Decision, decide, loadPolicy, type Policy, policyFindings, type Rule, } from "./policy/index.ts";
|
|
31
|
+
export { calibration, FEATURES, features, MIN_EACH, type PrecogModel, precogFindings, precogReport, predict, prefixOf, splitOf, TARGET, train, } from "./precog/index.ts";
|
|
32
|
+
export { type InterventionEvidence, interventionEvidence, interventionGain, } from "./precog/intervention.ts";
|
|
33
|
+
export { activities, buildNormal, type NormalModel, type NormalScore, normalScore, normalThreshold, } from "./precog/normal.ts";
|
|
34
|
+
export { type PreflightFinding, preflightFindings } from "./preflight/index.ts";
|
|
35
|
+
export { type Rating, type TypeUnratedFinding, typeRatings, typeUnrated, } from "./ratings/index.ts";
|
|
36
|
+
export { type Finding, type FindingCode, type Harness, loadLocal, type ReconcileOptions, RecordNotVerified, type Report, reconcile, } from "./reconcile/index.ts";
|
|
37
|
+
export { cassette, requestKey, type Take } from "./replay/index.ts";
|
|
38
|
+
export { ORPHAN_TEXT, repairToolCalls } from "./replay/repair.ts";
|
|
39
|
+
export { type DrainResult, drainSpools } from "./session/drain.ts";
|
|
40
|
+
export { BlackboxSession, type FlightPlan, type LlmCallIds, type SessionError, type SessionOptions, type SessionState, type SessionStats, session, stableEventId, } from "./session/index.ts";
|
|
41
|
+
export { type Compensation, checkCompensations, runUndo, type UndoFinding, type UndoStatus, type UndoStep, undoFindings, undoPlan, } from "./undo/index.ts";
|
|
42
|
+
export * from "./verify/index.ts";
|
|
43
|
+
export { VERSION } from "./version.ts";
|
|
44
|
+
export { type Conditions, type Sample, weather } from "./weather/index.ts";
|
|
45
|
+
export { postReceipt, receiptFor, type Tree, workspaceTree } from "./workspace-receipt/index.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Public API of @zanii/blackbox. Everything customers can import is re-exported here.
|
|
2
|
+
// Keep this file in step with sdks/python/src/zanii_blackbox/__init__.py (the SDKs mirror each other).
|
|
3
|
+
export { causality, memoryXray } from "./agents/index.js";
|
|
4
|
+
export { detectors, fingerprint } from "./analysis/detectors.js";
|
|
5
|
+
export { FAULTS, faultOf } from "./analysis/faults.js";
|
|
6
|
+
export { analyze, checkFlightPlan, checkpointReplay, dualWitness, eventsOf, findingKey, landing, OUTCOMES, rollup, waste, } from "./analysis/index.js";
|
|
7
|
+
export { approvalFindings } from "./approvals/index.js";
|
|
8
|
+
export { textWarnings } from "./approvals/warnings.js";
|
|
9
|
+
export { attest, isReadOnly, normalise, parseCommand } from "./attest/index.js";
|
|
10
|
+
export { authorityAt, authorityTimeline, automationSurprise, } from "./authority/index.js";
|
|
11
|
+
export { invoice, loadPlans, renderTaxInvoice, stripeSignatureOk, taxInvoice, } from "./billing/index.js";
|
|
12
|
+
export { BlackboxApiError, client, } from "./client/index.js";
|
|
13
|
+
export { complianceFacts, complianceReport, renderReport, } from "./compliance/index.js";
|
|
14
|
+
export { callMicroUsd, effectivePrice, formatAed, loadPrices, priceCall, priceFor, promptTokens, requestsOf, sessionCost, toAedFils, tokensOf, } from "./cost/index.js";
|
|
15
|
+
export { directives, fleetDirectives, } from "./directives/index.js";
|
|
16
|
+
export { checkDrill, drillReport } from "./drills/index.js";
|
|
17
|
+
export { checkDuty, dutyFindings } from "./duty/index.js";
|
|
18
|
+
export { aggregateFindings, airworthiness, collisions, didFromSeed, incidentReport, logbook, sessionSummary, signatureOf, signatures, signCertificate, verifyCertificate, } from "./fleet/index.js";
|
|
19
|
+
export { attachBlackbox, BlackboxAgentHooks, BlackboxCallbackHandler, blackboxAgentHooks, blackboxCallbacks, blackboxMiddleware, llmIds, llmIdsOf, trackMemory, wrapAnthropic, wrapBedrock, wrapGemini, wrapOpenAI, } from "./hooks/index.js";
|
|
20
|
+
export { BlackboxStoppedError, blackboxAgentMiddleware, blackboxHitl, } from "./hooks/langchain-agent.js";
|
|
21
|
+
export { blackboxCheckpointer } from "./hooks/langgraph-checkpoint.js";
|
|
22
|
+
export { MANAGED_END, MANAGED_START, managedBlock, protectedEdit } from "./hooks/protect.js";
|
|
23
|
+
export { investigation, renderInvestigation, } from "./investigate/index.js";
|
|
24
|
+
export { mcpWrap } from "./mcp-wrap/index.js";
|
|
25
|
+
export { anthropicStatement, baselines, checkConnector, checkStatement, csvStatement, customStatement, decimalToMicroUsd, fuel, modelSpend, openaiStatement, pageParams, parseXml, reconcileBilling, requestFor, resolvePath, } from "./money/index.js";
|
|
26
|
+
export { filingPack, occurrenceFacts, occurrenceReport, renderOccurrence, } from "./occurrence/index.js";
|
|
27
|
+
export { ingestOcsf, ocsfLine, toOcsf } from "./ocsf/index.js";
|
|
28
|
+
export { toOtlp } from "./otlp/index.js";
|
|
29
|
+
export { checkPack, corePack, packFrameworks } from "./packs/index.js";
|
|
30
|
+
export { policyDelta } from "./policy/delta.js";
|
|
31
|
+
export { policyDrafts } from "./policy/drafts.js";
|
|
32
|
+
export { audited, compilePolicy, decide, loadPolicy, policyFindings, } from "./policy/index.js";
|
|
33
|
+
export { calibration, FEATURES, features, MIN_EACH, precogFindings, precogReport, predict, prefixOf, splitOf, TARGET, train, } from "./precog/index.js";
|
|
34
|
+
export { interventionEvidence, interventionGain, } from "./precog/intervention.js";
|
|
35
|
+
export { activities, buildNormal, normalScore, normalThreshold, } from "./precog/normal.js";
|
|
36
|
+
export { preflightFindings } from "./preflight/index.js";
|
|
37
|
+
export { typeRatings, typeUnrated, } from "./ratings/index.js";
|
|
38
|
+
export { loadLocal, RecordNotVerified, reconcile, } from "./reconcile/index.js";
|
|
39
|
+
export { cassette, requestKey } from "./replay/index.js";
|
|
40
|
+
export { ORPHAN_TEXT, repairToolCalls } from "./replay/repair.js";
|
|
41
|
+
export { drainSpools } from "./session/drain.js";
|
|
42
|
+
export { BlackboxSession, session, stableEventId, } from "./session/index.js";
|
|
43
|
+
export { checkCompensations, runUndo, undoFindings, undoPlan, } from "./undo/index.js";
|
|
44
|
+
export * from "./verify/index.js";
|
|
45
|
+
export { VERSION } from "./version.js";
|
|
46
|
+
export { weather } from "./weather/index.js";
|
|
47
|
+
export { postReceipt, receiptFor, workspaceTree } from "./workspace-receipt/index.js";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type Span } from "../authority/index.ts";
|
|
2
|
+
import type { Directive } from "../directives/index.ts";
|
|
3
|
+
import { type Summary } from "../fleet/index.ts";
|
|
4
|
+
export interface InvestigationOptions {
|
|
5
|
+
summary: Summary;
|
|
6
|
+
models: readonly string[];
|
|
7
|
+
directives?: readonly Directive[];
|
|
8
|
+
}
|
|
9
|
+
/** spec/investigations.md §1. */
|
|
10
|
+
export declare function investigation(lines: readonly string[], opts: InvestigationOptions): {
|
|
11
|
+
kind: "blackbox.investigation";
|
|
12
|
+
v: 1;
|
|
13
|
+
session_id: string;
|
|
14
|
+
label: string | null;
|
|
15
|
+
started_at: string;
|
|
16
|
+
last_event_at: string;
|
|
17
|
+
events: number;
|
|
18
|
+
outcome: string | null;
|
|
19
|
+
authority: Span[];
|
|
20
|
+
findings: {
|
|
21
|
+
seq: number;
|
|
22
|
+
code: string;
|
|
23
|
+
fault: string;
|
|
24
|
+
severity: string;
|
|
25
|
+
source: string;
|
|
26
|
+
in_control: import("../authority/index.ts").Mode | null;
|
|
27
|
+
in_control_by: string | null;
|
|
28
|
+
weather: {} | null;
|
|
29
|
+
}[];
|
|
30
|
+
directives: {
|
|
31
|
+
id: string;
|
|
32
|
+
applies_to: {
|
|
33
|
+
model: string;
|
|
34
|
+
} | {
|
|
35
|
+
tool: string;
|
|
36
|
+
};
|
|
37
|
+
pattern: string[];
|
|
38
|
+
affected_ppm: number;
|
|
39
|
+
}[] | null;
|
|
40
|
+
drill: {
|
|
41
|
+
drill: true;
|
|
42
|
+
planned: import("../drills/index.ts").Fault[];
|
|
43
|
+
injected: {
|
|
44
|
+
seq: number;
|
|
45
|
+
kind: string;
|
|
46
|
+
}[];
|
|
47
|
+
findings_after: string[];
|
|
48
|
+
recovered: boolean;
|
|
49
|
+
outcome: string | null;
|
|
50
|
+
} | null;
|
|
51
|
+
};
|
|
52
|
+
export type Investigation = ReturnType<typeof investigation> & {
|
|
53
|
+
verification?: {
|
|
54
|
+
ok: boolean;
|
|
55
|
+
identity: boolean;
|
|
56
|
+
proofs: string;
|
|
57
|
+
};
|
|
58
|
+
investigated_at?: string;
|
|
59
|
+
bundle_sha256?: string;
|
|
60
|
+
signed?: {
|
|
61
|
+
by: string;
|
|
62
|
+
sig: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
/** spec/investigations.md §3: the reading copy. The signed JSON is the report; this isn't. */
|
|
66
|
+
export declare function renderInvestigation(r: Investigation): string;
|