@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.
Files changed (60) hide show
  1. package/dist/scripts/supervisor.js +21 -0
  2. package/dist/server/server/agent/agent-manager.d.ts +13 -5
  3. package/dist/server/server/agent/agent-manager.js +110 -74
  4. package/dist/server/server/agent/agent-projections.d.ts +4 -2
  5. package/dist/server/server/agent/agent-projections.js +8 -28
  6. package/dist/server/server/agent/agent-sdk-types.d.ts +30 -10
  7. package/dist/server/server/agent/import-sessions.d.ts +3 -2
  8. package/dist/server/server/agent/import-sessions.js +23 -55
  9. package/dist/server/server/agent/prompt-attachments.js +8 -0
  10. package/dist/server/server/agent/provider-registry.d.ts +0 -1
  11. package/dist/server/server/agent/provider-registry.js +55 -16
  12. package/dist/server/server/agent/provider-session-import.d.ts +10 -0
  13. package/dist/server/server/agent/provider-session-import.js +49 -0
  14. package/dist/server/server/agent/providers/acp-agent.d.ts +12 -2
  15. package/dist/server/server/agent/providers/acp-agent.js +78 -36
  16. package/dist/server/server/agent/providers/claude/agent.d.ts +3 -2
  17. package/dist/server/server/agent/providers/claude/agent.js +28 -24
  18. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +3 -2
  19. package/dist/server/server/agent/providers/codex-app-server-agent.js +29 -26
  20. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +1 -0
  21. package/dist/server/server/agent/providers/cursor-acp-agent.js +1 -0
  22. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +9 -0
  23. package/dist/server/server/agent/providers/generic-acp-agent.js +18 -1
  24. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +3 -2
  25. package/dist/server/server/agent/providers/mock-load-test-agent.js +11 -1
  26. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +1 -2
  27. package/dist/server/server/agent/providers/mock-slow-provider.js +0 -3
  28. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +3 -0
  29. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +12 -0
  30. package/dist/server/server/agent/providers/opencode-agent.d.ts +18 -3
  31. package/dist/server/server/agent/providers/opencode-agent.js +135 -36
  32. package/dist/server/server/agent/providers/pi/agent.d.ts +25 -2
  33. package/dist/server/server/agent/providers/pi/agent.js +243 -14
  34. package/dist/server/server/agent/providers/pi/cli-runtime.js +9 -0
  35. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +9 -0
  36. package/dist/server/server/agent/providers/pi/runtime.d.ts +2 -0
  37. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +11 -0
  38. package/dist/server/server/agent/providers/pi/session-descriptor.js +284 -0
  39. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +8 -0
  40. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +22 -0
  41. package/dist/server/server/agent/runtime-mcp-config.d.ts +8 -0
  42. package/dist/server/server/agent/runtime-mcp-config.js +50 -0
  43. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +2 -2
  44. package/dist/server/server/daemon-worker.js +84 -1
  45. package/dist/server/server/file-upload/index.d.ts +27 -0
  46. package/dist/server/server/file-upload/index.js +158 -0
  47. package/dist/server/server/loop-service.d.ts +12 -12
  48. package/dist/server/server/persisted-config.d.ts +8 -0
  49. package/dist/server/server/persisted-config.js +1 -1
  50. package/dist/server/server/persistence-hooks.js +6 -4
  51. package/dist/server/server/session.d.ts +5 -2
  52. package/dist/server/server/session.js +20 -3
  53. package/dist/server/server/speech/providers/local/runtime.js +1 -0
  54. package/dist/server/server/speech/providers/local/worker-client.d.ts +14 -1
  55. package/dist/server/server/speech/providers/local/worker-client.js +169 -7
  56. package/dist/server/server/websocket-server.d.ts +2 -0
  57. package/dist/server/server/websocket-server.js +20 -7
  58. package/dist/server/server/workspace-registry.d.ts +4 -4
  59. package/dist/src/server/persisted-config.js +1 -1
  60. 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 summarizeACPRequestError(error) {
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: error.message,
43
+ message,
29
44
  code,
30
- diagnostic: `${error.message} | code=${code}${data}`,
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 listPersistedAgents(options) {
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
- provider: this.provider,
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: normalizeMcpServers(this.config.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: normalizeMcpServers(this.config.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: normalizeMcpServers(this.config.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 ListModelsOptions, type ListPersistedAgentsOptions, type McpServerConfig, type PersistedAgentDescriptor } from "../../agent-sdk-types.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 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
- listPersistedAgents(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
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 listPersistedAgents(options) {
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((descriptor) => descriptor !== null)
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
- acc.timeline.push({ type: "user_message", text });
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
- timeline: [],
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, timeline } = acc;
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
- provider: "claude",
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 ListModelsOptions, type ListPersistedAgentsOptions, type PersistedAgentDescriptor } from "../agent-sdk-types.js";
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
- listPersistedAgents(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
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 listPersistedAgents(options) {
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
- const descriptors = threads.slice(0, limit).map((thread) => {
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
- provider: CODEX_PROVIDER,
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();
@@ -7,6 +7,7 @@ interface CursorACPAgentClientOptions {
7
7
  env?: Record<string, string>;
8
8
  providerId?: string;
9
9
  label?: string;
10
+ providerParams?: unknown;
10
11
  }
11
12
  export declare class CursorACPAgentClient extends GenericACPAgentClient {
12
13
  private readonly cursorCommand;
@@ -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, ListModesOptions, ListModelsOptions, ListPersistedAgentsOptions, PersistedAgentDescriptor } from "../agent-sdk-types.js";
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
- listPersistedAgents(_options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
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;