@getpaseo/server 0.1.91 → 0.1.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/server/agent/agent-manager.d.ts +12 -4
- package/dist/server/server/agent/agent-manager.js +87 -26
- package/dist/server/server/agent/agent-projections.d.ts +4 -2
- package/dist/server/server/agent/agent-projections.js +8 -28
- package/dist/server/server/agent/agent-sdk-types.d.ts +30 -10
- package/dist/server/server/agent/import-sessions.d.ts +3 -2
- package/dist/server/server/agent/import-sessions.js +23 -55
- package/dist/server/server/agent/provider-registry.js +34 -13
- package/dist/server/server/agent/provider-session-import.d.ts +10 -0
- package/dist/server/server/agent/provider-session-import.js +49 -0
- package/dist/server/server/agent/providers/acp-agent.d.ts +12 -2
- package/dist/server/server/agent/providers/acp-agent.js +78 -36
- package/dist/server/server/agent/providers/claude/agent.d.ts +3 -2
- package/dist/server/server/agent/providers/claude/agent.js +28 -24
- package/dist/server/server/agent/providers/claude/models.js +15 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +3 -2
- package/dist/server/server/agent/providers/codex-app-server-agent.js +20 -21
- package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +1 -0
- package/dist/server/server/agent/providers/cursor-acp-agent.js +1 -0
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +9 -0
- package/dist/server/server/agent/providers/generic-acp-agent.js +18 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +3 -2
- package/dist/server/server/agent/providers/mock-load-test-agent.js +11 -1
- package/dist/server/server/agent/providers/mock-slow-provider.d.ts +1 -2
- package/dist/server/server/agent/providers/mock-slow-provider.js +0 -3
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +8 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts +3 -2
- package/dist/server/server/agent/providers/opencode-agent.js +60 -32
- package/dist/server/server/agent/providers/pi/agent.d.ts +3 -2
- package/dist/server/server/agent/providers/pi/agent.js +28 -5
- package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +3 -4
- package/dist/server/server/agent/providers/pi/session-descriptor.js +17 -37
- package/dist/server/server/session.js +0 -1
- package/package.json +5 -5
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentClient, AgentPersistenceHandle, AgentProvider, AgentSessionConfig, ImportedProviderSession, ImportProviderSessionContext, ImportProviderSessionInput } from "./agent-sdk-types.js";
|
|
2
|
+
export declare function importSessionFromPersistence(input: {
|
|
3
|
+
provider: AgentProvider;
|
|
4
|
+
request: ImportProviderSessionInput;
|
|
5
|
+
context: ImportProviderSessionContext;
|
|
6
|
+
resumeSession: AgentClient["resumeSession"];
|
|
7
|
+
config?: Partial<AgentSessionConfig>;
|
|
8
|
+
persistence?: AgentPersistenceHandle;
|
|
9
|
+
}): Promise<ImportedProviderSession>;
|
|
10
|
+
//# sourceMappingURL=provider-session-import.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export async function importSessionFromPersistence(input) {
|
|
2
|
+
const config = {
|
|
3
|
+
...input.context.config,
|
|
4
|
+
...input.config,
|
|
5
|
+
provider: input.provider,
|
|
6
|
+
cwd: input.request.cwd,
|
|
7
|
+
};
|
|
8
|
+
const storedConfig = {
|
|
9
|
+
...input.context.storedConfig,
|
|
10
|
+
...input.config,
|
|
11
|
+
provider: input.provider,
|
|
12
|
+
cwd: input.request.cwd,
|
|
13
|
+
};
|
|
14
|
+
const persistence = input.persistence ?? buildImportPersistenceHandle(input.provider, input.request, storedConfig);
|
|
15
|
+
const session = await input.resumeSession(persistence, config, input.context.launchContext);
|
|
16
|
+
const timeline = await collectImportedTimeline(session.streamHistory());
|
|
17
|
+
return {
|
|
18
|
+
session,
|
|
19
|
+
config: storedConfig,
|
|
20
|
+
persistence,
|
|
21
|
+
timeline,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function buildImportPersistenceHandle(provider, input, config) {
|
|
25
|
+
return {
|
|
26
|
+
provider,
|
|
27
|
+
sessionId: input.providerHandleId,
|
|
28
|
+
nativeHandle: input.providerHandleId,
|
|
29
|
+
metadata: {
|
|
30
|
+
...config,
|
|
31
|
+
provider,
|
|
32
|
+
cwd: input.cwd,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function collectImportedTimeline(events) {
|
|
37
|
+
const timeline = [];
|
|
38
|
+
for await (const event of events) {
|
|
39
|
+
if (event.type !== "timeline") {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
timeline.push({
|
|
43
|
+
item: event.item,
|
|
44
|
+
...(event.timestamp ? { timestamp: event.timestamp } : {}),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return timeline;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=provider-session-import.js.map
|
|
@@ -2,8 +2,14 @@ import { type ChildProcessWithoutNullStreams } from "node:child_process";
|
|
|
2
2
|
import type { ReadableStream as NodeReadableStream, WritableStream as NodeWritableStream } from "node:stream/web";
|
|
3
3
|
import { ClientSideConnection, type Client as ACPClient, type CreateTerminalRequest, type InitializeResponse, type KillTerminalRequest, type LoadSessionResponse, type NewSessionResponse, type ReadTextFileRequest, type RequestPermissionRequest, type RequestPermissionResponse, type ResumeSessionResponse, type SessionConfigOption, type SessionMode, type SessionModelState, type SessionNotification, type TerminalOutputRequest, type TerminalOutputResponse, type ToolCallContent, type ToolCallLocation, type ToolCallStatus, type ToolKind, type Usage, type WaitForTerminalExitRequest, type WriteTextFileRequest, type Stream as ACPStream } from "@agentclientprotocol/sdk";
|
|
4
4
|
import type { Logger } from "pino";
|
|
5
|
-
import { type AgentCapabilityFlags, type AgentClient, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentUsage, type
|
|
5
|
+
import { type AgentCapabilityFlags, type AgentClient, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentUsage, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModesOptions, type ListModelsOptions } from "../agent-sdk-types.js";
|
|
6
6
|
import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
|
|
7
|
+
export declare function summarizeACPRequestError(error: unknown): {
|
|
8
|
+
message: string;
|
|
9
|
+
code?: string;
|
|
10
|
+
diagnostic?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const DEFAULT_ACP_CAPABILITIES: AgentCapabilityFlags;
|
|
7
13
|
export declare function createLoggedNdJsonStream(output: NodeWritableStream, input: NodeReadableStream, options: {
|
|
8
14
|
logger: Logger;
|
|
9
15
|
provider: string;
|
|
@@ -147,13 +153,15 @@ export declare class ACPAgentClient implements AgentClient {
|
|
|
147
153
|
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
148
154
|
listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
|
|
149
155
|
listModes(options: ListModesOptions): Promise<AgentMode[]>;
|
|
150
|
-
|
|
156
|
+
listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
|
|
157
|
+
importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
|
|
151
158
|
isAvailable(): Promise<boolean>;
|
|
152
159
|
protected spawnProcess(launchEnv?: Record<string, string>, options?: {
|
|
153
160
|
initializeTimeoutMs?: number;
|
|
154
161
|
}): Promise<SpawnedACPProcess>;
|
|
155
162
|
protected buildProbeClient(): ACPClient;
|
|
156
163
|
protected closeProbe(probe: SpawnedACPProcess): Promise<void>;
|
|
164
|
+
protected runACPRequest<T>(request: () => Promise<T>): Promise<T>;
|
|
157
165
|
protected resolveLaunchCommand(): Promise<{
|
|
158
166
|
command: string;
|
|
159
167
|
args: string[];
|
|
@@ -257,6 +265,8 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
|
|
|
257
265
|
}): Promise<void>;
|
|
258
266
|
killTerminal(params: KillTerminalRequest): Promise<Record<string, never>>;
|
|
259
267
|
private spawnProcess;
|
|
268
|
+
private runACPRequest;
|
|
269
|
+
private acpMcpServers;
|
|
260
270
|
private applySessionState;
|
|
261
271
|
private transformConfigOptions;
|
|
262
272
|
private transformModeId;
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { Readable, Writable } from "node:stream";
|
|
5
5
|
import { ClientSideConnection, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk";
|
|
6
6
|
import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
|
|
7
|
+
import { importSessionFromPersistence } from "../provider-session-import.js";
|
|
7
8
|
import { checkProviderLaunchAvailable, createProviderEnvSpec, resolveProviderLaunch, } from "../provider-launch-config.js";
|
|
8
9
|
import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
|
|
9
10
|
import { appendOrReplaceGrowingAssistantMessage, runProviderTurn } from "./provider-runner.js";
|
|
@@ -19,15 +20,29 @@ function isRecord(value) {
|
|
|
19
20
|
function isACPError(value) {
|
|
20
21
|
return isRecord(value) && typeof value.message === "string" && typeof value.code === "number";
|
|
21
22
|
}
|
|
22
|
-
function
|
|
23
|
+
function extractACPErrorDataMessage(data) {
|
|
24
|
+
if (!isRecord(data)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
for (const key of ["details", "errorMessage", "message", "detail", "title"]) {
|
|
28
|
+
const value = data[key];
|
|
29
|
+
if (typeof value === "string" && value.trim()) {
|
|
30
|
+
return value.trim();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return extractACPErrorDataMessage(data.error);
|
|
34
|
+
}
|
|
35
|
+
export function summarizeACPRequestError(error) {
|
|
23
36
|
// Promise rejections are untyped, but the ACP SDK rejects JSON-RPC failures as response.error.
|
|
24
37
|
if (isACPError(error)) {
|
|
25
38
|
const code = String(error.code);
|
|
39
|
+
const detail = extractACPErrorDataMessage(error.data);
|
|
40
|
+
const message = detail && detail !== error.message ? `${error.message}: ${detail}` : error.message;
|
|
26
41
|
const data = error.data === undefined ? "" : ` | data=${JSON.stringify(error.data)}`;
|
|
27
42
|
return {
|
|
28
|
-
message
|
|
43
|
+
message,
|
|
29
44
|
code,
|
|
30
|
-
diagnostic: `${
|
|
45
|
+
diagnostic: `${message} | code=${code}${data}`,
|
|
31
46
|
};
|
|
32
47
|
}
|
|
33
48
|
if (error instanceof Error) {
|
|
@@ -35,6 +50,15 @@ function summarizeACPRequestError(error) {
|
|
|
35
50
|
}
|
|
36
51
|
return { message: String(error) };
|
|
37
52
|
}
|
|
53
|
+
function toACPRequestError(error) {
|
|
54
|
+
if (!isACPError(error)) {
|
|
55
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
56
|
+
}
|
|
57
|
+
const summary = summarizeACPRequestError(error);
|
|
58
|
+
const next = new Error(summary.message);
|
|
59
|
+
next.name = "ACPRequestError";
|
|
60
|
+
return next;
|
|
61
|
+
}
|
|
38
62
|
function resolveTerminalCommand(command, args) {
|
|
39
63
|
if (args && args.length > 0) {
|
|
40
64
|
return { command, args };
|
|
@@ -45,7 +69,7 @@ function resolveTerminalCommand(command, args) {
|
|
|
45
69
|
const shell = platformShell();
|
|
46
70
|
return { command: shell.command, args: [...shell.flag, command] };
|
|
47
71
|
}
|
|
48
|
-
const DEFAULT_ACP_CAPABILITIES = {
|
|
72
|
+
export const DEFAULT_ACP_CAPABILITIES = {
|
|
49
73
|
supportsStreaming: true,
|
|
50
74
|
supportsSessionPersistence: true,
|
|
51
75
|
supportsDynamicModes: true,
|
|
@@ -318,10 +342,10 @@ export class ACPAgentClient {
|
|
|
318
342
|
const { cwd } = options;
|
|
319
343
|
const probe = await this.spawnProcess(PROBE_ENV);
|
|
320
344
|
try {
|
|
321
|
-
const response = await probe.connection.newSession({
|
|
345
|
+
const response = await this.runACPRequest(() => probe.connection.newSession({
|
|
322
346
|
cwd,
|
|
323
347
|
mcpServers: [],
|
|
324
|
-
});
|
|
348
|
+
}));
|
|
325
349
|
const transformed = this.transformSessionResponse(response);
|
|
326
350
|
const models = deriveModelDefinitionsFromACP(this.provider, transformed.models, transformed.configOptions);
|
|
327
351
|
return this.modelTransformer ? this.modelTransformer(models) : models;
|
|
@@ -334,10 +358,10 @@ export class ACPAgentClient {
|
|
|
334
358
|
const { cwd } = options;
|
|
335
359
|
const probe = await this.spawnProcess(PROBE_ENV);
|
|
336
360
|
try {
|
|
337
|
-
const response = await probe.connection.newSession({
|
|
361
|
+
const response = await this.runACPRequest(() => probe.connection.newSession({
|
|
338
362
|
cwd,
|
|
339
363
|
mcpServers: [],
|
|
340
|
-
});
|
|
364
|
+
}));
|
|
341
365
|
const transformed = this.transformSessionResponse(response);
|
|
342
366
|
const modeInfo = deriveModesFromACP(this.defaultModes, transformed.modes, transformed.configOptions);
|
|
343
367
|
return modeInfo.modes;
|
|
@@ -346,7 +370,7 @@ export class ACPAgentClient {
|
|
|
346
370
|
await this.closeProbe(probe);
|
|
347
371
|
}
|
|
348
372
|
}
|
|
349
|
-
async
|
|
373
|
+
async listImportableSessions(options) {
|
|
350
374
|
const probe = await this.spawnProcess(PROBE_ENV);
|
|
351
375
|
try {
|
|
352
376
|
if (!probe.initialize.agentCapabilities?.sessionCapabilities?.list) {
|
|
@@ -355,25 +379,15 @@ export class ACPAgentClient {
|
|
|
355
379
|
const sessions = [];
|
|
356
380
|
let cursor;
|
|
357
381
|
for (;;) {
|
|
358
|
-
const page = await probe.connection.listSessions(cursor ? { cursor } : {});
|
|
382
|
+
const page = await this.runACPRequest(() => probe.connection.listSessions(cursor ? { cursor } : {}));
|
|
359
383
|
for (const session of page.sessions) {
|
|
360
384
|
sessions.push({
|
|
361
|
-
|
|
362
|
-
sessionId: session.sessionId,
|
|
385
|
+
providerHandleId: session.sessionId,
|
|
363
386
|
cwd: session.cwd,
|
|
364
387
|
title: session.title ?? null,
|
|
388
|
+
firstPromptPreview: null,
|
|
389
|
+
lastPromptPreview: null,
|
|
365
390
|
lastActivityAt: session.updatedAt ? new Date(session.updatedAt) : new Date(0),
|
|
366
|
-
persistence: {
|
|
367
|
-
provider: this.provider,
|
|
368
|
-
sessionId: session.sessionId,
|
|
369
|
-
nativeHandle: session.sessionId,
|
|
370
|
-
metadata: {
|
|
371
|
-
provider: this.provider,
|
|
372
|
-
cwd: session.cwd,
|
|
373
|
-
title: session.title ?? null,
|
|
374
|
-
},
|
|
375
|
-
},
|
|
376
|
-
timeline: [],
|
|
377
391
|
});
|
|
378
392
|
}
|
|
379
393
|
cursor = page.nextCursor ?? null;
|
|
@@ -388,6 +402,14 @@ export class ACPAgentClient {
|
|
|
388
402
|
await this.closeProbe(probe);
|
|
389
403
|
}
|
|
390
404
|
}
|
|
405
|
+
async importSession(input, context) {
|
|
406
|
+
return importSessionFromPersistence({
|
|
407
|
+
provider: this.provider,
|
|
408
|
+
request: input,
|
|
409
|
+
context,
|
|
410
|
+
resumeSession: this.resumeSession.bind(this),
|
|
411
|
+
});
|
|
412
|
+
}
|
|
391
413
|
async isAvailable() {
|
|
392
414
|
try {
|
|
393
415
|
await this.resolveLaunchCommand();
|
|
@@ -430,7 +452,7 @@ export class ACPAgentClient {
|
|
|
430
452
|
: null;
|
|
431
453
|
let initialize;
|
|
432
454
|
try {
|
|
433
|
-
initialize = await Promise.race([
|
|
455
|
+
initialize = await this.runACPRequest(() => Promise.race([
|
|
434
456
|
connection.initialize({
|
|
435
457
|
protocolVersion: PROTOCOL_VERSION,
|
|
436
458
|
clientCapabilities: ACP_CLIENT_CAPABILITIES,
|
|
@@ -438,7 +460,7 @@ export class ACPAgentClient {
|
|
|
438
460
|
}),
|
|
439
461
|
spawnErrorPromise,
|
|
440
462
|
...(initializeTimeoutPromise ? [initializeTimeoutPromise] : []),
|
|
441
|
-
]);
|
|
463
|
+
]));
|
|
442
464
|
}
|
|
443
465
|
catch (error) {
|
|
444
466
|
await terminateChildProcess(child, 2000);
|
|
@@ -481,6 +503,14 @@ export class ACPAgentClient {
|
|
|
481
503
|
await terminateChildProcess(probe.child, 2000);
|
|
482
504
|
}
|
|
483
505
|
}
|
|
506
|
+
async runACPRequest(request) {
|
|
507
|
+
try {
|
|
508
|
+
return await request();
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
throw toACPRequestError(error);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
484
514
|
async resolveLaunchCommand() {
|
|
485
515
|
const prefix = await resolveProviderLaunch({
|
|
486
516
|
commandConfig: this.runtimeSettings?.command,
|
|
@@ -575,10 +605,10 @@ export class ACPAgentSession {
|
|
|
575
605
|
this.child = spawned.child;
|
|
576
606
|
this.connection = spawned.connection;
|
|
577
607
|
this.agentCapabilities = spawned.initialize.agentCapabilities ?? null;
|
|
578
|
-
const response = await this.connection.newSession({
|
|
608
|
+
const response = await this.runACPRequest(() => this.connection.newSession({
|
|
579
609
|
cwd: this.config.cwd,
|
|
580
|
-
mcpServers:
|
|
581
|
-
});
|
|
610
|
+
mcpServers: this.acpMcpServers(),
|
|
611
|
+
}));
|
|
582
612
|
this.sessionId = response.sessionId;
|
|
583
613
|
this.bootstrapThreadEventPending = true;
|
|
584
614
|
this.applySessionState(response);
|
|
@@ -598,21 +628,21 @@ export class ACPAgentSession {
|
|
|
598
628
|
const sessionCapabilities = this.agentCapabilities?.sessionCapabilities;
|
|
599
629
|
if (this.agentCapabilities?.loadSession) {
|
|
600
630
|
this.replayingHistory = true;
|
|
601
|
-
const response = await this.connection.loadSession({
|
|
631
|
+
const response = await this.runACPRequest(() => this.connection.loadSession({
|
|
602
632
|
sessionId: handle.sessionId,
|
|
603
633
|
cwd: this.config.cwd,
|
|
604
|
-
mcpServers:
|
|
605
|
-
});
|
|
634
|
+
mcpServers: this.acpMcpServers(),
|
|
635
|
+
}));
|
|
606
636
|
this.replayingHistory = false;
|
|
607
637
|
this.historyPending = this.persistedHistory.length > 0;
|
|
608
638
|
this.applySessionState(response);
|
|
609
639
|
}
|
|
610
640
|
else if (sessionCapabilities?.resume) {
|
|
611
|
-
const response = await this.connection.unstable_resumeSession({
|
|
641
|
+
const response = await this.runACPRequest(() => this.connection.unstable_resumeSession({
|
|
612
642
|
sessionId: handle.sessionId,
|
|
613
643
|
cwd: this.config.cwd,
|
|
614
|
-
mcpServers:
|
|
615
|
-
});
|
|
644
|
+
mcpServers: this.acpMcpServers(),
|
|
645
|
+
}));
|
|
616
646
|
this.applySessionState(response);
|
|
617
647
|
}
|
|
618
648
|
else {
|
|
@@ -1282,13 +1312,24 @@ export class ACPAgentSession {
|
|
|
1282
1312
|
});
|
|
1283
1313
|
const stream = createLoggedNdJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout), { logger: this.logger, provider: this.provider });
|
|
1284
1314
|
const connection = new ClientSideConnection(() => this, stream);
|
|
1285
|
-
const initialize = await connection.initialize({
|
|
1315
|
+
const initialize = await this.runACPRequest(() => connection.initialize({
|
|
1286
1316
|
protocolVersion: PROTOCOL_VERSION,
|
|
1287
1317
|
clientCapabilities: ACP_CLIENT_CAPABILITIES,
|
|
1288
1318
|
clientInfo: { name: "Paseo", version: "dev" },
|
|
1289
|
-
});
|
|
1319
|
+
}));
|
|
1290
1320
|
return { child, connection, initialize };
|
|
1291
1321
|
}
|
|
1322
|
+
async runACPRequest(request) {
|
|
1323
|
+
try {
|
|
1324
|
+
return await request();
|
|
1325
|
+
}
|
|
1326
|
+
catch (error) {
|
|
1327
|
+
throw toACPRequestError(error);
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
acpMcpServers() {
|
|
1331
|
+
return this.capabilities.supportsMcpServers ? normalizeMcpServers(this.config.mcpServers) : [];
|
|
1332
|
+
}
|
|
1292
1333
|
applySessionState(response) {
|
|
1293
1334
|
const transformed = this.sessionResponseTransformer
|
|
1294
1335
|
? this.sessionResponseTransformer(response)
|
|
@@ -1400,6 +1441,7 @@ export class ACPAgentSession {
|
|
|
1400
1441
|
name: command.name,
|
|
1401
1442
|
description: command.description,
|
|
1402
1443
|
argumentHint: "",
|
|
1444
|
+
kind: "command",
|
|
1403
1445
|
}));
|
|
1404
1446
|
this.settleCommandsReady();
|
|
1405
1447
|
return [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type AgentDefinition, type McpServerConfig as ClaudeSdkMcpServerConfig, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
2
2
|
import type { Logger } from "pino";
|
|
3
3
|
import { type ClaudeQueryFactory } from "./query.js";
|
|
4
|
-
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMetadata, type AgentModelDefinition, type AgentPersistenceHandle, type AgentSession, type AgentSessionConfig, type AgentTimelineItem, type
|
|
4
|
+
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMetadata, type AgentModelDefinition, type AgentPersistenceHandle, type AgentSession, type AgentSessionConfig, type AgentTimelineItem, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModelsOptions, type McpServerConfig } from "../../agent-sdk-types.js";
|
|
5
5
|
import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
|
|
6
6
|
export declare function normalizeClaudeAskUserQuestionUpdatedInput(updatedInput: AgentMetadata | undefined, fallbackInput: AgentMetadata | undefined): AgentMetadata;
|
|
7
7
|
interface EventIdentifiers {
|
|
@@ -40,7 +40,8 @@ export declare class ClaudeAgentClient implements AgentClient {
|
|
|
40
40
|
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
41
41
|
listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
|
|
42
42
|
listFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
|
|
43
|
-
|
|
43
|
+
listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
|
|
44
|
+
importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../../agent-sdk-types.js").ImportedProviderSession>;
|
|
44
45
|
isAvailable(): Promise<boolean>;
|
|
45
46
|
getDiagnostic(): Promise<{
|
|
46
47
|
diagnostic: string;
|
|
@@ -17,6 +17,7 @@ import { realClaudeRewindSdk, revertClaudeConversation, revertClaudeFiles } from
|
|
|
17
17
|
import { normalizeProviderReplayTimestamp } from "../../provider-history-timestamps.js";
|
|
18
18
|
import { claudeProjectDirSync } from "./project-dir.js";
|
|
19
19
|
import { getAgentStreamEventTurnId, } from "../../agent-sdk-types.js";
|
|
20
|
+
import { importSessionFromPersistence } from "../../provider-session-import.js";
|
|
20
21
|
import { checkProviderLaunchAvailable, createProviderEnv, createProviderEnvSpec, resolveProviderLaunch, } from "../../provider-launch-config.js";
|
|
21
22
|
import { withTimeout } from "../../../../utils/promise-timeout.js";
|
|
22
23
|
import { execCommand } from "../../../../utils/spawn.js";
|
|
@@ -87,6 +88,7 @@ function isImageMimeType(value) {
|
|
|
87
88
|
const CLAUDE_CAPABILITIES = {
|
|
88
89
|
supportsStreaming: true,
|
|
89
90
|
supportsSessionPersistence: true,
|
|
91
|
+
supportsSessionListing: true,
|
|
90
92
|
supportsDynamicModes: true,
|
|
91
93
|
supportsMcpServers: true,
|
|
92
94
|
supportsReasoningStream: true,
|
|
@@ -974,7 +976,7 @@ export class ClaudeAgentClient {
|
|
|
974
976
|
fastModeEnabled: claudeConfig.featureValues?.fast_mode === true,
|
|
975
977
|
});
|
|
976
978
|
}
|
|
977
|
-
async
|
|
979
|
+
async listImportableSessions(options) {
|
|
978
980
|
const configDir = process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
|
|
979
981
|
const projectsRoot = path.join(configDir, "projects");
|
|
980
982
|
if (!(await pathExists(projectsRoot))) {
|
|
@@ -984,9 +986,17 @@ export class ClaudeAgentClient {
|
|
|
984
986
|
const candidates = await collectRecentClaudeSessions(projectsRoot, limit * 3);
|
|
985
987
|
const parsed = await Promise.all(candidates.map((candidate) => parseClaudeSessionDescriptor(candidate.path, candidate.mtime)));
|
|
986
988
|
return parsed
|
|
987
|
-
.filter((
|
|
989
|
+
.filter((session) => session !== null)
|
|
988
990
|
.slice(0, limit);
|
|
989
991
|
}
|
|
992
|
+
async importSession(input, context) {
|
|
993
|
+
return importSessionFromPersistence({
|
|
994
|
+
provider: "claude",
|
|
995
|
+
request: input,
|
|
996
|
+
context,
|
|
997
|
+
resumeSession: this.resumeSession.bind(this),
|
|
998
|
+
});
|
|
999
|
+
}
|
|
990
1000
|
async isAvailable() {
|
|
991
1001
|
const launch = await resolveProviderLaunch({
|
|
992
1002
|
commandConfig: this.runtimeSettings?.command,
|
|
@@ -1655,6 +1665,7 @@ class ClaudeAgentSession {
|
|
|
1655
1665
|
name: cmd.name,
|
|
1656
1666
|
description: cmd.description,
|
|
1657
1667
|
argumentHint: cmd.argumentHint,
|
|
1668
|
+
kind: "command",
|
|
1658
1669
|
});
|
|
1659
1670
|
}
|
|
1660
1671
|
}
|
|
@@ -3951,16 +3962,12 @@ function applyClaudeSessionEntryToAccumulator(entryRaw, acc) {
|
|
|
3951
3962
|
if (!acc.title) {
|
|
3952
3963
|
acc.title = text;
|
|
3953
3964
|
}
|
|
3954
|
-
|
|
3965
|
+
const preview = normalizeImportablePromptPreview(text);
|
|
3966
|
+
acc.firstPromptPreview ?? (acc.firstPromptPreview = preview);
|
|
3967
|
+
acc.lastPromptPreview = preview;
|
|
3955
3968
|
}
|
|
3956
3969
|
return;
|
|
3957
3970
|
}
|
|
3958
|
-
if (entry.type === "assistant" && entry.message) {
|
|
3959
|
-
const text = extractClaudeUserText(entry.message);
|
|
3960
|
-
if (text) {
|
|
3961
|
-
acc.timeline.push({ type: "assistant_message", text });
|
|
3962
|
-
}
|
|
3963
|
-
}
|
|
3964
3971
|
}
|
|
3965
3972
|
async function parseClaudeSessionDescriptor(filePath, mtime) {
|
|
3966
3973
|
let content;
|
|
@@ -3974,7 +3981,8 @@ async function parseClaudeSessionDescriptor(filePath, mtime) {
|
|
|
3974
3981
|
sessionId: null,
|
|
3975
3982
|
cwd: null,
|
|
3976
3983
|
title: null,
|
|
3977
|
-
|
|
3984
|
+
firstPromptPreview: null,
|
|
3985
|
+
lastPromptPreview: null,
|
|
3978
3986
|
};
|
|
3979
3987
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
3980
3988
|
const line = rawLine.trim();
|
|
@@ -3992,29 +4000,25 @@ async function parseClaudeSessionDescriptor(filePath, mtime) {
|
|
|
3992
4000
|
break;
|
|
3993
4001
|
}
|
|
3994
4002
|
}
|
|
3995
|
-
const { sessionId, cwd, title
|
|
4003
|
+
const { sessionId, cwd, title } = acc;
|
|
3996
4004
|
if (!sessionId || !cwd) {
|
|
3997
4005
|
return null;
|
|
3998
4006
|
}
|
|
3999
|
-
const persistence = {
|
|
4000
|
-
provider: "claude",
|
|
4001
|
-
sessionId,
|
|
4002
|
-
nativeHandle: sessionId,
|
|
4003
|
-
metadata: {
|
|
4004
|
-
provider: "claude",
|
|
4005
|
-
cwd,
|
|
4006
|
-
},
|
|
4007
|
-
};
|
|
4008
4007
|
return {
|
|
4009
|
-
|
|
4010
|
-
sessionId,
|
|
4008
|
+
providerHandleId: sessionId,
|
|
4011
4009
|
cwd,
|
|
4012
4010
|
title: (title ?? "").trim() || `Claude session ${sessionId.slice(0, 8)}`,
|
|
4011
|
+
firstPromptPreview: acc.firstPromptPreview,
|
|
4012
|
+
lastPromptPreview: acc.lastPromptPreview,
|
|
4013
4013
|
lastActivityAt: mtime,
|
|
4014
|
-
persistence,
|
|
4015
|
-
timeline,
|
|
4016
4014
|
};
|
|
4017
4015
|
}
|
|
4016
|
+
function normalizeImportablePromptPreview(text) {
|
|
4017
|
+
const normalized = text.trim().replace(/\s+/g, " ");
|
|
4018
|
+
if (!normalized)
|
|
4019
|
+
return null;
|
|
4020
|
+
return normalized.length > 160 ? normalized.slice(0, 160) : normalized;
|
|
4021
|
+
}
|
|
4018
4022
|
function extractClaudeUserText(messageRaw) {
|
|
4019
4023
|
const message = toObjectRecord(messageRaw);
|
|
4020
4024
|
if (!message) {
|
|
@@ -15,6 +15,13 @@ const CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS = [
|
|
|
15
15
|
{ id: "max", label: "Max" },
|
|
16
16
|
];
|
|
17
17
|
const CLAUDE_MODELS = [
|
|
18
|
+
{
|
|
19
|
+
provider: "claude",
|
|
20
|
+
id: "claude-fable-5",
|
|
21
|
+
label: "Fable 5",
|
|
22
|
+
description: "Fable 5 · Most powerful model",
|
|
23
|
+
thinkingOptions: [...CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS],
|
|
24
|
+
},
|
|
18
25
|
{
|
|
19
26
|
provider: "claude",
|
|
20
27
|
id: "claude-opus-4-8[1m]",
|
|
@@ -170,6 +177,14 @@ export function normalizeClaudeRuntimeModelId(value) {
|
|
|
170
177
|
if (CLAUDE_MODELS.some((model) => model.id === trimmed)) {
|
|
171
178
|
return trimmed;
|
|
172
179
|
}
|
|
180
|
+
// Fable uses a single-segment version (claude-fable-5), not the {major}-{minor}
|
|
181
|
+
// scheme of opus/sonnet/haiku, so match it separately. This maps dated runtime
|
|
182
|
+
// strings (e.g. claude-fable-5-20260301) back to the catalog ID. No [1m] variant:
|
|
183
|
+
// Fable 5 is natively 1M, so there is no 200K-default model to opt into 1M.
|
|
184
|
+
const fableMatch = trimmed.match(/(?:claude-)?fable[-_ ]+(\d+)/i);
|
|
185
|
+
if (fableMatch) {
|
|
186
|
+
return `claude-fable-${fableMatch[1]}`;
|
|
187
|
+
}
|
|
173
188
|
// Match: claude-{family}-{major}-{minor}[1m]? possibly followed by a date suffix
|
|
174
189
|
const runtimeMatch = trimmed.match(/(?:claude-)?(opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(\[1m\])?/i);
|
|
175
190
|
if (!runtimeMatch) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPersistenceHandle, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentPromptContentBlock, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentTimelineItem, type ToolCallTimelineItem, type AgentUsage, type
|
|
1
|
+
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPersistenceHandle, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentPromptContentBlock, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentTimelineItem, type ToolCallTimelineItem, type AgentUsage, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModelsOptions } from "../agent-sdk-types.js";
|
|
2
2
|
import type { Logger } from "pino";
|
|
3
3
|
import type { ChildProcessWithoutNullStreams } from "node:child_process";
|
|
4
4
|
import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
|
|
@@ -293,7 +293,8 @@ export declare class CodexAppServerAgentClient implements AgentClient {
|
|
|
293
293
|
sessionId: string;
|
|
294
294
|
metadata?: Record<string, unknown>;
|
|
295
295
|
}, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
296
|
-
|
|
296
|
+
listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
|
|
297
|
+
importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
|
|
297
298
|
listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
|
|
298
299
|
archiveNativeSession(handle: AgentPersistenceHandle): Promise<void>;
|
|
299
300
|
isAvailable(): Promise<boolean>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
|
|
2
|
+
import { importSessionFromPersistence } from "../provider-session-import.js";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
import * as fsSync from "node:fs";
|
|
@@ -94,6 +95,7 @@ function formatOutOfBandStatusMessage(text) {
|
|
|
94
95
|
const CODEX_APP_SERVER_CAPABILITIES = {
|
|
95
96
|
supportsStreaming: true,
|
|
96
97
|
supportsSessionPersistence: true,
|
|
98
|
+
supportsSessionListing: true,
|
|
97
99
|
supportsDynamicModes: false,
|
|
98
100
|
supportsMcpServers: true,
|
|
99
101
|
supportsReasoningStream: true,
|
|
@@ -431,6 +433,7 @@ async function listCodexCustomPrompts() {
|
|
|
431
433
|
name: `prompts:${name}`,
|
|
432
434
|
description,
|
|
433
435
|
argumentHint,
|
|
436
|
+
kind: "command",
|
|
434
437
|
};
|
|
435
438
|
}));
|
|
436
439
|
const commands = parsedCommands.filter((cmd) => cmd !== null);
|
|
@@ -482,6 +485,7 @@ export async function listCodexSkills(cwd, workspaceGitService) {
|
|
|
482
485
|
name,
|
|
483
486
|
description,
|
|
484
487
|
argumentHint: "",
|
|
488
|
+
kind: "skill",
|
|
485
489
|
});
|
|
486
490
|
}
|
|
487
491
|
}
|
|
@@ -580,10 +584,6 @@ function filterCodexThreadsByCwd(threads, cwd) {
|
|
|
580
584
|
const matchesCwd = createPathEquivalenceMatcher(cwd);
|
|
581
585
|
return threads.filter((thread) => typeof thread.cwd === "string" && matchesCwd(thread.cwd));
|
|
582
586
|
}
|
|
583
|
-
function buildCodexThreadListTimeline(thread) {
|
|
584
|
-
const preview = typeof thread.preview === "string" ? thread.preview.trim() : "";
|
|
585
|
-
return preview ? [{ type: "user_message", text: preview }] : [];
|
|
586
|
-
}
|
|
587
587
|
export function toAgentUsage(tokenUsage) {
|
|
588
588
|
const usage = toObjectRecord(tokenUsage);
|
|
589
589
|
if (!usage)
|
|
@@ -3006,6 +3006,7 @@ export class CodexAppServerAgentSession {
|
|
|
3006
3006
|
name: skill.name,
|
|
3007
3007
|
description: skill.description,
|
|
3008
3008
|
argumentHint: "",
|
|
3009
|
+
kind: "skill",
|
|
3009
3010
|
}));
|
|
3010
3011
|
const fallbackSkills = appServerSkills.length === 0
|
|
3011
3012
|
? await listCodexSkills(this.config.cwd, this.deps.workspaceGitService)
|
|
@@ -3015,6 +3016,7 @@ export class CodexAppServerAgentSession {
|
|
|
3015
3016
|
name: "compact",
|
|
3016
3017
|
description: "Summarize conversation to prevent hitting the context limit",
|
|
3017
3018
|
argumentHint: "",
|
|
3019
|
+
kind: "command",
|
|
3018
3020
|
},
|
|
3019
3021
|
];
|
|
3020
3022
|
if (this.goalsEnabled) {
|
|
@@ -3022,6 +3024,7 @@ export class CodexAppServerAgentSession {
|
|
|
3022
3024
|
name: "goal",
|
|
3023
3025
|
description: "Set, pause, resume, or clear the agent's goal",
|
|
3024
3026
|
argumentHint: "[<objective>|pause|resume|clear]",
|
|
3027
|
+
kind: "command",
|
|
3025
3028
|
});
|
|
3026
3029
|
}
|
|
3027
3030
|
return [...builtin, ...appServerSkills, ...fallbackSkills, ...prompts].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -4315,7 +4318,7 @@ export class CodexAppServerAgentClient {
|
|
|
4315
4318
|
await session.connect();
|
|
4316
4319
|
return session;
|
|
4317
4320
|
}
|
|
4318
|
-
async
|
|
4321
|
+
async listImportableSessions(options) {
|
|
4319
4322
|
const child = await this.spawnAppServer();
|
|
4320
4323
|
const client = this.deps._createCodexClient?.(child, this.logger, () => ({})) ??
|
|
4321
4324
|
new CodexAppServerClient(child, this.logger);
|
|
@@ -4333,39 +4336,35 @@ export class CodexAppServerAgentClient {
|
|
|
4333
4336
|
}));
|
|
4334
4337
|
const allThreads = Array.isArray(response?.data) ? response.data.filter(isRecord) : [];
|
|
4335
4338
|
const threads = filterCodexThreadsByCwd(allThreads, options?.cwd);
|
|
4336
|
-
|
|
4339
|
+
return threads.slice(0, limit).map((thread) => {
|
|
4337
4340
|
const threadId = typeof thread.id === "string" ? thread.id : "";
|
|
4338
4341
|
const cwd = typeof thread.cwd === "string" ? thread.cwd : process.cwd();
|
|
4339
4342
|
const preview = typeof thread.preview === "string" ? thread.preview : null;
|
|
4340
4343
|
const title = typeof thread.name === "string" && thread.name.trim() ? thread.name : preview;
|
|
4341
4344
|
return {
|
|
4342
|
-
|
|
4343
|
-
sessionId: threadId,
|
|
4345
|
+
providerHandleId: threadId,
|
|
4344
4346
|
cwd,
|
|
4345
4347
|
title,
|
|
4348
|
+
firstPromptPreview: preview,
|
|
4349
|
+
lastPromptPreview: preview,
|
|
4346
4350
|
lastActivityAt: new Date(((typeof thread.updatedAt === "number" ? thread.updatedAt : undefined) ??
|
|
4347
4351
|
(typeof thread.createdAt === "number" ? thread.createdAt : undefined) ??
|
|
4348
4352
|
0) * 1000),
|
|
4349
|
-
persistence: {
|
|
4350
|
-
provider: CODEX_PROVIDER,
|
|
4351
|
-
sessionId: threadId,
|
|
4352
|
-
nativeHandle: threadId,
|
|
4353
|
-
metadata: {
|
|
4354
|
-
provider: CODEX_PROVIDER,
|
|
4355
|
-
cwd,
|
|
4356
|
-
title,
|
|
4357
|
-
threadId,
|
|
4358
|
-
},
|
|
4359
|
-
},
|
|
4360
|
-
timeline: buildCodexThreadListTimeline(thread),
|
|
4361
4353
|
};
|
|
4362
4354
|
});
|
|
4363
|
-
return descriptors;
|
|
4364
4355
|
}
|
|
4365
4356
|
finally {
|
|
4366
4357
|
await client.dispose();
|
|
4367
4358
|
}
|
|
4368
4359
|
}
|
|
4360
|
+
async importSession(input, context) {
|
|
4361
|
+
return importSessionFromPersistence({
|
|
4362
|
+
provider: CODEX_PROVIDER,
|
|
4363
|
+
request: input,
|
|
4364
|
+
context,
|
|
4365
|
+
resumeSession: this.resumeSession.bind(this),
|
|
4366
|
+
});
|
|
4367
|
+
}
|
|
4369
4368
|
async listModels(_options) {
|
|
4370
4369
|
// Codex model/list is global to the app server in this flow; cwd/force are intentionally ignored.
|
|
4371
4370
|
const child = await this.spawnAppServer();
|