mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-19 08:01:19 +00:00
feat(coding-agent): add set_session_name RPC command (#1075)
- Add set_session_name command with empty name validation - Expose sessionName in get_state response - Add setSessionName() to AgentSession and RpcClient - Document in docs/rpc.md
This commit is contained in:
parent
cb08758696
commit
e20583aac8
6 changed files with 86 additions and 1 deletions
|
|
@ -154,6 +154,7 @@ Response:
|
||||||
"followUpMode": "one-at-a-time",
|
"followUpMode": "one-at-a-time",
|
||||||
"sessionFile": "/path/to/session.jsonl",
|
"sessionFile": "/path/to/session.jsonl",
|
||||||
"sessionId": "abc123",
|
"sessionId": "abc123",
|
||||||
|
"sessionName": "my-feature-work",
|
||||||
"autoCompactionEnabled": true,
|
"autoCompactionEnabled": true,
|
||||||
"messageCount": 5,
|
"messageCount": 5,
|
||||||
"pendingMessageCount": 0
|
"pendingMessageCount": 0
|
||||||
|
|
@ -161,7 +162,7 @@ Response:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `model` field is a full [Model](#model) object or `null`.
|
The `model` field is a full [Model](#model) object or `null`. The `sessionName` field is the display name set via `set_session_name`, or omitted if not set.
|
||||||
|
|
||||||
#### get_messages
|
#### get_messages
|
||||||
|
|
||||||
|
|
@ -612,6 +613,25 @@ Response:
|
||||||
|
|
||||||
Returns `{"text": null}` if no assistant messages exist.
|
Returns `{"text": null}` if no assistant messages exist.
|
||||||
|
|
||||||
|
#### set_session_name
|
||||||
|
|
||||||
|
Set a display name for the current session. The name appears in session listings and helps identify sessions.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"type": "set_session_name", "name": "my-feature-work"}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "response",
|
||||||
|
"command": "set_session_name",
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The current session name is available via `get_state` in the `sessionName` field.
|
||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
#### get_commands
|
#### get_commands
|
||||||
|
|
|
||||||
|
|
@ -590,6 +590,11 @@ export class AgentSession {
|
||||||
return this.sessionManager.getSessionId();
|
return this.sessionManager.getSessionId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Current session display name, if set */
|
||||||
|
get sessionName(): string | undefined {
|
||||||
|
return this.sessionManager.getSessionName();
|
||||||
|
}
|
||||||
|
|
||||||
/** Scoped models for cycling (from --models flag) */
|
/** Scoped models for cycling (from --models flag) */
|
||||||
get scopedModels(): ReadonlyArray<{ model: Model<any>; thinkingLevel: ThinkingLevel }> {
|
get scopedModels(): ReadonlyArray<{ model: Model<any>; thinkingLevel: ThinkingLevel }> {
|
||||||
return this._scopedModels;
|
return this._scopedModels;
|
||||||
|
|
@ -2181,6 +2186,13 @@ export class AgentSession {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a display name for the current session.
|
||||||
|
*/
|
||||||
|
setSessionName(name: string): void {
|
||||||
|
this.sessionManager.appendSessionInfo(name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a fork from a specific entry.
|
* Create a fork from a specific entry.
|
||||||
* Emits before_fork/fork session events to extensions.
|
* Emits before_fork/fork session events to extensions.
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,13 @@ export class RpcClient {
|
||||||
return this.getData<{ text: string | null }>(response).text;
|
return this.getData<{ text: string | null }>(response).text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the session display name.
|
||||||
|
*/
|
||||||
|
async setSessionName(name: string): Promise<void> {
|
||||||
|
await this.send({ type: "set_session_name", name });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all messages in the session.
|
* Get all messages in the session.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -349,6 +349,7 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
||||||
followUpMode: session.followUpMode,
|
followUpMode: session.followUpMode,
|
||||||
sessionFile: session.sessionFile,
|
sessionFile: session.sessionFile,
|
||||||
sessionId: session.sessionId,
|
sessionId: session.sessionId,
|
||||||
|
sessionName: session.sessionName,
|
||||||
autoCompactionEnabled: session.autoCompactionEnabled,
|
autoCompactionEnabled: session.autoCompactionEnabled,
|
||||||
messageCount: session.messages.length,
|
messageCount: session.messages.length,
|
||||||
pendingMessageCount: session.pendingMessageCount,
|
pendingMessageCount: session.pendingMessageCount,
|
||||||
|
|
@ -490,6 +491,15 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
||||||
return success(id, "get_last_assistant_text", { text });
|
return success(id, "get_last_assistant_text", { text });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "set_session_name": {
|
||||||
|
const name = command.name.trim();
|
||||||
|
if (!name) {
|
||||||
|
return error(id, "set_session_name", "Session name cannot be empty");
|
||||||
|
}
|
||||||
|
session.setSessionName(name);
|
||||||
|
return success(id, "set_session_name");
|
||||||
|
}
|
||||||
|
|
||||||
// =================================================================
|
// =================================================================
|
||||||
// Messages
|
// Messages
|
||||||
// =================================================================
|
// =================================================================
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ export type RpcCommand =
|
||||||
| { id?: string; type: "fork"; entryId: string }
|
| { id?: string; type: "fork"; entryId: string }
|
||||||
| { id?: string; type: "get_fork_messages" }
|
| { id?: string; type: "get_fork_messages" }
|
||||||
| { id?: string; type: "get_last_assistant_text" }
|
| { id?: string; type: "get_last_assistant_text" }
|
||||||
|
| { id?: string; type: "set_session_name"; name: string }
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
| { id?: string; type: "get_messages" }
|
| { id?: string; type: "get_messages" }
|
||||||
|
|
@ -96,6 +97,7 @@ export interface RpcSessionState {
|
||||||
followUpMode: "all" | "one-at-a-time";
|
followUpMode: "all" | "one-at-a-time";
|
||||||
sessionFile?: string;
|
sessionFile?: string;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
|
sessionName?: string;
|
||||||
autoCompactionEnabled: boolean;
|
autoCompactionEnabled: boolean;
|
||||||
messageCount: number;
|
messageCount: number;
|
||||||
pendingMessageCount: number;
|
pendingMessageCount: number;
|
||||||
|
|
@ -185,6 +187,7 @@ export type RpcResponse =
|
||||||
success: true;
|
success: true;
|
||||||
data: { text: string | null };
|
data: { text: string | null };
|
||||||
}
|
}
|
||||||
|
| { id?: string; type: "response"; command: "set_session_name"; success: true }
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
| { id?: string; type: "response"; command: "get_messages"; success: true; data: { messages: AgentMessage[] } }
|
| { id?: string; type: "response"; command: "get_messages"; success: true; data: { messages: AgentMessage[] } }
|
||||||
|
|
|
||||||
|
|
@ -282,4 +282,37 @@ describe.skipIf(!process.env.ANTHROPIC_API_KEY && !process.env.ANTHROPIC_OAUTH_T
|
||||||
text = await client.getLastAssistantText();
|
text = await client.getLastAssistantText();
|
||||||
expect(text).toContain("test123");
|
expect(text).toContain("test123");
|
||||||
}, 90000);
|
}, 90000);
|
||||||
|
|
||||||
|
test("should set and get session name", async () => {
|
||||||
|
await client.start();
|
||||||
|
|
||||||
|
// Initially undefined
|
||||||
|
let state = await client.getState();
|
||||||
|
expect(state.sessionName).toBeUndefined();
|
||||||
|
|
||||||
|
// Set name
|
||||||
|
await client.setSessionName("my-test-session");
|
||||||
|
|
||||||
|
// Verify via state
|
||||||
|
state = await client.getState();
|
||||||
|
expect(state.sessionName).toBe("my-test-session");
|
||||||
|
|
||||||
|
// Wait for file writes
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
// Verify session_info entry in session file
|
||||||
|
const sessionsPath = join(sessionDir, "sessions");
|
||||||
|
const sessionDirs = readdirSync(sessionsPath);
|
||||||
|
const cwdSessionDir = join(sessionsPath, sessionDirs[0]);
|
||||||
|
const sessionFiles = readdirSync(cwdSessionDir).filter((f) => f.endsWith(".jsonl"));
|
||||||
|
const sessionContent = readFileSync(join(cwdSessionDir, sessionFiles[0]), "utf8");
|
||||||
|
const entries = sessionContent
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map((line) => JSON.parse(line));
|
||||||
|
|
||||||
|
const sessionInfoEntries = entries.filter((e: { type: string }) => e.type === "session_info");
|
||||||
|
expect(sessionInfoEntries.length).toBe(1);
|
||||||
|
expect(sessionInfoEntries[0].name).toBe("my-test-session");
|
||||||
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue