mirror of
https://github.com/harivansh-afk/clanker-agent.git
synced 2026-04-15 05:02:07 +00:00
chat titles
This commit is contained in:
parent
ce61669442
commit
a5f4b58221
3 changed files with 128 additions and 19 deletions
|
|
@ -177,15 +177,14 @@ export class GatewayRuntime {
|
||||||
request: GatewayMessageRequest;
|
request: GatewayMessageRequest;
|
||||||
onStart?: () => void;
|
onStart?: () => void;
|
||||||
onFinish?: () => void;
|
onFinish?: () => void;
|
||||||
}):
|
}): Promise<
|
||||||
Promise<
|
| { accepted: false; errorResult: GatewayMessageResult }
|
||||||
| { accepted: false; errorResult: GatewayMessageResult }
|
| {
|
||||||
| {
|
accepted: true;
|
||||||
accepted: true;
|
managedSession: ManagedGatewaySession;
|
||||||
managedSession: ManagedGatewaySession;
|
completion: Promise<GatewayMessageResult>;
|
||||||
completion: Promise<GatewayMessageResult>;
|
}
|
||||||
}
|
> {
|
||||||
> {
|
|
||||||
const managedSession = await this.ensureSession(
|
const managedSession = await this.ensureSession(
|
||||||
queuedMessage.request.sessionKey,
|
queuedMessage.request.sessionKey,
|
||||||
);
|
);
|
||||||
|
|
@ -640,6 +639,7 @@ export class GatewayRuntime {
|
||||||
managedSession: ManagedGatewaySession,
|
managedSession: ManagedGatewaySession,
|
||||||
): GatewaySessionSnapshot {
|
): GatewaySessionSnapshot {
|
||||||
const messages = managedSession.session.messages;
|
const messages = managedSession.session.messages;
|
||||||
|
const name = managedSession.session.sessionName?.trim() || undefined;
|
||||||
let lastMessagePreview: string | undefined;
|
let lastMessagePreview: string | undefined;
|
||||||
for (let i = messages.length - 1; i >= 0; i--) {
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
const msg = messages[i];
|
const msg = messages[i];
|
||||||
|
|
@ -676,6 +676,7 @@ export class GatewayRuntime {
|
||||||
lastActiveAt: managedSession.lastActiveAt,
|
lastActiveAt: managedSession.lastActiveAt,
|
||||||
createdAt: managedSession.createdAt,
|
createdAt: managedSession.createdAt,
|
||||||
updatedAt: managedSession.lastActiveAt,
|
updatedAt: managedSession.lastActiveAt,
|
||||||
|
name,
|
||||||
lastMessagePreview,
|
lastMessagePreview,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1292,15 +1293,13 @@ export class GatewayRuntime {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const managed = await this.requireExistingSession(sessionKey);
|
const managed = await this.requireExistingSession(sessionKey);
|
||||||
if (patch.name !== undefined) {
|
if (patch.name !== undefined) {
|
||||||
// Labels in pi-mono are per-entry; we label the current leaf entry
|
const name = patch.name.trim();
|
||||||
const leafId = managed.session.sessionManager.getLeafId();
|
if (!name) {
|
||||||
if (!leafId) {
|
throw new HttpError(400, "Session name cannot be empty");
|
||||||
throw new HttpError(
|
|
||||||
409,
|
|
||||||
`Cannot rename session without an active leaf entry: ${sessionKey}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
managed.session.sessionManager.appendLabelChange(leafId, patch.name);
|
managed.session.sessionManager.appendSessionInfo(name);
|
||||||
|
managed.lastActiveAt = Date.now();
|
||||||
|
this.emitState(managed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
101
packages/coding-agent/test/gateway-session-titles.test.ts
Normal file
101
packages/coding-agent/test/gateway-session-titles.test.ts
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import { GatewayRuntime } from "../src/core/gateway/runtime.js";
|
||||||
|
|
||||||
|
function createMockSession(options?: { sessionName?: string }) {
|
||||||
|
return {
|
||||||
|
sessionId: "session-1",
|
||||||
|
sessionName: options?.sessionName,
|
||||||
|
messages: [],
|
||||||
|
prompt: vi.fn().mockResolvedValue(undefined),
|
||||||
|
steer: vi.fn().mockResolvedValue(undefined),
|
||||||
|
abort: vi.fn().mockResolvedValue(undefined),
|
||||||
|
dispose: vi.fn(),
|
||||||
|
subscribe: vi.fn(() => () => {}),
|
||||||
|
sessionManager: {
|
||||||
|
getSessionDir: () => "/tmp/pi-gateway-test",
|
||||||
|
appendSessionInfo: vi.fn(),
|
||||||
|
appendLabelChange: vi.fn(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRuntime(session = createMockSession()) {
|
||||||
|
return new GatewayRuntime({
|
||||||
|
config: {
|
||||||
|
bind: "127.0.0.1",
|
||||||
|
port: 0,
|
||||||
|
session: {
|
||||||
|
idleMinutes: 5,
|
||||||
|
maxQueuePerSession: 4,
|
||||||
|
},
|
||||||
|
webhook: {
|
||||||
|
enabled: false,
|
||||||
|
basePath: "/webhooks",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
primarySessionKey: "primary",
|
||||||
|
primarySession: session as never,
|
||||||
|
createSession: async () => session as never,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addManagedSession(
|
||||||
|
runtime: GatewayRuntime,
|
||||||
|
sessionKey: string,
|
||||||
|
session: ReturnType<typeof createMockSession>,
|
||||||
|
) {
|
||||||
|
const managedSession = {
|
||||||
|
sessionKey,
|
||||||
|
session,
|
||||||
|
queue: [],
|
||||||
|
processing: false,
|
||||||
|
activeAssistantMessage: null,
|
||||||
|
pendingToolResults: [],
|
||||||
|
createdAt: Date.now(),
|
||||||
|
lastActiveAt: Date.now(),
|
||||||
|
listeners: new Set(),
|
||||||
|
unsubscribe: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
(runtime as unknown as { sessions: Map<string, unknown> }).sessions.set(
|
||||||
|
sessionKey,
|
||||||
|
managedSession,
|
||||||
|
);
|
||||||
|
|
||||||
|
return managedSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("GatewayRuntime session titles", () => {
|
||||||
|
it("includes the session name in snapshots", () => {
|
||||||
|
const session = createMockSession({ sessionName: "Generated title" });
|
||||||
|
const runtime = createRuntime(session);
|
||||||
|
addManagedSession(runtime, "chat", session);
|
||||||
|
|
||||||
|
expect(runtime.listSessions()).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
sessionKey: "chat",
|
||||||
|
name: "Generated title",
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("persists renamed sessions via session_info entries", async () => {
|
||||||
|
const session = createMockSession();
|
||||||
|
const runtime = createRuntime(session);
|
||||||
|
addManagedSession(runtime, "chat", session);
|
||||||
|
|
||||||
|
await (
|
||||||
|
runtime as unknown as {
|
||||||
|
handlePatchSession: (
|
||||||
|
sessionKey: string,
|
||||||
|
patch: { name?: string },
|
||||||
|
) => Promise<void>;
|
||||||
|
}
|
||||||
|
).handlePatchSession("chat", { name: "Renamed title" });
|
||||||
|
|
||||||
|
expect(session.sessionManager.appendSessionInfo).toHaveBeenCalledWith(
|
||||||
|
"Renamed title",
|
||||||
|
);
|
||||||
|
expect(session.sessionManager.appendLabelChange).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -4,6 +4,7 @@ import { GatewayRuntime } from "../src/core/gateway/runtime.js";
|
||||||
function createMockSession() {
|
function createMockSession() {
|
||||||
return {
|
return {
|
||||||
sessionId: "session-1",
|
sessionId: "session-1",
|
||||||
|
sessionName: undefined,
|
||||||
messages: [],
|
messages: [],
|
||||||
prompt: vi.fn().mockResolvedValue(undefined),
|
prompt: vi.fn().mockResolvedValue(undefined),
|
||||||
steer: vi.fn().mockResolvedValue(undefined),
|
steer: vi.fn().mockResolvedValue(undefined),
|
||||||
|
|
@ -74,7 +75,11 @@ describe("GatewayRuntime steer handling", () => {
|
||||||
handleSteer: (
|
handleSteer: (
|
||||||
sessionKey: string,
|
sessionKey: string,
|
||||||
text: string,
|
text: string,
|
||||||
) => Promise<{ ok: true; mode: "steer" | "queued"; sessionKey: string }>;
|
) => Promise<{
|
||||||
|
ok: true;
|
||||||
|
mode: "steer" | "queued";
|
||||||
|
sessionKey: string;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
).handleSteer("chat", "keep going");
|
).handleSteer("chat", "keep going");
|
||||||
|
|
||||||
|
|
@ -97,7 +102,11 @@ describe("GatewayRuntime steer handling", () => {
|
||||||
handleSteer: (
|
handleSteer: (
|
||||||
sessionKey: string,
|
sessionKey: string,
|
||||||
text: string,
|
text: string,
|
||||||
) => Promise<{ ok: true; mode: "steer" | "queued"; sessionKey: string }>;
|
) => Promise<{
|
||||||
|
ok: true;
|
||||||
|
mode: "steer" | "queued";
|
||||||
|
sessionKey: string;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
).handleSteer("chat", "pick this up next");
|
).handleSteer("chat", "pick this up next");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue