fix(agent): simplify state API and update consumers fixes #2633

This commit is contained in:
Mario Zechner
2026-03-30 12:43:34 +02:00
parent 5e3852fc9c
commit cbe1a8b732
24 changed files with 829 additions and 1198 deletions

View File

@@ -358,7 +358,7 @@ export class AgentSession {
* happens here instead of in wrappers.
*/
private _installAgentToolHooks(): void {
this.agent.setBeforeToolCall(async ({ toolCall, args }) => {
this.agent.beforeToolCall = async ({ toolCall, args }) => {
const runner = this._extensionRunner;
if (!runner?.hasHandlers("tool_call")) {
return undefined;
@@ -379,9 +379,9 @@ export class AgentSession {
}
throw new Error(`Extension failed, blocking execution: ${String(err)}`);
}
});
};
this.agent.setAfterToolCall(async ({ toolCall, args, result, isError }) => {
this.agent.afterToolCall = async ({ toolCall, args, result, isError }) => {
const runner = this._extensionRunner;
if (!runner?.hasHandlers("tool_result")) {
return undefined;
@@ -405,7 +405,7 @@ export class AgentSession {
content: hookResult.content,
details: hookResult.details,
};
});
};
}
// =========================================================================
@@ -790,11 +790,11 @@ export class AgentSession {
validToolNames.push(name);
}
}
this.agent.setTools(tools);
this.agent.state.tools = tools;
// Rebuild base system prompt with new tool set
this._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);
this.agent.setSystemPrompt(this._baseSystemPrompt);
this.agent.state.systemPrompt = this._baseSystemPrompt;
}
/** Whether compaction or branch summarization is currently running */
@@ -813,12 +813,12 @@ export class AgentSession {
/** Current steering mode */
get steeringMode(): "all" | "one-at-a-time" {
return this.agent.getSteeringMode();
return this.agent.steeringMode;
}
/** Current follow-up mode */
get followUpMode(): "all" | "one-at-a-time" {
return this.agent.getFollowUpMode();
return this.agent.followUpMode;
}
/** Current session file path, or undefined if sessions are disabled */
@@ -1051,10 +1051,10 @@ export class AgentSession {
}
// Apply extension-modified system prompt, or reset to base
if (result?.systemPrompt) {
this.agent.setSystemPrompt(result.systemPrompt);
this.agent.state.systemPrompt = result.systemPrompt;
} else {
// Ensure we're using the base prompt (in case previous turn had modifications)
this.agent.setSystemPrompt(this._baseSystemPrompt);
this.agent.state.systemPrompt = this._baseSystemPrompt;
}
}
@@ -1251,7 +1251,7 @@ export class AgentSession {
} else if (options?.triggerTurn) {
await this.agent.prompt(appMessage);
} else {
this.agent.appendMessage(appMessage);
this.agent.state.messages.push(appMessage);
this.sessionManager.appendCustomMessageEntry(
message.customType,
message.content,
@@ -1388,7 +1388,7 @@ export class AgentSession {
await options.setup(this.sessionManager);
// Sync agent state with session manager after setup
const sessionContext = this.sessionManager.buildSessionContext();
this.agent.replaceMessages(sessionContext.messages);
this.agent.state.messages = sessionContext.messages;
}
this._reconnectToAgent();
@@ -1437,7 +1437,7 @@ export class AgentSession {
const previousModel = this.model;
const thinkingLevel = this._getThinkingLevelForModelSwitch();
this.agent.setModel(model);
this.agent.state.model = model;
this.sessionManager.appendModelChange(model.provider, model.id);
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
@@ -1478,7 +1478,7 @@ export class AgentSession {
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
// Apply model
this.agent.setModel(next.model);
this.agent.state.model = next.model;
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
@@ -1506,7 +1506,7 @@ export class AgentSession {
const nextModel = availableModels[nextIndex];
const thinkingLevel = this._getThinkingLevelForModelSwitch();
this.agent.setModel(nextModel);
this.agent.state.model = nextModel;
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
@@ -1534,7 +1534,7 @@ export class AgentSession {
// Only persist if actually changing
const isChanging = effectiveLevel !== this.agent.state.thinkingLevel;
this.agent.setThinkingLevel(effectiveLevel);
this.agent.state.thinkingLevel = effectiveLevel;
if (isChanging) {
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
@@ -1620,7 +1620,7 @@ export class AgentSession {
* Saves to settings.
*/
setSteeringMode(mode: "all" | "one-at-a-time"): void {
this.agent.setSteeringMode(mode);
this.agent.steeringMode = mode;
this.settingsManager.setSteeringMode(mode);
}
@@ -1629,7 +1629,7 @@ export class AgentSession {
* Saves to settings.
*/
setFollowUpMode(mode: "all" | "one-at-a-time"): void {
this.agent.setFollowUpMode(mode);
this.agent.followUpMode = mode;
this.settingsManager.setFollowUpMode(mode);
}
@@ -1724,7 +1724,7 @@ export class AgentSession {
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
const newEntries = this.sessionManager.getEntries();
const sessionContext = this.sessionManager.buildSessionContext();
this.agent.replaceMessages(sessionContext.messages);
this.agent.state.messages = sessionContext.messages;
// Get the saved compaction entry for the extension event
const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary) as
@@ -1843,7 +1843,7 @@ export class AgentSession {
// but we don't want it in context for the retry)
const messages = this.agent.state.messages;
if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
this.agent.replaceMessages(messages.slice(0, -1));
this.agent.state.messages = messages.slice(0, -1);
}
await this._runAutoCompaction("overflow", true);
return;
@@ -1995,7 +1995,7 @@ export class AgentSession {
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
const newEntries = this.sessionManager.getEntries();
const sessionContext = this.sessionManager.buildSessionContext();
this.agent.replaceMessages(sessionContext.messages);
this.agent.state.messages = sessionContext.messages;
// Get the saved compaction entry for the extension event
const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary) as
@@ -2022,7 +2022,7 @@ export class AgentSession {
const messages = this.agent.state.messages;
const lastMsg = messages[messages.length - 1];
if (lastMsg?.role === "assistant" && (lastMsg as AssistantMessage).stopReason === "error") {
this.agent.replaceMessages(messages.slice(0, -1));
this.agent.state.messages = messages.slice(0, -1);
}
setTimeout(() => {
@@ -2108,7 +2108,7 @@ export class AgentSession {
this._resourceLoader.extendResources(extensionPaths);
this._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());
this.agent.setSystemPrompt(this._baseSystemPrompt);
this.agent.state.systemPrompt = this._baseSystemPrompt;
}
private buildExtensionResourcePaths(entries: Array<{ path: string; extensionPath: string }>): Array<{
@@ -2160,7 +2160,7 @@ export class AgentSession {
return;
}
this.agent.setModel(refreshedModel);
this.agent.state.model = refreshedModel;
}
private _bindExtensionCore(runner: ExtensionRunner): void {
@@ -2500,7 +2500,7 @@ export class AgentSession {
// Remove error message from agent state (keep in session for history)
const messages = this.agent.state.messages;
if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
this.agent.replaceMessages(messages.slice(0, -1));
this.agent.state.messages = messages.slice(0, -1);
}
// Wait with exponential backoff (abortable)
@@ -2633,7 +2633,7 @@ export class AgentSession {
this._pendingBashMessages.push(bashMessage);
} else {
// Add to agent state immediately
this.agent.appendMessage(bashMessage);
this.agent.state.messages.push(bashMessage);
// Save to session
this.sessionManager.appendMessage(bashMessage);
@@ -2666,7 +2666,7 @@ export class AgentSession {
for (const bashMessage of this._pendingBashMessages) {
// Add to agent state
this.agent.appendMessage(bashMessage);
this.agent.state.messages.push(bashMessage);
// Save to session
this.sessionManager.appendMessage(bashMessage);
@@ -2725,7 +2725,7 @@ export class AgentSession {
// Emit session event to custom tools
this.agent.replaceMessages(sessionContext.messages);
this.agent.state.messages = sessionContext.messages;
// Restore model if saved
if (sessionContext.model) {
@@ -2735,7 +2735,7 @@ export class AgentSession {
(m) => m.provider === sessionContext.model!.provider && m.id === sessionContext.model!.modelId,
);
if (match) {
this.agent.setModel(match);
this.agent.state.model = match;
await this._emitModelSelect(match, previousModel, "restore");
}
}
@@ -2751,7 +2751,7 @@ export class AgentSession {
const effectiveLevel = availableLevels.includes(defaultThinkingLevel)
? defaultThinkingLevel
: this._clampThinkingLevel(defaultThinkingLevel, availableLevels);
this.agent.setThinkingLevel(effectiveLevel);
this.agent.state.thinkingLevel = effectiveLevel;
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
}
@@ -2824,7 +2824,7 @@ export class AgentSession {
// Emit session event to custom tools (with reason "fork")
if (!skipConversationRestore) {
this.agent.replaceMessages(sessionContext.messages);
this.agent.state.messages = sessionContext.messages;
}
return { selectedText, cancelled: false };
@@ -3006,7 +3006,7 @@ export class AgentSession {
// Update agent state
const sessionContext = this.sessionManager.buildSessionContext();
this.agent.replaceMessages(sessionContext.messages);
this.agent.state.messages = sessionContext.messages;
// Emit session_tree event
if (this._extensionRunner) {

View File

@@ -326,7 +326,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
// Restore messages if session has existing data
if (hasExistingSession) {
agent.replaceMessages(existingSession.messages);
agent.state.messages = existingSession.messages;
if (!hasThinkingEntry) {
sessionManager.appendThinkingLevelChange(thinkingLevel);
}

View File

@@ -3319,7 +3319,7 @@ export class InteractiveMode {
},
onTransportChange: (transport) => {
this.settingsManager.setTransport(transport);
this.session.agent.setTransport(transport);
this.session.agent.transport = transport;
},
onThinkingLevelChange: (level) => {
this.session.setThinkingLevel(level);