@copilotkitnext/runtime 1.53.0 → 1.53.1-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/runner/intelligence.cjs +79 -11
- package/dist/runner/intelligence.cjs.map +1 -1
- package/dist/runner/intelligence.d.cts +27 -1
- package/dist/runner/intelligence.d.cts.map +1 -1
- package/dist/runner/intelligence.d.mts +27 -1
- package/dist/runner/intelligence.d.mts.map +1 -1
- package/dist/runner/intelligence.mjs +80 -12
- package/dist/runner/intelligence.mjs.map +1 -1
- package/package.json +5 -5
package/dist/package.cjs
CHANGED
package/dist/package.mjs
CHANGED
|
@@ -8,27 +8,71 @@ let phoenix = require("phoenix");
|
|
|
8
8
|
|
|
9
9
|
//#region src/runner/intelligence.ts
|
|
10
10
|
var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
11
|
-
|
|
11
|
+
options;
|
|
12
12
|
threads = /* @__PURE__ */ new Map();
|
|
13
13
|
constructor(options) {
|
|
14
14
|
super();
|
|
15
|
-
this.
|
|
16
|
-
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a new Phoenix socket with explicit exponential backoff.
|
|
19
|
+
*
|
|
20
|
+
* Each run/connect gets its own socket so that:
|
|
21
|
+
* - A socket failure only affects a single thread, not all threads.
|
|
22
|
+
* - Cleanup is simple: channel.leave() + socket.disconnect() tears
|
|
23
|
+
* down everything for that run with no shared-state concerns.
|
|
24
|
+
* - Each run gets its own independent retry budget.
|
|
25
|
+
*
|
|
26
|
+
* reconnectAfterMs — delay before Phoenix reconnects the WebSocket
|
|
27
|
+
* after an unclean close. 100ms base, doubling up to a 10s cap.
|
|
28
|
+
*
|
|
29
|
+
* rejoinAfterMs — delay before Phoenix re-joins a channel that
|
|
30
|
+
* entered the "errored" state. 1s base, doubling up to 30s cap.
|
|
31
|
+
*
|
|
32
|
+
* These are set explicitly because Phoenix's default schedule is a
|
|
33
|
+
* fixed stepped array (not exponential), and any code that calls
|
|
34
|
+
* socket.disconnect() in an onError handler will set
|
|
35
|
+
* closeWasClean = true and reset the reconnect timer — permanently
|
|
36
|
+
* killing retries.
|
|
37
|
+
*/
|
|
38
|
+
createSocket() {
|
|
39
|
+
const socket = new phoenix.Socket(this.options.url, {
|
|
40
|
+
params: this.options.socketParams ?? {},
|
|
41
|
+
reconnectAfterMs: (0, _copilotkitnext_shared.phoenixExponentialBackoff)(100, 1e4),
|
|
42
|
+
rejoinAfterMs: (0, _copilotkitnext_shared.phoenixExponentialBackoff)(1e3, 3e4)
|
|
43
|
+
});
|
|
44
|
+
socket.connect();
|
|
45
|
+
return socket;
|
|
17
46
|
}
|
|
18
47
|
run(request) {
|
|
19
48
|
const { threadId, agent, input } = request;
|
|
20
49
|
if (this.threads.get(threadId)?.isRunning) throw new Error("Thread already running");
|
|
21
50
|
return new rxjs.Observable((observer) => {
|
|
22
|
-
const
|
|
23
|
-
const channel =
|
|
51
|
+
const socket = this.createSocket();
|
|
52
|
+
const channel = socket.channel(`agent:${threadId}`, { runId: input.runId });
|
|
24
53
|
const state = {
|
|
54
|
+
socket,
|
|
25
55
|
channel,
|
|
26
56
|
isRunning: true,
|
|
27
57
|
stopRequested: false,
|
|
28
58
|
agent,
|
|
29
|
-
currentEvents
|
|
59
|
+
currentEvents: []
|
|
30
60
|
};
|
|
31
61
|
this.threads.set(threadId, state);
|
|
62
|
+
const MAX_CONSECUTIVE_ERRORS = 5;
|
|
63
|
+
let consecutiveErrors = 0;
|
|
64
|
+
socket.onError(() => {
|
|
65
|
+
consecutiveErrors++;
|
|
66
|
+
if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS && state.agent) try {
|
|
67
|
+
state.agent.abortRun();
|
|
68
|
+
} catch {}
|
|
69
|
+
});
|
|
70
|
+
socket.onOpen(() => {
|
|
71
|
+
consecutiveErrors = 0;
|
|
72
|
+
});
|
|
73
|
+
channel.on(_copilotkitnext_shared.AG_UI_CHANNEL_EVENT, (payload) => {
|
|
74
|
+
if (payload.type === _ag_ui_client.EventType.CUSTOM && payload.name === "stop") this.stop({ threadId });
|
|
75
|
+
});
|
|
32
76
|
channel.join().receive("ok", () => {
|
|
33
77
|
this.executeAgentRun(request, state, threadId).subscribe({ complete: () => observer.complete() });
|
|
34
78
|
}).receive("error", (resp) => {
|
|
@@ -38,7 +82,17 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
38
82
|
code: "CHANNEL_JOIN_ERROR"
|
|
39
83
|
};
|
|
40
84
|
observer.next(errorEvent);
|
|
41
|
-
currentEvents.push(errorEvent);
|
|
85
|
+
state.currentEvents.push(errorEvent);
|
|
86
|
+
this.removeThread(threadId);
|
|
87
|
+
observer.complete();
|
|
88
|
+
}).receive("timeout", () => {
|
|
89
|
+
const errorEvent = {
|
|
90
|
+
type: _ag_ui_client.EventType.RUN_ERROR,
|
|
91
|
+
message: "Timed out joining channel",
|
|
92
|
+
code: "CHANNEL_JOIN_TIMEOUT"
|
|
93
|
+
};
|
|
94
|
+
observer.next(errorEvent);
|
|
95
|
+
state.currentEvents.push(errorEvent);
|
|
42
96
|
this.removeThread(threadId);
|
|
43
97
|
observer.complete();
|
|
44
98
|
});
|
|
@@ -50,22 +104,31 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
50
104
|
connect(request) {
|
|
51
105
|
const { threadId } = request;
|
|
52
106
|
return new rxjs.Observable((observer) => {
|
|
53
|
-
const
|
|
107
|
+
const socket = this.createSocket();
|
|
108
|
+
const channel = socket.channel(`agent:${threadId}`, { mode: "connect" });
|
|
54
109
|
channel.on(_copilotkitnext_shared.AG_UI_CHANNEL_EVENT, (payload) => {
|
|
55
110
|
observer.next(payload);
|
|
56
111
|
if (payload.type === _ag_ui_client.EventType.RUN_FINISHED || payload.type === _ag_ui_client.EventType.RUN_ERROR) observer.complete();
|
|
57
112
|
});
|
|
113
|
+
const cleanup = () => {
|
|
114
|
+
channel.leave();
|
|
115
|
+
socket.disconnect();
|
|
116
|
+
};
|
|
58
117
|
channel.join().receive("ok", () => {
|
|
59
118
|
channel.push(_ag_ui_client.EventType.CUSTOM, {
|
|
60
119
|
type: _ag_ui_client.EventType.CUSTOM,
|
|
61
120
|
name: "connect",
|
|
62
121
|
value: { threadId }
|
|
63
122
|
});
|
|
64
|
-
}).receive("error", () => {
|
|
65
|
-
observer.
|
|
123
|
+
}).receive("error", (resp) => {
|
|
124
|
+
observer.error(/* @__PURE__ */ new Error(`Failed to join channel: ${JSON.stringify(resp)}`));
|
|
125
|
+
cleanup();
|
|
126
|
+
}).receive("timeout", () => {
|
|
127
|
+
observer.error(/* @__PURE__ */ new Error("Timed out joining channel"));
|
|
128
|
+
cleanup();
|
|
66
129
|
});
|
|
67
130
|
return () => {
|
|
68
|
-
|
|
131
|
+
cleanup();
|
|
69
132
|
};
|
|
70
133
|
});
|
|
71
134
|
}
|
|
@@ -101,10 +164,15 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
101
164
|
this.removeThread(threadId);
|
|
102
165
|
}));
|
|
103
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Tear down all resources for a thread: leave the channel,
|
|
169
|
+
* disconnect the per-run socket, and remove the thread state.
|
|
170
|
+
*/
|
|
104
171
|
removeThread(threadId) {
|
|
105
172
|
const state = this.threads.get(threadId);
|
|
106
173
|
if (state) {
|
|
107
174
|
state.channel.leave();
|
|
175
|
+
state.socket.disconnect();
|
|
108
176
|
this.threads.delete(threadId);
|
|
109
177
|
}
|
|
110
178
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intelligence.cjs","names":["AgentRunner","Socket","Observable","EventType","AG_UI_CHANNEL_EVENT","EMPTY"],"sources":["../../src/runner/intelligence.ts"],"sourcesContent":["import {\n AgentRunner,\n AgentRunnerConnectRequest,\n AgentRunnerIsRunningRequest,\n AgentRunnerRunRequest,\n type AgentRunnerStopRequest,\n} from \"./agent-runner\";\nimport { EMPTY, Observable, from } from \"rxjs\";\nimport { catchError, finalize } from \"rxjs/operators\";\nimport { AbstractAgent, BaseEvent, EventType } from \"@ag-ui/client\";\nimport { finalizeRunEvents, AG_UI_CHANNEL_EVENT } from \"@copilotkitnext/shared\";\nimport { Socket, Channel } from \"phoenix\";\n\nexport interface IntelligenceAgentRunnerOptions {\n /** Phoenix websocket URL, e.g. \"ws://localhost:4000/socket\" */\n url: string;\n /** Optional params sent on socket connect (e.g. auth token) */\n socketParams?: Record<string, string>;\n}\n\ninterface ThreadState {\n channel: Channel;\n isRunning: boolean;\n stopRequested: boolean;\n agent: AbstractAgent | null;\n currentEvents: BaseEvent[];\n}\n\nexport class IntelligenceAgentRunner extends AgentRunner {\n private socket: Socket;\n private threads = new Map<string, ThreadState>();\n\n constructor(options: IntelligenceAgentRunnerOptions) {\n super();\n this.socket = new Socket(options.url, {\n params: options.socketParams ?? {},\n });\n this.socket.connect();\n }\n\n run(request: AgentRunnerRunRequest): Observable<BaseEvent> {\n const { threadId, agent, input } = request;\n\n const existing = this.threads.get(threadId);\n if (existing?.isRunning) {\n throw new Error(\"Thread already running\");\n }\n\n return new Observable((observer) => {\n const currentEvents: BaseEvent[] = [];\n\n const channel = this.socket.channel(`agent:${threadId}`, {\n runId: input.runId,\n });\n\n const state: ThreadState = {\n channel,\n isRunning: true,\n stopRequested: false,\n agent,\n currentEvents,\n };\n this.threads.set(threadId, state);\n\n channel\n .join()\n .receive(\"ok\", () => {\n this.executeAgentRun(request, state, threadId).subscribe({\n complete: () => observer.complete(),\n });\n })\n .receive(\"error\", (resp) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: `Failed to join channel: ${JSON.stringify(resp)}`,\n code: \"CHANNEL_JOIN_ERROR\",\n } as BaseEvent;\n observer.next(errorEvent);\n currentEvents.push(errorEvent);\n this.removeThread(threadId);\n observer.complete();\n });\n\n return () => {\n this.removeThread(threadId);\n };\n });\n }\n\n connect(request: AgentRunnerConnectRequest): Observable<BaseEvent> {\n const { threadId } = request;\n\n return new Observable((observer) => {\n const channel = this.socket.channel(`agent:${threadId}`, {\n mode: \"connect\",\n });\n\n // Listen for AG-UI events on a single channel event name.\n channel.on(AG_UI_CHANNEL_EVENT, (payload: BaseEvent) => {\n observer.next(payload);\n\n if (\n payload.type === EventType.RUN_FINISHED ||\n payload.type === EventType.RUN_ERROR\n ) {\n observer.complete();\n }\n });\n\n channel\n .join()\n .receive(\"ok\", () => {\n // Ask the server to replay history via a CUSTOM event.\n channel.push(EventType.CUSTOM, {\n type: EventType.CUSTOM,\n name: \"connect\",\n value: { threadId },\n });\n })\n .receive(\"error\", () => {\n observer.complete();\n });\n\n return () => {\n channel.leave();\n };\n });\n }\n\n isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean> {\n const state = this.threads.get(request.threadId);\n return Promise.resolve(state?.isRunning ?? false);\n }\n\n stop(request: AgentRunnerStopRequest): Promise<boolean | undefined> {\n const state = this.threads.get(request.threadId);\n if (!state || !state.isRunning || state.stopRequested) {\n return Promise.resolve(false);\n }\n\n state.stopRequested = true;\n\n // Direct local abort — the runtime is the authority.\n if (state.agent) {\n try {\n state.agent.abortRun();\n } catch {\n // Ignore abort errors.\n }\n }\n\n return Promise.resolve(true);\n }\n\n private executeAgentRun(\n request: AgentRunnerRunRequest,\n state: ThreadState,\n threadId: string,\n ): Observable<void> {\n const { currentEvents, channel } = state;\n\n return from(\n request.agent.runAgent(request.input, {\n onEvent: ({ event }: { event: BaseEvent }) => {\n currentEvents.push(event);\n\n // Push to Phoenix channel so frontend WS listeners receive it.\n channel.push(AG_UI_CHANNEL_EVENT, event);\n },\n }),\n ).pipe(\n catchError((error) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: error instanceof Error ? error.message : String(error),\n } as BaseEvent;\n currentEvents.push(errorEvent);\n channel.push(AG_UI_CHANNEL_EVENT, errorEvent);\n return EMPTY;\n }),\n finalize(() => {\n const appended = finalizeRunEvents(currentEvents, {\n stopRequested: state.stopRequested,\n });\n for (const event of appended) {\n channel.push(AG_UI_CHANNEL_EVENT, event);\n }\n this.removeThread(threadId);\n }),\n );\n }\n\n private removeThread(threadId: string): void {\n const state = this.threads.get(threadId);\n if (state) {\n state.channel.leave();\n this.threads.delete(threadId);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"intelligence.cjs","names":["AgentRunner","Socket","Observable","AG_UI_CHANNEL_EVENT","EventType","EMPTY"],"sources":["../../src/runner/intelligence.ts"],"sourcesContent":["import {\n AgentRunner,\n AgentRunnerConnectRequest,\n AgentRunnerIsRunningRequest,\n AgentRunnerRunRequest,\n type AgentRunnerStopRequest,\n} from \"./agent-runner\";\nimport { EMPTY, Observable, from } from \"rxjs\";\nimport { catchError, finalize } from \"rxjs/operators\";\nimport { AbstractAgent, BaseEvent, EventType } from \"@ag-ui/client\";\nimport {\n finalizeRunEvents,\n AG_UI_CHANNEL_EVENT,\n phoenixExponentialBackoff,\n} from \"@copilotkitnext/shared\";\nimport { Socket, Channel } from \"phoenix\";\n\nexport interface IntelligenceAgentRunnerOptions {\n /** Phoenix websocket URL, e.g. \"ws://localhost:4000/socket\" */\n url: string;\n /** Optional params sent on socket connect (e.g. auth token) */\n socketParams?: Record<string, string>;\n}\n\ninterface ThreadState {\n socket: Socket;\n channel: Channel;\n isRunning: boolean;\n stopRequested: boolean;\n agent: AbstractAgent | null;\n currentEvents: BaseEvent[];\n}\n\nexport class IntelligenceAgentRunner extends AgentRunner {\n private options: IntelligenceAgentRunnerOptions;\n private threads = new Map<string, ThreadState>();\n\n constructor(options: IntelligenceAgentRunnerOptions) {\n super();\n // Store config — sockets are created per-run, not eagerly.\n this.options = options;\n }\n\n /**\n * Create a new Phoenix socket with explicit exponential backoff.\n *\n * Each run/connect gets its own socket so that:\n * - A socket failure only affects a single thread, not all threads.\n * - Cleanup is simple: channel.leave() + socket.disconnect() tears\n * down everything for that run with no shared-state concerns.\n * - Each run gets its own independent retry budget.\n *\n * reconnectAfterMs — delay before Phoenix reconnects the WebSocket\n * after an unclean close. 100ms base, doubling up to a 10s cap.\n *\n * rejoinAfterMs — delay before Phoenix re-joins a channel that\n * entered the \"errored\" state. 1s base, doubling up to 30s cap.\n *\n * These are set explicitly because Phoenix's default schedule is a\n * fixed stepped array (not exponential), and any code that calls\n * socket.disconnect() in an onError handler will set\n * closeWasClean = true and reset the reconnect timer — permanently\n * killing retries.\n */\n private createSocket(): Socket {\n const socket = new Socket(this.options.url, {\n params: this.options.socketParams ?? {},\n reconnectAfterMs: phoenixExponentialBackoff(100, 10_000),\n rejoinAfterMs: phoenixExponentialBackoff(1_000, 30_000),\n });\n socket.connect();\n return socket;\n }\n\n run(request: AgentRunnerRunRequest): Observable<BaseEvent> {\n const { threadId, agent, input } = request;\n\n const existing = this.threads.get(threadId);\n if (existing?.isRunning) {\n throw new Error(\"Thread already running\");\n }\n\n return new Observable((observer) => {\n const socket = this.createSocket();\n\n const channel = socket.channel(`agent:${threadId}`, {\n runId: input.runId,\n });\n\n const state: ThreadState = {\n socket,\n channel,\n isRunning: true,\n stopRequested: false,\n agent,\n currentEvents: [],\n };\n this.threads.set(threadId, state);\n\n // Track consecutive socket errors for this run. Phoenix retries\n // automatically via reconnectAfterMs, but if the connection fails\n // repeatedly we abort the agent — otherwise runAgent() completes\n // normally, finalization events buffer silently on the dead\n // channel, and the client never receives them.\n //\n // Aborting the agent is the single trigger that cascades through\n // the existing error pipeline: runAgent() rejects → catchError\n // pushes RUN_ERROR → finalize calls finalizeRunEvents +\n // removeThread → channel.leave() + socket.disconnect().\n const MAX_CONSECUTIVE_ERRORS = 5;\n let consecutiveErrors = 0;\n\n socket.onError(() => {\n consecutiveErrors++;\n if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS && state.agent) {\n try {\n state.agent.abortRun();\n } catch {\n // Ignore abort errors.\n }\n }\n // Otherwise: Phoenix retries automatically using the exponential\n // backoff schedule configured in createSocket().\n });\n\n socket.onOpen(() => {\n // A successful (re)connection resets the counter so transient\n // network blips don't accumulate across recoveries.\n consecutiveErrors = 0;\n });\n\n // Listen for custom \"stop\" events pushed by the client over the\n // channel. This must be registered before channel.join() so the\n // handler is in place by the time the server starts relaying messages.\n // The client sends the stop event before leaving the channel, so the\n // runner is guaranteed to receive it while still joined.\n channel.on(AG_UI_CHANNEL_EVENT, (payload: BaseEvent) => {\n if (\n payload.type === EventType.CUSTOM &&\n (payload as BaseEvent & { name?: string }).name === \"stop\"\n ) {\n this.stop({ threadId });\n }\n });\n\n channel\n .join()\n .receive(\"ok\", () => {\n this.executeAgentRun(request, state, threadId).subscribe({\n complete: () => observer.complete(),\n });\n })\n .receive(\"error\", (resp) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: `Failed to join channel: ${JSON.stringify(resp)}`,\n code: \"CHANNEL_JOIN_ERROR\",\n } as BaseEvent;\n observer.next(errorEvent);\n state.currentEvents.push(errorEvent);\n this.removeThread(threadId);\n observer.complete();\n })\n .receive(\"timeout\", () => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: \"Timed out joining channel\",\n code: \"CHANNEL_JOIN_TIMEOUT\",\n } as BaseEvent;\n observer.next(errorEvent);\n state.currentEvents.push(errorEvent);\n this.removeThread(threadId);\n observer.complete();\n });\n\n return () => {\n this.removeThread(threadId);\n };\n });\n }\n\n connect(request: AgentRunnerConnectRequest): Observable<BaseEvent> {\n const { threadId } = request;\n\n return new Observable((observer) => {\n const socket = this.createSocket();\n\n const channel = socket.channel(`agent:${threadId}`, {\n mode: \"connect\",\n });\n\n // Listen for AG-UI events on a single channel event name.\n channel.on(AG_UI_CHANNEL_EVENT, (payload: BaseEvent) => {\n observer.next(payload);\n\n if (\n payload.type === EventType.RUN_FINISHED ||\n payload.type === EventType.RUN_ERROR\n ) {\n observer.complete();\n }\n });\n\n const cleanup = () => {\n channel.leave();\n socket.disconnect();\n };\n\n channel\n .join()\n .receive(\"ok\", () => {\n // Ask the server to replay history via a CUSTOM event.\n channel.push(EventType.CUSTOM, {\n type: EventType.CUSTOM,\n name: \"connect\",\n value: { threadId },\n });\n })\n .receive(\"error\", (resp) => {\n observer.error(\n new Error(`Failed to join channel: ${JSON.stringify(resp)}`),\n );\n cleanup();\n })\n .receive(\"timeout\", () => {\n observer.error(new Error(\"Timed out joining channel\"));\n cleanup();\n });\n\n return () => {\n cleanup();\n };\n });\n }\n\n isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean> {\n const state = this.threads.get(request.threadId);\n return Promise.resolve(state?.isRunning ?? false);\n }\n\n stop(request: AgentRunnerStopRequest): Promise<boolean | undefined> {\n const state = this.threads.get(request.threadId);\n if (!state || !state.isRunning || state.stopRequested) {\n return Promise.resolve(false);\n }\n\n state.stopRequested = true;\n\n // Direct local abort — the runtime is the authority.\n if (state.agent) {\n try {\n state.agent.abortRun();\n } catch {\n // Ignore abort errors.\n }\n }\n\n return Promise.resolve(true);\n }\n\n private executeAgentRun(\n request: AgentRunnerRunRequest,\n state: ThreadState,\n threadId: string,\n ): Observable<void> {\n const { currentEvents, channel } = state;\n\n return from(\n request.agent.runAgent(request.input, {\n onEvent: ({ event }: { event: BaseEvent }) => {\n currentEvents.push(event);\n\n // Push to Phoenix channel so frontend WS listeners receive it.\n channel.push(AG_UI_CHANNEL_EVENT, event);\n },\n }),\n ).pipe(\n catchError((error) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: error instanceof Error ? error.message : String(error),\n } as BaseEvent;\n currentEvents.push(errorEvent);\n channel.push(AG_UI_CHANNEL_EVENT, errorEvent);\n return EMPTY;\n }),\n finalize(() => {\n const appended = finalizeRunEvents(currentEvents, {\n stopRequested: state.stopRequested,\n });\n for (const event of appended) {\n channel.push(AG_UI_CHANNEL_EVENT, event);\n }\n this.removeThread(threadId);\n }),\n );\n }\n\n /**\n * Tear down all resources for a thread: leave the channel,\n * disconnect the per-run socket, and remove the thread state.\n */\n private removeThread(threadId: string): void {\n const state = this.threads.get(threadId);\n if (state) {\n state.channel.leave();\n state.socket.disconnect();\n this.threads.delete(threadId);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -10,14 +10,40 @@ interface IntelligenceAgentRunnerOptions {
|
|
|
10
10
|
socketParams?: Record<string, string>;
|
|
11
11
|
}
|
|
12
12
|
declare class IntelligenceAgentRunner extends AgentRunner {
|
|
13
|
-
private
|
|
13
|
+
private options;
|
|
14
14
|
private threads;
|
|
15
15
|
constructor(options: IntelligenceAgentRunnerOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Create a new Phoenix socket with explicit exponential backoff.
|
|
18
|
+
*
|
|
19
|
+
* Each run/connect gets its own socket so that:
|
|
20
|
+
* - A socket failure only affects a single thread, not all threads.
|
|
21
|
+
* - Cleanup is simple: channel.leave() + socket.disconnect() tears
|
|
22
|
+
* down everything for that run with no shared-state concerns.
|
|
23
|
+
* - Each run gets its own independent retry budget.
|
|
24
|
+
*
|
|
25
|
+
* reconnectAfterMs — delay before Phoenix reconnects the WebSocket
|
|
26
|
+
* after an unclean close. 100ms base, doubling up to a 10s cap.
|
|
27
|
+
*
|
|
28
|
+
* rejoinAfterMs — delay before Phoenix re-joins a channel that
|
|
29
|
+
* entered the "errored" state. 1s base, doubling up to 30s cap.
|
|
30
|
+
*
|
|
31
|
+
* These are set explicitly because Phoenix's default schedule is a
|
|
32
|
+
* fixed stepped array (not exponential), and any code that calls
|
|
33
|
+
* socket.disconnect() in an onError handler will set
|
|
34
|
+
* closeWasClean = true and reset the reconnect timer — permanently
|
|
35
|
+
* killing retries.
|
|
36
|
+
*/
|
|
37
|
+
private createSocket;
|
|
16
38
|
run(request: AgentRunnerRunRequest): Observable<BaseEvent>;
|
|
17
39
|
connect(request: AgentRunnerConnectRequest): Observable<BaseEvent>;
|
|
18
40
|
isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean>;
|
|
19
41
|
stop(request: AgentRunnerStopRequest): Promise<boolean | undefined>;
|
|
20
42
|
private executeAgentRun;
|
|
43
|
+
/**
|
|
44
|
+
* Tear down all resources for a thread: leave the channel,
|
|
45
|
+
* disconnect the per-run socket, and remove the thread state.
|
|
46
|
+
*/
|
|
21
47
|
private removeThread;
|
|
22
48
|
}
|
|
23
49
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intelligence.d.cts","names":[],"sources":["../../src/runner/intelligence.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"intelligence.d.cts","names":[],"sources":["../../src/runner/intelligence.ts"],"mappings":";;;;;UAiBiB,8BAAA;;EAEf,GAAA;EAF6C;EAI7C,YAAA,GAAe,MAAA;AAAA;AAAA,cAYJ,uBAAA,SAAgC,WAAA;EAAA,QACnC,OAAA;EAAA,QACA,OAAA;cAEI,OAAA,EAAS,8BAAA;EAhBA;AAYvB;;;;;;;;;;;;;;;;;;;;EAZuB,QA2Cb,YAAA;EAUR,GAAA,CAAI,OAAA,EAAS,qBAAA,GAAwB,UAAA,CAAW,SAAA;EA2GhD,OAAA,CAAQ,OAAA,EAAS,yBAAA,GAA4B,UAAA,CAAW,SAAA;EAsDxD,SAAA,CAAU,OAAA,EAAS,2BAAA,GAA8B,OAAA;EAKjD,IAAA,CAAK,OAAA,EAAS,sBAAA,GAAyB,OAAA;EAAA,QAoB/B,eAAA;EA1LJ;;;;EAAA,QAoOI,YAAA;AAAA"}
|
|
@@ -10,14 +10,40 @@ interface IntelligenceAgentRunnerOptions {
|
|
|
10
10
|
socketParams?: Record<string, string>;
|
|
11
11
|
}
|
|
12
12
|
declare class IntelligenceAgentRunner extends AgentRunner {
|
|
13
|
-
private
|
|
13
|
+
private options;
|
|
14
14
|
private threads;
|
|
15
15
|
constructor(options: IntelligenceAgentRunnerOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Create a new Phoenix socket with explicit exponential backoff.
|
|
18
|
+
*
|
|
19
|
+
* Each run/connect gets its own socket so that:
|
|
20
|
+
* - A socket failure only affects a single thread, not all threads.
|
|
21
|
+
* - Cleanup is simple: channel.leave() + socket.disconnect() tears
|
|
22
|
+
* down everything for that run with no shared-state concerns.
|
|
23
|
+
* - Each run gets its own independent retry budget.
|
|
24
|
+
*
|
|
25
|
+
* reconnectAfterMs — delay before Phoenix reconnects the WebSocket
|
|
26
|
+
* after an unclean close. 100ms base, doubling up to a 10s cap.
|
|
27
|
+
*
|
|
28
|
+
* rejoinAfterMs — delay before Phoenix re-joins a channel that
|
|
29
|
+
* entered the "errored" state. 1s base, doubling up to 30s cap.
|
|
30
|
+
*
|
|
31
|
+
* These are set explicitly because Phoenix's default schedule is a
|
|
32
|
+
* fixed stepped array (not exponential), and any code that calls
|
|
33
|
+
* socket.disconnect() in an onError handler will set
|
|
34
|
+
* closeWasClean = true and reset the reconnect timer — permanently
|
|
35
|
+
* killing retries.
|
|
36
|
+
*/
|
|
37
|
+
private createSocket;
|
|
16
38
|
run(request: AgentRunnerRunRequest): Observable<BaseEvent>;
|
|
17
39
|
connect(request: AgentRunnerConnectRequest): Observable<BaseEvent>;
|
|
18
40
|
isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean>;
|
|
19
41
|
stop(request: AgentRunnerStopRequest): Promise<boolean | undefined>;
|
|
20
42
|
private executeAgentRun;
|
|
43
|
+
/**
|
|
44
|
+
* Tear down all resources for a thread: leave the channel,
|
|
45
|
+
* disconnect the per-run socket, and remove the thread state.
|
|
46
|
+
*/
|
|
21
47
|
private removeThread;
|
|
22
48
|
}
|
|
23
49
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intelligence.d.mts","names":[],"sources":["../../src/runner/intelligence.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"intelligence.d.mts","names":[],"sources":["../../src/runner/intelligence.ts"],"mappings":";;;;;UAiBiB,8BAAA;;EAEf,GAAA;EAF6C;EAI7C,YAAA,GAAe,MAAA;AAAA;AAAA,cAYJ,uBAAA,SAAgC,WAAA;EAAA,QACnC,OAAA;EAAA,QACA,OAAA;cAEI,OAAA,EAAS,8BAAA;EAhBA;AAYvB;;;;;;;;;;;;;;;;;;;;EAZuB,QA2Cb,YAAA;EAUR,GAAA,CAAI,OAAA,EAAS,qBAAA,GAAwB,UAAA,CAAW,SAAA;EA2GhD,OAAA,CAAQ,OAAA,EAAS,yBAAA,GAA4B,UAAA,CAAW,SAAA;EAsDxD,SAAA,CAAU,OAAA,EAAS,2BAAA,GAA8B,OAAA;EAKjD,IAAA,CAAK,OAAA,EAAS,sBAAA,GAAyB,OAAA;EAAA,QAoB/B,eAAA;EA1LJ;;;;EAAA,QAoOI,YAAA;AAAA"}
|
|
@@ -1,33 +1,77 @@
|
|
|
1
1
|
import { AgentRunner } from "./agent-runner.mjs";
|
|
2
2
|
import { EMPTY, Observable, from } from "rxjs";
|
|
3
3
|
import { EventType } from "@ag-ui/client";
|
|
4
|
-
import { AG_UI_CHANNEL_EVENT, finalizeRunEvents } from "@copilotkitnext/shared";
|
|
4
|
+
import { AG_UI_CHANNEL_EVENT, finalizeRunEvents, phoenixExponentialBackoff } from "@copilotkitnext/shared";
|
|
5
5
|
import { catchError, finalize } from "rxjs/operators";
|
|
6
6
|
import { Socket } from "phoenix";
|
|
7
7
|
|
|
8
8
|
//#region src/runner/intelligence.ts
|
|
9
9
|
var IntelligenceAgentRunner = class extends AgentRunner {
|
|
10
|
-
|
|
10
|
+
options;
|
|
11
11
|
threads = /* @__PURE__ */ new Map();
|
|
12
12
|
constructor(options) {
|
|
13
13
|
super();
|
|
14
|
-
this.
|
|
15
|
-
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a new Phoenix socket with explicit exponential backoff.
|
|
18
|
+
*
|
|
19
|
+
* Each run/connect gets its own socket so that:
|
|
20
|
+
* - A socket failure only affects a single thread, not all threads.
|
|
21
|
+
* - Cleanup is simple: channel.leave() + socket.disconnect() tears
|
|
22
|
+
* down everything for that run with no shared-state concerns.
|
|
23
|
+
* - Each run gets its own independent retry budget.
|
|
24
|
+
*
|
|
25
|
+
* reconnectAfterMs — delay before Phoenix reconnects the WebSocket
|
|
26
|
+
* after an unclean close. 100ms base, doubling up to a 10s cap.
|
|
27
|
+
*
|
|
28
|
+
* rejoinAfterMs — delay before Phoenix re-joins a channel that
|
|
29
|
+
* entered the "errored" state. 1s base, doubling up to 30s cap.
|
|
30
|
+
*
|
|
31
|
+
* These are set explicitly because Phoenix's default schedule is a
|
|
32
|
+
* fixed stepped array (not exponential), and any code that calls
|
|
33
|
+
* socket.disconnect() in an onError handler will set
|
|
34
|
+
* closeWasClean = true and reset the reconnect timer — permanently
|
|
35
|
+
* killing retries.
|
|
36
|
+
*/
|
|
37
|
+
createSocket() {
|
|
38
|
+
const socket = new Socket(this.options.url, {
|
|
39
|
+
params: this.options.socketParams ?? {},
|
|
40
|
+
reconnectAfterMs: phoenixExponentialBackoff(100, 1e4),
|
|
41
|
+
rejoinAfterMs: phoenixExponentialBackoff(1e3, 3e4)
|
|
42
|
+
});
|
|
43
|
+
socket.connect();
|
|
44
|
+
return socket;
|
|
16
45
|
}
|
|
17
46
|
run(request) {
|
|
18
47
|
const { threadId, agent, input } = request;
|
|
19
48
|
if (this.threads.get(threadId)?.isRunning) throw new Error("Thread already running");
|
|
20
49
|
return new Observable((observer) => {
|
|
21
|
-
const
|
|
22
|
-
const channel =
|
|
50
|
+
const socket = this.createSocket();
|
|
51
|
+
const channel = socket.channel(`agent:${threadId}`, { runId: input.runId });
|
|
23
52
|
const state = {
|
|
53
|
+
socket,
|
|
24
54
|
channel,
|
|
25
55
|
isRunning: true,
|
|
26
56
|
stopRequested: false,
|
|
27
57
|
agent,
|
|
28
|
-
currentEvents
|
|
58
|
+
currentEvents: []
|
|
29
59
|
};
|
|
30
60
|
this.threads.set(threadId, state);
|
|
61
|
+
const MAX_CONSECUTIVE_ERRORS = 5;
|
|
62
|
+
let consecutiveErrors = 0;
|
|
63
|
+
socket.onError(() => {
|
|
64
|
+
consecutiveErrors++;
|
|
65
|
+
if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS && state.agent) try {
|
|
66
|
+
state.agent.abortRun();
|
|
67
|
+
} catch {}
|
|
68
|
+
});
|
|
69
|
+
socket.onOpen(() => {
|
|
70
|
+
consecutiveErrors = 0;
|
|
71
|
+
});
|
|
72
|
+
channel.on(AG_UI_CHANNEL_EVENT, (payload) => {
|
|
73
|
+
if (payload.type === EventType.CUSTOM && payload.name === "stop") this.stop({ threadId });
|
|
74
|
+
});
|
|
31
75
|
channel.join().receive("ok", () => {
|
|
32
76
|
this.executeAgentRun(request, state, threadId).subscribe({ complete: () => observer.complete() });
|
|
33
77
|
}).receive("error", (resp) => {
|
|
@@ -37,7 +81,17 @@ var IntelligenceAgentRunner = class extends AgentRunner {
|
|
|
37
81
|
code: "CHANNEL_JOIN_ERROR"
|
|
38
82
|
};
|
|
39
83
|
observer.next(errorEvent);
|
|
40
|
-
currentEvents.push(errorEvent);
|
|
84
|
+
state.currentEvents.push(errorEvent);
|
|
85
|
+
this.removeThread(threadId);
|
|
86
|
+
observer.complete();
|
|
87
|
+
}).receive("timeout", () => {
|
|
88
|
+
const errorEvent = {
|
|
89
|
+
type: EventType.RUN_ERROR,
|
|
90
|
+
message: "Timed out joining channel",
|
|
91
|
+
code: "CHANNEL_JOIN_TIMEOUT"
|
|
92
|
+
};
|
|
93
|
+
observer.next(errorEvent);
|
|
94
|
+
state.currentEvents.push(errorEvent);
|
|
41
95
|
this.removeThread(threadId);
|
|
42
96
|
observer.complete();
|
|
43
97
|
});
|
|
@@ -49,22 +103,31 @@ var IntelligenceAgentRunner = class extends AgentRunner {
|
|
|
49
103
|
connect(request) {
|
|
50
104
|
const { threadId } = request;
|
|
51
105
|
return new Observable((observer) => {
|
|
52
|
-
const
|
|
106
|
+
const socket = this.createSocket();
|
|
107
|
+
const channel = socket.channel(`agent:${threadId}`, { mode: "connect" });
|
|
53
108
|
channel.on(AG_UI_CHANNEL_EVENT, (payload) => {
|
|
54
109
|
observer.next(payload);
|
|
55
110
|
if (payload.type === EventType.RUN_FINISHED || payload.type === EventType.RUN_ERROR) observer.complete();
|
|
56
111
|
});
|
|
112
|
+
const cleanup = () => {
|
|
113
|
+
channel.leave();
|
|
114
|
+
socket.disconnect();
|
|
115
|
+
};
|
|
57
116
|
channel.join().receive("ok", () => {
|
|
58
117
|
channel.push(EventType.CUSTOM, {
|
|
59
118
|
type: EventType.CUSTOM,
|
|
60
119
|
name: "connect",
|
|
61
120
|
value: { threadId }
|
|
62
121
|
});
|
|
63
|
-
}).receive("error", () => {
|
|
64
|
-
observer.
|
|
122
|
+
}).receive("error", (resp) => {
|
|
123
|
+
observer.error(/* @__PURE__ */ new Error(`Failed to join channel: ${JSON.stringify(resp)}`));
|
|
124
|
+
cleanup();
|
|
125
|
+
}).receive("timeout", () => {
|
|
126
|
+
observer.error(/* @__PURE__ */ new Error("Timed out joining channel"));
|
|
127
|
+
cleanup();
|
|
65
128
|
});
|
|
66
129
|
return () => {
|
|
67
|
-
|
|
130
|
+
cleanup();
|
|
68
131
|
};
|
|
69
132
|
});
|
|
70
133
|
}
|
|
@@ -100,10 +163,15 @@ var IntelligenceAgentRunner = class extends AgentRunner {
|
|
|
100
163
|
this.removeThread(threadId);
|
|
101
164
|
}));
|
|
102
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Tear down all resources for a thread: leave the channel,
|
|
168
|
+
* disconnect the per-run socket, and remove the thread state.
|
|
169
|
+
*/
|
|
103
170
|
removeThread(threadId) {
|
|
104
171
|
const state = this.threads.get(threadId);
|
|
105
172
|
if (state) {
|
|
106
173
|
state.channel.leave();
|
|
174
|
+
state.socket.disconnect();
|
|
107
175
|
this.threads.delete(threadId);
|
|
108
176
|
}
|
|
109
177
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intelligence.mjs","names":[],"sources":["../../src/runner/intelligence.ts"],"sourcesContent":["import {\n AgentRunner,\n AgentRunnerConnectRequest,\n AgentRunnerIsRunningRequest,\n AgentRunnerRunRequest,\n type AgentRunnerStopRequest,\n} from \"./agent-runner\";\nimport { EMPTY, Observable, from } from \"rxjs\";\nimport { catchError, finalize } from \"rxjs/operators\";\nimport { AbstractAgent, BaseEvent, EventType } from \"@ag-ui/client\";\nimport { finalizeRunEvents, AG_UI_CHANNEL_EVENT } from \"@copilotkitnext/shared\";\nimport { Socket, Channel } from \"phoenix\";\n\nexport interface IntelligenceAgentRunnerOptions {\n /** Phoenix websocket URL, e.g. \"ws://localhost:4000/socket\" */\n url: string;\n /** Optional params sent on socket connect (e.g. auth token) */\n socketParams?: Record<string, string>;\n}\n\ninterface ThreadState {\n channel: Channel;\n isRunning: boolean;\n stopRequested: boolean;\n agent: AbstractAgent | null;\n currentEvents: BaseEvent[];\n}\n\nexport class IntelligenceAgentRunner extends AgentRunner {\n private socket: Socket;\n private threads = new Map<string, ThreadState>();\n\n constructor(options: IntelligenceAgentRunnerOptions) {\n super();\n this.socket = new Socket(options.url, {\n params: options.socketParams ?? {},\n });\n this.socket.connect();\n }\n\n run(request: AgentRunnerRunRequest): Observable<BaseEvent> {\n const { threadId, agent, input } = request;\n\n const existing = this.threads.get(threadId);\n if (existing?.isRunning) {\n throw new Error(\"Thread already running\");\n }\n\n return new Observable((observer) => {\n const currentEvents: BaseEvent[] = [];\n\n const channel = this.socket.channel(`agent:${threadId}`, {\n runId: input.runId,\n });\n\n const state: ThreadState = {\n channel,\n isRunning: true,\n stopRequested: false,\n agent,\n currentEvents,\n };\n this.threads.set(threadId, state);\n\n channel\n .join()\n .receive(\"ok\", () => {\n this.executeAgentRun(request, state, threadId).subscribe({\n complete: () => observer.complete(),\n });\n })\n .receive(\"error\", (resp) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: `Failed to join channel: ${JSON.stringify(resp)}`,\n code: \"CHANNEL_JOIN_ERROR\",\n } as BaseEvent;\n observer.next(errorEvent);\n currentEvents.push(errorEvent);\n this.removeThread(threadId);\n observer.complete();\n });\n\n return () => {\n this.removeThread(threadId);\n };\n });\n }\n\n connect(request: AgentRunnerConnectRequest): Observable<BaseEvent> {\n const { threadId } = request;\n\n return new Observable((observer) => {\n const channel = this.socket.channel(`agent:${threadId}`, {\n mode: \"connect\",\n });\n\n // Listen for AG-UI events on a single channel event name.\n channel.on(AG_UI_CHANNEL_EVENT, (payload: BaseEvent) => {\n observer.next(payload);\n\n if (\n payload.type === EventType.RUN_FINISHED ||\n payload.type === EventType.RUN_ERROR\n ) {\n observer.complete();\n }\n });\n\n channel\n .join()\n .receive(\"ok\", () => {\n // Ask the server to replay history via a CUSTOM event.\n channel.push(EventType.CUSTOM, {\n type: EventType.CUSTOM,\n name: \"connect\",\n value: { threadId },\n });\n })\n .receive(\"error\", () => {\n observer.complete();\n });\n\n return () => {\n channel.leave();\n };\n });\n }\n\n isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean> {\n const state = this.threads.get(request.threadId);\n return Promise.resolve(state?.isRunning ?? false);\n }\n\n stop(request: AgentRunnerStopRequest): Promise<boolean | undefined> {\n const state = this.threads.get(request.threadId);\n if (!state || !state.isRunning || state.stopRequested) {\n return Promise.resolve(false);\n }\n\n state.stopRequested = true;\n\n // Direct local abort — the runtime is the authority.\n if (state.agent) {\n try {\n state.agent.abortRun();\n } catch {\n // Ignore abort errors.\n }\n }\n\n return Promise.resolve(true);\n }\n\n private executeAgentRun(\n request: AgentRunnerRunRequest,\n state: ThreadState,\n threadId: string,\n ): Observable<void> {\n const { currentEvents, channel } = state;\n\n return from(\n request.agent.runAgent(request.input, {\n onEvent: ({ event }: { event: BaseEvent }) => {\n currentEvents.push(event);\n\n // Push to Phoenix channel so frontend WS listeners receive it.\n channel.push(AG_UI_CHANNEL_EVENT, event);\n },\n }),\n ).pipe(\n catchError((error) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: error instanceof Error ? error.message : String(error),\n } as BaseEvent;\n currentEvents.push(errorEvent);\n channel.push(AG_UI_CHANNEL_EVENT, errorEvent);\n return EMPTY;\n }),\n finalize(() => {\n const appended = finalizeRunEvents(currentEvents, {\n stopRequested: state.stopRequested,\n });\n for (const event of appended) {\n channel.push(AG_UI_CHANNEL_EVENT, event);\n }\n this.removeThread(threadId);\n }),\n );\n }\n\n private removeThread(threadId: string): void {\n const state = this.threads.get(threadId);\n if (state) {\n state.channel.leave();\n this.threads.delete(threadId);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"intelligence.mjs","names":[],"sources":["../../src/runner/intelligence.ts"],"sourcesContent":["import {\n AgentRunner,\n AgentRunnerConnectRequest,\n AgentRunnerIsRunningRequest,\n AgentRunnerRunRequest,\n type AgentRunnerStopRequest,\n} from \"./agent-runner\";\nimport { EMPTY, Observable, from } from \"rxjs\";\nimport { catchError, finalize } from \"rxjs/operators\";\nimport { AbstractAgent, BaseEvent, EventType } from \"@ag-ui/client\";\nimport {\n finalizeRunEvents,\n AG_UI_CHANNEL_EVENT,\n phoenixExponentialBackoff,\n} from \"@copilotkitnext/shared\";\nimport { Socket, Channel } from \"phoenix\";\n\nexport interface IntelligenceAgentRunnerOptions {\n /** Phoenix websocket URL, e.g. \"ws://localhost:4000/socket\" */\n url: string;\n /** Optional params sent on socket connect (e.g. auth token) */\n socketParams?: Record<string, string>;\n}\n\ninterface ThreadState {\n socket: Socket;\n channel: Channel;\n isRunning: boolean;\n stopRequested: boolean;\n agent: AbstractAgent | null;\n currentEvents: BaseEvent[];\n}\n\nexport class IntelligenceAgentRunner extends AgentRunner {\n private options: IntelligenceAgentRunnerOptions;\n private threads = new Map<string, ThreadState>();\n\n constructor(options: IntelligenceAgentRunnerOptions) {\n super();\n // Store config — sockets are created per-run, not eagerly.\n this.options = options;\n }\n\n /**\n * Create a new Phoenix socket with explicit exponential backoff.\n *\n * Each run/connect gets its own socket so that:\n * - A socket failure only affects a single thread, not all threads.\n * - Cleanup is simple: channel.leave() + socket.disconnect() tears\n * down everything for that run with no shared-state concerns.\n * - Each run gets its own independent retry budget.\n *\n * reconnectAfterMs — delay before Phoenix reconnects the WebSocket\n * after an unclean close. 100ms base, doubling up to a 10s cap.\n *\n * rejoinAfterMs — delay before Phoenix re-joins a channel that\n * entered the \"errored\" state. 1s base, doubling up to 30s cap.\n *\n * These are set explicitly because Phoenix's default schedule is a\n * fixed stepped array (not exponential), and any code that calls\n * socket.disconnect() in an onError handler will set\n * closeWasClean = true and reset the reconnect timer — permanently\n * killing retries.\n */\n private createSocket(): Socket {\n const socket = new Socket(this.options.url, {\n params: this.options.socketParams ?? {},\n reconnectAfterMs: phoenixExponentialBackoff(100, 10_000),\n rejoinAfterMs: phoenixExponentialBackoff(1_000, 30_000),\n });\n socket.connect();\n return socket;\n }\n\n run(request: AgentRunnerRunRequest): Observable<BaseEvent> {\n const { threadId, agent, input } = request;\n\n const existing = this.threads.get(threadId);\n if (existing?.isRunning) {\n throw new Error(\"Thread already running\");\n }\n\n return new Observable((observer) => {\n const socket = this.createSocket();\n\n const channel = socket.channel(`agent:${threadId}`, {\n runId: input.runId,\n });\n\n const state: ThreadState = {\n socket,\n channel,\n isRunning: true,\n stopRequested: false,\n agent,\n currentEvents: [],\n };\n this.threads.set(threadId, state);\n\n // Track consecutive socket errors for this run. Phoenix retries\n // automatically via reconnectAfterMs, but if the connection fails\n // repeatedly we abort the agent — otherwise runAgent() completes\n // normally, finalization events buffer silently on the dead\n // channel, and the client never receives them.\n //\n // Aborting the agent is the single trigger that cascades through\n // the existing error pipeline: runAgent() rejects → catchError\n // pushes RUN_ERROR → finalize calls finalizeRunEvents +\n // removeThread → channel.leave() + socket.disconnect().\n const MAX_CONSECUTIVE_ERRORS = 5;\n let consecutiveErrors = 0;\n\n socket.onError(() => {\n consecutiveErrors++;\n if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS && state.agent) {\n try {\n state.agent.abortRun();\n } catch {\n // Ignore abort errors.\n }\n }\n // Otherwise: Phoenix retries automatically using the exponential\n // backoff schedule configured in createSocket().\n });\n\n socket.onOpen(() => {\n // A successful (re)connection resets the counter so transient\n // network blips don't accumulate across recoveries.\n consecutiveErrors = 0;\n });\n\n // Listen for custom \"stop\" events pushed by the client over the\n // channel. This must be registered before channel.join() so the\n // handler is in place by the time the server starts relaying messages.\n // The client sends the stop event before leaving the channel, so the\n // runner is guaranteed to receive it while still joined.\n channel.on(AG_UI_CHANNEL_EVENT, (payload: BaseEvent) => {\n if (\n payload.type === EventType.CUSTOM &&\n (payload as BaseEvent & { name?: string }).name === \"stop\"\n ) {\n this.stop({ threadId });\n }\n });\n\n channel\n .join()\n .receive(\"ok\", () => {\n this.executeAgentRun(request, state, threadId).subscribe({\n complete: () => observer.complete(),\n });\n })\n .receive(\"error\", (resp) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: `Failed to join channel: ${JSON.stringify(resp)}`,\n code: \"CHANNEL_JOIN_ERROR\",\n } as BaseEvent;\n observer.next(errorEvent);\n state.currentEvents.push(errorEvent);\n this.removeThread(threadId);\n observer.complete();\n })\n .receive(\"timeout\", () => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: \"Timed out joining channel\",\n code: \"CHANNEL_JOIN_TIMEOUT\",\n } as BaseEvent;\n observer.next(errorEvent);\n state.currentEvents.push(errorEvent);\n this.removeThread(threadId);\n observer.complete();\n });\n\n return () => {\n this.removeThread(threadId);\n };\n });\n }\n\n connect(request: AgentRunnerConnectRequest): Observable<BaseEvent> {\n const { threadId } = request;\n\n return new Observable((observer) => {\n const socket = this.createSocket();\n\n const channel = socket.channel(`agent:${threadId}`, {\n mode: \"connect\",\n });\n\n // Listen for AG-UI events on a single channel event name.\n channel.on(AG_UI_CHANNEL_EVENT, (payload: BaseEvent) => {\n observer.next(payload);\n\n if (\n payload.type === EventType.RUN_FINISHED ||\n payload.type === EventType.RUN_ERROR\n ) {\n observer.complete();\n }\n });\n\n const cleanup = () => {\n channel.leave();\n socket.disconnect();\n };\n\n channel\n .join()\n .receive(\"ok\", () => {\n // Ask the server to replay history via a CUSTOM event.\n channel.push(EventType.CUSTOM, {\n type: EventType.CUSTOM,\n name: \"connect\",\n value: { threadId },\n });\n })\n .receive(\"error\", (resp) => {\n observer.error(\n new Error(`Failed to join channel: ${JSON.stringify(resp)}`),\n );\n cleanup();\n })\n .receive(\"timeout\", () => {\n observer.error(new Error(\"Timed out joining channel\"));\n cleanup();\n });\n\n return () => {\n cleanup();\n };\n });\n }\n\n isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean> {\n const state = this.threads.get(request.threadId);\n return Promise.resolve(state?.isRunning ?? false);\n }\n\n stop(request: AgentRunnerStopRequest): Promise<boolean | undefined> {\n const state = this.threads.get(request.threadId);\n if (!state || !state.isRunning || state.stopRequested) {\n return Promise.resolve(false);\n }\n\n state.stopRequested = true;\n\n // Direct local abort — the runtime is the authority.\n if (state.agent) {\n try {\n state.agent.abortRun();\n } catch {\n // Ignore abort errors.\n }\n }\n\n return Promise.resolve(true);\n }\n\n private executeAgentRun(\n request: AgentRunnerRunRequest,\n state: ThreadState,\n threadId: string,\n ): Observable<void> {\n const { currentEvents, channel } = state;\n\n return from(\n request.agent.runAgent(request.input, {\n onEvent: ({ event }: { event: BaseEvent }) => {\n currentEvents.push(event);\n\n // Push to Phoenix channel so frontend WS listeners receive it.\n channel.push(AG_UI_CHANNEL_EVENT, event);\n },\n }),\n ).pipe(\n catchError((error) => {\n const errorEvent = {\n type: EventType.RUN_ERROR,\n message: error instanceof Error ? error.message : String(error),\n } as BaseEvent;\n currentEvents.push(errorEvent);\n channel.push(AG_UI_CHANNEL_EVENT, errorEvent);\n return EMPTY;\n }),\n finalize(() => {\n const appended = finalizeRunEvents(currentEvents, {\n stopRequested: state.stopRequested,\n });\n for (const event of appended) {\n channel.push(AG_UI_CHANNEL_EVENT, event);\n }\n this.removeThread(threadId);\n }),\n );\n }\n\n /**\n * Tear down all resources for a thread: leave the channel,\n * disconnect the per-run socket, and remove the thread state.\n */\n private removeThread(threadId: string): void {\n const state = this.threads.get(threadId);\n if (state) {\n state.channel.leave();\n state.socket.disconnect();\n this.threads.delete(threadId);\n }\n }\n}\n"],"mappings":";;;;;;;;AAiCA,IAAa,0BAAb,cAA6C,YAAY;CACvD,AAAQ;CACR,AAAQ,0BAAU,IAAI,KAA0B;CAEhD,YAAY,SAAyC;AACnD,SAAO;AAEP,OAAK,UAAU;;;;;;;;;;;;;;;;;;;;;;;CAwBjB,AAAQ,eAAuB;EAC7B,MAAM,SAAS,IAAI,OAAO,KAAK,QAAQ,KAAK;GAC1C,QAAQ,KAAK,QAAQ,gBAAgB,EAAE;GACvC,kBAAkB,0BAA0B,KAAK,IAAO;GACxD,eAAe,0BAA0B,KAAO,IAAO;GACxD,CAAC;AACF,SAAO,SAAS;AAChB,SAAO;;CAGT,IAAI,SAAuD;EACzD,MAAM,EAAE,UAAU,OAAO,UAAU;AAGnC,MADiB,KAAK,QAAQ,IAAI,SAAS,EAC7B,UACZ,OAAM,IAAI,MAAM,yBAAyB;AAG3C,SAAO,IAAI,YAAY,aAAa;GAClC,MAAM,SAAS,KAAK,cAAc;GAElC,MAAM,UAAU,OAAO,QAAQ,SAAS,YAAY,EAClD,OAAO,MAAM,OACd,CAAC;GAEF,MAAM,QAAqB;IACzB;IACA;IACA,WAAW;IACX,eAAe;IACf;IACA,eAAe,EAAE;IAClB;AACD,QAAK,QAAQ,IAAI,UAAU,MAAM;GAYjC,MAAM,yBAAyB;GAC/B,IAAI,oBAAoB;AAExB,UAAO,cAAc;AACnB;AACA,QAAI,qBAAqB,0BAA0B,MAAM,MACvD,KAAI;AACF,WAAM,MAAM,UAAU;YAChB;KAMV;AAEF,UAAO,aAAa;AAGlB,wBAAoB;KACpB;AAOF,WAAQ,GAAG,sBAAsB,YAAuB;AACtD,QACE,QAAQ,SAAS,UAAU,UAC1B,QAA0C,SAAS,OAEpD,MAAK,KAAK,EAAE,UAAU,CAAC;KAEzB;AAEF,WACG,MAAM,CACN,QAAQ,YAAY;AACnB,SAAK,gBAAgB,SAAS,OAAO,SAAS,CAAC,UAAU,EACvD,gBAAgB,SAAS,UAAU,EACpC,CAAC;KACF,CACD,QAAQ,UAAU,SAAS;IAC1B,MAAM,aAAa;KACjB,MAAM,UAAU;KAChB,SAAS,2BAA2B,KAAK,UAAU,KAAK;KACxD,MAAM;KACP;AACD,aAAS,KAAK,WAAW;AACzB,UAAM,cAAc,KAAK,WAAW;AACpC,SAAK,aAAa,SAAS;AAC3B,aAAS,UAAU;KACnB,CACD,QAAQ,iBAAiB;IACxB,MAAM,aAAa;KACjB,MAAM,UAAU;KAChB,SAAS;KACT,MAAM;KACP;AACD,aAAS,KAAK,WAAW;AACzB,UAAM,cAAc,KAAK,WAAW;AACpC,SAAK,aAAa,SAAS;AAC3B,aAAS,UAAU;KACnB;AAEJ,gBAAa;AACX,SAAK,aAAa,SAAS;;IAE7B;;CAGJ,QAAQ,SAA2D;EACjE,MAAM,EAAE,aAAa;AAErB,SAAO,IAAI,YAAY,aAAa;GAClC,MAAM,SAAS,KAAK,cAAc;GAElC,MAAM,UAAU,OAAO,QAAQ,SAAS,YAAY,EAClD,MAAM,WACP,CAAC;AAGF,WAAQ,GAAG,sBAAsB,YAAuB;AACtD,aAAS,KAAK,QAAQ;AAEtB,QACE,QAAQ,SAAS,UAAU,gBAC3B,QAAQ,SAAS,UAAU,UAE3B,UAAS,UAAU;KAErB;GAEF,MAAM,gBAAgB;AACpB,YAAQ,OAAO;AACf,WAAO,YAAY;;AAGrB,WACG,MAAM,CACN,QAAQ,YAAY;AAEnB,YAAQ,KAAK,UAAU,QAAQ;KAC7B,MAAM,UAAU;KAChB,MAAM;KACN,OAAO,EAAE,UAAU;KACpB,CAAC;KACF,CACD,QAAQ,UAAU,SAAS;AAC1B,aAAS,sBACP,IAAI,MAAM,2BAA2B,KAAK,UAAU,KAAK,GAAG,CAC7D;AACD,aAAS;KACT,CACD,QAAQ,iBAAiB;AACxB,aAAS,sBAAM,IAAI,MAAM,4BAA4B,CAAC;AACtD,aAAS;KACT;AAEJ,gBAAa;AACX,aAAS;;IAEX;;CAGJ,UAAU,SAAwD;EAChE,MAAM,QAAQ,KAAK,QAAQ,IAAI,QAAQ,SAAS;AAChD,SAAO,QAAQ,QAAQ,OAAO,aAAa,MAAM;;CAGnD,KAAK,SAA+D;EAClE,MAAM,QAAQ,KAAK,QAAQ,IAAI,QAAQ,SAAS;AAChD,MAAI,CAAC,SAAS,CAAC,MAAM,aAAa,MAAM,cACtC,QAAO,QAAQ,QAAQ,MAAM;AAG/B,QAAM,gBAAgB;AAGtB,MAAI,MAAM,MACR,KAAI;AACF,SAAM,MAAM,UAAU;UAChB;AAKV,SAAO,QAAQ,QAAQ,KAAK;;CAG9B,AAAQ,gBACN,SACA,OACA,UACkB;EAClB,MAAM,EAAE,eAAe,YAAY;AAEnC,SAAO,KACL,QAAQ,MAAM,SAAS,QAAQ,OAAO,EACpC,UAAU,EAAE,YAAkC;AAC5C,iBAAc,KAAK,MAAM;AAGzB,WAAQ,KAAK,qBAAqB,MAAM;KAE3C,CAAC,CACH,CAAC,KACA,YAAY,UAAU;GACpB,MAAM,aAAa;IACjB,MAAM,UAAU;IAChB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAChE;AACD,iBAAc,KAAK,WAAW;AAC9B,WAAQ,KAAK,qBAAqB,WAAW;AAC7C,UAAO;IACP,EACF,eAAe;GACb,MAAM,WAAW,kBAAkB,eAAe,EAChD,eAAe,MAAM,eACtB,CAAC;AACF,QAAK,MAAM,SAAS,SAClB,SAAQ,KAAK,qBAAqB,MAAM;AAE1C,QAAK,aAAa,SAAS;IAC3B,CACH;;;;;;CAOH,AAAQ,aAAa,UAAwB;EAC3C,MAAM,QAAQ,KAAK,QAAQ,IAAI,SAAS;AACxC,MAAI,OAAO;AACT,SAAM,QAAQ,OAAO;AACrB,SAAM,OAAO,YAAY;AACzB,QAAK,QAAQ,OAAO,SAAS"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkitnext/runtime",
|
|
3
|
-
"version": "1.53.0",
|
|
3
|
+
"version": "1.53.1-next.0",
|
|
4
4
|
"description": "Server-side runtime package for CopilotKit2",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"types": "./dist/index.d.cts",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"tsdown": "^0.20.3",
|
|
30
30
|
"typescript": "5.8.2",
|
|
31
31
|
"vitest": "^3.0.5",
|
|
32
|
-
"@copilotkitnext/eslint-config": "1.53.0",
|
|
33
|
-
"@copilotkitnext/typescript-config": "1.53.0"
|
|
32
|
+
"@copilotkitnext/eslint-config": "1.53.1-next.0",
|
|
33
|
+
"@copilotkitnext/typescript-config": "1.53.1-next.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@ag-ui/a2ui-middleware": "0.0.2",
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
"express": "^4.21.2",
|
|
45
45
|
"hono": "^4.11.4",
|
|
46
46
|
"rxjs": "7.8.1",
|
|
47
|
-
"@copilotkitnext/shared": "1.53.0"
|
|
47
|
+
"@copilotkitnext/shared": "1.53.1-next.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@ag-ui/client": "0.0.47",
|
|
51
51
|
"@ag-ui/core": "0.0.47",
|
|
52
52
|
"@ag-ui/encoder": "0.0.47",
|
|
53
|
-
"@copilotkitnext/shared": "1.53.0"
|
|
53
|
+
"@copilotkitnext/shared": "1.53.1-next.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {},
|
|
56
56
|
"engines": {
|