@copilotkit/runtime 1.77.0 → 1.77.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/_virtual/_rolldown/runtime.mjs +1 -25
- package/dist/lib/runtime/copilot-runtime.cjs +1 -0
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts +1 -0
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts +1 -0
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +1 -0
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/lib/telemetry-client.cjs +1 -1
- package/dist/lib/telemetry-client.mjs +1 -1
- package/dist/package.cjs +5 -5
- package/dist/package.mjs +5 -5
- package/dist/v2/runtime/core/channel-manager.cjs +15 -15
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.cts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.mts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +15 -15
- package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
- package/dist/v2/runtime/core/package-info.cjs +10 -0
- package/dist/v2/runtime/core/package-info.cjs.map +1 -0
- package/dist/v2/runtime/core/package-info.mjs +8 -0
- package/dist/v2/runtime/core/package-info.mjs.map +1 -0
- package/dist/v2/runtime/core/runtime.cjs +4 -4
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +7 -1
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +7 -1
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +4 -5
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-trajectory-connect.cjs +1 -1
- package/dist/v2/runtime/handlers/handle-trajectory-connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-trajectory-connect.mjs +1 -1
- package/dist/v2/runtime/handlers/handle-trajectory-connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/memories.cjs +5 -17
- package/dist/v2/runtime/handlers/intelligence/memories.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/memories.mjs +5 -17
- package/dist/v2/runtime/handlers/intelligence/memories.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +43 -16
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +43 -16
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/threads.cjs +4 -3
- package/dist/v2/runtime/handlers/intelligence/threads.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/threads.mjs +4 -3
- package/dist/v2/runtime/handlers/intelligence/threads.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs +1 -2
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs +1 -2
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/platform-error.cjs +40 -0
- package/dist/v2/runtime/handlers/shared/platform-error.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/platform-error.mjs +40 -0
- package/dist/v2/runtime/handlers/shared/platform-error.mjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/client.cjs +59 -17
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +21 -0
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +21 -0
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +59 -17
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/thread-lock-heartbeat.cjs +143 -0
- package/dist/v2/runtime/intelligence-platform/thread-lock-heartbeat.cjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/thread-lock-heartbeat.mjs +142 -0
- package/dist/v2/runtime/intelligence-platform/thread-lock-heartbeat.mjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/trajectories.cjs +19 -3
- package/dist/v2/runtime/intelligence-platform/trajectories.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/trajectories.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/trajectories.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/trajectories.mjs +19 -3
- package/dist/v2/runtime/intelligence-platform/trajectories.mjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.cjs +8 -1
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.cts +12 -0
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.mts +12 -0
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.mjs +8 -1
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.cjs +3 -4
- package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.d.cts.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.d.mts.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.mjs +3 -5
- package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
- package/package.json +9 -9
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-lock-heartbeat.cjs","names":["PlatformRequestError"],"sources":["../../../../src/v2/runtime/intelligence-platform/thread-lock-heartbeat.ts"],"sourcesContent":["import { logger } from \"@copilotkit/shared\";\nimport { PlatformRequestError } from \"./client\";\nimport type { RenewThreadLockResponse } from \"./client\";\n\n/** Delay before the first retry of a failed renewal; doubles per attempt. */\nconst INITIAL_RETRY_DELAY_MS = 1_000;\n/** Upper bound for the delay between renewal retries. */\nconst MAX_RETRY_DELAY_MS = 8_000;\n/** Longest a single renewal may stay in flight before it counts as failed. */\nconst ATTEMPT_TIMEOUT_MS = 10_000;\n/** Stop retrying this long before the lock would expire. */\nconst DEADLINE_SAFETY_MARGIN_MS = 1_000;\n\nexport interface ThreadLockHeartbeatOptions {\n /**\n * Sends one renewal request. The signal aborts when the attempt times out,\n * so an abandoned request never overlaps its retry.\n */\n renew: (signal: AbortSignal) => Promise<RenewThreadLockResponse>;\n /** Delay between successful renewals. */\n intervalMs: number;\n /**\n * Lock lifetime assumed when the platform has not reported one: until the\n * first successful renewal when {@link initialTtlSeconds} is absent, and\n * for renewal responses that omit `ttlSeconds`.\n */\n fallbackTtlSeconds: number;\n /**\n * Remaining lock lifetime when the heartbeat starts, as reported by the\n * platform at acquisition, measured from when the acquire request was sent.\n * Used until the first successful renewal; when absent,\n * {@link fallbackTtlSeconds} applies instead. A value of zero or less means\n * the lock has already expired.\n */\n initialTtlSeconds?: number;\n /**\n * Called once when the lock can no longer be kept: a non-retryable failure,\n * or retryable failures that ran out the lock's remaining lifetime. Never\n * called after {@link ThreadLockHeartbeat.stop}.\n */\n onLost: (error: unknown) => void;\n /** Unref timers so a pending heartbeat never keeps the process alive. */\n unref?: boolean;\n}\n\nexport interface ThreadLockHeartbeat {\n /** Cancel the next renewal and any pending retry. Idempotent. */\n stop(): void;\n}\n\nclass RenewalTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Thread lock renewal did not settle within ${timeoutMs}ms`);\n this.name = \"RenewalTimeoutError\";\n }\n}\n\n/**\n * Whether a failed renewal may succeed if retried. A lost lock is a 409 the\n * platform marks `retryable: false`; server failures (5xx), timeouts and\n * network errors are worth retrying while the lock is still valid.\n */\nexport function isRetryableLockRenewalError(error: unknown): boolean {\n if (error instanceof PlatformRequestError) {\n if (error.retryable !== undefined) return error.retryable;\n return error.status >= 500 || error.status === 408 || error.status === 429;\n }\n // Timeouts, fetch network failures and malformed responses.\n return true;\n}\n\n/**\n * Keep a thread lock alive for a running agent.\n *\n * Renews every `intervalMs` (sooner if that would run past the lock's\n * lifetime), with at most one renewal in flight. A failed renewal is retried\n * with exponential backoff while the lock is still valid: the deadline is when\n * the last successful renewal was *sent* plus the `ttlSeconds` it returned,\n * because the platform starts the TTL when it handles the request (initially\n * start plus `initialTtlSeconds`, or `fallbackTtlSeconds` when the platform\n * reported no lifetime at acquisition). A non-retryable failure, or running\n * out of time before the deadline, calls `onLost`.\n * A `\"completed\"` response means the run already ended on the platform, so\n * the heartbeat stops without calling `onLost`.\n */\nexport function startThreadLockHeartbeat(\n options: ThreadLockHeartbeatOptions,\n): ThreadLockHeartbeat {\n const { renew, intervalMs, fallbackTtlSeconds, onLost } = options;\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const initialTtlSeconds =\n typeof options.initialTtlSeconds === \"number\" &&\n Number.isFinite(options.initialTtlSeconds)\n ? options.initialTtlSeconds\n : fallbackTtlSeconds;\n let deadline = Date.now() + initialTtlSeconds * 1_000;\n let failedAttempts = 0;\n\n const schedule = (delayMs: number): void => {\n timer = setTimeout(() => {\n timer = undefined;\n void attempt();\n }, delayMs);\n if (options.unref) timer.unref?.();\n };\n\n /** Time left before the safety cutoff ahead of the lock's expiry. */\n const remainingMs = (): number =>\n deadline - DEADLINE_SAFETY_MARGIN_MS - Date.now();\n\n // Renew on the interval, or right away when waiting that long would run\n // past the cutoff and leave the lock to lapse.\n const scheduleRenewal = (): void => {\n schedule(intervalMs < remainingMs() ? intervalMs : 0);\n };\n\n const stop = (): void => {\n stopped = true;\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n }\n };\n\n const lose = (error: unknown): void => {\n stop();\n onLost(error);\n };\n\n const attempt = async (): Promise<void> => {\n // Bound each attempt by the lock's remaining lifetime so a hung request\n // cannot silently outlive the lock; past the cutoff, renewing is too late.\n const timeoutMs = Math.min(ATTEMPT_TIMEOUT_MS, remainingMs());\n if (timeoutMs <= 0) {\n lose(new Error(\"Thread lock expired before it could be renewed\"));\n return;\n }\n const sentAt = Date.now();\n const controller = new AbortController();\n let response: RenewThreadLockResponse;\n try {\n response = await withTimeout(\n renew(controller.signal),\n timeoutMs,\n options.unref,\n () => controller.abort(),\n );\n } catch (error) {\n if (!stopped) handleFailure(error);\n return;\n }\n if (stopped) return;\n\n failedAttempts = 0;\n if (response?.status === \"completed\") {\n stop();\n return;\n }\n const ttlSeconds =\n typeof response?.ttlSeconds === \"number\" && response.ttlSeconds > 0\n ? response.ttlSeconds\n : fallbackTtlSeconds;\n deadline = sentAt + ttlSeconds * 1_000;\n scheduleRenewal();\n };\n\n const handleFailure = (error: unknown): void => {\n if (!isRetryableLockRenewalError(error)) {\n lose(error);\n return;\n }\n const delayMs = Math.min(\n INITIAL_RETRY_DELAY_MS * 2 ** failedAttempts,\n MAX_RETRY_DELAY_MS,\n );\n failedAttempts += 1;\n const remaining = remainingMs();\n if (delayMs >= remaining) {\n lose(error);\n return;\n }\n logger.warn(\n {\n err: error,\n attempt: failedAttempts,\n retryInMs: delayMs,\n remainingMs: remaining,\n },\n \"Thread lock renewal failed; retrying before the lock expires\",\n );\n schedule(delayMs);\n };\n\n scheduleRenewal();\n return { stop };\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n unref: boolean | undefined,\n onTimeout: () => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timeout = setTimeout(() => {\n onTimeout();\n reject(new RenewalTimeoutError(timeoutMs));\n }, timeoutMs);\n if (unref) timeout.unref?.();\n promise.then(\n (value) => {\n clearTimeout(timeout);\n resolve(value);\n },\n (error: unknown) => {\n clearTimeout(timeout);\n reject(error);\n },\n );\n });\n}\n"],"mappings":";;;;;;;AAKA,MAAM,yBAAyB;;AAE/B,MAAM,qBAAqB;;AAE3B,MAAM,qBAAqB;;AAE3B,MAAM,4BAA4B;AAuClC,IAAM,sBAAN,cAAkC,MAAM;CACtC,YAAY,WAAmB;AAC7B,QAAM,6CAA6C,UAAU,IAAI;AACjE,OAAK,OAAO;;;;;;;;AAShB,SAAgB,4BAA4B,OAAyB;AACnE,KAAI,iBAAiBA,qCAAsB;AACzC,MAAI,MAAM,cAAc,OAAW,QAAO,MAAM;AAChD,SAAO,MAAM,UAAU,OAAO,MAAM,WAAW,OAAO,MAAM,WAAW;;AAGzE,QAAO;;;;;;;;;;;;;;;;AAiBT,SAAgB,yBACd,SACqB;CACrB,MAAM,EAAE,OAAO,YAAY,oBAAoB,WAAW;CAC1D,IAAI,UAAU;CACd,IAAI;CACJ,MAAM,oBACJ,OAAO,QAAQ,sBAAsB,YACrC,OAAO,SAAS,QAAQ,kBAAkB,GACtC,QAAQ,oBACR;CACN,IAAI,WAAW,KAAK,KAAK,GAAG,oBAAoB;CAChD,IAAI,iBAAiB;CAErB,MAAM,YAAY,YAA0B;AAC1C,UAAQ,iBAAiB;AACvB,WAAQ;AACR,GAAK,SAAS;KACb,QAAQ;AACX,MAAI,QAAQ,MAAO,OAAM,SAAS;;;CAIpC,MAAM,oBACJ,WAAW,4BAA4B,KAAK,KAAK;CAInD,MAAM,wBAA8B;AAClC,WAAS,aAAa,aAAa,GAAG,aAAa,EAAE;;CAGvD,MAAM,aAAmB;AACvB,YAAU;AACV,MAAI,UAAU,QAAW;AACvB,gBAAa,MAAM;AACnB,WAAQ;;;CAIZ,MAAM,QAAQ,UAAyB;AACrC,QAAM;AACN,SAAO,MAAM;;CAGf,MAAM,UAAU,YAA2B;EAGzC,MAAM,YAAY,KAAK,IAAI,oBAAoB,aAAa,CAAC;AAC7D,MAAI,aAAa,GAAG;AAClB,wBAAK,IAAI,MAAM,iDAAiD,CAAC;AACjE;;EAEF,MAAM,SAAS,KAAK,KAAK;EACzB,MAAM,aAAa,IAAI,iBAAiB;EACxC,IAAI;AACJ,MAAI;AACF,cAAW,MAAM,YACf,MAAM,WAAW,OAAO,EACxB,WACA,QAAQ,aACF,WAAW,OAAO,CACzB;WACM,OAAO;AACd,OAAI,CAAC,QAAS,eAAc,MAAM;AAClC;;AAEF,MAAI,QAAS;AAEb,mBAAiB;AACjB,MAAI,UAAU,WAAW,aAAa;AACpC,SAAM;AACN;;AAMF,aAAW,UAHT,OAAO,UAAU,eAAe,YAAY,SAAS,aAAa,IAC9D,SAAS,aACT,sBAC2B;AACjC,mBAAiB;;CAGnB,MAAM,iBAAiB,UAAyB;AAC9C,MAAI,CAAC,4BAA4B,MAAM,EAAE;AACvC,QAAK,MAAM;AACX;;EAEF,MAAM,UAAU,KAAK,IACnB,yBAAyB,KAAK,gBAC9B,mBACD;AACD,oBAAkB;EAClB,MAAM,YAAY,aAAa;AAC/B,MAAI,WAAW,WAAW;AACxB,QAAK,MAAM;AACX;;AAEF,4BAAO,KACL;GACE,KAAK;GACL,SAAS;GACT,WAAW;GACX,aAAa;GACd,EACD,+DACD;AACD,WAAS,QAAQ;;AAGnB,kBAAiB;AACjB,QAAO,EAAE,MAAM;;AAGjB,SAAS,YACP,SACA,WACA,OACA,WACY;AACZ,QAAO,IAAI,SAAY,SAAS,WAAW;EACzC,MAAM,UAAU,iBAAiB;AAC/B,cAAW;AACX,UAAO,IAAI,oBAAoB,UAAU,CAAC;KACzC,UAAU;AACb,MAAI,MAAO,SAAQ,SAAS;AAC5B,UAAQ,MACL,UAAU;AACT,gBAAa,QAAQ;AACrB,WAAQ,MAAM;MAEf,UAAmB;AAClB,gBAAa,QAAQ;AACrB,UAAO,MAAM;IAEhB;GACD"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { PlatformRequestError } from "./client.mjs";
|
|
3
|
+
import { logger } from "@copilotkit/shared";
|
|
4
|
+
|
|
5
|
+
//#region src/v2/runtime/intelligence-platform/thread-lock-heartbeat.ts
|
|
6
|
+
/** Delay before the first retry of a failed renewal; doubles per attempt. */
|
|
7
|
+
const INITIAL_RETRY_DELAY_MS = 1e3;
|
|
8
|
+
/** Upper bound for the delay between renewal retries. */
|
|
9
|
+
const MAX_RETRY_DELAY_MS = 8e3;
|
|
10
|
+
/** Longest a single renewal may stay in flight before it counts as failed. */
|
|
11
|
+
const ATTEMPT_TIMEOUT_MS = 1e4;
|
|
12
|
+
/** Stop retrying this long before the lock would expire. */
|
|
13
|
+
const DEADLINE_SAFETY_MARGIN_MS = 1e3;
|
|
14
|
+
var RenewalTimeoutError = class extends Error {
|
|
15
|
+
constructor(timeoutMs) {
|
|
16
|
+
super(`Thread lock renewal did not settle within ${timeoutMs}ms`);
|
|
17
|
+
this.name = "RenewalTimeoutError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Whether a failed renewal may succeed if retried. A lost lock is a 409 the
|
|
22
|
+
* platform marks `retryable: false`; server failures (5xx), timeouts and
|
|
23
|
+
* network errors are worth retrying while the lock is still valid.
|
|
24
|
+
*/
|
|
25
|
+
function isRetryableLockRenewalError(error) {
|
|
26
|
+
if (error instanceof PlatformRequestError) {
|
|
27
|
+
if (error.retryable !== void 0) return error.retryable;
|
|
28
|
+
return error.status >= 500 || error.status === 408 || error.status === 429;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Keep a thread lock alive for a running agent.
|
|
34
|
+
*
|
|
35
|
+
* Renews every `intervalMs` (sooner if that would run past the lock's
|
|
36
|
+
* lifetime), with at most one renewal in flight. A failed renewal is retried
|
|
37
|
+
* with exponential backoff while the lock is still valid: the deadline is when
|
|
38
|
+
* the last successful renewal was *sent* plus the `ttlSeconds` it returned,
|
|
39
|
+
* because the platform starts the TTL when it handles the request (initially
|
|
40
|
+
* start plus `initialTtlSeconds`, or `fallbackTtlSeconds` when the platform
|
|
41
|
+
* reported no lifetime at acquisition). A non-retryable failure, or running
|
|
42
|
+
* out of time before the deadline, calls `onLost`.
|
|
43
|
+
* A `"completed"` response means the run already ended on the platform, so
|
|
44
|
+
* the heartbeat stops without calling `onLost`.
|
|
45
|
+
*/
|
|
46
|
+
function startThreadLockHeartbeat(options) {
|
|
47
|
+
const { renew, intervalMs, fallbackTtlSeconds, onLost } = options;
|
|
48
|
+
let stopped = false;
|
|
49
|
+
let timer;
|
|
50
|
+
const initialTtlSeconds = typeof options.initialTtlSeconds === "number" && Number.isFinite(options.initialTtlSeconds) ? options.initialTtlSeconds : fallbackTtlSeconds;
|
|
51
|
+
let deadline = Date.now() + initialTtlSeconds * 1e3;
|
|
52
|
+
let failedAttempts = 0;
|
|
53
|
+
const schedule = (delayMs) => {
|
|
54
|
+
timer = setTimeout(() => {
|
|
55
|
+
timer = void 0;
|
|
56
|
+
attempt();
|
|
57
|
+
}, delayMs);
|
|
58
|
+
if (options.unref) timer.unref?.();
|
|
59
|
+
};
|
|
60
|
+
/** Time left before the safety cutoff ahead of the lock's expiry. */
|
|
61
|
+
const remainingMs = () => deadline - DEADLINE_SAFETY_MARGIN_MS - Date.now();
|
|
62
|
+
const scheduleRenewal = () => {
|
|
63
|
+
schedule(intervalMs < remainingMs() ? intervalMs : 0);
|
|
64
|
+
};
|
|
65
|
+
const stop = () => {
|
|
66
|
+
stopped = true;
|
|
67
|
+
if (timer !== void 0) {
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
timer = void 0;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const lose = (error) => {
|
|
73
|
+
stop();
|
|
74
|
+
onLost(error);
|
|
75
|
+
};
|
|
76
|
+
const attempt = async () => {
|
|
77
|
+
const timeoutMs = Math.min(ATTEMPT_TIMEOUT_MS, remainingMs());
|
|
78
|
+
if (timeoutMs <= 0) {
|
|
79
|
+
lose(/* @__PURE__ */ new Error("Thread lock expired before it could be renewed"));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const sentAt = Date.now();
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
let response;
|
|
85
|
+
try {
|
|
86
|
+
response = await withTimeout(renew(controller.signal), timeoutMs, options.unref, () => controller.abort());
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (!stopped) handleFailure(error);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (stopped) return;
|
|
92
|
+
failedAttempts = 0;
|
|
93
|
+
if (response?.status === "completed") {
|
|
94
|
+
stop();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
deadline = sentAt + (typeof response?.ttlSeconds === "number" && response.ttlSeconds > 0 ? response.ttlSeconds : fallbackTtlSeconds) * 1e3;
|
|
98
|
+
scheduleRenewal();
|
|
99
|
+
};
|
|
100
|
+
const handleFailure = (error) => {
|
|
101
|
+
if (!isRetryableLockRenewalError(error)) {
|
|
102
|
+
lose(error);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const delayMs = Math.min(INITIAL_RETRY_DELAY_MS * 2 ** failedAttempts, MAX_RETRY_DELAY_MS);
|
|
106
|
+
failedAttempts += 1;
|
|
107
|
+
const remaining = remainingMs();
|
|
108
|
+
if (delayMs >= remaining) {
|
|
109
|
+
lose(error);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
logger.warn({
|
|
113
|
+
err: error,
|
|
114
|
+
attempt: failedAttempts,
|
|
115
|
+
retryInMs: delayMs,
|
|
116
|
+
remainingMs: remaining
|
|
117
|
+
}, "Thread lock renewal failed; retrying before the lock expires");
|
|
118
|
+
schedule(delayMs);
|
|
119
|
+
};
|
|
120
|
+
scheduleRenewal();
|
|
121
|
+
return { stop };
|
|
122
|
+
}
|
|
123
|
+
function withTimeout(promise, timeoutMs, unref, onTimeout) {
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
const timeout = setTimeout(() => {
|
|
126
|
+
onTimeout();
|
|
127
|
+
reject(new RenewalTimeoutError(timeoutMs));
|
|
128
|
+
}, timeoutMs);
|
|
129
|
+
if (unref) timeout.unref?.();
|
|
130
|
+
promise.then((value) => {
|
|
131
|
+
clearTimeout(timeout);
|
|
132
|
+
resolve(value);
|
|
133
|
+
}, (error) => {
|
|
134
|
+
clearTimeout(timeout);
|
|
135
|
+
reject(error);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
export { startThreadLockHeartbeat };
|
|
142
|
+
//# sourceMappingURL=thread-lock-heartbeat.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-lock-heartbeat.mjs","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/thread-lock-heartbeat.ts"],"sourcesContent":["import { logger } from \"@copilotkit/shared\";\nimport { PlatformRequestError } from \"./client\";\nimport type { RenewThreadLockResponse } from \"./client\";\n\n/** Delay before the first retry of a failed renewal; doubles per attempt. */\nconst INITIAL_RETRY_DELAY_MS = 1_000;\n/** Upper bound for the delay between renewal retries. */\nconst MAX_RETRY_DELAY_MS = 8_000;\n/** Longest a single renewal may stay in flight before it counts as failed. */\nconst ATTEMPT_TIMEOUT_MS = 10_000;\n/** Stop retrying this long before the lock would expire. */\nconst DEADLINE_SAFETY_MARGIN_MS = 1_000;\n\nexport interface ThreadLockHeartbeatOptions {\n /**\n * Sends one renewal request. The signal aborts when the attempt times out,\n * so an abandoned request never overlaps its retry.\n */\n renew: (signal: AbortSignal) => Promise<RenewThreadLockResponse>;\n /** Delay between successful renewals. */\n intervalMs: number;\n /**\n * Lock lifetime assumed when the platform has not reported one: until the\n * first successful renewal when {@link initialTtlSeconds} is absent, and\n * for renewal responses that omit `ttlSeconds`.\n */\n fallbackTtlSeconds: number;\n /**\n * Remaining lock lifetime when the heartbeat starts, as reported by the\n * platform at acquisition, measured from when the acquire request was sent.\n * Used until the first successful renewal; when absent,\n * {@link fallbackTtlSeconds} applies instead. A value of zero or less means\n * the lock has already expired.\n */\n initialTtlSeconds?: number;\n /**\n * Called once when the lock can no longer be kept: a non-retryable failure,\n * or retryable failures that ran out the lock's remaining lifetime. Never\n * called after {@link ThreadLockHeartbeat.stop}.\n */\n onLost: (error: unknown) => void;\n /** Unref timers so a pending heartbeat never keeps the process alive. */\n unref?: boolean;\n}\n\nexport interface ThreadLockHeartbeat {\n /** Cancel the next renewal and any pending retry. Idempotent. */\n stop(): void;\n}\n\nclass RenewalTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Thread lock renewal did not settle within ${timeoutMs}ms`);\n this.name = \"RenewalTimeoutError\";\n }\n}\n\n/**\n * Whether a failed renewal may succeed if retried. A lost lock is a 409 the\n * platform marks `retryable: false`; server failures (5xx), timeouts and\n * network errors are worth retrying while the lock is still valid.\n */\nexport function isRetryableLockRenewalError(error: unknown): boolean {\n if (error instanceof PlatformRequestError) {\n if (error.retryable !== undefined) return error.retryable;\n return error.status >= 500 || error.status === 408 || error.status === 429;\n }\n // Timeouts, fetch network failures and malformed responses.\n return true;\n}\n\n/**\n * Keep a thread lock alive for a running agent.\n *\n * Renews every `intervalMs` (sooner if that would run past the lock's\n * lifetime), with at most one renewal in flight. A failed renewal is retried\n * with exponential backoff while the lock is still valid: the deadline is when\n * the last successful renewal was *sent* plus the `ttlSeconds` it returned,\n * because the platform starts the TTL when it handles the request (initially\n * start plus `initialTtlSeconds`, or `fallbackTtlSeconds` when the platform\n * reported no lifetime at acquisition). A non-retryable failure, or running\n * out of time before the deadline, calls `onLost`.\n * A `\"completed\"` response means the run already ended on the platform, so\n * the heartbeat stops without calling `onLost`.\n */\nexport function startThreadLockHeartbeat(\n options: ThreadLockHeartbeatOptions,\n): ThreadLockHeartbeat {\n const { renew, intervalMs, fallbackTtlSeconds, onLost } = options;\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const initialTtlSeconds =\n typeof options.initialTtlSeconds === \"number\" &&\n Number.isFinite(options.initialTtlSeconds)\n ? options.initialTtlSeconds\n : fallbackTtlSeconds;\n let deadline = Date.now() + initialTtlSeconds * 1_000;\n let failedAttempts = 0;\n\n const schedule = (delayMs: number): void => {\n timer = setTimeout(() => {\n timer = undefined;\n void attempt();\n }, delayMs);\n if (options.unref) timer.unref?.();\n };\n\n /** Time left before the safety cutoff ahead of the lock's expiry. */\n const remainingMs = (): number =>\n deadline - DEADLINE_SAFETY_MARGIN_MS - Date.now();\n\n // Renew on the interval, or right away when waiting that long would run\n // past the cutoff and leave the lock to lapse.\n const scheduleRenewal = (): void => {\n schedule(intervalMs < remainingMs() ? intervalMs : 0);\n };\n\n const stop = (): void => {\n stopped = true;\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n }\n };\n\n const lose = (error: unknown): void => {\n stop();\n onLost(error);\n };\n\n const attempt = async (): Promise<void> => {\n // Bound each attempt by the lock's remaining lifetime so a hung request\n // cannot silently outlive the lock; past the cutoff, renewing is too late.\n const timeoutMs = Math.min(ATTEMPT_TIMEOUT_MS, remainingMs());\n if (timeoutMs <= 0) {\n lose(new Error(\"Thread lock expired before it could be renewed\"));\n return;\n }\n const sentAt = Date.now();\n const controller = new AbortController();\n let response: RenewThreadLockResponse;\n try {\n response = await withTimeout(\n renew(controller.signal),\n timeoutMs,\n options.unref,\n () => controller.abort(),\n );\n } catch (error) {\n if (!stopped) handleFailure(error);\n return;\n }\n if (stopped) return;\n\n failedAttempts = 0;\n if (response?.status === \"completed\") {\n stop();\n return;\n }\n const ttlSeconds =\n typeof response?.ttlSeconds === \"number\" && response.ttlSeconds > 0\n ? response.ttlSeconds\n : fallbackTtlSeconds;\n deadline = sentAt + ttlSeconds * 1_000;\n scheduleRenewal();\n };\n\n const handleFailure = (error: unknown): void => {\n if (!isRetryableLockRenewalError(error)) {\n lose(error);\n return;\n }\n const delayMs = Math.min(\n INITIAL_RETRY_DELAY_MS * 2 ** failedAttempts,\n MAX_RETRY_DELAY_MS,\n );\n failedAttempts += 1;\n const remaining = remainingMs();\n if (delayMs >= remaining) {\n lose(error);\n return;\n }\n logger.warn(\n {\n err: error,\n attempt: failedAttempts,\n retryInMs: delayMs,\n remainingMs: remaining,\n },\n \"Thread lock renewal failed; retrying before the lock expires\",\n );\n schedule(delayMs);\n };\n\n scheduleRenewal();\n return { stop };\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n unref: boolean | undefined,\n onTimeout: () => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timeout = setTimeout(() => {\n onTimeout();\n reject(new RenewalTimeoutError(timeoutMs));\n }, timeoutMs);\n if (unref) timeout.unref?.();\n promise.then(\n (value) => {\n clearTimeout(timeout);\n resolve(value);\n },\n (error: unknown) => {\n clearTimeout(timeout);\n reject(error);\n },\n );\n });\n}\n"],"mappings":";;;;;;AAKA,MAAM,yBAAyB;;AAE/B,MAAM,qBAAqB;;AAE3B,MAAM,qBAAqB;;AAE3B,MAAM,4BAA4B;AAuClC,IAAM,sBAAN,cAAkC,MAAM;CACtC,YAAY,WAAmB;AAC7B,QAAM,6CAA6C,UAAU,IAAI;AACjE,OAAK,OAAO;;;;;;;;AAShB,SAAgB,4BAA4B,OAAyB;AACnE,KAAI,iBAAiB,sBAAsB;AACzC,MAAI,MAAM,cAAc,OAAW,QAAO,MAAM;AAChD,SAAO,MAAM,UAAU,OAAO,MAAM,WAAW,OAAO,MAAM,WAAW;;AAGzE,QAAO;;;;;;;;;;;;;;;;AAiBT,SAAgB,yBACd,SACqB;CACrB,MAAM,EAAE,OAAO,YAAY,oBAAoB,WAAW;CAC1D,IAAI,UAAU;CACd,IAAI;CACJ,MAAM,oBACJ,OAAO,QAAQ,sBAAsB,YACrC,OAAO,SAAS,QAAQ,kBAAkB,GACtC,QAAQ,oBACR;CACN,IAAI,WAAW,KAAK,KAAK,GAAG,oBAAoB;CAChD,IAAI,iBAAiB;CAErB,MAAM,YAAY,YAA0B;AAC1C,UAAQ,iBAAiB;AACvB,WAAQ;AACR,GAAK,SAAS;KACb,QAAQ;AACX,MAAI,QAAQ,MAAO,OAAM,SAAS;;;CAIpC,MAAM,oBACJ,WAAW,4BAA4B,KAAK,KAAK;CAInD,MAAM,wBAA8B;AAClC,WAAS,aAAa,aAAa,GAAG,aAAa,EAAE;;CAGvD,MAAM,aAAmB;AACvB,YAAU;AACV,MAAI,UAAU,QAAW;AACvB,gBAAa,MAAM;AACnB,WAAQ;;;CAIZ,MAAM,QAAQ,UAAyB;AACrC,QAAM;AACN,SAAO,MAAM;;CAGf,MAAM,UAAU,YAA2B;EAGzC,MAAM,YAAY,KAAK,IAAI,oBAAoB,aAAa,CAAC;AAC7D,MAAI,aAAa,GAAG;AAClB,wBAAK,IAAI,MAAM,iDAAiD,CAAC;AACjE;;EAEF,MAAM,SAAS,KAAK,KAAK;EACzB,MAAM,aAAa,IAAI,iBAAiB;EACxC,IAAI;AACJ,MAAI;AACF,cAAW,MAAM,YACf,MAAM,WAAW,OAAO,EACxB,WACA,QAAQ,aACF,WAAW,OAAO,CACzB;WACM,OAAO;AACd,OAAI,CAAC,QAAS,eAAc,MAAM;AAClC;;AAEF,MAAI,QAAS;AAEb,mBAAiB;AACjB,MAAI,UAAU,WAAW,aAAa;AACpC,SAAM;AACN;;AAMF,aAAW,UAHT,OAAO,UAAU,eAAe,YAAY,SAAS,aAAa,IAC9D,SAAS,aACT,sBAC2B;AACjC,mBAAiB;;CAGnB,MAAM,iBAAiB,UAAyB;AAC9C,MAAI,CAAC,4BAA4B,MAAM,EAAE;AACvC,QAAK,MAAM;AACX;;EAEF,MAAM,UAAU,KAAK,IACnB,yBAAyB,KAAK,gBAC9B,mBACD;AACD,oBAAkB;EAClB,MAAM,YAAY,aAAa;AAC/B,MAAI,WAAW,WAAW;AACxB,QAAK,MAAM;AACX;;AAEF,SAAO,KACL;GACE,KAAK;GACL,SAAS;GACT,WAAW;GACX,aAAa;GACd,EACD,+DACD;AACD,WAAS,QAAQ;;AAGnB,kBAAiB;AACjB,QAAO,EAAE,MAAM;;AAGjB,SAAS,YACP,SACA,WACA,OACA,WACY;AACZ,QAAO,IAAI,SAAY,SAAS,WAAW;EACzC,MAAM,UAAU,iBAAiB;AAC/B,cAAW;AACX,UAAO,IAAI,oBAAoB,UAAU,CAAC;KACzC,UAAU;AACb,MAAI,MAAO,SAAQ,SAAS;AAC5B,UAAQ,MACL,UAAU;AACT,gBAAa,QAAQ;AACrB,WAAQ,MAAM;MAEf,UAAmB;AAClB,gBAAa,QAAQ;AACrB,UAAO,MAAM;IAEhB;GACD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require("reflect-metadata");
|
|
2
2
|
const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
let _copilotkit_shared = require("@copilotkit/shared");
|
|
3
4
|
let zod = require("zod");
|
|
4
5
|
|
|
5
6
|
//#region src/v2/runtime/intelligence-platform/trajectories.ts
|
|
@@ -34,7 +35,8 @@ const contractErrorSchema = zod.z.object({ error: zod.z.object({
|
|
|
34
35
|
"LEARNING_CONTAINER_NOT_FOUND",
|
|
35
36
|
"RATE_LIMIT_EXCEEDED",
|
|
36
37
|
"INTERNAL_SERVER_ERROR",
|
|
37
|
-
"MARKETPLACE_LICENSE_REQUIRED"
|
|
38
|
+
"MARKETPLACE_LICENSE_REQUIRED",
|
|
39
|
+
"TRAJECTORIES_NOT_ENABLED"
|
|
38
40
|
]),
|
|
39
41
|
message: zod.z.string().trim().min(1).max(512)
|
|
40
42
|
}) });
|
|
@@ -55,7 +57,11 @@ function parseTrajectoryConnectionGrant(value, trajectoryId, clientUrl) {
|
|
|
55
57
|
topic: `trajectory:${trajectoryId}`
|
|
56
58
|
}
|
|
57
59
|
} : void 0);
|
|
58
|
-
if (!result.success)
|
|
60
|
+
if (!result.success) {
|
|
61
|
+
const joinValid = join.success && join.data.trajectoryId === trajectoryId;
|
|
62
|
+
_copilotkit_shared.logger.warn({ trajectoryIdMatches: joinValid }, joinValid ? "Intelligence returned a Trajectory join token, but the Gateway URL is invalid; check the Intelligence wsUrl" : "Intelligence returned an invalid Trajectory join response");
|
|
63
|
+
throw new TrajectoryConnectionError("CONNECTION_FAILED", "Intelligence returned an invalid trajectory connection grant", 502);
|
|
64
|
+
}
|
|
59
65
|
return {
|
|
60
66
|
joinToken: result.data.joinToken,
|
|
61
67
|
realtime: {
|
|
@@ -64,11 +70,21 @@ function parseTrajectoryConnectionGrant(value, trajectoryId, clientUrl) {
|
|
|
64
70
|
}
|
|
65
71
|
};
|
|
66
72
|
}
|
|
73
|
+
const routeNotFoundSchema = zod.z.object({ error: zod.z.object({ code: zod.z.literal("ROUTE_NOT_FOUND") }) });
|
|
74
|
+
const upstreamCodeSchema = zod.z.object({ error: zod.z.object({ code: zod.z.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/) }) });
|
|
67
75
|
/** Forward only the public contract, never raw platform errors or credentials. */
|
|
68
76
|
function trajectoryResponseError(value, status, apiKey) {
|
|
69
|
-
if (runtimeConfigurationErrorSchema.safeParse(value).success) return new TrajectoryConnectionError("CONNECTION_FAILED", "Could not connect to Intelligence", 502);
|
|
70
77
|
const result = contractErrorSchema.safeParse(value);
|
|
71
78
|
if (result.success && !result.data.error.message.includes(apiKey)) return new TrajectoryConnectionError(result.data.error.code, result.data.error.message, status);
|
|
79
|
+
if (status === 404 && routeNotFoundSchema.safeParse(value).success) {
|
|
80
|
+
_copilotkit_shared.logger.warn({ status }, "Intelligence does not serve Trajectory capture; enable Trajectories for this deployment");
|
|
81
|
+
return new TrajectoryConnectionError("TRAJECTORIES_UNAVAILABLE", "This Intelligence deployment does not serve Trajectory capture", 404);
|
|
82
|
+
}
|
|
83
|
+
_copilotkit_shared.logger.warn({
|
|
84
|
+
status,
|
|
85
|
+
upstreamCode: upstreamCodeSchema.safeParse(value).data?.error.code
|
|
86
|
+
}, "Intelligence rejected the Trajectory connection request; the browser receives CONNECTION_FAILED");
|
|
87
|
+
if (runtimeConfigurationErrorSchema.safeParse(value).success) return new TrajectoryConnectionError("CONNECTION_FAILED", "Could not connect to Intelligence", 502);
|
|
72
88
|
return new TrajectoryConnectionError("CONNECTION_FAILED", "Intelligence rejected the trajectory connection request", status);
|
|
73
89
|
}
|
|
74
90
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trajectories.cjs","names":["z"],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport interface TrajectoryConnectionGrant {\n joinToken: string;\n realtime: { clientUrl: string; topic: string };\n}\n\nconst trajectoryIdSchema = z.string().uuid();\n\nexport function isValidTrajectoryId(value: unknown): value is string {\n return trajectoryIdSchema.safeParse(value).success;\n}\n\nconst joinResponseSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n trajectoryId: trajectoryIdSchema,\n});\n\nconst grantSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n realtime: z.object({\n clientUrl: z\n .string()\n .url()\n .refine((value) => {\n const url = new URL(value);\n return (\n (url.protocol === \"wss:\" || url.protocol === \"ws:\") &&\n !url.username &&\n !url.password\n );\n }),\n topic: z\n .string()\n .refine((value) => value.trim().length > 0 && !/\\p{Cc}/u.test(value)),\n }),\n});\n\nconst runtimeConfigurationErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"AUTH_UNAUTHENTICATED\",\n \"API_KEY_NOT_FOUND\",\n \"ORG_NOT_FOUND\",\n \"PROJECT_NOT_FOUND\",\n ]),\n }),\n});\n\nconst contractErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"VALIDATION_ERROR\",\n \"TRAJECTORY_APP_USER_CONFLICT\",\n \"LEARNING_CONTAINER_NOT_FOUND\",\n \"RATE_LIMIT_EXCEEDED\",\n \"INTERNAL_SERVER_ERROR\",\n \"MARKETPLACE_LICENSE_REQUIRED\",\n ]),\n message: z.string().trim().min(1).max(512),\n }),\n});\n\nexport class TrajectoryConnectionError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = \"TrajectoryConnectionError\";\n }\n}\n\nexport function parseTrajectoryConnectionGrant(\n value: unknown,\n trajectoryId: string,\n clientUrl: string,\n): TrajectoryConnectionGrant {\n const join = joinResponseSchema.safeParse(value);\n const result = grantSchema.safeParse(\n join.success && join.data.trajectoryId === trajectoryId\n ? {\n joinToken: join.data.joinToken,\n realtime: { clientUrl, topic: `trajectory:${trajectoryId}` },\n }\n : undefined,\n );\n if (!result.success) {\n throw new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Intelligence returned an invalid trajectory connection grant\",\n 502,\n );\n }\n return {\n joinToken: result.data.joinToken,\n realtime: {\n clientUrl: result.data.realtime.clientUrl,\n topic: result.data.realtime.topic,\n },\n };\n}\n\n/** Forward only the public contract, never raw platform errors or credentials. */\nexport function trajectoryResponseError(\n value: unknown,\n status: number,\n apiKey: string,\n): TrajectoryConnectionError {\n // These failures describe the Runtime's server credentials or tenant setup,\n // not the browser user's identity. Do not expose them as a client auth error.\n if (runtimeConfigurationErrorSchema.safeParse(value).success) {\n return new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Could not connect to Intelligence\",\n 502,\n );\n }\n
|
|
1
|
+
{"version":3,"file":"trajectories.cjs","names":["z"],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"sourcesContent":["import { logger } from \"@copilotkit/shared\";\nimport { z } from \"zod\";\n\nexport interface TrajectoryConnectionGrant {\n joinToken: string;\n realtime: { clientUrl: string; topic: string };\n}\n\nconst trajectoryIdSchema = z.string().uuid();\n\nexport function isValidTrajectoryId(value: unknown): value is string {\n return trajectoryIdSchema.safeParse(value).success;\n}\n\nconst joinResponseSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n trajectoryId: trajectoryIdSchema,\n});\n\nconst grantSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n realtime: z.object({\n clientUrl: z\n .string()\n .url()\n .refine((value) => {\n const url = new URL(value);\n return (\n (url.protocol === \"wss:\" || url.protocol === \"ws:\") &&\n !url.username &&\n !url.password\n );\n }),\n topic: z\n .string()\n .refine((value) => value.trim().length > 0 && !/\\p{Cc}/u.test(value)),\n }),\n});\n\nconst runtimeConfigurationErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"AUTH_UNAUTHENTICATED\",\n \"API_KEY_NOT_FOUND\",\n \"ORG_NOT_FOUND\",\n \"PROJECT_NOT_FOUND\",\n ]),\n }),\n});\n\nconst contractErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"VALIDATION_ERROR\",\n \"TRAJECTORY_APP_USER_CONFLICT\",\n \"LEARNING_CONTAINER_NOT_FOUND\",\n \"RATE_LIMIT_EXCEEDED\",\n \"INTERNAL_SERVER_ERROR\",\n \"MARKETPLACE_LICENSE_REQUIRED\",\n \"TRAJECTORIES_NOT_ENABLED\",\n ]),\n message: z.string().trim().min(1).max(512),\n }),\n});\n\nexport class TrajectoryConnectionError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = \"TrajectoryConnectionError\";\n }\n}\n\nexport function parseTrajectoryConnectionGrant(\n value: unknown,\n trajectoryId: string,\n clientUrl: string,\n): TrajectoryConnectionGrant {\n const join = joinResponseSchema.safeParse(value);\n const result = grantSchema.safeParse(\n join.success && join.data.trajectoryId === trajectoryId\n ? {\n joinToken: join.data.joinToken,\n realtime: { clientUrl, topic: `trajectory:${trajectoryId}` },\n }\n : undefined,\n );\n if (!result.success) {\n const joinValid = join.success && join.data.trajectoryId === trajectoryId;\n logger.warn(\n { trajectoryIdMatches: joinValid },\n joinValid\n ? \"Intelligence returned a Trajectory join token, but the Gateway URL is invalid; check the Intelligence wsUrl\"\n : \"Intelligence returned an invalid Trajectory join response\",\n );\n throw new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Intelligence returned an invalid trajectory connection grant\",\n 502,\n );\n }\n return {\n joinToken: result.data.joinToken,\n realtime: {\n clientUrl: result.data.realtime.clientUrl,\n topic: result.data.realtime.topic,\n },\n };\n}\n\n// Intelligence answers with this code when Trajectory capture is switched off\n// for the deployment, because the join route is then not registered.\nconst routeNotFoundSchema = z.object({\n error: z.object({ code: z.literal(\"ROUTE_NOT_FOUND\") }),\n});\n\nconst upstreamCodeSchema = z.object({\n error: z.object({ code: z.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/) }),\n});\n\n/** Forward only the public contract, never raw platform errors or credentials. */\nexport function trajectoryResponseError(\n value: unknown,\n status: number,\n apiKey: string,\n): TrajectoryConnectionError {\n const result = contractErrorSchema.safeParse(value);\n if (result.success && !result.data.error.message.includes(apiKey)) {\n return new TrajectoryConnectionError(\n result.data.error.code,\n result.data.error.message,\n status,\n );\n }\n if (status === 404 && routeNotFoundSchema.safeParse(value).success) {\n logger.warn(\n { status },\n \"Intelligence does not serve Trajectory capture; enable Trajectories for this deployment\",\n );\n return new TrajectoryConnectionError(\n \"TRAJECTORIES_UNAVAILABLE\",\n \"This Intelligence deployment does not serve Trajectory capture\",\n 404,\n );\n }\n // The browser only learns that the connection failed. Log the upstream code,\n // never the message, so the cause is visible to the Runtime's operator.\n logger.warn(\n {\n status,\n upstreamCode: upstreamCodeSchema.safeParse(value).data?.error.code,\n },\n \"Intelligence rejected the Trajectory connection request; the browser receives CONNECTION_FAILED\",\n );\n // These failures describe the Runtime's server credentials or tenant setup,\n // not the browser user's identity. Do not expose them as a client auth error.\n if (runtimeConfigurationErrorSchema.safeParse(value).success) {\n return new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Could not connect to Intelligence\",\n 502,\n );\n }\n return new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Intelligence rejected the trajectory connection request\",\n status,\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trajectories.d.cts","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"trajectories.d.cts","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"mappings":";;UAGiB,yBAAA;EACf,SAAA;EACA,QAAA;IAAY,SAAA;IAAmB,KAAA;EAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trajectories.d.mts","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"trajectories.d.mts","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"mappings":";;UAGiB,yBAAA;EACf,SAAA;EACA,QAAA;IAAY,SAAA;IAAmB,KAAA;EAAA;AAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
+
import { logger } from "@copilotkit/shared";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
|
|
4
5
|
//#region src/v2/runtime/intelligence-platform/trajectories.ts
|
|
@@ -33,7 +34,8 @@ const contractErrorSchema = z.object({ error: z.object({
|
|
|
33
34
|
"LEARNING_CONTAINER_NOT_FOUND",
|
|
34
35
|
"RATE_LIMIT_EXCEEDED",
|
|
35
36
|
"INTERNAL_SERVER_ERROR",
|
|
36
|
-
"MARKETPLACE_LICENSE_REQUIRED"
|
|
37
|
+
"MARKETPLACE_LICENSE_REQUIRED",
|
|
38
|
+
"TRAJECTORIES_NOT_ENABLED"
|
|
37
39
|
]),
|
|
38
40
|
message: z.string().trim().min(1).max(512)
|
|
39
41
|
}) });
|
|
@@ -54,7 +56,11 @@ function parseTrajectoryConnectionGrant(value, trajectoryId, clientUrl) {
|
|
|
54
56
|
topic: `trajectory:${trajectoryId}`
|
|
55
57
|
}
|
|
56
58
|
} : void 0);
|
|
57
|
-
if (!result.success)
|
|
59
|
+
if (!result.success) {
|
|
60
|
+
const joinValid = join.success && join.data.trajectoryId === trajectoryId;
|
|
61
|
+
logger.warn({ trajectoryIdMatches: joinValid }, joinValid ? "Intelligence returned a Trajectory join token, but the Gateway URL is invalid; check the Intelligence wsUrl" : "Intelligence returned an invalid Trajectory join response");
|
|
62
|
+
throw new TrajectoryConnectionError("CONNECTION_FAILED", "Intelligence returned an invalid trajectory connection grant", 502);
|
|
63
|
+
}
|
|
58
64
|
return {
|
|
59
65
|
joinToken: result.data.joinToken,
|
|
60
66
|
realtime: {
|
|
@@ -63,11 +69,21 @@ function parseTrajectoryConnectionGrant(value, trajectoryId, clientUrl) {
|
|
|
63
69
|
}
|
|
64
70
|
};
|
|
65
71
|
}
|
|
72
|
+
const routeNotFoundSchema = z.object({ error: z.object({ code: z.literal("ROUTE_NOT_FOUND") }) });
|
|
73
|
+
const upstreamCodeSchema = z.object({ error: z.object({ code: z.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/) }) });
|
|
66
74
|
/** Forward only the public contract, never raw platform errors or credentials. */
|
|
67
75
|
function trajectoryResponseError(value, status, apiKey) {
|
|
68
|
-
if (runtimeConfigurationErrorSchema.safeParse(value).success) return new TrajectoryConnectionError("CONNECTION_FAILED", "Could not connect to Intelligence", 502);
|
|
69
76
|
const result = contractErrorSchema.safeParse(value);
|
|
70
77
|
if (result.success && !result.data.error.message.includes(apiKey)) return new TrajectoryConnectionError(result.data.error.code, result.data.error.message, status);
|
|
78
|
+
if (status === 404 && routeNotFoundSchema.safeParse(value).success) {
|
|
79
|
+
logger.warn({ status }, "Intelligence does not serve Trajectory capture; enable Trajectories for this deployment");
|
|
80
|
+
return new TrajectoryConnectionError("TRAJECTORIES_UNAVAILABLE", "This Intelligence deployment does not serve Trajectory capture", 404);
|
|
81
|
+
}
|
|
82
|
+
logger.warn({
|
|
83
|
+
status,
|
|
84
|
+
upstreamCode: upstreamCodeSchema.safeParse(value).data?.error.code
|
|
85
|
+
}, "Intelligence rejected the Trajectory connection request; the browser receives CONNECTION_FAILED");
|
|
86
|
+
if (runtimeConfigurationErrorSchema.safeParse(value).success) return new TrajectoryConnectionError("CONNECTION_FAILED", "Could not connect to Intelligence", 502);
|
|
71
87
|
return new TrajectoryConnectionError("CONNECTION_FAILED", "Intelligence rejected the trajectory connection request", status);
|
|
72
88
|
}
|
|
73
89
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trajectories.mjs","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport interface TrajectoryConnectionGrant {\n joinToken: string;\n realtime: { clientUrl: string; topic: string };\n}\n\nconst trajectoryIdSchema = z.string().uuid();\n\nexport function isValidTrajectoryId(value: unknown): value is string {\n return trajectoryIdSchema.safeParse(value).success;\n}\n\nconst joinResponseSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n trajectoryId: trajectoryIdSchema,\n});\n\nconst grantSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n realtime: z.object({\n clientUrl: z\n .string()\n .url()\n .refine((value) => {\n const url = new URL(value);\n return (\n (url.protocol === \"wss:\" || url.protocol === \"ws:\") &&\n !url.username &&\n !url.password\n );\n }),\n topic: z\n .string()\n .refine((value) => value.trim().length > 0 && !/\\p{Cc}/u.test(value)),\n }),\n});\n\nconst runtimeConfigurationErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"AUTH_UNAUTHENTICATED\",\n \"API_KEY_NOT_FOUND\",\n \"ORG_NOT_FOUND\",\n \"PROJECT_NOT_FOUND\",\n ]),\n }),\n});\n\nconst contractErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"VALIDATION_ERROR\",\n \"TRAJECTORY_APP_USER_CONFLICT\",\n \"LEARNING_CONTAINER_NOT_FOUND\",\n \"RATE_LIMIT_EXCEEDED\",\n \"INTERNAL_SERVER_ERROR\",\n \"MARKETPLACE_LICENSE_REQUIRED\",\n ]),\n message: z.string().trim().min(1).max(512),\n }),\n});\n\nexport class TrajectoryConnectionError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = \"TrajectoryConnectionError\";\n }\n}\n\nexport function parseTrajectoryConnectionGrant(\n value: unknown,\n trajectoryId: string,\n clientUrl: string,\n): TrajectoryConnectionGrant {\n const join = joinResponseSchema.safeParse(value);\n const result = grantSchema.safeParse(\n join.success && join.data.trajectoryId === trajectoryId\n ? {\n joinToken: join.data.joinToken,\n realtime: { clientUrl, topic: `trajectory:${trajectoryId}` },\n }\n : undefined,\n );\n if (!result.success) {\n throw new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Intelligence returned an invalid trajectory connection grant\",\n 502,\n );\n }\n return {\n joinToken: result.data.joinToken,\n realtime: {\n clientUrl: result.data.realtime.clientUrl,\n topic: result.data.realtime.topic,\n },\n };\n}\n\n/** Forward only the public contract, never raw platform errors or credentials. */\nexport function trajectoryResponseError(\n value: unknown,\n status: number,\n apiKey: string,\n): TrajectoryConnectionError {\n // These failures describe the Runtime's server credentials or tenant setup,\n // not the browser user's identity. Do not expose them as a client auth error.\n if (runtimeConfigurationErrorSchema.safeParse(value).success) {\n return new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Could not connect to Intelligence\",\n 502,\n );\n }\n
|
|
1
|
+
{"version":3,"file":"trajectories.mjs","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/trajectories.ts"],"sourcesContent":["import { logger } from \"@copilotkit/shared\";\nimport { z } from \"zod\";\n\nexport interface TrajectoryConnectionGrant {\n joinToken: string;\n realtime: { clientUrl: string; topic: string };\n}\n\nconst trajectoryIdSchema = z.string().uuid();\n\nexport function isValidTrajectoryId(value: unknown): value is string {\n return trajectoryIdSchema.safeParse(value).success;\n}\n\nconst joinResponseSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n trajectoryId: trajectoryIdSchema,\n});\n\nconst grantSchema = z.object({\n joinToken: z.string().refine((value) => value.trim().length > 0),\n realtime: z.object({\n clientUrl: z\n .string()\n .url()\n .refine((value) => {\n const url = new URL(value);\n return (\n (url.protocol === \"wss:\" || url.protocol === \"ws:\") &&\n !url.username &&\n !url.password\n );\n }),\n topic: z\n .string()\n .refine((value) => value.trim().length > 0 && !/\\p{Cc}/u.test(value)),\n }),\n});\n\nconst runtimeConfigurationErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"AUTH_UNAUTHENTICATED\",\n \"API_KEY_NOT_FOUND\",\n \"ORG_NOT_FOUND\",\n \"PROJECT_NOT_FOUND\",\n ]),\n }),\n});\n\nconst contractErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"VALIDATION_ERROR\",\n \"TRAJECTORY_APP_USER_CONFLICT\",\n \"LEARNING_CONTAINER_NOT_FOUND\",\n \"RATE_LIMIT_EXCEEDED\",\n \"INTERNAL_SERVER_ERROR\",\n \"MARKETPLACE_LICENSE_REQUIRED\",\n \"TRAJECTORIES_NOT_ENABLED\",\n ]),\n message: z.string().trim().min(1).max(512),\n }),\n});\n\nexport class TrajectoryConnectionError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = \"TrajectoryConnectionError\";\n }\n}\n\nexport function parseTrajectoryConnectionGrant(\n value: unknown,\n trajectoryId: string,\n clientUrl: string,\n): TrajectoryConnectionGrant {\n const join = joinResponseSchema.safeParse(value);\n const result = grantSchema.safeParse(\n join.success && join.data.trajectoryId === trajectoryId\n ? {\n joinToken: join.data.joinToken,\n realtime: { clientUrl, topic: `trajectory:${trajectoryId}` },\n }\n : undefined,\n );\n if (!result.success) {\n const joinValid = join.success && join.data.trajectoryId === trajectoryId;\n logger.warn(\n { trajectoryIdMatches: joinValid },\n joinValid\n ? \"Intelligence returned a Trajectory join token, but the Gateway URL is invalid; check the Intelligence wsUrl\"\n : \"Intelligence returned an invalid Trajectory join response\",\n );\n throw new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Intelligence returned an invalid trajectory connection grant\",\n 502,\n );\n }\n return {\n joinToken: result.data.joinToken,\n realtime: {\n clientUrl: result.data.realtime.clientUrl,\n topic: result.data.realtime.topic,\n },\n };\n}\n\n// Intelligence answers with this code when Trajectory capture is switched off\n// for the deployment, because the join route is then not registered.\nconst routeNotFoundSchema = z.object({\n error: z.object({ code: z.literal(\"ROUTE_NOT_FOUND\") }),\n});\n\nconst upstreamCodeSchema = z.object({\n error: z.object({ code: z.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/) }),\n});\n\n/** Forward only the public contract, never raw platform errors or credentials. */\nexport function trajectoryResponseError(\n value: unknown,\n status: number,\n apiKey: string,\n): TrajectoryConnectionError {\n const result = contractErrorSchema.safeParse(value);\n if (result.success && !result.data.error.message.includes(apiKey)) {\n return new TrajectoryConnectionError(\n result.data.error.code,\n result.data.error.message,\n status,\n );\n }\n if (status === 404 && routeNotFoundSchema.safeParse(value).success) {\n logger.warn(\n { status },\n \"Intelligence does not serve Trajectory capture; enable Trajectories for this deployment\",\n );\n return new TrajectoryConnectionError(\n \"TRAJECTORIES_UNAVAILABLE\",\n \"This Intelligence deployment does not serve Trajectory capture\",\n 404,\n );\n }\n // The browser only learns that the connection failed. Log the upstream code,\n // never the message, so the cause is visible to the Runtime's operator.\n logger.warn(\n {\n status,\n upstreamCode: upstreamCodeSchema.safeParse(value).data?.error.code,\n },\n \"Intelligence rejected the Trajectory connection request; the browser receives CONNECTION_FAILED\",\n );\n // These failures describe the Runtime's server credentials or tenant setup,\n // not the browser user's identity. Do not expose them as a client auth error.\n if (runtimeConfigurationErrorSchema.safeParse(value).success) {\n return new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Could not connect to Intelligence\",\n 502,\n );\n }\n return new TrajectoryConnectionError(\n \"CONNECTION_FAILED\",\n \"Intelligence rejected the trajectory connection request\",\n status,\n );\n}\n"],"mappings":"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"}
|
|
@@ -41,12 +41,19 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
41
41
|
* socket.disconnect() in an onError handler will set
|
|
42
42
|
* closeWasClean = true and reset the reconnect timer — permanently
|
|
43
43
|
* killing retries.
|
|
44
|
+
*
|
|
45
|
+
* heartbeatIntervalMs — how often Phoenix pings the server
|
|
46
|
+
* (default 15s). Phoenix's own default is 30s, which equals a common
|
|
47
|
+
* reverse-proxy WebSocket idle timeout (e.g. Azure Application Gateway
|
|
48
|
+
* behind AGIC), so a run that emits no events for 30s would have its
|
|
49
|
+
* socket dropped by the proxy. The proxy timeout must exceed this value.
|
|
44
50
|
*/
|
|
45
51
|
createSocket(authToken = this.options.authToken) {
|
|
46
52
|
const socket = new phoenix.Socket(this.options.url, {
|
|
47
53
|
...authToken ? { authToken } : {},
|
|
48
54
|
reconnectAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(100, this.options.maxReconnectMs ?? 1e4),
|
|
49
|
-
rejoinAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(1e3, this.options.maxRejoinMs ?? 3e4)
|
|
55
|
+
rejoinAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(1e3, this.options.maxRejoinMs ?? 3e4),
|
|
56
|
+
heartbeatIntervalMs: this.options.heartbeatIntervalMs ?? 15e3
|
|
50
57
|
});
|
|
51
58
|
socket.connect();
|
|
52
59
|
return socket;
|