@graphorin/agent 0.5.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 +7 -0
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/dist/errors/index.d.ts +170 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +204 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/evaluator-optimizer/index.d.ts +91 -0
- package/dist/evaluator-optimizer/index.d.ts.map +1 -0
- package/dist/evaluator-optimizer/index.js +85 -0
- package/dist/evaluator-optimizer/index.js.map +1 -0
- package/dist/factory.d.ts +13 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +1853 -0
- package/dist/factory.js.map +1 -0
- package/dist/fallback/index.d.ts +52 -0
- package/dist/fallback/index.d.ts.map +1 -0
- package/dist/fallback/index.js +53 -0
- package/dist/fallback/index.js.map +1 -0
- package/dist/fanout/index.d.ts +142 -0
- package/dist/fanout/index.d.ts.map +1 -0
- package/dist/fanout/index.js +252 -0
- package/dist/fanout/index.js.map +1 -0
- package/dist/filters/index.d.ts +137 -0
- package/dist/filters/index.d.ts.map +1 -0
- package/dist/filters/index.js +273 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/ids.js +46 -0
- package/dist/internal/ids.js.map +1 -0
- package/dist/internal/usage-accumulator.js +62 -0
- package/dist/internal/usage-accumulator.js.map +1 -0
- package/dist/lateral-leak/causality-monitor.d.ts +97 -0
- package/dist/lateral-leak/causality-monitor.d.ts.map +1 -0
- package/dist/lateral-leak/causality-monitor.js +139 -0
- package/dist/lateral-leak/causality-monitor.js.map +1 -0
- package/dist/lateral-leak/index.d.ts +4 -0
- package/dist/lateral-leak/index.js +5 -0
- package/dist/lateral-leak/merge-guard.d.ts +89 -0
- package/dist/lateral-leak/merge-guard.d.ts.map +1 -0
- package/dist/lateral-leak/merge-guard.js +65 -0
- package/dist/lateral-leak/merge-guard.js.map +1 -0
- package/dist/lateral-leak/protocol-guard.d.ts +76 -0
- package/dist/lateral-leak/protocol-guard.d.ts.map +1 -0
- package/dist/lateral-leak/protocol-guard.js +147 -0
- package/dist/lateral-leak/protocol-guard.js.map +1 -0
- package/dist/preferred-model/index.d.ts +53 -0
- package/dist/preferred-model/index.d.ts.map +1 -0
- package/dist/preferred-model/index.js +141 -0
- package/dist/preferred-model/index.js.map +1 -0
- package/dist/progress/index.d.ts +62 -0
- package/dist/progress/index.d.ts.map +1 -0
- package/dist/progress/index.js +150 -0
- package/dist/progress/index.js.map +1 -0
- package/dist/run-state/index.d.ts +152 -0
- package/dist/run-state/index.d.ts.map +1 -0
- package/dist/run-state/index.js +311 -0
- package/dist/run-state/index.js.map +1 -0
- package/dist/tooling/adapters.js +154 -0
- package/dist/tooling/adapters.js.map +1 -0
- package/dist/tooling/catalogue.js +37 -0
- package/dist/tooling/catalogue.js.map +1 -0
- package/dist/tooling/dataflow.js +99 -0
- package/dist/tooling/dataflow.js.map +1 -0
- package/dist/tooling/registry-build.js +85 -0
- package/dist/tooling/registry-build.js.map +1 -0
- package/dist/types.d.ts +413 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +115 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { containsPii } from "@graphorin/security/guardrails";
|
|
2
|
+
import { createDataFlowPolicy, createTaintLedger, deriveTaintLabel } from "@graphorin/security/dataflow";
|
|
3
|
+
|
|
4
|
+
//#region src/tooling/dataflow.ts
|
|
5
|
+
/**
|
|
6
|
+
* Adapter: build the executor's {@link DataFlowGuard} from a
|
|
7
|
+
* {@link DataFlowPolicyConfig} (WI-12 / P1-3).
|
|
8
|
+
*
|
|
9
|
+
* Bridges `@graphorin/security`'s pure taint engine (policy + per-run
|
|
10
|
+
* ledger + provenance derivation) to the `@graphorin/tools` executor hook.
|
|
11
|
+
* The executor calls {@link DataFlowGuard.inspect} as a sink gate and
|
|
12
|
+
* {@link DataFlowGuard.record} after every successful output; this adapter
|
|
13
|
+
* routes each call to the right run's {@link TaintLedger} and maps the
|
|
14
|
+
* security {@link DataFlowDecision} onto the executor's
|
|
15
|
+
* {@link DataFlowVerdict} (so the executor takes no security dependency).
|
|
16
|
+
*
|
|
17
|
+
* Because the agent builds one executor that serves the whole run (and the
|
|
18
|
+
* code-mode quiet executor too), the guard keeps a per-run ledger map.
|
|
19
|
+
* Taint state is in-memory and run-scoped; like `tool_search` promotion it
|
|
20
|
+
* is **not** persisted across a suspend/resume. The map is bounded by
|
|
21
|
+
* insertion-order eviction so a long-lived agent never leaks ledgers.
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
/** Max concurrent run ledgers retained before evicting the oldest. */
|
|
26
|
+
const MAX_TRACKED_RUNS = 128;
|
|
27
|
+
/** Serialize tool-call args to text for the verbatim-carry probe. */
|
|
28
|
+
function stringifyArgs(value) {
|
|
29
|
+
if (typeof value === "string") return value;
|
|
30
|
+
try {
|
|
31
|
+
return JSON.stringify(value) ?? "";
|
|
32
|
+
} catch {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function buildDataFlowGuard(config) {
|
|
37
|
+
const policy = createDataFlowPolicy(config);
|
|
38
|
+
const ledgerOpts = {
|
|
39
|
+
...config.minSpanLength !== void 0 ? { minSpanLength: config.minSpanLength } : {},
|
|
40
|
+
...config.treatPiiAsSensitive === true ? { piiSensitivity: containsPii } : {}
|
|
41
|
+
};
|
|
42
|
+
const ledgers = /* @__PURE__ */ new Map();
|
|
43
|
+
function ledgerFor(runId) {
|
|
44
|
+
const existing = ledgers.get(runId);
|
|
45
|
+
if (existing !== void 0) return existing;
|
|
46
|
+
const ledger = createTaintLedger(ledgerOpts);
|
|
47
|
+
ledgers.set(runId, ledger);
|
|
48
|
+
while (ledgers.size > MAX_TRACKED_RUNS) {
|
|
49
|
+
const oldest = ledgers.keys().next().value;
|
|
50
|
+
if (oldest === void 0) break;
|
|
51
|
+
ledgers.delete(oldest);
|
|
52
|
+
}
|
|
53
|
+
return ledger;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
inspect(input) {
|
|
57
|
+
const ledger = ledgerFor(input.runContext.runId);
|
|
58
|
+
const probe = ledger.inspectArgs(stringifyArgs(input.args));
|
|
59
|
+
const decision = policy.evaluate({
|
|
60
|
+
toolName: input.toolName,
|
|
61
|
+
sideEffectClass: input.sideEffectClass,
|
|
62
|
+
carriesUntrustedVerbatim: probe.carriesUntrustedVerbatim,
|
|
63
|
+
untrustedSeen: ledger.untrustedSeen,
|
|
64
|
+
sensitiveSeen: ledger.sensitiveSeen,
|
|
65
|
+
sourceKinds: probe.matchedSourceKinds.length > 0 ? probe.matchedSourceKinds : ledger.untrustedSourceKinds
|
|
66
|
+
});
|
|
67
|
+
if (decision.action === "allow") return { action: "allow" };
|
|
68
|
+
return {
|
|
69
|
+
action: decision.action,
|
|
70
|
+
flow: decision.flow,
|
|
71
|
+
reason: decision.reason,
|
|
72
|
+
sourceKinds: decision.sourceKinds
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
record(input) {
|
|
76
|
+
const ledger = ledgerFor(input.runContext.runId);
|
|
77
|
+
const label = deriveTaintLabel({
|
|
78
|
+
trustClass: input.trustClass,
|
|
79
|
+
...input.source !== void 0 ? { source: input.source } : {},
|
|
80
|
+
...input.sensitivity !== void 0 ? { sensitivity: input.sensitivity } : {},
|
|
81
|
+
...config.sensitiveTiers !== void 0 ? { sensitiveTiers: config.sensitiveTiers } : {}
|
|
82
|
+
});
|
|
83
|
+
ledger.recordOutput(label, input.outputText);
|
|
84
|
+
},
|
|
85
|
+
snapshotLedger(runId) {
|
|
86
|
+
return ledgers.get(runId)?.snapshot();
|
|
87
|
+
},
|
|
88
|
+
seedLedger(runId, summary) {
|
|
89
|
+
ledgers.set(runId, createTaintLedger({
|
|
90
|
+
...ledgerOpts,
|
|
91
|
+
initial: summary
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
export { buildDataFlowGuard };
|
|
99
|
+
//# sourceMappingURL=dataflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataflow.js","names":[],"sources":["../../src/tooling/dataflow.ts"],"sourcesContent":["/**\n * Adapter: build the executor's {@link DataFlowGuard} from a\n * {@link DataFlowPolicyConfig} (WI-12 / P1-3).\n *\n * Bridges `@graphorin/security`'s pure taint engine (policy + per-run\n * ledger + provenance derivation) to the `@graphorin/tools` executor hook.\n * The executor calls {@link DataFlowGuard.inspect} as a sink gate and\n * {@link DataFlowGuard.record} after every successful output; this adapter\n * routes each call to the right run's {@link TaintLedger} and maps the\n * security {@link DataFlowDecision} onto the executor's\n * {@link DataFlowVerdict} (so the executor takes no security dependency).\n *\n * Because the agent builds one executor that serves the whole run (and the\n * code-mode quiet executor too), the guard keeps a per-run ledger map.\n * Taint state is in-memory and run-scoped; like `tool_search` promotion it\n * is **not** persisted across a suspend/resume. The map is bounded by\n * insertion-order eviction so a long-lived agent never leaks ledgers.\n *\n * @packageDocumentation\n */\n\nimport {\n createDataFlowPolicy,\n createTaintLedger,\n type DataFlowPolicyConfig,\n deriveTaintLabel,\n type TaintLedger,\n type TaintLedgerSnapshot,\n} from '@graphorin/security/dataflow';\nimport { containsPii } from '@graphorin/security/guardrails';\nimport type {\n DataFlowGuard,\n DataFlowInspectInput,\n DataFlowRecordInput,\n DataFlowVerdict,\n} from '@graphorin/tools/executor';\n\n/** Max concurrent run ledgers retained before evicting the oldest. */\nconst MAX_TRACKED_RUNS = 128;\n\n/** Serialize tool-call args to text for the verbatim-carry probe. */\nfunction stringifyArgs(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return '';\n }\n}\n\n/**\n * Build a {@link DataFlowGuard} backed by `@graphorin/security`'s taint\n * engine. Returns a guard whose `inspect`/`record` operate on a per-run\n * ledger keyed by `runContext.runId`.\n *\n * @internal\n */\n/**\n * The executor's {@link DataFlowGuard} plus AG-19 ledger-persistence hooks the\n * agent uses to carry the coarse taint summary across a suspend/resume.\n */\nexport interface DataFlowGuardWithLedgers extends DataFlowGuard {\n /** Read a run's coarse taint summary to persist on suspend (or `undefined`). */\n snapshotLedger(runId: string): TaintLedgerSnapshot | undefined;\n /** Pre-seed a run's ledger from a persisted summary on resume. */\n seedLedger(runId: string, summary: TaintLedgerSnapshot): void;\n}\n\nexport function buildDataFlowGuard(config: DataFlowPolicyConfig): DataFlowGuardWithLedgers {\n const policy = createDataFlowPolicy(config);\n // FIDES-lattice (SDF-8): when treatPiiAsSensitive is on, feed the PII catalogue\n // into the ledger so PII reads arm the trifecta `sensitive` leg. Default off.\n const ledgerOpts = {\n ...(config.minSpanLength !== undefined ? { minSpanLength: config.minSpanLength } : {}),\n ...(config.treatPiiAsSensitive === true ? { piiSensitivity: containsPii } : {}),\n };\n const ledgers = new Map<string, TaintLedger>();\n\n function ledgerFor(runId: string): TaintLedger {\n const existing = ledgers.get(runId);\n if (existing !== undefined) return existing;\n const ledger = createTaintLedger(ledgerOpts);\n ledgers.set(runId, ledger);\n while (ledgers.size > MAX_TRACKED_RUNS) {\n const oldest = ledgers.keys().next().value;\n if (oldest === undefined) break;\n ledgers.delete(oldest);\n }\n return ledger;\n }\n\n return {\n inspect(input: DataFlowInspectInput): DataFlowVerdict {\n const ledger = ledgerFor(input.runContext.runId);\n const probe = ledger.inspectArgs(stringifyArgs(input.args));\n const decision = policy.evaluate({\n toolName: input.toolName,\n sideEffectClass: input.sideEffectClass,\n carriesUntrustedVerbatim: probe.carriesUntrustedVerbatim,\n untrustedSeen: ledger.untrustedSeen,\n sensitiveSeen: ledger.sensitiveSeen,\n sourceKinds:\n probe.matchedSourceKinds.length > 0\n ? probe.matchedSourceKinds\n : ledger.untrustedSourceKinds,\n });\n if (decision.action === 'allow') return { action: 'allow' };\n return {\n action: decision.action,\n flow: decision.flow,\n reason: decision.reason,\n sourceKinds: decision.sourceKinds,\n };\n },\n\n record(input: DataFlowRecordInput): void {\n const ledger = ledgerFor(input.runContext.runId);\n const label = deriveTaintLabel({\n trustClass: input.trustClass,\n ...(input.source !== undefined ? { source: input.source } : {}),\n ...(input.sensitivity !== undefined ? { sensitivity: input.sensitivity } : {}),\n // SDF-8: widen the trifecta `sensitive` leg to the operator's\n // configured tiers (default secret-only ⇒ byte-identical).\n ...(config.sensitiveTiers !== undefined ? { sensitiveTiers: config.sensitiveTiers } : {}),\n });\n ledger.recordOutput(label, input.outputText);\n },\n\n // AG-19: snapshot/rehydrate the run's coarse taint summary across a\n // suspend/resume so the sink gate is not silently un-gated on the HITL\n // boundary. Only the load-bearing flags cross the boundary — never spans.\n snapshotLedger(runId: string): TaintLedgerSnapshot | undefined {\n return ledgers.get(runId)?.snapshot();\n },\n seedLedger(runId: string, summary: TaintLedgerSnapshot): void {\n ledgers.set(runId, createTaintLedger({ ...ledgerOpts, initial: summary }));\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAM,mBAAmB;;AAGzB,SAAS,cAAc,OAAwB;AAC7C,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI;AACF,SAAO,KAAK,UAAU,MAAM,IAAI;SAC1B;AACN,SAAO;;;AAsBX,SAAgB,mBAAmB,QAAwD;CACzF,MAAM,SAAS,qBAAqB,OAAO;CAG3C,MAAM,aAAa;EACjB,GAAI,OAAO,kBAAkB,SAAY,EAAE,eAAe,OAAO,eAAe,GAAG,EAAE;EACrF,GAAI,OAAO,wBAAwB,OAAO,EAAE,gBAAgB,aAAa,GAAG,EAAE;EAC/E;CACD,MAAM,0BAAU,IAAI,KAA0B;CAE9C,SAAS,UAAU,OAA4B;EAC7C,MAAM,WAAW,QAAQ,IAAI,MAAM;AACnC,MAAI,aAAa,OAAW,QAAO;EACnC,MAAM,SAAS,kBAAkB,WAAW;AAC5C,UAAQ,IAAI,OAAO,OAAO;AAC1B,SAAO,QAAQ,OAAO,kBAAkB;GACtC,MAAM,SAAS,QAAQ,MAAM,CAAC,MAAM,CAAC;AACrC,OAAI,WAAW,OAAW;AAC1B,WAAQ,OAAO,OAAO;;AAExB,SAAO;;AAGT,QAAO;EACL,QAAQ,OAA8C;GACpD,MAAM,SAAS,UAAU,MAAM,WAAW,MAAM;GAChD,MAAM,QAAQ,OAAO,YAAY,cAAc,MAAM,KAAK,CAAC;GAC3D,MAAM,WAAW,OAAO,SAAS;IAC/B,UAAU,MAAM;IAChB,iBAAiB,MAAM;IACvB,0BAA0B,MAAM;IAChC,eAAe,OAAO;IACtB,eAAe,OAAO;IACtB,aACE,MAAM,mBAAmB,SAAS,IAC9B,MAAM,qBACN,OAAO;IACd,CAAC;AACF,OAAI,SAAS,WAAW,QAAS,QAAO,EAAE,QAAQ,SAAS;AAC3D,UAAO;IACL,QAAQ,SAAS;IACjB,MAAM,SAAS;IACf,QAAQ,SAAS;IACjB,aAAa,SAAS;IACvB;;EAGH,OAAO,OAAkC;GACvC,MAAM,SAAS,UAAU,MAAM,WAAW,MAAM;GAChD,MAAM,QAAQ,iBAAiB;IAC7B,YAAY,MAAM;IAClB,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,QAAQ,GAAG,EAAE;IAC9D,GAAI,MAAM,gBAAgB,SAAY,EAAE,aAAa,MAAM,aAAa,GAAG,EAAE;IAG7E,GAAI,OAAO,mBAAmB,SAAY,EAAE,gBAAgB,OAAO,gBAAgB,GAAG,EAAE;IACzF,CAAC;AACF,UAAO,aAAa,OAAO,MAAM,WAAW;;EAM9C,eAAe,OAAgD;AAC7D,UAAO,QAAQ,IAAI,MAAM,EAAE,UAAU;;EAEvC,WAAW,OAAe,SAAoC;AAC5D,WAAQ,IAAI,OAAO,kBAAkB;IAAE,GAAG;IAAY,SAAS;IAAS,CAAC,CAAC;;EAE7E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { stampSkillTool } from "@graphorin/skills";
|
|
2
|
+
import { createToolRegistry } from "@graphorin/tools/registry";
|
|
3
|
+
|
|
4
|
+
//#region src/tooling/registry-build.ts
|
|
5
|
+
/** The source attributed to an unstamped first-party `config.tools` entry. */
|
|
6
|
+
const FIRST_PARTY_SOURCE = Object.freeze({ kind: "first-party" });
|
|
7
|
+
/** The five `ToolSource.kind` discriminants (used to validate a stamp). */
|
|
8
|
+
const TOOL_SOURCE_KINDS = new Set([
|
|
9
|
+
"first-party",
|
|
10
|
+
"built-in",
|
|
11
|
+
"skill",
|
|
12
|
+
"mcp",
|
|
13
|
+
"web-search"
|
|
14
|
+
]);
|
|
15
|
+
/**
|
|
16
|
+
* Build and collision-resolve a {@link ToolRegistry} from the supplied
|
|
17
|
+
* tool sources.
|
|
18
|
+
*
|
|
19
|
+
* Registration order (which seeds the `'registration-order'` tie-break)
|
|
20
|
+
* is: every `tools` entry, then every inline tool of every skill.
|
|
21
|
+
* Throws whatever `register(...)` throws for a malformed tool
|
|
22
|
+
* (`InvalidExampleError`, `InvalidPreferredModelError`,
|
|
23
|
+
* `InvalidSideEffectClassError`) — the registry is the validation
|
|
24
|
+
* authority, so a bad tool fails fast at build time.
|
|
25
|
+
*
|
|
26
|
+
* @stable
|
|
27
|
+
*/
|
|
28
|
+
function buildToolRegistry(options = {}) {
|
|
29
|
+
const registry = createToolRegistry({
|
|
30
|
+
...options.emitAudit !== void 0 ? { emitAudit: options.emitAudit } : {},
|
|
31
|
+
...options.embedder !== void 0 ? { embedder: options.embedder } : {},
|
|
32
|
+
...options.semanticScoreThreshold !== void 0 ? { semanticScoreThreshold: options.semanticScoreThreshold } : {}
|
|
33
|
+
});
|
|
34
|
+
let registered = 0;
|
|
35
|
+
for (const tool of options.tools ?? []) {
|
|
36
|
+
registry.register(tool, inferToolSource(tool));
|
|
37
|
+
registered += 1;
|
|
38
|
+
}
|
|
39
|
+
let skippedSkillEntries = 0;
|
|
40
|
+
for (const entry of options.skills?.list?.() ?? []) {
|
|
41
|
+
if (!isSkillLike(entry)) {
|
|
42
|
+
skippedSkillEntries += 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
for (const tool of entry.tools()) {
|
|
46
|
+
const stamped = stampSkillTool(tool, entry);
|
|
47
|
+
registry.register(stamped.tool, stamped.source);
|
|
48
|
+
registered += 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const resolutions = registry.assertNoDuplicates(options.collisionStrategy ?? "auto-prefix", options.collisionContext ?? { source: FIRST_PARTY_SOURCE });
|
|
52
|
+
return Object.freeze({
|
|
53
|
+
registry,
|
|
54
|
+
resolutions,
|
|
55
|
+
registered,
|
|
56
|
+
skippedSkillEntries
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Derive the {@link ToolSource} for a `config.tools` entry. Honours an
|
|
61
|
+
* explicit, well-formed `__source` stamp when present (so re-registered
|
|
62
|
+
* `ResolvedTool`s and a future `mcp` config hook keep their provenance);
|
|
63
|
+
* otherwise the tool is first-party. See the module doc on why MCP tools
|
|
64
|
+
* are *not* auto-detected here.
|
|
65
|
+
*/
|
|
66
|
+
function inferToolSource(tool) {
|
|
67
|
+
const stamped = tool.__source;
|
|
68
|
+
return isToolSource(stamped) ? stamped : FIRST_PARTY_SOURCE;
|
|
69
|
+
}
|
|
70
|
+
/** Structural guard: a well-formed {@link ToolSource} discriminated union. */
|
|
71
|
+
function isToolSource(value) {
|
|
72
|
+
if (typeof value !== "object" || value === null) return false;
|
|
73
|
+
const kind = value.kind;
|
|
74
|
+
return typeof kind === "string" && TOOL_SOURCE_KINDS.has(kind);
|
|
75
|
+
}
|
|
76
|
+
/** Structural guard for the {@link SkillLike} surface. */
|
|
77
|
+
function isSkillLike(value) {
|
|
78
|
+
if (typeof value !== "object" || value === null) return false;
|
|
79
|
+
const metadata = value.metadata;
|
|
80
|
+
return typeof metadata === "object" && metadata !== null && typeof metadata.name === "string" && typeof metadata.graphorinTrustLevel === "string" && typeof value.tools === "function";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
export { buildToolRegistry };
|
|
85
|
+
//# sourceMappingURL=registry-build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-build.js","names":["FIRST_PARTY_SOURCE: ToolSource","TOOL_SOURCE_KINDS: ReadonlySet<string>"],"sources":["../../src/tooling/registry-build.ts"],"sourcesContent":["/**\n * Assemble a single `@graphorin/tools` {@link ToolRegistry} from every\n * tool source the agent knows about (first-party `config.tools` + skill\n * tools), then resolve cross-source name collisions deterministically.\n *\n * This realises Principle #12 (one registry, one collision policy) and\n * gives `createToolRegistry(...)` its first production call-site\n * (`createAgent(...)` warm-up — see `factory.ts`). The run loop consumes\n * the resulting registry in a later work item (WI-03); `tool_search`\n * uses it in WI-05. This module only *builds* it.\n *\n * Two deliberate fidelity notes (verified against source, not the plan):\n * - **MCP tools are not auto-stamped.** `adaptMCPTools(...)` returns\n * plain `Tool`s; `__source`/`__trustClass` are only ever assigned by\n * the registry's `normaliseTool(...)` at registration time, derived\n * from the `source` passed to `register(...)`. So {@link inferToolSource}\n * honours an explicit `__source` stamp if one is present (forward-\n * compatible with a dedicated `mcp` config hook / re-registered\n * `ResolvedTool`s) and otherwise treats the tool as first-party. The\n * MCP tool's baked-in `sandboxPolicy` / `inboundSanitization` are\n * preserved regardless (operator override > trust-class default).\n * - **Skill tool-stamping lives here, not in `@graphorin/skills`.** The\n * skills loader defers it (it does not depend on a tools registry);\n * the agent — which depends on both — stamps each inline skill tool\n * via `stampSkillTool(...)`.\n *\n * @packageDocumentation\n */\n\nimport type { Tool, ToolSource } from '@graphorin/core';\nimport type { SkillMetadata } from '@graphorin/skills';\nimport { stampSkillTool } from '@graphorin/skills';\nimport {\n type CollisionContext,\n type CollisionResolution,\n type CollisionStrategy,\n createToolRegistry,\n type ToolAuditEvent,\n type ToolRegistry,\n type ToolSearchEmbedder,\n} from '@graphorin/tools/registry';\n\nimport type { SkillsRegistryLike } from '../types.js';\n\n/** The source attributed to an unstamped first-party `config.tools` entry. */\nconst FIRST_PARTY_SOURCE: ToolSource = Object.freeze({ kind: 'first-party' });\n\n/** The five `ToolSource.kind` discriminants (used to validate a stamp). */\nconst TOOL_SOURCE_KINDS: ReadonlySet<string> = new Set([\n 'first-party',\n 'built-in',\n 'skill',\n 'mcp',\n 'web-search',\n]);\n\n/** Options for {@link buildToolRegistry}. */\nexport interface BuildToolRegistryOptions {\n /** First-party (and any pre-stamped) tools, i.e. `config.tools`. */\n readonly tools?: ReadonlyArray<Tool<unknown, unknown, unknown>>;\n /**\n * The agent's skill registry (`config.skills`). Only entries that\n * structurally match the {@link SkillLike} surface contribute tools;\n * non-inline skill sources expose `tools(): []` and are a no-op here.\n */\n readonly skills?: SkillsRegistryLike;\n /** Collision-resolution strategy. Default `'auto-prefix'`. */\n readonly collisionStrategy?: CollisionStrategy;\n /**\n * Context tag carried on the collision audit rows + used for the\n * `'priority'` tie-break boost. Default `{ source: first-party }`.\n */\n readonly collisionContext?: CollisionContext;\n /** Audit sink forwarded to the registry (collision + classification rows). */\n readonly emitAudit?: (event: ToolAuditEvent) => void;\n /** Semantic-search embedder. Passed through; consumed by `tool_search` (WI-05). */\n readonly embedder?: ToolSearchEmbedder;\n /** Cosine threshold for the semantic search stage (WI-05). */\n readonly semanticScoreThreshold?: number;\n}\n\n/** Outcome of {@link buildToolRegistry}. */\nexport interface BuildToolRegistryResult {\n /** The assembled registry, post collision-resolution. */\n readonly registry: ToolRegistry;\n /** The collision resolutions (also emitted on the audit sink). */\n readonly resolutions: ReadonlyArray<CollisionResolution>;\n /** Count of tools registered across every source. */\n readonly registered: number;\n /** Count of `skills.list()` entries skipped for not matching the `Skill` surface. */\n readonly skippedSkillEntries: number;\n}\n\n/**\n * Build and collision-resolve a {@link ToolRegistry} from the supplied\n * tool sources.\n *\n * Registration order (which seeds the `'registration-order'` tie-break)\n * is: every `tools` entry, then every inline tool of every skill.\n * Throws whatever `register(...)` throws for a malformed tool\n * (`InvalidExampleError`, `InvalidPreferredModelError`,\n * `InvalidSideEffectClassError`) — the registry is the validation\n * authority, so a bad tool fails fast at build time.\n *\n * @stable\n */\nexport function buildToolRegistry(options: BuildToolRegistryOptions = {}): BuildToolRegistryResult {\n const registry = createToolRegistry({\n ...(options.emitAudit !== undefined ? { emitAudit: options.emitAudit } : {}),\n ...(options.embedder !== undefined ? { embedder: options.embedder } : {}),\n ...(options.semanticScoreThreshold !== undefined\n ? { semanticScoreThreshold: options.semanticScoreThreshold }\n : {}),\n });\n\n let registered = 0;\n\n // 1. First-party / pre-stamped tools (`config.tools`).\n for (const tool of options.tools ?? []) {\n registry.register(tool, inferToolSource(tool));\n registered += 1;\n }\n\n // 2. Skill tools. The agent accepts a loose `SkillsRegistryLike`, so\n // each `list()` entry is narrowed structurally before stamping.\n let skippedSkillEntries = 0;\n for (const entry of options.skills?.list?.() ?? []) {\n if (!isSkillLike(entry)) {\n skippedSkillEntries += 1;\n continue;\n }\n for (const tool of entry.tools()) {\n const stamped = stampSkillTool(tool, entry);\n registry.register(stamped.tool, stamped.source);\n registered += 1;\n }\n }\n\n // 3. Resolve collisions deterministically (first-party wins; losers\n // are namespaced). `assertNoDuplicates(strategy, ctx)` emits a\n // `tool:collision:*` audit row per resolution.\n const resolutions = registry.assertNoDuplicates(\n options.collisionStrategy ?? 'auto-prefix',\n options.collisionContext ?? { source: FIRST_PARTY_SOURCE },\n );\n\n return Object.freeze({ registry, resolutions, registered, skippedSkillEntries });\n}\n\n/**\n * Derive the {@link ToolSource} for a `config.tools` entry. Honours an\n * explicit, well-formed `__source` stamp when present (so re-registered\n * `ResolvedTool`s and a future `mcp` config hook keep their provenance);\n * otherwise the tool is first-party. See the module doc on why MCP tools\n * are *not* auto-detected here.\n */\nfunction inferToolSource(tool: Tool<unknown, unknown, unknown>): ToolSource {\n const stamped = (tool as { readonly __source?: unknown }).__source;\n return isToolSource(stamped) ? stamped : FIRST_PARTY_SOURCE;\n}\n\n/** Structural guard: a well-formed {@link ToolSource} discriminated union. */\nfunction isToolSource(value: unknown): value is ToolSource {\n if (typeof value !== 'object' || value === null) return false;\n const kind = (value as { readonly kind?: unknown }).kind;\n return typeof kind === 'string' && TOOL_SOURCE_KINDS.has(kind);\n}\n\n/**\n * Minimal structural view of a `@graphorin/skills` `Skill` — exactly the\n * members {@link buildToolRegistry} reads. The agent's `SkillsRegistryLike`\n * is intentionally loose (`list?(): unknown[]`), so entries are validated\n * at runtime before being treated as skills.\n */\ninterface SkillLike {\n readonly metadata: SkillMetadata;\n tools(): ReadonlyArray<Tool<unknown, unknown, unknown>>;\n}\n\n/** Structural guard for the {@link SkillLike} surface. */\nfunction isSkillLike(value: unknown): value is SkillLike {\n if (typeof value !== 'object' || value === null) return false;\n const metadata = (value as { readonly metadata?: unknown }).metadata;\n const metadataOk =\n typeof metadata === 'object' &&\n metadata !== null &&\n typeof (metadata as { readonly name?: unknown }).name === 'string' &&\n typeof (metadata as { readonly graphorinTrustLevel?: unknown }).graphorinTrustLevel ===\n 'string';\n return metadataOk && typeof (value as { readonly tools?: unknown }).tools === 'function';\n}\n"],"mappings":";;;;;AA6CA,MAAMA,qBAAiC,OAAO,OAAO,EAAE,MAAM,eAAe,CAAC;;AAG7E,MAAMC,oBAAyC,IAAI,IAAI;CACrD;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;;;;;;AAoDF,SAAgB,kBAAkB,UAAoC,EAAE,EAA2B;CACjG,MAAM,WAAW,mBAAmB;EAClC,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EAC3E,GAAI,QAAQ,aAAa,SAAY,EAAE,UAAU,QAAQ,UAAU,GAAG,EAAE;EACxE,GAAI,QAAQ,2BAA2B,SACnC,EAAE,wBAAwB,QAAQ,wBAAwB,GAC1D,EAAE;EACP,CAAC;CAEF,IAAI,aAAa;AAGjB,MAAK,MAAM,QAAQ,QAAQ,SAAS,EAAE,EAAE;AACtC,WAAS,SAAS,MAAM,gBAAgB,KAAK,CAAC;AAC9C,gBAAc;;CAKhB,IAAI,sBAAsB;AAC1B,MAAK,MAAM,SAAS,QAAQ,QAAQ,QAAQ,IAAI,EAAE,EAAE;AAClD,MAAI,CAAC,YAAY,MAAM,EAAE;AACvB,0BAAuB;AACvB;;AAEF,OAAK,MAAM,QAAQ,MAAM,OAAO,EAAE;GAChC,MAAM,UAAU,eAAe,MAAM,MAAM;AAC3C,YAAS,SAAS,QAAQ,MAAM,QAAQ,OAAO;AAC/C,iBAAc;;;CAOlB,MAAM,cAAc,SAAS,mBAC3B,QAAQ,qBAAqB,eAC7B,QAAQ,oBAAoB,EAAE,QAAQ,oBAAoB,CAC3D;AAED,QAAO,OAAO,OAAO;EAAE;EAAU;EAAa;EAAY;EAAqB,CAAC;;;;;;;;;AAUlF,SAAS,gBAAgB,MAAmD;CAC1E,MAAM,UAAW,KAAyC;AAC1D,QAAO,aAAa,QAAQ,GAAG,UAAU;;;AAI3C,SAAS,aAAa,OAAqC;AACzD,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;CACxD,MAAM,OAAQ,MAAsC;AACpD,QAAO,OAAO,SAAS,YAAY,kBAAkB,IAAI,KAAK;;;AAehE,SAAS,YAAY,OAAoC;AACvD,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;CACxD,MAAM,WAAY,MAA0C;AAO5D,QALE,OAAO,aAAa,YACpB,aAAa,QACb,OAAQ,SAAyC,SAAS,YAC1D,OAAQ,SAAwD,wBAC9D,YACiB,OAAQ,MAAuC,UAAU"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { AgentFallbackPolicy } from "./fallback/index.js";
|
|
2
|
+
import { MergeGuardConfig } from "./lateral-leak/merge-guard.js";
|
|
3
|
+
import { ChildResult, FanOutOptions, FanOutResult, MergeStrategy, PerChildBudget } from "./fanout/index.js";
|
|
4
|
+
import { CausalityMonitorConfig } from "./lateral-leak/causality-monitor.js";
|
|
5
|
+
import { ProgressIO, ProgressReadOptions, ProgressWriteOptions } from "./progress/index.js";
|
|
6
|
+
import { AgentEvent, AgentResult, CheckpointStore, HandoffFilter, Message, ModelHint, ModelSpec, ProgressArtifactRef, Provider, ReasoningRetention, RunContext, RunState, Sensitivity, StopCondition, Tool, ToolChoice, Tracer } from "@graphorin/core";
|
|
7
|
+
import { InputGuardrail, OutputGuardrail } from "@graphorin/security/guardrails";
|
|
8
|
+
import { ResultReader } from "@graphorin/tools/result";
|
|
9
|
+
import { DataFlowPolicyConfig } from "@graphorin/security/dataflow";
|
|
10
|
+
import { ToolRegistry } from "@graphorin/tools/registry";
|
|
11
|
+
import { Memory, PostCompactionHook } from "@graphorin/memory";
|
|
12
|
+
|
|
13
|
+
//#region src/types.d.ts
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Forward-compatible type alias for the input accepted by
|
|
17
|
+
* `Agent.stream / run / steer / followUp`. v0.1 ships with the
|
|
18
|
+
* canonical text + multimodal Message shape; future versions may
|
|
19
|
+
* add structured inputs.
|
|
20
|
+
*
|
|
21
|
+
* @stable
|
|
22
|
+
*/
|
|
23
|
+
type AgentInput = string | Message | ReadonlyArray<Message>;
|
|
24
|
+
/**
|
|
25
|
+
* Output type specification.
|
|
26
|
+
*
|
|
27
|
+
* @stable
|
|
28
|
+
*/
|
|
29
|
+
interface OutputSpec<TOutput> {
|
|
30
|
+
readonly kind: 'text' | 'structured';
|
|
31
|
+
/**
|
|
32
|
+
* Local validator (Zod-compatible `{ parse }`) applied to the final
|
|
33
|
+
* model output on the completed path (AG-3). A parse failure fails
|
|
34
|
+
* the run with `output-validation-failed` — never a silent cast.
|
|
35
|
+
*/
|
|
36
|
+
readonly schema?: {
|
|
37
|
+
parse(value: unknown): TOutput;
|
|
38
|
+
};
|
|
39
|
+
/** Optional description shown to the model alongside the schema. */
|
|
40
|
+
readonly description?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Wire-format JSON Schema advertised to the model: forwarded on
|
|
43
|
+
* `ProviderRequest.outputType` for adapters with native structured
|
|
44
|
+
* output, and embedded in the fallback JSON instruction appended as
|
|
45
|
+
* a trailing system message (the documented contract until adapters
|
|
46
|
+
* consume `outputType` natively — PS-24).
|
|
47
|
+
*/
|
|
48
|
+
readonly jsonSchema?: Readonly<Record<string, unknown>>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Per-step override hook. Receives the current `RunContext` and may
|
|
52
|
+
* return overrides applied to the next provider call only.
|
|
53
|
+
*
|
|
54
|
+
* @stable
|
|
55
|
+
*/
|
|
56
|
+
type PrepareStepHook<TDeps = unknown> = (ctx: RunContext<TDeps>) => Promise<PrepareStepOverrides<TDeps>> | PrepareStepOverrides<TDeps>;
|
|
57
|
+
/** @stable */
|
|
58
|
+
interface PrepareStepOverrides<TDeps = unknown> {
|
|
59
|
+
readonly provider?: Provider;
|
|
60
|
+
readonly tools?: ReadonlyArray<Tool<unknown, unknown, TDeps>>;
|
|
61
|
+
readonly toolChoice?: ToolChoice;
|
|
62
|
+
readonly temperature?: number;
|
|
63
|
+
readonly maxTokens?: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Compaction post-hook factory accepted by `createAgent({...})`.
|
|
67
|
+
* Re-exported from `@graphorin/memory` here for ergonomic typing.
|
|
68
|
+
*
|
|
69
|
+
* @stable
|
|
70
|
+
*/
|
|
71
|
+
type PostCompactionHook$1 = PostCompactionHook;
|
|
72
|
+
/**
|
|
73
|
+
* Skill-registry shape consumed by the agent loop. Implementations
|
|
74
|
+
* live in `@graphorin/skills`. We accept any structurally-compatible
|
|
75
|
+
* value to avoid the heavyweight peer dependency on the typing
|
|
76
|
+
* surface.
|
|
77
|
+
*
|
|
78
|
+
* @stable
|
|
79
|
+
*/
|
|
80
|
+
interface SkillsRegistryLike {
|
|
81
|
+
list?(): ReadonlyArray<unknown>;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Handoff target entry accepted by `createAgent({ handoffs })`.
|
|
85
|
+
* Either a bare {@link Agent} reference (default filter applied) or
|
|
86
|
+
* an explicit `{ target, inputFilter? }` envelope.
|
|
87
|
+
*
|
|
88
|
+
* @stable
|
|
89
|
+
*/
|
|
90
|
+
type HandoffEntry<TDeps = unknown> = Agent<TDeps, any> | {
|
|
91
|
+
readonly target: Agent<TDeps, any>;
|
|
92
|
+
readonly inputFilter?: HandoffFilter;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* The full options object accepted by {@link createAgent}.
|
|
96
|
+
*
|
|
97
|
+
* @stable
|
|
98
|
+
*/
|
|
99
|
+
interface AgentConfig<TDeps = unknown, TOutput = string> {
|
|
100
|
+
readonly name: string;
|
|
101
|
+
/**
|
|
102
|
+
* The agent's system prompt. A string is used verbatim; a function is
|
|
103
|
+
* resolved **once per run** (sync or async, awaited) against a
|
|
104
|
+
* {@link RunContext} snapshot at step 0, and its result is pinned as the
|
|
105
|
+
* run's system-prompt prefix for the whole run (it is not re-evaluated
|
|
106
|
+
* per step). An empty string injects no system message.
|
|
107
|
+
*/
|
|
108
|
+
readonly instructions: string | ((ctx: RunContext<TDeps>) => string | Promise<string>);
|
|
109
|
+
readonly provider: Provider;
|
|
110
|
+
readonly tools?: ReadonlyArray<Tool<unknown, unknown, TDeps>>;
|
|
111
|
+
readonly skills?: SkillsRegistryLike;
|
|
112
|
+
readonly memory?: Memory;
|
|
113
|
+
/**
|
|
114
|
+
* Opt in to building the per-run system prompt from the memory
|
|
115
|
+
* {@link ContextEngine} (CE-1). When `true` **and** `memory` is wired, the
|
|
116
|
+
* runtime calls `memory.contextEngine.assemble(...)` once at run start: the
|
|
117
|
+
* agent's `instructions` become Layer 2 and the engine prepends the memory
|
|
118
|
+
* base and appends working blocks, procedural rules, skill cards, the
|
|
119
|
+
* metadata counts, and — when `factsAutoRecall` is configured — auto-recalled
|
|
120
|
+
* facts. Defaults `false`: the prompt is built from `instructions` alone and
|
|
121
|
+
* the model reaches memory only through the memory tools it calls (the
|
|
122
|
+
* documented explicit pattern). Has no effect without `memory`.
|
|
123
|
+
*/
|
|
124
|
+
readonly autoAssembleContext?: boolean;
|
|
125
|
+
readonly handoffs?: ReadonlyArray<HandoffEntry<TDeps>>;
|
|
126
|
+
readonly outputType?: OutputSpec<TOutput>;
|
|
127
|
+
/**
|
|
128
|
+
* Deterministic checks run by the loop (AG-2; canonical contract is
|
|
129
|
+
* `@graphorin/security`'s `GuardrailDefinition` — SDF-4).
|
|
130
|
+
*
|
|
131
|
+
* - `input` guardrails run over each **fresh-run seed user message**
|
|
132
|
+
* (string content) before the first provider call. `'block'` fails
|
|
133
|
+
* the run (`guardrail-blocked`) without reaching the model;
|
|
134
|
+
* `'rewrite'` replaces the message content (mirrored into the
|
|
135
|
+
* persisted `RunState`); `'warn'` logs and continues.
|
|
136
|
+
* - `output` guardrails run over the **final output** on the
|
|
137
|
+
* completed path before `agent.end`. `'block'` fails the run;
|
|
138
|
+
* `'rewrite'` replaces `result.output` (text deltas were already
|
|
139
|
+
* streamed — the rewrite governs the durable result, not the
|
|
140
|
+
* live token stream).
|
|
141
|
+
*
|
|
142
|
+
* Every trip emits a `guardrail.tripped` event.
|
|
143
|
+
*/
|
|
144
|
+
readonly guardrails?: {
|
|
145
|
+
readonly input?: ReadonlyArray<InputGuardrail<string>>;
|
|
146
|
+
readonly output?: ReadonlyArray<OutputGuardrail<TOutput>>;
|
|
147
|
+
};
|
|
148
|
+
readonly stopWhen?: StopCondition;
|
|
149
|
+
readonly toolChoice?: ToolChoice;
|
|
150
|
+
readonly prepareStep?: PrepareStepHook<TDeps>;
|
|
151
|
+
readonly maxParallelTools?: number;
|
|
152
|
+
/**
|
|
153
|
+
* How the model invokes tools (P1-2).
|
|
154
|
+
*
|
|
155
|
+
* - `'direct'` (default) — the model emits one provider tool-call per
|
|
156
|
+
* tool, each result inlined into the conversation.
|
|
157
|
+
* - `'code-mode'` — the agent advertises only the `code_execute` /
|
|
158
|
+
* `code_search` meta-tools; the model writes a script that calls
|
|
159
|
+
* tools in a sandbox via `tools.<name>(args)`, and **only the
|
|
160
|
+
* script's final result re-enters context** (intermediate results
|
|
161
|
+
* stay inside the sandbox). Each in-script call still runs through
|
|
162
|
+
* the executor, so per-tool ACL / sanitization / truncation apply.
|
|
163
|
+
* Approval-gated tools are not reachable from code-mode (there is no
|
|
164
|
+
* durable-HITL path mid-script); call those in `'direct'` mode.
|
|
165
|
+
*
|
|
166
|
+
* @default 'direct'
|
|
167
|
+
*/
|
|
168
|
+
readonly toolInvocation?: 'direct' | 'code-mode';
|
|
169
|
+
readonly fallbackModels?: ReadonlyArray<ModelSpec>;
|
|
170
|
+
readonly fallbackPolicy?: AgentFallbackPolicy;
|
|
171
|
+
readonly preferredModel?: ModelHint | ModelSpec;
|
|
172
|
+
readonly modelTierMap?: Partial<Record<ModelHint, ModelSpec>>;
|
|
173
|
+
/**
|
|
174
|
+
* Per-agent override of the per-provider auto-detected
|
|
175
|
+
* {@link ReasoningRetention} default. Wins over the provider-
|
|
176
|
+
* level default when both are present. The agent runtime feeds
|
|
177
|
+
* the effective value into every `provider.stream(...)` call so
|
|
178
|
+
* the wire-correct contract is honoured per RB-42 / suggested
|
|
179
|
+
* DEC-158 / suggested ADR-046.
|
|
180
|
+
*/
|
|
181
|
+
readonly reasoningRetention?: ReasoningRetention;
|
|
182
|
+
readonly causalityMonitor?: CausalityMonitorConfig;
|
|
183
|
+
/**
|
|
184
|
+
* Sideways-injection merge guard for `agent.fanOut` `'judge-merge'`
|
|
185
|
+
* (AG-7): scores per-child source trust × contribution weight against
|
|
186
|
+
* the judge's merged output; a biased merge emits
|
|
187
|
+
* `agent.lateral-leak.detected` and `'detect-and-block'` throws
|
|
188
|
+
* `MergeBlockedError`.
|
|
189
|
+
*/
|
|
190
|
+
readonly mergeGuard?: MergeGuardConfig;
|
|
191
|
+
/**
|
|
192
|
+
* Provenance / taint-based data-flow policy (P1-3, opt-in). Enforces
|
|
193
|
+
* data-flow rules at the tool-execution boundary using the provenance
|
|
194
|
+
* Graphorin already tracks (trust class + source + sensitivity), to
|
|
195
|
+
* defuse the lethal trifecta: a sink (`side-effecting` /
|
|
196
|
+
* `external-stateful` tool) is blocked when untrusted content flows
|
|
197
|
+
* into it verbatim, or — conservatively — when it fires while both
|
|
198
|
+
* untrusted content and secret-tier data are present in the run.
|
|
199
|
+
*
|
|
200
|
+
* - `mode: 'shadow'` — audit-only; tainted flows are flagged
|
|
201
|
+
* (`tool:dataflow:flagged` audit + counter) but never blocked. Ship
|
|
202
|
+
* this first to surface false positives.
|
|
203
|
+
* - `mode: 'enforce'` — tainted flows are blocked (the sink does not
|
|
204
|
+
* run; the call yields a `dataflow_policy_blocked` error) unless the
|
|
205
|
+
* sink is listed in `declassifySinks` (an audited operator override).
|
|
206
|
+
*
|
|
207
|
+
* Composes with `'code-mode'`: each in-script tool call flows through
|
|
208
|
+
* the same executor gate. Absent (the default) leaves the loop
|
|
209
|
+
* unchanged.
|
|
210
|
+
*/
|
|
211
|
+
readonly dataFlowPolicy?: DataFlowPolicyConfig;
|
|
212
|
+
/**
|
|
213
|
+
* Additional result-handle readers (P1-4 / WI-13), tried after the
|
|
214
|
+
* built-in spill-file reader. Wire an MCP resource reader
|
|
215
|
+
* (`createMcpResourceReader` from `@graphorin/mcp/client`) here so the
|
|
216
|
+
* model can resolve an MCP `resource_link` on demand via the built-in
|
|
217
|
+
* `read_result` tool, instead of inlining the resource body. Supplying
|
|
218
|
+
* any reader force-registers `read_result` even when no tool spills.
|
|
219
|
+
*/
|
|
220
|
+
readonly resultReaders?: ReadonlyArray<ResultReader>;
|
|
221
|
+
readonly tracer?: Tracer;
|
|
222
|
+
readonly checkpointStore?: CheckpointStore;
|
|
223
|
+
readonly sensitivity?: Sensitivity;
|
|
224
|
+
readonly sessionId?: string;
|
|
225
|
+
readonly userId?: string;
|
|
226
|
+
readonly deps?: TDeps;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Single approval decision attached to a {@link ResumeDirective}.
|
|
230
|
+
* Mirrors the directive surface the HITL caller supplies on resume
|
|
231
|
+
* (per `Command(approval: { granted, reason? })` in the agent-loop
|
|
232
|
+
* reference, renamed to `Directive` per Graphorin's own naming).
|
|
233
|
+
*
|
|
234
|
+
* @stable
|
|
235
|
+
*/
|
|
236
|
+
interface ApprovalDecision {
|
|
237
|
+
readonly toolCallId: string;
|
|
238
|
+
readonly granted: boolean;
|
|
239
|
+
readonly reason?: string;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Resume directive accepted by `agent.run(input | RunState, { directive })`.
|
|
243
|
+
*
|
|
244
|
+
* The library-mode pickup pattern is: the operator stores the
|
|
245
|
+
* suspended `RunState` from the previous `agent.run(...)` call,
|
|
246
|
+
* waits for the user / cron / webhook to resolve the pending
|
|
247
|
+
* approval, and re-invokes `agent.run(savedState, { directive: {
|
|
248
|
+
* approvals: [...] } })` to resume.
|
|
249
|
+
*
|
|
250
|
+
* @stable
|
|
251
|
+
*/
|
|
252
|
+
interface ResumeDirective {
|
|
253
|
+
readonly approvals?: ReadonlyArray<ApprovalDecision>;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Per-call options accepted by `agent.stream(...)` / `agent.run(...)`.
|
|
257
|
+
*
|
|
258
|
+
* @stable
|
|
259
|
+
*/
|
|
260
|
+
interface AgentCallOptions<TDeps> {
|
|
261
|
+
readonly deps?: TDeps;
|
|
262
|
+
readonly signal?: AbortSignal;
|
|
263
|
+
readonly sessionId?: string;
|
|
264
|
+
readonly userId?: string;
|
|
265
|
+
/**
|
|
266
|
+
* HITL resume directive. Supplied alongside a `RunState` to
|
|
267
|
+
* resolve any approvals that were pending when the previous
|
|
268
|
+
* `agent.run(...)` call suspended.
|
|
269
|
+
*/
|
|
270
|
+
readonly directive?: ResumeDirective;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* `agent.toTool({...})` options.
|
|
274
|
+
*
|
|
275
|
+
* @stable
|
|
276
|
+
*/
|
|
277
|
+
interface AgentToToolOptions {
|
|
278
|
+
readonly name?: string;
|
|
279
|
+
readonly description?: string;
|
|
280
|
+
readonly exposeTurns?: 'final' | 'all' | 'none';
|
|
281
|
+
/**
|
|
282
|
+
* Shapes the sub-agent seed from the parent history (AG-17): when
|
|
283
|
+
* supplied, the sub-agent is seeded with
|
|
284
|
+
* `[...inputFilter(parentMessages), { role: 'user', content: input }]`.
|
|
285
|
+
* Without a filter the sub-agent sees ONLY the input string — no
|
|
286
|
+
* parent conversation crosses the boundary (least authority by
|
|
287
|
+
* construction; there is no secret-inheritance mechanism at this
|
|
288
|
+
* boundary at all).
|
|
289
|
+
*/
|
|
290
|
+
readonly inputFilter?: HandoffFilter;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Cancellation options accepted by `agent.abort({...})`.
|
|
294
|
+
*
|
|
295
|
+
* @stable
|
|
296
|
+
*/
|
|
297
|
+
interface AbortOptions {
|
|
298
|
+
/**
|
|
299
|
+
* When `true`, let the in-flight provider stream finish (the current step
|
|
300
|
+
* reaches its boundary) instead of interrupting it mid-event, then stop at the
|
|
301
|
+
* next step. Default `false` hard-kills the in-flight stream immediately. (The
|
|
302
|
+
* step's tool calls still observe the cancellation once the signal is set.)
|
|
303
|
+
*/
|
|
304
|
+
readonly drain?: boolean;
|
|
305
|
+
/**
|
|
306
|
+
* What to do with approvals that were already requested but not
|
|
307
|
+
* resolved at abort time.
|
|
308
|
+
*
|
|
309
|
+
* - `'deny'` (default) — auto-deny pending approvals.
|
|
310
|
+
* - `'hold'` — keep the approvals on `RunState.pendingApprovals`.
|
|
311
|
+
* - `'fail'` — reject the run with `RunError(code: 'run-aborted')`.
|
|
312
|
+
*/
|
|
313
|
+
readonly onPendingApprovals?: 'deny' | 'hold' | 'fail';
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* `agent.compact({...})` options.
|
|
317
|
+
*
|
|
318
|
+
* @stable
|
|
319
|
+
*/
|
|
320
|
+
interface CompactOptions {
|
|
321
|
+
readonly source?: 'manual' | 'pre-step';
|
|
322
|
+
readonly preserveRecentTurns?: number;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Result of `agent.compact({...})`.
|
|
326
|
+
*
|
|
327
|
+
* @stable
|
|
328
|
+
*/
|
|
329
|
+
interface CompactionApiResult {
|
|
330
|
+
readonly beforeTokens: number;
|
|
331
|
+
readonly afterTokens: number;
|
|
332
|
+
readonly summaryTokens: number;
|
|
333
|
+
readonly durationMs: number;
|
|
334
|
+
readonly hooksFiredCount: number;
|
|
335
|
+
readonly summary: string;
|
|
336
|
+
/**
|
|
337
|
+
* `true` when the compaction trimmed + spliced the live run buffer
|
|
338
|
+
* (CE-3/AG-13). `false` results carry an explicit
|
|
339
|
+
* {@link skippedReason} instead of silently reporting zeros.
|
|
340
|
+
*/
|
|
341
|
+
readonly applied: boolean;
|
|
342
|
+
/** Why nothing was spliced, when {@link applied} is `false`. */
|
|
343
|
+
readonly skippedReason?: 'no-memory' | 'no-active-run' | 'nothing-to-trim' | 'sensitivity-gated';
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Per-call shape accepted by `Agent.fanOut(...)`. Mirrors the
|
|
347
|
+
* pure-function {@link FanOutOptions} but omits the runtime-supplied
|
|
348
|
+
* identifiers — the `Agent` instance carries those.
|
|
349
|
+
*
|
|
350
|
+
* @stable
|
|
351
|
+
*/
|
|
352
|
+
interface AgentFanOutOptions<TOutput = unknown> {
|
|
353
|
+
readonly children: FanOutOptions<TOutput>['children'];
|
|
354
|
+
readonly maxConcurrentChildren?: number;
|
|
355
|
+
readonly perBudget?: PerChildBudget;
|
|
356
|
+
readonly mergeStrategy?: MergeStrategy<TOutput>;
|
|
357
|
+
readonly signal?: AbortSignal;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Progress IO surface exposed on the `Agent` instance. The methods
|
|
361
|
+
* default the `runId` cursor to the in-flight run when present, so
|
|
362
|
+
* callers can use them inside an `agent.run(...)` boundary without
|
|
363
|
+
* repeating the cursor.
|
|
364
|
+
*
|
|
365
|
+
* @stable
|
|
366
|
+
*/
|
|
367
|
+
interface AgentProgressIO {
|
|
368
|
+
write(content: string, options?: ProgressWriteOptions): Promise<ProgressArtifactRef>;
|
|
369
|
+
read(options?: ProgressReadOptions): Promise<ReadonlyArray<ProgressArtifactRef>>;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Public agent surface returned by {@link createAgent}.
|
|
373
|
+
*
|
|
374
|
+
* @stable
|
|
375
|
+
*/
|
|
376
|
+
interface Agent<TDeps = unknown, TOutput = string> {
|
|
377
|
+
readonly id: string;
|
|
378
|
+
readonly config: AgentConfig<TDeps, TOutput>;
|
|
379
|
+
stream(input: AgentInput | RunState, options?: AgentCallOptions<TDeps>): AsyncIterable<AgentEvent<TOutput>>;
|
|
380
|
+
run(input: AgentInput | RunState, options?: AgentCallOptions<TDeps>): Promise<AgentResult<TOutput>>;
|
|
381
|
+
steer(message: AgentInput): void;
|
|
382
|
+
followUp(message: AgentInput): void;
|
|
383
|
+
abort(options?: AbortOptions): void;
|
|
384
|
+
toTool(options?: AgentToToolOptions): Tool<{
|
|
385
|
+
readonly input: string;
|
|
386
|
+
}, TOutput, TDeps>;
|
|
387
|
+
compact(options?: CompactOptions): Promise<CompactionApiResult>;
|
|
388
|
+
/**
|
|
389
|
+
* Convenience wrapper around the standalone `runFanOut(...)`. The
|
|
390
|
+
* returned `FanOutResult` carries per-child status + the merged
|
|
391
|
+
* output. Per-child failures are captured in `children[].status`
|
|
392
|
+
* — this method never throws on a child failure (the merge
|
|
393
|
+
* strategy decides whether to propagate).
|
|
394
|
+
*/
|
|
395
|
+
fanOut<TFanOutOutput = unknown>(options: AgentFanOutOptions<TFanOutOutput>): Promise<FanOutResult<TFanOutOutput>>;
|
|
396
|
+
/**
|
|
397
|
+
* Structured handoff-artifact APIs. Persists / reads UTF-8 text
|
|
398
|
+
* artifacts under the configured artifact root; cross-run reads
|
|
399
|
+
* require an explicit `runId` cursor on the read options.
|
|
400
|
+
*/
|
|
401
|
+
readonly progress: AgentProgressIO;
|
|
402
|
+
/**
|
|
403
|
+
* The unified tool registry assembled at `createAgent(...)` warm-up
|
|
404
|
+
* (Principle #12): every first-party + skill tool, with cross-source
|
|
405
|
+
* name collisions resolved deterministically. Read-only and exposed
|
|
406
|
+
* for inspection; the run loop and `tool_search` consume it. Always
|
|
407
|
+
* present on agents built by `createAgent(...)`.
|
|
408
|
+
*/
|
|
409
|
+
readonly registry?: ToolRegistry;
|
|
410
|
+
}
|
|
411
|
+
//#endregion
|
|
412
|
+
export { AbortOptions, Agent, AgentCallOptions, AgentConfig, AgentInput, AgentToToolOptions, CompactOptions, CompactionApiResult, OutputSpec, PostCompactionHook$1 as PostCompactionHook, PrepareStepHook, PrepareStepOverrides, ResumeDirective, SkillsRegistryLike };
|
|
413
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
|