@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
@@ -127,6 +127,26 @@ export function runSupervisor(options) {
127
127
  execArgv: workerExecArgv,
128
128
  });
129
129
  }
130
+ const currentChild = child;
131
+ const heartbeat = setInterval(() => {
132
+ const message = { type: "paseo:supervisor-heartbeat" };
133
+ if (currentChild.connected) {
134
+ currentChild.send?.(message, (error) => {
135
+ if (error) {
136
+ writeLifecycleLog("Worker heartbeat IPC send failed", {
137
+ error: error instanceof Error ? error.message : String(error),
138
+ });
139
+ }
140
+ });
141
+ }
142
+ else {
143
+ writeLifecycleLog("Worker heartbeat skipped because IPC channel is disconnected");
144
+ }
145
+ }, 1000);
146
+ heartbeat.unref();
147
+ child.on("disconnect", () => {
148
+ writeLifecycleLog("Worker IPC channel disconnected");
149
+ });
130
150
  child.stdout?.on("data", (chunk) => {
131
151
  process.stdout.write(chunk);
132
152
  writeDurableChunk(chunk);
@@ -157,6 +177,7 @@ export function runSupervisor(options) {
157
177
  requestRestart("Restart requested by worker");
158
178
  });
159
179
  child.on("close", (code, signal) => {
180
+ clearInterval(heartbeat);
160
181
  const exitDescriptor = describeExit(code, signal);
161
182
  writeLifecycleLog("Worker exited", { code, signal, exit: exitDescriptor });
162
183
  if (shuttingDown) {
@@ -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;
@@ -163,7 +166,6 @@ export interface AgentMetricsSnapshot {
163
166
  export declare class AgentManager {
164
167
  private readonly clients;
165
168
  private readonly providerEnabled;
166
- private readonly providerDerivedFromId;
167
169
  private readonly agents;
168
170
  private readonly timelineStore;
169
171
  private readonly agentsAwaitingInitialSnapshotPersist;
@@ -199,9 +201,8 @@ export declare class AgentManager {
199
201
  hasInFlightRun(agentId: string): boolean;
200
202
  subscribe(callback: AgentSubscriber, options?: SubscribeOptions): () => void;
201
203
  listAgents(): ManagedAgent[];
202
- listImportablePersistedAgents(options?: ImportablePersistedAgentQueryOptions): Promise<PersistedAgentDescriptor[]>;
204
+ listImportableSessions(options?: ImportablePersistedAgentQueryOptions): Promise<ManagedImportableProviderSession[]>;
203
205
  private isProviderImportable;
204
- findPersistedAgent(provider: AgentProvider, sessionId: string, options?: Pick<ListPersistedAgentsOptions, "cwd">): Promise<PersistedAgentDescriptor | null>;
205
206
  listProviderAvailability(): Promise<ProviderAvailability[]>;
206
207
  listDraftCommands(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
207
208
  listDraftFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
@@ -224,6 +225,12 @@ export declare class AgentManager {
224
225
  lastUserMessageAt?: Date | null;
225
226
  labels?: Record<string, string>;
226
227
  }): Promise<ManagedAgent>;
228
+ importProviderSession(input: {
229
+ provider: AgentProvider;
230
+ providerHandleId: string;
231
+ cwd: string;
232
+ labels?: Record<string, string>;
233
+ }): Promise<ManagedAgent>;
227
234
  reloadAgentSession(agentId: string, overrides?: Partial<AgentSessionConfig>, options?: {
228
235
  rehydrateFromDisk?: boolean;
229
236
  }): Promise<ManagedAgent>;
@@ -337,6 +344,7 @@ export declare class AgentManager {
337
344
  private dispatchStream;
338
345
  private dispatch;
339
346
  private normalizeConfig;
347
+ private prepareSessionConfig;
340
348
  private applyDaemonAppendSystemPrompt;
341
349
  private buildLaunchContext;
342
350
  private requireAvailableClient;
@@ -10,9 +10,10 @@ import { InMemoryAgentTimelineStore, } from "./agent-timeline-store.js";
10
10
  import { AGENT_STREAM_COALESCE_DEFAULT_WINDOW_MS, AgentStreamCoalescer, } from "./agent-stream-coalescer.js";
11
11
  import { ForegroundRunState } from "./foreground-run-state.js";
12
12
  import { getAgentProviderDefinition } from "@getpaseo/protocol/provider-manifest";
13
- import { IMPORTABLE_PROVIDERS } from "./provider-registry.js";
14
13
  import { invokeRewindCapability } from "./rewind/rewind.js";
15
14
  import { isSystemInjectedEnvelope } from "./agent-prompt.js";
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 = {
@@ -54,7 +55,7 @@ function buildStoredAgentConfig(record) {
54
55
  }
55
56
  if (record.config.mcpServers != null)
56
57
  config.mcpServers = record.config.mcpServers;
57
- return config;
58
+ return stripInternalPaseoMcpServer(config);
58
59
  }
59
60
  export { AGENT_LIFECYCLE_STATUSES };
60
61
  function resolveInitialAttention(input) {
@@ -122,11 +123,48 @@ 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();
128
167
  this.providerEnabled = new Map();
129
- this.providerDerivedFromId = new Map();
130
168
  this.agents = new Map();
131
169
  this.timelineStore = new InMemoryAgentTimelineStore();
132
170
  this.agentsAwaitingInitialSnapshotPersist = new Set();
@@ -166,7 +204,6 @@ export class AgentManager {
166
204
  for (const [provider, definition] of Object.entries(input.providerDefinitions)) {
167
205
  if (definition) {
168
206
  this.providerEnabled.set(provider, definition.enabled);
169
- this.providerDerivedFromId.set(provider, definition.derivedFromProviderId ?? null);
170
207
  }
171
208
  }
172
209
  for (const [provider, client] of Object.entries(input.clients)) {
@@ -281,52 +318,37 @@ export class AgentManager {
281
318
  .filter((agent) => !agent.internal)
282
319
  .map((agent) => Object.assign({}, agent));
283
320
  }
284
- async listImportablePersistedAgents(options) {
285
- 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 &&
286
324
  this.isProviderImportable(provider, options?.providerFilter));
287
- const descriptorLists = await Promise.all(providerEntries.map(async ([provider, client]) => {
325
+ const sessionLists = await Promise.all(providerEntries.map(async ([provider, client]) => {
288
326
  try {
289
- return await client.listPersistedAgents({
327
+ return (await client.listImportableSessions({
290
328
  limit: options?.limit,
291
329
  cwd: options?.cwd,
292
- });
330
+ })).map((session) => Object.assign(session, { provider }));
293
331
  }
294
332
  catch (error) {
295
- 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");
296
334
  return [];
297
335
  }
298
336
  }));
299
- const descriptors = descriptorLists.flat();
337
+ const sessions = sessionLists.flat();
300
338
  const limit = options?.limit ?? 20;
301
- return descriptors
339
+ return sessions
302
340
  .sort((a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime())
303
341
  .slice(0, limit);
304
342
  }
305
343
  isProviderImportable(provider, providerFilter) {
306
- if (!IMPORTABLE_PROVIDERS.includes(provider)) {
307
- return false;
308
- }
309
344
  if (this.providerEnabled.get(provider) === false) {
310
345
  return false;
311
346
  }
312
- if (this.providerDerivedFromId.get(provider) != null) {
313
- return false;
314
- }
315
347
  if (providerFilter && !providerFilter.has(provider)) {
316
348
  return false;
317
349
  }
318
350
  return true;
319
351
  }
320
- async findPersistedAgent(provider, sessionId, options) {
321
- const client = this.requireClient(provider);
322
- if (!client.listPersistedAgents) {
323
- return null;
324
- }
325
- const descriptors = await client.listPersistedAgents({ limit: 200, cwd: options?.cwd });
326
- return (descriptors.find((descriptor) => {
327
- return (descriptor.sessionId === sessionId || descriptor.persistence.nativeHandle === sessionId);
328
- }) ?? null);
329
- }
330
352
  async listProviderAvailability() {
331
353
  const checks = Array.from(this.clients.keys()).map(async (provider) => {
332
354
  const client = this.clients.get(provider);
@@ -427,27 +449,15 @@ export class AgentManager {
427
449
  }
428
450
  async createAgent(config, agentId, options) {
429
451
  const resolvedAgentId = validateAgentId(agentId ?? this.idFactory(), "createAgent");
430
- const injectedConfig = this.mcpBaseUrl == null
431
- ? config
432
- : {
433
- ...config,
434
- mcpServers: {
435
- paseo: {
436
- type: "http",
437
- url: `${this.mcpBaseUrl}?callerAgentId=${resolvedAgentId}`,
438
- },
439
- ...config.mcpServers,
440
- },
441
- };
442
- this.requireEnabledProvider(injectedConfig.provider);
443
- const normalizedConfig = this.applyDaemonAppendSystemPrompt(await this.normalizeConfig(injectedConfig));
452
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig(config, resolvedAgentId);
453
+ this.requireEnabledProvider(storedConfig.provider);
444
454
  const launchContext = this.buildLaunchContext(resolvedAgentId, options?.env);
445
455
  const client = await this.requireAvailableClient({
446
- provider: normalizedConfig.provider,
456
+ provider: storedConfig.provider,
447
457
  });
448
458
  const createOptions = this.buildCreateSessionOptions(options);
449
- const session = await client.createSession(normalizedConfig, launchContext, createOptions);
450
- return this.registerSession(session, normalizedConfig, resolvedAgentId, {
459
+ const session = await client.createSession(launchConfig, launchContext, createOptions);
460
+ return this.registerSession(session, storedConfig, resolvedAgentId, {
451
461
  labels: options?.labels,
452
462
  workspaceId: options?.workspaceId,
453
463
  initialTitle: options?.initialTitle,
@@ -468,29 +478,44 @@ export class AgentManager {
468
478
  ...overrides,
469
479
  provider: handle.provider,
470
480
  };
471
- const normalizedConfig = this.applyDaemonAppendSystemPrompt(await this.normalizeConfig(mergedConfig));
472
- const resumeOverrides = { ...overrides };
473
- let hasResumeOverrides = overrides !== undefined;
474
- if (normalizedConfig.model !== mergedConfig.model) {
475
- resumeOverrides.model = normalizedConfig.model;
476
- hasResumeOverrides = true;
477
- }
478
- if (normalizedConfig.modeId !== mergedConfig.modeId) {
479
- resumeOverrides.modeId = normalizedConfig.modeId;
480
- hasResumeOverrides = true;
481
- }
482
- if (metadata.daemonAppendSystemPrompt !== normalizedConfig.daemonAppendSystemPrompt) {
483
- resumeOverrides.daemonAppendSystemPrompt = normalizedConfig.daemonAppendSystemPrompt;
484
- hasResumeOverrides = true;
485
- }
481
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig(mergedConfig, resolvedAgentId);
486
482
  const launchContext = this.buildLaunchContext(resolvedAgentId);
487
483
  const client = this.requireClient(handle.provider);
488
484
  const available = await client.isAvailable();
489
485
  if (!available) {
490
486
  throw new Error(`Provider '${handle.provider}' is not available. Please ensure the CLI is installed.`);
491
487
  }
492
- const session = await client.resumeSession(handle, hasResumeOverrides ? resumeOverrides : undefined, launchContext);
493
- return this.registerSession(session, normalizedConfig, resolvedAgentId, options);
488
+ const session = await client.resumeSession(handle, launchConfig, launchContext);
489
+ return this.registerSession(session, storedConfig, resolvedAgentId, options);
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
+ });
494
519
  }
495
520
  // Hot-reload an active agent session with config overrides. By default the
496
521
  // in-memory timeline is preserved (used for voice-mode toggles and similar
@@ -517,11 +542,11 @@ export class AgentManager {
517
542
  ...overrides,
518
543
  provider,
519
544
  };
520
- const normalizedConfig = this.applyDaemonAppendSystemPrompt(await this.normalizeConfig(refreshConfig));
545
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig(refreshConfig, agentId);
521
546
  const launchContext = this.buildLaunchContext(agentId);
522
547
  const session = handle
523
- ? await client.resumeSession(handle, normalizedConfig, launchContext)
524
- : await client.createSession(normalizedConfig, launchContext);
548
+ ? await client.resumeSession(handle, launchConfig, launchContext)
549
+ : await client.createSession(launchConfig, launchContext);
525
550
  this.agentStreamCoalescer.flushAndDiscard(agentId);
526
551
  // Remove the existing agent entry before swapping sessions
527
552
  this.agents.delete(agentId);
@@ -539,7 +564,7 @@ export class AgentManager {
539
564
  this.timelineStore.delete(agentId);
540
565
  }
541
566
  // Preserve existing labels and timeline during reload.
542
- return this.registerSession(session, normalizedConfig, agentId, {
567
+ return this.registerSession(session, storedConfig, agentId, {
543
568
  labels: existing.labels,
544
569
  createdAt: existing.createdAt,
545
570
  updatedAt: existing.updatedAt,
@@ -1639,13 +1664,15 @@ export class AgentManager {
1639
1664
  this.agents.set(resolvedAgentId, managed);
1640
1665
  // Initialize previousStatus to track transitions
1641
1666
  this.previousStatuses.set(resolvedAgentId, managed.lifecycle);
1642
- await this.refreshRuntimeInfo(managed);
1667
+ await this.refreshRuntimeInfo(managed, { emit: !options?.publishWhenReady });
1643
1668
  await this.persistSnapshot(managed, {
1644
1669
  workspaceId: options?.workspaceId,
1645
1670
  title: initialPersistedTitle,
1646
1671
  });
1647
- this.emitState(managed, { persist: false });
1648
- await this.refreshSessionState(managed);
1672
+ if (!options?.publishWhenReady) {
1673
+ this.emitState(managed, { persist: false });
1674
+ }
1675
+ await this.refreshSessionState(managed, { emit: !options?.publishWhenReady });
1649
1676
  managed.lifecycle = "idle";
1650
1677
  await this.persistSnapshot(managed, { workspaceId: options?.workspaceId });
1651
1678
  this.emitState(managed, { persist: false });
@@ -1694,7 +1721,7 @@ export class AgentManager {
1694
1721
  foregroundTurnWaiters: new Set(),
1695
1722
  finalizedForegroundTurnIds: new Set(),
1696
1723
  unsubscribeSession: null,
1697
- persistence: attachPersistenceCwd(session.describePersistence(), config.cwd),
1724
+ persistence: attachPersistenceCwd(options?.persistence ?? session.describePersistence(), config.cwd),
1698
1725
  historyPrimed: options?.historyPrimed ?? durableTimelineHasRows,
1699
1726
  lastUserMessageAt: options?.lastUserMessageAt ?? null,
1700
1727
  lastUsage: options?.lastUsage,
@@ -1846,7 +1873,7 @@ export class AgentManager {
1846
1873
  }
1847
1874
  return this.registry;
1848
1875
  }
1849
- async refreshSessionState(agent) {
1876
+ async refreshSessionState(agent, options) {
1850
1877
  try {
1851
1878
  const modes = await agent.session.getAvailableModes();
1852
1879
  agent.availableModes = modes;
@@ -1868,9 +1895,9 @@ export class AgentManager {
1868
1895
  agent.pendingPermissions.clear();
1869
1896
  }
1870
1897
  this.syncFeaturesFromSession(agent);
1871
- await this.refreshRuntimeInfo(agent);
1898
+ await this.refreshRuntimeInfo(agent, options);
1872
1899
  }
1873
- async refreshRuntimeInfo(agent) {
1900
+ async refreshRuntimeInfo(agent, options) {
1874
1901
  try {
1875
1902
  const newInfo = await agent.session.getRuntimeInfo();
1876
1903
  const changed = newInfo.model !== agent.runtimeInfo?.model ||
@@ -1882,7 +1909,7 @@ export class AgentManager {
1882
1909
  agent.persistence = attachPersistenceCwd({ provider: agent.provider, sessionId: newInfo.sessionId }, agent.cwd);
1883
1910
  }
1884
1911
  // Emit state if runtimeInfo changed so clients get the updated model
1885
- if (changed) {
1912
+ if (changed && options?.emit !== false) {
1886
1913
  this.emitState(agent);
1887
1914
  }
1888
1915
  }
@@ -2503,6 +2530,15 @@ export class AgentManager {
2503
2530
  }
2504
2531
  return normalized;
2505
2532
  }
2533
+ async prepareSessionConfig(config, agentId) {
2534
+ const storedConfig = await this.normalizeConfig(stripInternalPaseoMcpServer(config));
2535
+ const launchConfig = this.applyDaemonAppendSystemPrompt(withRuntimePaseoMcpServer({
2536
+ config: storedConfig,
2537
+ agentId,
2538
+ mcpBaseUrl: this.mcpBaseUrl,
2539
+ }));
2540
+ return { storedConfig, launchConfig };
2541
+ }
2506
2542
  applyDaemonAppendSystemPrompt(config) {
2507
2543
  const daemonAppendSystemPrompt = this.appendSystemPrompt.trim();
2508
2544
  const next = { ...config };
@@ -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
  }