@getpaseo/server 0.1.91 → 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 (34) hide show
  1. package/dist/server/server/agent/agent-manager.d.ts +12 -4
  2. package/dist/server/server/agent/agent-manager.js +87 -26
  3. package/dist/server/server/agent/agent-projections.d.ts +4 -2
  4. package/dist/server/server/agent/agent-projections.js +8 -28
  5. package/dist/server/server/agent/agent-sdk-types.d.ts +30 -10
  6. package/dist/server/server/agent/import-sessions.d.ts +3 -2
  7. package/dist/server/server/agent/import-sessions.js +23 -55
  8. package/dist/server/server/agent/provider-registry.js +34 -13
  9. package/dist/server/server/agent/provider-session-import.d.ts +10 -0
  10. package/dist/server/server/agent/provider-session-import.js +49 -0
  11. package/dist/server/server/agent/providers/acp-agent.d.ts +12 -2
  12. package/dist/server/server/agent/providers/acp-agent.js +78 -36
  13. package/dist/server/server/agent/providers/claude/agent.d.ts +3 -2
  14. package/dist/server/server/agent/providers/claude/agent.js +28 -24
  15. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +3 -2
  16. package/dist/server/server/agent/providers/codex-app-server-agent.js +20 -21
  17. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +1 -0
  18. package/dist/server/server/agent/providers/cursor-acp-agent.js +1 -0
  19. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +9 -0
  20. package/dist/server/server/agent/providers/generic-acp-agent.js +18 -1
  21. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +3 -2
  22. package/dist/server/server/agent/providers/mock-load-test-agent.js +11 -1
  23. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +1 -2
  24. package/dist/server/server/agent/providers/mock-slow-provider.js +0 -3
  25. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +2 -0
  26. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +8 -0
  27. package/dist/server/server/agent/providers/opencode-agent.d.ts +3 -2
  28. package/dist/server/server/agent/providers/opencode-agent.js +60 -32
  29. package/dist/server/server/agent/providers/pi/agent.d.ts +3 -2
  30. package/dist/server/server/agent/providers/pi/agent.js +28 -5
  31. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +3 -4
  32. package/dist/server/server/agent/providers/pi/session-descriptor.js +17 -37
  33. package/dist/server/server/session.js +0 -1
  34. package/package.json +5 -5
@@ -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;
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { importSessionFromPersistence } from "../provider-session-import.js";
2
3
  import { getAgentProviderDefinition } from "@getpaseo/protocol/provider-manifest";
3
4
  export const MOCK_LOAD_TEST_PROVIDER_ID = "mock";
4
5
  export const MOCK_LOAD_TEST_DEFAULT_MODEL_ID = "five-minute-stream";
