@yourgpt/copilot-sdk 2.5.1-beta.0 → 2.5.2-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-JPUKXFR4.js → chunk-37HN4F6S.js} +488 -92
- package/dist/chunk-37HN4F6S.js.map +1 -0
- package/dist/{chunk-6R63NBNP.cjs → chunk-4PL7TK42.cjs} +16 -16
- package/dist/{chunk-6R63NBNP.cjs.map → chunk-4PL7TK42.cjs.map} +1 -1
- package/dist/{chunk-ZYLHGNIG.cjs → chunk-GW5ZZHJ7.cjs} +488 -92
- package/dist/chunk-GW5ZZHJ7.cjs.map +1 -0
- package/dist/{chunk-YYLTWY5R.js → chunk-VHJ46HKC.js} +3 -3
- package/dist/{chunk-YYLTWY5R.js.map → chunk-VHJ46HKC.js.map} +1 -1
- package/dist/experimental/index.cjs +2 -2
- package/dist/experimental/index.js +1 -1
- package/dist/react/index.cjs +62 -62
- package/dist/react/index.d.cts +74 -2
- package/dist/react/index.d.ts +74 -2
- package/dist/react/index.js +2 -2
- package/dist/ui/index.cjs +129 -54
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +12 -1
- package/dist/ui/index.d.ts +12 -1
- package/dist/ui/index.js +126 -51
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-JPUKXFR4.js.map +0 -1
- package/dist/chunk-ZYLHGNIG.cjs.map +0 -1
|
@@ -1555,6 +1555,10 @@ var AbstractChat = class {
|
|
|
1555
1555
|
get isStreaming() {
|
|
1556
1556
|
return this.transport.isStreaming();
|
|
1557
1557
|
}
|
|
1558
|
+
/** The thread id currently associated with this chat, if any. */
|
|
1559
|
+
get threadId() {
|
|
1560
|
+
return this.config.threadId;
|
|
1561
|
+
}
|
|
1558
1562
|
// ============================================
|
|
1559
1563
|
// Public Actions
|
|
1560
1564
|
// ============================================
|
|
@@ -2200,6 +2204,7 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2200
2204
|
this.debug("Starting to process stream");
|
|
2201
2205
|
let chunkCount = 0;
|
|
2202
2206
|
let toolCallsEmitted = false;
|
|
2207
|
+
let postToolTextStreamed = false;
|
|
2203
2208
|
let pendingClientToolCalls;
|
|
2204
2209
|
for await (const chunk of stream) {
|
|
2205
2210
|
chunkCount++;
|
|
@@ -2256,15 +2261,27 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2256
2261
|
continue;
|
|
2257
2262
|
}
|
|
2258
2263
|
if (!this.streamState) {
|
|
2259
|
-
if (chunk.type === "
|
|
2264
|
+
if (chunk.type === "message:delta") {
|
|
2265
|
+
this.debug(
|
|
2266
|
+
"message:delta with no streamState \u2014 auto-init new message"
|
|
2267
|
+
);
|
|
2268
|
+
const currentLeaf = this.state.messages;
|
|
2269
|
+
const currentLeafId = currentLeaf.length > 0 ? currentLeaf[currentLeaf.length - 1].id : void 0;
|
|
2270
|
+
const newMessage = createEmptyAssistantMessage(void 0, {
|
|
2271
|
+
parentId: currentLeafId
|
|
2272
|
+
});
|
|
2273
|
+
this.state.pushMessage(newMessage);
|
|
2274
|
+
this.streamState = createStreamState(newMessage.id);
|
|
2275
|
+
this.callbacks.onMessageStart?.(newMessage.id);
|
|
2276
|
+
postToolTextStreamed = true;
|
|
2277
|
+
} else if (chunk.type === "tool_calls") {
|
|
2260
2278
|
pendingClientToolCalls = chunk.toolCalls;
|
|
2261
2279
|
this.debug("tool_calls (post-message:end, stored as pending)", {
|
|
2262
2280
|
count: pendingClientToolCalls?.length,
|
|
2263
2281
|
ids: pendingClientToolCalls?.map((tc) => tc.id)
|
|
2264
2282
|
});
|
|
2265
2283
|
continue;
|
|
2266
|
-
}
|
|
2267
|
-
if (chunk.type === "done") {
|
|
2284
|
+
} else if (chunk.type === "done") {
|
|
2268
2285
|
this.debug("done (post-message:end)", {
|
|
2269
2286
|
hasPendingToolCalls: !!pendingClientToolCalls?.length,
|
|
2270
2287
|
pendingCount: pendingClientToolCalls?.length ?? 0,
|
|
@@ -2356,9 +2373,10 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2356
2373
|
});
|
|
2357
2374
|
}
|
|
2358
2375
|
continue;
|
|
2376
|
+
} else {
|
|
2377
|
+
this.debug("warning", "streamState is null, skipping chunk");
|
|
2378
|
+
continue;
|
|
2359
2379
|
}
|
|
2360
|
-
this.debug("warning", "streamState is null, skipping chunk");
|
|
2361
|
-
continue;
|
|
2362
2380
|
}
|
|
2363
2381
|
this.streamState = processStreamChunk(chunk, this.streamState);
|
|
2364
2382
|
if (chunk.type === "action:start") {
|
|
@@ -2454,9 +2472,12 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2454
2472
|
}
|
|
2455
2473
|
}
|
|
2456
2474
|
}
|
|
2475
|
+
let seenToolResult = false;
|
|
2457
2476
|
for (const msg of chunk.messages) {
|
|
2477
|
+
if (msg.role === "tool") seenToolResult = true;
|
|
2458
2478
|
if (msg.role === "assistant" && !msg.tool_calls?.length) {
|
|
2459
|
-
continue;
|
|
2479
|
+
if (!seenToolResult) continue;
|
|
2480
|
+
if (postToolTextStreamed) continue;
|
|
2460
2481
|
}
|
|
2461
2482
|
if (msg.role === "assistant" && msg.tool_calls?.length && msg.tool_calls.every(
|
|
2462
2483
|
(toolCall) => currentStreamToolCallIds.has(toolCall.id)
|
|
@@ -2984,6 +3005,7 @@ var AbstractAgentLoop = class {
|
|
|
2984
3005
|
}
|
|
2985
3006
|
const result = await tool.handler(toolCall.args, {
|
|
2986
3007
|
signal: this.abortController?.signal,
|
|
3008
|
+
threadId: this.config.getThreadId?.(),
|
|
2987
3009
|
data: { toolCallId: toolCall.id },
|
|
2988
3010
|
approvalData
|
|
2989
3011
|
});
|
|
@@ -3511,7 +3533,13 @@ var ChatWithTools = class {
|
|
|
3511
3533
|
this.agentLoop = new AbstractAgentLoop(
|
|
3512
3534
|
{
|
|
3513
3535
|
maxIterations: config.maxIterations ?? 20,
|
|
3514
|
-
tools: config.tools
|
|
3536
|
+
tools: config.tools,
|
|
3537
|
+
// Expose this chat's current threadId to tool handlers via
|
|
3538
|
+
// ToolContext.threadId. Read lazily per invocation so it reflects
|
|
3539
|
+
// the id assigned by the server mid-stream (thread:created).
|
|
3540
|
+
// If the caller provided a getThreadId override (e.g. the React
|
|
3541
|
+
// provider exposing its stable registry key), prefer that.
|
|
3542
|
+
getThreadId: config.getThreadId ? () => config.getThreadId() : () => this.chat?.threadId
|
|
3515
3543
|
},
|
|
3516
3544
|
{
|
|
3517
3545
|
onExecutionsChange: (executions) => {
|
|
@@ -5421,7 +5449,8 @@ function CopilotProvider(props) {
|
|
|
5421
5449
|
mcpServers,
|
|
5422
5450
|
optimization,
|
|
5423
5451
|
messageHistory,
|
|
5424
|
-
skills
|
|
5452
|
+
skills,
|
|
5453
|
+
concurrentThreads = false
|
|
5425
5454
|
} = props;
|
|
5426
5455
|
const isThreadIdControlled = Object.prototype.hasOwnProperty.call(
|
|
5427
5456
|
props,
|
|
@@ -5459,87 +5488,350 @@ function CopilotProvider(props) {
|
|
|
5459
5488
|
controlled: isThreadIdControlled,
|
|
5460
5489
|
value: threadId
|
|
5461
5490
|
});
|
|
5491
|
+
const SINGLE_INSTANCE_KEY = "__single__";
|
|
5462
5492
|
const chatRef = useRef(null);
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5493
|
+
const instancesRef = useRef(/* @__PURE__ */ new Map());
|
|
5494
|
+
const activeInstanceKeyRef = useRef(SINGLE_INSTANCE_KEY);
|
|
5495
|
+
const pendingCounterRef = useRef(0);
|
|
5496
|
+
const sharedToolsRef = useRef(/* @__PURE__ */ new Map());
|
|
5497
|
+
const sharedSkillsRef = useRef([]);
|
|
5498
|
+
const sharedSystemContextRef = useRef("");
|
|
5499
|
+
const subscribersRef = useRef(/* @__PURE__ */ new Set());
|
|
5500
|
+
const stableSubscribe = useMemo(
|
|
5501
|
+
() => (cb) => {
|
|
5502
|
+
subscribersRef.current.add(cb);
|
|
5503
|
+
return () => {
|
|
5504
|
+
subscribersRef.current.delete(cb);
|
|
5505
|
+
};
|
|
5506
|
+
},
|
|
5507
|
+
[]
|
|
5508
|
+
);
|
|
5509
|
+
const [busyThreadIds, setBusyThreadIds] = useState(
|
|
5510
|
+
() => /* @__PURE__ */ new Set()
|
|
5511
|
+
);
|
|
5512
|
+
const recomputeBusyThreadIds = useCallback(() => {
|
|
5513
|
+
if (!concurrentThreads) return;
|
|
5514
|
+
const next = /* @__PURE__ */ new Set();
|
|
5515
|
+
for (const [key, inst] of instancesRef.current) {
|
|
5516
|
+
if (key === SINGLE_INSTANCE_KEY) continue;
|
|
5517
|
+
if (key.startsWith("__pending_")) continue;
|
|
5518
|
+
const s = inst.status;
|
|
5519
|
+
if (s === "streaming" || s === "submitted") next.add(key);
|
|
5520
|
+
}
|
|
5521
|
+
setBusyThreadIds((prev) => {
|
|
5522
|
+
if (prev.size === next.size) {
|
|
5523
|
+
let same = true;
|
|
5524
|
+
for (const id of next) {
|
|
5525
|
+
if (!prev.has(id)) {
|
|
5526
|
+
same = false;
|
|
5527
|
+
break;
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
if (same) return prev;
|
|
5531
|
+
}
|
|
5532
|
+
return next;
|
|
5533
|
+
});
|
|
5534
|
+
}, [concurrentThreads]);
|
|
5535
|
+
const [pendingApprovalsByThread, setPendingApprovalsByThread] = useState(() => /* @__PURE__ */ new Map());
|
|
5536
|
+
const recomputePendingApprovalsByThread = useCallback(() => {
|
|
5537
|
+
if (!concurrentThreads) return;
|
|
5538
|
+
const next = /* @__PURE__ */ new Map();
|
|
5539
|
+
for (const [key, inst] of instancesRef.current) {
|
|
5540
|
+
if (key === SINGLE_INSTANCE_KEY) continue;
|
|
5541
|
+
if (key.startsWith("__pending_")) continue;
|
|
5542
|
+
const pending = inst.toolExecutions.filter(
|
|
5543
|
+
(e) => e.approvalStatus === "required"
|
|
5544
|
+
);
|
|
5545
|
+
if (pending.length > 0) next.set(key, pending);
|
|
5546
|
+
}
|
|
5547
|
+
setPendingApprovalsByThread((prev) => {
|
|
5548
|
+
if (prev.size !== next.size) return next;
|
|
5549
|
+
for (const [id, execs] of next) {
|
|
5550
|
+
const prevExecs = prev.get(id);
|
|
5551
|
+
if (!prevExecs || prevExecs.length !== execs.length) return next;
|
|
5552
|
+
for (let i = 0; i < execs.length; i++) {
|
|
5553
|
+
if (prevExecs[i] !== execs[i]) return next;
|
|
5554
|
+
}
|
|
5555
|
+
}
|
|
5556
|
+
return prev;
|
|
5557
|
+
});
|
|
5558
|
+
}, [concurrentThreads]);
|
|
5559
|
+
const notifyStateChange = useCallback(() => {
|
|
5560
|
+
for (const cb of subscribersRef.current) cb();
|
|
5561
|
+
recomputeBusyThreadIds();
|
|
5562
|
+
recomputePendingApprovalsByThread();
|
|
5563
|
+
}, [recomputeBusyThreadIds, recomputePendingApprovalsByThread]);
|
|
5564
|
+
const configRef = useRef({
|
|
5565
|
+
runtimeUrl,
|
|
5566
|
+
systemPrompt,
|
|
5567
|
+
threadId,
|
|
5568
|
+
onCreateSession,
|
|
5569
|
+
yourgptConfig,
|
|
5570
|
+
initialMessages,
|
|
5571
|
+
streaming,
|
|
5572
|
+
headers,
|
|
5573
|
+
body,
|
|
5574
|
+
parseError,
|
|
5575
|
+
debug,
|
|
5576
|
+
maxIterations,
|
|
5577
|
+
maxIterationsMessage,
|
|
5578
|
+
optimization
|
|
5579
|
+
});
|
|
5580
|
+
configRef.current = {
|
|
5581
|
+
runtimeUrl,
|
|
5582
|
+
systemPrompt,
|
|
5583
|
+
threadId,
|
|
5584
|
+
onCreateSession,
|
|
5585
|
+
yourgptConfig,
|
|
5586
|
+
initialMessages,
|
|
5587
|
+
streaming,
|
|
5588
|
+
headers,
|
|
5589
|
+
body,
|
|
5590
|
+
parseError,
|
|
5591
|
+
debug,
|
|
5592
|
+
maxIterations,
|
|
5593
|
+
maxIterationsMessage,
|
|
5594
|
+
optimization
|
|
5595
|
+
};
|
|
5596
|
+
const callbacksRef = useRef({ onError, onThreadChange });
|
|
5597
|
+
callbacksRef.current = { onError, onThreadChange };
|
|
5598
|
+
const handleInstanceThreadAssigned = useCallback(
|
|
5599
|
+
(inst, newId) => {
|
|
5600
|
+
let oldKey;
|
|
5601
|
+
for (const [k, v] of instancesRef.current) {
|
|
5602
|
+
if (v === inst) {
|
|
5603
|
+
oldKey = k;
|
|
5604
|
+
break;
|
|
5605
|
+
}
|
|
5606
|
+
}
|
|
5607
|
+
if (oldKey === void 0) return;
|
|
5608
|
+
const isInternalKey = oldKey === SINGLE_INSTANCE_KEY || oldKey.startsWith("__pending_");
|
|
5609
|
+
const shouldRekey = !concurrentThreads || isInternalKey;
|
|
5610
|
+
if (shouldRekey && oldKey !== newId && !instancesRef.current.has(newId)) {
|
|
5611
|
+
instancesRef.current.delete(oldKey);
|
|
5612
|
+
instancesRef.current.set(newId, inst);
|
|
5613
|
+
if (activeInstanceKeyRef.current === oldKey) {
|
|
5614
|
+
activeInstanceKeyRef.current = newId;
|
|
5615
|
+
}
|
|
5616
|
+
if (inst === chatRef.current) {
|
|
5617
|
+
debugLog("Thread/session ID assigned:", newId);
|
|
5618
|
+
setActualThreadId(newId);
|
|
5619
|
+
callbacksRef.current.onThreadChange?.(newId);
|
|
5620
|
+
}
|
|
5621
|
+
}
|
|
5622
|
+
recomputeBusyThreadIds();
|
|
5623
|
+
recomputePendingApprovalsByThread();
|
|
5624
|
+
},
|
|
5625
|
+
[
|
|
5626
|
+
concurrentThreads,
|
|
5627
|
+
debugLog,
|
|
5628
|
+
recomputeBusyThreadIds,
|
|
5629
|
+
recomputePendingApprovalsByThread
|
|
5630
|
+
]
|
|
5631
|
+
);
|
|
5632
|
+
const createInstance = useCallback(
|
|
5633
|
+
(key, opts) => {
|
|
5634
|
+
const cfg = configRef.current;
|
|
5635
|
+
const initialThreadId = key === SINGLE_INSTANCE_KEY || key.startsWith("__pending_") ? cfg.threadId : key;
|
|
5636
|
+
const inst = new ReactChatWithTools(
|
|
5637
|
+
{
|
|
5638
|
+
runtimeUrl: cfg.runtimeUrl,
|
|
5639
|
+
systemPrompt: cfg.systemPrompt,
|
|
5640
|
+
threadId: initialThreadId,
|
|
5641
|
+
onCreateSession: cfg.onCreateSession,
|
|
5642
|
+
yourgptConfig: cfg.yourgptConfig,
|
|
5643
|
+
initialMessages: opts?.initialMessages ?? cfg.initialMessages,
|
|
5644
|
+
streaming: cfg.streaming,
|
|
5645
|
+
headers: cfg.headers,
|
|
5646
|
+
body: cfg.body,
|
|
5647
|
+
parseError: cfg.parseError,
|
|
5648
|
+
debug: cfg.debug,
|
|
5649
|
+
maxIterations: cfg.maxIterations,
|
|
5650
|
+
maxIterationsMessage: cfg.maxIterationsMessage,
|
|
5651
|
+
optimization: cfg.optimization,
|
|
5652
|
+
// Expose the registry key (usually the UI thread id after
|
|
5653
|
+
// assignLocalThreadId runs) to tool handlers, NOT chat.config.threadId.
|
|
5654
|
+
// For extensions that key per-thread state on context.threadId (e.g.
|
|
5655
|
+
// browser-tab pinning), this guarantees a stable id — even while the
|
|
5656
|
+
// backend session id is still being resolved. Internal keys
|
|
5657
|
+
// (__single__, __pending_*) return undefined so handlers can treat
|
|
5658
|
+
// them as "not yet committed".
|
|
5659
|
+
getThreadId: () => {
|
|
5660
|
+
for (const [k, v] of instancesRef.current) {
|
|
5661
|
+
if (v === inst) {
|
|
5662
|
+
if (k === SINGLE_INSTANCE_KEY || k.startsWith("__pending_")) {
|
|
5663
|
+
return void 0;
|
|
5664
|
+
}
|
|
5665
|
+
return k;
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
return void 0;
|
|
5669
|
+
}
|
|
5509
5670
|
},
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5671
|
+
{
|
|
5672
|
+
onToolExecutionsChange: (executions) => {
|
|
5673
|
+
debugLog("Tool executions changed:", executions.length);
|
|
5674
|
+
if (inst === chatRef.current) {
|
|
5675
|
+
setToolExecutions(executions);
|
|
5676
|
+
setAgentIteration(inst.iteration ?? 0);
|
|
5677
|
+
}
|
|
5678
|
+
recomputePendingApprovalsByThread();
|
|
5679
|
+
},
|
|
5680
|
+
onApprovalRequired: (execution) => {
|
|
5681
|
+
debugLog("Tool approval required:", execution.name);
|
|
5682
|
+
recomputePendingApprovalsByThread();
|
|
5683
|
+
},
|
|
5684
|
+
onContextUsageChange: (usage) => {
|
|
5685
|
+
if (inst === chatRef.current) {
|
|
5686
|
+
setContextUsage(usage);
|
|
5687
|
+
}
|
|
5688
|
+
},
|
|
5689
|
+
onError: (error2) => {
|
|
5690
|
+
if (error2 && inst === chatRef.current) {
|
|
5691
|
+
callbacksRef.current.onError?.(error2);
|
|
5692
|
+
}
|
|
5693
|
+
},
|
|
5694
|
+
onThreadChange: (id) => {
|
|
5695
|
+
handleInstanceThreadAssigned(inst, id);
|
|
5696
|
+
},
|
|
5697
|
+
onSessionStatusChange: (status2) => {
|
|
5698
|
+
debugLog("Session status:", status2);
|
|
5699
|
+
if (inst === chatRef.current) {
|
|
5700
|
+
setSessionStatus(status2);
|
|
5701
|
+
}
|
|
5702
|
+
},
|
|
5703
|
+
onStreamChunk: (chunk) => {
|
|
5704
|
+
if (streamListenersRef.current.size > 0) {
|
|
5705
|
+
for (const handler of streamListenersRef.current) {
|
|
5706
|
+
handler(chunk);
|
|
5707
|
+
}
|
|
5514
5708
|
}
|
|
5515
5709
|
}
|
|
5516
5710
|
}
|
|
5711
|
+
);
|
|
5712
|
+
for (const { tool } of sharedToolsRef.current.values()) {
|
|
5713
|
+
inst.registerTool(tool);
|
|
5517
5714
|
}
|
|
5518
|
-
|
|
5715
|
+
if (sharedSkillsRef.current.length > 0) {
|
|
5716
|
+
inst.setInlineSkills(sharedSkillsRef.current);
|
|
5717
|
+
}
|
|
5718
|
+
if (sharedSystemContextRef.current) {
|
|
5719
|
+
inst.setContext(sharedSystemContextRef.current);
|
|
5720
|
+
}
|
|
5721
|
+
inst.subscribe(notifyStateChange);
|
|
5722
|
+
instancesRef.current.set(key, inst);
|
|
5723
|
+
return inst;
|
|
5724
|
+
},
|
|
5725
|
+
[
|
|
5726
|
+
debugLog,
|
|
5727
|
+
handleInstanceThreadAssigned,
|
|
5728
|
+
notifyStateChange,
|
|
5729
|
+
recomputePendingApprovalsByThread
|
|
5730
|
+
]
|
|
5731
|
+
);
|
|
5732
|
+
if (chatRef.current !== null && chatRef.current.disposed) {
|
|
5733
|
+
for (const inst of instancesRef.current.values()) {
|
|
5734
|
+
inst.revive();
|
|
5735
|
+
inst.subscribe(notifyStateChange);
|
|
5736
|
+
}
|
|
5737
|
+
debugLog("Revived disposed instance(s) (React StrictMode)");
|
|
5519
5738
|
}
|
|
5739
|
+
if (chatRef.current === null) {
|
|
5740
|
+
const initialKey = concurrentThreads && threadId ? threadId : SINGLE_INSTANCE_KEY;
|
|
5741
|
+
activeInstanceKeyRef.current = initialKey;
|
|
5742
|
+
chatRef.current = createInstance(initialKey);
|
|
5743
|
+
}
|
|
5744
|
+
const switchActiveInstance = useCallback(
|
|
5745
|
+
(key, opts) => {
|
|
5746
|
+
if (!concurrentThreads) {
|
|
5747
|
+
chatRef.current?.setActiveThread(key);
|
|
5748
|
+
return;
|
|
5749
|
+
}
|
|
5750
|
+
let targetKey;
|
|
5751
|
+
if (key == null) {
|
|
5752
|
+
const currentKey = activeInstanceKeyRef.current;
|
|
5753
|
+
const currentInst = instancesRef.current.get(currentKey);
|
|
5754
|
+
const isCurrentFreshEmpty = currentInst !== void 0 && currentInst.messages.length === 0 && (currentKey === SINGLE_INSTANCE_KEY || currentKey.startsWith("__pending_"));
|
|
5755
|
+
if (isCurrentFreshEmpty) {
|
|
5756
|
+
return;
|
|
5757
|
+
}
|
|
5758
|
+
targetKey = `__pending_${++pendingCounterRef.current}__`;
|
|
5759
|
+
} else {
|
|
5760
|
+
targetKey = key;
|
|
5761
|
+
}
|
|
5762
|
+
let inst = instancesRef.current.get(targetKey);
|
|
5763
|
+
const wasFresh = !inst;
|
|
5764
|
+
if (!inst) {
|
|
5765
|
+
const currentKey = activeInstanceKeyRef.current;
|
|
5766
|
+
const currentInst = instancesRef.current.get(currentKey);
|
|
5767
|
+
const currentIsPromotableSlot = currentInst !== void 0 && currentInst.messages.length === 0 && (currentKey === SINGLE_INSTANCE_KEY || currentKey.startsWith("__pending_"));
|
|
5768
|
+
if (currentIsPromotableSlot) {
|
|
5769
|
+
instancesRef.current.delete(currentKey);
|
|
5770
|
+
instancesRef.current.set(targetKey, currentInst);
|
|
5771
|
+
currentInst.setActiveThread(targetKey);
|
|
5772
|
+
inst = currentInst;
|
|
5773
|
+
if (opts?.hydrateMessages) {
|
|
5774
|
+
inst.setMessages(opts.hydrateMessages);
|
|
5775
|
+
}
|
|
5776
|
+
if (opts?.hydrateActiveLeafId) {
|
|
5777
|
+
inst.switchBranch(opts.hydrateActiveLeafId);
|
|
5778
|
+
}
|
|
5779
|
+
} else {
|
|
5780
|
+
inst = createInstance(targetKey, {
|
|
5781
|
+
initialMessages: opts?.hydrateMessages
|
|
5782
|
+
});
|
|
5783
|
+
if (opts?.hydrateActiveLeafId) {
|
|
5784
|
+
inst.switchBranch(opts.hydrateActiveLeafId);
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5787
|
+
} else if (wasFresh && opts?.hydrateMessages && inst.messages.length === 0) {
|
|
5788
|
+
inst.setMessages(opts.hydrateMessages);
|
|
5789
|
+
if (opts.hydrateActiveLeafId)
|
|
5790
|
+
inst.switchBranch(opts.hydrateActiveLeafId);
|
|
5791
|
+
}
|
|
5792
|
+
if (activeInstanceKeyRef.current === targetKey) return;
|
|
5793
|
+
activeInstanceKeyRef.current = targetKey;
|
|
5794
|
+
chatRef.current = inst;
|
|
5795
|
+
if (targetKey === SINGLE_INSTANCE_KEY || targetKey.startsWith("__pending_")) {
|
|
5796
|
+
setActualThreadId(void 0);
|
|
5797
|
+
} else {
|
|
5798
|
+
setActualThreadId(targetKey);
|
|
5799
|
+
}
|
|
5800
|
+
setSessionStatus(inst.getSessionStatus());
|
|
5801
|
+
setToolExecutions(inst.toolExecutions);
|
|
5802
|
+
setAgentIteration(inst.iteration);
|
|
5803
|
+
notifyStateChange();
|
|
5804
|
+
debugLog("Active instance switched", { key: targetKey });
|
|
5805
|
+
},
|
|
5806
|
+
[concurrentThreads, createInstance, debugLog, notifyStateChange]
|
|
5807
|
+
);
|
|
5520
5808
|
useEffect(() => {
|
|
5521
|
-
if (
|
|
5522
|
-
|
|
5523
|
-
|
|
5809
|
+
if (systemPrompt === void 0) return;
|
|
5810
|
+
for (const inst of instancesRef.current.values()) {
|
|
5811
|
+
inst.setSystemPrompt(systemPrompt);
|
|
5524
5812
|
}
|
|
5813
|
+
debugLog("System prompt updated from prop");
|
|
5525
5814
|
}, [systemPrompt, debugLog]);
|
|
5526
5815
|
useEffect(() => {
|
|
5527
|
-
if (
|
|
5528
|
-
|
|
5529
|
-
|
|
5816
|
+
if (headers === void 0) return;
|
|
5817
|
+
for (const inst of instancesRef.current.values()) {
|
|
5818
|
+
inst.setHeaders(headers);
|
|
5530
5819
|
}
|
|
5820
|
+
debugLog("Headers config updated from prop");
|
|
5531
5821
|
}, [headers, debugLog]);
|
|
5532
5822
|
useEffect(() => {
|
|
5533
|
-
if (
|
|
5534
|
-
|
|
5535
|
-
|
|
5823
|
+
if (body === void 0) return;
|
|
5824
|
+
for (const inst of instancesRef.current.values()) {
|
|
5825
|
+
inst.setBody(body);
|
|
5536
5826
|
}
|
|
5827
|
+
debugLog("Body config updated from prop");
|
|
5537
5828
|
}, [body, debugLog]);
|
|
5538
5829
|
useEffect(() => {
|
|
5539
|
-
if (
|
|
5540
|
-
|
|
5541
|
-
|
|
5830
|
+
if (runtimeUrl === void 0) return;
|
|
5831
|
+
for (const inst of instancesRef.current.values()) {
|
|
5832
|
+
inst.setUrl(runtimeUrl);
|
|
5542
5833
|
}
|
|
5834
|
+
debugLog("URL config updated from prop");
|
|
5543
5835
|
}, [runtimeUrl, debugLog]);
|
|
5544
5836
|
useEffect(() => {
|
|
5545
5837
|
const prev = lastControlledThreadIdRef.current;
|
|
@@ -5555,11 +5847,21 @@ function CopilotProvider(props) {
|
|
|
5555
5847
|
if (!isThreadIdControlled) {
|
|
5556
5848
|
return;
|
|
5557
5849
|
}
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5850
|
+
if (concurrentThreads) {
|
|
5851
|
+
switchActiveInstance(threadId ?? null);
|
|
5852
|
+
} else {
|
|
5853
|
+
chatRef.current?.setActiveThread(threadId ?? null);
|
|
5854
|
+
setActualThreadId(threadId);
|
|
5855
|
+
setSessionStatus(threadId ? "ready" : "idle");
|
|
5856
|
+
}
|
|
5561
5857
|
debugLog("Thread/session synced from prop", { threadId });
|
|
5562
|
-
}, [
|
|
5858
|
+
}, [
|
|
5859
|
+
debugLog,
|
|
5860
|
+
isThreadIdControlled,
|
|
5861
|
+
threadId,
|
|
5862
|
+
concurrentThreads,
|
|
5863
|
+
switchActiveInstance
|
|
5864
|
+
]);
|
|
5563
5865
|
const EMPTY_MESSAGES = useRef([]);
|
|
5564
5866
|
const getMessagesSnapshot = useCallback(() => chatRef.current.messages, []);
|
|
5565
5867
|
const getServerMessagesSnapshot = useCallback(
|
|
@@ -5569,36 +5871,110 @@ function CopilotProvider(props) {
|
|
|
5569
5871
|
const getStatusSnapshot = useCallback(() => chatRef.current.status, []);
|
|
5570
5872
|
const getErrorSnapshot = useCallback(() => chatRef.current.error, []);
|
|
5571
5873
|
const messages = useSyncExternalStore(
|
|
5572
|
-
|
|
5874
|
+
stableSubscribe,
|
|
5573
5875
|
getMessagesSnapshot,
|
|
5574
5876
|
getServerMessagesSnapshot
|
|
5575
5877
|
);
|
|
5576
5878
|
const status = useSyncExternalStore(
|
|
5577
|
-
|
|
5879
|
+
stableSubscribe,
|
|
5578
5880
|
getStatusSnapshot,
|
|
5579
5881
|
() => "ready"
|
|
5580
5882
|
);
|
|
5581
5883
|
const errorFromChat = useSyncExternalStore(
|
|
5582
|
-
|
|
5884
|
+
stableSubscribe,
|
|
5583
5885
|
getErrorSnapshot,
|
|
5584
5886
|
() => void 0
|
|
5585
5887
|
);
|
|
5586
5888
|
const error = errorFromChat ?? null;
|
|
5587
5889
|
const isLoading = status === "streaming" || status === "submitted";
|
|
5588
|
-
const setActiveThread = useCallback(
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5890
|
+
const setActiveThread = useCallback(
|
|
5891
|
+
(id, opts) => {
|
|
5892
|
+
if (concurrentThreads) {
|
|
5893
|
+
switchActiveInstance(id, opts);
|
|
5894
|
+
} else {
|
|
5895
|
+
chatRef.current?.setActiveThread(id);
|
|
5896
|
+
setActualThreadId(id ?? void 0);
|
|
5897
|
+
}
|
|
5898
|
+
},
|
|
5899
|
+
[concurrentThreads, switchActiveInstance]
|
|
5900
|
+
);
|
|
5901
|
+
const disposeThreadInstance = useCallback(
|
|
5902
|
+
(id) => {
|
|
5903
|
+
if (!concurrentThreads) return;
|
|
5904
|
+
const inst = instancesRef.current.get(id);
|
|
5905
|
+
if (!inst) return;
|
|
5906
|
+
inst.dispose();
|
|
5907
|
+
instancesRef.current.delete(id);
|
|
5908
|
+
if (activeInstanceKeyRef.current === id) {
|
|
5909
|
+
switchActiveInstance(null);
|
|
5910
|
+
} else {
|
|
5911
|
+
recomputeBusyThreadIds();
|
|
5912
|
+
recomputePendingApprovalsByThread();
|
|
5913
|
+
}
|
|
5914
|
+
},
|
|
5915
|
+
[
|
|
5916
|
+
concurrentThreads,
|
|
5917
|
+
switchActiveInstance,
|
|
5918
|
+
recomputeBusyThreadIds,
|
|
5919
|
+
recomputePendingApprovalsByThread
|
|
5920
|
+
]
|
|
5921
|
+
);
|
|
5922
|
+
const assignLocalThreadId = useCallback(
|
|
5923
|
+
(localId) => {
|
|
5924
|
+
if (!concurrentThreads) return;
|
|
5925
|
+
if (!localId) return;
|
|
5926
|
+
const currentKey = activeInstanceKeyRef.current;
|
|
5927
|
+
if (currentKey === localId) return;
|
|
5928
|
+
const currentInst = instancesRef.current.get(currentKey);
|
|
5929
|
+
if (!currentInst) return;
|
|
5930
|
+
const isInternalSlot = currentKey === SINGLE_INSTANCE_KEY || currentKey.startsWith("__pending_");
|
|
5931
|
+
if (!isInternalSlot) return;
|
|
5932
|
+
if (instancesRef.current.has(localId)) return;
|
|
5933
|
+
instancesRef.current.delete(currentKey);
|
|
5934
|
+
instancesRef.current.set(localId, currentInst);
|
|
5935
|
+
activeInstanceKeyRef.current = localId;
|
|
5936
|
+
if (currentInst === chatRef.current) {
|
|
5937
|
+
setActualThreadId(localId);
|
|
5938
|
+
callbacksRef.current.onThreadChange?.(localId);
|
|
5939
|
+
}
|
|
5940
|
+
recomputeBusyThreadIds();
|
|
5941
|
+
recomputePendingApprovalsByThread();
|
|
5942
|
+
debugLog("Assigned local thread id", { localId });
|
|
5943
|
+
},
|
|
5944
|
+
[
|
|
5945
|
+
concurrentThreads,
|
|
5946
|
+
debugLog,
|
|
5947
|
+
recomputeBusyThreadIds,
|
|
5948
|
+
recomputePendingApprovalsByThread
|
|
5949
|
+
]
|
|
5950
|
+
);
|
|
5592
5951
|
const renewSession = useCallback(() => {
|
|
5593
5952
|
chatRef.current?.renewSession();
|
|
5594
5953
|
setActualThreadId(void 0);
|
|
5595
5954
|
setSessionStatus("idle");
|
|
5596
5955
|
}, []);
|
|
5597
5956
|
const registerTool = useCallback((tool) => {
|
|
5598
|
-
|
|
5957
|
+
const existing = sharedToolsRef.current.get(tool.name);
|
|
5958
|
+
if (existing) {
|
|
5959
|
+
existing.tool = tool;
|
|
5960
|
+
existing.refCount++;
|
|
5961
|
+
} else {
|
|
5962
|
+
sharedToolsRef.current.set(tool.name, { tool, refCount: 1 });
|
|
5963
|
+
}
|
|
5964
|
+
for (const inst of instancesRef.current.values()) {
|
|
5965
|
+
inst.registerTool(tool);
|
|
5966
|
+
}
|
|
5599
5967
|
}, []);
|
|
5600
5968
|
const unregisterTool = useCallback((name) => {
|
|
5601
|
-
|
|
5969
|
+
const entry = sharedToolsRef.current.get(name);
|
|
5970
|
+
if (!entry) return;
|
|
5971
|
+
entry.refCount = Math.max(0, entry.refCount - 1);
|
|
5972
|
+
for (const inst of instancesRef.current.values()) {
|
|
5973
|
+
inst.unregisterTool(name);
|
|
5974
|
+
}
|
|
5975
|
+
if (entry.refCount === 0) {
|
|
5976
|
+
sharedToolsRef.current.delete(name);
|
|
5977
|
+
}
|
|
5602
5978
|
}, []);
|
|
5603
5979
|
const approveToolExecution = useCallback(
|
|
5604
5980
|
(id, extraData, permissionLevel) => {
|
|
@@ -5649,6 +6025,7 @@ function CopilotProvider(props) {
|
|
|
5649
6025
|
parentId
|
|
5650
6026
|
);
|
|
5651
6027
|
const contextString = printTree(contextTreeRef.current);
|
|
6028
|
+
sharedSystemContextRef.current = contextString;
|
|
5652
6029
|
chatRef.current?.setContext(contextString);
|
|
5653
6030
|
setContextChars(contextString.length);
|
|
5654
6031
|
debugLog("Context added:", id);
|
|
@@ -5660,6 +6037,7 @@ function CopilotProvider(props) {
|
|
|
5660
6037
|
(id) => {
|
|
5661
6038
|
contextTreeRef.current = removeNode(contextTreeRef.current, id);
|
|
5662
6039
|
const contextString = printTree(contextTreeRef.current);
|
|
6040
|
+
sharedSystemContextRef.current = contextString;
|
|
5663
6041
|
chatRef.current?.setContext(contextString);
|
|
5664
6042
|
setContextChars(contextString.length);
|
|
5665
6043
|
debugLog("Context removed:", id);
|
|
@@ -5668,14 +6046,19 @@ function CopilotProvider(props) {
|
|
|
5668
6046
|
);
|
|
5669
6047
|
const setSystemPrompt = useCallback(
|
|
5670
6048
|
(prompt) => {
|
|
5671
|
-
|
|
6049
|
+
for (const inst of instancesRef.current.values()) {
|
|
6050
|
+
inst.setSystemPrompt(prompt);
|
|
6051
|
+
}
|
|
5672
6052
|
debugLog("System prompt updated via function");
|
|
5673
6053
|
},
|
|
5674
6054
|
[debugLog]
|
|
5675
6055
|
);
|
|
5676
6056
|
const setInlineSkills = useCallback(
|
|
5677
6057
|
(skills2) => {
|
|
5678
|
-
|
|
6058
|
+
sharedSkillsRef.current = skills2;
|
|
6059
|
+
for (const inst of instancesRef.current.values()) {
|
|
6060
|
+
inst.setInlineSkills(skills2);
|
|
6061
|
+
}
|
|
5679
6062
|
debugLog("Inline skills updated", { count: skills2.length });
|
|
5680
6063
|
},
|
|
5681
6064
|
[debugLog]
|
|
@@ -5723,7 +6106,7 @@ function CopilotProvider(props) {
|
|
|
5723
6106
|
[]
|
|
5724
6107
|
);
|
|
5725
6108
|
const hasBranches = useSyncExternalStore(
|
|
5726
|
-
|
|
6109
|
+
stableSubscribe,
|
|
5727
6110
|
getHasBranchesSnapshot,
|
|
5728
6111
|
() => false
|
|
5729
6112
|
);
|
|
@@ -5758,7 +6141,9 @@ function CopilotProvider(props) {
|
|
|
5758
6141
|
}, [error, onError]);
|
|
5759
6142
|
useEffect(() => {
|
|
5760
6143
|
return () => {
|
|
5761
|
-
|
|
6144
|
+
for (const inst of instancesRef.current.values()) {
|
|
6145
|
+
inst.dispose();
|
|
6146
|
+
}
|
|
5762
6147
|
};
|
|
5763
6148
|
}, []);
|
|
5764
6149
|
const contextValue = useMemo(
|
|
@@ -5812,7 +6197,13 @@ function CopilotProvider(props) {
|
|
|
5812
6197
|
toolsConfig,
|
|
5813
6198
|
// Headless primitives
|
|
5814
6199
|
subscribeToStreamEvents,
|
|
5815
|
-
messageMeta: messageMetaStoreRef.current
|
|
6200
|
+
messageMeta: messageMetaStoreRef.current,
|
|
6201
|
+
// Multi-thread streaming
|
|
6202
|
+
concurrentThreads,
|
|
6203
|
+
busyThreadIds,
|
|
6204
|
+
pendingApprovalsByThread,
|
|
6205
|
+
disposeThreadInstance,
|
|
6206
|
+
assignLocalThreadId
|
|
5816
6207
|
}),
|
|
5817
6208
|
[
|
|
5818
6209
|
messages,
|
|
@@ -5852,7 +6243,12 @@ function CopilotProvider(props) {
|
|
|
5852
6243
|
renewSession,
|
|
5853
6244
|
sessionStatus,
|
|
5854
6245
|
runtimeUrl,
|
|
5855
|
-
toolsConfig
|
|
6246
|
+
toolsConfig,
|
|
6247
|
+
concurrentThreads,
|
|
6248
|
+
busyThreadIds,
|
|
6249
|
+
pendingApprovalsByThread,
|
|
6250
|
+
disposeThreadInstance,
|
|
6251
|
+
assignLocalThreadId
|
|
5856
6252
|
]
|
|
5857
6253
|
);
|
|
5858
6254
|
const messageHistoryContextValue = React2.useMemo(
|
|
@@ -5958,5 +6354,5 @@ function useMCPTools(config) {
|
|
|
5958
6354
|
}
|
|
5959
6355
|
|
|
5960
6356
|
export { AbstractAgentLoop, AbstractChat, CopilotProvider, MessageHistoryContext, MessageTree, ReactChatState, SkillProvider, createReactChatState, defaultMessageHistoryConfig, initialAgentLoopState, isCompactionMarker, keepToolPairsAtomic, toDisplayMessage, toLLMMessage, toLLMMessages, useAIContext, useAIContexts, useCopilot, useMCPClient, useMCPTools, useMessageHistory, useMessageHistoryContext, useSkillContext, useTool, useTools };
|
|
5961
|
-
//# sourceMappingURL=chunk-
|
|
5962
|
-
//# sourceMappingURL=chunk-
|
|
6357
|
+
//# sourceMappingURL=chunk-37HN4F6S.js.map
|
|
6358
|
+
//# sourceMappingURL=chunk-37HN4F6S.js.map
|