@statelyai/agent 2.0.0-alpha.20 → 2.0.0-alpha.21
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/dist/ai-sdk.cjs +89 -25
- package/dist/ai-sdk.d.cts +56 -12
- package/dist/ai-sdk.d.mts +56 -12
- package/dist/ai-sdk.mjs +89 -26
- package/dist/{decision-DhsKLYAI.cjs → decision-BnTCsuJv.cjs} +15 -3
- package/dist/{decision-BfhSgCc6.mjs → decision-JWx6n3xR.mjs} +4 -4
- package/dist/index.cjs +202 -41
- package/dist/index.d.cts +138 -18
- package/dist/index.d.mts +138 -18
- package/dist/index.mjs +202 -42
- package/dist/machines.cjs +1 -1
- package/dist/machines.d.cts +1 -1
- package/dist/machines.d.mts +1 -1
- package/dist/machines.mjs +1 -1
- package/dist/otel.d.cts +1 -1
- package/dist/otel.d.mts +1 -1
- package/dist/{run-agent-CwmzAZwj.d.mts → run-agent-DBNI8ETM.d.mts} +3 -3
- package/dist/{run-agent--4bbms-D.d.cts → run-agent-Do094mGu.d.cts} +3 -3
- package/dist/{setup-agent-gISRLxRe.cjs → setup-agent-91FSuZbB.cjs} +2 -15
- package/dist/{setup-agent-BOcSpsIq.mjs → setup-agent-DqqdcdNh.mjs} +3 -10
- package/dist/sqlite.d.cts +1 -1
- package/dist/sqlite.d.mts +1 -1
- package/dist/{text-logic-Er5KkTX6.d.mts → text-logic-BR5twXCv.d.mts} +8 -5
- package/dist/{text-logic-Cavva1W6.d.cts → text-logic-Mmbgb2jy.d.cts} +8 -5
- package/dist/{types-DYpK3QF4.d.mts → types-CvWRGFxP.d.mts} +6 -1
- package/dist/{types-pJ5Hn8fv.d.cts → types-DSdj2tGs.d.cts} +6 -1
- package/dist/validate.cjs +2 -2
- package/dist/validate.mjs +1 -1
- package/package.json +28 -28
- package/readme.md +4 -4
- package/schemas/agent-workflow.json +1 -1
|
@@ -424,7 +424,7 @@ function createBuiltinTextActor(src, mode, outputSchema) {
|
|
|
424
424
|
messages: ({ input }) => input.messages,
|
|
425
425
|
tools: ({ input }) => input.tools,
|
|
426
426
|
toolChoice: ({ input }) => input.toolChoice,
|
|
427
|
-
|
|
427
|
+
includeReasoning: ({ input }) => input.includeReasoning,
|
|
428
428
|
temperature: ({ input }) => input.temperature,
|
|
429
429
|
maxOutputTokens: ({ input }) => input.maxOutputTokens,
|
|
430
430
|
topP: ({ input }) => input.topP,
|
|
@@ -496,7 +496,7 @@ function createTextLogic(config, execute) {
|
|
|
496
496
|
tools: resolveTextLogicValue(config.tools, args),
|
|
497
497
|
toolChoice: resolveTextLogicValue(config.toolChoice, args),
|
|
498
498
|
outputSchema: schemas.output,
|
|
499
|
-
|
|
499
|
+
includeReasoning: resolveTextLogicValue(config.includeReasoning, args),
|
|
500
500
|
temperature: resolveTextLogicValue(config.temperature, args),
|
|
501
501
|
maxOutputTokens: resolveTextLogicValue(config.maxOutputTokens, args),
|
|
502
502
|
topP: resolveTextLogicValue(config.topP, args),
|
|
@@ -643,7 +643,7 @@ function buildEnvelopeSchema(inner, options = {}) {
|
|
|
643
643
|
*/
|
|
644
644
|
function parseStructuredEnvelope(request, value) {
|
|
645
645
|
if (!request.outputSchema) throw new Error("parseStructuredEnvelope: the request declares no outputSchema.");
|
|
646
|
-
return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.
|
|
646
|
+
return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.includeReasoning }), value);
|
|
647
647
|
}
|
|
648
648
|
/**
|
|
649
649
|
* Merges request-declared and call-site `tools`, dispatches to the
|
|
@@ -1048,12 +1048,24 @@ Object.defineProperty(exports, "DECIDE_ACTOR", {
|
|
|
1048
1048
|
return DECIDE_ACTOR;
|
|
1049
1049
|
}
|
|
1050
1050
|
});
|
|
1051
|
+
Object.defineProperty(exports, "GENERATE_TEXT_ACTOR", {
|
|
1052
|
+
enumerable: true,
|
|
1053
|
+
get: function() {
|
|
1054
|
+
return GENERATE_TEXT_ACTOR;
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1051
1057
|
Object.defineProperty(exports, "INTERPRET_SOURCE", {
|
|
1052
1058
|
enumerable: true,
|
|
1053
1059
|
get: function() {
|
|
1054
1060
|
return INTERPRET_SOURCE;
|
|
1055
1061
|
}
|
|
1056
1062
|
});
|
|
1063
|
+
Object.defineProperty(exports, "STREAM_TEXT_ACTOR", {
|
|
1064
|
+
enumerable: true,
|
|
1065
|
+
get: function() {
|
|
1066
|
+
return STREAM_TEXT_ACTOR;
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1057
1069
|
Object.defineProperty(exports, "USER_INPUT_ACTOR", {
|
|
1058
1070
|
enumerable: true,
|
|
1059
1071
|
get: function() {
|
|
@@ -423,7 +423,7 @@ function createBuiltinTextActor(src, mode, outputSchema) {
|
|
|
423
423
|
messages: ({ input }) => input.messages,
|
|
424
424
|
tools: ({ input }) => input.tools,
|
|
425
425
|
toolChoice: ({ input }) => input.toolChoice,
|
|
426
|
-
|
|
426
|
+
includeReasoning: ({ input }) => input.includeReasoning,
|
|
427
427
|
temperature: ({ input }) => input.temperature,
|
|
428
428
|
maxOutputTokens: ({ input }) => input.maxOutputTokens,
|
|
429
429
|
topP: ({ input }) => input.topP,
|
|
@@ -495,7 +495,7 @@ function createTextLogic(config, execute) {
|
|
|
495
495
|
tools: resolveTextLogicValue(config.tools, args),
|
|
496
496
|
toolChoice: resolveTextLogicValue(config.toolChoice, args),
|
|
497
497
|
outputSchema: schemas.output,
|
|
498
|
-
|
|
498
|
+
includeReasoning: resolveTextLogicValue(config.includeReasoning, args),
|
|
499
499
|
temperature: resolveTextLogicValue(config.temperature, args),
|
|
500
500
|
maxOutputTokens: resolveTextLogicValue(config.maxOutputTokens, args),
|
|
501
501
|
topP: resolveTextLogicValue(config.topP, args),
|
|
@@ -642,7 +642,7 @@ function buildEnvelopeSchema(inner, options = {}) {
|
|
|
642
642
|
*/
|
|
643
643
|
function parseStructuredEnvelope(request, value) {
|
|
644
644
|
if (!request.outputSchema) throw new Error("parseStructuredEnvelope: the request declares no outputSchema.");
|
|
645
|
-
return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.
|
|
645
|
+
return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.includeReasoning }), value);
|
|
646
646
|
}
|
|
647
647
|
/**
|
|
648
648
|
* Merges request-declared and call-site `tools`, dispatches to the
|
|
@@ -1029,4 +1029,4 @@ async function resolveDecision(request, executors, options = {}) {
|
|
|
1029
1029
|
throw new AgentDecisionExhaustedError(attempts);
|
|
1030
1030
|
}
|
|
1031
1031
|
//#endregion
|
|
1032
|
-
export {
|
|
1032
|
+
export { getMachineStaticTransitionTargets as A, getJsonSchema as B, parseModelRef as C, agentExecutionOptions as D, userInputActor as E, missingActor as F, resolveMachineVersion as G, getMachineStructuralHash as H, assistantMessage as I, userMessage as J, systemMessage as K, djb2Hex as L, isUnboundPlaceholder as M, machineIdlePredicates as N, executorBoundLogics as O, machineStaticTransitionTargets as P, findNonSerializableContextPaths as R, normalizeGeneratorResult as S, parseStructuredEnvelope as T, getStateMeta as U, getJsonSchemaSync as V, isStandardSchema as W, validateSchemaSync as Y, createTextLogic as _, resolveDecision as a, getCallUsage as b, AGENT_USAGE_TOKEN_FIELDS as c, INTERPRET_SOURCE as d, STREAM_TEXT_ACTOR as f, builtinTextActors as g, buildEnvelopeSchema as h, renderDecisionAttempts as i, getRegisteredAgentExecutionOptions as j, getMachineIdlePredicate as k, DECIDE_ACTOR as l, bindRequestExecutor as m, createDecideActor as n, getAcceptedEvents as o, USER_INPUT_ACTOR as p, toolMessage as q, isDecisionLogic as r, parseAgentEvent as s, AgentDecisionExhaustedError as t, GENERATE_TEXT_ACTOR as u, executeAgentTextRequest as v, parseOutput as w, isTextLogic as x, getAgentOutputMode as y, getAgentMessages as z };
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_errors = require("./errors-DUBBzRLP.cjs");
|
|
3
|
-
const require_setup_agent = require("./setup-agent-
|
|
4
|
-
const require_decision = require("./decision-
|
|
3
|
+
const require_setup_agent = require("./setup-agent-91FSuZbB.cjs");
|
|
4
|
+
const require_decision = require("./decision-BnTCsuJv.cjs");
|
|
5
5
|
const require_event_log_store = require("./event-log-store-a_TKy1gk.cjs");
|
|
6
6
|
require("./validate.cjs");
|
|
7
7
|
let xstate = require("xstate");
|
|
@@ -570,9 +570,13 @@ function invokingActorOf(self, runCtx) {
|
|
|
570
570
|
* identical event shapes by construction. @internal
|
|
571
571
|
*/
|
|
572
572
|
function bindTextLogic(logic, runCtx) {
|
|
573
|
-
return logic.withExecutor(async ({ request, self: selfArg, signal }) => {
|
|
573
|
+
return logic.withExecutor(async ({ request: rawRequest, self: selfArg, signal }) => {
|
|
574
574
|
const self = selfArg;
|
|
575
575
|
const { id, src } = selfIdAndSrc(self);
|
|
576
|
+
const request = rawRequest.name === void 0 && src !== "" && src !== "agent.generateText" && src !== "agent.streamText" ? {
|
|
577
|
+
...rawRequest,
|
|
578
|
+
name: src
|
|
579
|
+
} : rawRequest;
|
|
576
580
|
const executor = logic.mode === "stream" ? runCtx.streamText : runCtx.generateText;
|
|
577
581
|
if (!executor) throw new Error(`No '${logic.mode === "stream" ? "streamText" : "generateText"}' executor provided.`);
|
|
578
582
|
const requestWithTools = {
|
|
@@ -2086,8 +2090,8 @@ function lintAgentMachine(machine, options = {}) {
|
|
|
2086
2090
|
return diagnostics;
|
|
2087
2091
|
}
|
|
2088
2092
|
/**
|
|
2089
|
-
* Thrown by `lintAgentMachine(machine, { throw: true })`
|
|
2090
|
-
* failing diagnostics.
|
|
2093
|
+
* Thrown by `lintAgentMachine(machine, { throw: true })` (and its
|
|
2094
|
+
* {@link assertAgentMachine} alias) when lint finds failing diagnostics.
|
|
2091
2095
|
* `diagnostics` holds the findings; the message lists them one per finding,
|
|
2092
2096
|
* so a test runner's failure output reads like the CLI's lint report.
|
|
2093
2097
|
*/
|
|
@@ -2100,6 +2104,26 @@ var AgentLintError = class extends require_errors.AgentError {
|
|
|
2100
2104
|
this.diagnostics = diagnostics;
|
|
2101
2105
|
}
|
|
2102
2106
|
};
|
|
2107
|
+
/**
|
|
2108
|
+
* Asserts a machine passes {@link lintAgentMachine}: returns silently when
|
|
2109
|
+
* clean, throws {@link AgentLintError} (with the findings on `.diagnostics`)
|
|
2110
|
+
* otherwise — sugar for `lintAgentMachine(machine, { ...options, throw: true })`.
|
|
2111
|
+
* Fails on error-severity findings; set `warnings: true` to fail on warnings
|
|
2112
|
+
* too. The one-liner for tests and generation loops:
|
|
2113
|
+
*
|
|
2114
|
+
* @example
|
|
2115
|
+
* ```ts
|
|
2116
|
+
* test('agent machine is structurally sound', () => {
|
|
2117
|
+
* assertAgentMachine(machine);
|
|
2118
|
+
* });
|
|
2119
|
+
* ```
|
|
2120
|
+
*/
|
|
2121
|
+
function assertAgentMachine(machine, options = {}) {
|
|
2122
|
+
lintAgentMachine(machine, {
|
|
2123
|
+
...options,
|
|
2124
|
+
throw: true
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2103
2127
|
function pendingInvokes(step) {
|
|
2104
2128
|
const out = [];
|
|
2105
2129
|
for (const action of step.actions) {
|
|
@@ -2126,6 +2150,21 @@ function takeFromQueue(channel, src) {
|
|
|
2126
2150
|
* the real transition logic. Returns the terminal `status`, final `snapshot`,
|
|
2127
2151
|
* and a `trail` of every step taken.
|
|
2128
2152
|
*
|
|
2153
|
+
* Decisions run through the live run's own validation/retry core,
|
|
2154
|
+
* {@link resolveDecision}, with the script standing in for the model: each
|
|
2155
|
+
* attempt consumes the next queued {@link ChosenEvent} for that src, so an
|
|
2156
|
+
* unknown, payload-invalid, or guard-rejected event is NOT silently swallowed
|
|
2157
|
+
* — the next queued decision is tried, exactly as a live run re-asks the
|
|
2158
|
+
* model. The decision logic's `maxRetries` caps attempts as it would live;
|
|
2159
|
+
* when retries continue past the end of the queue, the last queued decision
|
|
2160
|
+
* repeats (a scripted model that insists). The repeat applies only within one
|
|
2161
|
+
* decision request's retries — each new decision request must have its own
|
|
2162
|
+
* queued entry, or the dry-script error throws as usual. Exhausting all
|
|
2163
|
+
* attempts delivers
|
|
2164
|
+
* the resulting {@link AgentDecisionExhaustedError} to the machine as the
|
|
2165
|
+
* decision invoke's error (so an `onError` transition observes it, as it
|
|
2166
|
+
* would live); with no `onError` to catch it, it is thrown.
|
|
2167
|
+
*
|
|
2129
2168
|
* Throws a descriptive error when the script runs dry mid-request, naming the
|
|
2130
2169
|
* pending request's kind, src, and id so the missing scripted response is
|
|
2131
2170
|
* obvious.
|
|
@@ -2134,7 +2173,10 @@ function takeFromQueue(channel, src) {
|
|
|
2134
2173
|
* ```ts
|
|
2135
2174
|
* const { status, snapshot } = simulateAgent(machine, {
|
|
2136
2175
|
* input: { topic: 'state machines' },
|
|
2137
|
-
* script: {
|
|
2176
|
+
* script: {
|
|
2177
|
+
* decisions: { 'agent.decide': [{ type: 'ESCALATE' }] },
|
|
2178
|
+
* events: [{ type: 'APPROVE' }], // crosses the human gate
|
|
2179
|
+
* },
|
|
2138
2180
|
* });
|
|
2139
2181
|
* ```
|
|
2140
2182
|
*/
|
|
@@ -2143,11 +2185,12 @@ async function simulateAgent(machine, options) {
|
|
|
2143
2185
|
const script = {
|
|
2144
2186
|
text: mapValues(options.script.text ?? {}, (arr) => [...arr]),
|
|
2145
2187
|
decisions: mapValues(options.script.decisions ?? {}, (arr) => [...arr]),
|
|
2146
|
-
invokes: mapValues(options.script.invokes ?? {}, (arr) => [...arr])
|
|
2188
|
+
invokes: mapValues(options.script.invokes ?? {}, (arr) => [...arr]),
|
|
2189
|
+
events: [...options.script.events ?? []]
|
|
2147
2190
|
};
|
|
2148
2191
|
if (options.script.userInput?.length) script.invokes[USER_INPUT_SRC] = [...options.script.userInput, ...script.invokes[USER_INPUT_SRC] ?? []];
|
|
2149
2192
|
let step = require_setup_agent.initialAgentStep(machine, options.input);
|
|
2150
|
-
const trail = [];
|
|
2193
|
+
const trail = [{ state: step.snapshot.value }];
|
|
2151
2194
|
for (let i = 0; i < maxSteps; i++) {
|
|
2152
2195
|
if (step.done) return {
|
|
2153
2196
|
status: "done",
|
|
@@ -2157,14 +2200,10 @@ async function simulateAgent(machine, options) {
|
|
|
2157
2200
|
const request = step.requests[0];
|
|
2158
2201
|
if (request) {
|
|
2159
2202
|
if (request.kind === "decision") {
|
|
2160
|
-
const
|
|
2161
|
-
const
|
|
2162
|
-
|
|
2163
|
-
step =
|
|
2164
|
-
trail.push({
|
|
2165
|
-
state: step.snapshot.value,
|
|
2166
|
-
appliedEvent: taken.value
|
|
2167
|
-
});
|
|
2203
|
+
const invokeMeta = findInvokeMetadata(step, request.id);
|
|
2204
|
+
const src = invokeMeta?.src ?? request.id;
|
|
2205
|
+
const decisionSrc = src in (script.decisions ?? {}) ? src : request.id in (script.decisions ?? {}) ? request.id : src;
|
|
2206
|
+
step = await applyScriptedDecision(machine, step, request, decisionSrc, invokeMeta?.logic, script, trail);
|
|
2168
2207
|
continue;
|
|
2169
2208
|
}
|
|
2170
2209
|
const taken = takeFromQueue(script.text, request.src);
|
|
@@ -2195,6 +2234,18 @@ async function simulateAgent(machine, options) {
|
|
|
2195
2234
|
});
|
|
2196
2235
|
continue;
|
|
2197
2236
|
}
|
|
2237
|
+
const external = script.events;
|
|
2238
|
+
if (external.length > 0) {
|
|
2239
|
+
const event = external.shift();
|
|
2240
|
+
if (!step.snapshot.can(event)) throw new Error(`simulateAgent: scripted external event '${event.type}' cannot be taken in state ${JSON.stringify(step.snapshot.value)} (no handler, or its guard rejected it). A live run's send would be silently dropped here; fix the script's \`events\` queue.`);
|
|
2241
|
+
step = require_setup_agent.transitionAgentStep(machine, step, event);
|
|
2242
|
+
trail.push({
|
|
2243
|
+
state: step.snapshot.value,
|
|
2244
|
+
appliedEvent: event,
|
|
2245
|
+
external: true
|
|
2246
|
+
});
|
|
2247
|
+
continue;
|
|
2248
|
+
}
|
|
2198
2249
|
return {
|
|
2199
2250
|
status: "idle",
|
|
2200
2251
|
snapshot: step.snapshot,
|
|
@@ -2207,6 +2258,66 @@ async function simulateAgent(machine, options) {
|
|
|
2207
2258
|
trail
|
|
2208
2259
|
};
|
|
2209
2260
|
}
|
|
2261
|
+
async function applyScriptedDecision(machine, step, request, decisionSrc, invokeLogic, script, trail) {
|
|
2262
|
+
const dequeued = [];
|
|
2263
|
+
const decide = async () => {
|
|
2264
|
+
const taken = takeFromQueue(script.decisions, decisionSrc);
|
|
2265
|
+
if (taken.found) {
|
|
2266
|
+
dequeued.push(taken.value);
|
|
2267
|
+
return { event: taken.value };
|
|
2268
|
+
}
|
|
2269
|
+
if (dequeued.length === 0) throw scriptDryError("decision", decisionSrc, request.id, request);
|
|
2270
|
+
return { event: dequeued[dequeued.length - 1] };
|
|
2271
|
+
};
|
|
2272
|
+
const maxRetries = (require_decision.isDecisionLogic(invokeLogic) ? invokeLogic : resolveRegisteredDecisionLogic(machine, decisionSrc))?.maxRetries;
|
|
2273
|
+
let chosen;
|
|
2274
|
+
try {
|
|
2275
|
+
chosen = await require_decision.resolveDecision(request, { decide }, {
|
|
2276
|
+
maxRetries,
|
|
2277
|
+
canTake: (event) => step.snapshot.can(event)
|
|
2278
|
+
});
|
|
2279
|
+
} catch (error) {
|
|
2280
|
+
if (!(error instanceof require_decision.AgentDecisionExhaustedError)) throw error;
|
|
2281
|
+
const next = require_setup_agent.transitionAgentStep(machine, step, {
|
|
2282
|
+
type: "xstate.error.actor",
|
|
2283
|
+
actorId: request.id,
|
|
2284
|
+
...sessionIdOf(step.snapshot, request.id),
|
|
2285
|
+
error
|
|
2286
|
+
});
|
|
2287
|
+
if (next.snapshot.status === "error") throw error;
|
|
2288
|
+
trail.push({
|
|
2289
|
+
state: next.snapshot.value,
|
|
2290
|
+
rejectedEvents: dequeued
|
|
2291
|
+
});
|
|
2292
|
+
return next;
|
|
2293
|
+
}
|
|
2294
|
+
const next = require_setup_agent.transitionAgentStep(machine, step, chosen);
|
|
2295
|
+
const rejected = dequeued.slice(0, -1);
|
|
2296
|
+
trail.push({
|
|
2297
|
+
state: next.snapshot.value,
|
|
2298
|
+
appliedEvent: chosen,
|
|
2299
|
+
...rejected.length > 0 ? { rejectedEvents: rejected } : {}
|
|
2300
|
+
});
|
|
2301
|
+
return next;
|
|
2302
|
+
}
|
|
2303
|
+
function findInvokeMetadata(step, id) {
|
|
2304
|
+
for (const action of step.actions) {
|
|
2305
|
+
const metadata = require_setup_agent.getInvokeEffectMetadata(action);
|
|
2306
|
+
if (metadata?.id !== id) continue;
|
|
2307
|
+
return {
|
|
2308
|
+
...typeof metadata.src === "string" ? { src: metadata.src } : {},
|
|
2309
|
+
logic: metadata.logic ?? (typeof metadata.src === "object" ? metadata.src : void 0)
|
|
2310
|
+
};
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
function resolveRegisteredDecisionLogic(machine, src) {
|
|
2314
|
+
const candidate = require_decision.getRegisteredAgentExecutionOptions(machine).actors?.[src] ?? machine.sources?.actors?.[src];
|
|
2315
|
+
return require_decision.isDecisionLogic(candidate) ? candidate : void 0;
|
|
2316
|
+
}
|
|
2317
|
+
function sessionIdOf(snapshot, id) {
|
|
2318
|
+
const child = snapshot.children[id];
|
|
2319
|
+
return typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {};
|
|
2320
|
+
}
|
|
2210
2321
|
function mapValues(obj, fn) {
|
|
2211
2322
|
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value)]));
|
|
2212
2323
|
}
|
|
@@ -2243,6 +2354,10 @@ async function explore(machine, options, stopWhen) {
|
|
|
2243
2354
|
const advance = (step) => {
|
|
2244
2355
|
let current = step;
|
|
2245
2356
|
for (let i = 0; i < MAX_ADVANCE_STEPS; i++) {
|
|
2357
|
+
if (stopWhen?.(current.snapshot)) return {
|
|
2358
|
+
step: current,
|
|
2359
|
+
hit: true
|
|
2360
|
+
};
|
|
2246
2361
|
if (current.done) return { step: current };
|
|
2247
2362
|
const request = current.requests[0];
|
|
2248
2363
|
if (request && request.kind === "text") {
|
|
@@ -2275,8 +2390,8 @@ async function explore(machine, options, stopWhen) {
|
|
|
2275
2390
|
hitPathCap = true;
|
|
2276
2391
|
return;
|
|
2277
2392
|
}
|
|
2278
|
-
const { step: settled, blockedSrc } = advance(step);
|
|
2279
|
-
if (
|
|
2393
|
+
const { step: settled, blockedSrc, hit } = advance(step);
|
|
2394
|
+
if (hit) {
|
|
2280
2395
|
witness = path;
|
|
2281
2396
|
return;
|
|
2282
2397
|
}
|
|
@@ -2371,8 +2486,11 @@ async function explorePaths(machine, options = {}) {
|
|
|
2371
2486
|
return (await explore(machine, options)).report;
|
|
2372
2487
|
}
|
|
2373
2488
|
/**
|
|
2374
|
-
* Answers "can the machine reach
|
|
2375
|
-
*
|
|
2489
|
+
* Answers "can the machine reach this?" by exploring its branches (a thin
|
|
2490
|
+
* wrapper over {@link explorePaths}). The target is either a state path string
|
|
2491
|
+
* (`snapshot.matches(...)` semantics) or a snapshot predicate — the predicate
|
|
2492
|
+
* form checks any property (a context invariant, a tag, a state+context
|
|
2493
|
+
* combination) without reifying a sentinel state for it. Returns
|
|
2376
2494
|
* `{ reachable: true, witness }` with the event sequence that reaches it, or
|
|
2377
2495
|
* `{ reachable: false }`.
|
|
2378
2496
|
*
|
|
@@ -2381,11 +2499,21 @@ async function explorePaths(machine, options = {}) {
|
|
|
2381
2499
|
* const { reachable, witness } = await canReach(refundMachine, 'denied', { input: { request: 'x', amount: 5000 } });
|
|
2382
2500
|
* // reachable → true; witness → [{ type: 'NEEDS_REVIEW' }, { type: 'DENY' }]
|
|
2383
2501
|
* ```
|
|
2502
|
+
*
|
|
2503
|
+
* @example Predicate target — a violation property, no sentinel state needed
|
|
2504
|
+
* ```ts
|
|
2505
|
+
* const violation = await canReach(
|
|
2506
|
+
* refundMachine,
|
|
2507
|
+
* (snapshot) => snapshot.matches('issued') && !snapshot.context.approved,
|
|
2508
|
+
* { input: { amount: 5000 } },
|
|
2509
|
+
* );
|
|
2510
|
+
* // violation.reachable → false is the safety proof
|
|
2511
|
+
* ```
|
|
2384
2512
|
*/
|
|
2385
|
-
async function canReach(machine,
|
|
2386
|
-
const { witness } = await explore(machine, options, (snapshot) => {
|
|
2513
|
+
async function canReach(machine, target, options = {}) {
|
|
2514
|
+
const { witness } = await explore(machine, options, typeof target === "function" ? target : (snapshot) => {
|
|
2387
2515
|
try {
|
|
2388
|
-
return snapshot.matches(
|
|
2516
|
+
return snapshot.matches(target);
|
|
2389
2517
|
} catch {
|
|
2390
2518
|
return false;
|
|
2391
2519
|
}
|
|
@@ -2717,6 +2845,8 @@ async function runSeam(machine, options) {
|
|
|
2717
2845
|
let calls = 0;
|
|
2718
2846
|
let seamMatches = 0;
|
|
2719
2847
|
let seamOutput;
|
|
2848
|
+
let seamUsage;
|
|
2849
|
+
const callLog = [];
|
|
2720
2850
|
let seamReached = false;
|
|
2721
2851
|
let callsBeforeSeam = -1;
|
|
2722
2852
|
let seamStateAt = 0;
|
|
@@ -2741,6 +2871,15 @@ async function runSeam(machine, options) {
|
|
|
2741
2871
|
const route = async (request, info) => {
|
|
2742
2872
|
const callIndex = calls++;
|
|
2743
2873
|
const isSeam = request.name === seam.request && seamMatches++ === (seam.occurrence ?? 0);
|
|
2874
|
+
const ledger = (source) => {
|
|
2875
|
+
callLog.push({
|
|
2876
|
+
...request.name !== void 0 ? { name: request.name } : {},
|
|
2877
|
+
model: request.model,
|
|
2878
|
+
key: queueKeyOf(request),
|
|
2879
|
+
source,
|
|
2880
|
+
seam: isSeam
|
|
2881
|
+
});
|
|
2882
|
+
};
|
|
2744
2883
|
if (isSeam && candidate) {
|
|
2745
2884
|
await takeScriptedSlot(request, info);
|
|
2746
2885
|
seamReached = true;
|
|
@@ -2749,15 +2888,19 @@ async function runSeam(machine, options) {
|
|
|
2749
2888
|
seamEventAt = liveEvents;
|
|
2750
2889
|
const result = await candidate(request, info);
|
|
2751
2890
|
seamOutput = await seamOutputOf(result, request);
|
|
2891
|
+
seamUsage = require_decision.getCallUsage(result);
|
|
2892
|
+
ledger("candidate");
|
|
2752
2893
|
return result;
|
|
2753
2894
|
}
|
|
2754
2895
|
const scripted = await scriptedAnswer(request, info);
|
|
2896
|
+
ledger("script");
|
|
2755
2897
|
if (!isSeam) return scripted;
|
|
2756
2898
|
seamReached = true;
|
|
2757
2899
|
callsBeforeSeam = callIndex;
|
|
2758
2900
|
seamStateAt = statePath.length;
|
|
2759
2901
|
seamEventAt = liveEvents;
|
|
2760
2902
|
seamOutput = scripted.output;
|
|
2903
|
+
seamUsage = scripted.usage;
|
|
2761
2904
|
return scripted;
|
|
2762
2905
|
};
|
|
2763
2906
|
const executors = {
|
|
@@ -2819,7 +2962,9 @@ async function runSeam(machine, options) {
|
|
|
2819
2962
|
return {
|
|
2820
2963
|
result,
|
|
2821
2964
|
seamOutput,
|
|
2965
|
+
...seamUsage !== void 0 ? { seamUsage } : {},
|
|
2822
2966
|
callsBeforeSeam,
|
|
2967
|
+
calls: callLog,
|
|
2823
2968
|
before: {
|
|
2824
2969
|
statePath: statePath.slice(0, splitStateAt),
|
|
2825
2970
|
events: events.slice(0, splitAt)
|
|
@@ -2854,6 +2999,8 @@ function completionActorId(event) {
|
|
|
2854
2999
|
const actorId = event.actorId;
|
|
2855
3000
|
return typeof actorId === "string" ? actorId : void 0;
|
|
2856
3001
|
}
|
|
3002
|
+
/** Thrown by the adapter's `waitForEvent` when nothing can produce an event. */
|
|
3003
|
+
const IDLE = Symbol("agent.durable.idle");
|
|
2857
3004
|
function createMailbox() {
|
|
2858
3005
|
const queue = [];
|
|
2859
3006
|
const waiters = [];
|
|
@@ -2919,6 +3066,8 @@ async function runDurableAgent(machine, options = {}) {
|
|
|
2919
3066
|
const actorId = completionActorId(event);
|
|
2920
3067
|
if (actorId !== void 0) journaledCompletions.set(actorId, (journaledCompletions.get(actorId) ?? 0) + 1);
|
|
2921
3068
|
}
|
|
3069
|
+
const storedExecutionId = hasInit ? priorEntries[0].metadata?.executionId : void 0;
|
|
3070
|
+
const executionId = typeof storedExecutionId === "string" ? storedExecutionId : hasInit ? priorEntries[0].id : crypto.randomUUID();
|
|
2922
3071
|
const mailbox = createMailbox();
|
|
2923
3072
|
const rootAddress = machineId;
|
|
2924
3073
|
const suppressedChildren = /* @__PURE__ */ new WeakSet();
|
|
@@ -2933,7 +3082,10 @@ async function runDurableAgent(machine, options = {}) {
|
|
|
2933
3082
|
}
|
|
2934
3083
|
};
|
|
2935
3084
|
let replaying = journal.length > 0;
|
|
3085
|
+
let liveEventConsumed = false;
|
|
3086
|
+
let latestSnapshot;
|
|
2936
3087
|
const execution = (0, xstate_durable.createDurable)(bound, {
|
|
3088
|
+
executionId,
|
|
2937
3089
|
sendEvent(source, target, event) {
|
|
2938
3090
|
if (target.address === rootAddress) {
|
|
2939
3091
|
mailbox.push(event);
|
|
@@ -2963,8 +3115,14 @@ async function runDurableAgent(machine, options = {}) {
|
|
|
2963
3115
|
if (replaying) return;
|
|
2964
3116
|
action.exec?.();
|
|
2965
3117
|
},
|
|
2966
|
-
waitForEvent() {
|
|
2967
|
-
return mailbox.take();
|
|
3118
|
+
async waitForEvent() {
|
|
3119
|
+
if (mailbox.size() > 0) return await mailbox.take();
|
|
3120
|
+
if (liveInFlight.size > 0 && !(options.isIdle?.(latestSnapshot) ?? false)) return await mailbox.take();
|
|
3121
|
+
if (!liveEventConsumed && options.event !== void 0) {
|
|
3122
|
+
liveEventConsumed = true;
|
|
3123
|
+
return options.event;
|
|
3124
|
+
}
|
|
3125
|
+
throw IDLE;
|
|
2968
3126
|
}
|
|
2969
3127
|
});
|
|
2970
3128
|
const entries = [...priorEntries];
|
|
@@ -2978,17 +3136,18 @@ async function runDurableAgent(machine, options = {}) {
|
|
|
2978
3136
|
options.onEntry?.(entry);
|
|
2979
3137
|
};
|
|
2980
3138
|
if (!hasInit) {
|
|
2981
|
-
const entry = require_setup_agent.initEntry(machine, input,
|
|
3139
|
+
const entry = require_setup_agent.initEntry(machine, input, {
|
|
3140
|
+
...entryOptions,
|
|
3141
|
+
metadata: { executionId }
|
|
3142
|
+
});
|
|
2982
3143
|
entries.push(entry);
|
|
2983
3144
|
options.onEntry?.(entry);
|
|
2984
3145
|
}
|
|
2985
|
-
const sessions = /* @__PURE__ */ new Map();
|
|
2986
3146
|
let journalIndex = 0;
|
|
2987
|
-
let liveEventConsumed = false;
|
|
2988
3147
|
let [snapshot, effects] = execution.initialTransition(input);
|
|
3148
|
+
latestSnapshot = snapshot;
|
|
2989
3149
|
for (;;) {
|
|
2990
|
-
|
|
2991
|
-
for (const rootEvent of captured) mailbox.push(rootEvent.event);
|
|
3150
|
+
await execution.executeEffects(effects);
|
|
2992
3151
|
const machineSnapshot = snapshot;
|
|
2993
3152
|
if (machineSnapshot.status === "done") return {
|
|
2994
3153
|
status: "done",
|
|
@@ -3000,24 +3159,25 @@ async function runDurableAgent(machine, options = {}) {
|
|
|
3000
3159
|
let event;
|
|
3001
3160
|
let fromJournal = false;
|
|
3002
3161
|
if (journalIndex < journal.length) {
|
|
3003
|
-
event =
|
|
3162
|
+
event = journal[journalIndex];
|
|
3004
3163
|
journalIndex++;
|
|
3005
3164
|
fromJournal = true;
|
|
3006
3165
|
replaying = journalIndex < journal.length;
|
|
3007
|
-
} else
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
}
|
|
3166
|
+
} else try {
|
|
3167
|
+
event = await execution.waitForEvent();
|
|
3168
|
+
} catch (error) {
|
|
3169
|
+
if (error === IDLE) return {
|
|
3170
|
+
status: "idle",
|
|
3171
|
+
snapshot,
|
|
3172
|
+
entries
|
|
3173
|
+
};
|
|
3174
|
+
throw error;
|
|
3175
|
+
}
|
|
3017
3176
|
const completedId = completionActorId(event);
|
|
3018
3177
|
if (completedId !== void 0) liveInFlight.delete(completedId);
|
|
3019
3178
|
if (!fromJournal) appendEntry(event);
|
|
3020
3179
|
[snapshot, effects] = execution.transition(snapshot, event);
|
|
3180
|
+
latestSnapshot = snapshot;
|
|
3021
3181
|
}
|
|
3022
3182
|
}
|
|
3023
3183
|
//#endregion
|
|
@@ -3038,6 +3198,7 @@ exports.AgentSnapshotVersionMismatchError = AgentSnapshotVersionMismatchError;
|
|
|
3038
3198
|
exports.NonSerializableAgentEventError = require_event_log_store.NonSerializableAgentEventError;
|
|
3039
3199
|
exports.appendMessages = require_setup_agent.appendMessages;
|
|
3040
3200
|
exports.assertAgentLogEntry = require_event_log_store.assertAgentLogEntry;
|
|
3201
|
+
exports.assertAgentMachine = assertAgentMachine;
|
|
3041
3202
|
exports.assertEventLogStoreConformance = require_event_log_store.assertEventLogStoreConformance;
|
|
3042
3203
|
exports.assertJsonSerializable = require_event_log_store.assertJsonSerializable;
|
|
3043
3204
|
exports.assistantMessage = require_decision.assistantMessage;
|