@getpaseo/server 0.1.91-beta.2 → 0.1.92
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/scripts/supervisor.js +21 -0
- package/dist/server/server/agent/agent-manager.d.ts +13 -5
- package/dist/server/server/agent/agent-manager.js +110 -74
- 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/prompt-attachments.js +8 -0
- package/dist/server/server/agent/provider-registry.d.ts +0 -1
- package/dist/server/server/agent/provider-registry.js +55 -16
- 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/codex-app-server-agent.d.ts +3 -2
- package/dist/server/server/agent/providers/codex-app-server-agent.js +29 -26
- 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 +3 -0
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +12 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts +18 -3
- package/dist/server/server/agent/providers/opencode-agent.js +135 -36
- package/dist/server/server/agent/providers/pi/agent.d.ts +25 -2
- package/dist/server/server/agent/providers/pi/agent.js +243 -14
- package/dist/server/server/agent/providers/pi/cli-runtime.js +9 -0
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +9 -0
- package/dist/server/server/agent/providers/pi/runtime.d.ts +2 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +11 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.js +284 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +8 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +22 -0
- package/dist/server/server/agent/runtime-mcp-config.d.ts +8 -0
- package/dist/server/server/agent/runtime-mcp-config.js +50 -0
- package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +2 -2
- package/dist/server/server/daemon-worker.js +84 -1
- package/dist/server/server/file-upload/index.d.ts +27 -0
- package/dist/server/server/file-upload/index.js +158 -0
- package/dist/server/server/loop-service.d.ts +12 -12
- package/dist/server/server/persisted-config.d.ts +8 -0
- package/dist/server/server/persisted-config.js +1 -1
- package/dist/server/server/persistence-hooks.js +6 -4
- package/dist/server/server/session.d.ts +5 -2
- package/dist/server/server/session.js +20 -3
- package/dist/server/server/speech/providers/local/runtime.js +1 -0
- package/dist/server/server/speech/providers/local/worker-client.d.ts +14 -1
- package/dist/server/server/speech/providers/local/worker-client.js +169 -7
- package/dist/server/server/websocket-server.d.ts +2 -0
- package/dist/server/server/websocket-server.js +20 -7
- package/dist/server/server/workspace-registry.d.ts +4 -4
- package/dist/src/server/persisted-config.js +1 -1
- package/package.json +5 -5
|
@@ -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) {
|
|
@@ -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";
|
|
@@ -34,6 +35,14 @@ const TURN_START_TIMEOUT_MS = 90 * 1000;
|
|
|
34
35
|
const INTERRUPT_TIMEOUT_MS = 2000;
|
|
35
36
|
const CODEX_PROVIDER = "codex";
|
|
36
37
|
const CODEX_IMAGE_ATTACHMENT_DIR = "paseo-attachments";
|
|
38
|
+
// Codex treats most app-server client names as the model-request originator.
|
|
39
|
+
// This reserved Codex name is non-originating, so requests keep Codex's default
|
|
40
|
+
// CLI identity instead of showing up as Paseo in provider usage logs.
|
|
41
|
+
const CODEX_NON_ORIGINATING_APP_SERVER_CLIENT_INFO = {
|
|
42
|
+
name: "codex_app_server_daemon",
|
|
43
|
+
title: "Codex App Server Daemon",
|
|
44
|
+
version: "0.0.0",
|
|
45
|
+
};
|
|
37
46
|
const ASSISTANT_MESSAGE_BOUNDARY_MARKDOWN = "\n\n---\n\n";
|
|
38
47
|
const CODEX_TOOL_THREAD_ITEM_TYPES = new Set([
|
|
39
48
|
"commandExecution",
|
|
@@ -86,6 +95,7 @@ function formatOutOfBandStatusMessage(text) {
|
|
|
86
95
|
const CODEX_APP_SERVER_CAPABILITIES = {
|
|
87
96
|
supportsStreaming: true,
|
|
88
97
|
supportsSessionPersistence: true,
|
|
98
|
+
supportsSessionListing: true,
|
|
89
99
|
supportsDynamicModes: false,
|
|
90
100
|
supportsMcpServers: true,
|
|
91
101
|
supportsReasoningStream: true,
|
|
@@ -423,6 +433,7 @@ async function listCodexCustomPrompts() {
|
|
|
423
433
|
name: `prompts:${name}`,
|
|
424
434
|
description,
|
|
425
435
|
argumentHint,
|
|
436
|
+
kind: "command",
|
|
426
437
|
};
|
|
427
438
|
}));
|
|
428
439
|
const commands = parsedCommands.filter((cmd) => cmd !== null);
|
|
@@ -474,6 +485,7 @@ export async function listCodexSkills(cwd, workspaceGitService) {
|
|
|
474
485
|
name,
|
|
475
486
|
description,
|
|
476
487
|
argumentHint: "",
|
|
488
|
+
kind: "skill",
|
|
477
489
|
});
|
|
478
490
|
}
|
|
479
491
|
}
|
|
@@ -572,10 +584,6 @@ function filterCodexThreadsByCwd(threads, cwd) {
|
|
|
572
584
|
const matchesCwd = createPathEquivalenceMatcher(cwd);
|
|
573
585
|
return threads.filter((thread) => typeof thread.cwd === "string" && matchesCwd(thread.cwd));
|
|
574
586
|
}
|
|
575
|
-
function buildCodexThreadListTimeline(thread) {
|
|
576
|
-
const preview = typeof thread.preview === "string" ? thread.preview.trim() : "";
|
|
577
|
-
return preview ? [{ type: "user_message", text: preview }] : [];
|
|
578
|
-
}
|
|
579
587
|
export function toAgentUsage(tokenUsage) {
|
|
580
588
|
const usage = toObjectRecord(tokenUsage);
|
|
581
589
|
if (!usage)
|
|
@@ -2093,11 +2101,7 @@ export function buildCodexAppServerEnv(runtimeSettings, launchEnv) {
|
|
|
2093
2101
|
}
|
|
2094
2102
|
function buildCodexAppServerInitializeParams() {
|
|
2095
2103
|
return {
|
|
2096
|
-
clientInfo:
|
|
2097
|
-
name: "paseo",
|
|
2098
|
-
title: "Paseo",
|
|
2099
|
-
version: "0.0.0",
|
|
2100
|
-
},
|
|
2104
|
+
clientInfo: CODEX_NON_ORIGINATING_APP_SERVER_CLIENT_INFO,
|
|
2101
2105
|
capabilities: {
|
|
2102
2106
|
experimentalApi: true,
|
|
2103
2107
|
},
|
|
@@ -3002,6 +3006,7 @@ export class CodexAppServerAgentSession {
|
|
|
3002
3006
|
name: skill.name,
|
|
3003
3007
|
description: skill.description,
|
|
3004
3008
|
argumentHint: "",
|
|
3009
|
+
kind: "skill",
|
|
3005
3010
|
}));
|
|
3006
3011
|
const fallbackSkills = appServerSkills.length === 0
|
|
3007
3012
|
? await listCodexSkills(this.config.cwd, this.deps.workspaceGitService)
|
|
@@ -3011,6 +3016,7 @@ export class CodexAppServerAgentSession {
|
|
|
3011
3016
|
name: "compact",
|
|
3012
3017
|
description: "Summarize conversation to prevent hitting the context limit",
|
|
3013
3018
|
argumentHint: "",
|
|
3019
|
+
kind: "command",
|
|
3014
3020
|
},
|
|
3015
3021
|
];
|
|
3016
3022
|
if (this.goalsEnabled) {
|
|
@@ -3018,6 +3024,7 @@ export class CodexAppServerAgentSession {
|
|
|
3018
3024
|
name: "goal",
|
|
3019
3025
|
description: "Set, pause, resume, or clear the agent's goal",
|
|
3020
3026
|
argumentHint: "[<objective>|pause|resume|clear]",
|
|
3027
|
+
kind: "command",
|
|
3021
3028
|
});
|
|
3022
3029
|
}
|
|
3023
3030
|
return [...builtin, ...appServerSkills, ...fallbackSkills, ...prompts].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -4311,7 +4318,7 @@ export class CodexAppServerAgentClient {
|
|
|
4311
4318
|
await session.connect();
|
|
4312
4319
|
return session;
|
|
4313
4320
|
}
|
|
4314
|
-
async
|
|
4321
|
+
async listImportableSessions(options) {
|
|
4315
4322
|
const child = await this.spawnAppServer();
|
|
4316
4323
|
const client = this.deps._createCodexClient?.(child, this.logger, () => ({})) ??
|
|
4317
4324
|
new CodexAppServerClient(child, this.logger);
|
|
@@ -4329,39 +4336,35 @@ export class CodexAppServerAgentClient {
|
|
|
4329
4336
|
}));
|
|
4330
4337
|
const allThreads = Array.isArray(response?.data) ? response.data.filter(isRecord) : [];
|
|
4331
4338
|
const threads = filterCodexThreadsByCwd(allThreads, options?.cwd);
|
|
4332
|
-
|
|
4339
|
+
return threads.slice(0, limit).map((thread) => {
|
|
4333
4340
|
const threadId = typeof thread.id === "string" ? thread.id : "";
|
|
4334
4341
|
const cwd = typeof thread.cwd === "string" ? thread.cwd : process.cwd();
|
|
4335
4342
|
const preview = typeof thread.preview === "string" ? thread.preview : null;
|
|
4336
4343
|
const title = typeof thread.name === "string" && thread.name.trim() ? thread.name : preview;
|
|
4337
4344
|
return {
|
|
4338
|
-
|
|
4339
|
-
sessionId: threadId,
|
|
4345
|
+
providerHandleId: threadId,
|
|
4340
4346
|
cwd,
|
|
4341
4347
|
title,
|
|
4348
|
+
firstPromptPreview: preview,
|
|
4349
|
+
lastPromptPreview: preview,
|
|
4342
4350
|
lastActivityAt: new Date(((typeof thread.updatedAt === "number" ? thread.updatedAt : undefined) ??
|
|
4343
4351
|
(typeof thread.createdAt === "number" ? thread.createdAt : undefined) ??
|
|
4344
4352
|
0) * 1000),
|
|
4345
|
-
persistence: {
|
|
4346
|
-
provider: CODEX_PROVIDER,
|
|
4347
|
-
sessionId: threadId,
|
|
4348
|
-
nativeHandle: threadId,
|
|
4349
|
-
metadata: {
|
|
4350
|
-
provider: CODEX_PROVIDER,
|
|
4351
|
-
cwd,
|
|
4352
|
-
title,
|
|
4353
|
-
threadId,
|
|
4354
|
-
},
|
|
4355
|
-
},
|
|
4356
|
-
timeline: buildCodexThreadListTimeline(thread),
|
|
4357
4353
|
};
|
|
4358
4354
|
});
|
|
4359
|
-
return descriptors;
|
|
4360
4355
|
}
|
|
4361
4356
|
finally {
|
|
4362
4357
|
await client.dispose();
|
|
4363
4358
|
}
|
|
4364
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
|
+
}
|
|
4365
4368
|
async listModels(_options) {
|
|
4366
4369
|
// Codex model/list is global to the app server in this flow; cwd/force are intentionally ignored.
|
|
4367
4370
|
const child = await this.spawnAppServer();
|
|
@@ -12,6 +12,7 @@ export class CursorACPAgentClient extends GenericACPAgentClient {
|
|
|
12
12
|
env: options.env,
|
|
13
13
|
providerId: options.providerId,
|
|
14
14
|
label: options.label,
|
|
15
|
+
providerParams: options.providerParams,
|
|
15
16
|
// cursor-agent publishes slash commands asynchronously via available_commands_update.
|
|
16
17
|
waitForInitialCommands: true,
|
|
17
18
|
initialCommandsWaitTimeoutMs: CURSOR_INITIAL_COMMANDS_WAIT_TIMEOUT_MS,
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
import { ACPAgentClient } from "./acp-agent.js";
|
|
4
|
+
export declare const GenericACPProviderParamsSchema: z.ZodObject<{
|
|
5
|
+
supportsMcpServers: z.ZodOptional<z.ZodBoolean>;
|
|
6
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
7
|
+
supportsMcpServers: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
9
|
+
supportsMcpServers: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
3
11
|
interface GenericACPAgentClientOptions {
|
|
4
12
|
logger: Logger;
|
|
5
13
|
command: [string, ...string[]];
|
|
6
14
|
env?: Record<string, string>;
|
|
7
15
|
providerId?: string;
|
|
8
16
|
label?: string;
|
|
17
|
+
providerParams?: unknown;
|
|
9
18
|
waitForInitialCommands?: boolean;
|
|
10
19
|
initialCommandsWaitTimeoutMs?: number;
|
|
11
20
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
import { checkProviderLaunchAvailable, resolveProviderLaunch } from "../provider-launch-config.js";
|
|
3
|
-
import { ACPAgentClient, deriveModelDefinitionsFromACP, deriveModesFromACP, } from "./acp-agent.js";
|
|
4
|
+
import { ACPAgentClient, DEFAULT_ACP_CAPABILITIES, deriveModelDefinitionsFromACP, deriveModesFromACP, } from "./acp-agent.js";
|
|
4
5
|
import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
|
|
5
6
|
const ACP_DIAGNOSTIC_INITIALIZE_TIMEOUT_MS = 8000;
|
|
6
7
|
const ACP_DIAGNOSTIC_SESSION_TIMEOUT_MS = 8000;
|
|
8
|
+
export const GenericACPProviderParamsSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
supportsMcpServers: z.boolean().optional(),
|
|
11
|
+
})
|
|
12
|
+
.passthrough();
|
|
7
13
|
export class GenericACPAgentClient extends ACPAgentClient {
|
|
8
14
|
constructor(options) {
|
|
9
15
|
super({
|
|
@@ -13,6 +19,7 @@ export class GenericACPAgentClient extends ACPAgentClient {
|
|
|
13
19
|
env: options.env,
|
|
14
20
|
},
|
|
15
21
|
defaultCommand: options.command,
|
|
22
|
+
capabilities: buildGenericACPCapabilities(options),
|
|
16
23
|
waitForInitialCommands: options.waitForInitialCommands,
|
|
17
24
|
initialCommandsWaitTimeoutMs: options.initialCommandsWaitTimeoutMs,
|
|
18
25
|
});
|
|
@@ -128,6 +135,16 @@ export class GenericACPAgentClient extends ACPAgentClient {
|
|
|
128
135
|
}
|
|
129
136
|
}
|
|
130
137
|
}
|
|
138
|
+
function buildGenericACPCapabilities(options) {
|
|
139
|
+
const params = parseGenericACPProviderParams(options.providerParams);
|
|
140
|
+
return {
|
|
141
|
+
...DEFAULT_ACP_CAPABILITIES,
|
|
142
|
+
supportsMcpServers: params.supportsMcpServers ?? DEFAULT_ACP_CAPABILITIES.supportsMcpServers,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function parseGenericACPProviderParams(params) {
|
|
146
|
+
return GenericACPProviderParamsSchema.parse(params ?? {});
|
|
147
|
+
}
|
|
131
148
|
function formatProviderName(label, providerId) {
|
|
132
149
|
if (label) {
|
|
133
150
|
return `${label} (ACP)`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
|
-
import type { AgentCapabilityFlags, AgentClient, AgentFeature, AgentLaunchContext, AgentMode, AgentModelDefinition, AgentPersistenceHandle, AgentPermissionRequest, AgentPermissionResponse, AgentPermissionResult, AgentPromptInput, AgentProvider, AgentRunOptions, AgentRunResult, AgentRuntimeInfo, AgentSession, AgentSessionConfig, AgentStreamEvent,
|
|
2
|
+
import type { AgentCapabilityFlags, AgentClient, AgentFeature, AgentLaunchContext, AgentMode, AgentModelDefinition, AgentPersistenceHandle, AgentPermissionRequest, AgentPermissionResponse, AgentPermissionResult, AgentPromptInput, AgentProvider, AgentRunOptions, AgentRunResult, AgentRuntimeInfo, AgentSession, AgentSessionConfig, AgentStreamEvent, ImportableProviderSession, ImportProviderSessionContext, ImportProviderSessionInput, ListModesOptions, ListModelsOptions } from "../agent-sdk-types.js";
|
|
3
3
|
export declare const MOCK_LOAD_TEST_PROVIDER_ID = "mock";
|
|
4
4
|
export declare const MOCK_LOAD_TEST_DEFAULT_MODEL_ID = "five-minute-stream";
|
|
5
5
|
export declare class MockLoadTestAgentClient implements AgentClient {
|
|
@@ -11,7 +11,8 @@ export declare class MockLoadTestAgentClient implements AgentClient {
|
|
|
11
11
|
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, _launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
12
12
|
listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
|
|
13
13
|
listModes(_options: ListModesOptions): Promise<AgentMode[]>;
|
|
14
|
-
|
|
14
|
+
listImportableSessions(): Promise<ImportableProviderSession[]>;
|
|
15
|
+
importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
|
|
15
16
|
isAvailable(): Promise<boolean>;
|
|
16
17
|
getDiagnostic(): Promise<{
|
|
17
18
|
diagnostic: string;
|