@copilotkitnext/runtime 0.0.18 → 0.0.19-threads-and-attachements.1
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/index.d.mts +247 -4
- package/dist/index.d.ts +247 -4
- package/dist/index.js +634 -120
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +629 -121
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -25,14 +25,21 @@ __export(index_exports, {
|
|
|
25
25
|
InMemoryAgentRunner: () => InMemoryAgentRunner,
|
|
26
26
|
VERSION: () => VERSION,
|
|
27
27
|
createCopilotEndpoint: () => createCopilotEndpoint,
|
|
28
|
-
|
|
28
|
+
createFilteringThreadScopeResolver: () => createFilteringThreadScopeResolver,
|
|
29
|
+
createStrictThreadScopeResolver: () => createStrictThreadScopeResolver,
|
|
30
|
+
filterAuthorizedResourceIds: () => filterAuthorizedResourceIds,
|
|
31
|
+
finalizeRunEvents: () => import_shared5.finalizeRunEvents,
|
|
32
|
+
validateResourceIdMatch: () => validateResourceIdMatch
|
|
29
33
|
});
|
|
30
34
|
module.exports = __toCommonJS(index_exports);
|
|
31
35
|
|
|
36
|
+
// src/runtime.ts
|
|
37
|
+
var import_shared2 = require("@copilotkitnext/shared");
|
|
38
|
+
|
|
32
39
|
// package.json
|
|
33
40
|
var package_default = {
|
|
34
41
|
name: "@copilotkitnext/runtime",
|
|
35
|
-
version: "0.0.
|
|
42
|
+
version: "0.0.19-threads-and-attachements.1",
|
|
36
43
|
description: "Server-side runtime package for CopilotKit2",
|
|
37
44
|
main: "dist/index.js",
|
|
38
45
|
types: "dist/index.d.ts",
|
|
@@ -68,9 +75,9 @@ var package_default = {
|
|
|
68
75
|
vitest: "^3.0.5"
|
|
69
76
|
},
|
|
70
77
|
dependencies: {
|
|
71
|
-
"@ag-ui/client": "0.0.40-alpha.
|
|
72
|
-
"@ag-ui/core": "0.0.40-alpha.
|
|
73
|
-
"@ag-ui/encoder": "0.0.40-alpha.
|
|
78
|
+
"@ag-ui/client": "0.0.40-alpha.7",
|
|
79
|
+
"@ag-ui/core": "0.0.40-alpha.7",
|
|
80
|
+
"@ag-ui/encoder": "0.0.40-alpha.7",
|
|
74
81
|
"@copilotkitnext/shared": "workspace:*",
|
|
75
82
|
hono: "^4.6.13",
|
|
76
83
|
rxjs: "7.8.1"
|
|
@@ -93,8 +100,10 @@ var import_rxjs = require("rxjs");
|
|
|
93
100
|
var import_client = require("@ag-ui/client");
|
|
94
101
|
var import_shared = require("@copilotkitnext/shared");
|
|
95
102
|
var InMemoryEventStore = class {
|
|
96
|
-
constructor(threadId) {
|
|
103
|
+
constructor(threadId, resourceIds, properties) {
|
|
97
104
|
this.threadId = threadId;
|
|
105
|
+
this.resourceIds = resourceIds;
|
|
106
|
+
this.properties = properties;
|
|
98
107
|
}
|
|
99
108
|
/** The subject that current consumers subscribe to. */
|
|
100
109
|
subject = null;
|
|
@@ -114,11 +123,41 @@ var InMemoryEventStore = class {
|
|
|
114
123
|
currentEvents = null;
|
|
115
124
|
};
|
|
116
125
|
var GLOBAL_STORE = /* @__PURE__ */ new Map();
|
|
126
|
+
function matchesScope(store, scope) {
|
|
127
|
+
if (scope === void 0 || scope === null) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
const scopeIds = Array.isArray(scope.resourceId) ? scope.resourceId : [scope.resourceId];
|
|
131
|
+
return scopeIds.some((scopeId) => store.resourceIds.includes(scopeId));
|
|
132
|
+
}
|
|
117
133
|
var InMemoryAgentRunner = class extends AgentRunner {
|
|
118
134
|
run(request) {
|
|
119
135
|
let existingStore = GLOBAL_STORE.get(request.threadId);
|
|
120
|
-
if (!existingStore) {
|
|
121
|
-
|
|
136
|
+
if (!existingStore && request.scope === null) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
"Cannot create thread with null scope. Admin users must specify an explicit resourceId for the thread owner."
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
let resourceIds;
|
|
142
|
+
if (request.scope === void 0) {
|
|
143
|
+
resourceIds = ["global"];
|
|
144
|
+
} else if (request.scope === null) {
|
|
145
|
+
resourceIds = [];
|
|
146
|
+
} else if (Array.isArray(request.scope.resourceId)) {
|
|
147
|
+
if (request.scope.resourceId.length === 0) {
|
|
148
|
+
throw new Error("Invalid scope: resourceId array cannot be empty");
|
|
149
|
+
}
|
|
150
|
+
resourceIds = request.scope.resourceId;
|
|
151
|
+
} else {
|
|
152
|
+
resourceIds = [request.scope.resourceId];
|
|
153
|
+
}
|
|
154
|
+
if (existingStore) {
|
|
155
|
+
if (request.scope !== null && !matchesScope(existingStore, request.scope)) {
|
|
156
|
+
throw new Error("Unauthorized: Cannot run on thread owned by different resource");
|
|
157
|
+
}
|
|
158
|
+
resourceIds = existingStore.resourceIds;
|
|
159
|
+
} else {
|
|
160
|
+
existingStore = new InMemoryEventStore(request.threadId, resourceIds, request.scope?.properties);
|
|
122
161
|
GLOBAL_STORE.set(request.threadId, existingStore);
|
|
123
162
|
}
|
|
124
163
|
const store = existingStore;
|
|
@@ -162,9 +201,7 @@ var InMemoryAgentRunner = class extends AgentRunner {
|
|
|
162
201
|
if (event.type === import_client.EventType.RUN_STARTED) {
|
|
163
202
|
const runStartedEvent = event;
|
|
164
203
|
if (!runStartedEvent.input) {
|
|
165
|
-
const sanitizedMessages = request.input.messages ? request.input.messages.filter(
|
|
166
|
-
(message) => !historicMessageIds.has(message.id)
|
|
167
|
-
) : void 0;
|
|
204
|
+
const sanitizedMessages = request.input.messages ? request.input.messages.filter((message) => !historicMessageIds.has(message.id)) : void 0;
|
|
168
205
|
const updatedInput = {
|
|
169
206
|
...request.input,
|
|
170
207
|
...sanitizedMessages !== void 0 ? { messages: sanitizedMessages } : {}
|
|
@@ -261,7 +298,7 @@ var InMemoryAgentRunner = class extends AgentRunner {
|
|
|
261
298
|
connect(request) {
|
|
262
299
|
const store = GLOBAL_STORE.get(request.threadId);
|
|
263
300
|
const connectionSubject = new import_rxjs.ReplaySubject(Infinity);
|
|
264
|
-
if (!store) {
|
|
301
|
+
if (!store || !matchesScope(store, request.scope)) {
|
|
265
302
|
connectionSubject.complete();
|
|
266
303
|
return connectionSubject.asObservable();
|
|
267
304
|
}
|
|
@@ -297,54 +334,256 @@ var InMemoryAgentRunner = class extends AgentRunner {
|
|
|
297
334
|
const store = GLOBAL_STORE.get(request.threadId);
|
|
298
335
|
return Promise.resolve(store?.isRunning ?? false);
|
|
299
336
|
}
|
|
300
|
-
stop(request) {
|
|
337
|
+
async stop(request) {
|
|
301
338
|
const store = GLOBAL_STORE.get(request.threadId);
|
|
302
|
-
if (!store
|
|
303
|
-
return
|
|
304
|
-
}
|
|
305
|
-
if (store.stopRequested) {
|
|
306
|
-
return Promise.resolve(false);
|
|
339
|
+
if (!store) {
|
|
340
|
+
return false;
|
|
307
341
|
}
|
|
308
|
-
store.
|
|
309
|
-
|
|
310
|
-
const agent = store.agent;
|
|
311
|
-
if (!agent) {
|
|
312
|
-
store.stopRequested = false;
|
|
342
|
+
if (store.isRunning) {
|
|
343
|
+
store.stopRequested = true;
|
|
313
344
|
store.isRunning = false;
|
|
314
|
-
|
|
345
|
+
const agent = store.agent;
|
|
346
|
+
try {
|
|
347
|
+
if (agent) {
|
|
348
|
+
agent.abortRun();
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
return false;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.warn("Failed to abort in-memory runner:", error);
|
|
354
|
+
store.stopRequested = false;
|
|
355
|
+
store.isRunning = true;
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
315
358
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
async listThreads(request) {
|
|
362
|
+
const limit = request.limit ?? 50;
|
|
363
|
+
const offset = request.offset ?? 0;
|
|
364
|
+
if (request.scope !== void 0 && request.scope !== null) {
|
|
365
|
+
const scopeIds = Array.isArray(request.scope.resourceId) ? request.scope.resourceId : [request.scope.resourceId];
|
|
366
|
+
if (scopeIds.length === 0) {
|
|
367
|
+
return { threads: [], total: 0 };
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const threadInfos = [];
|
|
371
|
+
for (const [threadId, store] of GLOBAL_STORE.entries()) {
|
|
372
|
+
if (threadId.includes("-suggestions-")) {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (!matchesScope(store, request.scope)) {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (store.historicRuns.length === 0) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
const firstRun = store.historicRuns[0];
|
|
382
|
+
const lastRun = store.historicRuns[store.historicRuns.length - 1];
|
|
383
|
+
if (!firstRun || !lastRun) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
threadInfos.push({
|
|
387
|
+
threadId,
|
|
388
|
+
createdAt: firstRun.createdAt,
|
|
389
|
+
lastActivityAt: lastRun.createdAt,
|
|
390
|
+
store
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
threadInfos.sort((a, b) => b.lastActivityAt - a.lastActivityAt);
|
|
394
|
+
const total = threadInfos.length;
|
|
395
|
+
const paginatedInfos = threadInfos.slice(offset, offset + limit);
|
|
396
|
+
const threads = paginatedInfos.map((info) => {
|
|
397
|
+
let firstMessage;
|
|
398
|
+
const firstRun = info.store.historicRuns[0];
|
|
399
|
+
if (firstRun) {
|
|
400
|
+
const textContent = firstRun.events.find((e) => e.type === import_client.EventType.TEXT_MESSAGE_CONTENT);
|
|
401
|
+
if (textContent?.delta) {
|
|
402
|
+
firstMessage = textContent.delta.substring(0, 100);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
const messageIds = /* @__PURE__ */ new Set();
|
|
406
|
+
for (const run of info.store.historicRuns) {
|
|
407
|
+
for (const event of run.events) {
|
|
408
|
+
if ("messageId" in event && typeof event.messageId === "string") {
|
|
409
|
+
messageIds.add(event.messageId);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
threadId: info.threadId,
|
|
415
|
+
createdAt: info.createdAt,
|
|
416
|
+
lastActivityAt: info.lastActivityAt,
|
|
417
|
+
isRunning: info.store.isRunning,
|
|
418
|
+
messageCount: messageIds.size,
|
|
419
|
+
firstMessage,
|
|
420
|
+
resourceId: info.store.resourceIds[0] || "unknown",
|
|
421
|
+
// Return first for backward compatibility
|
|
422
|
+
properties: info.store.properties
|
|
423
|
+
};
|
|
424
|
+
});
|
|
425
|
+
return { threads, total };
|
|
426
|
+
}
|
|
427
|
+
async getThreadMetadata(threadId, scope) {
|
|
428
|
+
const store = GLOBAL_STORE.get(threadId);
|
|
429
|
+
if (!store || !matchesScope(store, scope) || store.historicRuns.length === 0) {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
const firstRun = store.historicRuns[0];
|
|
433
|
+
const lastRun = store.historicRuns[store.historicRuns.length - 1];
|
|
434
|
+
if (!firstRun || !lastRun) {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
let firstMessage;
|
|
438
|
+
const textContent = firstRun.events.find((e) => e.type === import_client.EventType.TEXT_MESSAGE_CONTENT);
|
|
439
|
+
if (textContent?.delta) {
|
|
440
|
+
firstMessage = textContent.delta.substring(0, 100);
|
|
441
|
+
}
|
|
442
|
+
const messageIds = /* @__PURE__ */ new Set();
|
|
443
|
+
for (const run of store.historicRuns) {
|
|
444
|
+
for (const event of run.events) {
|
|
445
|
+
if ("messageId" in event && typeof event.messageId === "string") {
|
|
446
|
+
messageIds.add(event.messageId);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
threadId,
|
|
452
|
+
createdAt: firstRun.createdAt,
|
|
453
|
+
lastActivityAt: lastRun.createdAt,
|
|
454
|
+
isRunning: store.isRunning,
|
|
455
|
+
messageCount: messageIds.size,
|
|
456
|
+
firstMessage,
|
|
457
|
+
resourceId: store.resourceIds[0] || "unknown",
|
|
458
|
+
// Return first for backward compatibility
|
|
459
|
+
properties: store.properties
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
async deleteThread(threadId, scope) {
|
|
463
|
+
const store = GLOBAL_STORE.get(threadId);
|
|
464
|
+
if (!store || !matchesScope(store, scope)) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (store.agent) {
|
|
468
|
+
try {
|
|
469
|
+
store.agent.abortRun();
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.warn("Failed to abort agent during thread deletion:", error);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
store.subject?.complete();
|
|
475
|
+
GLOBAL_STORE.delete(threadId);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Clear all threads from the global store (for testing purposes only)
|
|
479
|
+
* @internal
|
|
480
|
+
*/
|
|
481
|
+
clearAllThreads() {
|
|
482
|
+
for (const [threadId, store] of GLOBAL_STORE.entries()) {
|
|
483
|
+
if (store.agent) {
|
|
484
|
+
try {
|
|
485
|
+
store.agent.abortRun();
|
|
486
|
+
} catch (error) {
|
|
487
|
+
console.warn("Failed to abort agent during clearAllThreads:", error);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
store.subject?.complete();
|
|
491
|
+
GLOBAL_STORE.delete(threadId);
|
|
324
492
|
}
|
|
325
493
|
}
|
|
326
494
|
};
|
|
327
495
|
|
|
328
496
|
// src/runtime.ts
|
|
329
497
|
var VERSION = package_default.version;
|
|
330
|
-
var CopilotRuntime = class {
|
|
498
|
+
var CopilotRuntime = class _CopilotRuntime {
|
|
499
|
+
/**
|
|
500
|
+
* Built-in global scope for single-user apps or demos.
|
|
501
|
+
*
|
|
502
|
+
* All threads are globally accessible when using this scope.
|
|
503
|
+
*
|
|
504
|
+
* @example
|
|
505
|
+
* ```typescript
|
|
506
|
+
* new CopilotRuntime({
|
|
507
|
+
* agents: { myAgent },
|
|
508
|
+
* resolveThreadsScope: CopilotRuntime.GLOBAL_SCOPE,
|
|
509
|
+
* suppressResourceIdWarning: true
|
|
510
|
+
* });
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
513
|
+
static GLOBAL_SCOPE = async (context) => ({
|
|
514
|
+
resourceId: "global"
|
|
515
|
+
});
|
|
516
|
+
/**
|
|
517
|
+
* Parses the client-declared resource ID(s) from the request header.
|
|
518
|
+
*
|
|
519
|
+
* This is a utility method used internally by handlers to extract the
|
|
520
|
+
* `X-CopilotKit-Resource-ID` header sent by the client via `CopilotKitProvider`.
|
|
521
|
+
*
|
|
522
|
+
* **You typically don't need to call this directly** - it's automatically called
|
|
523
|
+
* by the runtime handlers and passed to your `resolveThreadsScope` function as
|
|
524
|
+
* the `clientDeclared` parameter.
|
|
525
|
+
*
|
|
526
|
+
* @param request - The incoming HTTP request
|
|
527
|
+
* @returns The parsed resource ID(s), or undefined if header is missing
|
|
528
|
+
* - Returns a string if single ID
|
|
529
|
+
* - Returns an array if multiple comma-separated IDs
|
|
530
|
+
* - Returns undefined if header not present
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```typescript
|
|
534
|
+
* // Automatically used internally:
|
|
535
|
+
* const clientDeclared = CopilotRuntime.parseClientDeclaredResourceId(request);
|
|
536
|
+
* const scope = await runtime.resolveThreadsScope({ request, clientDeclared });
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
static parseClientDeclaredResourceId(request) {
|
|
540
|
+
const header = request.headers.get("X-CopilotKit-Resource-ID");
|
|
541
|
+
if (!header) {
|
|
542
|
+
return void 0;
|
|
543
|
+
}
|
|
544
|
+
const values = header.split(",").map((v) => decodeURIComponent(v.trim()));
|
|
545
|
+
return values.length === 1 ? values[0] : values;
|
|
546
|
+
}
|
|
331
547
|
agents;
|
|
332
548
|
transcriptionService;
|
|
333
549
|
beforeRequestMiddleware;
|
|
334
550
|
afterRequestMiddleware;
|
|
335
551
|
runner;
|
|
552
|
+
resolveThreadsScope;
|
|
553
|
+
suppressResourceIdWarning;
|
|
336
554
|
constructor({
|
|
337
555
|
agents,
|
|
338
556
|
transcriptionService,
|
|
339
557
|
beforeRequestMiddleware,
|
|
340
558
|
afterRequestMiddleware,
|
|
341
|
-
runner
|
|
559
|
+
runner,
|
|
560
|
+
resolveThreadsScope,
|
|
561
|
+
suppressResourceIdWarning = false
|
|
342
562
|
}) {
|
|
343
563
|
this.agents = agents;
|
|
344
564
|
this.transcriptionService = transcriptionService;
|
|
345
565
|
this.beforeRequestMiddleware = beforeRequestMiddleware;
|
|
346
566
|
this.afterRequestMiddleware = afterRequestMiddleware;
|
|
347
567
|
this.runner = runner ?? new InMemoryAgentRunner();
|
|
568
|
+
this.resolveThreadsScope = resolveThreadsScope ?? _CopilotRuntime.GLOBAL_SCOPE;
|
|
569
|
+
this.suppressResourceIdWarning = suppressResourceIdWarning;
|
|
570
|
+
if (!resolveThreadsScope && !suppressResourceIdWarning) {
|
|
571
|
+
this.logGlobalScopeWarning();
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
logGlobalScopeWarning() {
|
|
575
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
576
|
+
if (isProduction) {
|
|
577
|
+
import_shared2.logger.error({
|
|
578
|
+
msg: "CopilotKit Security Warning: GLOBAL_SCOPE in production",
|
|
579
|
+
details: "No resolveThreadsScope configured. All threads are globally accessible to all users. Configure authentication for production: https://docs.copilotkit.ai/security/thread-scoping To suppress this warning (if intentional), set suppressResourceIdWarning: true"
|
|
580
|
+
});
|
|
581
|
+
} else {
|
|
582
|
+
import_shared2.logger.warn({
|
|
583
|
+
msg: "CopilotKit: Using GLOBAL_SCOPE",
|
|
584
|
+
details: "No resolveThreadsScope configured. All threads are globally accessible. This is fine for development, but add authentication for production: https://docs.copilotkit.ai/security/thread-scoping"
|
|
585
|
+
});
|
|
586
|
+
}
|
|
348
587
|
}
|
|
349
588
|
};
|
|
350
589
|
|
|
@@ -355,11 +594,7 @@ var import_cors = require("hono/cors");
|
|
|
355
594
|
// src/handlers/handle-run.ts
|
|
356
595
|
var import_client2 = require("@ag-ui/client");
|
|
357
596
|
var import_encoder = require("@ag-ui/encoder");
|
|
358
|
-
async function handleRunAgent({
|
|
359
|
-
runtime,
|
|
360
|
-
request,
|
|
361
|
-
agentId
|
|
362
|
-
}) {
|
|
597
|
+
async function handleRunAgent({ runtime, request, agentId }) {
|
|
363
598
|
try {
|
|
364
599
|
const agents = await runtime.agents;
|
|
365
600
|
if (!agents[agentId]) {
|
|
@@ -396,6 +631,23 @@ async function handleRunAgent({
|
|
|
396
631
|
const writer = stream.writable.getWriter();
|
|
397
632
|
const encoder = new import_encoder.EventEncoder();
|
|
398
633
|
let streamClosed = false;
|
|
634
|
+
let subscription;
|
|
635
|
+
let abortListener;
|
|
636
|
+
const cleanupAbortListener = () => {
|
|
637
|
+
if (abortListener) {
|
|
638
|
+
request.signal.removeEventListener("abort", abortListener);
|
|
639
|
+
abortListener = void 0;
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
const closeStream = async () => {
|
|
643
|
+
if (!streamClosed) {
|
|
644
|
+
try {
|
|
645
|
+
await writer.close();
|
|
646
|
+
} catch {
|
|
647
|
+
}
|
|
648
|
+
streamClosed = true;
|
|
649
|
+
}
|
|
650
|
+
};
|
|
399
651
|
(async () => {
|
|
400
652
|
let input;
|
|
401
653
|
try {
|
|
@@ -409,13 +661,26 @@ async function handleRunAgent({
|
|
|
409
661
|
{ status: 400 }
|
|
410
662
|
);
|
|
411
663
|
}
|
|
664
|
+
const clientDeclared = CopilotRuntime["parseClientDeclaredResourceId"](request);
|
|
665
|
+
const scope = await runtime.resolveThreadsScope({ request, clientDeclared });
|
|
666
|
+
if (scope === void 0) {
|
|
667
|
+
throw new Error("Unauthorized: No resource scope provided");
|
|
668
|
+
}
|
|
412
669
|
agent.setMessages(input.messages);
|
|
413
670
|
agent.setState(input.state);
|
|
414
671
|
agent.threadId = input.threadId;
|
|
415
|
-
|
|
672
|
+
const stopRunner = async () => {
|
|
673
|
+
try {
|
|
674
|
+
await runtime.runner.stop({ threadId: input.threadId });
|
|
675
|
+
} catch (stopError) {
|
|
676
|
+
console.error("Error stopping runner:", stopError);
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
subscription = runtime.runner.run({
|
|
416
680
|
threadId: input.threadId,
|
|
417
681
|
agent,
|
|
418
|
-
input
|
|
682
|
+
input,
|
|
683
|
+
scope
|
|
419
684
|
}).subscribe({
|
|
420
685
|
next: async (event) => {
|
|
421
686
|
if (!request.signal.aborted && !streamClosed) {
|
|
@@ -430,42 +695,39 @@ async function handleRunAgent({
|
|
|
430
695
|
},
|
|
431
696
|
error: async (error) => {
|
|
432
697
|
console.error("Error running agent:", error);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
await writer.close();
|
|
436
|
-
streamClosed = true;
|
|
437
|
-
} catch {
|
|
438
|
-
}
|
|
439
|
-
}
|
|
698
|
+
cleanupAbortListener();
|
|
699
|
+
await closeStream();
|
|
440
700
|
},
|
|
441
701
|
complete: async () => {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
await writer.close();
|
|
445
|
-
streamClosed = true;
|
|
446
|
-
} catch {
|
|
447
|
-
}
|
|
448
|
-
}
|
|
702
|
+
cleanupAbortListener();
|
|
703
|
+
await closeStream();
|
|
449
704
|
}
|
|
450
705
|
});
|
|
706
|
+
const handleAbort = () => {
|
|
707
|
+
subscription?.unsubscribe();
|
|
708
|
+
subscription = void 0;
|
|
709
|
+
cleanupAbortListener();
|
|
710
|
+
void stopRunner();
|
|
711
|
+
void closeStream();
|
|
712
|
+
};
|
|
713
|
+
if (request.signal.aborted) {
|
|
714
|
+
handleAbort();
|
|
715
|
+
} else {
|
|
716
|
+
abortListener = handleAbort;
|
|
717
|
+
request.signal.addEventListener("abort", abortListener);
|
|
718
|
+
}
|
|
451
719
|
})().catch((error) => {
|
|
452
720
|
console.error("Error running agent:", error);
|
|
453
|
-
console.error(
|
|
454
|
-
"Error stack:",
|
|
455
|
-
error instanceof Error ? error.stack : "No stack trace"
|
|
456
|
-
);
|
|
721
|
+
console.error("Error stack:", error instanceof Error ? error.stack : "No stack trace");
|
|
457
722
|
console.error("Error details:", {
|
|
458
723
|
name: error instanceof Error ? error.name : "Unknown",
|
|
459
724
|
message: error instanceof Error ? error.message : String(error),
|
|
460
725
|
cause: error instanceof Error ? error.cause : void 0
|
|
461
726
|
});
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
} catch {
|
|
467
|
-
}
|
|
468
|
-
}
|
|
727
|
+
subscription?.unsubscribe();
|
|
728
|
+
subscription = void 0;
|
|
729
|
+
cleanupAbortListener();
|
|
730
|
+
void closeStream();
|
|
469
731
|
});
|
|
470
732
|
return new Response(stream.readable, {
|
|
471
733
|
status: 200,
|
|
@@ -477,10 +739,7 @@ async function handleRunAgent({
|
|
|
477
739
|
});
|
|
478
740
|
} catch (error) {
|
|
479
741
|
console.error("Error running agent:", error);
|
|
480
|
-
console.error(
|
|
481
|
-
"Error stack:",
|
|
482
|
-
error instanceof Error ? error.stack : "No stack trace"
|
|
483
|
-
);
|
|
742
|
+
console.error("Error stack:", error instanceof Error ? error.stack : "No stack trace");
|
|
484
743
|
console.error("Error details:", {
|
|
485
744
|
name: error instanceof Error ? error.name : "Unknown",
|
|
486
745
|
message: error instanceof Error ? error.message : String(error),
|
|
@@ -638,10 +897,10 @@ async function handleTranscribe({
|
|
|
638
897
|
}
|
|
639
898
|
|
|
640
899
|
// src/endpoint.ts
|
|
641
|
-
var
|
|
900
|
+
var import_shared4 = require("@copilotkitnext/shared");
|
|
642
901
|
|
|
643
902
|
// src/middleware.ts
|
|
644
|
-
var
|
|
903
|
+
var import_shared3 = require("@copilotkitnext/shared");
|
|
645
904
|
async function callBeforeRequestMiddleware({
|
|
646
905
|
runtime,
|
|
647
906
|
request,
|
|
@@ -652,7 +911,7 @@ async function callBeforeRequestMiddleware({
|
|
|
652
911
|
if (typeof mw === "function") {
|
|
653
912
|
return mw({ runtime, request, path });
|
|
654
913
|
}
|
|
655
|
-
|
|
914
|
+
import_shared3.logger.warn({ mw }, "Unsupported beforeRequestMiddleware value \u2013 skipped");
|
|
656
915
|
return;
|
|
657
916
|
}
|
|
658
917
|
async function callAfterRequestMiddleware({
|
|
@@ -665,17 +924,13 @@ async function callAfterRequestMiddleware({
|
|
|
665
924
|
if (typeof mw === "function") {
|
|
666
925
|
return mw({ runtime, response, path });
|
|
667
926
|
}
|
|
668
|
-
|
|
927
|
+
import_shared3.logger.warn({ mw }, "Unsupported afterRequestMiddleware value \u2013 skipped");
|
|
669
928
|
}
|
|
670
929
|
|
|
671
930
|
// src/handlers/handle-connect.ts
|
|
672
931
|
var import_client3 = require("@ag-ui/client");
|
|
673
932
|
var import_encoder2 = require("@ag-ui/encoder");
|
|
674
|
-
async function handleConnectAgent({
|
|
675
|
-
runtime,
|
|
676
|
-
request,
|
|
677
|
-
agentId
|
|
678
|
-
}) {
|
|
933
|
+
async function handleConnectAgent({ runtime, request, agentId }) {
|
|
679
934
|
try {
|
|
680
935
|
const agents = await runtime.agents;
|
|
681
936
|
if (!agents[agentId]) {
|
|
@@ -694,6 +949,23 @@ async function handleConnectAgent({
|
|
|
694
949
|
const writer = stream.writable.getWriter();
|
|
695
950
|
const encoder = new import_encoder2.EventEncoder();
|
|
696
951
|
let streamClosed = false;
|
|
952
|
+
let subscription;
|
|
953
|
+
let abortListener;
|
|
954
|
+
const cleanupAbortListener = () => {
|
|
955
|
+
if (abortListener) {
|
|
956
|
+
request.signal.removeEventListener("abort", abortListener);
|
|
957
|
+
abortListener = void 0;
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
const closeStream = async () => {
|
|
961
|
+
if (!streamClosed) {
|
|
962
|
+
try {
|
|
963
|
+
await writer.close();
|
|
964
|
+
} catch {
|
|
965
|
+
}
|
|
966
|
+
streamClosed = true;
|
|
967
|
+
}
|
|
968
|
+
};
|
|
697
969
|
(async () => {
|
|
698
970
|
let input;
|
|
699
971
|
try {
|
|
@@ -707,8 +979,14 @@ async function handleConnectAgent({
|
|
|
707
979
|
{ status: 400 }
|
|
708
980
|
);
|
|
709
981
|
}
|
|
710
|
-
|
|
711
|
-
|
|
982
|
+
const clientDeclared = CopilotRuntime["parseClientDeclaredResourceId"](request);
|
|
983
|
+
const scope = await runtime.resolveThreadsScope({ request, clientDeclared });
|
|
984
|
+
if (scope === void 0) {
|
|
985
|
+
throw new Error("Unauthorized: No resource scope provided");
|
|
986
|
+
}
|
|
987
|
+
subscription = runtime.runner.connect({
|
|
988
|
+
threadId: input.threadId,
|
|
989
|
+
scope
|
|
712
990
|
}).subscribe({
|
|
713
991
|
next: async (event) => {
|
|
714
992
|
if (!request.signal.aborted && !streamClosed) {
|
|
@@ -723,42 +1001,38 @@ async function handleConnectAgent({
|
|
|
723
1001
|
},
|
|
724
1002
|
error: async (error) => {
|
|
725
1003
|
console.error("Error running agent:", error);
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
await writer.close();
|
|
729
|
-
streamClosed = true;
|
|
730
|
-
} catch {
|
|
731
|
-
}
|
|
732
|
-
}
|
|
1004
|
+
cleanupAbortListener();
|
|
1005
|
+
await closeStream();
|
|
733
1006
|
},
|
|
734
1007
|
complete: async () => {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
await writer.close();
|
|
738
|
-
streamClosed = true;
|
|
739
|
-
} catch {
|
|
740
|
-
}
|
|
741
|
-
}
|
|
1008
|
+
cleanupAbortListener();
|
|
1009
|
+
await closeStream();
|
|
742
1010
|
}
|
|
743
1011
|
});
|
|
1012
|
+
const handleAbort = () => {
|
|
1013
|
+
subscription?.unsubscribe();
|
|
1014
|
+
subscription = void 0;
|
|
1015
|
+
cleanupAbortListener();
|
|
1016
|
+
void closeStream();
|
|
1017
|
+
};
|
|
1018
|
+
if (request.signal.aborted) {
|
|
1019
|
+
handleAbort();
|
|
1020
|
+
} else {
|
|
1021
|
+
abortListener = handleAbort;
|
|
1022
|
+
request.signal.addEventListener("abort", abortListener);
|
|
1023
|
+
}
|
|
744
1024
|
})().catch((error) => {
|
|
745
1025
|
console.error("Error running agent:", error);
|
|
746
|
-
console.error(
|
|
747
|
-
"Error stack:",
|
|
748
|
-
error instanceof Error ? error.stack : "No stack trace"
|
|
749
|
-
);
|
|
1026
|
+
console.error("Error stack:", error instanceof Error ? error.stack : "No stack trace");
|
|
750
1027
|
console.error("Error details:", {
|
|
751
1028
|
name: error instanceof Error ? error.name : "Unknown",
|
|
752
1029
|
message: error instanceof Error ? error.message : String(error),
|
|
753
1030
|
cause: error instanceof Error ? error.cause : void 0
|
|
754
1031
|
});
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
} catch {
|
|
760
|
-
}
|
|
761
|
-
}
|
|
1032
|
+
subscription?.unsubscribe();
|
|
1033
|
+
subscription = void 0;
|
|
1034
|
+
cleanupAbortListener();
|
|
1035
|
+
void closeStream();
|
|
762
1036
|
});
|
|
763
1037
|
return new Response(stream.readable, {
|
|
764
1038
|
status: 200,
|
|
@@ -770,10 +1044,7 @@ async function handleConnectAgent({
|
|
|
770
1044
|
});
|
|
771
1045
|
} catch (error) {
|
|
772
1046
|
console.error("Error running agent:", error);
|
|
773
|
-
console.error(
|
|
774
|
-
"Error stack:",
|
|
775
|
-
error instanceof Error ? error.stack : "No stack trace"
|
|
776
|
-
);
|
|
1047
|
+
console.error("Error stack:", error instanceof Error ? error.stack : "No stack trace");
|
|
777
1048
|
console.error("Error details:", {
|
|
778
1049
|
name: error instanceof Error ? error.name : "Unknown",
|
|
779
1050
|
message: error instanceof Error ? error.message : String(error),
|
|
@@ -814,7 +1085,35 @@ async function handleStopAgent({
|
|
|
814
1085
|
}
|
|
815
1086
|
);
|
|
816
1087
|
}
|
|
817
|
-
const
|
|
1088
|
+
const clientDeclared = CopilotRuntime["parseClientDeclaredResourceId"](request);
|
|
1089
|
+
const scope = await runtime.resolveThreadsScope({ request, clientDeclared });
|
|
1090
|
+
if (scope === void 0) {
|
|
1091
|
+
return new Response(
|
|
1092
|
+
JSON.stringify({
|
|
1093
|
+
error: "Unauthorized",
|
|
1094
|
+
message: "No resource scope provided"
|
|
1095
|
+
}),
|
|
1096
|
+
{
|
|
1097
|
+
status: 401,
|
|
1098
|
+
headers: { "Content-Type": "application/json" }
|
|
1099
|
+
}
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
const runner = await runtime.runner;
|
|
1103
|
+
const metadata = await runner.getThreadMetadata(threadId, scope);
|
|
1104
|
+
if (!metadata) {
|
|
1105
|
+
return new Response(
|
|
1106
|
+
JSON.stringify({
|
|
1107
|
+
error: "Thread not found",
|
|
1108
|
+
message: `Thread '${threadId}' does not exist or you don't have access`
|
|
1109
|
+
}),
|
|
1110
|
+
{
|
|
1111
|
+
status: 404,
|
|
1112
|
+
headers: { "Content-Type": "application/json" }
|
|
1113
|
+
}
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
const stopped = await runner.stop({ threadId });
|
|
818
1117
|
if (!stopped) {
|
|
819
1118
|
return new Response(
|
|
820
1119
|
JSON.stringify({
|
|
@@ -856,6 +1155,141 @@ async function handleStopAgent({
|
|
|
856
1155
|
}
|
|
857
1156
|
}
|
|
858
1157
|
|
|
1158
|
+
// src/handlers/handle-threads.ts
|
|
1159
|
+
async function handleListThreads({ runtime, request }) {
|
|
1160
|
+
try {
|
|
1161
|
+
const clientDeclared = CopilotRuntime["parseClientDeclaredResourceId"](request);
|
|
1162
|
+
const scope = await runtime.resolveThreadsScope({ request, clientDeclared });
|
|
1163
|
+
if (scope === void 0) {
|
|
1164
|
+
return new Response(
|
|
1165
|
+
JSON.stringify({
|
|
1166
|
+
error: "Unauthorized",
|
|
1167
|
+
message: "No resource scope provided"
|
|
1168
|
+
}),
|
|
1169
|
+
{
|
|
1170
|
+
status: 401,
|
|
1171
|
+
headers: { "Content-Type": "application/json" }
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
const url = new URL(request.url);
|
|
1176
|
+
const limitParam = url.searchParams.get("limit");
|
|
1177
|
+
const offsetParam = url.searchParams.get("offset");
|
|
1178
|
+
const parsedLimit = limitParam ? Number.parseInt(limitParam, 10) : NaN;
|
|
1179
|
+
const parsedOffset = offsetParam ? Number.parseInt(offsetParam, 10) : NaN;
|
|
1180
|
+
const limit = Math.max(1, Math.min(100, Number.isNaN(parsedLimit) ? 20 : parsedLimit));
|
|
1181
|
+
const offset = Math.max(0, Number.isNaN(parsedOffset) ? 0 : parsedOffset);
|
|
1182
|
+
const runner = await runtime.runner;
|
|
1183
|
+
const result = await runner.listThreads({ scope, limit, offset });
|
|
1184
|
+
return new Response(JSON.stringify(result), {
|
|
1185
|
+
status: 200,
|
|
1186
|
+
headers: { "Content-Type": "application/json" }
|
|
1187
|
+
});
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1190
|
+
return new Response(
|
|
1191
|
+
JSON.stringify({
|
|
1192
|
+
error: "Failed to list threads",
|
|
1193
|
+
message: errorMessage
|
|
1194
|
+
}),
|
|
1195
|
+
{
|
|
1196
|
+
status: 500,
|
|
1197
|
+
headers: { "Content-Type": "application/json" }
|
|
1198
|
+
}
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
async function handleGetThread({ runtime, threadId, request }) {
|
|
1203
|
+
try {
|
|
1204
|
+
const clientDeclared = CopilotRuntime["parseClientDeclaredResourceId"](request);
|
|
1205
|
+
const scope = await runtime.resolveThreadsScope({ request, clientDeclared });
|
|
1206
|
+
if (scope === void 0) {
|
|
1207
|
+
return new Response(
|
|
1208
|
+
JSON.stringify({
|
|
1209
|
+
error: "Unauthorized",
|
|
1210
|
+
message: "No resource scope provided"
|
|
1211
|
+
}),
|
|
1212
|
+
{
|
|
1213
|
+
status: 401,
|
|
1214
|
+
headers: { "Content-Type": "application/json" }
|
|
1215
|
+
}
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
const runner = await runtime.runner;
|
|
1219
|
+
const metadata = await runner.getThreadMetadata(threadId, scope);
|
|
1220
|
+
if (!metadata) {
|
|
1221
|
+
return new Response(
|
|
1222
|
+
JSON.stringify({
|
|
1223
|
+
error: "Thread not found",
|
|
1224
|
+
message: `Thread '${threadId}' does not exist`
|
|
1225
|
+
}),
|
|
1226
|
+
{
|
|
1227
|
+
status: 404,
|
|
1228
|
+
headers: { "Content-Type": "application/json" }
|
|
1229
|
+
}
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
return new Response(JSON.stringify(metadata), {
|
|
1233
|
+
status: 200,
|
|
1234
|
+
headers: { "Content-Type": "application/json" }
|
|
1235
|
+
});
|
|
1236
|
+
} catch (error) {
|
|
1237
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1238
|
+
return new Response(
|
|
1239
|
+
JSON.stringify({
|
|
1240
|
+
error: "Failed to get thread",
|
|
1241
|
+
message: errorMessage
|
|
1242
|
+
}),
|
|
1243
|
+
{
|
|
1244
|
+
status: 500,
|
|
1245
|
+
headers: { "Content-Type": "application/json" }
|
|
1246
|
+
}
|
|
1247
|
+
);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
async function handleDeleteThread({ runtime, threadId, request }) {
|
|
1251
|
+
if (!threadId) {
|
|
1252
|
+
return new Response(JSON.stringify({ error: "Thread ID required" }), {
|
|
1253
|
+
status: 400,
|
|
1254
|
+
headers: { "Content-Type": "application/json" }
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
try {
|
|
1258
|
+
const clientDeclared = CopilotRuntime["parseClientDeclaredResourceId"](request);
|
|
1259
|
+
const scope = await runtime.resolveThreadsScope({ request, clientDeclared });
|
|
1260
|
+
if (scope === void 0) {
|
|
1261
|
+
return new Response(
|
|
1262
|
+
JSON.stringify({
|
|
1263
|
+
error: "Unauthorized",
|
|
1264
|
+
message: "No resource scope provided"
|
|
1265
|
+
}),
|
|
1266
|
+
{
|
|
1267
|
+
status: 401,
|
|
1268
|
+
headers: { "Content-Type": "application/json" }
|
|
1269
|
+
}
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
const runner = await runtime.runner;
|
|
1273
|
+
await runner.deleteThread(threadId, scope);
|
|
1274
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
1275
|
+
status: 200,
|
|
1276
|
+
headers: { "Content-Type": "application/json" }
|
|
1277
|
+
});
|
|
1278
|
+
} catch (error) {
|
|
1279
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1280
|
+
return new Response(
|
|
1281
|
+
JSON.stringify({
|
|
1282
|
+
error: "Failed to delete thread",
|
|
1283
|
+
message: errorMessage
|
|
1284
|
+
}),
|
|
1285
|
+
{
|
|
1286
|
+
status: 500,
|
|
1287
|
+
headers: { "Content-Type": "application/json" }
|
|
1288
|
+
}
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
859
1293
|
// src/endpoint.ts
|
|
860
1294
|
function createCopilotEndpoint({ runtime, basePath }) {
|
|
861
1295
|
const app = new import_hono.Hono();
|
|
@@ -879,7 +1313,7 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
879
1313
|
c.set("modifiedRequest", maybeModifiedRequest);
|
|
880
1314
|
}
|
|
881
1315
|
} catch (error) {
|
|
882
|
-
|
|
1316
|
+
import_shared4.logger.error({ err: error, url: request.url, path }, "Error running before request middleware");
|
|
883
1317
|
if (error instanceof Response) {
|
|
884
1318
|
return error;
|
|
885
1319
|
}
|
|
@@ -895,7 +1329,7 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
895
1329
|
response,
|
|
896
1330
|
path
|
|
897
1331
|
}).catch((error) => {
|
|
898
|
-
|
|
1332
|
+
import_shared4.logger.error({ err: error, url: c.req.url, path }, "Error running after request middleware");
|
|
899
1333
|
});
|
|
900
1334
|
}).post("/agent/:agentId/run", async (c) => {
|
|
901
1335
|
const agentId = c.req.param("agentId");
|
|
@@ -907,7 +1341,7 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
907
1341
|
agentId
|
|
908
1342
|
});
|
|
909
1343
|
} catch (error) {
|
|
910
|
-
|
|
1344
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
911
1345
|
throw error;
|
|
912
1346
|
}
|
|
913
1347
|
}).post("/agent/:agentId/connect", async (c) => {
|
|
@@ -920,7 +1354,7 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
920
1354
|
agentId
|
|
921
1355
|
});
|
|
922
1356
|
} catch (error) {
|
|
923
|
-
|
|
1357
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
924
1358
|
throw error;
|
|
925
1359
|
}
|
|
926
1360
|
}).post("/agent/:agentId/stop/:threadId", async (c) => {
|
|
@@ -935,7 +1369,7 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
935
1369
|
threadId
|
|
936
1370
|
});
|
|
937
1371
|
} catch (error) {
|
|
938
|
-
|
|
1372
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
939
1373
|
throw error;
|
|
940
1374
|
}
|
|
941
1375
|
}).get("/info", async (c) => {
|
|
@@ -946,7 +1380,7 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
946
1380
|
request
|
|
947
1381
|
});
|
|
948
1382
|
} catch (error) {
|
|
949
|
-
|
|
1383
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
950
1384
|
throw error;
|
|
951
1385
|
}
|
|
952
1386
|
}).post("/transcribe", async (c) => {
|
|
@@ -957,7 +1391,44 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
957
1391
|
request
|
|
958
1392
|
});
|
|
959
1393
|
} catch (error) {
|
|
960
|
-
|
|
1394
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
1395
|
+
throw error;
|
|
1396
|
+
}
|
|
1397
|
+
}).get("/threads", async (c) => {
|
|
1398
|
+
const request = c.get("modifiedRequest") || c.req.raw;
|
|
1399
|
+
try {
|
|
1400
|
+
return await handleListThreads({
|
|
1401
|
+
runtime,
|
|
1402
|
+
request
|
|
1403
|
+
});
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
1406
|
+
throw error;
|
|
1407
|
+
}
|
|
1408
|
+
}).get("/threads/:threadId", async (c) => {
|
|
1409
|
+
const threadId = c.req.param("threadId");
|
|
1410
|
+
const request = c.get("modifiedRequest") || c.req.raw;
|
|
1411
|
+
try {
|
|
1412
|
+
return await handleGetThread({
|
|
1413
|
+
runtime,
|
|
1414
|
+
request,
|
|
1415
|
+
threadId
|
|
1416
|
+
});
|
|
1417
|
+
} catch (error) {
|
|
1418
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
1419
|
+
throw error;
|
|
1420
|
+
}
|
|
1421
|
+
}).delete("/threads/:threadId", async (c) => {
|
|
1422
|
+
const threadId = c.req.param("threadId");
|
|
1423
|
+
const request = c.get("modifiedRequest") || c.req.raw;
|
|
1424
|
+
try {
|
|
1425
|
+
return await handleDeleteThread({
|
|
1426
|
+
runtime,
|
|
1427
|
+
request,
|
|
1428
|
+
threadId
|
|
1429
|
+
});
|
|
1430
|
+
} catch (error) {
|
|
1431
|
+
import_shared4.logger.error({ err: error, url: request.url, path: c.req.path }, "Error running request handler");
|
|
961
1432
|
throw error;
|
|
962
1433
|
}
|
|
963
1434
|
}).notFound((c) => {
|
|
@@ -966,7 +1437,46 @@ function createCopilotEndpoint({ runtime, basePath }) {
|
|
|
966
1437
|
}
|
|
967
1438
|
|
|
968
1439
|
// src/runner/index.ts
|
|
969
|
-
var
|
|
1440
|
+
var import_shared5 = require("@copilotkitnext/shared");
|
|
1441
|
+
|
|
1442
|
+
// src/resource-id-helpers.ts
|
|
1443
|
+
function validateResourceIdMatch(clientDeclared, serverAuthorized) {
|
|
1444
|
+
if (!clientDeclared) {
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
const clientIds = Array.isArray(clientDeclared) ? clientDeclared : [clientDeclared];
|
|
1448
|
+
const authorizedIds = Array.isArray(serverAuthorized) ? serverAuthorized : [serverAuthorized];
|
|
1449
|
+
const hasMatch = clientIds.some((clientId) => authorizedIds.includes(clientId));
|
|
1450
|
+
if (!hasMatch) {
|
|
1451
|
+
throw new Error("Unauthorized: Client-declared resourceId does not match authenticated user");
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
function filterAuthorizedResourceIds(clientDeclared, serverAuthorized) {
|
|
1455
|
+
const authorizedIds = Array.isArray(serverAuthorized) ? serverAuthorized : [serverAuthorized];
|
|
1456
|
+
if (!clientDeclared) {
|
|
1457
|
+
return serverAuthorized;
|
|
1458
|
+
}
|
|
1459
|
+
const clientIds = Array.isArray(clientDeclared) ? clientDeclared : [clientDeclared];
|
|
1460
|
+
const filtered = clientIds.filter((id) => authorizedIds.includes(id));
|
|
1461
|
+
if (filtered.length === 0) {
|
|
1462
|
+
throw new Error("Unauthorized: None of the client-declared resourceIds are authorized");
|
|
1463
|
+
}
|
|
1464
|
+
return Array.isArray(clientDeclared) ? filtered : filtered[0];
|
|
1465
|
+
}
|
|
1466
|
+
function createStrictThreadScopeResolver(getUserId) {
|
|
1467
|
+
return async ({ request, clientDeclared }) => {
|
|
1468
|
+
const userId = await getUserId(request);
|
|
1469
|
+
validateResourceIdMatch(clientDeclared, userId);
|
|
1470
|
+
return { resourceId: userId };
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
function createFilteringThreadScopeResolver(getUserResourceIds) {
|
|
1474
|
+
return async ({ request, clientDeclared }) => {
|
|
1475
|
+
const userResourceIds = await getUserResourceIds(request);
|
|
1476
|
+
const resourceId = filterAuthorizedResourceIds(clientDeclared, userResourceIds);
|
|
1477
|
+
return { resourceId };
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
970
1480
|
// Annotate the CommonJS export names for ESM import in node:
|
|
971
1481
|
0 && (module.exports = {
|
|
972
1482
|
AgentRunner,
|
|
@@ -974,6 +1484,10 @@ var import_shared4 = require("@copilotkitnext/shared");
|
|
|
974
1484
|
InMemoryAgentRunner,
|
|
975
1485
|
VERSION,
|
|
976
1486
|
createCopilotEndpoint,
|
|
977
|
-
|
|
1487
|
+
createFilteringThreadScopeResolver,
|
|
1488
|
+
createStrictThreadScopeResolver,
|
|
1489
|
+
filterAuthorizedResourceIds,
|
|
1490
|
+
finalizeRunEvents,
|
|
1491
|
+
validateResourceIdMatch
|
|
978
1492
|
});
|
|
979
1493
|
//# sourceMappingURL=index.js.map
|