@copilotkit/runtime 1.55.2 → 1.55.3-canary.1776243725
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/agent/converters/tanstack.cjs.map +1 -1
- package/dist/agent/converters/tanstack.d.cts +6 -19
- package/dist/agent/converters/tanstack.d.cts.map +1 -1
- package/dist/agent/converters/tanstack.d.mts +6 -19
- package/dist/agent/converters/tanstack.d.mts.map +1 -1
- package/dist/agent/converters/tanstack.mjs.map +1 -1
- package/dist/agent/index.cjs +14 -0
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +12 -1
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts +12 -1
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +14 -0
- package/dist/agent/index.mjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.mts +2 -1
- package/dist/lib/index.d.cts +1 -0
- package/dist/lib/index.d.cts.map +1 -1
- package/dist/lib/index.d.mts +1 -0
- package/dist/lib/index.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +13 -4
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts +3 -3
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts +3 -3
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +13 -4
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/package.cjs +4 -3
- package/dist/package.mjs +4 -3
- package/dist/service-adapters/openai/openai-adapter.cjs +1 -1
- package/dist/service-adapters/openai/openai-adapter.cjs.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.cts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.mts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.mjs +2 -2
- package/dist/service-adapters/openai/openai-adapter.mjs.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.cjs +8 -9
- package/dist/service-adapters/openai/openai-assistant-adapter.cjs.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.d.cts.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.d.mts.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.mjs +9 -10
- package/dist/service-adapters/openai/openai-assistant-adapter.mjs.map +1 -1
- package/dist/service-adapters/openai/utils.cjs +53 -0
- package/dist/service-adapters/openai/utils.cjs.map +1 -1
- package/dist/service-adapters/openai/utils.mjs +51 -1
- package/dist/service-adapters/openai/utils.mjs.map +1 -1
- package/dist/v2/index.cjs +1 -0
- package/dist/v2/index.d.cts +3 -3
- package/dist/v2/index.d.mts +3 -3
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/runtime/core/runtime.cjs +13 -0
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +43 -3
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +43 -3
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +13 -1
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/get-runtime-info.cjs +18 -10
- package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -1
- package/dist/v2/runtime/handlers/get-runtime-info.mjs +19 -11
- package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.cjs +1 -1
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-stop.cjs +2 -1
- package/dist/v2/runtime/handlers/handle-stop.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-stop.mjs +2 -1
- package/dist/v2/runtime/handlers/handle-stop.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +3 -2
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +3 -2
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -1
- package/dist/v2/runtime/index.d.mts +1 -1
- package/package.json +5 -4
- package/src/agent/__tests__/capabilities.test.ts +81 -0
- package/src/agent/converters/tanstack.ts +15 -7
- package/src/agent/index.ts +33 -0
- package/src/lib/runtime/__tests__/v1-agent-factory.test.ts +109 -0
- package/src/lib/runtime/copilot-runtime.ts +23 -2
- package/src/service-adapters/openai/__tests__/openai-v5-compat.test.ts +177 -0
- package/src/service-adapters/openai/openai-adapter.ts +3 -1
- package/src/service-adapters/openai/openai-assistant-adapter.ts +7 -9
- package/src/service-adapters/openai/utils.ts +100 -0
- package/src/v2/runtime/__tests__/agents-factory.test.ts +136 -0
- package/src/v2/runtime/__tests__/get-runtime-info.test.ts +134 -1
- package/src/v2/runtime/core/runtime.ts +63 -2
- package/src/v2/runtime/handlers/get-runtime-info.ts +33 -8
- package/src/v2/runtime/handlers/handle-connect.ts +1 -1
- package/src/v2/runtime/handlers/handle-run.ts +1 -1
- package/src/v2/runtime/handlers/handle-stop.ts +2 -1
- package/src/v2/runtime/handlers/intelligence/thread-names.ts +1 -1
- package/src/v2/runtime/handlers/shared/agent-utils.ts +3 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { handleGetRuntimeInfo } from "../handlers/get-runtime-info";
|
|
2
2
|
import { CopilotRuntime } from "../core/runtime";
|
|
3
3
|
import { TranscriptionService } from "../transcription-service/transcription-service";
|
|
4
|
-
import { describe, it, expect } from "vitest";
|
|
4
|
+
import { describe, it, expect, vi } from "vitest";
|
|
5
5
|
import type { AbstractAgent } from "@ag-ui/client";
|
|
6
6
|
|
|
7
7
|
// Mock transcription service
|
|
@@ -117,6 +117,139 @@ describe("handleGetRuntimeInfo", () => {
|
|
|
117
117
|
expect(data.a2uiEnabled).toBe(true);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
it("should include capabilities when agent implements getCapabilities", async () => {
|
|
121
|
+
const mockCapabilities = {
|
|
122
|
+
tools: { supported: true, clientProvided: true },
|
|
123
|
+
transport: { streaming: true },
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const mockAgent = {
|
|
127
|
+
description: "Capable agent",
|
|
128
|
+
constructor: { name: "CapableAgent" },
|
|
129
|
+
getCapabilities: async () => mockCapabilities,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const runtime = new CopilotRuntime({
|
|
133
|
+
agents: {
|
|
134
|
+
capableAgent: mockAgent as unknown as AbstractAgent,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const response = await handleGetRuntimeInfo({
|
|
139
|
+
runtime,
|
|
140
|
+
request: mockRequest,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(response.status).toBe(200);
|
|
144
|
+
|
|
145
|
+
const data = await response.json();
|
|
146
|
+
expect(data.agents.capableAgent.capabilities).toEqual(mockCapabilities);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("should omit capabilities when agent does not implement getCapabilities", async () => {
|
|
150
|
+
const mockAgent = {
|
|
151
|
+
description: "Basic agent",
|
|
152
|
+
constructor: { name: "BasicAgent" },
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const runtime = new CopilotRuntime({
|
|
156
|
+
agents: {
|
|
157
|
+
basicAgent: mockAgent as unknown as AbstractAgent,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const response = await handleGetRuntimeInfo({
|
|
162
|
+
runtime,
|
|
163
|
+
request: mockRequest,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
expect(response.status).toBe(200);
|
|
167
|
+
|
|
168
|
+
const data = await response.json();
|
|
169
|
+
expect(data.agents.basicAgent.capabilities).toBeUndefined();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should include empty capabilities object when getCapabilities returns {}", async () => {
|
|
173
|
+
const mockAgent = {
|
|
174
|
+
description: "Empty caps agent",
|
|
175
|
+
constructor: { name: "EmptyCapsAgent" },
|
|
176
|
+
getCapabilities: async () => ({}),
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const runtime = new CopilotRuntime({
|
|
180
|
+
agents: {
|
|
181
|
+
emptyAgent: mockAgent as unknown as AbstractAgent,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const response = await handleGetRuntimeInfo({
|
|
186
|
+
runtime,
|
|
187
|
+
request: mockRequest,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
expect(response.status).toBe(200);
|
|
191
|
+
|
|
192
|
+
const data = await response.json();
|
|
193
|
+
// {} is truthy, so it should be included in the response
|
|
194
|
+
expect(data.agents.emptyAgent.capabilities).toEqual({});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should isolate per-agent getCapabilities failures and log a warning", async () => {
|
|
198
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
199
|
+
|
|
200
|
+
const failingAgent = {
|
|
201
|
+
description: "Failing agent",
|
|
202
|
+
constructor: { name: "FailingAgent" },
|
|
203
|
+
getCapabilities: async () => {
|
|
204
|
+
throw new Error("capability fetch failed");
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const healthyAgent = {
|
|
209
|
+
description: "Healthy agent",
|
|
210
|
+
constructor: { name: "HealthyAgent" },
|
|
211
|
+
getCapabilities: async () => ({
|
|
212
|
+
tools: { supported: true },
|
|
213
|
+
}),
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const runtime = new CopilotRuntime({
|
|
217
|
+
agents: {
|
|
218
|
+
failing: failingAgent as unknown as AbstractAgent,
|
|
219
|
+
healthy: healthyAgent as unknown as AbstractAgent,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const response = await handleGetRuntimeInfo({
|
|
224
|
+
runtime,
|
|
225
|
+
request: mockRequest,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(response.status).toBe(200);
|
|
229
|
+
|
|
230
|
+
const data = await response.json();
|
|
231
|
+
// Failing agent should still appear but without capabilities
|
|
232
|
+
expect(data.agents.failing).toEqual({
|
|
233
|
+
name: "failing",
|
|
234
|
+
description: "Failing agent",
|
|
235
|
+
className: "FailingAgent",
|
|
236
|
+
});
|
|
237
|
+
expect(data.agents.failing.capabilities).toBeUndefined();
|
|
238
|
+
|
|
239
|
+
// Healthy agent should have its capabilities
|
|
240
|
+
expect(data.agents.healthy.capabilities).toEqual({
|
|
241
|
+
tools: { supported: true },
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Error should be logged, not silently swallowed
|
|
245
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
246
|
+
'Failed to fetch capabilities for agent "failing":',
|
|
247
|
+
"capability fetch failed",
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
warnSpy.mockRestore();
|
|
251
|
+
});
|
|
252
|
+
|
|
120
253
|
it("should return 500 error when runtime.agents throws an error", async () => {
|
|
121
254
|
const runtime = {
|
|
122
255
|
get agents(): Record<string, AbstractAgent> {
|
|
@@ -56,9 +56,70 @@ interface CopilotRuntimeMiddlewares {
|
|
|
56
56
|
openGenerativeUI?: OpenGenerativeUIConfig;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Context passed to agent factory functions for per-request agent resolution.
|
|
61
|
+
*/
|
|
62
|
+
export interface AgentFactoryContext {
|
|
63
|
+
/** The incoming HTTP request. */
|
|
64
|
+
request: Request;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A function that dynamically creates agents on a per-request basis.
|
|
69
|
+
* Useful for multi-tenant scenarios or request-scoped agent configuration.
|
|
70
|
+
*/
|
|
71
|
+
export type AgentsFactory = (
|
|
72
|
+
ctx: AgentFactoryContext,
|
|
73
|
+
) => MaybePromise<NonEmptyRecord<Record<string, AbstractAgent>>>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Agents can be provided as:
|
|
77
|
+
* - A static record of agents
|
|
78
|
+
* - A Promise that resolves to a record of agents
|
|
79
|
+
* - A factory function that receives request context and returns agents (or a Promise of agents)
|
|
80
|
+
*/
|
|
81
|
+
export type AgentsConfig =
|
|
82
|
+
| MaybePromise<NonEmptyRecord<Record<string, AbstractAgent>>>
|
|
83
|
+
| AgentsFactory;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Resolve an AgentsConfig value to a concrete record of agents.
|
|
87
|
+
* If the config is a factory function, it is called with the given request context.
|
|
88
|
+
* Otherwise it is awaited directly (static record or Promise).
|
|
89
|
+
*/
|
|
90
|
+
export async function resolveAgents(
|
|
91
|
+
agents: AgentsConfig,
|
|
92
|
+
request?: Request,
|
|
93
|
+
): Promise<Record<string, AbstractAgent>> {
|
|
94
|
+
if (typeof agents === "function") {
|
|
95
|
+
if (!request) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"Agent factory function requires a request context, but none was provided.",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return agents({ request });
|
|
101
|
+
}
|
|
102
|
+
return agents;
|
|
103
|
+
}
|
|
104
|
+
|
|
59
105
|
interface BaseCopilotRuntimeOptions extends CopilotRuntimeMiddlewares {
|
|
60
|
-
/**
|
|
61
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Map of available agents, or a factory function for per-request agent resolution.
|
|
108
|
+
*
|
|
109
|
+
* Static record:
|
|
110
|
+
* ```ts
|
|
111
|
+
* agents: { support: new SupportAgent(), technical: new TechnicalAgent() }
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* Factory function (called per-request):
|
|
115
|
+
* ```ts
|
|
116
|
+
* agents: ({ request }) => {
|
|
117
|
+
* const tenantId = request.headers.get("x-tenant-id");
|
|
118
|
+
* return { default: createAgentForTenant(tenantId) };
|
|
119
|
+
* }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
agents: AgentsConfig;
|
|
62
123
|
/** Optional transcription service for audio processing. */
|
|
63
124
|
transcriptionService?: TranscriptionService;
|
|
64
125
|
/** Optional *before* middleware – callback function or webhook URL. */
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AgentCapabilities } from "@ag-ui/core";
|
|
2
|
+
import {
|
|
3
|
+
CopilotRuntimeLike,
|
|
4
|
+
isIntelligenceRuntime,
|
|
5
|
+
resolveAgents,
|
|
6
|
+
} from "../core/runtime";
|
|
2
7
|
import {
|
|
3
8
|
AgentDescription,
|
|
4
9
|
RuntimeInfo,
|
|
@@ -26,22 +31,42 @@ interface HandleGetRuntimeInfoParameters {
|
|
|
26
31
|
|
|
27
32
|
export async function handleGetRuntimeInfo({
|
|
28
33
|
runtime,
|
|
34
|
+
request,
|
|
29
35
|
}: HandleGetRuntimeInfoParameters) {
|
|
30
36
|
try {
|
|
31
|
-
const agents = await runtime.agents;
|
|
37
|
+
const agents = await resolveAgents(runtime.agents, request);
|
|
38
|
+
|
|
39
|
+
const agentEntries = await Promise.all(
|
|
40
|
+
Object.entries(agents).map(async ([name, agent]) => {
|
|
41
|
+
let capabilities: AgentCapabilities | undefined;
|
|
42
|
+
try {
|
|
43
|
+
capabilities = agent.getCapabilities
|
|
44
|
+
? await agent.getCapabilities()
|
|
45
|
+
: undefined;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
// Per-agent isolation: a single agent failing to report capabilities
|
|
48
|
+
// must not take down the entire /info endpoint.
|
|
49
|
+
console.warn(
|
|
50
|
+
`Failed to fetch capabilities for agent "${name}":`,
|
|
51
|
+
error instanceof Error ? error.message : error,
|
|
52
|
+
);
|
|
53
|
+
capabilities = undefined;
|
|
54
|
+
}
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
(acc, [name, agent]) => {
|
|
35
|
-
acc[name] = {
|
|
56
|
+
const description: AgentDescription = {
|
|
36
57
|
name,
|
|
37
58
|
description: agent.description,
|
|
38
59
|
className: agent.constructor.name,
|
|
60
|
+
...(capabilities ? { capabilities } : {}),
|
|
39
61
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
|
|
63
|
+
return [name, description] as const;
|
|
64
|
+
}),
|
|
43
65
|
);
|
|
44
66
|
|
|
67
|
+
const agentsDict: Record<string, AgentDescription> =
|
|
68
|
+
Object.fromEntries(agentEntries);
|
|
69
|
+
|
|
45
70
|
const runtimeInfo: RuntimeInfo = {
|
|
46
71
|
version: VERSION,
|
|
47
72
|
agents: agentsDict,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CopilotRuntimeLike } from "../core/runtime";
|
|
2
|
+
import { resolveAgents } from "../core/runtime";
|
|
2
3
|
import { EventType } from "@ag-ui/client";
|
|
3
4
|
|
|
4
5
|
interface StopAgentParameters {
|
|
@@ -15,7 +16,7 @@ export async function handleStopAgent({
|
|
|
15
16
|
threadId,
|
|
16
17
|
}: StopAgentParameters) {
|
|
17
18
|
try {
|
|
18
|
-
const agents = await runtime.agents;
|
|
19
|
+
const agents = await resolveAgents(runtime.agents, request);
|
|
19
20
|
|
|
20
21
|
if (!agents[agentId]) {
|
|
21
22
|
return new Response(
|
|
@@ -99,7 +99,7 @@ async function runTitleGenerationAttempt(params: {
|
|
|
99
99
|
prompt: string;
|
|
100
100
|
}): Promise<string | null> {
|
|
101
101
|
const { runtime, request, agentId, threadId, prompt } = params;
|
|
102
|
-
const agent = await cloneAgentForRequest(runtime, agentId);
|
|
102
|
+
const agent = await cloneAgentForRequest(runtime, agentId, request);
|
|
103
103
|
if (isHandlerResponse(agent)) {
|
|
104
104
|
logger.warn(
|
|
105
105
|
{ agentId, threadId },
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "@ag-ui/client";
|
|
6
6
|
import { A2UIMiddleware } from "@ag-ui/a2ui-middleware";
|
|
7
7
|
import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";
|
|
8
|
-
import { CopilotRuntimeLike } from "../../core/runtime";
|
|
8
|
+
import { CopilotRuntimeLike, resolveAgents } from "../../core/runtime";
|
|
9
9
|
import { OpenGenerativeUIMiddleware } from "../../open-generative-ui-middleware";
|
|
10
10
|
import { extractForwardableHeaders } from "../header-utils";
|
|
11
11
|
import { logger } from "@copilotkit/shared";
|
|
@@ -28,8 +28,9 @@ export interface ConnectRequestBody extends RunAgentInput {
|
|
|
28
28
|
export async function cloneAgentForRequest(
|
|
29
29
|
runtime: CopilotRuntimeLike,
|
|
30
30
|
agentId: string,
|
|
31
|
+
request?: Request,
|
|
31
32
|
): Promise<AbstractAgent | Response> {
|
|
32
|
-
const agents = await runtime.agents;
|
|
33
|
+
const agents = await resolveAgents(runtime.agents, request);
|
|
33
34
|
|
|
34
35
|
if (!agents[agentId]) {
|
|
35
36
|
return new Response(
|