@copilotkit/runtime 1.56.2 → 1.56.4
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/graphql/resolvers/copilot.resolver.cjs +2 -1
- package/dist/graphql/resolvers/copilot.resolver.cjs.map +1 -1
- package/dist/graphql/resolvers/copilot.resolver.mjs +2 -1
- package/dist/graphql/resolvers/copilot.resolver.mjs.map +1 -1
- package/dist/graphql/resolvers/resolve-message-id.cjs +19 -0
- package/dist/graphql/resolvers/resolve-message-id.cjs.map +1 -0
- package/dist/graphql/resolvers/resolve-message-id.mjs +18 -0
- package/dist/graphql/resolvers/resolve-message-id.mjs.map +1 -0
- package/dist/lib/runtime/copilot-runtime.cjs +4 -2
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +4 -2
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/package.cjs +2 -2
- package/dist/package.mjs +2 -2
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/runtime/core/debug-event-bus.cjs +36 -0
- package/dist/v2/runtime/core/debug-event-bus.cjs.map +1 -0
- package/dist/v2/runtime/core/debug-event-bus.d.cts +19 -0
- package/dist/v2/runtime/core/debug-event-bus.d.cts.map +1 -0
- package/dist/v2/runtime/core/debug-event-bus.d.mts +19 -0
- package/dist/v2/runtime/core/debug-event-bus.d.mts.map +1 -0
- package/dist/v2/runtime/core/debug-event-bus.mjs +35 -0
- package/dist/v2/runtime/core/debug-event-bus.mjs.map +1 -0
- package/dist/v2/runtime/core/fetch-handler.cjs +8 -0
- package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.cts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.mts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.mjs +8 -0
- package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
- package/dist/v2/runtime/core/fetch-router.cjs +1 -0
- package/dist/v2/runtime/core/fetch-router.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-router.mjs +1 -0
- package/dist/v2/runtime/core/fetch-router.mjs.map +1 -1
- package/dist/v2/runtime/core/hooks.cjs.map +1 -1
- package/dist/v2/runtime/core/hooks.d.cts +2 -0
- package/dist/v2/runtime/core/hooks.d.cts.map +1 -1
- package/dist/v2/runtime/core/hooks.d.mts +2 -0
- package/dist/v2/runtime/core/hooks.d.mts.map +1 -1
- package/dist/v2/runtime/core/hooks.mjs.map +1 -1
- package/dist/v2/runtime/core/runtime.cjs +5 -0
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +5 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +5 -1
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +5 -0
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs +3 -2
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs +3 -2
- package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-debug-events.cjs +33 -0
- package/dist/v2/runtime/handlers/handle-debug-events.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-debug-events.mjs +32 -0
- package/dist/v2/runtime/handlers/handle-debug-events.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-run.cjs +1 -0
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +1 -0
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/connect.cjs +24 -4
- package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/connect.mjs +25 -5
- package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +111 -26
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +111 -26
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs +7 -3
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs +7 -3
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs +5 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs +5 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +21 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +21 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.cjs +3 -1
- package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.mjs +3 -1
- package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.cjs +3 -1
- package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.mjs +3 -1
- package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -1
- package/dist/v2/runtime/index.d.mts +1 -2
- package/dist/v2/runtime/index.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.cjs +6 -8
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +16 -21
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +16 -21
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +6 -8
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.cts +0 -1
- package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.mts +0 -1
- package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -1
- package/dist/v2/runtime/runner/index.d.cts +1 -1
- package/dist/v2/runtime/runner/index.d.mts +1 -1
- package/dist/v2/runtime/runner/intelligence.cjs +47 -10
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.cts +8 -1
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.mts +8 -1
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.mjs +47 -10
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
- package/dist/v2/runtime/telemetry/instance-created.cjs +33 -0
- package/dist/v2/runtime/telemetry/instance-created.cjs.map +1 -0
- package/dist/v2/runtime/telemetry/instance-created.mjs +33 -0
- package/dist/v2/runtime/telemetry/instance-created.mjs.map +1 -0
- package/dist/v2/runtime/telemetry/telemetry-client.cjs +1 -38
- package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.mjs +1 -37
- package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
- package/package.json +3 -3
- package/src/agents/langgraph/__tests__/event-source.test.ts +256 -0
- package/src/graphql/resolvers/__tests__/resolve-message-id.test.ts +25 -0
- package/src/graphql/resolvers/copilot.resolver.ts +2 -1
- package/src/graphql/resolvers/resolve-message-id.ts +14 -0
- package/src/lib/runtime/__tests__/handle-service-adapter.test.ts +108 -0
- package/src/lib/runtime/__tests__/retry-utils.test.ts +137 -0
- package/src/lib/runtime/agent-integrations/langgraph/__tests__/dispatch-event-filtering.test.ts +190 -0
- package/src/lib/runtime/copilot-runtime.ts +20 -4
- package/src/lib/runtime/retry-utils.ts +41 -1
- package/src/v2/runtime/__tests__/express-single-telemetry.integration.test.ts +65 -0
- package/src/v2/runtime/__tests__/express-telemetry.integration.test.ts +101 -0
- package/src/v2/runtime/__tests__/fetch-router.test.ts +22 -0
- package/src/v2/runtime/__tests__/handle-connect.test.ts +183 -23
- package/src/v2/runtime/__tests__/handle-run.test.ts +411 -33
- package/src/v2/runtime/__tests__/handle-threads.test.ts +66 -4
- package/src/v2/runtime/__tests__/hono-single-telemetry.integration.test.ts +46 -0
- package/src/v2/runtime/__tests__/hono-telemetry.integration.test.ts +99 -0
- package/src/v2/runtime/__tests__/integration/node-servers.integration.test.ts +19 -0
- package/src/v2/runtime/__tests__/integration/suites/debug-events.suite.ts +253 -0
- package/src/v2/runtime/__tests__/intelligence-run-telemetry.test.ts +194 -0
- package/src/v2/runtime/__tests__/runtime.test.ts +3 -1
- package/src/v2/runtime/__tests__/sse-response-telemetry.test.ts +108 -0
- package/src/v2/runtime/__tests__/telemetry.test.ts +0 -61
- package/src/v2/runtime/core/__tests__/debug-event-bus.test.ts +156 -0
- package/src/v2/runtime/core/debug-event-bus.ts +45 -0
- package/src/v2/runtime/core/fetch-handler.ts +7 -0
- package/src/v2/runtime/core/fetch-router.ts +11 -0
- package/src/v2/runtime/core/hooks.ts +2 -1
- package/src/v2/runtime/core/runtime.ts +12 -0
- package/src/v2/runtime/handlers/__tests__/handle-debug-events.test.ts +176 -0
- package/src/v2/runtime/handlers/handle-connect.ts +2 -1
- package/src/v2/runtime/handlers/handle-debug-events.ts +52 -0
- package/src/v2/runtime/handlers/handle-run.ts +1 -0
- package/src/v2/runtime/handlers/intelligence/connect.ts +48 -11
- package/src/v2/runtime/handlers/intelligence/run.ts +162 -21
- package/src/v2/runtime/handlers/shared/intelligence-utils.ts +21 -1
- package/src/v2/runtime/handlers/shared/resolve-intelligence-user.ts +4 -1
- package/src/v2/runtime/handlers/shared/sse-response.ts +46 -0
- package/src/v2/runtime/handlers/sse/__tests__/sse-connect-agent-id.test.ts +71 -0
- package/src/v2/runtime/handlers/sse/connect.ts +6 -0
- package/src/v2/runtime/handlers/sse/run.ts +4 -0
- package/src/v2/runtime/intelligence-platform/__tests__/client.test.ts +33 -37
- package/src/v2/runtime/intelligence-platform/client.ts +37 -40
- package/src/v2/runtime/runner/__tests__/intelligence-runner.test.ts +66 -8
- package/src/v2/runtime/runner/agent-runner.ts +0 -1
- package/src/v2/runtime/runner/intelligence.ts +74 -15
- package/src/v2/runtime/telemetry/__tests__/instance-created.test.ts +96 -0
- package/src/v2/runtime/telemetry/instance-created.ts +44 -0
- package/src/v2/runtime/telemetry/telemetry-client.ts +1 -57
- package/dist/v2/runtime/intelligence-platform/index.d.mts +0 -2
- package/dist/v2/runtime/telemetry/utils.cjs +0 -15
- package/dist/v2/runtime/telemetry/utils.cjs.map +0 -1
- package/dist/v2/runtime/telemetry/utils.mjs +0 -14
- package/dist/v2/runtime/telemetry/utils.mjs.map +0 -1
- package/src/v2/runtime/telemetry/utils.ts +0 -15
|
@@ -286,6 +286,49 @@ describe("IntelligenceAgentRunner", () => {
|
|
|
286
286
|
expect(ch.pushLog[2].payload.metadata.cpki_event_seq).toBe(3);
|
|
287
287
|
});
|
|
288
288
|
|
|
289
|
+
it("overrides conflicting event thread and run ownership before pushing to the channel", async () => {
|
|
290
|
+
const threadId = "t-canonical";
|
|
291
|
+
const input = createRunInput({ threadId, runId: "r-canonical" });
|
|
292
|
+
|
|
293
|
+
const agent = new MockAgent([
|
|
294
|
+
{
|
|
295
|
+
type: EventType.RUN_STARTED,
|
|
296
|
+
threadId: "backend-thread",
|
|
297
|
+
runId: "backend-run",
|
|
298
|
+
} as RunStartedEvent,
|
|
299
|
+
{
|
|
300
|
+
type: EventType.RUN_FINISHED,
|
|
301
|
+
threadId: "backend-thread",
|
|
302
|
+
runId: "backend-run",
|
|
303
|
+
} as RunFinishedEvent,
|
|
304
|
+
]);
|
|
305
|
+
|
|
306
|
+
const eventsPromise = collectEvents(
|
|
307
|
+
runner.run({ threadId, agent, input }),
|
|
308
|
+
);
|
|
309
|
+
const ch = mockChannels[0];
|
|
310
|
+
ch.triggerJoin("ok");
|
|
311
|
+
|
|
312
|
+
await eventsPromise;
|
|
313
|
+
|
|
314
|
+
expect(ch.pushLog.map((entry) => entry.payload)).toEqual([
|
|
315
|
+
expect.objectContaining({
|
|
316
|
+
type: EventType.RUN_STARTED,
|
|
317
|
+
threadId,
|
|
318
|
+
runId: input.runId,
|
|
319
|
+
thread_id: threadId,
|
|
320
|
+
run_id: input.runId,
|
|
321
|
+
}),
|
|
322
|
+
expect.objectContaining({
|
|
323
|
+
type: EventType.RUN_FINISHED,
|
|
324
|
+
threadId,
|
|
325
|
+
runId: input.runId,
|
|
326
|
+
thread_id: threadId,
|
|
327
|
+
run_id: input.runId,
|
|
328
|
+
}),
|
|
329
|
+
]);
|
|
330
|
+
});
|
|
331
|
+
|
|
289
332
|
it("rewrites RUN_STARTED input.messages to the unseen persisted subset", async () => {
|
|
290
333
|
const threadId = "t-persisted-input";
|
|
291
334
|
const input = createRunInput({
|
|
@@ -442,7 +485,14 @@ describe("IntelligenceAgentRunner", () => {
|
|
|
442
485
|
(p) => p.payload?.type === EventType.RUN_ERROR,
|
|
443
486
|
);
|
|
444
487
|
expect(errorPush).toBeDefined();
|
|
445
|
-
expect(errorPush!.payload
|
|
488
|
+
expect(errorPush!.payload).toMatchObject({
|
|
489
|
+
type: EventType.RUN_ERROR,
|
|
490
|
+
message: "Something went wrong",
|
|
491
|
+
threadId,
|
|
492
|
+
runId: input.runId,
|
|
493
|
+
thread_id: threadId,
|
|
494
|
+
run_id: input.runId,
|
|
495
|
+
});
|
|
446
496
|
});
|
|
447
497
|
|
|
448
498
|
it("finalizes open message streams before completing", async () => {
|
|
@@ -569,10 +619,9 @@ describe("IntelligenceAgentRunner", () => {
|
|
|
569
619
|
});
|
|
570
620
|
});
|
|
571
621
|
|
|
572
|
-
describe("run
|
|
573
|
-
it("uses
|
|
622
|
+
describe("run channel ownership", () => {
|
|
623
|
+
it("uses runId for the ingestion channel topic", async () => {
|
|
574
624
|
const threadId = "t-jc";
|
|
575
|
-
const joinCode = "join-abc-123";
|
|
576
625
|
const input = createRunInput({ threadId, runId: "r-jc" });
|
|
577
626
|
const agent = new MockAgent([
|
|
578
627
|
{
|
|
@@ -583,15 +632,16 @@ describe("IntelligenceAgentRunner", () => {
|
|
|
583
632
|
]);
|
|
584
633
|
|
|
585
634
|
const eventsPromise = collectEvents(
|
|
586
|
-
runner.run({ threadId, agent, input
|
|
635
|
+
runner.run({ threadId, agent, input }),
|
|
587
636
|
);
|
|
588
637
|
const ch = mockChannels[0];
|
|
589
|
-
expect(ch.topic).toBe(
|
|
638
|
+
expect(ch.topic).toBe("ingestion:r-jc");
|
|
639
|
+
expect(ch.params).toEqual({ thread_id: threadId, run_id: "r-jc" });
|
|
590
640
|
ch.triggerJoin("ok");
|
|
591
641
|
await eventsPromise;
|
|
592
642
|
});
|
|
593
643
|
|
|
594
|
-
it("
|
|
644
|
+
it("keeps pushed event payload ownership on canonical threadId and runId", async () => {
|
|
595
645
|
const threadId = "t-no-jc";
|
|
596
646
|
const input = createRunInput({ threadId, runId: "r-no-jc" });
|
|
597
647
|
const agent = new MockAgent([
|
|
@@ -606,9 +656,17 @@ describe("IntelligenceAgentRunner", () => {
|
|
|
606
656
|
runner.run({ threadId, agent, input }),
|
|
607
657
|
);
|
|
608
658
|
const ch = mockChannels[0];
|
|
609
|
-
expect(ch.topic).toBe(`ingestion:${threadId}`);
|
|
610
659
|
ch.triggerJoin("ok");
|
|
611
660
|
await eventsPromise;
|
|
661
|
+
|
|
662
|
+
expect(ch.pushLog[0].payload).toEqual(
|
|
663
|
+
expect.objectContaining({
|
|
664
|
+
threadId,
|
|
665
|
+
runId: "r-no-jc",
|
|
666
|
+
thread_id: threadId,
|
|
667
|
+
run_id: "r-no-jc",
|
|
668
|
+
}),
|
|
669
|
+
);
|
|
612
670
|
});
|
|
613
671
|
});
|
|
614
672
|
|
|
@@ -32,6 +32,11 @@ export interface IntelligenceAgentRunnerOptions {
|
|
|
32
32
|
maxRejoinMs?: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
export interface RunnerStartupBoundary {
|
|
36
|
+
events: Observable<BaseEvent>;
|
|
37
|
+
startup: Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
interface ThreadState {
|
|
36
41
|
socket: Socket;
|
|
37
42
|
channel: Channel;
|
|
@@ -95,22 +100,33 @@ export class IntelligenceAgentRunner extends AgentRunner {
|
|
|
95
100
|
request: AgentRunnerRunRequest,
|
|
96
101
|
state: ThreadState,
|
|
97
102
|
): Record<string, unknown> {
|
|
98
|
-
const canonicalEvent = this.stampRunnerMetadata(
|
|
103
|
+
const canonicalEvent = this.stampRunnerMetadata(
|
|
104
|
+
this.stampCanonicalRunOwnership(event, request),
|
|
105
|
+
state,
|
|
106
|
+
);
|
|
99
107
|
const payload = {
|
|
100
108
|
...(canonicalEvent as Record<string, unknown>),
|
|
101
109
|
};
|
|
102
110
|
|
|
103
|
-
payload.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (runId) {
|
|
108
|
-
payload.run_id = runId;
|
|
109
|
-
}
|
|
111
|
+
payload.threadId = request.threadId;
|
|
112
|
+
payload.runId = request.input.runId;
|
|
113
|
+
payload.thread_id = request.threadId;
|
|
114
|
+
payload.run_id = request.input.runId;
|
|
110
115
|
|
|
111
116
|
return payload;
|
|
112
117
|
}
|
|
113
118
|
|
|
119
|
+
private stampCanonicalRunOwnership(
|
|
120
|
+
event: BaseEvent,
|
|
121
|
+
request: AgentRunnerRunRequest,
|
|
122
|
+
): BaseEvent {
|
|
123
|
+
return {
|
|
124
|
+
...(event as BaseEvent & Record<string, unknown>),
|
|
125
|
+
threadId: request.threadId,
|
|
126
|
+
runId: request.input.runId,
|
|
127
|
+
} as BaseEvent;
|
|
128
|
+
}
|
|
129
|
+
|
|
114
130
|
private stampRunnerMetadata(event: BaseEvent, state: ThreadState): BaseEvent {
|
|
115
131
|
const eventRecord = event as BaseEvent & {
|
|
116
132
|
metadata?: Record<string, unknown>;
|
|
@@ -142,7 +158,36 @@ export class IntelligenceAgentRunner extends AgentRunner {
|
|
|
142
158
|
}
|
|
143
159
|
|
|
144
160
|
run(request: AgentRunnerRunRequest): Observable<BaseEvent> {
|
|
145
|
-
|
|
161
|
+
return this.createRunObservable(request);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
runWithStartupBoundary(
|
|
165
|
+
request: AgentRunnerRunRequest,
|
|
166
|
+
): RunnerStartupBoundary {
|
|
167
|
+
let resolveStartup: (() => void) | undefined;
|
|
168
|
+
let rejectStartup: ((reason: Error) => void) | undefined;
|
|
169
|
+
const startup = new Promise<void>((resolve, reject) => {
|
|
170
|
+
resolveStartup = resolve;
|
|
171
|
+
rejectStartup = reject;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
events: this.createRunObservable(request, {
|
|
176
|
+
resolveStartup: () => resolveStartup?.(),
|
|
177
|
+
rejectStartup: (error) => rejectStartup?.(error),
|
|
178
|
+
}),
|
|
179
|
+
startup,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private createRunObservable(
|
|
184
|
+
request: AgentRunnerRunRequest,
|
|
185
|
+
startupBoundary?: {
|
|
186
|
+
resolveStartup: () => void;
|
|
187
|
+
rejectStartup: (error: Error) => void;
|
|
188
|
+
},
|
|
189
|
+
): Observable<BaseEvent> {
|
|
190
|
+
const { threadId, agent, input } = request;
|
|
146
191
|
|
|
147
192
|
const existing = this.threads.get(threadId);
|
|
148
193
|
if (existing?.isRunning) {
|
|
@@ -152,9 +197,9 @@ export class IntelligenceAgentRunner extends AgentRunner {
|
|
|
152
197
|
return new Observable((observer) => {
|
|
153
198
|
const socket = this.createSocket();
|
|
154
199
|
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
200
|
+
const channel = socket.channel(`ingestion:${input.runId}`, {
|
|
201
|
+
thread_id: threadId,
|
|
202
|
+
run_id: input.runId,
|
|
158
203
|
});
|
|
159
204
|
|
|
160
205
|
const state: ThreadState = {
|
|
@@ -218,30 +263,37 @@ export class IntelligenceAgentRunner extends AgentRunner {
|
|
|
218
263
|
channel
|
|
219
264
|
.join()
|
|
220
265
|
.receive("ok", () => {
|
|
266
|
+
startupBoundary?.resolveStartup();
|
|
221
267
|
this.executeAgentRun(request, state, threadId).subscribe({
|
|
222
268
|
complete: () => observer.complete(),
|
|
223
269
|
});
|
|
224
270
|
})
|
|
225
271
|
.receive("error", (resp) => {
|
|
272
|
+
const error = new Error(
|
|
273
|
+
`Failed to join channel: ${JSON.stringify(resp)}`,
|
|
274
|
+
);
|
|
226
275
|
const errorEvent = {
|
|
227
276
|
type: EventType.RUN_ERROR,
|
|
228
|
-
message:
|
|
277
|
+
message: error.message,
|
|
229
278
|
code: "CHANNEL_JOIN_ERROR",
|
|
230
279
|
} as BaseEvent;
|
|
231
280
|
observer.next(errorEvent);
|
|
232
281
|
state.currentEvents.push(errorEvent);
|
|
233
282
|
this.removeThread(threadId);
|
|
283
|
+
startupBoundary?.rejectStartup(error);
|
|
234
284
|
observer.complete();
|
|
235
285
|
})
|
|
236
286
|
.receive("timeout", () => {
|
|
287
|
+
const error = new Error("Timed out joining channel");
|
|
237
288
|
const errorEvent = {
|
|
238
289
|
type: EventType.RUN_ERROR,
|
|
239
|
-
message:
|
|
290
|
+
message: error.message,
|
|
240
291
|
code: "CHANNEL_JOIN_TIMEOUT",
|
|
241
292
|
} as BaseEvent;
|
|
242
293
|
observer.next(errorEvent);
|
|
243
294
|
state.currentEvents.push(errorEvent);
|
|
244
295
|
this.removeThread(threadId);
|
|
296
|
+
startupBoundary?.rejectStartup(error);
|
|
245
297
|
observer.complete();
|
|
246
298
|
});
|
|
247
299
|
|
|
@@ -327,7 +379,10 @@ export class IntelligenceAgentRunner extends AgentRunner {
|
|
|
327
379
|
): Observable<void> {
|
|
328
380
|
const { currentEvents, channel } = state;
|
|
329
381
|
const pushCanonicalEvent = (event: BaseEvent): void => {
|
|
330
|
-
const canonicalEvent = this.stampRunnerMetadata(
|
|
382
|
+
const canonicalEvent = this.stampRunnerMetadata(
|
|
383
|
+
this.stampCanonicalRunOwnership(event, request),
|
|
384
|
+
state,
|
|
385
|
+
);
|
|
331
386
|
currentEvents.push(canonicalEvent);
|
|
332
387
|
|
|
333
388
|
if (canonicalEvent.type === EventType.RUN_STARTED) {
|
|
@@ -355,8 +410,12 @@ export class IntelligenceAgentRunner extends AgentRunner {
|
|
|
355
410
|
threadId: request.threadId,
|
|
356
411
|
runId: request.input.runId,
|
|
357
412
|
}),
|
|
413
|
+
threadId: request.threadId,
|
|
414
|
+
runId: request.input.runId,
|
|
358
415
|
input: {
|
|
359
416
|
...baseInput,
|
|
417
|
+
threadId: request.threadId,
|
|
418
|
+
runId: request.input.runId,
|
|
360
419
|
...(persistedInputMessages !== undefined
|
|
361
420
|
? { messages: persistedInputMessages }
|
|
362
421
|
: {}),
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { telemetry } from "..";
|
|
3
|
+
import { fireInstanceCreatedTelemetry } from "../instance-created";
|
|
4
|
+
import type { CopilotRuntimeLike } from "../../core/runtime";
|
|
5
|
+
|
|
6
|
+
// Minimal runtime stub: we only use `agents` from CopilotRuntimeLike inside
|
|
7
|
+
// the helper, so we cast the stub rather than construct a full runtime.
|
|
8
|
+
function makeRuntime(
|
|
9
|
+
agents:
|
|
10
|
+
| Record<string, unknown>
|
|
11
|
+
| Promise<Record<string, unknown>>
|
|
12
|
+
| ((ctx: { request: Request }) => Record<string, unknown>),
|
|
13
|
+
): CopilotRuntimeLike {
|
|
14
|
+
return { agents } as unknown as CopilotRuntimeLike;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("fireInstanceCreatedTelemetry", () => {
|
|
18
|
+
let captureSpy: ReturnType<typeof vi.spyOn>;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
captureSpy = vi.spyOn(telemetry, "capture").mockResolvedValue(undefined);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
captureSpy.mockRestore();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("captures instance_created with agent count from static agents record", async () => {
|
|
29
|
+
fireInstanceCreatedTelemetry({
|
|
30
|
+
runtime: makeRuntime({ a1: {}, a2: {}, a3: {} }),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await vi.waitFor(() => expect(captureSpy).toHaveBeenCalled());
|
|
34
|
+
|
|
35
|
+
expect(captureSpy).toHaveBeenCalledWith("oss.runtime.instance_created", {
|
|
36
|
+
actionsAmount: 0,
|
|
37
|
+
endpointTypes: [],
|
|
38
|
+
endpointsAmount: 0,
|
|
39
|
+
agentsAmount: 3,
|
|
40
|
+
"cloud.api_key_provided": false,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("awaits Promise-based agents before capturing", async () => {
|
|
45
|
+
fireInstanceCreatedTelemetry({
|
|
46
|
+
runtime: makeRuntime(Promise.resolve({ only: {} })),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await vi.waitFor(() => expect(captureSpy).toHaveBeenCalled());
|
|
50
|
+
|
|
51
|
+
const call = captureSpy.mock.calls[0][1] as { agentsAmount: number | null };
|
|
52
|
+
expect(call.agentsAmount).toBe(1);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("reports agentsAmount: null when agents is a factory (cannot resolve without request)", async () => {
|
|
56
|
+
fireInstanceCreatedTelemetry({
|
|
57
|
+
runtime: makeRuntime(() => ({ x: {} })),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
await vi.waitFor(() => expect(captureSpy).toHaveBeenCalled());
|
|
61
|
+
|
|
62
|
+
const call = captureSpy.mock.calls[0][1] as { agentsAmount: number | null };
|
|
63
|
+
expect(call.agentsAmount).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("does not hardcode cloud.api_key_provided — it is false at handler-creation time by design (key arrives per-request via header)", async () => {
|
|
67
|
+
fireInstanceCreatedTelemetry({
|
|
68
|
+
runtime: makeRuntime({ a1: {} }),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
await vi.waitFor(() => expect(captureSpy).toHaveBeenCalled());
|
|
72
|
+
|
|
73
|
+
const call = captureSpy.mock.calls[0][1] as {
|
|
74
|
+
"cloud.api_key_provided": boolean;
|
|
75
|
+
};
|
|
76
|
+
expect(call["cloud.api_key_provided"]).toBe(false);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("does not throw or reject when agents Promise rejects", async () => {
|
|
80
|
+
// Swallow the unhandled rejection from the input Promise itself — the
|
|
81
|
+
// Promise we pass in rejects synchronously regardless of whether we
|
|
82
|
+
// attach a .catch downstream.
|
|
83
|
+
const rejectingAgents = Promise.reject(new Error("boom"));
|
|
84
|
+
rejectingAgents.catch(() => {});
|
|
85
|
+
|
|
86
|
+
expect(() =>
|
|
87
|
+
fireInstanceCreatedTelemetry({
|
|
88
|
+
runtime: makeRuntime(rejectingAgents as any),
|
|
89
|
+
}),
|
|
90
|
+
).not.toThrow();
|
|
91
|
+
|
|
92
|
+
// Wait a microtask to let the internal catch fire; no capture should happen.
|
|
93
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
94
|
+
expect(captureSpy).not.toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { telemetry } from ".";
|
|
2
|
+
import type { CopilotRuntimeLike } from "../core/runtime";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fire the `oss.runtime.instance_created` telemetry event for a v2 runtime
|
|
6
|
+
* handler. Called once per handler factory invocation (not per request).
|
|
7
|
+
*
|
|
8
|
+
* v2 does not have a concept of remote endpoints or standalone actions, so
|
|
9
|
+
* those counts are 0 / []. `cloud.api_key_provided` is false at this level
|
|
10
|
+
* because in v2 the cloud public key arrives per-request via the
|
|
11
|
+
* `x-copilotcloud-public-api-key` header — not at handler creation time.
|
|
12
|
+
* See `handlers/handle-run.ts` for the per-request event that DOES carry
|
|
13
|
+
* the key when present.
|
|
14
|
+
*
|
|
15
|
+
* Errors resolving agents are swallowed — telemetry must never break
|
|
16
|
+
* runtime setup.
|
|
17
|
+
*/
|
|
18
|
+
export function fireInstanceCreatedTelemetry({
|
|
19
|
+
runtime,
|
|
20
|
+
}: {
|
|
21
|
+
runtime: CopilotRuntimeLike;
|
|
22
|
+
}): void {
|
|
23
|
+
// agents can be a static Record, a Promise, or a per-request factory.
|
|
24
|
+
// Factory configs cannot be resolved at handler-creation time (no Request
|
|
25
|
+
// context), so report agentsAmount as null in that case.
|
|
26
|
+
const agentsPromise =
|
|
27
|
+
typeof runtime.agents === "function"
|
|
28
|
+
? Promise.resolve<Record<string, unknown> | null>(null)
|
|
29
|
+
: Promise.resolve(runtime.agents);
|
|
30
|
+
|
|
31
|
+
agentsPromise
|
|
32
|
+
.then((agents) => {
|
|
33
|
+
telemetry.capture("oss.runtime.instance_created", {
|
|
34
|
+
actionsAmount: 0,
|
|
35
|
+
endpointTypes: [],
|
|
36
|
+
endpointsAmount: 0,
|
|
37
|
+
agentsAmount: agents ? Object.keys(agents).length : null,
|
|
38
|
+
"cloud.api_key_provided": false,
|
|
39
|
+
});
|
|
40
|
+
})
|
|
41
|
+
.catch(() => {
|
|
42
|
+
// Swallow — telemetry must not break runtime creation.
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { Analytics } from "@segment/analytics-node";
|
|
2
1
|
import { AnalyticsEvents } from "./events";
|
|
3
|
-
import { flattenObject } from "./utils";
|
|
4
|
-
import { v4 as uuidv4 } from "uuid";
|
|
5
2
|
import scarfClient from "./scarf-client";
|
|
6
3
|
|
|
7
4
|
export function isTelemetryDisabled(): boolean {
|
|
@@ -17,11 +14,8 @@ export function isTelemetryDisabled(): boolean {
|
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
export class TelemetryClient {
|
|
20
|
-
segment: Analytics | undefined;
|
|
21
|
-
globalProperties: Record<string, any> = {};
|
|
22
17
|
private telemetryDisabled: boolean = false;
|
|
23
18
|
private sampleRate: number = 0.05;
|
|
24
|
-
private anonymousId = `anon_${uuidv4()}`;
|
|
25
19
|
|
|
26
20
|
constructor({
|
|
27
21
|
telemetryDisabled,
|
|
@@ -31,21 +25,7 @@ export class TelemetryClient {
|
|
|
31
25
|
sampleRate?: number;
|
|
32
26
|
} = {}) {
|
|
33
27
|
this.telemetryDisabled = telemetryDisabled ?? isTelemetryDisabled();
|
|
34
|
-
|
|
35
|
-
if (this.telemetryDisabled) {
|
|
36
|
-
this.setSampleRate(sampleRate);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
28
|
this.setSampleRate(sampleRate);
|
|
41
|
-
|
|
42
|
-
const writeKey =
|
|
43
|
-
process.env.COPILOTKIT_SEGMENT_WRITE_KEY ||
|
|
44
|
-
"n7XAZtQCGS2v1vvBy3LgBCv2h3Y8whja";
|
|
45
|
-
|
|
46
|
-
this.segment = new Analytics({
|
|
47
|
-
writeKey,
|
|
48
|
-
});
|
|
49
29
|
}
|
|
50
30
|
|
|
51
31
|
private shouldSendEvent() {
|
|
@@ -58,48 +38,17 @@ export class TelemetryClient {
|
|
|
58
38
|
|
|
59
39
|
async capture<K extends keyof AnalyticsEvents>(
|
|
60
40
|
event: K,
|
|
61
|
-
|
|
41
|
+
_properties: AnalyticsEvents[K],
|
|
62
42
|
) {
|
|
63
43
|
if (!this.shouldSendEvent()) {
|
|
64
44
|
return;
|
|
65
45
|
}
|
|
66
46
|
|
|
67
|
-
const flattenedProperties = flattenObject(properties);
|
|
68
|
-
const propertiesWithGlobal = {
|
|
69
|
-
...this.globalProperties,
|
|
70
|
-
...flattenedProperties,
|
|
71
|
-
};
|
|
72
|
-
const orderedPropertiesWithGlobal = Object.keys(propertiesWithGlobal)
|
|
73
|
-
.sort()
|
|
74
|
-
.reduce(
|
|
75
|
-
(obj, key) => {
|
|
76
|
-
obj[key] = propertiesWithGlobal[key];
|
|
77
|
-
return obj;
|
|
78
|
-
},
|
|
79
|
-
{} as Record<string, any>,
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
if (this.segment) {
|
|
83
|
-
this.segment.track({
|
|
84
|
-
anonymousId: this.anonymousId,
|
|
85
|
-
event,
|
|
86
|
-
properties: { ...orderedPropertiesWithGlobal },
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
47
|
await scarfClient.logEvent({
|
|
91
48
|
event,
|
|
92
49
|
});
|
|
93
50
|
}
|
|
94
51
|
|
|
95
|
-
setGlobalProperties(properties: Record<string, any>) {
|
|
96
|
-
const flattenedProperties = flattenObject(properties);
|
|
97
|
-
this.globalProperties = {
|
|
98
|
-
...this.globalProperties,
|
|
99
|
-
...flattenedProperties,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
52
|
private setSampleRate(sampleRate: number | undefined) {
|
|
104
53
|
let _sampleRate: number;
|
|
105
54
|
|
|
@@ -114,11 +63,6 @@ export class TelemetryClient {
|
|
|
114
63
|
}
|
|
115
64
|
|
|
116
65
|
this.sampleRate = _sampleRate;
|
|
117
|
-
this.setGlobalProperties({
|
|
118
|
-
sampleRate: this.sampleRate,
|
|
119
|
-
sampleRateAdjustmentFactor: 1 - this.sampleRate,
|
|
120
|
-
sampleWeight: 1 / this.sampleRate,
|
|
121
|
-
});
|
|
122
66
|
}
|
|
123
67
|
}
|
|
124
68
|
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require("reflect-metadata");
|
|
2
|
-
|
|
3
|
-
//#region src/v2/runtime/telemetry/utils.ts
|
|
4
|
-
function flattenObject(obj, parentKey = "", res = {}) {
|
|
5
|
-
for (const key in obj) {
|
|
6
|
-
const propName = parentKey ? `${parentKey}.${key}` : key;
|
|
7
|
-
if (typeof obj[key] === "object" && obj[key] !== null) flattenObject(obj[key], propName, res);
|
|
8
|
-
else res[propName] = obj[key];
|
|
9
|
-
}
|
|
10
|
-
return res;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
//#endregion
|
|
14
|
-
exports.flattenObject = flattenObject;
|
|
15
|
-
//# sourceMappingURL=utils.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","names":[],"sources":["../../../../src/v2/runtime/telemetry/utils.ts"],"sourcesContent":["export function flattenObject(\n obj: Record<string, any>,\n parentKey = \"\",\n res: Record<string, any> = {},\n): Record<string, any> {\n for (const key in obj) {\n const propName = parentKey ? `${parentKey}.${key}` : key;\n if (typeof obj[key] === \"object\" && obj[key] !== null) {\n flattenObject(obj[key], propName, res);\n } else {\n res[propName] = obj[key];\n }\n }\n return res;\n}\n"],"mappings":";;;AAAA,SAAgB,cACd,KACA,YAAY,IACZ,MAA2B,EAAE,EACR;AACrB,MAAK,MAAM,OAAO,KAAK;EACrB,MAAM,WAAW,YAAY,GAAG,UAAU,GAAG,QAAQ;AACrD,MAAI,OAAO,IAAI,SAAS,YAAY,IAAI,SAAS,KAC/C,eAAc,IAAI,MAAM,UAAU,IAAI;MAEtC,KAAI,YAAY,IAAI;;AAGxB,QAAO"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import "reflect-metadata";
|
|
2
|
-
//#region src/v2/runtime/telemetry/utils.ts
|
|
3
|
-
function flattenObject(obj, parentKey = "", res = {}) {
|
|
4
|
-
for (const key in obj) {
|
|
5
|
-
const propName = parentKey ? `${parentKey}.${key}` : key;
|
|
6
|
-
if (typeof obj[key] === "object" && obj[key] !== null) flattenObject(obj[key], propName, res);
|
|
7
|
-
else res[propName] = obj[key];
|
|
8
|
-
}
|
|
9
|
-
return res;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
//#endregion
|
|
13
|
-
export { flattenObject };
|
|
14
|
-
//# sourceMappingURL=utils.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":[],"sources":["../../../../src/v2/runtime/telemetry/utils.ts"],"sourcesContent":["export function flattenObject(\n obj: Record<string, any>,\n parentKey = \"\",\n res: Record<string, any> = {},\n): Record<string, any> {\n for (const key in obj) {\n const propName = parentKey ? `${parentKey}.${key}` : key;\n if (typeof obj[key] === \"object\" && obj[key] !== null) {\n flattenObject(obj[key], propName, res);\n } else {\n res[propName] = obj[key];\n }\n }\n return res;\n}\n"],"mappings":";;AAAA,SAAgB,cACd,KACA,YAAY,IACZ,MAA2B,EAAE,EACR;AACrB,MAAK,MAAM,OAAO,KAAK;EACrB,MAAM,WAAW,YAAY,GAAG,UAAU,GAAG,QAAQ;AACrD,MAAI,OAAO,IAAI,SAAS,YAAY,IAAI,SAAS,KAC/C,eAAc,IAAI,MAAM,UAAU,IAAI;MAEtC,KAAI,YAAY,IAAI;;AAGxB,QAAO"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export function flattenObject(
|
|
2
|
-
obj: Record<string, any>,
|
|
3
|
-
parentKey = "",
|
|
4
|
-
res: Record<string, any> = {},
|
|
5
|
-
): Record<string, any> {
|
|
6
|
-
for (const key in obj) {
|
|
7
|
-
const propName = parentKey ? `${parentKey}.${key}` : key;
|
|
8
|
-
if (typeof obj[key] === "object" && obj[key] !== null) {
|
|
9
|
-
flattenObject(obj[key], propName, res);
|
|
10
|
-
} else {
|
|
11
|
-
res[propName] = obj[key];
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return res;
|
|
15
|
-
}
|