@getpaseo/server 0.1.91 → 0.1.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) 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/claude/models.js +15 -0
  16. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +3 -2
  17. package/dist/server/server/agent/providers/codex-app-server-agent.js +20 -21
  18. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +1 -0
  19. package/dist/server/server/agent/providers/cursor-acp-agent.js +1 -0
  20. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +9 -0
  21. package/dist/server/server/agent/providers/generic-acp-agent.js +18 -1
  22. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +3 -2
  23. package/dist/server/server/agent/providers/mock-load-test-agent.js +11 -1
  24. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +1 -2
  25. package/dist/server/server/agent/providers/mock-slow-provider.js +0 -3
  26. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +2 -0
  27. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +8 -0
  28. package/dist/server/server/agent/providers/opencode-agent.d.ts +3 -2
  29. package/dist/server/server/agent/providers/opencode-agent.js +60 -32
  30. package/dist/server/server/agent/providers/pi/agent.d.ts +3 -2
  31. package/dist/server/server/agent/providers/pi/agent.js +28 -5
  32. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +3 -4
  33. package/dist/server/server/agent/providers/pi/session-descriptor.js +17 -37
  34. package/dist/server/server/session.js +0 -1
  35. package/package.json +5 -5
@@ -1,7 +1,7 @@
1
1
  import { AGENT_LIFECYCLE_STATUSES, type AgentLifecycleStatus } from "@getpaseo/protocol/agent-lifecycle";
2
2
  import type { Logger } from "pino";
3
3
  import type { TerminalManager } from "../../terminal/terminal-manager.js";
4
- import { type AgentCapabilityFlags, type AgentClient, type AgentFeature, type AgentSlashCommand, type AgentMode, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentPersistenceHandle, type AgentPromptInput, type AgentProvider, type AgentRunOptions, type AgentRunResult, type AgentSession, type AgentSessionConfig, type AgentStreamEvent, type AgentTimelineItem, type AgentUsage, type AgentRuntimeInfo, type ListPersistedAgentsOptions, type PersistedAgentDescriptor } from "./agent-sdk-types.js";
4
+ import { type AgentCapabilityFlags, type AgentClient, type AgentFeature, type AgentSlashCommand, type AgentMode, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentPersistenceHandle, type AgentPromptInput, type AgentProvider, type AgentRunOptions, type AgentRunResult, type AgentSession, type AgentSessionConfig, type AgentStreamEvent, type AgentTimelineItem, type AgentUsage, type AgentRuntimeInfo, type ImportableProviderSession, type ListImportableSessionsOptions } from "./agent-sdk-types.js";
5
5
  import type { StoredAgentRecord, AgentStorage } from "./agent-storage.js";
6
6
  import type { AgentTimelineFetchOptions, AgentTimelineFetchResult, AgentTimelineRow, AgentTimelineStore } from "./agent-timeline-store-types.js";
7
7
  import { type ForegroundTurnWaiter } from "./foreground-run-state.js";
@@ -28,13 +28,16 @@ interface HydrateTimelineOptions {
28
28
  force?: boolean;
29
29
  broadcast?: boolean;
30
30
  }
