@agent-native/core 0.53.0 → 0.54.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/dist/action.d.ts +40 -1
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +69 -2
- package/dist/action.js.map +1 -1
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +1 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/observational-memory/index.d.ts +6 -6
- package/dist/agent/observational-memory/index.js +6 -6
- package/dist/agent/observational-memory/index.js.map +1 -1
- package/dist/agent/observational-memory/read.d.ts +7 -9
- package/dist/agent/observational-memory/read.d.ts.map +1 -1
- package/dist/agent/observational-memory/read.js +7 -9
- package/dist/agent/observational-memory/read.js.map +1 -1
- package/dist/agent/processors.d.ts +146 -0
- package/dist/agent/processors.d.ts.map +1 -0
- package/dist/agent/processors.js +122 -0
- package/dist/agent/processors.js.map +1 -0
- package/dist/agent/production-agent.d.ts +10 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +101 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +4 -5
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/tool-call-journal.d.ts +6 -8
- package/dist/agent/tool-call-journal.d.ts.map +1 -1
- package/dist/agent/tool-call-journal.js +6 -8
- package/dist/agent/tool-call-journal.js.map +1 -1
- package/dist/agent/types.d.ts +11 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +129 -4
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +38 -3
- package/dist/cli/skills.js.map +1 -1
- package/dist/coding-tools/run-code.d.ts.map +1 -1
- package/dist/coding-tools/run-code.js +18 -2
- package/dist/coding-tools/run-code.js.map +1 -1
- package/dist/extensions/fetch-tool.d.ts.map +1 -1
- package/dist/extensions/fetch-tool.js +80 -15
- package/dist/extensions/fetch-tool.js.map +1 -1
- package/dist/extensions/web-content.d.ts +61 -0
- package/dist/extensions/web-content.d.ts.map +1 -0
- package/dist/extensions/web-content.js +468 -0
- package/dist/extensions/web-content.js.map +1 -0
- package/dist/extensions/web-search-tool.js +3 -3
- package/dist/extensions/web-search-tool.js.map +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +4 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +80 -0
- package/dist/provider-api/corpus-jobs.d.ts.map +1 -1
- package/dist/provider-api/corpus-jobs.js +219 -22
- package/dist/provider-api/corpus-jobs.js.map +1 -1
- package/dist/provider-api/index.d.ts +24 -32
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +28 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/server/agent-chat-plugin.js +1 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +7 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +90 -0
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/deep-link.d.ts +7 -0
- package/dist/server/deep-link.d.ts.map +1 -1
- package/dist/server/deep-link.js +13 -2
- package/dist/server/deep-link.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/templates/default/.agents/skills/actions/SKILL.md +52 -1
- package/dist/templates/default/.agents/skills/security/SKILL.md +22 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +52 -1
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -4
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +11 -0
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +22 -0
- package/docs/content/actions.md +50 -0
- package/docs/content/durable-resume.md +49 -0
- package/docs/content/external-agents.md +2 -2
- package/docs/content/human-approval.md +101 -0
- package/docs/content/observability.md +21 -0
- package/docs/content/observational-memory.md +63 -0
- package/docs/content/plan-plugin.md +5 -0
- package/docs/content/pr-visual-recap.md +4 -3
- package/docs/content/processors.md +99 -0
- package/docs/content/template-plan.md +78 -14
- package/package.json +6 -1
- package/src/templates/default/.agents/skills/actions/SKILL.md +52 -1
- package/src/templates/default/.agents/skills/security/SKILL.md +22 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +52 -1
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -4
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +11 -0
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +22 -0
|
@@ -17,16 +17,14 @@ function sumTokens(entries) {
|
|
|
17
17
|
return entries.reduce((acc, entry) => acc + (entry.tokenEstimate || 0), 0);
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* prompt assembly.
|
|
20
|
+
* Build the three-tier Observational Memory context for a thread. The returned
|
|
21
|
+
* tiers are ready to be injected into the turn's prompt assembly.
|
|
23
22
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* section. This module deliberately does not edit production-agent.ts.
|
|
23
|
+
* This is consumed by the agent loop (`production-agent.ts`): when a thread has
|
|
24
|
+
* persisted observations/reflections, the older raw-message prefix (everything
|
|
25
|
+
* before `recentMessages`) is replaced with the `reflections` + `observations`
|
|
26
|
+
* text, `recentMessages` is kept verbatim, and a short "Observational Memory"
|
|
27
|
+
* block is prepended. Threads with no OM entries are left unchanged.
|
|
30
28
|
*/
|
|
31
29
|
/** True when this thread has at least one persisted observation or reflection. */
|
|
32
30
|
export function hasObservationalMemory(context) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/agent/observational-memory/read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EACL,gCAAgC,GAEjC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AActD,SAAS,SAAS,CAAC,OAAmC;IACpD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/agent/observational-memory/read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EACL,gCAAgC,GAEjC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AActD,SAAS,SAAS,CAAC,OAAmC;IACpD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;GASG;AACH,kFAAkF;AAClF,MAAM,UAAU,sBAAsB,CAAC,OAA6B;IAClE,OAAO,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iCAAiC,CAC/C,OAA6B;IAE7B,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAChD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,QAAQ,CAAC,IAAI,CACX,6EAA6E;QAC3E,2EAA2E;QAC3E,oEAAoE;QACpE,sEAAsE;QACtE,iEAAiE,CACpE,CAAC;IACF,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CACX,kCAAkC;YAChC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAC9D,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,QAAQ,CAAC,IAAI,CACX,kCAAkC;YAChC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAyC;IAEzC,MAAM,MAAM,GAAG,gCAAgC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,KAAK,GAA6B;QACtC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI;KAC7B,CAAC;IAEF,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpD,uBAAuB,CAAC;YACtB,GAAG,KAAK;YACR,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,IAAI,EAAE,YAAY;SACnB,CAAC;QACF,uBAAuB,CAAC;YACtB,GAAG,KAAK;YACR,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,IAAI,EAAE,aAAa;SACpB,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAC9D,MAAM,cAAc,GAClB,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9D,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAC7D,MAAM,gBAAgB,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IAChD,MAAM,iBAAiB,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC;IAElD,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,WAAW;QACX,YAAY;QACZ,cAAc;QACd,MAAM,EAAE;YACN,WAAW,EAAE,gBAAgB;YAC7B,YAAY,EAAE,iBAAiB;YAC/B,cAAc,EAAE,YAAY;YAC5B,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,YAAY;SAC3D;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Read API for Observational Memory.\n *\n * `buildObservationalContext` assembles the three tiers — reflections (highest\n * level) + observations (dense) + the recent raw message tail — into a single\n * structure ready to fold into a prompt. It is intentionally NOT wired into\n * production-agent.ts here; see the exported seam note below and the package\n * barrel export so the wire-up is one call later.\n *\n * Token-cheap by construction: a long thread is represented by its compacted\n * tiers plus only the last N raw turns, instead of the entire transcript.\n */\n\nimport type { EngineMessage } from \"../engine/types.js\";\nimport {\n resolveObservationalMemoryConfig,\n type ObservationalMemoryConfig,\n} from \"./config.js\";\nimport { listObservationalMemory } from \"./store.js\";\nimport { countWindowTokens } from \"./message-text.js\";\nimport type {\n ObservationalContext,\n ObservationalMemoryEntry,\n ObservationalMemoryOwner,\n} from \"./types.js\";\n\nexport interface BuildObservationalContextOptions extends ObservationalMemoryOwner {\n threadId: string;\n /** The full, ordered thread messages — the recent tail is taken from here. */\n messages: EngineMessage[];\n config?: Partial<ObservationalMemoryConfig>;\n}\n\nfunction sumTokens(entries: ObservationalMemoryEntry[]): number {\n return entries.reduce((acc, entry) => acc + (entry.tokenEstimate || 0), 0);\n}\n\n/**\n * Build the three-tier Observational Memory context for a thread. The returned\n * tiers are ready to be injected into the turn's prompt assembly.\n *\n * This is consumed by the agent loop (`production-agent.ts`): when a thread has\n * persisted observations/reflections, the older raw-message prefix (everything\n * before `recentMessages`) is replaced with the `reflections` + `observations`\n * text, `recentMessages` is kept verbatim, and a short \"Observational Memory\"\n * block is prepended. Threads with no OM entries are left unchanged.\n */\n/** True when this thread has at least one persisted observation or reflection. */\nexport function hasObservationalMemory(context: ObservationalContext): boolean {\n return context.reflections.length > 0 || context.observations.length > 0;\n}\n\n/**\n * Serialize the reflections + observations tiers into a single, clearly\n * delimited prompt block. The recent-raw-message tail is NOT serialized here —\n * it stays as verbatim engine messages — so this block represents only the\n * compacted older history that replaces the raw prefix.\n *\n * Returns an empty string when there is nothing compacted yet, so callers can\n * cheaply skip injection for short threads.\n */\nexport function serializeObservationalMemoryBlock(\n context: ObservationalContext,\n): string {\n if (!hasObservationalMemory(context)) return \"\";\n const sections: string[] = [];\n sections.push(\n \"[Observational Memory] The earlier part of this long conversation has been \" +\n \"compacted into the dated reflections and observations below. Treat these \" +\n \"as an authoritative record of what already happened — do not redo \" +\n \"completed work, and trust the recorded decisions, names, dates, and \" +\n \"status. The most recent turns follow verbatim after this block.\",\n );\n if (context.reflections.length > 0) {\n sections.push(\n \"## Reflections (highest-level)\\n\" +\n context.reflections.map((entry) => entry.text).join(\"\\n\\n\"),\n );\n }\n if (context.observations.length > 0) {\n sections.push(\n \"## Observations (dense, dated)\\n\" +\n context.observations.map((entry) => entry.text).join(\"\\n\\n\"),\n );\n }\n return sections.join(\"\\n\\n\");\n}\n\nexport async function buildObservationalContext(\n options: BuildObservationalContextOptions,\n): Promise<ObservationalContext> {\n const config = resolveObservationalMemoryConfig(options.config);\n const owner: ObservationalMemoryOwner = {\n ownerEmail: options.ownerEmail,\n orgId: options.orgId ?? null,\n };\n\n const [reflections, observations] = await Promise.all([\n listObservationalMemory({\n ...owner,\n threadId: options.threadId,\n tier: \"reflection\",\n }),\n listObservationalMemory({\n ...owner,\n threadId: options.threadId,\n tier: \"observation\",\n }),\n ]);\n\n const recentCount = Math.max(0, config.recentRawMessageCount);\n const recentMessages =\n recentCount > 0 ? options.messages.slice(-recentCount) : [];\n\n const recentTokens = await countWindowTokens(recentMessages);\n const reflectionTokens = sumTokens(reflections);\n const observationTokens = sumTokens(observations);\n\n return {\n threadId: options.threadId,\n reflections,\n observations,\n recentMessages,\n tokens: {\n reflections: reflectionTokens,\n observations: observationTokens,\n recentMessages: recentTokens,\n total: reflectionTokens + observationTokens + recentTokens,\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-loop processor seam for the agent loop.
|
|
3
|
+
*
|
|
4
|
+
* A `Processor` is loop-internal *configuration* — not a tool, not an authoring
|
|
5
|
+
* DSL, not an action. It observes the model's streamed output and tool calls as
|
|
6
|
+
* the run progresses, may mutate its own per-processor `state`, and may `abort()`
|
|
7
|
+
* the run. This is the structural prerequisite for real-time guardrails and a
|
|
8
|
+
* proof-of-done / coverage gate: code that can watch the model mid-run and halt
|
|
9
|
+
* it (or surface a verdict) before a "done" is claimed.
|
|
10
|
+
*
|
|
11
|
+
* Borrowed from Mastra's output processors. The shape is intentionally minimal:
|
|
12
|
+
*
|
|
13
|
+
* - `processOutputStream` fires per streamed chunk (text / thinking deltas,
|
|
14
|
+
* etc.) while the model is generating, so a guardrail can react before the
|
|
15
|
+
* full turn lands.
|
|
16
|
+
* - `processOutputStep` fires once per model response, around tool execution,
|
|
17
|
+
* with the tool calls the model just requested. A coverage gate can inspect
|
|
18
|
+
* what the model is about to do and abort.
|
|
19
|
+
* - `processOutputResult` fires once at run end with the final text.
|
|
20
|
+
*
|
|
21
|
+
* All hooks are OPTIONAL. When no processors are supplied to `runAgentLoop`, the
|
|
22
|
+
* loop must not run any of this code — the no-processors path is byte-for-byte
|
|
23
|
+
* unchanged and carries zero overhead (callers guard on a non-empty array).
|
|
24
|
+
*
|
|
25
|
+
* Each processor gets its own mutable `state` object that persists across every
|
|
26
|
+
* hook invocation for that processor within a single run, and is isolated from
|
|
27
|
+
* other processors' state.
|
|
28
|
+
*/
|
|
29
|
+
import type { EngineContentPart, EngineEvent } from "./engine/types.js";
|
|
30
|
+
/**
|
|
31
|
+
* Thrown by a processor's `abort()` to halt the run gracefully. The loop catches
|
|
32
|
+
* it, emits a `tripwire` event, and stops. Carries the human-readable `reason`
|
|
33
|
+
* plus optional structured `meta` and the originating `processor` name.
|
|
34
|
+
*
|
|
35
|
+
* Lives here (not in production-agent) so any consumer can `instanceof` it
|
|
36
|
+
* without an import cycle.
|
|
37
|
+
*/
|
|
38
|
+
export declare class TripWire extends Error {
|
|
39
|
+
/** Optional structured metadata supplied at the abort site. */
|
|
40
|
+
readonly meta?: Record<string, unknown>;
|
|
41
|
+
/** Name of the processor that aborted, when known. */
|
|
42
|
+
readonly processor?: string;
|
|
43
|
+
constructor(reason: string, opts?: {
|
|
44
|
+
meta?: Record<string, unknown>;
|
|
45
|
+
processor?: string;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Per-processor mutable scratch space. Each processor sees the SAME object
|
|
50
|
+
* across all of its hook invocations within one run; processors never see each
|
|
51
|
+
* other's state.
|
|
52
|
+
*/
|
|
53
|
+
export type ProcessorState = Record<string, unknown>;
|
|
54
|
+
/** Halts the run by throwing a {@link TripWire}. Never returns normally. */
|
|
55
|
+
export type ProcessorAbort = (reason: string, meta?: Record<string, unknown>) => never;
|
|
56
|
+
/** A single streamed chunk plus the running list of chunks seen so far. */
|
|
57
|
+
export interface ProcessOutputStreamArgs {
|
|
58
|
+
/** The chunk that just streamed from the engine. */
|
|
59
|
+
part: EngineEvent;
|
|
60
|
+
/** Every chunk observed so far this turn, including `part`. */
|
|
61
|
+
streamParts: EngineEvent[];
|
|
62
|
+
/** This processor's mutable, isolated, run-scoped state. */
|
|
63
|
+
state: ProcessorState;
|
|
64
|
+
/** Halt the run; throws {@link TripWire}. */
|
|
65
|
+
abort: ProcessorAbort;
|
|
66
|
+
}
|
|
67
|
+
/** Context for a completed model response, fired around tool execution. */
|
|
68
|
+
export interface ProcessOutputStepArgs {
|
|
69
|
+
/** Tool calls the model requested in this step (empty for a final answer). */
|
|
70
|
+
toolCalls: {
|
|
71
|
+
id: string;
|
|
72
|
+
name: string;
|
|
73
|
+
input: unknown;
|
|
74
|
+
}[];
|
|
75
|
+
/** Terminal stop reason for the step, when the engine reported one. */
|
|
76
|
+
finishReason?: "end_turn" | "tool_use" | "max_tokens" | "stop_sequence" | "error";
|
|
77
|
+
/** Cumulative token usage for the run so far, when available. */
|
|
78
|
+
usage?: {
|
|
79
|
+
inputTokens: number;
|
|
80
|
+
outputTokens: number;
|
|
81
|
+
cacheReadTokens?: number;
|
|
82
|
+
cacheWriteTokens?: number;
|
|
83
|
+
};
|
|
84
|
+
/** This processor's mutable, isolated, run-scoped state. */
|
|
85
|
+
state: ProcessorState;
|
|
86
|
+
/** Halt the run; throws {@link TripWire}. */
|
|
87
|
+
abort: ProcessorAbort;
|
|
88
|
+
}
|
|
89
|
+
/** Context for the end of the whole run. */
|
|
90
|
+
export interface ProcessOutputResultArgs {
|
|
91
|
+
/** The final assistant text for the run. */
|
|
92
|
+
text: string;
|
|
93
|
+
/** This processor's mutable, isolated, run-scoped state. */
|
|
94
|
+
state: ProcessorState;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* A loop-internal observer/guardrail. All hooks are optional; implement only
|
|
98
|
+
* the ones a given guardrail needs. Hooks may be sync or async.
|
|
99
|
+
*/
|
|
100
|
+
export interface Processor {
|
|
101
|
+
/** Stable name, surfaced on `tripwire` events and in per-processor errors. */
|
|
102
|
+
name?: string;
|
|
103
|
+
/** Called per streamed chunk while the model generates. */
|
|
104
|
+
processOutputStream?(args: ProcessOutputStreamArgs): void | Promise<void>;
|
|
105
|
+
/** Called once per model response, around tool execution. */
|
|
106
|
+
processOutputStep?(args: ProcessOutputStepArgs): void | Promise<void>;
|
|
107
|
+
/** Called once at run end with the final text. */
|
|
108
|
+
processOutputResult?(args: ProcessOutputResultArgs): void | Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Runs a chain of processors over the loop's lifecycle. Created once per run;
|
|
112
|
+
* isolates each processor's `state`, runs hooks in registration order, and
|
|
113
|
+
* converts a processor's `abort()` (or any thrown `TripWire`) into a single
|
|
114
|
+
* halt signal the loop can act on.
|
|
115
|
+
*
|
|
116
|
+
* The executor is only constructed when at least one processor is supplied, so
|
|
117
|
+
* the no-processors path never touches any of this.
|
|
118
|
+
*/
|
|
119
|
+
export declare class ProcessorChain {
|
|
120
|
+
private readonly entries;
|
|
121
|
+
/** Accumulates every stream chunk so each `processOutputStream` call sees the running list. */
|
|
122
|
+
private readonly streamParts;
|
|
123
|
+
constructor(processors: Processor[]);
|
|
124
|
+
private makeAbort;
|
|
125
|
+
/** Fire `processOutputStream` for every processor that implements it. */
|
|
126
|
+
runStream(part: EngineEvent): Promise<void>;
|
|
127
|
+
/** Fire `processOutputStep` for every processor that implements it. */
|
|
128
|
+
runStep(args: {
|
|
129
|
+
toolCalls: {
|
|
130
|
+
id: string;
|
|
131
|
+
name: string;
|
|
132
|
+
input: unknown;
|
|
133
|
+
}[];
|
|
134
|
+
finishReason?: ProcessOutputStepArgs["finishReason"];
|
|
135
|
+
usage?: ProcessOutputStepArgs["usage"];
|
|
136
|
+
}): Promise<void>;
|
|
137
|
+
/** Fire `processOutputResult` for every processor that implements it. */
|
|
138
|
+
runResult(text: string): Promise<void>;
|
|
139
|
+
}
|
|
140
|
+
/** Engine content parts → the plain tool-call shape passed to `processOutputStep`. */
|
|
141
|
+
export declare function toolCallsFromContent(parts: EngineContentPart[]): {
|
|
142
|
+
id: string;
|
|
143
|
+
name: string;
|
|
144
|
+
input: unknown;
|
|
145
|
+
}[];
|
|
146
|
+
//# sourceMappingURL=processors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processors.d.ts","sourceRoot":"","sources":["../../src/agent/processors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-loop processor seam for the agent loop.
|
|
3
|
+
*
|
|
4
|
+
* A `Processor` is loop-internal *configuration* — not a tool, not an authoring
|
|
5
|
+
* DSL, not an action. It observes the model's streamed output and tool calls as
|
|
6
|
+
* the run progresses, may mutate its own per-processor `state`, and may `abort()`
|
|
7
|
+
* the run. This is the structural prerequisite for real-time guardrails and a
|
|
8
|
+
* proof-of-done / coverage gate: code that can watch the model mid-run and halt
|
|
9
|
+
* it (or surface a verdict) before a "done" is claimed.
|
|
10
|
+
*
|
|
11
|
+
* Borrowed from Mastra's output processors. The shape is intentionally minimal:
|
|
12
|
+
*
|
|
13
|
+
* - `processOutputStream` fires per streamed chunk (text / thinking deltas,
|
|
14
|
+
* etc.) while the model is generating, so a guardrail can react before the
|
|
15
|
+
* full turn lands.
|
|
16
|
+
* - `processOutputStep` fires once per model response, around tool execution,
|
|
17
|
+
* with the tool calls the model just requested. A coverage gate can inspect
|
|
18
|
+
* what the model is about to do and abort.
|
|
19
|
+
* - `processOutputResult` fires once at run end with the final text.
|
|
20
|
+
*
|
|
21
|
+
* All hooks are OPTIONAL. When no processors are supplied to `runAgentLoop`, the
|
|
22
|
+
* loop must not run any of this code — the no-processors path is byte-for-byte
|
|
23
|
+
* unchanged and carries zero overhead (callers guard on a non-empty array).
|
|
24
|
+
*
|
|
25
|
+
* Each processor gets its own mutable `state` object that persists across every
|
|
26
|
+
* hook invocation for that processor within a single run, and is isolated from
|
|
27
|
+
* other processors' state.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Thrown by a processor's `abort()` to halt the run gracefully. The loop catches
|
|
31
|
+
* it, emits a `tripwire` event, and stops. Carries the human-readable `reason`
|
|
32
|
+
* plus optional structured `meta` and the originating `processor` name.
|
|
33
|
+
*
|
|
34
|
+
* Lives here (not in production-agent) so any consumer can `instanceof` it
|
|
35
|
+
* without an import cycle.
|
|
36
|
+
*/
|
|
37
|
+
export class TripWire extends Error {
|
|
38
|
+
/** Optional structured metadata supplied at the abort site. */
|
|
39
|
+
meta;
|
|
40
|
+
/** Name of the processor that aborted, when known. */
|
|
41
|
+
processor;
|
|
42
|
+
constructor(reason, opts) {
|
|
43
|
+
super(reason);
|
|
44
|
+
this.name = "TripWire";
|
|
45
|
+
this.meta = opts?.meta;
|
|
46
|
+
this.processor = opts?.processor;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Runs a chain of processors over the loop's lifecycle. Created once per run;
|
|
51
|
+
* isolates each processor's `state`, runs hooks in registration order, and
|
|
52
|
+
* converts a processor's `abort()` (or any thrown `TripWire`) into a single
|
|
53
|
+
* halt signal the loop can act on.
|
|
54
|
+
*
|
|
55
|
+
* The executor is only constructed when at least one processor is supplied, so
|
|
56
|
+
* the no-processors path never touches any of this.
|
|
57
|
+
*/
|
|
58
|
+
export class ProcessorChain {
|
|
59
|
+
entries;
|
|
60
|
+
/** Accumulates every stream chunk so each `processOutputStream` call sees the running list. */
|
|
61
|
+
streamParts = [];
|
|
62
|
+
constructor(processors) {
|
|
63
|
+
this.entries = processors.map((processor) => ({
|
|
64
|
+
processor,
|
|
65
|
+
state: {},
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
makeAbort(processor) {
|
|
69
|
+
const processorName = processor.name;
|
|
70
|
+
return (reason, meta) => {
|
|
71
|
+
throw new TripWire(reason, {
|
|
72
|
+
...(meta ? { meta } : {}),
|
|
73
|
+
...(processorName ? { processor: processorName } : {}),
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Fire `processOutputStream` for every processor that implements it. */
|
|
78
|
+
async runStream(part) {
|
|
79
|
+
this.streamParts.push(part);
|
|
80
|
+
for (const { processor, state } of this.entries) {
|
|
81
|
+
if (!processor.processOutputStream)
|
|
82
|
+
continue;
|
|
83
|
+
await processor.processOutputStream({
|
|
84
|
+
part,
|
|
85
|
+
streamParts: this.streamParts,
|
|
86
|
+
state,
|
|
87
|
+
abort: this.makeAbort(processor),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Fire `processOutputStep` for every processor that implements it. */
|
|
92
|
+
async runStep(args) {
|
|
93
|
+
for (const { processor, state } of this.entries) {
|
|
94
|
+
if (!processor.processOutputStep)
|
|
95
|
+
continue;
|
|
96
|
+
await processor.processOutputStep({
|
|
97
|
+
toolCalls: args.toolCalls,
|
|
98
|
+
...(args.finishReason ? { finishReason: args.finishReason } : {}),
|
|
99
|
+
...(args.usage ? { usage: args.usage } : {}),
|
|
100
|
+
state,
|
|
101
|
+
abort: this.makeAbort(processor),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** Fire `processOutputResult` for every processor that implements it. */
|
|
106
|
+
async runResult(text) {
|
|
107
|
+
for (const { processor, state } of this.entries) {
|
|
108
|
+
if (!processor.processOutputResult)
|
|
109
|
+
continue;
|
|
110
|
+
await processor.processOutputResult({ text, state });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Engine content parts → the plain tool-call shape passed to `processOutputStep`. */
|
|
115
|
+
export function toolCallsFromContent(parts) {
|
|
116
|
+
return parts
|
|
117
|
+
.filter((p) => {
|
|
118
|
+
return p.type === "tool-call";
|
|
119
|
+
})
|
|
120
|
+
.map((p) => ({ id: p.id, name: p.name, input: p.input }));
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=processors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processors.js","sourceRoot":"","sources":["../../src/agent/processors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * In-loop processor seam for the agent loop.\n *\n * A `Processor` is loop-internal *configuration* — not a tool, not an authoring\n * DSL, not an action. It observes the model's streamed output and tool calls as\n * the run progresses, may mutate its own per-processor `state`, and may `abort()`\n * the run. This is the structural prerequisite for real-time guardrails and a\n * proof-of-done / coverage gate: code that can watch the model mid-run and halt\n * it (or surface a verdict) before a \"done\" is claimed.\n *\n * Borrowed from Mastra's output processors. The shape is intentionally minimal:\n *\n * - `processOutputStream` fires per streamed chunk (text / thinking deltas,\n * etc.) while the model is generating, so a guardrail can react before the\n * full turn lands.\n * - `processOutputStep` fires once per model response, around tool execution,\n * with the tool calls the model just requested. A coverage gate can inspect\n * what the model is about to do and abort.\n * - `processOutputResult` fires once at run end with the final text.\n *\n * All hooks are OPTIONAL. When no processors are supplied to `runAgentLoop`, the\n * loop must not run any of this code — the no-processors path is byte-for-byte\n * unchanged and carries zero overhead (callers guard on a non-empty array).\n *\n * Each processor gets its own mutable `state` object that persists across every\n * hook invocation for that processor within a single run, and is isolated from\n * other processors' state.\n */\n\nimport type { EngineContentPart, EngineEvent } from \"./engine/types.js\";\n\n/**\n * Thrown by a processor's `abort()` to halt the run gracefully. The loop catches\n * it, emits a `tripwire` event, and stops. Carries the human-readable `reason`\n * plus optional structured `meta` and the originating `processor` name.\n *\n * Lives here (not in production-agent) so any consumer can `instanceof` it\n * without an import cycle.\n */\nexport class TripWire extends Error {\n /** Optional structured metadata supplied at the abort site. */\n readonly meta?: Record<string, unknown>;\n /** Name of the processor that aborted, when known. */\n readonly processor?: string;\n constructor(\n reason: string,\n opts?: { meta?: Record<string, unknown>; processor?: string },\n ) {\n super(reason);\n this.name = \"TripWire\";\n this.meta = opts?.meta;\n this.processor = opts?.processor;\n }\n}\n\n/**\n * Per-processor mutable scratch space. Each processor sees the SAME object\n * across all of its hook invocations within one run; processors never see each\n * other's state.\n */\nexport type ProcessorState = Record<string, unknown>;\n\n/** Halts the run by throwing a {@link TripWire}. Never returns normally. */\nexport type ProcessorAbort = (\n reason: string,\n meta?: Record<string, unknown>,\n) => never;\n\n/** A single streamed chunk plus the running list of chunks seen so far. */\nexport interface ProcessOutputStreamArgs {\n /** The chunk that just streamed from the engine. */\n part: EngineEvent;\n /** Every chunk observed so far this turn, including `part`. */\n streamParts: EngineEvent[];\n /** This processor's mutable, isolated, run-scoped state. */\n state: ProcessorState;\n /** Halt the run; throws {@link TripWire}. */\n abort: ProcessorAbort;\n}\n\n/** Context for a completed model response, fired around tool execution. */\nexport interface ProcessOutputStepArgs {\n /** Tool calls the model requested in this step (empty for a final answer). */\n toolCalls: { id: string; name: string; input: unknown }[];\n /** Terminal stop reason for the step, when the engine reported one. */\n finishReason?:\n | \"end_turn\"\n | \"tool_use\"\n | \"max_tokens\"\n | \"stop_sequence\"\n | \"error\";\n /** Cumulative token usage for the run so far, when available. */\n usage?: {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n };\n /** This processor's mutable, isolated, run-scoped state. */\n state: ProcessorState;\n /** Halt the run; throws {@link TripWire}. */\n abort: ProcessorAbort;\n}\n\n/** Context for the end of the whole run. */\nexport interface ProcessOutputResultArgs {\n /** The final assistant text for the run. */\n text: string;\n /** This processor's mutable, isolated, run-scoped state. */\n state: ProcessorState;\n}\n\n/**\n * A loop-internal observer/guardrail. All hooks are optional; implement only\n * the ones a given guardrail needs. Hooks may be sync or async.\n */\nexport interface Processor {\n /** Stable name, surfaced on `tripwire` events and in per-processor errors. */\n name?: string;\n /** Called per streamed chunk while the model generates. */\n processOutputStream?(args: ProcessOutputStreamArgs): void | Promise<void>;\n /** Called once per model response, around tool execution. */\n processOutputStep?(args: ProcessOutputStepArgs): void | Promise<void>;\n /** Called once at run end with the final text. */\n processOutputResult?(args: ProcessOutputResultArgs): void | Promise<void>;\n}\n\n/**\n * Runs a chain of processors over the loop's lifecycle. Created once per run;\n * isolates each processor's `state`, runs hooks in registration order, and\n * converts a processor's `abort()` (or any thrown `TripWire`) into a single\n * halt signal the loop can act on.\n *\n * The executor is only constructed when at least one processor is supplied, so\n * the no-processors path never touches any of this.\n */\nexport class ProcessorChain {\n private readonly entries: { processor: Processor; state: ProcessorState }[];\n /** Accumulates every stream chunk so each `processOutputStream` call sees the running list. */\n private readonly streamParts: EngineEvent[] = [];\n\n constructor(processors: Processor[]) {\n this.entries = processors.map((processor) => ({\n processor,\n state: {},\n }));\n }\n\n private makeAbort(processor: Processor): ProcessorAbort {\n const processorName = processor.name;\n return (reason, meta) => {\n throw new TripWire(reason, {\n ...(meta ? { meta } : {}),\n ...(processorName ? { processor: processorName } : {}),\n });\n };\n }\n\n /** Fire `processOutputStream` for every processor that implements it. */\n async runStream(part: EngineEvent): Promise<void> {\n this.streamParts.push(part);\n for (const { processor, state } of this.entries) {\n if (!processor.processOutputStream) continue;\n await processor.processOutputStream({\n part,\n streamParts: this.streamParts,\n state,\n abort: this.makeAbort(processor),\n });\n }\n }\n\n /** Fire `processOutputStep` for every processor that implements it. */\n async runStep(args: {\n toolCalls: { id: string; name: string; input: unknown }[];\n finishReason?: ProcessOutputStepArgs[\"finishReason\"];\n usage?: ProcessOutputStepArgs[\"usage\"];\n }): Promise<void> {\n for (const { processor, state } of this.entries) {\n if (!processor.processOutputStep) continue;\n await processor.processOutputStep({\n toolCalls: args.toolCalls,\n ...(args.finishReason ? { finishReason: args.finishReason } : {}),\n ...(args.usage ? { usage: args.usage } : {}),\n state,\n abort: this.makeAbort(processor),\n });\n }\n }\n\n /** Fire `processOutputResult` for every processor that implements it. */\n async runResult(text: string): Promise<void> {\n for (const { processor, state } of this.entries) {\n if (!processor.processOutputResult) continue;\n await processor.processOutputResult({ text, state });\n }\n }\n}\n\n/** Engine content parts → the plain tool-call shape passed to `processOutputStep`. */\nexport function toolCallsFromContent(\n parts: EngineContentPart[],\n): { id: string; name: string; input: unknown }[] {\n return parts\n .filter((p): p is Extract<EngineContentPart, { type: \"tool-call\" }> => {\n return p.type === \"tool-call\";\n })\n .map((p) => ({ id: p.id, name: p.name, input: p.input }));\n}\n"]}
|
|
@@ -5,6 +5,7 @@ import { PROVIDER_TO_ENV } from "./engine/provider-env-vars.js";
|
|
|
5
5
|
import { subscribeToRun, getActiveRunForThread, getActiveRunForThreadAsync, getRun, abortRun } from "./run-manager.js";
|
|
6
6
|
import type { ActiveRun } from "./run-manager.js";
|
|
7
7
|
import { type ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
8
|
+
import { type Processor } from "./processors.js";
|
|
8
9
|
export { PROVIDER_TO_ENV };
|
|
9
10
|
/**
|
|
10
11
|
* Look up a user's persisted API key for the given provider. Returns
|
|
@@ -350,6 +351,15 @@ export declare function runAgentLoop(opts: {
|
|
|
350
351
|
* `approval_required`. See `AgentChatRequest.approvedToolCalls`.
|
|
351
352
|
*/
|
|
352
353
|
approvedToolCalls?: string[];
|
|
354
|
+
/**
|
|
355
|
+
* In-loop processor seam (see `processors.ts`). Each processor can observe
|
|
356
|
+
* streamed chunks, observe model responses around tool execution, and
|
|
357
|
+
* `abort()` the run. Loop-internal config, NOT a tool/authoring surface —
|
|
358
|
+
* processors only observe/mutate-stream/abort; they never define app
|
|
359
|
+
* behavior or replace actions. When omitted or empty, none of the seam code
|
|
360
|
+
* runs and the loop is byte-for-byte unchanged (zero overhead).
|
|
361
|
+
*/
|
|
362
|
+
processors?: Processor[];
|
|
353
363
|
}): Promise<AgentLoopUsage>;
|
|
354
364
|
export declare function createProductionAgentHandler(options: ProductionAgentOptions): H3EventHandler;
|
|
355
365
|
export { getActiveRunForThread, getActiveRunForThreadAsync, getRun, abortRun, subscribeToRun, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"production-agent.d.ts","sourceRoot":"","sources":["../../src/agent/production-agent.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,IAAI,cAAc,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,KAAK,EACV,UAAU,EACV,mBAAmB,EAEnB,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,iBAAiB,EAGlB,MAAM,mBAAmB,CAAC;AAmB3B,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIhE,OAAO,EAEL,cAAc,EACd,qBAAqB,EACrB,0BAA0B,EAC1B,MAAM,EACN,QAAQ,EAET,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAoBlD,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"production-agent.d.ts","sourceRoot":"","sources":["../../src/agent/production-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ import { classifyToolCallJournal, findCompletedJournalEntry, } from "./tool-call
|
|
|
24
24
|
import { preUploadAttachments } from "../file-upload/pre-upload-attachments.js";
|
|
25
25
|
import { extensionIdFromPathname } from "../extensions/path.js";
|
|
26
26
|
import { applyContextDirectives } from "./context-xray/apply-directives.js";
|
|
27
|
+
import { ProcessorChain, TripWire, toolCallsFromContent, } from "./processors.js";
|
|
27
28
|
import { completeRun as completeProgressRun, startRun as startProgressRun, updateRunProgress, } from "../progress/registry.js";
|
|
28
29
|
import { loadContextDirectives } from "./context-xray/directives-store.js";
|
|
29
30
|
import { buildManifest, writeContextManifest, } from "./context-xray/manifest.js";
|
|
@@ -1478,6 +1479,11 @@ function toolInputSchemaErrorResult(toolName, input, error) {
|
|
|
1478
1479
|
*/
|
|
1479
1480
|
export async function runAgentLoop(opts) {
|
|
1480
1481
|
const { engine, model, systemPrompt, tools, messages, actions, send, signal, } = opts;
|
|
1482
|
+
// Build the processor chain only when at least one processor is supplied so
|
|
1483
|
+
// the common (no-processors) path is unchanged and carries zero overhead.
|
|
1484
|
+
const processorChain = opts.processors && opts.processors.length > 0
|
|
1485
|
+
? new ProcessorChain(opts.processors)
|
|
1486
|
+
: null;
|
|
1481
1487
|
const usage = {
|
|
1482
1488
|
inputTokens: 0,
|
|
1483
1489
|
outputTokens: 0,
|
|
@@ -1528,6 +1534,19 @@ export async function runAgentLoop(opts) {
|
|
|
1528
1534
|
const bufferTextUntilFinalGuard = Boolean(opts.finalResponseGuard);
|
|
1529
1535
|
let finalGuardRetries = 0;
|
|
1530
1536
|
let iterations = 0;
|
|
1537
|
+
// Set when an in-loop processor aborts via `abort()` / throws a `TripWire`.
|
|
1538
|
+
// The loop emits the `tripwire` event, surfaces the reason as a final
|
|
1539
|
+
// assistant message, and stops cleanly.
|
|
1540
|
+
let tripwire = null;
|
|
1541
|
+
const emitTripwire = (err) => {
|
|
1542
|
+
tripwire = err;
|
|
1543
|
+
send({
|
|
1544
|
+
type: "tripwire",
|
|
1545
|
+
reason: err.message,
|
|
1546
|
+
...(err.processor ? { processor: err.processor } : {}),
|
|
1547
|
+
});
|
|
1548
|
+
send({ type: "text", text: err.message });
|
|
1549
|
+
};
|
|
1531
1550
|
while (true) {
|
|
1532
1551
|
if (signal.aborted)
|
|
1533
1552
|
break;
|
|
@@ -1621,6 +1640,22 @@ export async function runAgentLoop(opts) {
|
|
|
1621
1640
|
});
|
|
1622
1641
|
};
|
|
1623
1642
|
for await (const event of eventStream) {
|
|
1643
|
+
// In-loop processor seam (stream hook). Each chunk is offered to every
|
|
1644
|
+
// processor's `processOutputStream` before the loop handles it. A
|
|
1645
|
+
// processor `abort()` throws a TripWire; catch it locally so it is not
|
|
1646
|
+
// mistaken for a retryable engine error, then break out cleanly.
|
|
1647
|
+
if (processorChain) {
|
|
1648
|
+
try {
|
|
1649
|
+
await processorChain.runStream(event);
|
|
1650
|
+
}
|
|
1651
|
+
catch (err) {
|
|
1652
|
+
if (err instanceof TripWire) {
|
|
1653
|
+
emitTripwire(err);
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
throw err;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1624
1659
|
if (event.type === "text-delta") {
|
|
1625
1660
|
if (bufferTextUntilFinalGuard) {
|
|
1626
1661
|
bufferedAssistantText += event.text;
|
|
@@ -1713,6 +1748,10 @@ export async function runAgentLoop(opts) {
|
|
|
1713
1748
|
throw err;
|
|
1714
1749
|
}
|
|
1715
1750
|
}
|
|
1751
|
+
// A processor aborted mid-stream. The tripwire event + final message were
|
|
1752
|
+
// already emitted; halt the loop without sending a normal `done`.
|
|
1753
|
+
if (tripwire)
|
|
1754
|
+
break;
|
|
1716
1755
|
if (!assistantContent && toolCallErrors.size > 0) {
|
|
1717
1756
|
assistantContent = [];
|
|
1718
1757
|
}
|
|
@@ -1743,6 +1782,31 @@ export async function runAgentLoop(opts) {
|
|
|
1743
1782
|
: part);
|
|
1744
1783
|
messages.push({ role: "assistant", content: assistantContentForHistory });
|
|
1745
1784
|
const toolCallParts = assistantContent.filter((p) => p.type === "tool-call");
|
|
1785
|
+
// In-loop processor seam (step hook). Fires once per model response, around
|
|
1786
|
+
// tool execution, with the tool calls the model just requested (empty for a
|
|
1787
|
+
// final answer) plus the stop reason and cumulative usage. A coverage gate
|
|
1788
|
+
// can inspect what the model is about to do and `abort()` before tools run.
|
|
1789
|
+
if (processorChain) {
|
|
1790
|
+
try {
|
|
1791
|
+
await processorChain.runStep({
|
|
1792
|
+
toolCalls: toolCallsFromContent(assistantContent),
|
|
1793
|
+
...(terminalStopReason ? { finishReason: terminalStopReason } : {}),
|
|
1794
|
+
usage: {
|
|
1795
|
+
inputTokens: usage.inputTokens,
|
|
1796
|
+
outputTokens: usage.outputTokens,
|
|
1797
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
1798
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
1799
|
+
},
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
catch (err) {
|
|
1803
|
+
if (err instanceof TripWire) {
|
|
1804
|
+
emitTripwire(err);
|
|
1805
|
+
break;
|
|
1806
|
+
}
|
|
1807
|
+
throw err;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1746
1810
|
const flushBufferedAssistantText = () => {
|
|
1747
1811
|
if (!bufferTextUntilFinalGuard)
|
|
1748
1812
|
return;
|
|
@@ -2329,7 +2393,37 @@ export async function runAgentLoop(opts) {
|
|
|
2329
2393
|
break;
|
|
2330
2394
|
}
|
|
2331
2395
|
}
|
|
2396
|
+
// A processor halted the run: the `tripwire` event and final message were
|
|
2397
|
+
// already emitted at the abort site. Do NOT send the normal `done` — the run
|
|
2398
|
+
// ended on a guardrail, not a clean turn. The result hook still fires below
|
|
2399
|
+
// so processors can observe the (halted) final text.
|
|
2400
|
+
if (tripwire) {
|
|
2401
|
+
if (processorChain) {
|
|
2402
|
+
try {
|
|
2403
|
+
await processorChain.runResult(collectTextParts(messages.flatMap((m) => (m.role === "assistant" ? m.content : []))));
|
|
2404
|
+
}
|
|
2405
|
+
catch (err) {
|
|
2406
|
+
if (!(err instanceof TripWire))
|
|
2407
|
+
throw err;
|
|
2408
|
+
// A result-hook abort is a no-op: the run is already halting.
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
return usage;
|
|
2412
|
+
}
|
|
2332
2413
|
if (!signal.aborted) {
|
|
2414
|
+
// In-loop processor seam (result hook). Fires once at clean run end with the
|
|
2415
|
+
// final assistant text so processors (e.g. a proof-of-done gate) can record
|
|
2416
|
+
// a verdict. A result-hook abort cannot un-finish a completed run, so a
|
|
2417
|
+
// TripWire here is swallowed.
|
|
2418
|
+
if (processorChain) {
|
|
2419
|
+
try {
|
|
2420
|
+
await processorChain.runResult(collectTextParts(messages.flatMap((m) => (m.role === "assistant" ? m.content : []))));
|
|
2421
|
+
}
|
|
2422
|
+
catch (err) {
|
|
2423
|
+
if (!(err instanceof TripWire))
|
|
2424
|
+
throw err;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2333
2427
|
send({ type: "done" });
|
|
2334
2428
|
// Clean up any zombie-completion ledger entries for this thread now that
|
|
2335
2429
|
// the turn completed normally. If the run was aborted the ledger must stay
|
|
@@ -3206,6 +3300,13 @@ export function createProductionAgentHandler(options) {
|
|
|
3206
3300
|
catch {
|
|
3207
3301
|
// Experiments module unavailable — use default model
|
|
3208
3302
|
}
|
|
3303
|
+
// TODO(processor-seam): thread `processors` from ProductionAgentOptions
|
|
3304
|
+
// through to runAgentLoop here once the handler exposes a way to
|
|
3305
|
+
// configure them (e.g. a `processors` field on ProductionAgentOptions
|
|
3306
|
+
// or a per-request resolver). The loop-level seam (runAgentLoop's
|
|
3307
|
+
// `processors` opt + ProcessorChain/TripWire) is the deliverable and is
|
|
3308
|
+
// already callable directly by sub-agents, A2A, MCP, and tests; this is
|
|
3309
|
+
// only the HTTP-handler convenience plumbing.
|
|
3209
3310
|
const agentLoopOpts = {
|
|
3210
3311
|
engine,
|
|
3211
3312
|
model: effectiveModel,
|