@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
@@ -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,9 +74,11 @@ 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;
81
+ sessionSummarizeEvents: unknown[];
79
82
  sessionSummarizeResponse: OpenCodeResponse;
80
83
  sessionUpdateResponse: OpenCodeResponse;
81
84
  private readonly queuedEventStream;
@@ -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,9 +68,13 @@ 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 = {};
77
+ this.sessionSummarizeEvents = [idleEvent()];
73
78
  this.sessionSummarizeResponse = { data: {} };
74
79
  this.sessionUpdateResponse = {};
75
80
  this.queuedEventStream = createQueuedEventStream();
@@ -169,6 +174,10 @@ export class TestOpenCodeClient {
169
174
  this.calls.sessionDelete.push(parameters);
170
175
  return this.sessionDeleteResponse;
171
176
  },
177
+ get: async (parameters) => {
178
+ this.calls.sessionGet.push(parameters);
179
+ return this.sessionGetResponse;
180
+ },
172
181
  messages: async (parameters) => {
173
182
  this.calls.sessionMessages.push(parameters);
174
183
  return this.sessionMessagesResponse;
@@ -182,6 +191,9 @@ export class TestOpenCodeClient {
182
191
  },
183
192
  summarize: async (parameters) => {
184
193
  this.calls.sessionSummarize.push(parameters);
194
+ for (const event of this.sessionSummarizeEvents) {
195
+ this.emitEvent(event);
196
+ }
185
197
  return this.sessionSummarizeResponse;
186
198
  },
187
199
  update: async (parameters) => {
@@ -1,6 +1,6 @@
1
- import { type AssistantMessage as OpenCodeAssistantMessage, type Event as OpenCodeEvent, type FilePartInput as OpenCodeFilePartInput, type OpencodeClient, type TextPartInput as OpenCodeTextPartInput } from "@opencode-ai/sdk/v2/client";
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 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";
@@ -10,6 +10,10 @@ type OpenCodeAgentConfig = AgentSessionConfig & {
10
10
  provider: "opencode";
11
11
  };
12
12
  type OpenCodeMessageRole = "user" | "assistant";
13
+ interface OpenCodeSessionMessage {
14
+ info: OpenCodeMessage;
15
+ parts: OpenCodePart[];
16
+ }
13
17
  declare function reconcileOpenCodeSessionClose(params: {
14
18
  client: Pick<OpencodeClient, "session">;
15
19
  sessionId: string;
@@ -79,8 +83,10 @@ declare function mergeOpenCodeStepFinishUsage(usage: AgentUsage, part: {
79
83
  }): void;
80
84
  declare function hasNormalizedOpenCodeUsage(usage: AgentUsage): boolean;
81
85
  declare function buildOpenCodePromptParts(prompt: AgentPromptInput): Array<OpenCodeTextPartInput | OpenCodeFilePartInput>;
86
+ declare function buildOpenCodeSessionTimeline(messages: ReadonlyArray<OpenCodeSessionMessage>): AgentTimelineItem[];
82
87
  export declare const __openCodeInternals: {
83
88
  buildOpenCodePromptParts: typeof buildOpenCodePromptParts;
89
+ buildOpenCodeSessionTimeline: typeof buildOpenCodeSessionTimeline;
84
90
  buildOpenCodeModelContextWindowLookup: typeof buildOpenCodeModelContextWindowLookup;
85
91
  buildOpenCodeModelDefinition: typeof buildOpenCodeModelDefinition;
86
92
  buildOpenCodeModelLookupKey: typeof buildOpenCodeModelLookupKey;
@@ -114,7 +120,8 @@ export declare class OpenCodeAgentClient implements AgentClient {
114
120
  listModes(options: ListModesOptions): Promise<AgentMode[]>;
115
121
  listCommands(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
116
122
  listFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
117
- listPersistedAgents(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
123
+ listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
124
+ importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
118
125
  isAvailable(): Promise<boolean>;
119
126
  shutdown(): Promise<void>;
120
127
  getDiagnostic(): Promise<{
@@ -133,6 +140,11 @@ export interface OpenCodeEventTranslationState {
133
140
  sessionTotalCostUsd?: number;
134
141
  streamedPartKeys: Set<string>;
135
142
  emittedStructuredMessageIds: Set<string>;
143
+ compactionSummaryMessageIds: Set<string>;
144
+ emittedCompactionPartIds: Set<string>;
145
+ suppressAssistantMessagesUntilIdle?: {
146
+ active: boolean;
147
+ };
136
148
  /** Tracks the type of each part by ID, learned from message.part.updated events. */
137
149
  partTypes: Map<string, string>;
138
150
  subAgentsByCallId?: Map<string, OpenCodeSubAgentActivityState>;
@@ -186,6 +198,9 @@ declare class OpenCodeAgentSession implements AgentSession {
186
198
  private streamedPartKeys;
187
199
  /** Tracks assistant messages already emitted from structured payloads. */
188
200
  private emittedStructuredMessageIds;
201
+ private compactionSummaryMessageIds;
202
+ private emittedCompactionPartIds;
203
+ private suppressAssistantMessagesUntilIdle;
189
204
  /** Tracks the type of each part by ID, learned from message.part.updated events. */
190
205
  private partTypes;
191
206
  private availableModesCache;
@@ -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();
@@ -728,6 +720,13 @@ function buildOpenCodeReplayPartTimelineEvent(params) {
728
720
  part,
729
721
  });
730
722
  }
723
+ function isOpenCodeCompactionSummaryMessage(message) {
724
+ return (message.role === "assistant" &&
725
+ (message.summary === true || message.agent === "compaction" || message.mode === "compaction"));
726
+ }
727
+ function findOpenCodeCompactionPart(message) {
728
+ return message.parts.find((part) => part.type === "compaction");
729
+ }
731
730
  async function readOpenCodeSessionMessagesFromSdk(client, session) {
732
731
  const response = await client.session.messages({
733
732
  sessionID: session.id,
@@ -739,7 +738,24 @@ async function readOpenCodeSessionMessagesFromSdk(client, session) {
739
738
  return filterOpenCodeRevertedMessages(response.data, session.revert);
740
739
  }
741
740
  function buildOpenCodeSessionTimeline(messages) {
742
- return messages.flatMap((message) => buildOpenCodeReplayTimelineEvents(message).map((event) => event.item));
741
+ const timeline = [];
742
+ let hideNextAssistantAfterCompaction = false;
743
+ for (const message of messages) {
744
+ const compactionPart = findOpenCodeCompactionPart(message);
745
+ if (message.info.role === "assistant" && hideNextAssistantAfterCompaction) {
746
+ hideNextAssistantAfterCompaction = false;
747
+ continue;
748
+ }
749
+ if (message.info.role === "user" && !compactionPart) {
750
+ hideNextAssistantAfterCompaction = false;
751
+ }
752
+ timeline.push(...buildOpenCodeReplayTimelineEvents(message).map((event) => event.item));
753
+ if (message.info.role === "user" && compactionPart) {
754
+ timeline.push(createCompactionTimelineItem("completed", compactionPart.auto ? "auto" : "manual"));
755
+ hideNextAssistantAfterCompaction = true;
756
+ }
757
+ }
758
+ return timeline;
743
759
  }
744
760
  function filterOpenCodeRevertedMessages(messages, revert) {
745
761
  if (!revert?.messageID || revert.partID) {
@@ -778,6 +794,9 @@ function readOpenCodeMessageModel(message) {
778
794
  }
779
795
  function buildOpenCodeReplayTimelineEvents(message) {
780
796
  const { info, parts } = message;
797
+ if (isOpenCodeCompactionSummaryMessage(info)) {
798
+ return [];
799
+ }
781
800
  if (info.role === "user") {
782
801
  const text = parts
783
802
  .filter((part) => part.type === "text")
@@ -816,6 +835,7 @@ function buildOpenCodeReplayTimelineEvents(message) {
816
835
  }
817
836
  export const __openCodeInternals = {
818
837
  buildOpenCodePromptParts,
838
+ buildOpenCodeSessionTimeline,
819
839
  buildOpenCodeModelContextWindowLookup,
820
840
  buildOpenCodeModelDefinition,
821
841
  buildOpenCodeModelLookupKey,
@@ -1005,7 +1025,7 @@ export class OpenCodeAgentClient {
1005
1025
  async listFeatures(config) {
1006
1026
  return [buildOpenCodeAutoAcceptFeature(this.assertConfig(config))];
1007
1027
  }
1008
- async listPersistedAgents(options) {
1028
+ async listImportableSessions(options) {
1009
1029
  const acquisition = await this.runtime.acquireServer({ force: false });
1010
1030
  const { url } = acquisition.server;
1011
1031
  const client = this.runtime.createClient({
@@ -1013,7 +1033,42 @@ export class OpenCodeAgentClient {
1013
1033
  directory: options?.cwd ?? "",
1014
1034
  });
1015
1035
  try {
1016
- 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
+ });
1017
1072
  }
1018
1073
  finally {
1019
1074
  acquisition.release();
@@ -1151,6 +1206,7 @@ async function listOpenCodeCommandsFromSdk(client, directory) {
1151
1206
  name: cmd.name,
1152
1207
  description: cmd.description ?? "",
1153
1208
  argumentHint: cmd.hints?.length ? cmd.hints.join(" ") : "",
1209
+ kind: cmd.source === "skill" ? "skill" : "command",
1154
1210
  });
1155
1211
  }
1156
1212
  return Array.from(commandsByName.values());
@@ -1370,6 +1426,11 @@ export function translateOpenCodeEvent(event, state) {
1370
1426
  function resetOpenCodeTurnTrackingState(state) {
1371
1427
  state.streamedPartKeys.clear();
1372
1428
  state.partTypes.clear();
1429
+ state.compactionSummaryMessageIds.clear();
1430
+ state.emittedCompactionPartIds.clear();
1431
+ if (state.suppressAssistantMessagesUntilIdle) {
1432
+ state.suppressAssistantMessagesUntilIdle.active = false;
1433
+ }
1373
1434
  }
1374
1435
  function getOpenCodeSubAgentMaps(state) {
1375
1436
  state.subAgentsByCallId ?? (state.subAgentsByCallId = new Map());
@@ -1592,6 +1653,14 @@ function appendOpenCodeMessageUpdated(event, state, events) {
1592
1653
  if (info.role !== "assistant") {
1593
1654
  return;
1594
1655
  }
1656
+ if (state.suppressAssistantMessagesUntilIdle?.active) {
1657
+ state.compactionSummaryMessageIds.add(info.id);
1658
+ return;
1659
+ }
1660
+ if (isOpenCodeCompactionSummaryMessage(info)) {
1661
+ state.compactionSummaryMessageIds.add(info.id);
1662
+ return;
1663
+ }
1595
1664
  const modelLookupKey = resolveOpenCodeModelLookupKeyFromAssistantMessage(info);
1596
1665
  if (modelLookupKey) {
1597
1666
  const contextWindowMaxTokens = state.modelContextWindowsByModelKey?.get(modelLookupKey);
@@ -1638,6 +1707,13 @@ function appendOpenCodeMessagePartUpdated(event, state, events) {
1638
1707
  }
1639
1708
  const messageRole = state.messageRoles.get(part.messageID);
1640
1709
  state.partTypes.set(part.id, part.type);
1710
+ if (state.compactionSummaryMessageIds.has(part.messageID)) {
1711
+ return;
1712
+ }
1713
+ if (shouldSuppressOpenCodeAssistantPart(part, messageRole, state)) {
1714
+ state.compactionSummaryMessageIds.add(part.messageID);
1715
+ return;
1716
+ }
1641
1717
  if (part.type === "text") {
1642
1718
  appendOpenCodeTextPart(part, messageRole, state, events);
1643
1719
  return;
@@ -1654,6 +1730,10 @@ function appendOpenCodeMessagePartUpdated(event, state, events) {
1654
1730
  return;
1655
1731
  }
1656
1732
  if (part.type === "compaction") {
1733
+ if (state.emittedCompactionPartIds.has(part.id)) {
1734
+ return;
1735
+ }
1736
+ state.emittedCompactionPartIds.add(part.id);
1657
1737
  events.push({
1658
1738
  type: "timeline",
1659
1739
  provider: "opencode",
@@ -1678,6 +1758,11 @@ function appendOpenCodeMessagePartUpdated(event, state, events) {
1678
1758
  }
1679
1759
  }
1680
1760
  }
1761
+ function shouldSuppressOpenCodeAssistantPart(part, messageRole, state) {
1762
+ return (state.suppressAssistantMessagesUntilIdle?.active === true &&
1763
+ part.type === "text" &&
1764
+ messageRole !== "user");
1765
+ }
1681
1766
  function appendOpenCodeTextPart(part, messageRole, state, events) {
1682
1767
  if (messageRole === "user") {
1683
1768
  return;
@@ -1724,6 +1809,9 @@ function appendOpenCodeMessagePartDelta(event, state, events) {
1724
1809
  const messageRole = messageID ? state.messageRoles.get(messageID) : undefined;
1725
1810
  const knownPartType = partID ? state.partTypes.get(partID) : undefined;
1726
1811
  const isReasoning = knownPartType === "reasoning" || field === "reasoning";
1812
+ if (messageID && state.compactionSummaryMessageIds.has(messageID)) {
1813
+ return;
1814
+ }
1727
1815
  if (isReasoning) {
1728
1816
  if (partID) {
1729
1817
  state.streamedPartKeys.add(`reasoning:${partID}`);
@@ -1741,6 +1829,10 @@ function appendOpenCodeMessagePartDelta(event, state, events) {
1741
1829
  if (messageRole === "user") {
1742
1830
  return;
1743
1831
  }
1832
+ if (messageID && state.suppressAssistantMessagesUntilIdle?.active === true) {
1833
+ state.compactionSummaryMessageIds.add(messageID);
1834
+ return;
1835
+ }
1744
1836
  if (partID) {
1745
1837
  state.streamedPartKeys.add(`text:${partID}`);
1746
1838
  }
@@ -1938,6 +2030,9 @@ class OpenCodeAgentSession {
1938
2030
  this.streamedPartKeys = new Set();
1939
2031
  /** Tracks assistant messages already emitted from structured payloads. */
1940
2032
  this.emittedStructuredMessageIds = new Set();
2033
+ this.compactionSummaryMessageIds = new Set();
2034
+ this.emittedCompactionPartIds = new Set();
2035
+ this.suppressAssistantMessagesUntilIdle = { active: false };
1941
2036
  /** Tracks the type of each part by ID, learned from message.part.updated events. */
1942
2037
  this.partTypes = new Map();
1943
2038
  this.availableModesCache = null;
@@ -2069,6 +2164,7 @@ class OpenCodeAgentSession {
2069
2164
  this.accumulatedUsage = contextWindowMaxTokens !== undefined ? { contextWindowMaxTokens } : {};
2070
2165
  const parts = buildOpenCodePromptParts(prompt);
2071
2166
  this.pendingUserMessageText = buildOpenCodeUserTimelineText(prompt);
2167
+ this.suppressAssistantMessagesUntilIdle.active = false;
2072
2168
  const model = this.parseModel(this.config.model);
2073
2169
  const thinkingOptionId = this.config.thinkingOptionId;
2074
2170
  const effectiveVariant = thinkingOptionId ?? undefined;
@@ -2088,6 +2184,7 @@ class OpenCodeAgentSession {
2088
2184
  const slashCommand = await this.resolveSlashCommandInvocation(prompt);
2089
2185
  if (slashCommand) {
2090
2186
  if (slashCommand.commandName === "compact" || slashCommand.commandName === "summarize") {
2187
+ this.suppressAssistantMessagesUntilIdle.active = true;
2091
2188
  void this.client.session
2092
2189
  .summarize({
2093
2190
  sessionID: this.sessionId,
@@ -2096,18 +2193,17 @@ class OpenCodeAgentSession {
2096
2193
  })
2097
2194
  .then((response) => {
2098
2195
  if (response.error) {
2196
+ this.suppressAssistantMessagesUntilIdle.active = false;
2099
2197
  this.finishForegroundTurn({
2100
2198
  type: "turn_failed",
2101
2199
  provider: "opencode",
2102
2200
  error: toDiagnosticErrorMessage(response.error),
2103
2201
  }, turnId);
2104
2202
  }
2105
- else {
2106
- this.finishForegroundTurn({ type: "turn_completed", provider: "opencode", usage: undefined }, turnId);
2107
- }
2108
2203
  return;
2109
2204
  })
2110
2205
  .catch((error) => {
2206
+ this.suppressAssistantMessagesUntilIdle.active = false;
2111
2207
  this.finishForegroundTurn({
2112
2208
  type: "turn_failed",
2113
2209
  provider: "opencode",
@@ -2710,6 +2806,9 @@ class OpenCodeAgentSession {
2710
2806
  sessionTotalCostUsd: this.sessionTotalCostUsd,
2711
2807
  streamedPartKeys: this.streamedPartKeys,
2712
2808
  emittedStructuredMessageIds: this.emittedStructuredMessageIds,
2809
+ compactionSummaryMessageIds: this.compactionSummaryMessageIds,
2810
+ emittedCompactionPartIds: this.emittedCompactionPartIds,
2811
+ suppressAssistantMessagesUntilIdle: this.suppressAssistantMessagesUntilIdle,
2713
2812
  partTypes: this.partTypes,
2714
2813
  subAgentsByCallId: this.subAgentsByCallId,
2715
2814
  subAgentCallIdByChildSessionId: this.subAgentCallIdByChildSessionId,
@@ -1,11 +1,20 @@
1
1
  import type { Logger } from "pino";
2
- 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";
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 ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModesOptions, type ListModelsOptions } from "../../agent-sdk-types.js";
3
4
  import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
4
5
  import type { PiRuntime, PiRuntimeSession } from "./runtime.js";
5
6
  import type { PiSessionState } from "./rpc-types.js";
7
+ export declare const PiProviderParamsSchema: z.ZodObject<{
8
+ sessionDir: z.ZodOptional<z.ZodString>;
9
+ }, "strict", z.ZodTypeAny, {
10
+ sessionDir?: string | undefined;
11
+ }, {
12
+ sessionDir?: string | undefined;
13
+ }>;
6
14
  interface PiRpcAgentClientOptions {
7
15
  logger: Logger;
8
16
  runtimeSettings?: ProviderRuntimeSettings;
17
+ providerParams?: unknown;
9
18
  runtime?: PiRuntime;
10
19
  }
11
20
  interface StartTurnResult {
@@ -35,6 +44,9 @@ export declare class PiRpcAgentSession implements AgentSession {
35
44
  private readonly seenUserEntryIds;
36
45
  private readonly pendingUserMessages;
37
46
  private readonly pendingExtensionResults;
47
+ private outOfBandCompactionEmit;
48
+ private outOfBandCompactionStarted;
49
+ private outOfBandCompactionCompleted;
38
50
  private state;
39
51
  private closed;
40
52
  constructor(options: PiRpcAgentSessionOptions);
@@ -60,10 +72,18 @@ export declare class PiRpcAgentSession implements AgentSession {
60
72
  private runPiTreeExtensionCommand;
61
73
  close(): Promise<void>;
62
74
  listCommands(): Promise<AgentSlashCommand[]>;
75
+ tryHandleOutOfBand(prompt: AgentPromptInput): {
76
+ run(ctx: {
77
+ emit: (event: AgentStreamEvent) => void;
78
+ }): Promise<void>;
79
+ } | null;
63
80
  setModel(modelId: string | null): Promise<void>;
64
81
  setThinkingOption(thinkingOptionId: string | null): Promise<void>;
65
82
  private emit;
66
83
  private currentTurnIdForEvent;
84
+ private parseSlashCommandInput;
85
+ private executeCompactCommand;
86
+ private executeAutoCompactCommand;
67
87
  private requestEntryCapture;
68
88
  private waitForExtensionResult;
69
89
  private resolveExtensionResult;
@@ -78,6 +98,7 @@ export declare class PiRpcAgentSession implements AgentSession {
78
98
  private handleRuntimeEvent;
79
99
  private handleProcessExit;
80
100
  private handleSessionEvent;
101
+ private emitCompactionTimeline;
81
102
  private handleMessageUpdate;
82
103
  private handleMessageEnd;
83
104
  private emitToolCallEvent;
@@ -90,13 +111,15 @@ export declare class PiRpcAgentClient implements AgentClient {
90
111
  readonly capabilities: AgentCapabilityFlags;
91
112
  private readonly logger;
92
113
  private readonly runtimeSettings?;
114
+ private readonly providerParams;
93
115
  private readonly runtime;
94
116
  constructor(options: PiRpcAgentClientOptions);
95
117
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext): Promise<AgentSession>;
96
118
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, _launchContext?: AgentLaunchContext): Promise<AgentSession>;
97
119
  listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
98
120
  listModes(_options: ListModesOptions): Promise<AgentMode[]>;
99
- listPersistedAgents(_options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
121
+ listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
122
+ importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../../agent-sdk-types.js").ImportedProviderSession>;
100
123
  isAvailable(): Promise<boolean>;
101
124
  getDiagnostic(): Promise<{
102
125
  diagnostic: string;