31
- export type ImportablePersistedAgentQueryOptions = ListPersistedAgentsOptions & {
31
+ export type ImportablePersistedAgentQueryOptions = ListImportableSessionsOptions & {
32
32
  /**
33
33
  * When set, only providers in this set are scanned, in addition to the
34
34
  * built-in importable allowlist + enabled + non-derived rules.
35
35
  */
36
36
  providerFilter?: Set<string>;
37
37
  };
38
+ export interface ManagedImportableProviderSession extends ImportableProviderSession {
39
+ provider: AgentProvider;
40
+ }
38
41
  export type AgentAttentionCallback = (params: {
39
42
  agentId: string;
40
43
  provider: AgentProvider;
@@ -198,9 +201,8 @@ export declare class AgentManager {
198
201
  hasInFlightRun(agentId: string): boolean;
199
202
  subscribe(callback: AgentSubscriber, options?: SubscribeOptions): () => void;
200
203
  listAgents(): ManagedAgent[];
201
- listImportablePersistedAgents(options?: ImportablePersistedAgentQueryOptions): Promise<PersistedAgentDescriptor[]>;
204
+ listImportableSessions(options?: ImportablePersistedAgentQueryOptions): Promise<ManagedImportableProviderSession[]>;
202
205
  private isProviderImportable;
203
- findPersistedAgent(provider: AgentProvider, sessionId: string, options?: Pick<ListPersistedAgentsOptions, "cwd">): Promise<PersistedAgentDescriptor | null>;
204
206
  listProviderAvailability(): Promise<ProviderAvailability[]>;
205
207
  listDraftCommands(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
206
208
  listDraftFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
@@ -223,6 +225,12 @@ export declare class AgentManager {
223
225
  lastUserMessageAt?: Date | null;
224
226
  labels?: Record<string, string>;
225
227
  }): Promise<ManagedAgent>;
228
+ importProviderSession(input: {
229
+ provider: AgentProvider;
230
+ providerHandleId: string;
231
+ cwd: string;
232
+ labels?: Record<string, string>;
233
+ }): Promise<ManagedAgent>;
226
234
  reloadAgentSession(agentId: string, overrides?: Partial<AgentSessionConfig>, options?: {
227
235
  rehydrateFromDisk?: boolean;
228
236
  }): Promise<ManagedAgent>;
@@ -13,6 +13,7 @@ import { getAgentProviderDefinition } from "@getpaseo/protocol/provider-manifest
13
13
  import { invokeRewindCapability } from "./rewind/rewind.js";
14
14
  import { isSystemInjectedEnvelope } from "./agent-prompt.js";
15
15
  import { stripInternalPaseoMcpServer, withRuntimePaseoMcpServer } from "./runtime-mcp-config.js";
16
+ import { resolveCreateAgentTitles } from "./create-agent-title.js";
16
17
  const RELOAD_SESSION_CLOSE_TIMEOUT_MS = 3000;
17
18
  const INTERRUPT_SESSION_TIMEOUT_MS = 2000;
18
19
  const STORED_AGENT_CAPABILITIES = {
@@ -122,6 +123,44 @@ function buildExplicitTimelineSeedForRegister(now, options) {
122
123
  timestamp: (options?.updatedAt ?? options?.createdAt ?? now).toISOString(),
123
124
  };
124
125
  }
126
+ function buildImportedTimelineRows(entries) {
127
+ const rows = [];
128
+ for (const entry of entries) {
129
+ if (entry.item.type === "user_message" && isSystemInjectedEnvelope(entry.item.text)) {
130
+ continue;
131
+ }
132
+ rows.push({
133
+ seq: rows.length + 1,
134
+ timestamp: entry.timestamp ?? new Date().toISOString(),
135
+ item: entry.item,
136
+ });
137
+ }
138
+ return rows;
139
+ }
140
+ function resolveImportedAgentTitle(config, timelineRows) {
141
+ const initialPrompt = getFirstUserMessageTextFromRows(timelineRows);
142
+ if (!initialPrompt) {
143
+ return null;
144
+ }
145
+ const { explicitTitle, provisionalTitle } = resolveCreateAgentTitles({
146
+ configTitle: config.title,
147
+ initialPrompt,
148
+ });
149
+ return explicitTitle ?? provisionalTitle ?? null;
150
+ }
151
+ function getFirstUserMessageTextFromRows(rows) {
152
+ for (const row of rows) {
153
+ const item = row.item;
154
+ if (item.type !== "user_message") {
155
+ continue;
156
+ }
157
+ const text = item.text.trim();
158
+ if (text) {
159
+ return text;
160
+ }
161
+ }
162
+ return null;
163
+ }
125
164
  export class AgentManager {
126
165
  constructor(options) {
127
166
  this.clients = new Map();
@@ -279,24 +318,25 @@ export class AgentManager {
279
318
  .filter((agent) => !agent.internal)
280
319
  .map((agent) => Object.assign({}, agent));
281
320
  }
282
- async listImportablePersistedAgents(options) {
283
- const providerEntries = Array.from(this.clients.entries()).filter(([provider, client]) => !!client.listPersistedAgents &&
321
+ async listImportableSessions(options) {
322
+ const providerEntries = Array.from(this.clients.entries()).filter(([provider, client]) => client.capabilities.supportsSessionListing &&
323
+ !!client.listImportableSessions &&
284
324
  this.isProviderImportable(provider, options?.providerFilter));
285
- const descriptorLists = await Promise.all(providerEntries.map(async ([provider, client]) => {
325
+ const sessionLists = await Promise.all(providerEntries.map(async ([provider, client]) => {
286
326
  try {
287
- return await client.listPersistedAgents({
327
+ return (await client.listImportableSessions({
288
328
  limit: options?.limit,
289
329
  cwd: options?.cwd,
290
- });
330
+ })).map((session) => Object.assign(session, { provider }));
291
331
  }
292
332
  catch (error) {
293
- this.logger.warn({ err: error, provider }, "Failed to list persisted agents for provider");
333
+ this.logger.warn({ err: error, provider }, "Failed to list importable sessions for provider");
294
334
  return [];
295
335
  }
296
336
  }));
297
- const descriptors = descriptorLists.flat();
337
+ const sessions = sessionLists.flat();
298
338
  const limit = options?.limit ?? 20;
299
- return descriptors
339
+ return sessions
300
340
  .sort((a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime())
301
341
  .slice(0, limit);
302
342
  }
@@ -309,16 +349,6 @@ export class AgentManager {
309
349
  }
310
350
  return true;
311
351
  }
312
- async findPersistedAgent(provider, sessionId, options) {
313
- const client = this.requireClient(provider);
314
- if (!client.listPersistedAgents) {
315
- return null;
316
- }
317
- const descriptors = await client.listPersistedAgents({ limit: 200, cwd: options?.cwd });
318
- return (descriptors.find((descriptor) => {
319
- return (descriptor.sessionId === sessionId || descriptor.persistence.nativeHandle === sessionId);
320
- }) ?? null);
321
- }
322
352
  async listProviderAvailability() {
323
353
  const checks = Array.from(this.clients.keys()).map(async (provider) => {
324
354
  const client = this.clients.get(provider);
@@ -458,6 +488,35 @@ export class AgentManager {
458
488
  const session = await client.resumeSession(handle, launchConfig, launchContext);
459
489
  return this.registerSession(session, storedConfig, resolvedAgentId, options);
460
490
  }
491
+ async importProviderSession(input) {
492
+ const resolvedAgentId = validateAgentId(this.idFactory(), "importProviderSession");
493
+ this.requireEnabledProvider(input.provider);
494
+ const client = await this.requireAvailableClient({ provider: input.provider });
495
+ if (!client.importSession) {
496
+ throw new Error(`Provider '${input.provider}' does not support importing sessions`);
497
+ }
498
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig({
499
+ provider: input.provider,
500
+ cwd: input.cwd,
501
+ }, resolvedAgentId);
502
+ const launchContext = this.buildLaunchContext(resolvedAgentId);
503
+ const imported = await client.importSession({
504
+ providerHandleId: input.providerHandleId,
505
+ cwd: input.cwd,
506
+ }, { config: launchConfig, storedConfig, launchContext });
507
+ const importedConfig = await this.normalizeConfig(stripInternalPaseoMcpServer(imported.config));
508
+ const timelineRows = buildImportedTimelineRows(imported.timeline);
509
+ const initialTitle = resolveImportedAgentTitle(importedConfig, timelineRows);
510
+ return this.registerSession(imported.session, importedConfig, resolvedAgentId, {
511
+ labels: input.labels,
512
+ timelineRows,
513
+ timelineNextSeq: timelineRows.length + 1,
514
+ persistence: imported.persistence,
515
+ historyPrimed: true,
516
+ initialTitle,
517
+ publishWhenReady: true,
518
+ });
519
+ }
461
520
  // Hot-reload an active agent session with config overrides. By default the
462
521
  // in-memory timeline is preserved (used for voice-mode toggles and similar
463
522
  // config swaps). When `rehydrateFromDisk` is set, the timeline is wiped so a
@@ -1605,13 +1664,15 @@ export class AgentManager {
1605
1664
  this.agents.set(resolvedAgentId, managed);
1606
1665
  // Initialize previousStatus to track transitions
1607
1666
  this.previousStatuses.set(resolvedAgentId, managed.lifecycle);
1608
- await this.refreshRuntimeInfo(managed);
1667
+ await this.refreshRuntimeInfo(managed, { emit: !options?.publishWhenReady });
1609
1668
  await this.persistSnapshot(managed, {
1610
1669
  workspaceId: options?.workspaceId,
1611
1670
  title: initialPersistedTitle,
1612
1671
  });
1613
- this.emitState(managed, { persist: false });
1614
- await this.refreshSessionState(managed);
1672
+ if (!options?.publishWhenReady) {
1673
+ this.emitState(managed, { persist: false });
1674
+ }
1675
+ await this.refreshSessionState(managed, { emit: !options?.publishWhenReady });
1615
1676
  managed.lifecycle = "idle";
1616
1677
  await this.persistSnapshot(managed, { workspaceId: options?.workspaceId });
1617
1678
  this.emitState(managed, { persist: false });
@@ -1660,7 +1721,7 @@ export class AgentManager {
1660
1721
  foregroundTurnWaiters: new Set(),
1661
1722
  finalizedForegroundTurnIds: new Set(),
1662
1723
  unsubscribeSession: null,
1663
- persistence: attachPersistenceCwd(session.describePersistence(), config.cwd),
1724
+ persistence: attachPersistenceCwd(options?.persistence ?? session.describePersistence(), config.cwd),
1664
1725
  historyPrimed: options?.historyPrimed ?? durableTimelineHasRows,
1665
1726
  lastUserMessageAt: options?.lastUserMessageAt ?? null,
1666
1727
  lastUsage: options?.lastUsage,
@@ -1812,7 +1873,7 @@ export class AgentManager {
1812
1873
  }
1813
1874
  return this.registry;
1814
1875
  }
1815
- async refreshSessionState(agent) {
1876
+ async refreshSessionState(agent, options) {
1816
1877
  try {
1817
1878
  const modes = await agent.session.getAvailableModes();
1818
1879
  agent.availableModes = modes;
@@ -1834,9 +1895,9 @@ export class AgentManager {
1834
1895
  agent.pendingPermissions.clear();
1835
1896
  }
1836
1897
  this.syncFeaturesFromSession(agent);
1837
- await this.refreshRuntimeInfo(agent);
1898
+ await this.refreshRuntimeInfo(agent, options);
1838
1899
  }
1839
- async refreshRuntimeInfo(agent) {
1900
+ async refreshRuntimeInfo(agent, options) {
1840
1901
  try {
1841
1902
  const newInfo = await agent.session.getRuntimeInfo();
1842
1903
  const changed = newInfo.model !== agent.runtimeInfo?.model ||
@@ -1848,7 +1909,7 @@ export class AgentManager {
1848
1909
  agent.persistence = attachPersistenceCwd({ provider: agent.provider, sessionId: newInfo.sessionId }, agent.cwd);
1849
1910
  }
1850
1911
  // Emit state if runtimeInfo changed so clients get the updated model
1851
- if (changed) {
1912
+ if (changed && options?.emit !== false) {
1852
1913
  this.emitState(agent);
1853
1914
  }
1854
1915
  }
@@ -1,6 +1,6 @@
1
1
  import type { AgentListItemPayload, AgentSnapshotPayload, RecentProviderSessionDescriptorPayload } from "../messages.js";
2
2
  import type { StoredAgentRecord } from "./agent-storage.js";
3
- import type { AgentProvider, AgentRuntimeInfo, PersistedAgentDescriptor } from "./agent-sdk-types.js";
3
+ import type { AgentProvider, AgentRuntimeInfo, ImportableProviderSession } from "./agent-sdk-types.js";
4
4
  import type { ManagedAgent } from "./agent-manager.js";
5
5
  export type { ManagedAgent };
6
6
  interface ProjectionOptions {
@@ -19,6 +19,8 @@ export declare function toStoredAgentRecord(agent: ManagedAgent, options?: Proje
19
19
  export declare function toAgentPayload(agent: ManagedAgent, options?: ProjectionOptions): AgentSnapshotPayload;
20
20
  export declare function buildStoredAgentPayload(record: StoredAgentRecord, validProviders: Iterable<AgentProvider>): AgentSnapshotPayload;
21
21
  export declare function toAgentListItemPayload(agent: AgentSnapshotPayload): AgentListItemPayload;
22
- export declare function toRecentProviderSessionDescriptorPayload(descriptor: PersistedAgentDescriptor, options: RecentProviderSessionProjectionOptions): RecentProviderSessionDescriptorPayload;
22
+ export declare function toRecentProviderSessionDescriptorPayload(session: ImportableProviderSession & {
23
+ provider: string;
24
+ }, options: RecentProviderSessionProjectionOptions): RecentProviderSessionDescriptorPayload;
23
25
  export declare function resolveStoredAgentPayloadUpdatedAt(record: StoredAgentRecord): string;
24
26
  //# sourceMappingURL=agent-projections.d.ts.map
@@ -1,5 +1,4 @@
1
1
  import { isStoredAgentProviderAvailable, toAgentPersistenceHandle } from "../persistence-hooks.js";
2
- const PROMPT_PREVIEW_MAX_LENGTH = 160;
3
2
  function normalizeThinkingOptionId(value) {
4
3
  if (typeof value !== "string")
5
4
  return null;
@@ -193,17 +192,16 @@ export function toAgentListItemPayload(agent) {
193
192
  ...(agent.providerUnavailable ? { providerUnavailable: true } : {}),
194
193
  };
195
194
  }
196
- export function toRecentProviderSessionDescriptorPayload(descriptor, options) {
197
- const promptPreviews = collectPromptPreviews(descriptor.timeline);
195
+ export function toRecentProviderSessionDescriptorPayload(session, options) {
198
196
  return {
199
- providerId: descriptor.provider,
197
+ providerId: session.provider,
200
198
  providerLabel: options.providerLabel,
201
- providerHandleId: descriptor.persistence.nativeHandle ?? descriptor.persistence.sessionId,
202
- cwd: descriptor.cwd,
203
- title: descriptor.title,
204
- firstPromptPreview: promptPreviews[0] ?? null,
205
- lastPromptPreview: promptPreviews.at(-1) ?? null,
206
- lastActivityAt: descriptor.lastActivityAt.toISOString(),
199
+ providerHandleId: session.providerHandleId,
200
+ cwd: session.cwd,
201
+ title: session.title,
202
+ firstPromptPreview: session.firstPromptPreview,
203
+ lastPromptPreview: session.lastPromptPreview,
204
+ lastActivityAt: session.lastActivityAt.toISOString(),
207
205
  };
208
206
  }
209
207
  export function resolveStoredAgentPayloadUpdatedAt(record) {
@@ -220,24 +218,6 @@ export function resolveStoredAgentPayloadUpdatedAt(record) {
220
218
  timestamps.sort((a, b) => b.parsed - a.parsed);
221
219
  return timestamps[0].raw;
222
220
  }
223
- function collectPromptPreviews(timeline) {
224
- return timeline.flatMap((item) => {
225
- if (item.type !== "user_message") {
226
- return [];
227
- }
228
- const preview = normalizePromptPreview(item.text);
229
- return preview ? [preview] : [];
230
- });
231
- }
232
- function normalizePromptPreview(text) {
233
- const normalized = text.trim().replace(/\s+/g, " ");
234
- if (!normalized) {
235
- return null;
236
- }
237
- return normalized.length > PROMPT_PREVIEW_MAX_LENGTH
238
- ? normalized.slice(0, PROMPT_PREVIEW_MAX_LENGTH)
239
- : normalized;
240
- }
241
221
  function buildSerializableConfig(config) {
242
222
  const serializable = {};
243
223
  if (config.modeId) {
@@ -135,6 +135,7 @@ export type AgentFeature = AgentFeatureToggle | AgentFeatureSelect;
135
135
  export interface AgentCapabilityFlags {
136
136
  supportsStreaming: boolean;
137
137
  supportsSessionPersistence: boolean;
138
+ supportsSessionListing?: boolean;
138
139
  supportsDynamicModes: boolean;
139
140
  supportsMcpServers: boolean;
140
141
  supportsReasoningStream: boolean;
@@ -430,6 +431,7 @@ export interface AgentRuntimeInfo {
430
431
  modeId?: string | null;
431
432
  extra?: AgentMetadata;
432
433
  }
434
+ export type AgentSlashCommandKind = "command" | "skill";
433
435
  /**
434
436
  * Represents a slash command available in an agent session.
435
437
  * Commands are executed by sending them as prompts with / prefix.
@@ -438,25 +440,42 @@ export interface AgentSlashCommand {
438
440
  name: string;
439
441
  description: string;
440
442
  argumentHint: string;
443
+ kind?: AgentSlashCommandKind;
441
444
  }
442
- export interface ListPersistedAgentsOptions {
445
+ export interface ListImportableSessionsOptions {
443
446
  limit?: number;
444
447
  /**
445
- * Optional cwd hint. Providers that can cheaply pre-filter persisted
446
- * sessions by working directory should do so before doing expensive
447
- * work like fetching turn timelines. Providers that can't filter
448
- * cheaply may ignore this hint.
448
+ * Optional cwd hint. Providers that can cheaply pre-filter importable
449
+ * sessions by working directory should do so before doing expensive work.
449
450
  */
450
451
  cwd?: string;
451
452
  }
452
- export interface PersistedAgentDescriptor {
453
- provider: AgentProvider;
454
- sessionId: string;
453
+ export interface ImportableProviderSession {
454
+ providerHandleId: string;
455
455
  cwd: string;
456
456
  title: string | null;
457
+ firstPromptPreview: string | null;
458
+ lastPromptPreview: string | null;
457
459
  lastActivityAt: Date;
460
+ }
461
+ export interface ImportProviderSessionInput {
462
+ providerHandleId: string;
463
+ cwd: string;
464
+ }
465
+ export interface ImportProviderSessionContext {
466
+ config: AgentSessionConfig;
467
+ storedConfig: AgentSessionConfig;
468
+ launchContext?: AgentLaunchContext;
469
+ }
470
+ export interface ImportedTimelineEntry {
471
+ item: AgentTimelineItem;
472
+ timestamp?: string;
473
+ }
474
+ export interface ImportedProviderSession {
475
+ session: AgentSession;
476
+ config: AgentSessionConfig;
458
477
  persistence: AgentPersistenceHandle;
459
- timeline: AgentTimelineItem[];
478
+ timeline: ImportedTimelineEntry[];
460
479
  }
461
480
  export interface AgentSessionConfig {
462
481
  provider: AgentProvider;
@@ -575,7 +594,8 @@ export interface AgentClient {
575
594
  isCreateConfigUnattended?(input: AgentCreateConfigUnattendedInput): boolean;
576
595
  listCommands?(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
577
596
  listFeatures?(config: AgentSessionConfig): Promise<AgentFeature[]>;
578
- listPersistedAgents?(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
597
+ listImportableSessions?(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
598
+ importSession?(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<ImportedProviderSession>;
579
599
  /**
580
600
  * Check if this provider is available (CLI binary is installed).
581
601
  * Returns true if available, false otherwise.
@@ -3,13 +3,14 @@ import type { Logger } from "pino";
3
3
  import type { ProviderSnapshotManager } from "./provider-snapshot-manager.js";
4
4
  import type { AgentManager, ManagedAgent } from "./agent-manager.js";
5
5
  import type { AgentStorage } from "./agent-storage.js";
6
+ import type { AgentProvider } from "./agent-sdk-types.js";
6
7
  import { scheduleAgentMetadataGeneration } from "./agent-metadata-generator.js";
7
8
  import type { StructuredGenerationDaemonConfig } from "./structured-generation-providers.js";
8
9
  import type { FetchRecentProviderSessionsRequestMessage, ImportAgentRequestMessageSchema, RecentProviderSessionDescriptorPayload } from "@getpaseo/protocol/messages";
9
10
  import type { WorkspaceGitService } from "../workspace-git-service.js";
10
11
  type ImportAgentRequestMessage = z.infer<typeof ImportAgentRequestMessageSchema>;
11
12
  export interface NormalizedImportAgentRequest {
12
- provider: string;
13
+ provider: AgentProvider;
13
14
  providerHandleId: string;
14
15
  cwd?: string;
15
16
  labels?: Record<string, string>;
@@ -21,7 +22,7 @@ export declare class ImportSessionsRequestError extends Error {
21
22
  }
22
23
  export interface ListImportableProviderSessionsInput {
23
24
  request: FetchRecentProviderSessionsRequestMessage;
24
- agentManager: Pick<AgentManager, "listAgents" | "listImportablePersistedAgents">;
25
+ agentManager: Pick<AgentManager, "listAgents" | "listImportableSessions">;
25
26
  agentStorage: Pick<AgentStorage, "list">;
26
27
  providerSnapshotManager: Pick<ProviderSnapshotManager, "getProviderLabel">;
27
28
  }
@@ -23,7 +23,7 @@ export function normalizeImportAgentRequest(msg) {
23
23
  return { error: "Import requires providerId and providerHandleId" };
24
24
  }
25
25
  return {
26
- provider,
26
+ provider: provider,
27
27
  providerHandleId,
28
28
  cwd: msg.cwd,
29
29
  labels: msg.labels,
@@ -36,7 +36,7 @@ export async function listImportableProviderSessions(input) {
36
36
  const sinceTimestamp = parseRecentProviderSessionsSince(request.since);
37
37
  const providerFilter = request.providers ? new Set(request.providers) : undefined;
38
38
  const importedHandles = await collectImportedProviderSessionHandles(agentManager, agentStorage);
39
- const descriptors = await agentManager.listImportablePersistedAgents({
39
+ const sessions = await agentManager.listImportableSessions({
40
40
  limit,
41
41
  providerFilter,
42
42
  cwd: request.cwd,
@@ -44,25 +44,21 @@ export async function listImportableProviderSessions(input) {
44
44
  let filteredAlreadyImportedCount = 0;
45
45
  const candidates = [];
46
46
  const matchesRequestCwd = request.cwd ? createRealpathAwarePathMatcher(request.cwd) : null;
47
- for (const descriptor of descriptors) {
48
- if (matchesRequestCwd && !matchesRequestCwd(descriptor.cwd)) {
49
- continue;
50
- }
51
- if (sinceTimestamp !== null && descriptor.lastActivityAt.getTime() < sinceTimestamp) {
47
+ for (const session of sessions) {
48
+ if (matchesRequestCwd && !matchesRequestCwd(session.cwd)) {
52
49
  continue;
53
50
  }
54
- if (isMetadataGenerationDescriptor(descriptor)) {
51
+ if (sinceTimestamp !== null && session.lastActivityAt.getTime() < sinceTimestamp) {
55
52
  continue;
56
53
  }
57
- if (!hasUserPrompt(descriptor)) {
54
+ if (isMetadataGenerationSession(session)) {
58
55
  continue;
59
56
  }
60
- const providerHandleId = descriptor.persistence.nativeHandle ?? descriptor.persistence.sessionId;
61
- if (importedHandles.has(toProviderSessionHandleKey(descriptor.provider, providerHandleId))) {
57
+ if (importedHandles.has(toProviderSessionHandleKey(session.provider, session.providerHandleId))) {
62
58
  filteredAlreadyImportedCount += 1;
63
59
  continue;
64
60
  }
65
- candidates.push(descriptor);
61
+ candidates.push(session);
66
62
  }
67
63
  const entries = candidates
68
64
  .sort((a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime())
@@ -74,23 +70,19 @@ export async function listImportableProviderSessions(input) {
74
70
  }
75
71
  export async function importProviderSession(input) {
76
72
  const { provider, providerHandleId, cwd, labels } = input.request;
77
- const descriptor = await input.agentManager.findPersistedAgent(provider, providerHandleId, {
78
- cwd,
79
- });
80
- if (!descriptor && provider === "opencode" && !cwd) {
81
- throw new Error("OpenCode sessions require --cwd when the session cannot be found in persisted agents");
73
+ if (!cwd) {
74
+ throw new Error("Import requires cwd from the selected provider session");
82
75
  }
83
- const handle = descriptor
84
- ? applyImportCwdOverride(descriptor.persistence, cwd)
85
- : buildImportPersistenceHandle({ provider, providerHandleId, cwd });
86
- const overrides = cwd ? { cwd } : undefined;
76
+ const handle = buildImportPersistenceHandle({ provider, providerHandleId, cwd });
87
77
  await unarchiveAgentByHandle(input.agentStorage, input.agentManager, handle);
88
- const snapshot = await input.agentManager.resumeAgentFromPersistence(handle, overrides, undefined, {
78
+ const snapshot = await input.agentManager.importProviderSession({
79
+ provider,
80
+ providerHandleId,
81
+ cwd,
89
82
  labels,
90
83
  });
91
84
  await unarchiveAgentState(input.agentStorage, input.agentManager, snapshot.id);
92
- await input.agentManager.hydrateTimelineFromProvider(snapshot.id);
93
- await applyImportedAgentTitle({
85
+ scheduleImportedAgentMetadata({
94
86
  snapshot,
95
87
  agentManager: input.agentManager,
96
88
  workspaceGitService: input.workspaceGitService,
@@ -108,24 +100,22 @@ export async function importProviderSession(input) {
108
100
  async function unarchiveAgentByHandle(agentStorage, agentManager, handle) {
109
101
  const records = await agentStorage.list();
110
102
  const matched = records.find((record) => record.persistence?.provider === handle.provider &&
111
- record.persistence?.sessionId === handle.sessionId);
103
+ (record.persistence.sessionId === handle.sessionId ||
104
+ record.persistence.nativeHandle === handle.nativeHandle));
112
105
  if (!matched) {
113
106
  return;
114
107
  }
115
108
  await unarchiveAgentState(agentStorage, agentManager, matched.id);
116
109
  }
117
- async function applyImportedAgentTitle(input) {
110
+ function scheduleImportedAgentMetadata(input) {
118
111
  const initialPrompt = getFirstUserMessageText(input.agentManager.getTimeline(input.snapshot.id));
119
112
  if (!initialPrompt) {
120
113
  return;
121
114
  }
122
- const { explicitTitle, provisionalTitle } = resolveCreateAgentTitles({
115
+ const { explicitTitle } = resolveCreateAgentTitles({
123
116
  configTitle: input.snapshot.config.title,
124
117
  initialPrompt,
125
118
  });
126
- if (!explicitTitle && provisionalTitle) {
127
- await input.agentManager.setTitle(input.snapshot.id, provisionalTitle);
128
- }
129
119
  input.scheduleAgentMetadataGeneration({
130
120
  agentManager: input.agentManager,
131
121
  agentId: input.snapshot.id,
@@ -157,27 +147,13 @@ function parseRecentProviderSessionsSince(since) {
157
147
  return timestamp;
158
148
  }
159
149
  function buildImportPersistenceHandle(input) {
160
- const cwd = input.cwd ?? process.cwd();
161
150
  return {
162
151
  provider: input.provider,
163
152
  sessionId: input.providerHandleId,
164
153
  nativeHandle: input.providerHandleId,
165
154
  metadata: {
166
155
  provider: input.provider,
167
- cwd,
168
- },
169
- };
170
- }
171
- function applyImportCwdOverride(handle, cwd) {
172
- if (!cwd) {
173
- return handle;
174
- }
175
- return {
176
- ...handle,
177
- metadata: {
178
- ...handle.metadata,
179
- provider: handle.provider,
180
- cwd,
156
+ cwd: input.cwd,
181
157
  },
182
158
  };
183
159
  }
@@ -206,16 +182,8 @@ async function collectImportedProviderSessionHandles(agentManager, agentStorage)
206
182
  function toProviderSessionHandleKey(provider, providerHandleId) {
207
183
  return `${provider}\0${providerHandleId}`;
208
184
  }
209
- function isMetadataGenerationDescriptor(descriptor) {
210
- for (const item of descriptor.timeline) {
211
- if (item.type !== "user_message")
212
- continue;
213
- return item.text.trimStart().startsWith(METADATA_GENERATION_PROMPT_PREFIX);
214
- }
215
- return false;
216
- }
217
- function hasUserPrompt(descriptor) {
218
- return descriptor.timeline.some((item) => item.type === "user_message" && item.text.trim() !== "");
185
+ function isMetadataGenerationSession(input) {
186
+ return (input.firstPromptPreview?.trimStart().startsWith(METADATA_GENERATION_PROMPT_PREFIX) ?? false);
219
187
  }
220
188
  function collectProviderSessionHandleKeys(target, provider, persistence) {
221
189
  if (!persistence) {
@@ -141,16 +141,6 @@ function mapStreamEvent(provider, event) {
141
141
  provider,
142
142
  };
143
143
  }
144
- function mapPersistedAgentDescriptor(provider, descriptor) {
145
- return {
146
- ...descriptor,
147
- provider,
148
- persistence: {
149
- ...descriptor.persistence,
150
- provider,
151
- },
152
- };
153
- }
154
144
  function mapModel(provider, model) {
155
145
  return normalizeAgentModelDefinition({ ...model, provider });
156
146
  }
@@ -222,7 +212,8 @@ export function wrapSessionProvider(provider, inner) {
222
212
  };
223
213
  }
224
214
  function wrapClientProvider(provider, inner, profileModels, additionalModels, profileModelsAreAdditive) {
225
- const listPersistedAgents = inner.listPersistedAgents?.bind(inner);
215
+ const listImportableSessions = inner.listImportableSessions?.bind(inner);
216
+ const importSession = inner.importSession?.bind(inner);
226
217
  return {
227
218
  provider,
228
219
  capabilities: inner.capabilities,
@@ -245,8 +236,36 @@ function wrapClientProvider(provider, inner, profileModels, additionalModels, pr
245
236
  listModes: inner.listModes?.bind(inner),
246
237
  resolveCreateConfig: inner.resolveCreateConfig?.bind(inner),
247
238
  isCreateConfigUnattended: inner.isCreateConfigUnattended?.bind(inner),
248
- listPersistedAgents: listPersistedAgents
249
- ? async (options) => (await listPersistedAgents(options)).map((descriptor) => mapPersistedAgentDescriptor(provider, descriptor))
239
+ listImportableSessions: listImportableSessions
240
+ ? async (options) => await listImportableSessions(options)
241
+ : undefined,
242
+ importSession: importSession
243
+ ? async (input, context) => {
244
+ const imported = await importSession(input, {
245
+ ...context,
246
+ config: {
247
+ ...context.config,
248
+ provider: inner.provider,
249
+ },
250
+ storedConfig: {
251
+ ...context.storedConfig,
252
+ provider: inner.provider,
253
+ },
254
+ });
255
+ const persistence = mapPersistenceHandle(provider, imported.persistence);
256
+ if (!persistence) {
257
+ throw new Error(`Provider '${provider}' import did not return persistence`);
258
+ }
259
+ return {
260
+ ...imported,
261
+ session: wrapSessionProvider(provider, imported.session),
262
+ config: {
263
+ ...imported.config,
264
+ provider,
265
+ },
266
+ persistence,
267
+ };
268
+ }
250
269
  : undefined,
251
270
  isAvailable: () => inner.isAvailable(),
252
271
  getDiagnostic: inner.getDiagnostic?.bind(inner),
@@ -352,6 +371,7 @@ function addDerivedProviders(resolvedProviders, providerOverrides) {
352
371
  env: override.env,
353
372
  providerId,
354
373
  label: override.label ?? providerId,
374
+ providerParams: override.params,
355
375
  })
356
376
  : new GenericACPAgentClient({
357
377
  logger,
@@ -359,6 +379,7 @@ function addDerivedProviders(resolvedProviders, providerOverrides) {
359
379
  env: override.env,
360
380
  providerId,
361
381
  label: override.label ?? providerId,
382
+ providerParams: override.params,
362
383
  }),
363
384
  });
364
385
  continue;