@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.
Files changed (72) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +159 -0
  4. package/dist/errors/index.d.ts +170 -0
  5. package/dist/errors/index.d.ts.map +1 -0
  6. package/dist/errors/index.js +204 -0
  7. package/dist/errors/index.js.map +1 -0
  8. package/dist/evaluator-optimizer/index.d.ts +91 -0
  9. package/dist/evaluator-optimizer/index.d.ts.map +1 -0
  10. package/dist/evaluator-optimizer/index.js +85 -0
  11. package/dist/evaluator-optimizer/index.js.map +1 -0
  12. package/dist/factory.d.ts +13 -0
  13. package/dist/factory.d.ts.map +1 -0
  14. package/dist/factory.js +1853 -0
  15. package/dist/factory.js.map +1 -0
  16. package/dist/fallback/index.d.ts +52 -0
  17. package/dist/fallback/index.d.ts.map +1 -0
  18. package/dist/fallback/index.js +53 -0
  19. package/dist/fallback/index.js.map +1 -0
  20. package/dist/fanout/index.d.ts +142 -0
  21. package/dist/fanout/index.d.ts.map +1 -0
  22. package/dist/fanout/index.js +252 -0
  23. package/dist/fanout/index.js.map +1 -0
  24. package/dist/filters/index.d.ts +137 -0
  25. package/dist/filters/index.d.ts.map +1 -0
  26. package/dist/filters/index.js +273 -0
  27. package/dist/filters/index.js.map +1 -0
  28. package/dist/index.d.ts +51 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +49 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/internal/ids.js +46 -0
  33. package/dist/internal/ids.js.map +1 -0
  34. package/dist/internal/usage-accumulator.js +62 -0
  35. package/dist/internal/usage-accumulator.js.map +1 -0
  36. package/dist/lateral-leak/causality-monitor.d.ts +97 -0
  37. package/dist/lateral-leak/causality-monitor.d.ts.map +1 -0
  38. package/dist/lateral-leak/causality-monitor.js +139 -0
  39. package/dist/lateral-leak/causality-monitor.js.map +1 -0
  40. package/dist/lateral-leak/index.d.ts +4 -0
  41. package/dist/lateral-leak/index.js +5 -0
  42. package/dist/lateral-leak/merge-guard.d.ts +89 -0
  43. package/dist/lateral-leak/merge-guard.d.ts.map +1 -0
  44. package/dist/lateral-leak/merge-guard.js +65 -0
  45. package/dist/lateral-leak/merge-guard.js.map +1 -0
  46. package/dist/lateral-leak/protocol-guard.d.ts +76 -0
  47. package/dist/lateral-leak/protocol-guard.d.ts.map +1 -0
  48. package/dist/lateral-leak/protocol-guard.js +147 -0
  49. package/dist/lateral-leak/protocol-guard.js.map +1 -0
  50. package/dist/preferred-model/index.d.ts +53 -0
  51. package/dist/preferred-model/index.d.ts.map +1 -0
  52. package/dist/preferred-model/index.js +141 -0
  53. package/dist/preferred-model/index.js.map +1 -0
  54. package/dist/progress/index.d.ts +62 -0
  55. package/dist/progress/index.d.ts.map +1 -0
  56. package/dist/progress/index.js +150 -0
  57. package/dist/progress/index.js.map +1 -0
  58. package/dist/run-state/index.d.ts +152 -0
  59. package/dist/run-state/index.d.ts.map +1 -0
  60. package/dist/run-state/index.js +311 -0
  61. package/dist/run-state/index.js.map +1 -0
  62. package/dist/tooling/adapters.js +154 -0
  63. package/dist/tooling/adapters.js.map +1 -0
  64. package/dist/tooling/catalogue.js +37 -0
  65. package/dist/tooling/catalogue.js.map +1 -0
  66. package/dist/tooling/dataflow.js +99 -0
  67. package/dist/tooling/dataflow.js.map +1 -0
  68. package/dist/tooling/registry-build.js +85 -0
  69. package/dist/tooling/registry-build.js.map +1 -0
  70. package/dist/types.d.ts +413 -0
  71. package/dist/types.d.ts.map +1 -0
  72. 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"}
@@ -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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"}