@yourgpt/copilot-sdk 2.5.1-beta.1 → 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 +98 -31
- 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 +95 -28
- 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
|
@@ -1561,6 +1561,10 @@ var AbstractChat = class {
|
|
|
1561
1561
|
get isStreaming() {
|
|
1562
1562
|
return this.transport.isStreaming();
|
|
1563
1563
|
}
|
|
1564
|
+
/** The thread id currently associated with this chat, if any. */
|
|
1565
|
+
get threadId() {
|
|
1566
|
+
return this.config.threadId;
|
|
1567
|
+
}
|
|
1564
1568
|
// ============================================
|
|
1565
1569
|
// Public Actions
|
|
1566
1570
|
// ============================================
|
|
@@ -2206,6 +2210,7 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2206
2210
|
this.debug("Starting to process stream");
|
|
2207
2211
|
let chunkCount = 0;
|
|
2208
2212
|
let toolCallsEmitted = false;
|
|
2213
|
+
let postToolTextStreamed = false;
|
|
2209
2214
|
let pendingClientToolCalls;
|
|
2210
2215
|
for await (const chunk of stream) {
|
|
2211
2216
|
chunkCount++;
|
|
@@ -2262,15 +2267,27 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2262
2267
|
continue;
|
|
2263
2268
|
}
|
|
2264
2269
|
if (!this.streamState) {
|
|
2265
|
-
if (chunk.type === "
|
|
2270
|
+
if (chunk.type === "message:delta") {
|
|
2271
|
+
this.debug(
|
|
2272
|
+
"message:delta with no streamState \u2014 auto-init new message"
|
|
2273
|
+
);
|
|
2274
|
+
const currentLeaf = this.state.messages;
|
|
2275
|
+
const currentLeafId = currentLeaf.length > 0 ? currentLeaf[currentLeaf.length - 1].id : void 0;
|
|
2276
|
+
const newMessage = createEmptyAssistantMessage(void 0, {
|
|
2277
|
+
parentId: currentLeafId
|
|
2278
|
+
});
|
|
2279
|
+
this.state.pushMessage(newMessage);
|
|
2280
|
+
this.streamState = createStreamState(newMessage.id);
|
|
2281
|
+
this.callbacks.onMessageStart?.(newMessage.id);
|
|
2282
|
+
postToolTextStreamed = true;
|
|
2283
|
+
} else if (chunk.type === "tool_calls") {
|
|
2266
2284
|
pendingClientToolCalls = chunk.toolCalls;
|
|
2267
2285
|
this.debug("tool_calls (post-message:end, stored as pending)", {
|
|
2268
2286
|
count: pendingClientToolCalls?.length,
|
|
2269
2287
|
ids: pendingClientToolCalls?.map((tc) => tc.id)
|
|
2270
2288
|
});
|
|
2271
2289
|
continue;
|
|
2272
|
-
}
|
|
2273
|
-
if (chunk.type === "done") {
|
|
2290
|
+
} else if (chunk.type === "done") {
|
|
2274
2291
|
this.debug("done (post-message:end)", {
|
|
2275
2292
|
hasPendingToolCalls: !!pendingClientToolCalls?.length,
|
|
2276
2293
|
pendingCount: pendingClientToolCalls?.length ?? 0,
|
|
@@ -2362,9 +2379,10 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2362
2379
|
});
|
|
2363
2380
|
}
|
|
2364
2381
|
continue;
|
|
2382
|
+
} else {
|
|
2383
|
+
this.debug("warning", "streamState is null, skipping chunk");
|
|
2384
|
+
continue;
|
|
2365
2385
|
}
|
|
2366
|
-
this.debug("warning", "streamState is null, skipping chunk");
|
|
2367
|
-
continue;
|
|
2368
2386
|
}
|
|
2369
2387
|
this.streamState = processStreamChunk(chunk, this.streamState);
|
|
2370
2388
|
if (chunk.type === "action:start") {
|
|
@@ -2460,9 +2478,12 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
|
|
|
2460
2478
|
}
|
|
2461
2479
|
}
|
|
2462
2480
|
}
|
|
2481
|
+
let seenToolResult = false;
|
|
2463
2482
|
for (const msg of chunk.messages) {
|
|
2483
|
+
if (msg.role === "tool") seenToolResult = true;
|
|
2464
2484
|
if (msg.role === "assistant" && !msg.tool_calls?.length) {
|
|
2465
|
-
continue;
|
|
2485
|
+
if (!seenToolResult) continue;
|
|
2486
|
+
if (postToolTextStreamed) continue;
|
|
2466
2487
|
}
|
|
2467
2488
|
if (msg.role === "assistant" && msg.tool_calls?.length && msg.tool_calls.every(
|
|
2468
2489
|
(toolCall) => currentStreamToolCallIds.has(toolCall.id)
|
|
@@ -2990,6 +3011,7 @@ var AbstractAgentLoop = class {
|
|
|
2990
3011
|
}
|
|
2991
3012
|
const result = await tool.handler(toolCall.args, {
|
|
2992
3013
|
signal: this.abortController?.signal,
|
|
3014
|
+
threadId: this.config.getThreadId?.(),
|
|
2993
3015
|
data: { toolCallId: toolCall.id },
|
|
2994
3016
|
approvalData
|
|
2995
3017
|
});
|
|
@@ -3517,7 +3539,13 @@ var ChatWithTools = class {
|
|
|
3517
3539
|
this.agentLoop = new AbstractAgentLoop(
|
|
3518
3540
|
{
|
|
3519
3541
|
maxIterations: config.maxIterations ?? 20,
|
|
3520
|
-
tools: config.tools
|
|
3542
|
+
tools: config.tools,
|
|
3543
|
+
// Expose this chat's current threadId to tool handlers via
|
|
3544
|
+
// ToolContext.threadId. Read lazily per invocation so it reflects
|
|
3545
|
+
// the id assigned by the server mid-stream (thread:created).
|
|
3546
|
+
// If the caller provided a getThreadId override (e.g. the React
|
|
3547
|
+
// provider exposing its stable registry key), prefer that.
|
|
3548
|
+
getThreadId: config.getThreadId ? () => config.getThreadId() : () => this.chat?.threadId
|
|
3521
3549
|
},
|
|
3522
3550
|
{
|
|
3523
3551
|
onExecutionsChange: (executions) => {
|
|
@@ -5427,7 +5455,8 @@ function CopilotProvider(props) {
|
|
|
5427
5455
|
mcpServers,
|
|
5428
5456
|
optimization,
|
|
5429
5457
|
messageHistory,
|
|
5430
|
-
skills
|
|
5458
|
+
skills,
|
|
5459
|
+
concurrentThreads = false
|
|
5431
5460
|
} = props;
|
|
5432
5461
|
const isThreadIdControlled = Object.prototype.hasOwnProperty.call(
|
|
5433
5462
|
props,
|
|
@@ -5465,87 +5494,350 @@ function CopilotProvider(props) {
|
|
|
5465
5494
|
controlled: isThreadIdControlled,
|
|
5466
5495
|
value: threadId
|
|
5467
5496
|
});
|
|
5497
|
+
const SINGLE_INSTANCE_KEY = "__single__";
|
|
5468
5498
|
const chatRef = React2.useRef(null);
|
|
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
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5499
|
+
const instancesRef = React2.useRef(/* @__PURE__ */ new Map());
|
|
5500
|
+
const activeInstanceKeyRef = React2.useRef(SINGLE_INSTANCE_KEY);
|
|
5501
|
+
const pendingCounterRef = React2.useRef(0);
|
|
5502
|
+
const sharedToolsRef = React2.useRef(/* @__PURE__ */ new Map());
|
|
5503
|
+
const sharedSkillsRef = React2.useRef([]);
|
|
5504
|
+
const sharedSystemContextRef = React2.useRef("");
|
|
5505
|
+
const subscribersRef = React2.useRef(/* @__PURE__ */ new Set());
|
|
5506
|
+
const stableSubscribe = React2.useMemo(
|
|
5507
|
+
() => (cb) => {
|
|
5508
|
+
subscribersRef.current.add(cb);
|
|
5509
|
+
return () => {
|
|
5510
|
+
subscribersRef.current.delete(cb);
|
|
5511
|
+
};
|
|
5512
|
+
},
|
|
5513
|
+
[]
|
|
5514
|
+
);
|
|
5515
|
+
const [busyThreadIds, setBusyThreadIds] = React2.useState(
|
|
5516
|
+
() => /* @__PURE__ */ new Set()
|
|
5517
|
+
);
|
|
5518
|
+
const recomputeBusyThreadIds = React2.useCallback(() => {
|
|
5519
|
+
if (!concurrentThreads) return;
|
|
5520
|
+
const next = /* @__PURE__ */ new Set();
|
|
5521
|
+
for (const [key, inst] of instancesRef.current) {
|
|
5522
|
+
if (key === SINGLE_INSTANCE_KEY) continue;
|
|
5523
|
+
if (key.startsWith("__pending_")) continue;
|
|
5524
|
+
const s = inst.status;
|
|
5525
|
+
if (s === "streaming" || s === "submitted") next.add(key);
|
|
5526
|
+
}
|
|
5527
|
+
setBusyThreadIds((prev) => {
|
|
5528
|
+
if (prev.size === next.size) {
|
|
5529
|
+
let same = true;
|
|
5530
|
+
for (const id of next) {
|
|
5531
|
+
if (!prev.has(id)) {
|
|
5532
|
+
same = false;
|
|
5533
|
+
break;
|
|
5534
|
+
}
|
|
5535
|
+
}
|
|
5536
|
+
if (same) return prev;
|
|
5537
|
+
}
|
|
5538
|
+
return next;
|
|
5539
|
+
});
|
|
5540
|
+
}, [concurrentThreads]);
|
|
5541
|
+
const [pendingApprovalsByThread, setPendingApprovalsByThread] = React2.useState(() => /* @__PURE__ */ new Map());
|
|
5542
|
+
const recomputePendingApprovalsByThread = React2.useCallback(() => {
|
|
5543
|
+
if (!concurrentThreads) return;
|
|
5544
|
+
const next = /* @__PURE__ */ new Map();
|
|
5545
|
+
for (const [key, inst] of instancesRef.current) {
|
|
5546
|
+
if (key === SINGLE_INSTANCE_KEY) continue;
|
|
5547
|
+
if (key.startsWith("__pending_")) continue;
|
|
5548
|
+
const pending = inst.toolExecutions.filter(
|
|
5549
|
+
(e) => e.approvalStatus === "required"
|
|
5550
|
+
);
|
|
5551
|
+
if (pending.length > 0) next.set(key, pending);
|
|
5552
|
+
}
|
|
5553
|
+
setPendingApprovalsByThread((prev) => {
|
|
5554
|
+
if (prev.size !== next.size) return next;
|
|
5555
|
+
for (const [id, execs] of next) {
|
|
5556
|
+
const prevExecs = prev.get(id);
|
|
5557
|
+
if (!prevExecs || prevExecs.length !== execs.length) return next;
|
|
5558
|
+
for (let i = 0; i < execs.length; i++) {
|
|
5559
|
+
if (prevExecs[i] !== execs[i]) return next;
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
5562
|
+
return prev;
|
|
5563
|
+
});
|
|
5564
|
+
}, [concurrentThreads]);
|
|
5565
|
+
const notifyStateChange = React2.useCallback(() => {
|
|
5566
|
+
for (const cb of subscribersRef.current) cb();
|
|
5567
|
+
recomputeBusyThreadIds();
|
|
5568
|
+
recomputePendingApprovalsByThread();
|
|
5569
|
+
}, [recomputeBusyThreadIds, recomputePendingApprovalsByThread]);
|
|
5570
|
+
const configRef = React2.useRef({
|
|
5571
|
+
runtimeUrl,
|
|
5572
|
+
systemPrompt,
|
|
5573
|
+
threadId,
|
|
5574
|
+
onCreateSession,
|
|
5575
|
+
yourgptConfig,
|
|
5576
|
+
initialMessages,
|
|
5577
|
+
streaming,
|
|
5578
|
+
headers,
|
|
5579
|
+
body,
|
|
5580
|
+
parseError,
|
|
5581
|
+
debug,
|
|
5582
|
+
maxIterations,
|
|
5583
|
+
maxIterationsMessage,
|
|
5584
|
+
optimization
|
|
5585
|
+
});
|
|
5586
|
+
configRef.current = {
|
|
5587
|
+
runtimeUrl,
|
|
5588
|
+
systemPrompt,
|
|
5589
|
+
threadId,
|
|
5590
|
+
onCreateSession,
|
|
5591
|
+
yourgptConfig,
|
|
5592
|
+
initialMessages,
|
|
5593
|
+
streaming,
|
|
5594
|
+
headers,
|
|
5595
|
+
body,
|
|
5596
|
+
parseError,
|
|
5597
|
+
debug,
|
|
5598
|
+
maxIterations,
|
|
5599
|
+
maxIterationsMessage,
|
|
5600
|
+
optimization
|
|
5601
|
+
};
|
|
5602
|
+
const callbacksRef = React2.useRef({ onError, onThreadChange });
|
|
5603
|
+
callbacksRef.current = { onError, onThreadChange };
|
|
5604
|
+
const handleInstanceThreadAssigned = React2.useCallback(
|
|
5605
|
+
(inst, newId) => {
|
|
5606
|
+
let oldKey;
|
|
5607
|
+
for (const [k, v] of instancesRef.current) {
|
|
5608
|
+
if (v === inst) {
|
|
5609
|
+
oldKey = k;
|
|
5610
|
+
break;
|
|
5611
|
+
}
|
|
5612
|
+
}
|
|
5613
|
+
if (oldKey === void 0) return;
|
|
5614
|
+
const isInternalKey = oldKey === SINGLE_INSTANCE_KEY || oldKey.startsWith("__pending_");
|
|
5615
|
+
const shouldRekey = !concurrentThreads || isInternalKey;
|
|
5616
|
+
if (shouldRekey && oldKey !== newId && !instancesRef.current.has(newId)) {
|
|
5617
|
+
instancesRef.current.delete(oldKey);
|
|
5618
|
+
instancesRef.current.set(newId, inst);
|
|
5619
|
+
if (activeInstanceKeyRef.current === oldKey) {
|
|
5620
|
+
activeInstanceKeyRef.current = newId;
|
|
5621
|
+
}
|
|
5622
|
+
if (inst === chatRef.current) {
|
|
5623
|
+
debugLog("Thread/session ID assigned:", newId);
|
|
5624
|
+
setActualThreadId(newId);
|
|
5625
|
+
callbacksRef.current.onThreadChange?.(newId);
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
recomputeBusyThreadIds();
|
|
5629
|
+
recomputePendingApprovalsByThread();
|
|
5630
|
+
},
|
|
5631
|
+
[
|
|
5632
|
+
concurrentThreads,
|
|
5633
|
+
debugLog,
|
|
5634
|
+
recomputeBusyThreadIds,
|
|
5635
|
+
recomputePendingApprovalsByThread
|
|
5636
|
+
]
|
|
5637
|
+
);
|
|
5638
|
+
const createInstance = React2.useCallback(
|
|
5639
|
+
(key, opts) => {
|
|
5640
|
+
const cfg = configRef.current;
|
|
5641
|
+
const initialThreadId = key === SINGLE_INSTANCE_KEY || key.startsWith("__pending_") ? cfg.threadId : key;
|
|
5642
|
+
const inst = new ReactChatWithTools(
|
|
5643
|
+
{
|
|
5644
|
+
runtimeUrl: cfg.runtimeUrl,
|
|
5645
|
+
systemPrompt: cfg.systemPrompt,
|
|
5646
|
+
threadId: initialThreadId,
|
|
5647
|
+
onCreateSession: cfg.onCreateSession,
|
|
5648
|
+
yourgptConfig: cfg.yourgptConfig,
|
|
5649
|
+
initialMessages: opts?.initialMessages ?? cfg.initialMessages,
|
|
5650
|
+
streaming: cfg.streaming,
|
|
5651
|
+
headers: cfg.headers,
|
|
5652
|
+
body: cfg.body,
|
|
5653
|
+
parseError: cfg.parseError,
|
|
5654
|
+
debug: cfg.debug,
|
|
5655
|
+
maxIterations: cfg.maxIterations,
|
|
5656
|
+
maxIterationsMessage: cfg.maxIterationsMessage,
|
|
5657
|
+
optimization: cfg.optimization,
|
|
5658
|
+
// Expose the registry key (usually the UI thread id after
|
|
5659
|
+
// assignLocalThreadId runs) to tool handlers, NOT chat.config.threadId.
|
|
5660
|
+
// For extensions that key per-thread state on context.threadId (e.g.
|
|
5661
|
+
// browser-tab pinning), this guarantees a stable id — even while the
|
|
5662
|
+
// backend session id is still being resolved. Internal keys
|
|
5663
|
+
// (__single__, __pending_*) return undefined so handlers can treat
|
|
5664
|
+
// them as "not yet committed".
|
|
5665
|
+
getThreadId: () => {
|
|
5666
|
+
for (const [k, v] of instancesRef.current) {
|
|
5667
|
+
if (v === inst) {
|
|
5668
|
+
if (k === SINGLE_INSTANCE_KEY || k.startsWith("__pending_")) {
|
|
5669
|
+
return void 0;
|
|
5670
|
+
}
|
|
5671
|
+
return k;
|
|
5672
|
+
}
|
|
5673
|
+
}
|
|
5674
|
+
return void 0;
|
|
5675
|
+
}
|
|
5515
5676
|
},
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5677
|
+
{
|
|
5678
|
+
onToolExecutionsChange: (executions) => {
|
|
5679
|
+
debugLog("Tool executions changed:", executions.length);
|
|
5680
|
+
if (inst === chatRef.current) {
|
|
5681
|
+
setToolExecutions(executions);
|
|
5682
|
+
setAgentIteration(inst.iteration ?? 0);
|
|
5683
|
+
}
|
|
5684
|
+
recomputePendingApprovalsByThread();
|
|
5685
|
+
},
|
|
5686
|
+
onApprovalRequired: (execution) => {
|
|
5687
|
+
debugLog("Tool approval required:", execution.name);
|
|
5688
|
+
recomputePendingApprovalsByThread();
|
|
5689
|
+
},
|
|
5690
|
+
onContextUsageChange: (usage) => {
|
|
5691
|
+
if (inst === chatRef.current) {
|
|
5692
|
+
setContextUsage(usage);
|
|
5693
|
+
}
|
|
5694
|
+
},
|
|
5695
|
+
onError: (error2) => {
|
|
5696
|
+
if (error2 && inst === chatRef.current) {
|
|
5697
|
+
callbacksRef.current.onError?.(error2);
|
|
5698
|
+
}
|
|
5699
|
+
},
|
|
5700
|
+
onThreadChange: (id) => {
|
|
5701
|
+
handleInstanceThreadAssigned(inst, id);
|
|
5702
|
+
},
|
|
5703
|
+
onSessionStatusChange: (status2) => {
|
|
5704
|
+
debugLog("Session status:", status2);
|
|
5705
|
+
if (inst === chatRef.current) {
|
|
5706
|
+
setSessionStatus(status2);
|
|
5707
|
+
}
|
|
5708
|
+
},
|
|
5709
|
+
onStreamChunk: (chunk) => {
|
|
5710
|
+
if (streamListenersRef.current.size > 0) {
|
|
5711
|
+
for (const handler of streamListenersRef.current) {
|
|
5712
|
+
handler(chunk);
|
|
5713
|
+
}
|
|
5520
5714
|
}
|
|
5521
5715
|
}
|
|
5522
5716
|
}
|
|
5717
|
+
);
|
|
5718
|
+
for (const { tool } of sharedToolsRef.current.values()) {
|
|
5719
|
+
inst.registerTool(tool);
|
|
5523
5720
|
}
|
|
5524
|
-
|
|
5721
|
+
if (sharedSkillsRef.current.length > 0) {
|
|
5722
|
+
inst.setInlineSkills(sharedSkillsRef.current);
|
|
5723
|
+
}
|
|
5724
|
+
if (sharedSystemContextRef.current) {
|
|
5725
|
+
inst.setContext(sharedSystemContextRef.current);
|
|
5726
|
+
}
|
|
5727
|
+
inst.subscribe(notifyStateChange);
|
|
5728
|
+
instancesRef.current.set(key, inst);
|
|
5729
|
+
return inst;
|
|
5730
|
+
},
|
|
5731
|
+
[
|
|
5732
|
+
debugLog,
|
|
5733
|
+
handleInstanceThreadAssigned,
|
|
5734
|
+
notifyStateChange,
|
|
5735
|
+
recomputePendingApprovalsByThread
|
|
5736
|
+
]
|
|
5737
|
+
);
|
|
5738
|
+
if (chatRef.current !== null && chatRef.current.disposed) {
|
|
5739
|
+
for (const inst of instancesRef.current.values()) {
|
|
5740
|
+
inst.revive();
|
|
5741
|
+
inst.subscribe(notifyStateChange);
|
|
5742
|
+
}
|
|
5743
|
+
debugLog("Revived disposed instance(s) (React StrictMode)");
|
|
5525
5744
|
}
|
|
5745
|
+
if (chatRef.current === null) {
|
|
5746
|
+
const initialKey = concurrentThreads && threadId ? threadId : SINGLE_INSTANCE_KEY;
|
|
5747
|
+
activeInstanceKeyRef.current = initialKey;
|
|
5748
|
+
chatRef.current = createInstance(initialKey);
|
|
5749
|
+
}
|
|
5750
|
+
const switchActiveInstance = React2.useCallback(
|
|
5751
|
+
(key, opts) => {
|
|
5752
|
+
if (!concurrentThreads) {
|
|
5753
|
+
chatRef.current?.setActiveThread(key);
|
|
5754
|
+
return;
|
|
5755
|
+
}
|
|
5756
|
+
let targetKey;
|
|
5757
|
+
if (key == null) {
|
|
5758
|
+
const currentKey = activeInstanceKeyRef.current;
|
|
5759
|
+
const currentInst = instancesRef.current.get(currentKey);
|
|
5760
|
+
const isCurrentFreshEmpty = currentInst !== void 0 && currentInst.messages.length === 0 && (currentKey === SINGLE_INSTANCE_KEY || currentKey.startsWith("__pending_"));
|
|
5761
|
+
if (isCurrentFreshEmpty) {
|
|
5762
|
+
return;
|
|
5763
|
+
}
|
|
5764
|
+
targetKey = `__pending_${++pendingCounterRef.current}__`;
|
|
5765
|
+
} else {
|
|
5766
|
+
targetKey = key;
|
|
5767
|
+
}
|
|
5768
|
+
let inst = instancesRef.current.get(targetKey);
|
|
5769
|
+
const wasFresh = !inst;
|
|
5770
|
+
if (!inst) {
|
|
5771
|
+
const currentKey = activeInstanceKeyRef.current;
|
|
5772
|
+
const currentInst = instancesRef.current.get(currentKey);
|
|
5773
|
+
const currentIsPromotableSlot = currentInst !== void 0 && currentInst.messages.length === 0 && (currentKey === SINGLE_INSTANCE_KEY || currentKey.startsWith("__pending_"));
|
|
5774
|
+
if (currentIsPromotableSlot) {
|
|
5775
|
+
instancesRef.current.delete(currentKey);
|
|
5776
|
+
instancesRef.current.set(targetKey, currentInst);
|
|
5777
|
+
currentInst.setActiveThread(targetKey);
|
|
5778
|
+
inst = currentInst;
|
|
5779
|
+
if (opts?.hydrateMessages) {
|
|
5780
|
+
inst.setMessages(opts.hydrateMessages);
|
|
5781
|
+
}
|
|
5782
|
+
if (opts?.hydrateActiveLeafId) {
|
|
5783
|
+
inst.switchBranch(opts.hydrateActiveLeafId);
|
|
5784
|
+
}
|
|
5785
|
+
} else {
|
|
5786
|
+
inst = createInstance(targetKey, {
|
|
5787
|
+
initialMessages: opts?.hydrateMessages
|
|
5788
|
+
});
|
|
5789
|
+
if (opts?.hydrateActiveLeafId) {
|
|
5790
|
+
inst.switchBranch(opts.hydrateActiveLeafId);
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5793
|
+
} else if (wasFresh && opts?.hydrateMessages && inst.messages.length === 0) {
|
|
5794
|
+
inst.setMessages(opts.hydrateMessages);
|
|
5795
|
+
if (opts.hydrateActiveLeafId)
|
|
5796
|
+
inst.switchBranch(opts.hydrateActiveLeafId);
|
|
5797
|
+
}
|
|
5798
|
+
if (activeInstanceKeyRef.current === targetKey) return;
|
|
5799
|
+
activeInstanceKeyRef.current = targetKey;
|
|
5800
|
+
chatRef.current = inst;
|
|
5801
|
+
if (targetKey === SINGLE_INSTANCE_KEY || targetKey.startsWith("__pending_")) {
|
|
5802
|
+
setActualThreadId(void 0);
|
|
5803
|
+
} else {
|
|
5804
|
+
setActualThreadId(targetKey);
|
|
5805
|
+
}
|
|
5806
|
+
setSessionStatus(inst.getSessionStatus());
|
|
5807
|
+
setToolExecutions(inst.toolExecutions);
|
|
5808
|
+
setAgentIteration(inst.iteration);
|
|
5809
|
+
notifyStateChange();
|
|
5810
|
+
debugLog("Active instance switched", { key: targetKey });
|
|
5811
|
+
},
|
|
5812
|
+
[concurrentThreads, createInstance, debugLog, notifyStateChange]
|
|
5813
|
+
);
|
|
5526
5814
|
React2.useEffect(() => {
|
|
5527
|
-
if (
|
|
5528
|
-
|
|
5529
|
-
|
|
5815
|
+
if (systemPrompt === void 0) return;
|
|
5816
|
+
for (const inst of instancesRef.current.values()) {
|
|
5817
|
+
inst.setSystemPrompt(systemPrompt);
|
|
5530
5818
|
}
|
|
5819
|
+
debugLog("System prompt updated from prop");
|
|
5531
5820
|
}, [systemPrompt, debugLog]);
|
|
5532
5821
|
React2.useEffect(() => {
|
|
5533
|
-
if (
|
|
5534
|
-
|
|
5535
|
-
|
|
5822
|
+
if (headers === void 0) return;
|
|
5823
|
+
for (const inst of instancesRef.current.values()) {
|
|
5824
|
+
inst.setHeaders(headers);
|
|
5536
5825
|
}
|
|
5826
|
+
debugLog("Headers config updated from prop");
|
|
5537
5827
|
}, [headers, debugLog]);
|
|
5538
5828
|
React2.useEffect(() => {
|
|
5539
|
-
if (
|
|
5540
|
-
|
|
5541
|
-
|
|
5829
|
+
if (body === void 0) return;
|
|
5830
|
+
for (const inst of instancesRef.current.values()) {
|
|
5831
|
+
inst.setBody(body);
|
|
5542
5832
|
}
|
|
5833
|
+
debugLog("Body config updated from prop");
|
|
5543
5834
|
}, [body, debugLog]);
|
|
5544
5835
|
React2.useEffect(() => {
|
|
5545
|
-
if (
|
|
5546
|
-
|
|
5547
|
-
|
|
5836
|
+
if (runtimeUrl === void 0) return;
|
|
5837
|
+
for (const inst of instancesRef.current.values()) {
|
|
5838
|
+
inst.setUrl(runtimeUrl);
|
|
5548
5839
|
}
|
|
5840
|
+
debugLog("URL config updated from prop");
|
|
5549
5841
|
}, [runtimeUrl, debugLog]);
|
|
5550
5842
|
React2.useEffect(() => {
|
|
5551
5843
|
const prev = lastControlledThreadIdRef.current;
|
|
@@ -5561,11 +5853,21 @@ function CopilotProvider(props) {
|
|
|
5561
5853
|
if (!isThreadIdControlled) {
|
|
5562
5854
|
return;
|
|
5563
5855
|
}
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5856
|
+
if (concurrentThreads) {
|
|
5857
|
+
switchActiveInstance(threadId ?? null);
|
|
5858
|
+
} else {
|
|
5859
|
+
chatRef.current?.setActiveThread(threadId ?? null);
|
|
5860
|
+
setActualThreadId(threadId);
|
|
5861
|
+
setSessionStatus(threadId ? "ready" : "idle");
|
|
5862
|
+
}
|
|
5567
5863
|
debugLog("Thread/session synced from prop", { threadId });
|
|
5568
|
-
}, [
|
|
5864
|
+
}, [
|
|
5865
|
+
debugLog,
|
|
5866
|
+
isThreadIdControlled,
|
|
5867
|
+
threadId,
|
|
5868
|
+
concurrentThreads,
|
|
5869
|
+
switchActiveInstance
|
|
5870
|
+
]);
|
|
5569
5871
|
const EMPTY_MESSAGES = React2.useRef([]);
|
|
5570
5872
|
const getMessagesSnapshot = React2.useCallback(() => chatRef.current.messages, []);
|
|
5571
5873
|
const getServerMessagesSnapshot = React2.useCallback(
|
|
@@ -5575,36 +5877,110 @@ function CopilotProvider(props) {
|
|
|
5575
5877
|
const getStatusSnapshot = React2.useCallback(() => chatRef.current.status, []);
|
|
5576
5878
|
const getErrorSnapshot = React2.useCallback(() => chatRef.current.error, []);
|
|
5577
5879
|
const messages = React2.useSyncExternalStore(
|
|
5578
|
-
|
|
5880
|
+
stableSubscribe,
|
|
5579
5881
|
getMessagesSnapshot,
|
|
5580
5882
|
getServerMessagesSnapshot
|
|
5581
5883
|
);
|
|
5582
5884
|
const status = React2.useSyncExternalStore(
|
|
5583
|
-
|
|
5885
|
+
stableSubscribe,
|
|
5584
5886
|
getStatusSnapshot,
|
|
5585
5887
|
() => "ready"
|
|
5586
5888
|
);
|
|
5587
5889
|
const errorFromChat = React2.useSyncExternalStore(
|
|
5588
|
-
|
|
5890
|
+
stableSubscribe,
|
|
5589
5891
|
getErrorSnapshot,
|
|
5590
5892
|
() => void 0
|
|
5591
5893
|
);
|
|
5592
5894
|
const error = errorFromChat ?? null;
|
|
5593
5895
|
const isLoading = status === "streaming" || status === "submitted";
|
|
5594
|
-
const setActiveThread = React2.useCallback(
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5896
|
+
const setActiveThread = React2.useCallback(
|
|
5897
|
+
(id, opts) => {
|
|
5898
|
+
if (concurrentThreads) {
|
|
5899
|
+
switchActiveInstance(id, opts);
|
|
5900
|
+
} else {
|
|
5901
|
+
chatRef.current?.setActiveThread(id);
|
|
5902
|
+
setActualThreadId(id ?? void 0);
|
|
5903
|
+
}
|
|
5904
|
+
},
|
|
5905
|
+
[concurrentThreads, switchActiveInstance]
|
|
5906
|
+
);
|
|
5907
|
+
const disposeThreadInstance = React2.useCallback(
|
|
5908
|
+
(id) => {
|
|
5909
|
+
if (!concurrentThreads) return;
|
|
5910
|
+
const inst = instancesRef.current.get(id);
|
|
5911
|
+
if (!inst) return;
|
|
5912
|
+
inst.dispose();
|
|
5913
|
+
instancesRef.current.delete(id);
|
|
5914
|
+
if (activeInstanceKeyRef.current === id) {
|
|
5915
|
+
switchActiveInstance(null);
|
|
5916
|
+
} else {
|
|
5917
|
+
recomputeBusyThreadIds();
|
|
5918
|
+
recomputePendingApprovalsByThread();
|
|
5919
|
+
}
|
|
5920
|
+
},
|
|
5921
|
+
[
|
|
5922
|
+
concurrentThreads,
|
|
5923
|
+
switchActiveInstance,
|
|
5924
|
+
recomputeBusyThreadIds,
|
|
5925
|
+
recomputePendingApprovalsByThread
|
|
5926
|
+
]
|
|
5927
|
+
);
|
|
5928
|
+
const assignLocalThreadId = React2.useCallback(
|
|
5929
|
+
(localId) => {
|
|
5930
|
+
if (!concurrentThreads) return;
|
|
5931
|
+
if (!localId) return;
|
|
5932
|
+
const currentKey = activeInstanceKeyRef.current;
|
|
5933
|
+
if (currentKey === localId) return;
|
|
5934
|
+
const currentInst = instancesRef.current.get(currentKey);
|
|
5935
|
+
if (!currentInst) return;
|
|
5936
|
+
const isInternalSlot = currentKey === SINGLE_INSTANCE_KEY || currentKey.startsWith("__pending_");
|
|
5937
|
+
if (!isInternalSlot) return;
|
|
5938
|
+
if (instancesRef.current.has(localId)) return;
|
|
5939
|
+
instancesRef.current.delete(currentKey);
|
|
5940
|
+
instancesRef.current.set(localId, currentInst);
|
|
5941
|
+
activeInstanceKeyRef.current = localId;
|
|
5942
|
+
if (currentInst === chatRef.current) {
|
|
5943
|
+
setActualThreadId(localId);
|
|
5944
|
+
callbacksRef.current.onThreadChange?.(localId);
|
|
5945
|
+
}
|
|
5946
|
+
recomputeBusyThreadIds();
|
|
5947
|
+
recomputePendingApprovalsByThread();
|
|
5948
|
+
debugLog("Assigned local thread id", { localId });
|
|
5949
|
+
},
|
|
5950
|
+
[
|
|
5951
|
+
concurrentThreads,
|
|
5952
|
+
debugLog,
|
|
5953
|
+
recomputeBusyThreadIds,
|
|
5954
|
+
recomputePendingApprovalsByThread
|
|
5955
|
+
]
|
|
5956
|
+
);
|
|
5598
5957
|
const renewSession = React2.useCallback(() => {
|
|
5599
5958
|
chatRef.current?.renewSession();
|
|
5600
5959
|
setActualThreadId(void 0);
|
|
5601
5960
|
setSessionStatus("idle");
|
|
5602
5961
|
}, []);
|
|
5603
5962
|
const registerTool = React2.useCallback((tool) => {
|
|
5604
|
-
|
|
5963
|
+
const existing = sharedToolsRef.current.get(tool.name);
|
|
5964
|
+
if (existing) {
|
|
5965
|
+
existing.tool = tool;
|
|
5966
|
+
existing.refCount++;
|
|
5967
|
+
} else {
|
|
5968
|
+
sharedToolsRef.current.set(tool.name, { tool, refCount: 1 });
|
|
5969
|
+
}
|
|
5970
|
+
for (const inst of instancesRef.current.values()) {
|
|
5971
|
+
inst.registerTool(tool);
|
|
5972
|
+
}
|
|
5605
5973
|
}, []);
|
|
5606
5974
|
const unregisterTool = React2.useCallback((name) => {
|
|
5607
|
-
|
|
5975
|
+
const entry = sharedToolsRef.current.get(name);
|
|
5976
|
+
if (!entry) return;
|
|
5977
|
+
entry.refCount = Math.max(0, entry.refCount - 1);
|
|
5978
|
+
for (const inst of instancesRef.current.values()) {
|
|
5979
|
+
inst.unregisterTool(name);
|
|
5980
|
+
}
|
|
5981
|
+
if (entry.refCount === 0) {
|
|
5982
|
+
sharedToolsRef.current.delete(name);
|
|
5983
|
+
}
|
|
5608
5984
|
}, []);
|
|
5609
5985
|
const approveToolExecution = React2.useCallback(
|
|
5610
5986
|
(id, extraData, permissionLevel) => {
|
|
@@ -5655,6 +6031,7 @@ function CopilotProvider(props) {
|
|
|
5655
6031
|
parentId
|
|
5656
6032
|
);
|
|
5657
6033
|
const contextString = printTree(contextTreeRef.current);
|
|
6034
|
+
sharedSystemContextRef.current = contextString;
|
|
5658
6035
|
chatRef.current?.setContext(contextString);
|
|
5659
6036
|
setContextChars(contextString.length);
|
|
5660
6037
|
debugLog("Context added:", id);
|
|
@@ -5666,6 +6043,7 @@ function CopilotProvider(props) {
|
|
|
5666
6043
|
(id) => {
|
|
5667
6044
|
contextTreeRef.current = removeNode(contextTreeRef.current, id);
|
|
5668
6045
|
const contextString = printTree(contextTreeRef.current);
|
|
6046
|
+
sharedSystemContextRef.current = contextString;
|
|
5669
6047
|
chatRef.current?.setContext(contextString);
|
|
5670
6048
|
setContextChars(contextString.length);
|
|
5671
6049
|
debugLog("Context removed:", id);
|
|
@@ -5674,14 +6052,19 @@ function CopilotProvider(props) {
|
|
|
5674
6052
|
);
|
|
5675
6053
|
const setSystemPrompt = React2.useCallback(
|
|
5676
6054
|
(prompt) => {
|
|
5677
|
-
|
|
6055
|
+
for (const inst of instancesRef.current.values()) {
|
|
6056
|
+
inst.setSystemPrompt(prompt);
|
|
6057
|
+
}
|
|
5678
6058
|
debugLog("System prompt updated via function");
|
|
5679
6059
|
},
|
|
5680
6060
|
[debugLog]
|
|
5681
6061
|
);
|
|
5682
6062
|
const setInlineSkills = React2.useCallback(
|
|
5683
6063
|
(skills2) => {
|
|
5684
|
-
|
|
6064
|
+
sharedSkillsRef.current = skills2;
|
|
6065
|
+
for (const inst of instancesRef.current.values()) {
|
|
6066
|
+
inst.setInlineSkills(skills2);
|
|
6067
|
+
}
|
|
5685
6068
|
debugLog("Inline skills updated", { count: skills2.length });
|
|
5686
6069
|
},
|
|
5687
6070
|
[debugLog]
|
|
@@ -5729,7 +6112,7 @@ function CopilotProvider(props) {
|
|
|
5729
6112
|
[]
|
|
5730
6113
|
);
|
|
5731
6114
|
const hasBranches = React2.useSyncExternalStore(
|
|
5732
|
-
|
|
6115
|
+
stableSubscribe,
|
|
5733
6116
|
getHasBranchesSnapshot,
|
|
5734
6117
|
() => false
|
|
5735
6118
|
);
|
|
@@ -5764,7 +6147,9 @@ function CopilotProvider(props) {
|
|
|
5764
6147
|
}, [error, onError]);
|
|
5765
6148
|
React2.useEffect(() => {
|
|
5766
6149
|
return () => {
|
|
5767
|
-
|
|
6150
|
+
for (const inst of instancesRef.current.values()) {
|
|
6151
|
+
inst.dispose();
|
|
6152
|
+
}
|
|
5768
6153
|
};
|
|
5769
6154
|
}, []);
|
|
5770
6155
|
const contextValue = React2.useMemo(
|
|
@@ -5818,7 +6203,13 @@ function CopilotProvider(props) {
|
|
|
5818
6203
|
toolsConfig,
|
|
5819
6204
|
// Headless primitives
|
|
5820
6205
|
subscribeToStreamEvents,
|
|
5821
|
-
messageMeta: messageMetaStoreRef.current
|
|
6206
|
+
messageMeta: messageMetaStoreRef.current,
|
|
6207
|
+
// Multi-thread streaming
|
|
6208
|
+
concurrentThreads,
|
|
6209
|
+
busyThreadIds,
|
|
6210
|
+
pendingApprovalsByThread,
|
|
6211
|
+
disposeThreadInstance,
|
|
6212
|
+
assignLocalThreadId
|
|
5822
6213
|
}),
|
|
5823
6214
|
[
|
|
5824
6215
|
messages,
|
|
@@ -5858,7 +6249,12 @@ function CopilotProvider(props) {
|
|
|
5858
6249
|
renewSession,
|
|
5859
6250
|
sessionStatus,
|
|
5860
6251
|
runtimeUrl,
|
|
5861
|
-
toolsConfig
|
|
6252
|
+
toolsConfig,
|
|
6253
|
+
concurrentThreads,
|
|
6254
|
+
busyThreadIds,
|
|
6255
|
+
pendingApprovalsByThread,
|
|
6256
|
+
disposeThreadInstance,
|
|
6257
|
+
assignLocalThreadId
|
|
5862
6258
|
]
|
|
5863
6259
|
);
|
|
5864
6260
|
const messageHistoryContextValue = React2__default.default.useMemo(
|
|
@@ -5988,5 +6384,5 @@ exports.useMessageHistoryContext = useMessageHistoryContext;
|
|
|
5988
6384
|
exports.useSkillContext = useSkillContext;
|
|
5989
6385
|
exports.useTool = useTool;
|
|
5990
6386
|
exports.useTools = useTools;
|
|
5991
|
-
//# sourceMappingURL=chunk-
|
|
5992
|
-
//# sourceMappingURL=chunk-
|
|
6387
|
+
//# sourceMappingURL=chunk-GW5ZZHJ7.cjs.map
|
|
6388
|
+
//# sourceMappingURL=chunk-GW5ZZHJ7.cjs.map
|