Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,20 @@ export class AgentManager {
return this._tokenUsageChanged;
}

/**
* Signal emitted when the agent's busy state changes.
*/
get busyChanged(): ISignal<this, boolean> {
return this._busyChanged;
}

/**
* Whether the agent is currently generating a response or executing tools
*/
get busy(): boolean {
return this._busy;
}

/**
* Refresh the skills snapshot and rebuild the agent if resources are ready.
*/
Expand Down Expand Up @@ -592,6 +606,7 @@ export class AgentManager {
* @param message The user message to respond to (may include processed attachment content)
*/
async generateResponse(message: string): Promise<void> {
this._setBusy(true);
this._controller = new AbortController();

try {
Expand Down Expand Up @@ -659,6 +674,7 @@ export class AgentManager {
}
} finally {
this._controller = null;
this._setBusy(false);
}
}

Expand Down Expand Up @@ -1191,6 +1207,16 @@ WEB RETRIEVAL POLICY:
return `Supported MIME types in this session: ${safeMimeTypes.join(', ')}`;
}

/**
* Set busy state and emit signal
*/
private _setBusy(busy: boolean): void {
if (this._busy !== busy) {
this._busy = busy;
this._busyChanged.emit(busy);
}
}

// Private attributes
private _settingsModel: AISettingsModel;
private _toolRegistry?: IToolRegistry;
Expand All @@ -1201,6 +1227,8 @@ WEB RETRIEVAL POLICY:
private _agent: ToolLoopAgent<never, ToolMap> | null;
private _history: ModelMessage[];
private _mcpTools: ToolMap;
private _busy: boolean = false;
private _busyChanged = new Signal<this, boolean>(this);
private _controller: AbortController | null;
private _agentEvent: Signal<this, IAgentEvent>;
private _tokenUsage: ITokenUsage;
Expand Down
17 changes: 16 additions & 1 deletion src/chat-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,21 @@ export class AIChatModel extends AbstractChatModel {
this._agentManager = options.agentManager;
this._trans = options.trans;

// Listen for agent events
// Listen for agent events and busy state
this._agentManager.agentEvent.connect(this._onAgentEvent, this);

// Listen for settings changes to update chat behavior
this._settingsModel.stateChanged.connect(this._onSettingsChanged, this);

// Prevent clearing input field when user sends a message while agent is busy
const originalSend = this.input.send;
this.input.send = (content: string) => {
if (this._agentManager.busy) {
return;
}
originalSend(content);
};

this.setReady();
}

Expand Down Expand Up @@ -214,6 +224,11 @@ export class AIChatModel extends AbstractChatModel {
return;
}

// Prevent sending multiple messages concurrently
if (this._agentManager.busy) {
return;
}

// Add user message to chat
const userMessage: IMessageContent = {
body: message.body,
Expand Down