@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,141 @@
|
|
|
1
|
+
//#region src/preferred-model/index.ts
|
|
2
|
+
const TIER_ORDER = {
|
|
3
|
+
fast: 0,
|
|
4
|
+
balanced: 1,
|
|
5
|
+
smart: 2
|
|
6
|
+
};
|
|
7
|
+
function isModelHint(value) {
|
|
8
|
+
return value === "fast" || value === "balanced" || value === "smart";
|
|
9
|
+
}
|
|
10
|
+
function specToProvider(spec) {
|
|
11
|
+
if ("provider" in spec) return spec.provider;
|
|
12
|
+
return spec;
|
|
13
|
+
}
|
|
14
|
+
function modelIdFromSpec(spec) {
|
|
15
|
+
if ("provider" in spec) return spec.model;
|
|
16
|
+
return spec.modelId;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Pick the highest-cost tier across the supplied per-tool hints.
|
|
20
|
+
* Explicit `ModelSpec` entries are treated as the highest tier
|
|
21
|
+
* (`'smart'`) for tie-breaking — the conservative-correctness rule
|
|
22
|
+
* documented in DEC-169 / suggested ADR-057.
|
|
23
|
+
*
|
|
24
|
+
* Returns the picked hint together with the original `ModelSpec`
|
|
25
|
+
* (when an explicit spec won the tie-break).
|
|
26
|
+
*
|
|
27
|
+
* @stable
|
|
28
|
+
*/
|
|
29
|
+
function pickTopTierAcrossTools(hints) {
|
|
30
|
+
let bestRank = -1;
|
|
31
|
+
let bestSpec;
|
|
32
|
+
let bestHint;
|
|
33
|
+
for (const h of hints) {
|
|
34
|
+
if (h === void 0) continue;
|
|
35
|
+
if (isModelHint(h)) {
|
|
36
|
+
const rank = TIER_ORDER[h];
|
|
37
|
+
if (rank > bestRank) {
|
|
38
|
+
bestRank = rank;
|
|
39
|
+
bestSpec = void 0;
|
|
40
|
+
bestHint = h;
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
const rank = TIER_ORDER.smart;
|
|
44
|
+
if (rank >= bestRank) {
|
|
45
|
+
bestRank = rank;
|
|
46
|
+
bestSpec = h;
|
|
47
|
+
bestHint = "smart";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (bestHint === void 0) return void 0;
|
|
52
|
+
if (bestSpec !== void 0) return {
|
|
53
|
+
hint: bestHint,
|
|
54
|
+
spec: bestSpec
|
|
55
|
+
};
|
|
56
|
+
return { hint: bestHint };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Walk the precedence ladder and return the resolved provider for a
|
|
60
|
+
* single agent step. Pure function — no side effects.
|
|
61
|
+
*
|
|
62
|
+
* @stable
|
|
63
|
+
*/
|
|
64
|
+
function resolvePreferredModel(input) {
|
|
65
|
+
if (input.prepareStepProvider !== void 0) return {
|
|
66
|
+
resolvedProvider: input.prepareStepProvider,
|
|
67
|
+
resolvedModelId: input.prepareStepProvider.modelId,
|
|
68
|
+
source: "prepare-step"
|
|
69
|
+
};
|
|
70
|
+
const top = pickTopTierAcrossTools(input.toolPreferredModels);
|
|
71
|
+
if (top !== void 0) {
|
|
72
|
+
if (top.spec !== void 0) return {
|
|
73
|
+
resolvedProvider: specToProvider(top.spec),
|
|
74
|
+
resolvedModelId: modelIdFromSpec(top.spec),
|
|
75
|
+
source: "spec"
|
|
76
|
+
};
|
|
77
|
+
const mapped = input.modelTierMap?.[top.hint];
|
|
78
|
+
if (mapped !== void 0) return {
|
|
79
|
+
resolvedProvider: specToProvider(mapped),
|
|
80
|
+
resolvedModelId: modelIdFromSpec(mapped),
|
|
81
|
+
source: "tier-map",
|
|
82
|
+
hintApplied: top.hint
|
|
83
|
+
};
|
|
84
|
+
const agent$1 = input.agentPreferredModel;
|
|
85
|
+
if (agent$1 !== void 0) if (isModelHint(agent$1)) {
|
|
86
|
+
const agentMapped = input.modelTierMap?.[agent$1];
|
|
87
|
+
if (agentMapped !== void 0) return {
|
|
88
|
+
resolvedProvider: specToProvider(agentMapped),
|
|
89
|
+
resolvedModelId: modelIdFromSpec(agentMapped),
|
|
90
|
+
source: "agent-preferred",
|
|
91
|
+
hintApplied: agent$1,
|
|
92
|
+
fallthroughReason: "tier-not-mapped"
|
|
93
|
+
};
|
|
94
|
+
} else return {
|
|
95
|
+
resolvedProvider: specToProvider(agent$1),
|
|
96
|
+
resolvedModelId: modelIdFromSpec(agent$1),
|
|
97
|
+
source: "agent-preferred",
|
|
98
|
+
fallthroughReason: "tier-not-mapped"
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
resolvedProvider: input.agentDefaultProvider,
|
|
102
|
+
resolvedModelId: input.agentDefaultProvider.modelId,
|
|
103
|
+
source: "fallthrough-default",
|
|
104
|
+
hintApplied: top.hint,
|
|
105
|
+
fallthroughReason: "tier-not-mapped"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const agent = input.agentPreferredModel;
|
|
109
|
+
if (agent !== void 0) {
|
|
110
|
+
if (isModelHint(agent)) {
|
|
111
|
+
const mapped = input.modelTierMap?.[agent];
|
|
112
|
+
if (mapped !== void 0) return {
|
|
113
|
+
resolvedProvider: specToProvider(mapped),
|
|
114
|
+
resolvedModelId: modelIdFromSpec(mapped),
|
|
115
|
+
source: "agent-preferred",
|
|
116
|
+
hintApplied: agent
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
resolvedProvider: input.agentDefaultProvider,
|
|
120
|
+
resolvedModelId: input.agentDefaultProvider.modelId,
|
|
121
|
+
source: "fallthrough-default",
|
|
122
|
+
hintApplied: agent,
|
|
123
|
+
fallthroughReason: "tier-not-mapped"
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
resolvedProvider: specToProvider(agent),
|
|
128
|
+
resolvedModelId: modelIdFromSpec(agent),
|
|
129
|
+
source: "agent-preferred"
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
resolvedProvider: input.agentDefaultProvider,
|
|
134
|
+
resolvedModelId: input.agentDefaultProvider.modelId,
|
|
135
|
+
source: "fallthrough-default"
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
export { pickTopTierAcrossTools, resolvePreferredModel };
|
|
141
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["TIER_ORDER: Record<ModelHint, number>","bestSpec: ModelSpec | undefined","bestHint: ModelHint | undefined","agent"],"sources":["../../src/preferred-model/index.ts"],"sourcesContent":["/**\n * Per-tool / per-agent preferred-model resolution. Pure functions\n * consulted by the agent loop AFTER the model has decided which\n * tool(s) to call but BEFORE `provider.stream(...)` is invoked.\n *\n * The four-step precedence ladder (highest wins):\n *\n * 1. `prepareStep({ provider })` — the operator's explicit per-step\n * override always wins.\n * 2. `Tool.preferredModel` — the tool author's per-tool hint.\n * Only the tools the model actually CALLED on the previous step\n * are consulted (AG-15) — an advertised-but-uncalled hint never\n * escalates the run. Multi-tool ties resolve to the highest cost\n * tier (`'smart' > 'balanced' > 'fast'`; explicit `ModelSpec` is\n * treated as the highest tier).\n * 3. `Agent.preferredModel?` — the per-agent default.\n * 4. `Agent` default `provider` — the v0.1-alpha behaviour.\n *\n * Cost-tier resolution against `Agent.modelTierMap` is documented\n * as a hint: when the requested tier is unmapped, the resolver\n * falls through to the next precedence step rather than throwing.\n *\n * @packageDocumentation\n */\n\nimport type { ModelHint, ModelSpec, Provider } from '@graphorin/core';\n\nconst TIER_ORDER: Record<ModelHint, number> = { fast: 0, balanced: 1, smart: 2 };\n\n/**\n * Result returned by {@link resolvePreferredModel}.\n *\n * @stable\n */\nexport interface PreferredModelResolution {\n readonly resolvedProvider: Provider;\n readonly resolvedModelId: string;\n readonly source: 'prepare-step' | 'tier-map' | 'spec' | 'agent-preferred' | 'fallthrough-default';\n readonly hintApplied?: ModelHint;\n readonly fallthroughReason?:\n | 'tier-not-mapped'\n | 'provider-unavailable'\n | 'override-takes-precedence';\n}\n\n/**\n * Pure inputs to {@link resolvePreferredModel}.\n *\n * @stable\n */\nexport interface ResolvePreferredModelInput {\n readonly prepareStepProvider?: Provider;\n readonly toolPreferredModels: ReadonlyArray<ModelHint | ModelSpec | undefined>;\n readonly agentPreferredModel?: ModelHint | ModelSpec;\n readonly agentDefaultProvider: Provider;\n readonly modelTierMap?: Partial<Record<ModelHint, ModelSpec>>;\n}\n\nfunction isModelHint(value: ModelHint | ModelSpec | undefined): value is ModelHint {\n return value === 'fast' || value === 'balanced' || value === 'smart';\n}\n\nfunction specToProvider(spec: ModelSpec): Provider {\n if ('provider' in spec) return spec.provider as Provider;\n return spec as Provider;\n}\n\nfunction modelIdFromSpec(spec: ModelSpec): string {\n if ('provider' in spec) return spec.model;\n return (spec as Provider).modelId;\n}\n\n/**\n * Pick the highest-cost tier across the supplied per-tool hints.\n * Explicit `ModelSpec` entries are treated as the highest tier\n * (`'smart'`) for tie-breaking — the conservative-correctness rule\n * documented in DEC-169 / suggested ADR-057.\n *\n * Returns the picked hint together with the original `ModelSpec`\n * (when an explicit spec won the tie-break).\n *\n * @stable\n */\nexport function pickTopTierAcrossTools(\n hints: ReadonlyArray<ModelHint | ModelSpec | undefined>,\n): { readonly hint: ModelHint; readonly spec?: ModelSpec } | undefined {\n let bestRank = -1;\n let bestSpec: ModelSpec | undefined;\n let bestHint: ModelHint | undefined;\n for (const h of hints) {\n if (h === undefined) continue;\n if (isModelHint(h)) {\n const rank = TIER_ORDER[h];\n if (rank > bestRank) {\n bestRank = rank;\n bestSpec = undefined;\n bestHint = h;\n }\n } else {\n // Explicit `ModelSpec` -> treat as the highest tier.\n const rank = TIER_ORDER.smart;\n if (rank >= bestRank) {\n bestRank = rank;\n bestSpec = h;\n bestHint = 'smart';\n }\n }\n }\n if (bestHint === undefined) return undefined;\n if (bestSpec !== undefined) return { hint: bestHint, spec: bestSpec };\n return { hint: bestHint };\n}\n\n/**\n * Walk the precedence ladder and return the resolved provider for a\n * single agent step. Pure function — no side effects.\n *\n * @stable\n */\nexport function resolvePreferredModel(input: ResolvePreferredModelInput): PreferredModelResolution {\n if (input.prepareStepProvider !== undefined) {\n return {\n resolvedProvider: input.prepareStepProvider,\n resolvedModelId: input.prepareStepProvider.modelId,\n source: 'prepare-step',\n };\n }\n const top = pickTopTierAcrossTools(input.toolPreferredModels);\n if (top !== undefined) {\n if (top.spec !== undefined) {\n return {\n resolvedProvider: specToProvider(top.spec),\n resolvedModelId: modelIdFromSpec(top.spec),\n source: 'spec',\n };\n }\n const mapped = input.modelTierMap?.[top.hint];\n if (mapped !== undefined) {\n return {\n resolvedProvider: specToProvider(mapped),\n resolvedModelId: modelIdFromSpec(mapped),\n source: 'tier-map',\n hintApplied: top.hint,\n };\n }\n // Fall through to agent-preferred / default.\n const agent = input.agentPreferredModel;\n if (agent !== undefined) {\n if (isModelHint(agent)) {\n const agentMapped = input.modelTierMap?.[agent];\n if (agentMapped !== undefined) {\n return {\n resolvedProvider: specToProvider(agentMapped),\n resolvedModelId: modelIdFromSpec(agentMapped),\n source: 'agent-preferred',\n hintApplied: agent,\n fallthroughReason: 'tier-not-mapped',\n };\n }\n } else {\n return {\n resolvedProvider: specToProvider(agent),\n resolvedModelId: modelIdFromSpec(agent),\n source: 'agent-preferred',\n fallthroughReason: 'tier-not-mapped',\n };\n }\n }\n return {\n resolvedProvider: input.agentDefaultProvider,\n resolvedModelId: input.agentDefaultProvider.modelId,\n source: 'fallthrough-default',\n hintApplied: top.hint,\n fallthroughReason: 'tier-not-mapped',\n };\n }\n // No per-tool hints. Honour `Agent.preferredModel` next.\n const agent = input.agentPreferredModel;\n if (agent !== undefined) {\n if (isModelHint(agent)) {\n const mapped = input.modelTierMap?.[agent];\n if (mapped !== undefined) {\n return {\n resolvedProvider: specToProvider(mapped),\n resolvedModelId: modelIdFromSpec(mapped),\n source: 'agent-preferred',\n hintApplied: agent,\n };\n }\n // Agent-default tier not mapped: fall through.\n return {\n resolvedProvider: input.agentDefaultProvider,\n resolvedModelId: input.agentDefaultProvider.modelId,\n source: 'fallthrough-default',\n hintApplied: agent,\n fallthroughReason: 'tier-not-mapped',\n };\n }\n return {\n resolvedProvider: specToProvider(agent),\n resolvedModelId: modelIdFromSpec(agent),\n source: 'agent-preferred',\n };\n }\n return {\n resolvedProvider: input.agentDefaultProvider,\n resolvedModelId: input.agentDefaultProvider.modelId,\n source: 'fallthrough-default',\n };\n}\n"],"mappings":";AA2BA,MAAMA,aAAwC;CAAE,MAAM;CAAG,UAAU;CAAG,OAAO;CAAG;AA+BhF,SAAS,YAAY,OAA8D;AACjF,QAAO,UAAU,UAAU,UAAU,cAAc,UAAU;;AAG/D,SAAS,eAAe,MAA2B;AACjD,KAAI,cAAc,KAAM,QAAO,KAAK;AACpC,QAAO;;AAGT,SAAS,gBAAgB,MAAyB;AAChD,KAAI,cAAc,KAAM,QAAO,KAAK;AACpC,QAAQ,KAAkB;;;;;;;;;;;;;AAc5B,SAAgB,uBACd,OACqE;CACrE,IAAI,WAAW;CACf,IAAIC;CACJ,IAAIC;AACJ,MAAK,MAAM,KAAK,OAAO;AACrB,MAAI,MAAM,OAAW;AACrB,MAAI,YAAY,EAAE,EAAE;GAClB,MAAM,OAAO,WAAW;AACxB,OAAI,OAAO,UAAU;AACnB,eAAW;AACX,eAAW;AACX,eAAW;;SAER;GAEL,MAAM,OAAO,WAAW;AACxB,OAAI,QAAQ,UAAU;AACpB,eAAW;AACX,eAAW;AACX,eAAW;;;;AAIjB,KAAI,aAAa,OAAW,QAAO;AACnC,KAAI,aAAa,OAAW,QAAO;EAAE,MAAM;EAAU,MAAM;EAAU;AACrE,QAAO,EAAE,MAAM,UAAU;;;;;;;;AAS3B,SAAgB,sBAAsB,OAA6D;AACjG,KAAI,MAAM,wBAAwB,OAChC,QAAO;EACL,kBAAkB,MAAM;EACxB,iBAAiB,MAAM,oBAAoB;EAC3C,QAAQ;EACT;CAEH,MAAM,MAAM,uBAAuB,MAAM,oBAAoB;AAC7D,KAAI,QAAQ,QAAW;AACrB,MAAI,IAAI,SAAS,OACf,QAAO;GACL,kBAAkB,eAAe,IAAI,KAAK;GAC1C,iBAAiB,gBAAgB,IAAI,KAAK;GAC1C,QAAQ;GACT;EAEH,MAAM,SAAS,MAAM,eAAe,IAAI;AACxC,MAAI,WAAW,OACb,QAAO;GACL,kBAAkB,eAAe,OAAO;GACxC,iBAAiB,gBAAgB,OAAO;GACxC,QAAQ;GACR,aAAa,IAAI;GAClB;EAGH,MAAMC,UAAQ,MAAM;AACpB,MAAIA,YAAU,OACZ,KAAI,YAAYA,QAAM,EAAE;GACtB,MAAM,cAAc,MAAM,eAAeA;AACzC,OAAI,gBAAgB,OAClB,QAAO;IACL,kBAAkB,eAAe,YAAY;IAC7C,iBAAiB,gBAAgB,YAAY;IAC7C,QAAQ;IACR,aAAaA;IACb,mBAAmB;IACpB;QAGH,QAAO;GACL,kBAAkB,eAAeA,QAAM;GACvC,iBAAiB,gBAAgBA,QAAM;GACvC,QAAQ;GACR,mBAAmB;GACpB;AAGL,SAAO;GACL,kBAAkB,MAAM;GACxB,iBAAiB,MAAM,qBAAqB;GAC5C,QAAQ;GACR,aAAa,IAAI;GACjB,mBAAmB;GACpB;;CAGH,MAAM,QAAQ,MAAM;AACpB,KAAI,UAAU,QAAW;AACvB,MAAI,YAAY,MAAM,EAAE;GACtB,MAAM,SAAS,MAAM,eAAe;AACpC,OAAI,WAAW,OACb,QAAO;IACL,kBAAkB,eAAe,OAAO;IACxC,iBAAiB,gBAAgB,OAAO;IACxC,QAAQ;IACR,aAAa;IACd;AAGH,UAAO;IACL,kBAAkB,MAAM;IACxB,iBAAiB,MAAM,qBAAqB;IAC5C,QAAQ;IACR,aAAa;IACb,mBAAmB;IACpB;;AAEH,SAAO;GACL,kBAAkB,eAAe,MAAM;GACvC,iBAAiB,gBAAgB,MAAM;GACvC,QAAQ;GACT;;AAEH,QAAO;EACL,kBAAkB,MAAM;EACxB,iBAAiB,MAAM,qBAAqB;EAC5C,QAAQ;EACT"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ProgressArtifactRef, Sensitivity } from "@graphorin/core";
|
|
2
|
+
|
|
3
|
+
//#region src/progress/index.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Optional configuration accepted by {@link createProgressIO}.
|
|
7
|
+
*
|
|
8
|
+
* @stable
|
|
9
|
+
*/
|
|
10
|
+
interface ProgressIOConfig {
|
|
11
|
+
/** Filesystem root under which `<runId>/progress/<role>.<seq>.txt` files live. */
|
|
12
|
+
readonly artifactRoot?: string;
|
|
13
|
+
/** Default `Sensitivity` applied when the caller does not override. */
|
|
14
|
+
readonly defaultSensitivity?: Sensitivity;
|
|
15
|
+
/** Optional redaction transform applied to content before write. */
|
|
16
|
+
readonly redact?: (content: string) => string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Per-call options for {@link ProgressIO.write}.
|
|
20
|
+
*
|
|
21
|
+
* @stable
|
|
22
|
+
*/
|
|
23
|
+
interface ProgressWriteOptions {
|
|
24
|
+
readonly role?: string;
|
|
25
|
+
/** Explicit sequence number; default auto-increments per `(runId, role)`. */
|
|
26
|
+
readonly seq?: number;
|
|
27
|
+
readonly sensitivity?: Sensitivity;
|
|
28
|
+
readonly tags?: ReadonlyArray<string>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Per-call options for {@link ProgressIO.read}.
|
|
32
|
+
*
|
|
33
|
+
* @stable
|
|
34
|
+
*/
|
|
35
|
+
interface ProgressReadOptions {
|
|
36
|
+
readonly runId?: string;
|
|
37
|
+
readonly role?: string;
|
|
38
|
+
/** Skip artifacts whose `seq <= sinceSeq`. */
|
|
39
|
+
readonly sinceSeq?: number;
|
|
40
|
+
/** Default `100`. */
|
|
41
|
+
readonly maxArtifacts?: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Public surface returned by {@link createProgressIO}. Used by the
|
|
45
|
+
* agent runtime to back `agent.progress.write / read`.
|
|
46
|
+
*
|
|
47
|
+
* @stable
|
|
48
|
+
*/
|
|
49
|
+
interface ProgressIO {
|
|
50
|
+
write(runId: string, content: string, options?: ProgressWriteOptions): Promise<ProgressArtifactRef>;
|
|
51
|
+
read(currentRunId: string, options?: ProgressReadOptions): Promise<ReadonlyArray<ProgressArtifactRef>>;
|
|
52
|
+
rootFor(runId: string): string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build a {@link ProgressIO} bound to a particular artifact root.
|
|
56
|
+
*
|
|
57
|
+
* @stable
|
|
58
|
+
*/
|
|
59
|
+
declare function createProgressIO(config?: ProgressIOConfig): ProgressIO;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { ProgressIO, ProgressIOConfig, ProgressReadOptions, ProgressWriteOptions, createProgressIO };
|
|
62
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/progress/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;UAoCiB,gBAAA;;;;gCAIe;;;;;;;;;UAUf,oBAAA;;;;yBAIQ;kBACP;;;;;;;UAQD,mBAAA;;;;;;;;;;;;;;UAeA,UAAA;kDAIH,uBACT,QAAQ;uCAGC,sBACT,QAAQ,cAAc;;;;;;;;iBAkBX,gBAAA,UAAyB,mBAAwB"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { ProgressWriteError } from "../errors/index.js";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { mkdir, readFile, readdir, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
//#region src/progress/index.ts
|
|
8
|
+
/**
|
|
9
|
+
* Structured progress-artifact IO. Persists UTF-8 text artifacts
|
|
10
|
+
* under `<artifactRoot>/<runId>/progress/<role>.<seqPadded>.txt`
|
|
11
|
+
* via atomic-write `.tmp + rename` discipline.
|
|
12
|
+
*
|
|
13
|
+
* Cross-session continuity flow:
|
|
14
|
+
*
|
|
15
|
+
* 1. The current agent calls `agent.progress.write(content)` —
|
|
16
|
+
* runtime persists the file and queues the
|
|
17
|
+
* `agent.progress.written` event (drained into the active or
|
|
18
|
+
* next consumed stream).
|
|
19
|
+
* 2. A sibling / future agent calls
|
|
20
|
+
* `agent.progress.read({ runId: priorRunId })` — runtime
|
|
21
|
+
* discovers existing files (no implicit auto-discovery; the
|
|
22
|
+
* operator must supply the `runId` cursor).
|
|
23
|
+
*
|
|
24
|
+
* Auto-discovery across runs is deferred to v0.2.
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_ARTIFACT_DIR = "graphorin-progress";
|
|
29
|
+
const SEQ_PAD_WIDTH = 3;
|
|
30
|
+
const seqWidth = (n) => String(n).padStart(SEQ_PAD_WIDTH, "0");
|
|
31
|
+
const sha256Hex = (input) => createHash("sha256").update(input, "utf8").digest("hex");
|
|
32
|
+
/**
|
|
33
|
+
* Build a {@link ProgressIO} bound to a particular artifact root.
|
|
34
|
+
*
|
|
35
|
+
* @stable
|
|
36
|
+
*/
|
|
37
|
+
function createProgressIO(config = {}) {
|
|
38
|
+
const root = config.artifactRoot ?? join(tmpdir(), DEFAULT_ARTIFACT_DIR);
|
|
39
|
+
const defaultSensitivity = config.defaultSensitivity ?? "internal";
|
|
40
|
+
const redact = config.redact ?? ((s) => s);
|
|
41
|
+
const seqState = /* @__PURE__ */ new Map();
|
|
42
|
+
const directoryFor = (runId) => join(root, runId, "progress");
|
|
43
|
+
const seqKey = (runId, role) => `${runId}::${role}`;
|
|
44
|
+
const ensureSeqState = async (runId, role) => {
|
|
45
|
+
const key = seqKey(runId, role);
|
|
46
|
+
let state = seqState.get(key);
|
|
47
|
+
if (state !== void 0) return state;
|
|
48
|
+
state = { next: 1 };
|
|
49
|
+
try {
|
|
50
|
+
const entries = await readdir(directoryFor(runId));
|
|
51
|
+
let max = 0;
|
|
52
|
+
const prefix = `${role}.`;
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (!entry.startsWith(prefix) || !entry.endsWith(".txt")) continue;
|
|
55
|
+
const seqStr = entry.slice(prefix.length, entry.length - 4);
|
|
56
|
+
const n = Number(seqStr);
|
|
57
|
+
if (Number.isFinite(n) && n > max) max = n;
|
|
58
|
+
}
|
|
59
|
+
state.next = max + 1;
|
|
60
|
+
} catch {}
|
|
61
|
+
seqState.set(key, state);
|
|
62
|
+
return state;
|
|
63
|
+
};
|
|
64
|
+
const write = async (runId, rawContent, options = {}) => {
|
|
65
|
+
const role = options.role ?? "agent";
|
|
66
|
+
const sensitivity = options.sensitivity ?? defaultSensitivity;
|
|
67
|
+
const tags = options.tags ?? [];
|
|
68
|
+
const seqSource = await ensureSeqState(runId, role);
|
|
69
|
+
const seq = options.seq ?? seqSource.next;
|
|
70
|
+
seqSource.next = Math.max(seqSource.next, seq + 1);
|
|
71
|
+
const content = redact(rawContent);
|
|
72
|
+
const dir = directoryFor(runId);
|
|
73
|
+
const finalPath = join(dir, `${role}.${seqWidth(seq)}.txt`);
|
|
74
|
+
const tmpPath = `${finalPath}.tmp`;
|
|
75
|
+
try {
|
|
76
|
+
await mkdir(dir, { recursive: true });
|
|
77
|
+
await writeFile(tmpPath, content, { encoding: "utf8" });
|
|
78
|
+
await rename(tmpPath, finalPath);
|
|
79
|
+
} catch (cause) {
|
|
80
|
+
try {
|
|
81
|
+
await unlink(tmpPath);
|
|
82
|
+
} catch {}
|
|
83
|
+
throw new ProgressWriteError(finalPath, cause);
|
|
84
|
+
}
|
|
85
|
+
const stats = await stat(finalPath);
|
|
86
|
+
const sha256 = sha256Hex(content);
|
|
87
|
+
return {
|
|
88
|
+
path: finalPath,
|
|
89
|
+
role,
|
|
90
|
+
seq,
|
|
91
|
+
sizeBytes: stats.size,
|
|
92
|
+
sensitivity,
|
|
93
|
+
...tags.length > 0 ? { tags } : {},
|
|
94
|
+
writtenAtIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
95
|
+
sha256
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const read = async (currentRunId, options = {}) => {
|
|
99
|
+
const runId = options.runId ?? currentRunId;
|
|
100
|
+
const max = options.maxArtifacts ?? 100;
|
|
101
|
+
const sinceSeq = options.sinceSeq ?? 0;
|
|
102
|
+
const dir = directoryFor(runId);
|
|
103
|
+
let entries;
|
|
104
|
+
try {
|
|
105
|
+
entries = await readdir(dir);
|
|
106
|
+
} catch {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
const out = [];
|
|
110
|
+
const role = options.role;
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
if (!entry.endsWith(".txt")) continue;
|
|
113
|
+
const dot = entry.indexOf(".");
|
|
114
|
+
if (dot < 0) continue;
|
|
115
|
+
const entryRole = entry.slice(0, dot);
|
|
116
|
+
const seqStr = entry.slice(dot + 1, entry.length - 4);
|
|
117
|
+
const seq = Number(seqStr);
|
|
118
|
+
if (!Number.isFinite(seq)) continue;
|
|
119
|
+
if (role !== void 0 && entryRole !== role) continue;
|
|
120
|
+
if (seq <= sinceSeq) continue;
|
|
121
|
+
const fullPath = join(dir, entry);
|
|
122
|
+
const stats = await stat(fullPath);
|
|
123
|
+
const sha256 = sha256Hex(await readFile(fullPath, { encoding: "utf8" }));
|
|
124
|
+
out.push({
|
|
125
|
+
path: fullPath,
|
|
126
|
+
role: entryRole,
|
|
127
|
+
seq,
|
|
128
|
+
sizeBytes: stats.size,
|
|
129
|
+
sensitivity: "internal",
|
|
130
|
+
writtenAtIso: stats.mtime.toISOString(),
|
|
131
|
+
sha256
|
|
132
|
+
});
|
|
133
|
+
if (out.length >= max) break;
|
|
134
|
+
}
|
|
135
|
+
out.sort((a, b) => {
|
|
136
|
+
if (a.role !== b.role) return a.role.localeCompare(b.role);
|
|
137
|
+
return a.seq - b.seq;
|
|
138
|
+
});
|
|
139
|
+
return out;
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
write,
|
|
143
|
+
read,
|
|
144
|
+
rootFor: (runId) => directoryFor(runId)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
//#endregion
|
|
149
|
+
export { createProgressIO };
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["defaultSensitivity: Sensitivity","redact: (s: string) => string","entries: string[]","out: ProgressArtifactRef[]"],"sources":["../../src/progress/index.ts"],"sourcesContent":["/**\n * Structured progress-artifact IO. Persists UTF-8 text artifacts\n * under `<artifactRoot>/<runId>/progress/<role>.<seqPadded>.txt`\n * via atomic-write `.tmp + rename` discipline.\n *\n * Cross-session continuity flow:\n *\n * 1. The current agent calls `agent.progress.write(content)` —\n * runtime persists the file and queues the\n * `agent.progress.written` event (drained into the active or\n * next consumed stream).\n * 2. A sibling / future agent calls\n * `agent.progress.read({ runId: priorRunId })` — runtime\n * discovers existing files (no implicit auto-discovery; the\n * operator must supply the `runId` cursor).\n *\n * Auto-discovery across runs is deferred to v0.2.\n *\n * @packageDocumentation\n */\n\nimport { createHash } from 'node:crypto';\nimport { mkdir, readdir, readFile, rename, stat, unlink, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { ProgressArtifactRef, Sensitivity } from '@graphorin/core';\nimport { ProgressWriteError } from '../errors/index.js';\n\nconst DEFAULT_ARTIFACT_DIR = 'graphorin-progress';\nconst SEQ_PAD_WIDTH = 3;\n\n/**\n * Optional configuration accepted by {@link createProgressIO}.\n *\n * @stable\n */\nexport interface ProgressIOConfig {\n /** Filesystem root under which `<runId>/progress/<role>.<seq>.txt` files live. */\n readonly artifactRoot?: string;\n /** Default `Sensitivity` applied when the caller does not override. */\n readonly defaultSensitivity?: Sensitivity;\n /** Optional redaction transform applied to content before write. */\n readonly redact?: (content: string) => string;\n}\n\n/**\n * Per-call options for {@link ProgressIO.write}.\n *\n * @stable\n */\nexport interface ProgressWriteOptions {\n readonly role?: string;\n /** Explicit sequence number; default auto-increments per `(runId, role)`. */\n readonly seq?: number;\n readonly sensitivity?: Sensitivity;\n readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * Per-call options for {@link ProgressIO.read}.\n *\n * @stable\n */\nexport interface ProgressReadOptions {\n readonly runId?: string;\n readonly role?: string;\n /** Skip artifacts whose `seq <= sinceSeq`. */\n readonly sinceSeq?: number;\n /** Default `100`. */\n readonly maxArtifacts?: number;\n}\n\n/**\n * Public surface returned by {@link createProgressIO}. Used by the\n * agent runtime to back `agent.progress.write / read`.\n *\n * @stable\n */\nexport interface ProgressIO {\n write(\n runId: string,\n content: string,\n options?: ProgressWriteOptions,\n ): Promise<ProgressArtifactRef>;\n read(\n currentRunId: string,\n options?: ProgressReadOptions,\n ): Promise<ReadonlyArray<ProgressArtifactRef>>;\n rootFor(runId: string): string;\n}\n\ninterface InternalSeqState {\n next: number;\n}\n\nconst seqWidth = (n: number): string => String(n).padStart(SEQ_PAD_WIDTH, '0');\n\nconst sha256Hex = (input: string): string =>\n createHash('sha256').update(input, 'utf8').digest('hex');\n\n/**\n * Build a {@link ProgressIO} bound to a particular artifact root.\n *\n * @stable\n */\nexport function createProgressIO(config: ProgressIOConfig = {}): ProgressIO {\n const root = config.artifactRoot ?? join(tmpdir(), DEFAULT_ARTIFACT_DIR);\n const defaultSensitivity: Sensitivity = config.defaultSensitivity ?? 'internal';\n const redact: (s: string) => string = config.redact ?? ((s) => s);\n const seqState = new Map<string, InternalSeqState>();\n\n const directoryFor = (runId: string): string => join(root, runId, 'progress');\n\n const seqKey = (runId: string, role: string): string => `${runId}::${role}`;\n\n const ensureSeqState = async (runId: string, role: string): Promise<InternalSeqState> => {\n const key = seqKey(runId, role);\n let state = seqState.get(key);\n if (state !== undefined) return state;\n state = { next: 1 };\n try {\n const dir = directoryFor(runId);\n const entries = await readdir(dir);\n let max = 0;\n const prefix = `${role}.`;\n for (const entry of entries) {\n if (!entry.startsWith(prefix) || !entry.endsWith('.txt')) continue;\n const seqStr = entry.slice(prefix.length, entry.length - 4);\n const n = Number(seqStr);\n if (Number.isFinite(n) && n > max) max = n;\n }\n state.next = max + 1;\n } catch {\n // Directory does not exist yet — first write will create it.\n }\n seqState.set(key, state);\n return state;\n };\n\n const write = async (\n runId: string,\n rawContent: string,\n options: ProgressWriteOptions = {},\n ): Promise<ProgressArtifactRef> => {\n const role = options.role ?? 'agent';\n const sensitivity = options.sensitivity ?? defaultSensitivity;\n const tags = options.tags ?? [];\n const seqSource = await ensureSeqState(runId, role);\n const seq = options.seq ?? seqSource.next;\n seqSource.next = Math.max(seqSource.next, seq + 1);\n\n const content = redact(rawContent);\n const dir = directoryFor(runId);\n const filename = `${role}.${seqWidth(seq)}.txt`;\n const finalPath = join(dir, filename);\n const tmpPath = `${finalPath}.tmp`;\n\n try {\n await mkdir(dir, { recursive: true });\n await writeFile(tmpPath, content, { encoding: 'utf8' });\n await rename(tmpPath, finalPath);\n } catch (cause) {\n try {\n await unlink(tmpPath);\n } catch {\n // Best-effort cleanup; the write error is the operator-facing signal.\n }\n throw new ProgressWriteError(finalPath, cause);\n }\n\n const stats = await stat(finalPath);\n const sha256 = sha256Hex(content);\n return {\n path: finalPath,\n role,\n seq,\n sizeBytes: stats.size,\n sensitivity,\n ...(tags.length > 0 ? { tags } : {}),\n writtenAtIso: new Date().toISOString(),\n sha256,\n };\n };\n\n const read = async (\n currentRunId: string,\n options: ProgressReadOptions = {},\n ): Promise<ReadonlyArray<ProgressArtifactRef>> => {\n const runId = options.runId ?? currentRunId;\n const max = options.maxArtifacts ?? 100;\n const sinceSeq = options.sinceSeq ?? 0;\n const dir = directoryFor(runId);\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return [];\n }\n const out: ProgressArtifactRef[] = [];\n const role = options.role;\n for (const entry of entries) {\n if (!entry.endsWith('.txt')) continue;\n const dot = entry.indexOf('.');\n if (dot < 0) continue;\n const entryRole = entry.slice(0, dot);\n const seqStr = entry.slice(dot + 1, entry.length - 4);\n const seq = Number(seqStr);\n if (!Number.isFinite(seq)) continue;\n if (role !== undefined && entryRole !== role) continue;\n if (seq <= sinceSeq) continue;\n const fullPath = join(dir, entry);\n const stats = await stat(fullPath);\n const content = await readFile(fullPath, { encoding: 'utf8' });\n const sha256 = sha256Hex(content);\n out.push({\n path: fullPath,\n role: entryRole,\n seq,\n sizeBytes: stats.size,\n sensitivity: 'internal',\n writtenAtIso: stats.mtime.toISOString(),\n sha256,\n });\n if (out.length >= max) break;\n }\n out.sort((a, b) => {\n if (a.role !== b.role) return a.role.localeCompare(b.role);\n return a.seq - b.seq;\n });\n return out;\n };\n\n return {\n write,\n read,\n rootFor: (runId) => directoryFor(runId),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { CompletedToolCall, HandoffRecord, Message, RunState, RunStateUsageByModel, RunStatus, RunStep, RunTaintSummary, ToolApproval, Usage } from "@graphorin/core";
|
|
2
|
+
|
|
3
|
+
//#region src/run-state/index.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Canonical schema id for serialized {@link RunState} payloads.
|
|
7
|
+
*
|
|
8
|
+
* @stable
|
|
9
|
+
*/
|
|
10
|
+
declare const RUN_STATE_SCHEMA_VERSION: "graphorin-run-state/1.1";
|
|
11
|
+
/**
|
|
12
|
+
* Reader-supported schema id range. Major version 1 only for v0.1.
|
|
13
|
+
*
|
|
14
|
+
* @stable
|
|
15
|
+
*/
|
|
16
|
+
declare const RUN_STATE_SCHEMA_MAJOR_SUPPORTED = 1;
|
|
17
|
+
/**
|
|
18
|
+
* On-disk payload returned by {@link serializeRunState} and accepted
|
|
19
|
+
* by {@link deserializeRunState}. The shape is JSON-stable.
|
|
20
|
+
*
|
|
21
|
+
* @stable
|
|
22
|
+
*/
|
|
23
|
+
interface SerializedRunState {
|
|
24
|
+
readonly version: typeof RUN_STATE_SCHEMA_VERSION;
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly agentId: string;
|
|
27
|
+
readonly currentAgentId: string;
|
|
28
|
+
readonly sessionId: string;
|
|
29
|
+
readonly userId?: string;
|
|
30
|
+
readonly status: RunStatus;
|
|
31
|
+
readonly steps: ReadonlyArray<RunStep>;
|
|
32
|
+
readonly messages: ReadonlyArray<Message>;
|
|
33
|
+
readonly pendingApprovals: ReadonlyArray<ToolApproval>;
|
|
34
|
+
readonly handoffs: ReadonlyArray<HandoffRecord>;
|
|
35
|
+
readonly usage: Usage;
|
|
36
|
+
readonly usageByModel?: RunStateUsageByModel;
|
|
37
|
+
/** AG-19: coarse data-flow taint summary (no untrusted text). */
|
|
38
|
+
readonly taintSummary?: RunTaintSummary;
|
|
39
|
+
/** AG-19: deferred tools promoted by `tool_search` this run. */
|
|
40
|
+
readonly promotedTools?: ReadonlyArray<string>;
|
|
41
|
+
readonly startedAt: string;
|
|
42
|
+
readonly finishedAt?: string;
|
|
43
|
+
readonly error?: {
|
|
44
|
+
readonly message: string;
|
|
45
|
+
readonly code: string;
|
|
46
|
+
readonly details?: unknown;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Options accepted by {@link serializeRunState}.
|
|
51
|
+
*
|
|
52
|
+
* @stable
|
|
53
|
+
*/
|
|
54
|
+
interface SerializeRunStateOptions {
|
|
55
|
+
/**
|
|
56
|
+
* Deep-redact secret-named keys (`apiKey`, `authorization`,
|
|
57
|
+
* `bearerToken` / `accessToken` / `refreshToken`, `password`,
|
|
58
|
+
* `secret`, …) anywhere in the snapshot — tool results and messages
|
|
59
|
+
* included — replacing their values with `'[redacted]'`. Defaults to
|
|
60
|
+
* `false` for the round-trip canonical helper; the agent runtime
|
|
61
|
+
* passes `true` when persisting through the checkpoint store
|
|
62
|
+
* (AG-23). Redaction is best-effort by key name: secrets stored
|
|
63
|
+
* under unrelated keys are not detected.
|
|
64
|
+
*/
|
|
65
|
+
readonly stripTracingApiKey?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Render a JSON-stable snapshot of the supplied {@link RunState}.
|
|
69
|
+
* The returned value is plain JSON (no `Map`, `Set`, `Date`, ...).
|
|
70
|
+
*
|
|
71
|
+
* @stable
|
|
72
|
+
*/
|
|
73
|
+
declare function serializeRunState(state: RunState, options?: SerializeRunStateOptions): SerializedRunState;
|
|
74
|
+
/**
|
|
75
|
+
* Render the canonical JSON string representation of the supplied
|
|
76
|
+
* {@link RunState}. `JSON.stringify(serializeRunState(state))` —
|
|
77
|
+
* provided as a convenience.
|
|
78
|
+
*
|
|
79
|
+
* @stable
|
|
80
|
+
*/
|
|
81
|
+
declare function runStateToJSON(state: RunState, options?: SerializeRunStateOptions): string;
|
|
82
|
+
interface DeserializeOptions {
|
|
83
|
+
/**
|
|
84
|
+
* Synthesize `usageByModel` from a v0.1-alpha state that omits
|
|
85
|
+
* the field. Defaults to `true` so callers can rehydrate older
|
|
86
|
+
* states without explicit migration.
|
|
87
|
+
*/
|
|
88
|
+
readonly synthesizeUsageByModel?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Logger callback for one-time INFO messages emitted on
|
|
91
|
+
* backwards-compat synthesis. Defaults to a no-op.
|
|
92
|
+
*/
|
|
93
|
+
readonly logger?: (message: string) => void;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Rehydrate a {@link RunState} from the on-disk payload. Throws
|
|
97
|
+
* {@link RunStateVersionUnsupportedError} when the payload version
|
|
98
|
+
* is from a future major; throws
|
|
99
|
+
* {@link RunStateMalformedError} when the payload is structurally
|
|
100
|
+
* invalid.
|
|
101
|
+
*
|
|
102
|
+
* Backwards-compat: a payload that omits `usageByModel` is accepted
|
|
103
|
+
* and the field is synthesized from the aggregate `usage` with
|
|
104
|
+
* `attemptCount: 1` for the primary model.
|
|
105
|
+
*
|
|
106
|
+
* @stable
|
|
107
|
+
*/
|
|
108
|
+
declare function deserializeRunState(payload: unknown, options?: DeserializeOptions): RunState;
|
|
109
|
+
/** Convenience JSON-string parser pairing with {@link runStateToJSON}. */
|
|
110
|
+
declare function runStateFromJSON(serialized: string, options?: DeserializeOptions): RunState;
|
|
111
|
+
/**
|
|
112
|
+
* Build a fresh, minimal {@link RunState} for a new run. Helper used
|
|
113
|
+
* by `createAgent({...})` so consumers can construct deterministic
|
|
114
|
+
* run state in tests.
|
|
115
|
+
*
|
|
116
|
+
* @stable
|
|
117
|
+
*/
|
|
118
|
+
declare function createInitialRunState(args: {
|
|
119
|
+
readonly id: string;
|
|
120
|
+
readonly agentId: string;
|
|
121
|
+
readonly sessionId: string;
|
|
122
|
+
readonly userId?: string;
|
|
123
|
+
readonly startedAt?: string;
|
|
124
|
+
}): RunState;
|
|
125
|
+
/**
|
|
126
|
+
* Append a per-model usage entry to {@link RunState.usageByModel}.
|
|
127
|
+
* Mutates the supplied state in place — used by the agent runtime's
|
|
128
|
+
* per-step retry loop. Pure callers that need an immutable update
|
|
129
|
+
* should clone the state first.
|
|
130
|
+
*
|
|
131
|
+
* @stable
|
|
132
|
+
*/
|
|
133
|
+
declare function addModelUsage(state: RunState, modelId: string, delta: Usage): void;
|
|
134
|
+
/**
|
|
135
|
+
* Recompute the aggregate usage from `usageByModel`. Returns the
|
|
136
|
+
* sum that callers can compare against `state.usage` to verify the
|
|
137
|
+
* per-step retry loop maintained the documented invariant.
|
|
138
|
+
*
|
|
139
|
+
* @stable
|
|
140
|
+
*/
|
|
141
|
+
declare function aggregateUsageFromByModel(byModel: RunStateUsageByModel | undefined): Usage;
|
|
142
|
+
/**
|
|
143
|
+
* The "tools used" surface of a completed run. Cheap to compute
|
|
144
|
+
* from `RunState.steps`; surfaced as a stand-alone helper for
|
|
145
|
+
* Phase 17 example apps and operator-facing dashboards.
|
|
146
|
+
*
|
|
147
|
+
* @stable
|
|
148
|
+
*/
|
|
149
|
+
declare function completedToolCallsFromState(state: RunState): ReadonlyArray<CompletedToolCall>;
|
|
150
|
+
//#endregion
|
|
151
|
+
export { RUN_STATE_SCHEMA_MAJOR_SUPPORTED, RUN_STATE_SCHEMA_VERSION, SerializeRunStateOptions, SerializedRunState, addModelUsage, aggregateUsageFromByModel, completedToolCallsFromState, createInitialRunState, deserializeRunState, runStateFromJSON, runStateToJSON, serializeRunState };
|
|
152
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/run-state/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA4D0B,cA5Bb,wBA4Ba,EAAA,yBAAA;;;;AAe1B;AAoBA;AACS,cAzDI,gCAAA,GAyDJ,CAAA;;;;AAmFT;AAEC;AAiCD;AAoJgB,UA3TC,kBAAA,CA2T8C;EAkB/C,SAAA,OAAA,EAAA,OA5UW,wBAkVf;EAyBI,SAAA,EAAA,EAAA,MAAa;EA8Bb,SAAA,OAAA,EAAA,MAAA;EA+BA,SAAA,cAAA,EAAA,MAA2B;EAAQ,SAAA,SAAA,EAAA,MAAA;EAAyB,SAAA,MAAA,CAAA,EAAA,MAAA;EAAd,SAAA,MAAA,EAla3C,SAka2C;EAAa,SAAA,KAAA,EAjazD,aAiayD,CAja3C,OAia2C,CAAA;qBAhatD,cAAc;6BACN,cAAc;qBACtB,cAAc;kBACjB;0BACQ;;0BAEA;;2BAEC;;;;;;;;;;;;;;UAWV,wBAAA;;;;;;;;;;;;;;;;;;;iBAoBD,iBAAA,QACP,oBACE,2BACR;;;;;;;;iBAiFa,cAAA,QAAsB,oBAAoB;UAIhD,kBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+BM,mBAAA,6BAA+C,qBAA0B;;iBAoJzE,gBAAA,+BAA+C,qBAAqB;;;;;;;;iBAkBpE,qBAAA;;;;;;IAMZ;;;;;;;;;iBAyBY,aAAA,QAAqB,kCAAkC;;;;;;;;iBA8BvD,yBAAA,UAAmC,mCAAmC;;;;;;;;iBA+BtE,2BAAA,QAAmC,WAAW,cAAc"}
|