Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
15 changes: 15 additions & 0 deletions packages/coding-agent/src/core/agent-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,9 @@ export class AgentSession {
// Base system prompt (without extension appends) - used to apply fresh appends each turn
private _baseSystemPrompt = "";
private _baseSystemPromptOptions!: BuildSystemPromptOptions;
// Exact prompt last sent to the model. Distinct from state.systemPrompt, which is rebuilt
// early by tool/resource/refine changes before any request.
private _lastSentSystemPrompt: string | undefined;

constructor(config: AgentSessionConfig) {
this.agent = config.agent;
Expand Down Expand Up @@ -1870,6 +1873,17 @@ export class AgentSession {
return this.agent.state.systemPrompt;
}

/**
* Returns the exact prompt last sent to the model. Before the first turn, falls back to a
* freshly built base prompt (what would be sent next, before any per-turn extension changes).
*/
getSystemPromptForDisplay(): { prompt: string; sent: boolean } {
if (this._lastSentSystemPrompt !== undefined) {
return { prompt: this._lastSentSystemPrompt, sent: true };
}
return { prompt: this._rebuildSystemPrompt(this.getActiveToolNames()), sent: false };
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
}

/** Current retry attempt (0 if not retrying) */
get retryAttempt(): number {
return this._retryAttempt;
Expand Down Expand Up @@ -2197,6 +2211,7 @@ export class AgentSession {
// Ensure we're using the base prompt (in case previous turn had modifications)
this.agent.state.systemPrompt = this._baseSystemPrompt;
}
this._lastSentSystemPrompt = this.agent.state.systemPrompt;
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
} catch (error) {
preflightResult?.(false);
throw error;
Expand Down
1 change: 1 addition & 0 deletions packages/coding-agent/src/core/slash-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const CANONICAL_BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
{ name: "copy", description: "Copy last agent message to clipboard" },
{ name: "name", description: "Set session display name" },
{ name: "session", description: "Show session info" },
{ name: "system-prompt", description: "Show the exact system prompt sent to the model" },
{ name: "logs", description: "Show where daemon and client logs are saved" },
{
name: "traces",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,14 @@ export class DaemonAgentConnection implements AgentConnection {
return data.text ?? undefined;
}

async getSystemPrompt(): Promise<{ prompt: string; sent: boolean }> {
const data = await this.requestData<{ prompt: string; sent: boolean }>({
type: "get_system_prompt",
activeSessionId: this.activeSessionId,
});
return { prompt: data.prompt, sent: data.sent };
}

async getToolDefinition(name: string): Promise<AgentConnectionToolDefinition | undefined> {
const data = await this.requestData<{ toolDefinition?: AgentConnectionToolDefinition }>({
type: "get_tool_definition",
Expand Down Expand Up @@ -832,6 +840,7 @@ function invalidatesCachedSnapshot(commandType: DaemonCommandBody["type"]): bool
case "get_session_tree":
case "get_user_messages_for_forking":
case "get_last_assistant_text":
case "get_system_prompt":
case "get_tool_definition":
case "export_html":
case "export_jsonl":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ export class DeferredAgentConnection implements AgentConnection {
return this.real ? this.real.getLastAssistantText() : undefined;
}

async getSystemPrompt(): Promise<{ prompt: string; sent: boolean }> {
return this.real ? this.real.getSystemPrompt() : { prompt: "", sent: false };
}

async getToolDefinition(name: string): Promise<AgentConnectionToolDefinition | undefined> {
return this.real ? this.real.getToolDefinition(name) : undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ export class InProcessAgentConnection implements AgentConnection {
return this.session.getLastAssistantText();
}

async getSystemPrompt(): Promise<{ prompt: string; sent: boolean }> {
return this.session.getSystemPromptForDisplay();
}

async getToolDefinition(name: string): Promise<AgentConnectionToolDefinition | undefined> {
return createAgentConnectionToolDefinition(this.session.getToolDefinition(name));
}
Expand Down
5 changes: 5 additions & 0 deletions packages/coding-agent/src/modes/agent-connection/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,11 @@ export interface AgentConnection {
updateHeartbeat(action: AgentHeartbeatUpdateAction): Promise<AgentCronJob | undefined>;
getUserMessagesForForking(): Promise<AgentConnectionUserMessage[]>;
getLastAssistantText(): Promise<string | undefined>;
/**
* The system prompt for display. `prompt` is the exact string last sent to the model;
* if no turn has run yet, `sent` is false and `prompt` is the freshly built base prompt.
*/
getSystemPrompt(): Promise<{ prompt: string; sent: boolean }>;
getToolDefinition(name: string): Promise<AgentConnectionToolDefinition | undefined>;
setSessionEntryLabel(entryId: string, label: string | undefined): Promise<void>;
respondToExtensionUiRequest(requestId: string, response: AgentConnectionExtensionUiResponse): Promise<void>;
Expand Down
6 changes: 6 additions & 0 deletions packages/coding-agent/src/modes/daemon/daemon-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ const DAEMON_COMMAND_TYPES: ReadonlySet<string> = new Set([
"get_session_tree",
"get_user_messages_for_forking",
"get_last_assistant_text",
"get_system_prompt",
"get_tool_definition",
"set_session_entry_label",
"extension_ui_response",
Expand Down Expand Up @@ -1379,6 +1380,11 @@ export class AgentDaemon {
});
}

case "get_system_prompt": {
const state = this.getSessionState(command.activeSessionId);
return success(command.id, "get_system_prompt", state.runtime.session.getSystemPromptForDisplay());
}

case "get_tool_definition": {
const state = this.getSessionState(command.activeSessionId);
return success(command.id, "get_tool_definition", {
Expand Down
1 change: 1 addition & 0 deletions packages/coding-agent/src/modes/daemon/daemon-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ export type DaemonCommand =
| { id?: string; type: "get_session_tree"; activeSessionId: string }
| { id?: string; type: "get_user_messages_for_forking"; activeSessionId: string }
| { id?: string; type: "get_last_assistant_text"; activeSessionId: string }
| { id?: string; type: "get_system_prompt"; activeSessionId: string }
| { id?: string; type: "get_tool_definition"; activeSessionId: string; name: string }
| { id?: string; type: "set_session_entry_label"; activeSessionId: string; entryId: string; label?: string }
| {
Expand Down
17 changes: 17 additions & 0 deletions packages/coding-agent/src/modes/interactive/interactive-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3334,6 +3334,11 @@ export class InteractiveMode {
this.editor.setText("");
return;
}
if (commandName === "system-prompt" && !commandArgs) {
await this.handleSystemPromptCommand();
this.editor.setText("");
return;
}
if (commandName === "traces") {
await this.handleTracesCommand(canonicalCommandText);
this.editor.setText("");
Expand Down Expand Up @@ -6715,6 +6720,18 @@ export class InteractiveMode {
this.ui.requestRender();
}

private async handleSystemPromptCommand(): Promise<void> {
const { prompt, sent } = await this.agentConnection.getSystemPrompt();
const status = sent ? "exact, last sent" : "next turn, not yet sent";
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
const header = `${theme.bold("System Prompt")} ${theme.fg("dim", `(${prompt.length} chars, ${status})`)}`;

this.chatContainer.addChild(new Spacer(1));
this.chatContainer.addChild(new Text(header, 1, 0));
this.chatContainer.addChild(new Spacer(1));
this.chatContainer.addChild(new Text(prompt, 1, 0));
this.ui.requestRender();
}

private formatTraceUploadResult(result: AgentTraceUploadResult): string {
switch (result.status) {
case "uploaded":
Expand Down
Loading