@dreb/coding-agent 2.34.2 → 2.35.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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +3 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +30 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +172 -130
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/buddy/buddy-controller.d.ts +35 -1
- package/dist/core/buddy/buddy-controller.d.ts.map +1 -1
- package/dist/core/buddy/buddy-controller.js +65 -4
- package/dist/core/buddy/buddy-controller.js.map +1 -1
- package/dist/core/buddy/buddy-manager.d.ts +6 -0
- package/dist/core/buddy/buddy-manager.d.ts.map +1 -1
- package/dist/core/buddy/buddy-manager.js +25 -2
- package/dist/core/buddy/buddy-manager.js.map +1 -1
- package/dist/core/export-html/template.js +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +5 -102
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/git-branch.d.ts +19 -0
- package/dist/core/git-branch.d.ts.map +1 -0
- package/dist/core/git-branch.js +109 -0
- package/dist/core/git-branch.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +21 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +117 -42
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/{modes/interactive → core}/tab-title.d.ts +12 -3
- package/dist/core/tab-title.d.ts.map +1 -0
- package/dist/{modes/interactive → core}/tab-title.js +58 -16
- package/dist/core/tab-title.js.map +1 -0
- package/dist/core/tools/search.d.ts.map +1 -1
- package/dist/core/tools/search.js +4 -1
- package/dist/core/tools/search.js.map +1 -1
- package/dist/core/tools/subagent.d.ts +63 -2
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +459 -73
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/tools/web.d.ts +1 -1
- package/dist/core/tools/web.d.ts.map +1 -1
- package/dist/core/tools/web.js +60 -16
- package/dist/core/tools/web.js.map +1 -1
- package/dist/main.d.ts +10 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +54 -4
- package/dist/main.js.map +1 -1
- package/dist/modes/index.d.ts +2 -2
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +4 -40
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +20 -3
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/index.d.ts +2 -2
- package/dist/modes/rpc/index.d.ts.map +1 -1
- package/dist/modes/rpc/index.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +114 -6
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +140 -2
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +97 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +656 -27
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +312 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/buddy.md +9 -1
- package/docs/dashboard.md +152 -0
- package/docs/development.md +8 -5
- package/docs/rpc.md +652 -5
- package/examples/sdk/12-full-control.ts +1 -1
- package/package.json +1 -1
- package/dist/modes/interactive/tab-title.d.ts.map +0 -1
- package/dist/modes/interactive/tab-title.js.map +0 -1
|
@@ -581,6 +581,7 @@ export class AgentSession {
|
|
|
581
581
|
agentId,
|
|
582
582
|
agentType: result.agent,
|
|
583
583
|
success: result.exitCode === 0,
|
|
584
|
+
sessionFile: result.sessionFile,
|
|
584
585
|
});
|
|
585
586
|
}
|
|
586
587
|
catch (emitErr) {
|
|
@@ -716,13 +717,13 @@ export class AgentSession {
|
|
|
716
717
|
const messageText = this._getUserMessageText(event.message);
|
|
717
718
|
if (messageText) {
|
|
718
719
|
// Check steering queue first
|
|
719
|
-
const steeringIndex = this._steeringMessages.
|
|
720
|
+
const steeringIndex = this._steeringMessages.findIndex((message) => message.text === messageText);
|
|
720
721
|
if (steeringIndex !== -1) {
|
|
721
722
|
this._steeringMessages.splice(steeringIndex, 1);
|
|
722
723
|
}
|
|
723
724
|
else {
|
|
724
725
|
// Check follow-up queue
|
|
725
|
-
const followUpIndex = this._followUpMessages.
|
|
726
|
+
const followUpIndex = this._followUpMessages.findIndex((message) => message.text === messageText);
|
|
726
727
|
if (followUpIndex !== -1) {
|
|
727
728
|
this._followUpMessages.splice(followUpIndex, 1);
|
|
728
729
|
}
|
|
@@ -1389,7 +1390,7 @@ export class AgentSession {
|
|
|
1389
1390
|
* Internal: Queue a steering message (already expanded, no extension command check).
|
|
1390
1391
|
*/
|
|
1391
1392
|
async _queueSteer(text, images) {
|
|
1392
|
-
this._steeringMessages.push(text);
|
|
1393
|
+
this._steeringMessages.push({ text, images: images ? [...images] : undefined });
|
|
1393
1394
|
const content = [{ type: "text", text }];
|
|
1394
1395
|
if (images) {
|
|
1395
1396
|
content.push(...images);
|
|
@@ -1404,7 +1405,7 @@ export class AgentSession {
|
|
|
1404
1405
|
* Internal: Queue a follow-up message (already expanded, no extension command check).
|
|
1405
1406
|
*/
|
|
1406
1407
|
async _queueFollowUp(text, images) {
|
|
1407
|
-
this._followUpMessages.push(text);
|
|
1408
|
+
this._followUpMessages.push({ text, images: images ? [...images] : undefined });
|
|
1408
1409
|
const content = [{ type: "text", text }];
|
|
1409
1410
|
if (images) {
|
|
1410
1411
|
content.push(...images);
|
|
@@ -1513,23 +1514,39 @@ export class AgentSession {
|
|
|
1513
1514
|
* @returns Object with steering and followUp arrays
|
|
1514
1515
|
*/
|
|
1515
1516
|
clearQueue() {
|
|
1516
|
-
const
|
|
1517
|
-
|
|
1517
|
+
const steeringMessages = this._steeringMessages.map((message) => ({
|
|
1518
|
+
text: message.text,
|
|
1519
|
+
images: message.images ? [...message.images] : undefined,
|
|
1520
|
+
}));
|
|
1521
|
+
const followUpMessages = this._followUpMessages.map((message) => ({
|
|
1522
|
+
text: message.text,
|
|
1523
|
+
images: message.images ? [...message.images] : undefined,
|
|
1524
|
+
}));
|
|
1525
|
+
const steering = steeringMessages.map((message) => message.text);
|
|
1526
|
+
const followUp = followUpMessages.map((message) => message.text);
|
|
1518
1527
|
this._steeringMessages = [];
|
|
1519
1528
|
this._followUpMessages = [];
|
|
1520
1529
|
this.agent.clearAllQueues();
|
|
1521
|
-
return { steering, followUp };
|
|
1530
|
+
return { steering, followUp, steeringMessages, followUpMessages };
|
|
1522
1531
|
}
|
|
1523
1532
|
/** Number of pending messages (includes both steering and follow-up) */
|
|
1524
1533
|
get pendingMessageCount() {
|
|
1525
1534
|
return this._steeringMessages.length + this._followUpMessages.length;
|
|
1526
1535
|
}
|
|
1527
|
-
/** Get pending steering
|
|
1536
|
+
/** Get pending steering message text (read-only compatibility view). */
|
|
1528
1537
|
getSteeringMessages() {
|
|
1529
|
-
return this._steeringMessages;
|
|
1538
|
+
return this._steeringMessages.map((message) => message.text);
|
|
1530
1539
|
}
|
|
1531
|
-
/** Get pending follow-up
|
|
1540
|
+
/** Get pending follow-up message text (read-only compatibility view). */
|
|
1532
1541
|
getFollowUpMessages() {
|
|
1542
|
+
return this._followUpMessages.map((message) => message.text);
|
|
1543
|
+
}
|
|
1544
|
+
/** Get full pending steering payloads, including inline image attachments. */
|
|
1545
|
+
getSteeringMessagePayloads() {
|
|
1546
|
+
return this._steeringMessages;
|
|
1547
|
+
}
|
|
1548
|
+
/** Get full pending follow-up payloads, including inline image attachments. */
|
|
1549
|
+
getFollowUpMessagePayloads() {
|
|
1533
1550
|
return this._followUpMessages;
|
|
1534
1551
|
}
|
|
1535
1552
|
get resourceLoader() {
|
|
@@ -2274,7 +2291,7 @@ export class AgentSession {
|
|
|
2274
2291
|
this.sessionManager.appendCustomEntry(customType, data);
|
|
2275
2292
|
},
|
|
2276
2293
|
setSessionName: (name) => {
|
|
2277
|
-
this.
|
|
2294
|
+
this.setSessionName(name);
|
|
2278
2295
|
},
|
|
2279
2296
|
getSessionName: () => {
|
|
2280
2297
|
return this.sessionManager.getSessionName();
|
|
@@ -2446,12 +2463,15 @@ export class AgentSession {
|
|
|
2446
2463
|
parentSessionFile: () => this.sessionFile,
|
|
2447
2464
|
modelRegistry: this._modelRegistry,
|
|
2448
2465
|
getAgentModelsForAgent: (name) => this.settingsManager?.getAgentModelsForAgent(name),
|
|
2449
|
-
onBackgroundStart: (agentId, agentType, taskSummary) => {
|
|
2450
|
-
this._emit({ type: "background_agent_start", agentId, agentType, taskSummary });
|
|
2466
|
+
onBackgroundStart: (agentId, agentType, taskSummary, sessionDir) => {
|
|
2467
|
+
this._emit({ type: "background_agent_start", agentId, agentType, taskSummary, sessionDir });
|
|
2451
2468
|
},
|
|
2452
2469
|
onBackgroundComplete: (agentId, result, cancelled) => {
|
|
2453
2470
|
this._handleBackgroundComplete(agentId, result, cancelled);
|
|
2454
2471
|
},
|
|
2472
|
+
onBackgroundEvent: (agentId, event) => {
|
|
2473
|
+
this._emit({ type: "background_agent_event", agentId, event });
|
|
2474
|
+
},
|
|
2455
2475
|
},
|
|
2456
2476
|
});
|
|
2457
2477
|
this._baseToolDefinitions = new Map(Object.entries(baseToolDefinitions).map(([name, tool]) => [name, tool]));
|
|
@@ -2811,6 +2831,7 @@ export class AgentSession {
|
|
|
2811
2831
|
*/
|
|
2812
2832
|
setSessionName(name) {
|
|
2813
2833
|
this.sessionManager.appendSessionInfo(name);
|
|
2834
|
+
this._emit({ type: "session_name_changed", name: this.sessionName ?? "" });
|
|
2814
2835
|
}
|
|
2815
2836
|
/**
|
|
2816
2837
|
* Create a fork from a specific entry.
|
|
@@ -2879,6 +2900,16 @@ export class AgentSession {
|
|
|
2879
2900
|
* @returns Result with editorText (if user message) and cancelled status
|
|
2880
2901
|
*/
|
|
2881
2902
|
async navigateTree(targetId, options = {}) {
|
|
2903
|
+
// Navigating mid-stream would replace agent messages during an active run,
|
|
2904
|
+
// corrupting the conversation state. Fail loudly instead.
|
|
2905
|
+
if (this.isStreaming) {
|
|
2906
|
+
throw new Error("Cannot navigate the session tree while the agent is streaming. Abort or wait for idle first.");
|
|
2907
|
+
}
|
|
2908
|
+
// A second concurrent navigation (or a compaction) would clobber the shared branch-summary
|
|
2909
|
+
// abort controller and interleave tree mutations. Fail loudly instead.
|
|
2910
|
+
if (this.isCompacting) {
|
|
2911
|
+
throw new Error("Cannot navigate the session tree while summarization or compaction is in progress. Wait for idle first.");
|
|
2912
|
+
}
|
|
2882
2913
|
const oldLeafId = this.sessionManager.getLeafId();
|
|
2883
2914
|
// No-op if already at target
|
|
2884
2915
|
if (targetId === oldLeafId) {
|
|
@@ -2908,133 +2939,144 @@ export class AgentSession {
|
|
|
2908
2939
|
replaceInstructions,
|
|
2909
2940
|
label,
|
|
2910
2941
|
};
|
|
2911
|
-
// Set up abort controller for summarization
|
|
2942
|
+
// Set up abort controller for summarization. Cleared in the finally below on every
|
|
2943
|
+
// exit path (throws, cancel returns, summary abort, success) so isCompacting cannot
|
|
2944
|
+
// be left wedged true after an early exit.
|
|
2912
2945
|
this._branchSummaryAbortController = new AbortController();
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2946
|
+
try {
|
|
2947
|
+
let extensionSummary;
|
|
2948
|
+
let fromExtension = false;
|
|
2949
|
+
// Emit session_before_tree event
|
|
2950
|
+
if (this._extensionRunner?.hasHandlers("session_before_tree")) {
|
|
2951
|
+
const result = (await this._extensionRunner.emit({
|
|
2952
|
+
type: "session_before_tree",
|
|
2953
|
+
preparation,
|
|
2954
|
+
signal: this._branchSummaryAbortController.signal,
|
|
2955
|
+
}));
|
|
2956
|
+
if (result?.cancel) {
|
|
2957
|
+
return { cancelled: true };
|
|
2958
|
+
}
|
|
2959
|
+
if (result?.summary && options.summarize) {
|
|
2960
|
+
extensionSummary = result.summary;
|
|
2961
|
+
fromExtension = true;
|
|
2962
|
+
}
|
|
2963
|
+
// Allow extensions to override instructions and label
|
|
2964
|
+
if (result?.customInstructions !== undefined) {
|
|
2965
|
+
customInstructions = result.customInstructions;
|
|
2966
|
+
}
|
|
2967
|
+
if (result?.replaceInstructions !== undefined) {
|
|
2968
|
+
replaceInstructions = result.replaceInstructions;
|
|
2969
|
+
}
|
|
2970
|
+
if (result?.label !== undefined) {
|
|
2971
|
+
label = result.label;
|
|
2972
|
+
}
|
|
2928
2973
|
}
|
|
2929
|
-
//
|
|
2930
|
-
|
|
2931
|
-
|
|
2974
|
+
// Run default summarizer if needed
|
|
2975
|
+
let summaryText;
|
|
2976
|
+
let summaryDetails;
|
|
2977
|
+
if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
|
|
2978
|
+
const model = this.model;
|
|
2979
|
+
const apiKey = await this._modelRegistry.getApiKey(model);
|
|
2980
|
+
if (!apiKey) {
|
|
2981
|
+
throw new Error(`No API key for ${model.provider}`);
|
|
2982
|
+
}
|
|
2983
|
+
const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
|
|
2984
|
+
const result = await generateBranchSummary(entriesToSummarize, {
|
|
2985
|
+
model,
|
|
2986
|
+
apiKey,
|
|
2987
|
+
signal: this._branchSummaryAbortController.signal,
|
|
2988
|
+
customInstructions,
|
|
2989
|
+
replaceInstructions,
|
|
2990
|
+
reserveTokens: branchSummarySettings.reserveTokens,
|
|
2991
|
+
});
|
|
2992
|
+
if (result.aborted) {
|
|
2993
|
+
return { cancelled: true, aborted: true };
|
|
2994
|
+
}
|
|
2995
|
+
if (result.error) {
|
|
2996
|
+
throw new Error(result.error);
|
|
2997
|
+
}
|
|
2998
|
+
summaryText = result.summary;
|
|
2999
|
+
summaryDetails = {
|
|
3000
|
+
readFiles: result.readFiles || [],
|
|
3001
|
+
modifiedFiles: result.modifiedFiles || [],
|
|
3002
|
+
};
|
|
3003
|
+
}
|
|
3004
|
+
else if (extensionSummary) {
|
|
3005
|
+
summaryText = extensionSummary.summary;
|
|
3006
|
+
summaryDetails = extensionSummary.details;
|
|
3007
|
+
}
|
|
3008
|
+
// Re-check after extension/summarization awaits: prompt dispatch can start streaming
|
|
3009
|
+
// while we yielded (same race class guarded in the prompt path), and the mutation
|
|
3010
|
+
// block below must not replace messages during an active run.
|
|
3011
|
+
if (this.isStreaming) {
|
|
3012
|
+
throw new Error("Cannot navigate the session tree while the agent is streaming. Abort or wait for idle first.");
|
|
3013
|
+
}
|
|
3014
|
+
// Determine the new leaf position based on target type
|
|
3015
|
+
let newLeafId;
|
|
3016
|
+
let editorText;
|
|
3017
|
+
if (targetEntry.type === "message" && targetEntry.message.role === "user") {
|
|
3018
|
+
// User message: leaf = parent (null if root), text goes to editor
|
|
3019
|
+
newLeafId = targetEntry.parentId;
|
|
3020
|
+
editorText = this._extractUserMessageText(targetEntry.message.content);
|
|
3021
|
+
}
|
|
3022
|
+
else if (targetEntry.type === "custom_message") {
|
|
3023
|
+
// Custom message: leaf = parent (null if root), text goes to editor
|
|
3024
|
+
newLeafId = targetEntry.parentId;
|
|
3025
|
+
editorText =
|
|
3026
|
+
typeof targetEntry.content === "string"
|
|
3027
|
+
? targetEntry.content
|
|
3028
|
+
: targetEntry.content
|
|
3029
|
+
.filter((c) => c.type === "text")
|
|
3030
|
+
.map((c) => c.text)
|
|
3031
|
+
.join("");
|
|
2932
3032
|
}
|
|
2933
|
-
|
|
2934
|
-
|
|
3033
|
+
else {
|
|
3034
|
+
// Non-user message: leaf = selected node
|
|
3035
|
+
newLeafId = targetId;
|
|
3036
|
+
}
|
|
3037
|
+
// Switch leaf (with or without summary)
|
|
3038
|
+
// Summary is attached at the navigation target position (newLeafId), not the old branch
|
|
3039
|
+
let summaryEntry;
|
|
3040
|
+
if (summaryText) {
|
|
3041
|
+
// Create summary at target position (can be null for root)
|
|
3042
|
+
const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension);
|
|
3043
|
+
summaryEntry = this.sessionManager.getEntry(summaryId);
|
|
3044
|
+
// Attach label to the summary entry
|
|
3045
|
+
if (label) {
|
|
3046
|
+
this.sessionManager.appendLabelChange(summaryId, label);
|
|
3047
|
+
}
|
|
2935
3048
|
}
|
|
2936
|
-
if (
|
|
2937
|
-
|
|
3049
|
+
else if (newLeafId === null) {
|
|
3050
|
+
// No summary, navigating to root - reset leaf
|
|
3051
|
+
this.sessionManager.resetLeaf();
|
|
2938
3052
|
}
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
let summaryDetails;
|
|
2943
|
-
if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
|
|
2944
|
-
const model = this.model;
|
|
2945
|
-
const apiKey = await this._modelRegistry.getApiKey(model);
|
|
2946
|
-
if (!apiKey) {
|
|
2947
|
-
throw new Error(`No API key for ${model.provider}`);
|
|
2948
|
-
}
|
|
2949
|
-
const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
|
|
2950
|
-
const result = await generateBranchSummary(entriesToSummarize, {
|
|
2951
|
-
model,
|
|
2952
|
-
apiKey,
|
|
2953
|
-
signal: this._branchSummaryAbortController.signal,
|
|
2954
|
-
customInstructions,
|
|
2955
|
-
replaceInstructions,
|
|
2956
|
-
reserveTokens: branchSummarySettings.reserveTokens,
|
|
2957
|
-
});
|
|
2958
|
-
this._branchSummaryAbortController = undefined;
|
|
2959
|
-
if (result.aborted) {
|
|
2960
|
-
return { cancelled: true, aborted: true };
|
|
3053
|
+
else {
|
|
3054
|
+
// No summary, navigating to non-root
|
|
3055
|
+
this.sessionManager.branch(newLeafId);
|
|
2961
3056
|
}
|
|
2962
|
-
|
|
2963
|
-
|
|
3057
|
+
// Attach label to target entry when not summarizing (no summary entry to label)
|
|
3058
|
+
if (label && !summaryText) {
|
|
3059
|
+
this.sessionManager.appendLabelChange(targetId, label);
|
|
2964
3060
|
}
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
let editorText;
|
|
2978
|
-
if (targetEntry.type === "message" && targetEntry.message.role === "user") {
|
|
2979
|
-
// User message: leaf = parent (null if root), text goes to editor
|
|
2980
|
-
newLeafId = targetEntry.parentId;
|
|
2981
|
-
editorText = this._extractUserMessageText(targetEntry.message.content);
|
|
2982
|
-
}
|
|
2983
|
-
else if (targetEntry.type === "custom_message") {
|
|
2984
|
-
// Custom message: leaf = parent (null if root), text goes to editor
|
|
2985
|
-
newLeafId = targetEntry.parentId;
|
|
2986
|
-
editorText =
|
|
2987
|
-
typeof targetEntry.content === "string"
|
|
2988
|
-
? targetEntry.content
|
|
2989
|
-
: targetEntry.content
|
|
2990
|
-
.filter((c) => c.type === "text")
|
|
2991
|
-
.map((c) => c.text)
|
|
2992
|
-
.join("");
|
|
2993
|
-
}
|
|
2994
|
-
else {
|
|
2995
|
-
// Non-user message: leaf = selected node
|
|
2996
|
-
newLeafId = targetId;
|
|
2997
|
-
}
|
|
2998
|
-
// Switch leaf (with or without summary)
|
|
2999
|
-
// Summary is attached at the navigation target position (newLeafId), not the old branch
|
|
3000
|
-
let summaryEntry;
|
|
3001
|
-
if (summaryText) {
|
|
3002
|
-
// Create summary at target position (can be null for root)
|
|
3003
|
-
const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension);
|
|
3004
|
-
summaryEntry = this.sessionManager.getEntry(summaryId);
|
|
3005
|
-
// Attach label to the summary entry
|
|
3006
|
-
if (label) {
|
|
3007
|
-
this.sessionManager.appendLabelChange(summaryId, label);
|
|
3061
|
+
// Update agent state
|
|
3062
|
+
const sessionContext = this.sessionManager.buildSessionContext();
|
|
3063
|
+
this.agent.replaceMessages(sessionContext.messages);
|
|
3064
|
+
// Emit session_tree event
|
|
3065
|
+
if (this._extensionRunner) {
|
|
3066
|
+
await this._extensionRunner.emit({
|
|
3067
|
+
type: "session_tree",
|
|
3068
|
+
newLeafId: this.sessionManager.getLeafId(),
|
|
3069
|
+
oldLeafId,
|
|
3070
|
+
summaryEntry,
|
|
3071
|
+
fromExtension: summaryText ? fromExtension : undefined,
|
|
3072
|
+
});
|
|
3008
3073
|
}
|
|
3074
|
+
// Emit to custom tools
|
|
3075
|
+
return { editorText, cancelled: false, summaryEntry };
|
|
3009
3076
|
}
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
this.sessionManager.resetLeaf();
|
|
3013
|
-
}
|
|
3014
|
-
else {
|
|
3015
|
-
// No summary, navigating to non-root
|
|
3016
|
-
this.sessionManager.branch(newLeafId);
|
|
3017
|
-
}
|
|
3018
|
-
// Attach label to target entry when not summarizing (no summary entry to label)
|
|
3019
|
-
if (label && !summaryText) {
|
|
3020
|
-
this.sessionManager.appendLabelChange(targetId, label);
|
|
3021
|
-
}
|
|
3022
|
-
// Update agent state
|
|
3023
|
-
const sessionContext = this.sessionManager.buildSessionContext();
|
|
3024
|
-
this.agent.replaceMessages(sessionContext.messages);
|
|
3025
|
-
// Emit session_tree event
|
|
3026
|
-
if (this._extensionRunner) {
|
|
3027
|
-
await this._extensionRunner.emit({
|
|
3028
|
-
type: "session_tree",
|
|
3029
|
-
newLeafId: this.sessionManager.getLeafId(),
|
|
3030
|
-
oldLeafId,
|
|
3031
|
-
summaryEntry,
|
|
3032
|
-
fromExtension: summaryText ? fromExtension : undefined,
|
|
3033
|
-
});
|
|
3077
|
+
finally {
|
|
3078
|
+
this._branchSummaryAbortController = undefined;
|
|
3034
3079
|
}
|
|
3035
|
-
// Emit to custom tools
|
|
3036
|
-
this._branchSummaryAbortController = undefined;
|
|
3037
|
-
return { editorText, cancelled: false, summaryEntry };
|
|
3038
3080
|
}
|
|
3039
3081
|
/**
|
|
3040
3082
|
* Get all user messages from session for fork selector.
|