@tangle-network/agent-runtime 0.350.2 → 0.353.2
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/{activation-CfJMyzEs.js → activation-BkRaG5t0.js} +4 -4
- package/dist/{activation-CfJMyzEs.js.map → activation-BkRaG5t0.js.map} +1 -1
- package/dist/{activation-DyiHrTlS.d.ts → activation-CFS31SWI.d.ts} +2 -2
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -3
- package/dist/{bundle-Ze8pd07a.js → bundle-DeDkJbsr.js} +2 -2
- package/dist/{bundle-Ze8pd07a.js.map → bundle-DeDkJbsr.js.map} +1 -1
- package/dist/candidate-execution/index.js +4 -4
- package/dist/chat-turn.d.ts +2 -0
- package/dist/chat-turn.js +1 -0
- package/dist/{coordination-manager-BkVfWlMz.js → coordination-manager-BrRkc55z.js} +4 -4
- package/dist/{coordination-manager-BkVfWlMz.js.map → coordination-manager-BrRkc55z.js.map} +1 -1
- package/dist/{delegate-DgEie4ad.js → delegate-CAdajnf8.js} +3 -3
- package/dist/{delegate-DgEie4ad.js.map → delegate-CAdajnf8.js.map} +1 -1
- package/dist/durable.d.ts +7 -130
- package/dist/durable.js +24 -952
- package/dist/durable.js.map +1 -1
- package/dist/{errors-wuhGvpE3.js → errors-AzSuGI23.js} +4 -1
- package/dist/errors-AzSuGI23.js.map +1 -0
- package/dist/execution-handle-Bd2_nUB6.js +167 -0
- package/dist/execution-handle-Bd2_nUB6.js.map +1 -0
- package/dist/execution-handle-CujvqgCn.d.ts +130 -0
- package/dist/{graph-Cx0FhKSE.js → graph-CyaIHVGR.js} +7 -6
- package/dist/{graph-Cx0FhKSE.js.map → graph-CyaIHVGR.js.map} +1 -1
- package/dist/{improve-i0HU1-aa.js → improve-DwG-yioQ.js} +10 -9
- package/dist/{improve-i0HU1-aa.js.map → improve-DwG-yioQ.js.map} +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +14 -11
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +2 -2
- package/dist/intelligence.js +12 -10
- package/dist/intelligence.js.map +1 -1
- package/dist/journal-store-BJPMUydp.js +3925 -0
- package/dist/journal-store-BJPMUydp.js.map +1 -0
- package/dist/kernel.d.ts +1 -1
- package/dist/kernel.js +11 -10
- package/dist/{loop-runner-DvfOXVx9.d.ts → loop-runner-D9rcTNf2.d.ts} +2 -2
- package/dist/{loop-runner-BwN9MhdP.js → loop-runner-DwS3jARE.js} +3 -3
- package/dist/{loop-runner-BwN9MhdP.js.map → loop-runner-DwS3jARE.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +4 -4
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +8 -8
- package/dist/mcp/memory-bin.js +2 -2
- package/dist/{model-policy-GSxWwP-b.js → model-policy-C-RGAUW4.js} +2 -2
- package/dist/{model-policy-GSxWwP-b.js.map → model-policy-C-RGAUW4.js.map} +1 -1
- package/dist/{prepare-DE8TQnLu.js → prepare-XWwsOh8O.js} +4 -3
- package/dist/{prepare-DE8TQnLu.js.map → prepare-XWwsOh8O.js.map} +1 -1
- package/dist/{profile-CAhZDW2T.js → profile-C01SQZKa.js} +3 -3
- package/dist/{profile-CAhZDW2T.js.map → profile-C01SQZKa.js.map} +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +2 -2
- package/dist/{provision-supervisor-Bde_FF0R.js → provision-supervisor-AEnei2Jq.js} +7 -7
- package/dist/{provision-supervisor-Bde_FF0R.js.map → provision-supervisor-AEnei2Jq.js.map} +1 -1
- package/dist/{run-cancellation-BLy_Zz-w.js → run-cancellation-CoJRKvih.js} +2 -2
- package/dist/{run-cancellation-BLy_Zz-w.js.map → run-cancellation-CoJRKvih.js.map} +1 -1
- package/dist/{runtime-6Ec9sHRe.js → runtime-DCYSaYHW.js} +42 -39
- package/dist/{runtime-6Ec9sHRe.js.map → runtime-DCYSaYHW.js.map} +1 -1
- package/dist/{sandbox-profile-compat-BxMQ1VXv.js → sandbox-profile-compat-CXjozdWL.js} +4 -623
- package/dist/{sandbox-profile-compat-BxMQ1VXv.js.map → sandbox-profile-compat-CXjozdWL.js.map} +1 -1
- package/dist/{search-executor-B7g_5Wjl.js → search-executor-B2jc63hZ.js} +14 -11
- package/dist/{search-executor-B7g_5Wjl.js.map → search-executor-B2jc63hZ.js.map} +1 -1
- package/dist/{server-fvEMwGMQ.js → server-CKBTwWM8.js} +6 -6
- package/dist/{server-fvEMwGMQ.js.map → server-CKBTwWM8.js.map} +1 -1
- package/dist/{structural-rollout-B86bSixU.js → structural-rollout-rRT3ypqz.js} +7 -5
- package/dist/{structural-rollout-B86bSixU.js.map → structural-rollout-rRT3ypqz.js.map} +1 -1
- package/dist/{supervise-CaeZcgAW.js → supervise-B3_wtgHS.js} +18 -21
- package/dist/supervise-B3_wtgHS.js.map +1 -0
- package/dist/supervision-discovery-CewADdEs.js +772 -0
- package/dist/supervision-discovery-CewADdEs.js.map +1 -0
- package/dist/{supervisor-C1OePYE-.js → supervisor-C_sDmX5H.js} +156 -3984
- package/dist/supervisor-C_sDmX5H.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +13 -13
- package/dist/{tool-server-CwuYeW_Z.js → tool-server-CZWd_Opp.js} +2 -2
- package/dist/{tool-server-CwuYeW_Z.js.map → tool-server-CZWd_Opp.js.map} +1 -1
- package/dist/{top-snapshot-ChwpTr7A.js → top-snapshot-DcV7VG4m.js} +178 -161
- package/dist/top-snapshot-DcV7VG4m.js.map +1 -0
- package/dist/tui/bin.js +45 -74
- package/dist/tui/bin.js.map +1 -1
- package/dist/tui/index.d.ts +25 -54
- package/dist/tui/index.js +2 -2
- package/dist/{types-Fowuwdz2.d.ts → types-DTHxh4X9.d.ts} +47 -63
- package/dist/util-ebWMWzY0.js +624 -0
- package/dist/util-ebWMWzY0.js.map +1 -0
- package/dist/workspace-store/index.js +9 -3
- package/dist/workspace-store/index.js.map +1 -1
- package/package.json +18 -13
- package/dist/errors-wuhGvpE3.js.map +0 -1
- package/dist/record-events-B2GUgYdz.js +0 -261
- package/dist/record-events-B2GUgYdz.js.map +0 -1
- package/dist/supervise-CaeZcgAW.js.map +0 -1
- package/dist/supervisor-C1OePYE-.js.map +0 -1
- package/dist/top-snapshot-ChwpTr7A.js.map +0 -1
|
@@ -66,6 +66,8 @@ var BackendTransportError = class extends AgentEvalError {
|
|
|
66
66
|
* status arrived.
|
|
67
67
|
*/
|
|
68
68
|
upstreamCode;
|
|
69
|
+
/** Validated producer remedy; absent when the upstream supplied no trusted structured remedy. */
|
|
70
|
+
remediation;
|
|
69
71
|
/**
|
|
70
72
|
* Truncated upstream response body (≤2 KiB) when available. Diagnostic
|
|
71
73
|
* only — surfaces in `backend_error.error.body` and `final.error.body`
|
|
@@ -78,6 +80,7 @@ var BackendTransportError = class extends AgentEvalError {
|
|
|
78
80
|
this.backend = backend;
|
|
79
81
|
this.status = options?.status;
|
|
80
82
|
this.upstreamCode = options?.upstreamCode;
|
|
83
|
+
this.remediation = options?.remediation;
|
|
81
84
|
this.body = options?.body;
|
|
82
85
|
this.providerDispatch = options?.providerDispatch;
|
|
83
86
|
}
|
|
@@ -191,4 +194,4 @@ var RetainedRunDispatchBindingError = class extends AgentEvalError {
|
|
|
191
194
|
};
|
|
192
195
|
export { JudgeError as a, RetainedInteractiveAdmissionError as c, RetainedRunDispatchBindingError as d, RuntimeRunStateError as f, ConfigError as i, RetainedInteractiveBindingError as l, ValidationError as m, AnalystError as n, NotFoundError as o, SessionMismatchError as p, BackendTransportError as r, PlannerError as s, AgentEvalError$1 as t, RetainedRunAdmissionError as u };
|
|
193
196
|
|
|
194
|
-
//# sourceMappingURL=errors-
|
|
197
|
+
//# sourceMappingURL=errors-AzSuGI23.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-AzSuGI23.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n *\n * Error taxonomy for `@tangle-network/agent-runtime`.\n *\n * Public contract: every error this package throws as part of its consumer-\n * facing API either extends `AgentEvalError` (re-exported here for ergonomic\n * `instanceof` checks at the runtime boundary) or extends one of the\n * runtime-specific subclasses below.\n *\n * Internal invariant guards (`throw new Error('this should never happen')`)\n * remain plain `Error` — they are programmer-mistake assertions, not\n * consumer-catchable contract failures.\n *\n * Subclassing strategy: where a runtime-specific failure maps cleanly to an\n * agent-eval code (validation, config, not_found), we re-use the agent-eval\n * subclass. Runtime-only failure modes (session resume against the wrong\n * backend, backend transport errors) get fresh subclasses that still carry an\n * `AgentEvalErrorCode` so cross-package handlers can pattern-match without\n * importing the runtime.\n *\n * @stable\n */\n\nimport { AgentEvalError } from '@tangle-network/agent-eval'\nimport type {\n AgentInteractiveSessionRef,\n AgentInteractiveSessionStart,\n AgentInteractiveSessionStatus,\n} from '@tangle-network/agent-interface'\nimport type { RuntimeFailureCause } from './runtime/failure-cause'\nimport type {\n RetainedInteractiveAdmission,\n RetainedRunAdmission,\n} from './runtime/retained-run-types'\n\nexport {\n AgentEvalError,\n type AgentEvalErrorCode,\n ConfigError,\n JudgeError,\n NotFoundError,\n ValidationError,\n} from '@tangle-network/agent-eval'\n\n/**\n *\n * Caller asked to resume a session against a backend whose `kind` does not\n * match the session's recorded backend. This is a routing bug — the same\n * session id was reused across two different backend implementations — and\n * is not retryable without picking the right backend.\n *\n * @stable\n */\nexport class SessionMismatchError extends AgentEvalError {\n readonly sessionBackend: string\n readonly requestedBackend: string\n\n constructor(sessionBackend: string, requestedBackend: string, options?: { cause?: unknown }) {\n super(\n 'validation',\n `Cannot resume ${sessionBackend} session with ${requestedBackend} backend`,\n options,\n )\n this.sessionBackend = sessionBackend\n this.requestedBackend = requestedBackend\n }\n}\n\n/**\n *\n * A backend transport call (HTTP, gRPC, sidecar IPC) failed with a non-success\n * status. Distinct from `JudgeError` (which is structural / unrecoverable)\n * because backend failures are sometimes retryable and consumers may want to\n * branch on the upstream status code.\n *\n * @stable\n */\nexport class BackendTransportError extends AgentEvalError {\n readonly backend: string\n readonly status?: number\n /**\n * Router-owned proof that a rejected request never reached a provider.\n *\n * This is intentionally one-sided. An absent value, or any value this\n * package does not understand, remains unknown to Runtime.\n */\n readonly providerDispatch?: 'not_started'\n /**\n * The upstream's own error class when it names one (the bridge's `parse_error`,\n * `not_configured`, a provider's `invalid_request_error`). A class the upstream never\n * retries is a decision about the request, so a retry policy may read it where no\n * status arrived.\n */\n readonly upstreamCode?: string\n /** Validated producer remedy; absent when the upstream supplied no trusted structured remedy. */\n readonly remediation?: RuntimeFailureCause['remediation']\n /**\n * Truncated upstream response body (≤2 KiB) when available. Diagnostic\n * only — surfaces in `backend_error.error.body` and `final.error.body`\n * so operators can see \"free_tier_limit\", \"invalid_api_key\", etc. without\n * cracking the log line open.\n */\n readonly body?: string\n\n constructor(\n backend: string,\n message: string,\n options?: {\n cause?: unknown\n status?: number\n upstreamCode?: string\n remediation?: RuntimeFailureCause['remediation']\n body?: string\n providerDispatch?: 'not_started'\n },\n ) {\n super('config', message, options)\n this.backend = backend\n this.status = options?.status\n this.upstreamCode = options?.upstreamCode\n this.remediation = options?.remediation\n this.body = options?.body\n this.providerDispatch = options?.providerDispatch\n }\n}\n\n/**\n *\n * A runtime-run lifecycle method was called in an order the state machine does\n * not allow: `persist()` before `complete()`, `complete()` twice, etc.\n *\n * @stable\n */\nexport class RuntimeRunStateError extends AgentEvalError {\n constructor(message: string, options?: { cause?: unknown }) {\n super('validation', message, options)\n }\n}\n\n/**\n *\n * The dynamic-loop planner returned an unusable topology move — the LLM emitted\n * no parseable envelope, an unknown `kind`, or a structurally-invalid move\n * (e.g. a fanout with zero tasks). This is a structural failure of the\n * agent-authored topology, not a config mistake: the planner ran but its output\n * cannot drive the kernel. Carries `validation` so cross-package handlers can\n * pattern-match without importing the runtime. Fail loud — never substitute a\n * default move, or the loop silently runs a topology nobody chose.\n *\n * @stable\n */\nexport class PlannerError extends AgentEvalError {\n constructor(message: string, options?: { cause?: unknown }) {\n super('validation', message, options)\n }\n}\n\n/**\n * The analyst loop could not read or run over a round's trace — e.g. an empty round\n * (no iterations to analyze) or a malformed trace projection. Fail loud: a silent empty\n * store would mask a broken capture path and the driver would steer on nothing.\n */\nexport class AnalystError extends AgentEvalError {\n constructor(message: string, options?: { cause?: unknown }) {\n super('validation', message, options)\n }\n}\n\n/**\n *\n * The caller's `onAdmission` durability hook rejected, so a retained run's\n * admission record is not durable. For a pre-create intent, no provider work\n * has started. For a later record, provider state may already be live and the\n * environment remains available for recovery. Carries `capture_integrity`\n * because the required recovery record was not written.\n *\n * @stable\n */\nabstract class RetainedAdmissionError<\n TAdmission extends RetainedRunAdmission | RetainedInteractiveAdmission,\n> extends AgentEvalError {\n readonly phase: TAdmission['phase']\n /** The exact record the hook failed to persist, for direct recovery. */\n readonly admission: TAdmission\n\n constructor(admission: TAdmission, options?: { cause?: unknown }) {\n const recovery =\n admission.phase === 'intent' || admission.phase === 'interactive_intent'\n ? 'no provider work has started'\n : 'the environment is kept for recovery'\n super(\n 'capture_integrity',\n `retained run admission (${admission.phase}) was not persisted; ${recovery}`,\n options,\n )\n this.phase = admission.phase\n this.admission = admission\n }\n}\n\n/** The caller could not persist one detached-run recovery record. @stable */\nexport class RetainedRunAdmissionError extends RetainedAdmissionError<RetainedRunAdmission> {}\n\n/** The caller could not persist one exact interactive-process recovery record. @stable */\nexport class RetainedInteractiveAdmissionError extends RetainedAdmissionError<RetainedInteractiveAdmission> {}\n\n/**\n * A provider returned a valid interactive reference that does not bind to the\n * exact start request, or returned data that could not be parsed as one.\n *\n * The requested start and any valid provider reference are detached snapshots.\n * Malformed provider data is never copied into the error, so the error remains\n * safe to persist while the environment remains available for orphan cleanup.\n *\n * @stable\n */\nexport class RetainedInteractiveBindingError extends AgentEvalError {\n /** The exact native-process start request sent to the provider. */\n readonly requested: AgentInteractiveSessionStart\n /** The valid provider data, when the provider returned a parseable value. */\n readonly returned: {\n readonly ref?: AgentInteractiveSessionRef\n readonly status?: AgentInteractiveSessionStatus\n }\n\n constructor(\n requested: AgentInteractiveSessionStart,\n returned: RetainedInteractiveBindingError['returned'],\n options?: { cause?: unknown },\n ) {\n super(\n 'backend_integrity',\n 'provider returned interactive data that does not bind to the requested start; the environment is kept for diagnosis and cleanup',\n options,\n )\n this.requested = Object.freeze(requested)\n this.returned = Object.freeze(returned)\n }\n}\n\n/**\n *\n * A retained dispatch answered with coordinates that do not bind to the\n * identity the runtime requested, or failed exact verification. The\n * environment-phase admission is already durable at this point, so its\n * coordinates plus the provider reference carried here are the manual\n * recovery path. The environment is intentionally kept. Carries\n * `backend_integrity` because the provider violated its dispatch contract.\n *\n * @stable\n */\nexport class RetainedRunDispatchBindingError extends AgentEvalError {\n /** The coordinates the runtime sent with the dispatch. */\n readonly requested: {\n readonly provider: string\n readonly environmentId: string\n readonly sessionId: string\n readonly executionId: string\n }\n /** The loose reference the provider actually returned, for triage. */\n readonly returned: {\n readonly id?: string\n readonly provider?: string\n readonly controlRef?: unknown\n }\n\n constructor(\n requested: RetainedRunDispatchBindingError['requested'],\n returned: RetainedRunDispatchBindingError['returned'],\n options?: { cause?: unknown },\n ) {\n super(\n 'backend_integrity',\n 'retained dispatch did not bind to the requested identity; the durable environment admission and the returned reference on this error are the recovery path',\n options,\n )\n this.requested = requested\n this.returned = returned\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,IAAa,uBAAb,cAA0C,eAAe;CACvD;CACA;CAEA,YAAY,gBAAwB,kBAA0B,SAA+B;EAC3F,MACE,cACA,iBAAiB,eAAe,gBAAgB,iBAAiB,WACjE,OACF;EACA,KAAK,iBAAiB;EACtB,KAAK,mBAAmB;CAC1B;AACF;;;;;;;;;;AAWA,IAAa,wBAAb,cAA2C,eAAe;CACxD;CACA;;;;;;;CAOA;;;;;;;CAOA;;CAEA;;;;;;;CAOA;CAEA,YACE,SACA,SACA,SAQA;EACA,MAAM,UAAU,SAAS,OAAO;EAChC,KAAK,UAAU;EACf,KAAK,SAAS,SAAS;EACvB,KAAK,eAAe,SAAS;EAC7B,KAAK,cAAc,SAAS;EAC5B,KAAK,OAAO,SAAS;EACrB,KAAK,mBAAmB,SAAS;CACnC;AACF;;;;;;;;AASA,IAAa,uBAAb,cAA0C,eAAe;CACvD,YAAY,SAAiB,SAA+B;EAC1D,MAAM,cAAc,SAAS,OAAO;CACtC;AACF;;;;;;;;;;;;;AAcA,IAAa,eAAb,cAAkC,eAAe;CAC/C,YAAY,SAAiB,SAA+B;EAC1D,MAAM,cAAc,SAAS,OAAO;CACtC;AACF;;;;;;AAOA,IAAa,eAAb,cAAkC,eAAe;CAC/C,YAAY,SAAiB,SAA+B;EAC1D,MAAM,cAAc,SAAS,OAAO;CACtC;AACF;;;;;;;;;;;AAYA,IAAe,yBAAf,cAEU,eAAe;CACvB;;CAEA;CAEA,YAAY,WAAuB,SAA+B;EAChE,MAAM,WACJ,UAAU,UAAU,YAAY,UAAU,UAAU,uBAChD,iCACA;EACN,MACE,qBACA,2BAA2B,UAAU,MAAM,uBAAuB,YAClE,OACF;EACA,KAAK,QAAQ,UAAU;EACvB,KAAK,YAAY;CACnB;AACF;;AAGA,IAAa,4BAAb,cAA+C,uBAA6C,CAAC;;AAG7F,IAAa,oCAAb,cAAuD,uBAAqD,CAAC;;;;;;;;;;;AAY7G,IAAa,kCAAb,cAAqD,eAAe;;CAElE;;CAEA;CAKA,YACE,WACA,UACA,SACA;EACA,MACE,qBACA,mIACA,OACF;EACA,KAAK,YAAY,OAAO,OAAO,SAAS;EACxC,KAAK,WAAW,OAAO,OAAO,QAAQ;CACxC;AACF;;;;;;;;;;;;AAaA,IAAa,kCAAb,cAAqD,eAAe;;CAElE;;CAOA;CAMA,YACE,WACA,UACA,SACA;EACA,MACE,qBACA,8JACA,OACF;EACA,KAAK,YAAY;EACjB,KAAK,WAAW;CAClB;AACF"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// src/durable/chat-engine.ts
|
|
2
|
+
const encoder = new TextEncoder();
|
|
3
|
+
function encodeLine(event) {
|
|
4
|
+
return encoder.encode(`${JSON.stringify(event)}\n`);
|
|
5
|
+
}
|
|
6
|
+
function defaultLog(message, meta) {
|
|
7
|
+
if (meta) console.error(message, meta);
|
|
8
|
+
else console.error(message);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Preserve the useful part of a thrown HTTP Response at the stream boundary.
|
|
12
|
+
*
|
|
13
|
+
* Product routes commonly throw a typed Response for an upstream failure. A
|
|
14
|
+
* Response is not an Error, so String(response) produces the unusable
|
|
15
|
+
* "[object Response]" and hides the status that decides the next action.
|
|
16
|
+
* Read a clone so the caller's response body remains available to its owner.
|
|
17
|
+
*/
|
|
18
|
+
async function thrownErrorMessage(error) {
|
|
19
|
+
if (!(error instanceof Response)) return error instanceof Error ? error.message : String(error);
|
|
20
|
+
const prefix = `HTTP ${error.status}`;
|
|
21
|
+
try {
|
|
22
|
+
const text = await error.clone().text();
|
|
23
|
+
if (!text.trim()) return prefix;
|
|
24
|
+
try {
|
|
25
|
+
const body = JSON.parse(text);
|
|
26
|
+
const nested = typeof body.error === "object" && body.error !== null ? body.error.message : body.error;
|
|
27
|
+
const message = typeof nested === "string" ? nested : typeof body.message === "string" ? body.message : void 0;
|
|
28
|
+
if (message) return `${prefix}: ${message.slice(0, 500)}`;
|
|
29
|
+
} catch {}
|
|
30
|
+
} catch {}
|
|
31
|
+
return prefix;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Run one chat turn. Returns immediately with a `ReadableStream` body;
|
|
35
|
+
* execution starts while the stream is constructed. Backend
|
|
36
|
+
* failures surface as `error` + `session.run.failed` events.
|
|
37
|
+
*/
|
|
38
|
+
function handleChatTurn(input) {
|
|
39
|
+
const log = input.log ?? defaultLog;
|
|
40
|
+
const { identity, hooks } = input;
|
|
41
|
+
return {
|
|
42
|
+
body: new ReadableStream({ start: async (controller) => {
|
|
43
|
+
const emit = async (event) => {
|
|
44
|
+
controller.enqueue(encodeLine(event));
|
|
45
|
+
if (hooks.onEvent) try {
|
|
46
|
+
await hooks.onEvent(event);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
log("[chat-engine] onEvent hook threw", { error: err instanceof Error ? err.message : String(err) });
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
await emit({
|
|
53
|
+
type: "session.run.started",
|
|
54
|
+
data: {
|
|
55
|
+
sessionId: identity.sessionId,
|
|
56
|
+
tenantId: identity.tenantId,
|
|
57
|
+
turnIndex: identity.turnIndex
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
const producer = hooks.produce();
|
|
61
|
+
let failureData;
|
|
62
|
+
for await (const event of producer.stream) {
|
|
63
|
+
if (event.type === "session.run.failed") {
|
|
64
|
+
if (!failureData) await emit({
|
|
65
|
+
type: "error",
|
|
66
|
+
data: event.data
|
|
67
|
+
});
|
|
68
|
+
failureData = {
|
|
69
|
+
...failureData,
|
|
70
|
+
...event.data
|
|
71
|
+
};
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (event.type === "error") failureData = {
|
|
75
|
+
...failureData,
|
|
76
|
+
...event.data
|
|
77
|
+
};
|
|
78
|
+
if (event.type === "session.run.completed") continue;
|
|
79
|
+
await emit(event);
|
|
80
|
+
}
|
|
81
|
+
const rawFinal = producer.finalText();
|
|
82
|
+
const finalText = hooks.transformFinalText ? await hooks.transformFinalText(rawFinal) : rawFinal;
|
|
83
|
+
await hooks.persistAssistantMessage({
|
|
84
|
+
identity,
|
|
85
|
+
finalText
|
|
86
|
+
});
|
|
87
|
+
if (hooks.onTurnComplete) try {
|
|
88
|
+
await hooks.onTurnComplete({
|
|
89
|
+
identity,
|
|
90
|
+
finalText
|
|
91
|
+
});
|
|
92
|
+
} catch (err) {
|
|
93
|
+
log("[chat-engine] onTurnComplete threw", { error: err instanceof Error ? err.message : String(err) });
|
|
94
|
+
}
|
|
95
|
+
await emit({
|
|
96
|
+
type: failureData ? "session.run.failed" : "session.run.completed",
|
|
97
|
+
data: {
|
|
98
|
+
...failureData,
|
|
99
|
+
sessionId: identity.sessionId
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
const message = await thrownErrorMessage(err);
|
|
104
|
+
log("[chat-engine] turn failed", { error: message });
|
|
105
|
+
await emit({
|
|
106
|
+
type: "error",
|
|
107
|
+
data: { message }
|
|
108
|
+
});
|
|
109
|
+
await emit({
|
|
110
|
+
type: "session.run.failed",
|
|
111
|
+
data: {
|
|
112
|
+
sessionId: identity.sessionId,
|
|
113
|
+
message
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
} finally {
|
|
117
|
+
if (hooks.traceFlush) {
|
|
118
|
+
const flush = hooks.traceFlush().catch((err) => log("[chat-engine] traceFlush threw", { error: err instanceof Error ? err.message : String(err) }));
|
|
119
|
+
if (input.waitUntil) input.waitUntil(flush);
|
|
120
|
+
else await flush;
|
|
121
|
+
}
|
|
122
|
+
controller.close();
|
|
123
|
+
}
|
|
124
|
+
} }),
|
|
125
|
+
contentType: "application/x-ndjson"
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// src/durable/execution-handle.ts
|
|
129
|
+
/**
|
|
130
|
+
* Derive a stable execution id from the run identity.
|
|
131
|
+
* The same `(projectId, sessionId, turnIndex)` tuple yields the same id.
|
|
132
|
+
*
|
|
133
|
+
* Use the result as both `PromptOptions.executionId` and
|
|
134
|
+
* `PromptOptions.turnId` on the first dispatch.
|
|
135
|
+
* The execution id addresses the server-side execution for reconnect and
|
|
136
|
+
* replay; the turn id makes a repeated dispatch idempotent.
|
|
137
|
+
* An execution id alone does not make a repeated POST idempotent.
|
|
138
|
+
*
|
|
139
|
+
* Format is readable, not hashed: operators grepping orchestrator logs
|
|
140
|
+
* for `gtm-agent:thread-abc:3` find the run without translating an
|
|
141
|
+
* opaque id. Components are URL-encoded so delimiters inside caller ids
|
|
142
|
+
* cannot collapse distinct tuples. The final id is limited to the
|
|
143
|
+
* orchestrator replay route's 256-byte maximum. Execution ids are not a
|
|
144
|
+
* secrecy boundary.
|
|
145
|
+
*
|
|
146
|
+
* Wire integration:
|
|
147
|
+
* - Initial dispatch: pass the result as `executionId` and `turnId`.
|
|
148
|
+
* - Stream replay: pass it as `executionId` with `lastEventId`.
|
|
149
|
+
*
|
|
150
|
+
* @throws `TypeError` when either string id is blank.
|
|
151
|
+
* @throws `RangeError` when `turnIndex` is invalid or the result exceeds 256 bytes.
|
|
152
|
+
*/
|
|
153
|
+
function deriveExecutionId(input) {
|
|
154
|
+
if (input.projectId.trim().length === 0) throw new TypeError("projectId must be a non-empty string");
|
|
155
|
+
if (input.sessionId.trim().length === 0) throw new TypeError("sessionId must be a non-empty string");
|
|
156
|
+
if (!Number.isSafeInteger(input.turnIndex) || input.turnIndex < 0) throw new RangeError("turnIndex must be a non-negative safe integer");
|
|
157
|
+
const executionId = [
|
|
158
|
+
encodeURIComponent(input.projectId),
|
|
159
|
+
encodeURIComponent(input.sessionId),
|
|
160
|
+
String(input.turnIndex)
|
|
161
|
+
].join(":");
|
|
162
|
+
if (executionId.length > 256) throw new RangeError("derived execution id must not exceed 256 bytes");
|
|
163
|
+
return executionId;
|
|
164
|
+
}
|
|
165
|
+
export { handleChatTurn as n, deriveExecutionId as t };
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=execution-handle-Bd2_nUB6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-handle-Bd2_nUB6.js","names":[],"sources":["../src/durable/chat-engine.ts","../src/durable/execution-handle.ts"],"sourcesContent":["/**\n * `handleChatTurn` is a framework-neutral chat-turn HTTP orchestrator.\n * Owns the NDJSON `ChatStreamEvent` line protocol, the `session.run.*`\n * lifecycle vocabulary, and the persist / post-process / trace-flush\n * hook order. Returns a `ReadableStream` body the product hands to its\n * platform `Response`.\n *\n * Sandbox owns long-running execution, reconnect, and replay.\n * The producer this engine wraps already speaks that protocol; this\n * engine frames the events and orders product callbacks.\n *\n * Hooks (`ChatTurnHooks`):\n * - `produce`: build the backend event stream\n * - `persistAssistantMessage`: write the assistant turn to the product DB\n * - `onTurnComplete?`: post-process proposals, citations, and similar work\n * - `onEvent?`: send each event to another consumer\n * - `transformFinalText?`: transform text before persistence\n * - `traceFlush?`: let `waitUntil` keep the worker alive for export\n *\n * Framework neutrality: takes already-resolved values (`identity` tuple,\n * a `waitUntil`), never a `Request` or a `Context`. The product's thin\n * route adapter does auth + parse + access-control, then calls\n * `handleChatTurn(...)` and returns `result.body` as its platform `Response`.\n */\n\n/** The NDJSON line protocol every product chat client already speaks. */\nexport interface ChatStreamEvent {\n type: string\n data?: Record<string, unknown>\n}\n\n/** Identity of a chat turn. `tenantId` is the workspace id for workspace-\n * scoped products and the user id for session-scoped products. */\nexport interface ChatTurnIdentity {\n tenantId: string\n /** Thread / session id. */\n sessionId: string\n userId: string\n /** Monotonic 0-based turn index within the session. */\n turnIndex: number\n}\n\n/** The live side of a turn returned by the product's `produce` hook. */\nexport interface ChatTurnProducer<TEvent extends ChatStreamEvent = ChatStreamEvent> {\n /** The turn's events. The engine emits completion after persistence. */\n stream: AsyncGenerator<TEvent, void, unknown>\n /** The turn's final assistant text. Read once, after `stream` drains. */\n finalText(): string\n}\n\n/** Product callbacks invoked while one chat turn runs. */\nexport interface ChatTurnHooks {\n /** Build the backend stream. The engine forwards nonterminal events and\n * reads `finalText()` once the stream drains. Reported errors fail the turn. */\n produce(): ChatTurnProducer\n /** Persist the assistant message to the product's own store. Called\n * once, after drain, with the assembled (transform-applied) text. */\n persistAssistantMessage(input: { identity: ChatTurnIdentity; finalText: string }): Promise<void>\n /** Optional post-processing for proposals, citations, or credit metering.\n * Errors are logged without failing a turn that already streamed. */\n onTurnComplete?(input: { identity: ChatTurnIdentity; finalText: string }): Promise<void>\n /** Optional per-event side channel, such as a Durable Object broadcast.\n * Runs for every emitted event, including the lifecycle envelope.\n * Errors are logged without breaking the chat stream. */\n onEvent?(event: ChatStreamEvent): void | Promise<void>\n /** Optional pre-persist transform of the final text (e.g. PII\n * redaction). Affects only what is persisted; the live stream is\n * never altered. */\n transformFinalText?(text: string): string | Promise<string>\n /** Optional trace flush. Handed to `waitUntil` so the worker stays alive\n * until export completes. */\n traceFlush?(): Promise<void>\n}\n\n/** Inputs for one streamed product chat turn. */\nexport interface RunChatTurnInput {\n identity: ChatTurnIdentity\n hooks: ChatTurnHooks\n /** Worker liveness hook. When omitted, trace flush is awaited inline\n * before the stream closes. */\n waitUntil?: (p: Promise<unknown>) => void\n /** Structured logger for swallowed hook errors. Defaults to\n * `console.error` so failures surface without product wiring. */\n log?: (message: string, meta?: Record<string, unknown>) => void\n}\n\n/** HTTP response values returned for one chat turn. */\nexport interface ChatTurnResult {\n /** NDJSON body to return as the platform `Response` body. */\n body: ReadableStream<Uint8Array>\n /** Content type for the response. */\n contentType: 'application/x-ndjson'\n}\n\nconst encoder = new TextEncoder()\n\nfunction encodeLine(event: ChatStreamEvent): Uint8Array {\n return encoder.encode(`${JSON.stringify(event)}\\n`)\n}\n\nfunction defaultLog(message: string, meta?: Record<string, unknown>): void {\n if (meta) console.error(message, meta)\n else console.error(message)\n}\n\n/**\n * Preserve the useful part of a thrown HTTP Response at the stream boundary.\n *\n * Product routes commonly throw a typed Response for an upstream failure. A\n * Response is not an Error, so String(response) produces the unusable\n * \"[object Response]\" and hides the status that decides the next action.\n * Read a clone so the caller's response body remains available to its owner.\n */\nasync function thrownErrorMessage(error: unknown): Promise<string> {\n if (!(error instanceof Response)) {\n return error instanceof Error ? error.message : String(error)\n }\n\n const prefix = `HTTP ${error.status}`\n try {\n const text = await error.clone().text()\n if (!text.trim()) return prefix\n try {\n const body = JSON.parse(text) as {\n error?: { code?: unknown; message?: unknown } | string\n message?: unknown\n }\n const nested =\n typeof body.error === 'object' && body.error !== null ? body.error.message : body.error\n const message =\n typeof nested === 'string'\n ? nested\n : typeof body.message === 'string'\n ? body.message\n : undefined\n if (message) return `${prefix}: ${message.slice(0, 500)}`\n } catch {\n // Fall through to the status. Arbitrary upstream HTML or text is not a\n // stable product error contract and should not be copied into a chat.\n }\n } catch {\n // A consumed or unavailable body still has a useful HTTP status.\n }\n return prefix\n}\n\n/**\n * Run one chat turn. Returns immediately with a `ReadableStream` body;\n * execution starts while the stream is constructed. Backend\n * failures surface as `error` + `session.run.failed` events.\n */\nexport function handleChatTurn(input: RunChatTurnInput): ChatTurnResult {\n const log = input.log ?? defaultLog\n const { identity, hooks } = input\n\n const body = new ReadableStream<Uint8Array>({\n start: async (controller) => {\n const emit = async (event: ChatStreamEvent): Promise<void> => {\n controller.enqueue(encodeLine(event))\n if (hooks.onEvent) {\n try {\n await hooks.onEvent(event)\n } catch (err) {\n log('[chat-engine] onEvent hook threw', {\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n }\n\n try {\n await emit({\n type: 'session.run.started',\n data: {\n sessionId: identity.sessionId,\n tenantId: identity.tenantId,\n turnIndex: identity.turnIndex,\n },\n })\n\n const producer = hooks.produce()\n let failureData: Record<string, unknown> | undefined\n for await (const event of producer.stream) {\n if (event.type === 'session.run.failed') {\n if (!failureData) await emit({ type: 'error', data: event.data })\n failureData = { ...failureData, ...event.data }\n continue\n }\n if (event.type === 'error') failureData = { ...failureData, ...event.data }\n // A drained error stream is still a failed turn. Completion belongs\n // to this engine, after persistence, even when an upstream emits it.\n if (event.type === 'session.run.completed') continue\n await emit(event)\n }\n const rawFinal = producer.finalText()\n const finalText = hooks.transformFinalText\n ? await hooks.transformFinalText(rawFinal)\n : rawFinal\n\n await hooks.persistAssistantMessage({ identity, finalText })\n if (hooks.onTurnComplete) {\n try {\n await hooks.onTurnComplete({ identity, finalText })\n } catch (err) {\n log('[chat-engine] onTurnComplete threw', {\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n await emit({\n type: failureData ? 'session.run.failed' : 'session.run.completed',\n data: { ...failureData, sessionId: identity.sessionId },\n })\n } catch (err) {\n const message = await thrownErrorMessage(err)\n log('[chat-engine] turn failed', { error: message })\n await emit({ type: 'error', data: { message } })\n await emit({\n type: 'session.run.failed',\n data: { sessionId: identity.sessionId, message },\n })\n } finally {\n if (hooks.traceFlush) {\n const flush = hooks.traceFlush().catch((err) =>\n log('[chat-engine] traceFlush threw', {\n error: err instanceof Error ? err.message : String(err),\n }),\n )\n if (input.waitUntil) input.waitUntil(flush)\n else await flush\n }\n controller.close()\n }\n },\n })\n\n return { body, contentType: 'application/x-ndjson' }\n}\n","/**\n * Derive a stable execution id from the run identity.\n * The same `(projectId, sessionId, turnIndex)` tuple yields the same id.\n *\n * Use the result as both `PromptOptions.executionId` and\n * `PromptOptions.turnId` on the first dispatch.\n * The execution id addresses the server-side execution for reconnect and\n * replay; the turn id makes a repeated dispatch idempotent.\n * An execution id alone does not make a repeated POST idempotent.\n *\n * Format is readable, not hashed: operators grepping orchestrator logs\n * for `gtm-agent:thread-abc:3` find the run without translating an\n * opaque id. Components are URL-encoded so delimiters inside caller ids\n * cannot collapse distinct tuples. The final id is limited to the\n * orchestrator replay route's 256-byte maximum. Execution ids are not a\n * secrecy boundary.\n *\n * Wire integration:\n * - Initial dispatch: pass the result as `executionId` and `turnId`.\n * - Stream replay: pass it as `executionId` with `lastEventId`.\n *\n * @throws `TypeError` when either string id is blank.\n * @throws `RangeError` when `turnIndex` is invalid or the result exceeds 256 bytes.\n */\nexport function deriveExecutionId(input: {\n projectId: string\n sessionId: string\n turnIndex: number\n}): string {\n if (input.projectId.trim().length === 0) {\n throw new TypeError('projectId must be a non-empty string')\n }\n if (input.sessionId.trim().length === 0) {\n throw new TypeError('sessionId must be a non-empty string')\n }\n if (!Number.isSafeInteger(input.turnIndex) || input.turnIndex < 0) {\n throw new RangeError('turnIndex must be a non-negative safe integer')\n }\n\n const executionId = [\n encodeURIComponent(input.projectId),\n encodeURIComponent(input.sessionId),\n String(input.turnIndex),\n ].join(':')\n if (executionId.length > 256) {\n throw new RangeError('derived execution id must not exceed 256 bytes')\n }\n return executionId\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `handleChatTurn` is a framework-neutral chat-turn HTTP orchestrator.
|
|
3
|
+
* Owns the NDJSON `ChatStreamEvent` line protocol, the `session.run.*`
|
|
4
|
+
* lifecycle vocabulary, and the persist / post-process / trace-flush
|
|
5
|
+
* hook order. Returns a `ReadableStream` body the product hands to its
|
|
6
|
+
* platform `Response`.
|
|
7
|
+
*
|
|
8
|
+
* Sandbox owns long-running execution, reconnect, and replay.
|
|
9
|
+
* The producer this engine wraps already speaks that protocol; this
|
|
10
|
+
* engine frames the events and orders product callbacks.
|
|
11
|
+
*
|
|
12
|
+
* Hooks (`ChatTurnHooks`):
|
|
13
|
+
* - `produce`: build the backend event stream
|
|
14
|
+
* - `persistAssistantMessage`: write the assistant turn to the product DB
|
|
15
|
+
* - `onTurnComplete?`: post-process proposals, citations, and similar work
|
|
16
|
+
* - `onEvent?`: send each event to another consumer
|
|
17
|
+
* - `transformFinalText?`: transform text before persistence
|
|
18
|
+
* - `traceFlush?`: let `waitUntil` keep the worker alive for export
|
|
19
|
+
*
|
|
20
|
+
* Framework neutrality: takes already-resolved values (`identity` tuple,
|
|
21
|
+
* a `waitUntil`), never a `Request` or a `Context`. The product's thin
|
|
22
|
+
* route adapter does auth + parse + access-control, then calls
|
|
23
|
+
* `handleChatTurn(...)` and returns `result.body` as its platform `Response`.
|
|
24
|
+
*/
|
|
25
|
+
/** The NDJSON line protocol every product chat client already speaks. */
|
|
26
|
+
interface ChatStreamEvent {
|
|
27
|
+
type: string;
|
|
28
|
+
data?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
/** Identity of a chat turn. `tenantId` is the workspace id for workspace-
|
|
31
|
+
* scoped products and the user id for session-scoped products. */
|
|
32
|
+
interface ChatTurnIdentity {
|
|
33
|
+
tenantId: string;
|
|
34
|
+
/** Thread / session id. */
|
|
35
|
+
sessionId: string;
|
|
36
|
+
userId: string;
|
|
37
|
+
/** Monotonic 0-based turn index within the session. */
|
|
38
|
+
turnIndex: number;
|
|
39
|
+
}
|
|
40
|
+
/** The live side of a turn returned by the product's `produce` hook. */
|
|
41
|
+
interface ChatTurnProducer<TEvent extends ChatStreamEvent = ChatStreamEvent> {
|
|
42
|
+
/** The turn's events. The engine emits completion after persistence. */
|
|
43
|
+
stream: AsyncGenerator<TEvent, void, unknown>;
|
|
44
|
+
/** The turn's final assistant text. Read once, after `stream` drains. */
|
|
45
|
+
finalText(): string;
|
|
46
|
+
}
|
|
47
|
+
/** Product callbacks invoked while one chat turn runs. */
|
|
48
|
+
interface ChatTurnHooks {
|
|
49
|
+
/** Build the backend stream. The engine forwards nonterminal events and
|
|
50
|
+
* reads `finalText()` once the stream drains. Reported errors fail the turn. */
|
|
51
|
+
produce(): ChatTurnProducer;
|
|
52
|
+
/** Persist the assistant message to the product's own store. Called
|
|
53
|
+
* once, after drain, with the assembled (transform-applied) text. */
|
|
54
|
+
persistAssistantMessage(input: {
|
|
55
|
+
identity: ChatTurnIdentity;
|
|
56
|
+
finalText: string;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
/** Optional post-processing for proposals, citations, or credit metering.
|
|
59
|
+
* Errors are logged without failing a turn that already streamed. */
|
|
60
|
+
onTurnComplete?(input: {
|
|
61
|
+
identity: ChatTurnIdentity;
|
|
62
|
+
finalText: string;
|
|
63
|
+
}): Promise<void>;
|
|
64
|
+
/** Optional per-event side channel, such as a Durable Object broadcast.
|
|
65
|
+
* Runs for every emitted event, including the lifecycle envelope.
|
|
66
|
+
* Errors are logged without breaking the chat stream. */
|
|
67
|
+
onEvent?(event: ChatStreamEvent): void | Promise<void>;
|
|
68
|
+
/** Optional pre-persist transform of the final text (e.g. PII
|
|
69
|
+
* redaction). Affects only what is persisted; the live stream is
|
|
70
|
+
* never altered. */
|
|
71
|
+
transformFinalText?(text: string): string | Promise<string>;
|
|
72
|
+
/** Optional trace flush. Handed to `waitUntil` so the worker stays alive
|
|
73
|
+
* until export completes. */
|
|
74
|
+
traceFlush?(): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
/** Inputs for one streamed product chat turn. */
|
|
77
|
+
interface RunChatTurnInput {
|
|
78
|
+
identity: ChatTurnIdentity;
|
|
79
|
+
hooks: ChatTurnHooks;
|
|
80
|
+
/** Worker liveness hook. When omitted, trace flush is awaited inline
|
|
81
|
+
* before the stream closes. */
|
|
82
|
+
waitUntil?: (p: Promise<unknown>) => void;
|
|
83
|
+
/** Structured logger for swallowed hook errors. Defaults to
|
|
84
|
+
* `console.error` so failures surface without product wiring. */
|
|
85
|
+
log?: (message: string, meta?: Record<string, unknown>) => void;
|
|
86
|
+
}
|
|
87
|
+
/** HTTP response values returned for one chat turn. */
|
|
88
|
+
interface ChatTurnResult {
|
|
89
|
+
/** NDJSON body to return as the platform `Response` body. */
|
|
90
|
+
body: ReadableStream<Uint8Array>;
|
|
91
|
+
/** Content type for the response. */
|
|
92
|
+
contentType: 'application/x-ndjson';
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Run one chat turn. Returns immediately with a `ReadableStream` body;
|
|
96
|
+
* execution starts while the stream is constructed. Backend
|
|
97
|
+
* failures surface as `error` + `session.run.failed` events.
|
|
98
|
+
*/
|
|
99
|
+
declare function handleChatTurn(input: RunChatTurnInput): ChatTurnResult;
|
|
100
|
+
/**
|
|
101
|
+
* Derive a stable execution id from the run identity.
|
|
102
|
+
* The same `(projectId, sessionId, turnIndex)` tuple yields the same id.
|
|
103
|
+
*
|
|
104
|
+
* Use the result as both `PromptOptions.executionId` and
|
|
105
|
+
* `PromptOptions.turnId` on the first dispatch.
|
|
106
|
+
* The execution id addresses the server-side execution for reconnect and
|
|
107
|
+
* replay; the turn id makes a repeated dispatch idempotent.
|
|
108
|
+
* An execution id alone does not make a repeated POST idempotent.
|
|
109
|
+
*
|
|
110
|
+
* Format is readable, not hashed: operators grepping orchestrator logs
|
|
111
|
+
* for `gtm-agent:thread-abc:3` find the run without translating an
|
|
112
|
+
* opaque id. Components are URL-encoded so delimiters inside caller ids
|
|
113
|
+
* cannot collapse distinct tuples. The final id is limited to the
|
|
114
|
+
* orchestrator replay route's 256-byte maximum. Execution ids are not a
|
|
115
|
+
* secrecy boundary.
|
|
116
|
+
*
|
|
117
|
+
* Wire integration:
|
|
118
|
+
* - Initial dispatch: pass the result as `executionId` and `turnId`.
|
|
119
|
+
* - Stream replay: pass it as `executionId` with `lastEventId`.
|
|
120
|
+
*
|
|
121
|
+
* @throws `TypeError` when either string id is blank.
|
|
122
|
+
* @throws `RangeError` when `turnIndex` is invalid or the result exceeds 256 bytes.
|
|
123
|
+
*/
|
|
124
|
+
declare function deriveExecutionId(input: {
|
|
125
|
+
projectId: string;
|
|
126
|
+
sessionId: string;
|
|
127
|
+
turnIndex: number;
|
|
128
|
+
}): string;
|
|
129
|
+
export { ChatTurnProducer as a, handleChatTurn as c, ChatTurnIdentity as i, ChatStreamEvent as n, ChatTurnResult as o, ChatTurnHooks as r, RunChatTurnInput as s, deriveExecutionId as t };
|
|
130
|
+
//# sourceMappingURL=execution-handle-CujvqgCn.d.ts.map
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { c as readCommittedJsonLines, i as appendCommittedJsonLine, rt as contentAddress, u as withJsonlFileLock } from "./journal-store-BJPMUydp.js";
|
|
2
|
+
import { Er as defaultRunCommand } from "./supervisor-C_sDmX5H.js";
|
|
3
|
+
import { i as ConfigError, m as ValidationError } from "./errors-AzSuGI23.js";
|
|
4
|
+
import { v as harnessRunsAgent } from "./model-policy-C-RGAUW4.js";
|
|
4
5
|
import { t as composeRuntimeHooks } from "./runtime-hooks-CsW2pfFk.js";
|
|
5
|
-
import { g as withRunContext, h as createInMemoryRunContext, m as createFileRunContext } from "./coordination-manager-
|
|
6
|
-
import { B as runtimeFlowBrain, G as journaledGateDecider, H as GraphRouteError, K as routeFlowOf, U as createFlowRun, V as createGraphOverlay, W as flowRootProfile, X as validateGraphTopology, Y as graphRootProfile, i as profileGuidanceComposer, q as validateFlowGraph, r as superviseWithTestBrain, rt as kernelPromptRegistry, t as supervise } from "./supervise-
|
|
6
|
+
import { g as withRunContext, h as createInMemoryRunContext, m as createFileRunContext } from "./coordination-manager-BrRkc55z.js";
|
|
7
|
+
import { B as runtimeFlowBrain, G as journaledGateDecider, H as GraphRouteError, K as routeFlowOf, U as createFlowRun, V as createGraphOverlay, W as flowRootProfile, X as validateGraphTopology, Y as graphRootProfile, i as profileGuidanceComposer, q as validateFlowGraph, r as superviseWithTestBrain, rt as kernelPromptRegistry, t as supervise } from "./supervise-B3_wtgHS.js";
|
|
7
8
|
import { canonicalCandidateDigest } from "@tangle-network/agent-interface";
|
|
8
9
|
import { mkdirSync, realpathSync } from "node:fs";
|
|
9
10
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -578,4 +579,4 @@ function graphTask(graph, root) {
|
|
|
578
579
|
}
|
|
579
580
|
export { graphExecutionOptions as a, superviseAgentGraph as i, runGraph as n, runGraphWithTestBrain as r, GraphEdgeCapError as t };
|
|
580
581
|
|
|
581
|
-
//# sourceMappingURL=graph-
|
|
582
|
+
//# sourceMappingURL=graph-CyaIHVGR.js.map
|