@@ -8,6 +9,7 @@ const MOCK_LOAD_TEST_INTERVAL_MS = 40;
8
9
  const CAPABILITIES = {
9
10
  supportsStreaming: true,
10
11
  supportsSessionPersistence: true,
12
+ supportsSessionListing: true,
11
13
  supportsDynamicModes: false,
12
14
  supportsMcpServers: false,
13
15
  supportsReasoningStream: true,
@@ -308,9 +310,17 @@ export class MockLoadTestAgentClient {
308
310
  async listModes(_options) {
309
311
  return getAgentProviderDefinition(MOCK_LOAD_TEST_PROVIDER_ID).modes;
310
312
  }
311
- async listPersistedAgents(_options) {
313
+ async listImportableSessions() {
312
314
  return [];
313
315
  }
316
+ async importSession(input, context) {
317
+ return importSessionFromPersistence({
318
+ provider: MOCK_LOAD_TEST_PROVIDER_ID,
319
+ request: input,
320
+ context,
321
+ resumeSession: this.resumeSession.bind(this),
322
+ });
323
+ }
314
324
  async isAvailable() {
315
325
  return true;
316
326
  }
@@ -1,4 +1,4 @@
1
- import type { AgentCapabilityFlags, AgentClient, AgentLaunchContext, AgentMode, AgentModelDefinition, AgentPersistenceHandle, AgentProvider, AgentSession, AgentSessionConfig, ListModelsOptions, ListModesOptions, ListPersistedAgentsOptions, PersistedAgentDescriptor } from "../agent-sdk-types.js";
1
+ import type { AgentCapabilityFlags, AgentClient, AgentLaunchContext, AgentMode, AgentModelDefinition, AgentPersistenceHandle, AgentProvider, AgentSession, AgentSessionConfig, ListModelsOptions, ListModesOptions } from "../agent-sdk-types.js";
2
2
  export declare const MOCK_SLOW_PROVIDER_ID = "mock-slow";
3
3
  export declare class MockSlowProviderClient implements AgentClient {
4
4
  readonly provider: AgentProvider;
@@ -6,7 +6,6 @@ export declare class MockSlowProviderClient implements AgentClient {
6
6
  isAvailable(): Promise<boolean>;
7
7
  listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
8
8
  listModes(_options: ListModesOptions): Promise<AgentMode[]>;
9
- listPersistedAgents(_options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
10
9
  getDiagnostic(): Promise<{
11
10
  diagnostic: string;
12
11
  }>;
@@ -27,9 +27,6 @@ export class MockSlowProviderClient {
27
27
  listModes(_options) {
28
28
  return neverResolves();
29
29
  }
30
- async listPersistedAgents(_options) {
31
- return [];
32
- }
33
30
  async getDiagnostic() {
34
31
  return {
35
32
  diagnostic: "Mock slow provider: dev-only. listModels() never resolves so the snapshot manager will time out.",
@@ -51,6 +51,7 @@ export declare class TestOpenCodeClient {
51
51
  sessionCommand: unknown[];
52
52
  sessionCreate: unknown[];
53
53
  sessionDelete: unknown[];
54
+ sessionGet: unknown[];
54
55
  sessionMessages: unknown[];
55
56
  sessionPromptAsync: unknown[];
56
57
  sessionSummarize: unknown[];
@@ -73,6 +74,7 @@ export declare class TestOpenCodeClient {
73
74
  sessionCommandResponse: OpenCodeResponse;
74
75
  sessionCreateResponse: OpenCodeResponse;
75
76
  sessionDeleteResponse: OpenCodeResponse;
77
+ sessionGetResponse: OpenCodeResponse;
76
78
  sessionMessagesResponse: OpenCodeResponse;
77
79
  sessionPromptAsyncEvents: unknown[];
78
80
  sessionPromptAsyncResponse: OpenCodeResponse;
@@ -46,6 +46,7 @@ export class TestOpenCodeClient {
46
46
  sessionCommand: [],
47
47
  sessionCreate: [],
48
48
  sessionDelete: [],
49
+ sessionGet: [],
49
50
  sessionMessages: [],
50
51
  sessionPromptAsync: [],
51
52
  sessionSummarize: [],
@@ -67,6 +68,9 @@ export class TestOpenCodeClient {
67
68
  this.sessionCommandResponse = {};
68
69
  this.sessionCreateResponse = { data: { id: "session-1" } };
69
70
  this.sessionDeleteResponse = {};
71
+ this.sessionGetResponse = {
72
+ data: { id: "session-1", directory: "/workspace/repo", title: null },
73
+ };
70
74
  this.sessionMessagesResponse = { data: [] };
71
75
  this.sessionPromptAsyncEvents = [idleEvent()];
72
76
  this.sessionPromptAsyncResponse = {};
@@ -170,6 +174,10 @@ export class TestOpenCodeClient {
170
174
  this.calls.sessionDelete.push(parameters);
171
175
  return this.sessionDeleteResponse;
172
176
  },
177
+ get: async (parameters) => {
178
+ this.calls.sessionGet.push(parameters);
179
+ return this.sessionGetResponse;
180
+ },
173
181
  messages: async (parameters) => {
174
182
  this.calls.sessionMessages.push(parameters);
175
183
  return this.sessionMessagesResponse;
@@ -1,6 +1,6 @@
1
1
  import { type AssistantMessage as OpenCodeAssistantMessage, type Event as OpenCodeEvent, type FilePartInput as OpenCodeFilePartInput, type Message as OpenCodeMessage, type OpencodeClient, type Part as OpenCodePart, type TextPartInput as OpenCodeTextPartInput } from "@opencode-ai/sdk/v2/client";
2
2
  import type { Logger } from "pino";
3
- import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, 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 AgentTimelineItem, type AgentUsage, type ResolveAgentCreateConfigInput, type ResolveAgentCreateConfigResult, type ListModelsOptions, type ListModesOptions, type ListPersistedAgentsOptions, type PersistedAgentDescriptor, type ToolCallTimelineItem } from "../agent-sdk-types.js";
3
+ import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, 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 AgentTimelineItem, type AgentUsage, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ResolveAgentCreateConfigInput, type ResolveAgentCreateConfigResult, type ListModelsOptions, type ListModesOptions, type ToolCallTimelineItem } from "../agent-sdk-types.js";
4
4
  import { isDefaultAgentCreateConfigUnattended } from "../create-agent-mode.js";
5
5
  import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
6
6
  import { type OpenCodeRuntime } from "./opencode/runtime.js";
@@ -120,7 +120,8 @@ export declare class OpenCodeAgentClient implements AgentClient {
120
120
  listModes(options: ListModesOptions): Promise<AgentMode[]>;
121
121
  listCommands(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
122
122
  listFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
123
- listPersistedAgents(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
123
+ listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
124
+ importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
124
125
  isAvailable(): Promise<boolean>;
125
126
  shutdown(): Promise<void>;
126
127
  getDiagnostic(): Promise<{
@@ -3,6 +3,7 @@ import { createPathEquivalenceMatcher } from "../../../utils/path.js";
3
3
  import pLimit from "p-limit";
4
4
  import { z } from "zod";
5
5
  import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
6
+ import { importSessionFromPersistence } from "../provider-session-import.js";
6
7
  import { isDefaultAgentCreateConfigUnattended, resolveDefaultAgentCreateConfig, } from "../create-agent-mode.js";
7
8
  import { checkProviderLaunchAvailable, createProviderEnvSpec, resolveProviderLaunch, } from "../provider-launch-config.js";
8
9
  import { withTimeout } from "../../../utils/promise-timeout.js";
@@ -20,6 +21,7 @@ import { revertOpenCodeConversationAndFiles } from "./opencode/rewind.js";
20
21
  const OPENCODE_CAPABILITIES = {
21
22
  supportsStreaming: true,
22
23
  supportsSessionPersistence: true,
24
+ supportsSessionListing: true,
23
25
  supportsDynamicModes: true,
24
26
  supportsMcpServers: true,
25
27
  supportsReasoningStream: true,
@@ -135,8 +137,18 @@ const OPENCODE_PROVIDER_LIST_TIMEOUT_MS = 30000;
135
137
  const OPENCODE_METADATA_CONCURRENCY = 4;
136
138
  const openCodeMetadataLimit = pLimit(OPENCODE_METADATA_CONCURRENCY);
137
139
  const OPENCODE_HANDLED_BUILTIN_SLASH_COMMANDS = [
138
- { name: "compact", description: "Compact the current session", argumentHint: "" },
139
- { name: "summarize", description: "Compact the current session", argumentHint: "" },
140
+ {
141
+ name: "compact",
142
+ description: "Compact the current session",
143
+ argumentHint: "",
144
+ kind: "command",
145
+ },
146
+ {
147
+ name: "summarize",
148
+ description: "Compact the current session",
149
+ argumentHint: "",
150
+ kind: "command",
151
+ },
140
152
  ];
141
153
  const OPENCODE_HEADERS_TIMEOUT_TOKENS = [
142
154
  "headers timeout",
@@ -616,7 +628,7 @@ function buildOpenCodeUserTimelineText(prompt) {
616
628
  .filter((text) => text.trim().length > 0)
617
629
  .join("\n");
618
630
  }
619
- async function collectOpenCodePersistedAgentsFromSdk(client, options) {
631
+ async function collectOpenCodeImportableSessionsFromSdk(client, options) {
620
632
  const limit = options?.limit ?? OPENCODE_PERSISTED_SESSION_LIMIT;
621
633
  const sessionListLimit = options?.cwd ? Math.max(limit, OPENCODE_PERSISTED_SESSION_LIMIT) : limit;
622
634
  const response = await client.experimental.session.list({
@@ -627,39 +639,19 @@ async function collectOpenCodePersistedAgentsFromSdk(client, options) {
627
639
  if (response.error) {
628
640
  throw new Error(`Failed to list OpenCode sessions: ${JSON.stringify(response.error)}`);
629
641
  }
630
- const sessions = response.data ?? [];
631
642
  const matchesCwd = options?.cwd ? createPathEquivalenceMatcher(options.cwd) : null;
632
- const candidates = sessions
643
+ return (response.data ?? [])
633
644
  .filter((session) => !matchesCwd || matchesCwd(session.directory))
634
645
  .sort((left, right) => getOpenCodeSessionTimestamp(right) - getOpenCodeSessionTimestamp(left))
635
- .slice(0, limit);
636
- return await Promise.all(candidates.map((session) => buildOpenCodePersistedAgentDescriptor(client, session)));
637
- }
638
- async function buildOpenCodePersistedAgentDescriptor(client, session) {
639
- const messages = await readOpenCodeSessionMessagesFromSdk(client, session);
640
- const timeline = buildOpenCodeSessionTimeline(messages);
641
- const modeId = resolveOpenCodePersistedSessionModeId(session, messages);
642
- const model = resolveOpenCodePersistedSessionModel(session, messages);
643
- return {
644
- provider: "opencode",
645
- sessionId: session.id,
646
+ .slice(0, limit)
647
+ .map((session) => ({
648
+ providerHandleId: session.id,
646
649
  cwd: session.directory,
647
650
  title: normalizeOpenCodeSessionTitle(session.title),
651
+ firstPromptPreview: null,
652
+ lastPromptPreview: null,
648
653
  lastActivityAt: new Date(getOpenCodeSessionTimestamp(session)),
649
- persistence: {
650
- provider: "opencode",
651
- sessionId: session.id,
652
- nativeHandle: session.id,
653
- metadata: {
654
- provider: "opencode",
655
- cwd: session.directory,
656
- title: normalizeOpenCodeSessionTitle(session.title),
657
- ...(modeId ? { modeId } : {}),
658
- ...(model ? { model } : {}),
659
- },
660
- },
661
- timeline,
662
- };
654
+ }));
663
655
  }
664
656
  function normalizeOpenCodeSessionTitle(title) {
665
657
  const normalized = title?.trim();
@@ -1033,7 +1025,7 @@ export class OpenCodeAgentClient {
1033
1025
  async listFeatures(config) {
1034
1026
  return [buildOpenCodeAutoAcceptFeature(this.assertConfig(config))];
1035
1027
  }
1036
- async listPersistedAgents(options) {
1028
+ async listImportableSessions(options) {
1037
1029
  const acquisition = await this.runtime.acquireServer({ force: false });
1038
1030
  const { url } = acquisition.server;
1039
1031
  const client = this.runtime.createClient({
@@ -1041,7 +1033,42 @@ export class OpenCodeAgentClient {
1041
1033
  directory: options?.cwd ?? "",
1042
1034
  });
1043
1035
  try {
1044
- return await collectOpenCodePersistedAgentsFromSdk(client, options);
1036
+ return await collectOpenCodeImportableSessionsFromSdk(client, options);
1037
+ }
1038
+ finally {
1039
+ acquisition.release();
1040
+ }
1041
+ }
1042
+ async importSession(input, context) {
1043
+ const acquisition = await this.runtime.acquireServer({ force: false });
1044
+ const { url } = acquisition.server;
1045
+ const client = this.runtime.createClient({
1046
+ baseUrl: url,
1047
+ directory: input.cwd,
1048
+ });
1049
+ try {
1050
+ const sessionResponse = await client.session.get({
1051
+ sessionID: input.providerHandleId,
1052
+ directory: input.cwd,
1053
+ });
1054
+ if (sessionResponse.error || !sessionResponse.data) {
1055
+ throw new Error(`Failed to load OpenCode session ${input.providerHandleId}`);
1056
+ }
1057
+ const session = sessionResponse.data;
1058
+ const messages = await readOpenCodeSessionMessagesFromSdk(client, session);
1059
+ const modeId = resolveOpenCodePersistedSessionModeId(session, messages);
1060
+ const model = resolveOpenCodePersistedSessionModel(session, messages);
1061
+ return await importSessionFromPersistence({
1062
+ provider: "opencode",
1063
+ request: input,
1064
+ context,
1065
+ resumeSession: this.resumeSession.bind(this),
1066
+ config: {
1067
+ title: normalizeOpenCodeSessionTitle(session.title) ?? undefined,
1068
+ ...(modeId ? { modeId } : {}),
1069
+ ...(model ? { model } : {}),
1070
+ },
1071
+ });
1045
1072
  }
1046
1073
  finally {
1047
1074
  acquisition.release();
@@ -1179,6 +1206,7 @@ async function listOpenCodeCommandsFromSdk(client, directory) {
1179
1206
  name: cmd.name,
1180
1207
  description: cmd.description ?? "",
1181
1208
  argumentHint: cmd.hints?.length ? cmd.hints.join(" ") : "",
1209
+ kind: cmd.source === "skill" ? "skill" : "command",
1182
1210
  });
1183
1211
  }
1184
1212
  return Array.from(commandsByName.values());
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from "pino";
2
2
  import { z } from "zod";
3
- 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 ListPersistedAgentsOptions, type ListModesOptions, type ListModelsOptions, type PersistedAgentDescriptor } from "../../agent-sdk-types.js";
3
+ 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 ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModesOptions, type ListModelsOptions } from "../../agent-sdk-types.js";
4
4
  import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
5
5
  import type { PiRuntime, PiRuntimeSession } from "./runtime.js";
6
6
  import type { PiSessionState } from "./rpc-types.js";
@@ -118,7 +118,8 @@ export declare class PiRpcAgentClient implements AgentClient {
118
118
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, _launchContext?: AgentLaunchContext): Promise<AgentSession>;
119
119
  listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
120
120
  listModes(_options: ListModesOptions): Promise<AgentMode[]>;
121
- listPersistedAgents(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
121
+ listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
122
+ importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../../agent-sdk-types.js").ImportedProviderSession>;
122
123
  isAvailable(): Promise<boolean>;
123
124
  getDiagnostic(): Promise<{
124
125
  diagnostic: string;
@@ -3,6 +3,7 @@ import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { homedir, tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { z } from "zod";
6
+ import { importSessionFromPersistence } from "../../provider-session-import.js";
6
7
  import { runProviderTurn } from "../provider-runner.js";
7
8
  import { checkProviderLaunchAvailable, resolveProviderLaunch, } from "../../provider-launch-config.js";
8
9
  import { renderPromptAttachmentAsText } from "../../prompt-attachments.js";
@@ -11,7 +12,7 @@ import { buildBinaryDiagnosticRows, formatDiagnosticStatus, formatProviderDiagno
11
12
  import { getUserMessageText, streamPiHistory, } from "./history-mapper.js";
12
13
  import { PiCliRuntime } from "./cli-runtime.js";
13
14
  import { revertPiConversation } from "./rewind.js";
14
- import { listPiPersistedAgents } from "./session-descriptor.js";
15
+ import { listPiImportableSessions } from "./session-descriptor.js";
15
16
  import { mapToolDetail, parseToolArgs, parseToolResult, resolveToolCallName, } from "./tool-call-mapper.js";
16
17
  const PI_PROVIDER = "pi";
17
18
  const DEFAULT_PI_THINKING_LEVEL = "medium";
@@ -35,16 +36,25 @@ const PI_HANDLED_BUILTIN_SLASH_COMMANDS = [
35
36
  name: "compact",
36
37
  description: "Manually compact the session context",
37
38
  argumentHint: "[instructions]",
39
+ kind: "command",
38
40
  },
39
41
  {
40
42
  name: "autocompact",
41
43
  description: "Toggle automatic context compaction",
42
44
  argumentHint: "[on|off|toggle]",
45
+ kind: "command",
43
46
  },
44
47
  ];
48
+ function mapPiCommandKind(source) {
49
+ if (source === "skill") {
50
+ return "skill";
51
+ }
52
+ return "command";
53
+ }
45
54
  const PI_CAPABILITIES = {
46
55
  supportsStreaming: true,
47
56
  supportsSessionPersistence: true,
57
+ supportsSessionListing: true,
48
58
  supportsDynamicModes: true,
49
59
  supportsMcpServers: false,
50
60
  supportsReasoningStream: true,
@@ -62,7 +72,12 @@ const PI_THINKING_OPTIONS = [
62
72
  { id: "xhigh", label: "XHigh", description: "Maximum reasoning" },
63
73
  ];
64
74
  function normalizePiModelLabel(label) {
65
- return label.trim().replace(/[_\s]+/g, " ");
75
+ const normalizedLabel = label.trim().replace(/[_\s]+/g, " ");
76
+ const vendorSeparatorIndex = normalizedLabel.indexOf(": ");
77
+ if (vendorSeparatorIndex === -1) {
78
+ return normalizedLabel;
79
+ }
80
+ return normalizedLabel.slice(vendorSeparatorIndex + 2).trim();
66
81
  }
67
82
  export function transformPiModels(models) {
68
83
  return models.map((model) => {
@@ -863,6 +878,7 @@ export class PiRpcAgentSession {
863
878
  name: command.name,
864
879
  description: command.description ?? command.source,
865
880
  argumentHint: knownCommand?.argumentHint ?? "",
881
+ kind: mapPiCommandKind(command.source),
866
882
  });
867
883
  }
868
884
  return [...mappedCommands.values()];
@@ -1533,14 +1549,21 @@ export class PiRpcAgentClient {
1533
1549
  async listModes(_options) {
1534
1550
  return [];
1535
1551
  }
1536
- async listPersistedAgents(options) {
1537
- return await listPiPersistedAgents({
1552
+ async listImportableSessions(options) {
1553
+ return await listPiImportableSessions({
1538
1554
  ...options,
1539
- provider: PI_PROVIDER,
1540
1555
  sessionDir: this.providerParams.sessionDir,
1541
1556
  runtimeSettings: this.runtimeSettings,
1542
1557
  });
1543
1558
  }
1559
+ async importSession(input, context) {
1560
+ return importSessionFromPersistence({
1561
+ provider: PI_PROVIDER,
1562
+ request: input,
1563
+ context,
1564
+ resumeSession: this.resumeSession.bind(this),
1565
+ });
1566
+ }
1544
1567
  async isAvailable() {
1545
1568
  const launch = await this.resolvePiLaunch();
1546
1569
  const availability = await checkProviderLaunchAvailable(launch);
@@ -1,12 +1,11 @@
1
- import type { ListPersistedAgentsOptions, PersistedAgentDescriptor } from "../../agent-sdk-types.js";
1
+ import type { ImportableProviderSession, ListImportableSessionsOptions } from "../../agent-sdk-types.js";
2
2
  import type { ProviderRuntimeSettings } from "../../provider-launch-config.js";
3
- interface PiSessionDescriptorOptions extends ListPersistedAgentsOptions {
4
- provider?: string;
3
+ interface PiSessionDescriptorOptions extends ListImportableSessionsOptions {
5
4
  sessionDir?: string;
6
5
  runtimeSettings?: ProviderRuntimeSettings;
7
6
  env?: NodeJS.ProcessEnv;
8
7
  homeDir?: string;
9
8
  }
10
- export declare function listPiPersistedAgents(options?: PiSessionDescriptorOptions): Promise<PersistedAgentDescriptor[]>;
9
+ export declare function listPiImportableSessions(options?: PiSessionDescriptorOptions): Promise<ImportableProviderSession[]>;
11
10
  export {};
12
11
  //# sourceMappingURL=session-descriptor.d.ts.map
@@ -2,29 +2,27 @@ import { open, readdir, readFile, stat } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import path from "node:path";
4
4
  import { createRealpathAwarePathMatcher } from "../../../../utils/path.js";
5
- const PI_PROVIDER = "pi";
6
5
  const PI_CONFIG_DIR_NAME = ".pi";
7
6
  const PI_AGENT_DIR_ENV = "PI_CODING_AGENT_DIR";
8
7
  const PI_SESSION_DIR_ENV = "PI_CODING_AGENT_SESSION_DIR";
9
8
  const HEAD_BYTES = 64 * 1024;
10
9
  const TAIL_BYTES = 256 * 1024;
11
10
  const FULL_SCAN_LINE_LIMIT = 2000;
12
- export async function listPiPersistedAgents(options = {}) {
13
- const provider = options.provider ?? PI_PROVIDER;
11
+ export async function listPiImportableSessions(options = {}) {
14
12
  const sessionsDir = await resolvePiSessionsDir(options);
15
13
  const files = await walkJsonlFiles(sessionsDir);
16
14
  const matchesCwd = options.cwd ? createRealpathAwarePathMatcher(options.cwd) : null;
17
15
  const limit = options.limit ?? 20;
18
- const descriptors = [];
16
+ const sessions = [];
19
17
  for (const file of files) {
20
- const descriptor = await readPiSessionDescriptor(file, provider);
21
- if (!descriptor)
18
+ const session = await readPiImportableSession(file);
19
+ if (!session)
22
20
  continue;
23
- if (matchesCwd && !matchesCwd(descriptor.cwd))
21
+ if (matchesCwd && !matchesCwd(session.cwd))
24
22
  continue;
25
- descriptors.push(descriptor);
23
+ sessions.push(session);
26
24
  }
27
- return descriptors
25
+ return sessions
28
26
  .sort((left, right) => right.lastActivityAt.getTime() - left.lastActivityAt.getTime())
29
27
  .slice(0, limit);
30
28
  }
@@ -104,7 +102,7 @@ async function walkJsonlFiles(root) {
104
102
  }));
105
103
  return files.flat();
106
104
  }
107
- async function readPiSessionDescriptor(filePath, provider) {
105
+ async function readPiImportableSession(filePath) {
108
106
  const firstLine = await readFirstLine(filePath);
109
107
  if (!firstLine)
110
108
  return null;
@@ -116,27 +114,13 @@ async function readPiSessionDescriptor(filePath, provider) {
116
114
  const headInfo = await scanSessionHead(filePath);
117
115
  const title = tailInfo.title ?? headInfo.title ?? headInfo.firstUserMessage;
118
116
  const lastActivityAt = tailInfo.lastActivityAt ?? (await readFileMtime(filePath)) ?? header.createdAt ?? new Date(0);
119
- const timeline = buildPreviewTimeline({
120
- firstUserMessage: headInfo.firstUserMessage,
121
- lastUserMessage: tailInfo.lastUserMessage,
122
- });
123
- const persistence = {
124
- provider,
125
- sessionId: header.sessionId,
126
- nativeHandle: filePath,
127
- metadata: {
128
- provider,
129
- cwd: header.cwd,
130
- },
131
- };
132
117
  return {
133
- provider,
134
- sessionId: header.sessionId,
118
+ providerHandleId: filePath,
135
119
  cwd: header.cwd,
136
120
  title,
121
+ firstPromptPreview: normalizePromptPreview(headInfo.firstUserMessage),
122
+ lastPromptPreview: normalizePromptPreview(tailInfo.lastUserMessage ?? headInfo.firstUserMessage),
137
123
  lastActivityAt,
138
- persistence,
139
- timeline,
140
124
  };
141
125
  }
142
126
  async function readFirstLine(filePath) {
@@ -254,16 +238,6 @@ async function scanSessionHead(filePath) {
254
238
  }
255
239
  return { title, firstUserMessage };
256
240
  }
257
- function buildPreviewTimeline(input) {
258
- const items = [];
259
- if (input.firstUserMessage) {
260
- items.push({ type: "user_message", text: input.firstUserMessage });
261
- }
262
- if (input.lastUserMessage && input.lastUserMessage !== input.firstUserMessage) {
263
- items.push({ type: "user_message", text: input.lastUserMessage });
264
- }
265
- return items;
266
- }
267
241
  function parseJsonRecord(line) {
268
242
  if (!line)
269
243
  return null;
@@ -281,6 +255,12 @@ function isRecord(value) {
281
255
  function readNonEmptyString(value) {
282
256
  return typeof value === "string" && value.trim() ? value.trim() : null;
283
257
  }
258
+ function normalizePromptPreview(text) {
259
+ const normalized = text?.trim().replace(/\s+/g, " ") ?? "";
260
+ if (!normalized)
261
+ return null;
262
+ return normalized.length > 160 ? normalized.slice(0, 160) : normalized;
263
+ }
284
264
  function parseDate(value) {
285
265
  if (typeof value !== "string" && typeof value !== "number") {
286
266
  return null;
@@ -2269,7 +2269,6 @@ export class Session {
2269
2269
  logger: this.sessionLogger,
2270
2270
  });
2271
2271
  await this.registerWorkspaceForImportedAgent(snapshot.cwd);
2272
- await this.forwardAgentUpdate(snapshot);
2273
2272
  const agentPayload = await this.buildAgentPayload(snapshot);
2274
2273
  this.emit({
2275
2274
  type: "status",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getpaseo/server",
3
- "version": "0.1.91",
3
+ "version": "0.1.92",
4
4
  "description": "Paseo backend server",
5
5
  "files": [
6
6
  "dist/server",
@@ -59,10 +59,10 @@
59
59
  "dependencies": {
60
60
  "@agentclientprotocol/sdk": "^0.17.1",
61
61
  "@anthropic-ai/claude-agent-sdk": "^0.2.133",
62
- "@getpaseo/client": "0.1.91",
63
- "@getpaseo/highlight": "0.1.91",
64
- "@getpaseo/protocol": "0.1.91",
65
- "@getpaseo/relay": "0.1.91",
62
+ "@getpaseo/client": "0.1.92",
63
+ "@getpaseo/highlight": "0.1.92",
64
+ "@getpaseo/protocol": "0.1.92",
65
+ "@getpaseo/relay": "0.1.92",
66
66
  "@isaacs/ttlcache": "^2.1.4",
67
67
  "@modelcontextprotocol/sdk": "^1.20.1",
68
68
  "@opencode-ai/sdk": "1.14.46",