@getpaseo/server 0.1.91-beta.1 → 0.1.91

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 (50) hide show
  1. package/dist/scripts/supervisor.js +21 -0
  2. package/dist/server/server/agent/agent-manager.d.ts +1 -1
  3. package/dist/server/server/agent/agent-manager.js +23 -48
  4. package/dist/server/server/agent/agent-sdk-types.d.ts +15 -0
  5. package/dist/server/server/agent/prompt-attachments.js +8 -0
  6. package/dist/server/server/agent/provider-registry.d.ts +0 -1
  7. package/dist/server/server/agent/provider-registry.js +22 -4
  8. package/dist/server/server/agent/provider-snapshot-manager.js +19 -1
  9. package/dist/server/server/agent/providers/claude/agent.d.ts +5 -2
  10. package/dist/server/server/agent/providers/claude/agent.js +6 -2
  11. package/dist/server/server/agent/providers/claude/models.d.ts +1 -1
  12. package/dist/server/server/agent/providers/claude/models.js +6 -6
  13. package/dist/server/server/agent/providers/codex-app-server-agent.js +9 -5
  14. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +1 -0
  15. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +4 -0
  16. package/dist/server/server/agent/providers/opencode-agent.d.ts +16 -2
  17. package/dist/server/server/agent/providers/opencode-agent.js +75 -4
  18. package/dist/server/server/agent/providers/pi/agent.d.ts +23 -1
  19. package/dist/server/server/agent/providers/pi/agent.js +219 -13
  20. package/dist/server/server/agent/providers/pi/cli-runtime.js +9 -0
  21. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +9 -0
  22. package/dist/server/server/agent/providers/pi/runtime.d.ts +2 -0
  23. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +12 -0
  24. package/dist/server/server/agent/providers/pi/session-descriptor.js +304 -0
  25. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +8 -0
  26. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +22 -0
  27. package/dist/server/server/agent/runtime-mcp-config.d.ts +8 -0
  28. package/dist/server/server/agent/runtime-mcp-config.js +50 -0
  29. package/dist/server/server/auth.js +16 -1
  30. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +2 -2
  31. package/dist/server/server/daemon-worker.js +84 -1
  32. package/dist/server/server/file-upload/index.d.ts +27 -0
  33. package/dist/server/server/file-upload/index.js +158 -0
  34. package/dist/server/server/loop-service.d.ts +12 -12
  35. package/dist/server/server/persisted-config.d.ts +11 -0
  36. package/dist/server/server/persisted-config.js +2 -1
  37. package/dist/server/server/persistence-hooks.js +6 -4
  38. package/dist/server/server/session.d.ts +5 -2
  39. package/dist/server/server/session.js +20 -2
  40. package/dist/server/server/speech/providers/local/runtime.js +1 -0
  41. package/dist/server/server/speech/providers/local/worker-client.d.ts +14 -1
  42. package/dist/server/server/speech/providers/local/worker-client.js +169 -7
  43. package/dist/server/server/websocket-server.d.ts +2 -0
  44. package/dist/server/server/websocket-server.js +20 -7
  45. package/dist/server/server/workspace-registry.d.ts +4 -4
  46. package/dist/server/utils/directory-suggestions.js +10 -5
  47. package/dist/server/utils/worktree.d.ts +4 -0
  48. package/dist/server/utils/worktree.js +19 -2
  49. package/dist/src/server/persisted-config.js +2 -1
  50. package/package.json +5 -5
@@ -728,6 +728,13 @@ function buildOpenCodeReplayPartTimelineEvent(params) {
728
728
  part,
729
729
  });
730
730
  }
731
+ function isOpenCodeCompactionSummaryMessage(message) {
732
+ return (message.role === "assistant" &&
733
+ (message.summary === true || message.agent === "compaction" || message.mode === "compaction"));
734
+ }
735
+ function findOpenCodeCompactionPart(message) {
736
+ return message.parts.find((part) => part.type === "compaction");
737
+ }
731
738
  async function readOpenCodeSessionMessagesFromSdk(client, session) {
732
739
  const response = await client.session.messages({
733
740
  sessionID: session.id,
@@ -739,7 +746,24 @@ async function readOpenCodeSessionMessagesFromSdk(client, session) {
739
746
  return filterOpenCodeRevertedMessages(response.data, session.revert);
740
747
  }
741
748
  function buildOpenCodeSessionTimeline(messages) {
742
- return messages.flatMap((message) => buildOpenCodeReplayTimelineEvents(message).map((event) => event.item));
749
+ const timeline = [];
750
+ let hideNextAssistantAfterCompaction = false;
751
+ for (const message of messages) {
752
+ const compactionPart = findOpenCodeCompactionPart(message);
753
+ if (message.info.role === "assistant" && hideNextAssistantAfterCompaction) {
754
+ hideNextAssistantAfterCompaction = false;
755
+ continue;
756
+ }
757
+ if (message.info.role === "user" && !compactionPart) {
758
+ hideNextAssistantAfterCompaction = false;
759
+ }
760
+ timeline.push(...buildOpenCodeReplayTimelineEvents(message).map((event) => event.item));
761
+ if (message.info.role === "user" && compactionPart) {
762
+ timeline.push(createCompactionTimelineItem("completed", compactionPart.auto ? "auto" : "manual"));
763
+ hideNextAssistantAfterCompaction = true;
764
+ }
765
+ }
766
+ return timeline;
743
767
  }
744
768
  function filterOpenCodeRevertedMessages(messages, revert) {
745
769
  if (!revert?.messageID || revert.partID) {
@@ -778,6 +802,9 @@ function readOpenCodeMessageModel(message) {
778
802
  }
779
803
  function buildOpenCodeReplayTimelineEvents(message) {
780
804
  const { info, parts } = message;
805
+ if (isOpenCodeCompactionSummaryMessage(info)) {
806
+ return [];
807
+ }
781
808
  if (info.role === "user") {
782
809
  const text = parts
783
810
  .filter((part) => part.type === "text")
@@ -816,6 +843,7 @@ function buildOpenCodeReplayTimelineEvents(message) {
816
843
  }
817
844
  export const __openCodeInternals = {
818
845
  buildOpenCodePromptParts,
846
+ buildOpenCodeSessionTimeline,
819
847
  buildOpenCodeModelContextWindowLookup,
820
848
  buildOpenCodeModelDefinition,
821
849
  buildOpenCodeModelLookupKey,
@@ -1370,6 +1398,11 @@ export function translateOpenCodeEvent(event, state) {
1370
1398
  function resetOpenCodeTurnTrackingState(state) {
1371
1399
  state.streamedPartKeys.clear();
1372
1400
  state.partTypes.clear();
1401
+ state.compactionSummaryMessageIds.clear();
1402
+ state.emittedCompactionPartIds.clear();
1403
+ if (state.suppressAssistantMessagesUntilIdle) {
1404
+ state.suppressAssistantMessagesUntilIdle.active = false;
1405
+ }
1373
1406
  }
1374
1407
  function getOpenCodeSubAgentMaps(state) {
1375
1408
  state.subAgentsByCallId ?? (state.subAgentsByCallId = new Map());
@@ -1592,6 +1625,14 @@ function appendOpenCodeMessageUpdated(event, state, events) {
1592
1625
  if (info.role !== "assistant") {
1593
1626
  return;
1594
1627
  }
1628
+ if (state.suppressAssistantMessagesUntilIdle?.active) {
1629
+ state.compactionSummaryMessageIds.add(info.id);
1630
+ return;
1631
+ }
1632
+ if (isOpenCodeCompactionSummaryMessage(info)) {
1633
+ state.compactionSummaryMessageIds.add(info.id);
1634
+ return;
1635
+ }
1595
1636
  const modelLookupKey = resolveOpenCodeModelLookupKeyFromAssistantMessage(info);
1596
1637
  if (modelLookupKey) {
1597
1638
  const contextWindowMaxTokens = state.modelContextWindowsByModelKey?.get(modelLookupKey);
@@ -1638,6 +1679,13 @@ function appendOpenCodeMessagePartUpdated(event, state, events) {
1638
1679
  }
1639
1680
  const messageRole = state.messageRoles.get(part.messageID);
1640
1681
  state.partTypes.set(part.id, part.type);
1682
+ if (state.compactionSummaryMessageIds.has(part.messageID)) {
1683
+ return;
1684
+ }
1685
+ if (shouldSuppressOpenCodeAssistantPart(part, messageRole, state)) {
1686
+ state.compactionSummaryMessageIds.add(part.messageID);
1687
+ return;
1688
+ }
1641
1689
  if (part.type === "text") {
1642
1690
  appendOpenCodeTextPart(part, messageRole, state, events);
1643
1691
  return;
@@ -1654,6 +1702,10 @@ function appendOpenCodeMessagePartUpdated(event, state, events) {
1654
1702
  return;
1655
1703
  }
1656
1704
  if (part.type === "compaction") {
1705
+ if (state.emittedCompactionPartIds.has(part.id)) {
1706
+ return;
1707
+ }
1708
+ state.emittedCompactionPartIds.add(part.id);
1657
1709
  events.push({
1658
1710
  type: "timeline",
1659
1711
  provider: "opencode",
@@ -1678,6 +1730,11 @@ function appendOpenCodeMessagePartUpdated(event, state, events) {
1678
1730
  }
1679
1731
  }
1680
1732
  }
1733
+ function shouldSuppressOpenCodeAssistantPart(part, messageRole, state) {
1734
+ return (state.suppressAssistantMessagesUntilIdle?.active === true &&
1735
+ part.type === "text" &&
1736
+ messageRole !== "user");
1737
+ }
1681
1738
  function appendOpenCodeTextPart(part, messageRole, state, events) {
1682
1739
  if (messageRole === "user") {
1683
1740
  return;
@@ -1724,6 +1781,9 @@ function appendOpenCodeMessagePartDelta(event, state, events) {
1724
1781
  const messageRole = messageID ? state.messageRoles.get(messageID) : undefined;
1725
1782
  const knownPartType = partID ? state.partTypes.get(partID) : undefined;
1726
1783
  const isReasoning = knownPartType === "reasoning" || field === "reasoning";
1784
+ if (messageID && state.compactionSummaryMessageIds.has(messageID)) {
1785
+ return;
1786
+ }
1727
1787
  if (isReasoning) {
1728
1788
  if (partID) {
1729
1789
  state.streamedPartKeys.add(`reasoning:${partID}`);
@@ -1741,6 +1801,10 @@ function appendOpenCodeMessagePartDelta(event, state, events) {
1741
1801
  if (messageRole === "user") {
1742
1802
  return;
1743
1803
  }
1804
+ if (messageID && state.suppressAssistantMessagesUntilIdle?.active === true) {
1805
+ state.compactionSummaryMessageIds.add(messageID);
1806
+ return;
1807
+ }
1744
1808
  if (partID) {
1745
1809
  state.streamedPartKeys.add(`text:${partID}`);
1746
1810
  }
@@ -1938,6 +2002,9 @@ class OpenCodeAgentSession {
1938
2002
  this.streamedPartKeys = new Set();
1939
2003
  /** Tracks assistant messages already emitted from structured payloads. */
1940
2004
  this.emittedStructuredMessageIds = new Set();
2005
+ this.compactionSummaryMessageIds = new Set();
2006
+ this.emittedCompactionPartIds = new Set();
2007
+ this.suppressAssistantMessagesUntilIdle = { active: false };
1941
2008
  /** Tracks the type of each part by ID, learned from message.part.updated events. */
1942
2009
  this.partTypes = new Map();
1943
2010
  this.availableModesCache = null;
@@ -2069,6 +2136,7 @@ class OpenCodeAgentSession {
2069
2136
  this.accumulatedUsage = contextWindowMaxTokens !== undefined ? { contextWindowMaxTokens } : {};
2070
2137
  const parts = buildOpenCodePromptParts(prompt);
2071
2138
  this.pendingUserMessageText = buildOpenCodeUserTimelineText(prompt);
2139
+ this.suppressAssistantMessagesUntilIdle.active = false;
2072
2140
  const model = this.parseModel(this.config.model);
2073
2141
  const thinkingOptionId = this.config.thinkingOptionId;
2074
2142
  const effectiveVariant = thinkingOptionId ?? undefined;
@@ -2088,6 +2156,7 @@ class OpenCodeAgentSession {
2088
2156
  const slashCommand = await this.resolveSlashCommandInvocation(prompt);
2089
2157
  if (slashCommand) {
2090
2158
  if (slashCommand.commandName === "compact" || slashCommand.commandName === "summarize") {
2159
+ this.suppressAssistantMessagesUntilIdle.active = true;
2091
2160
  void this.client.session
2092
2161
  .summarize({
2093
2162
  sessionID: this.sessionId,
@@ -2096,18 +2165,17 @@ class OpenCodeAgentSession {
2096
2165
  })
2097
2166
  .then((response) => {
2098
2167
  if (response.error) {
2168
+ this.suppressAssistantMessagesUntilIdle.active = false;
2099
2169
  this.finishForegroundTurn({
2100
2170
  type: "turn_failed",
2101
2171
  provider: "opencode",
2102
2172
  error: toDiagnosticErrorMessage(response.error),
2103
2173
  }, turnId);
2104
2174
  }
2105
- else {
2106
- this.finishForegroundTurn({ type: "turn_completed", provider: "opencode", usage: undefined }, turnId);
2107
- }
2108
2175
  return;
2109
2176
  })
2110
2177
  .catch((error) => {
2178
+ this.suppressAssistantMessagesUntilIdle.active = false;
2111
2179
  this.finishForegroundTurn({
2112
2180
  type: "turn_failed",
2113
2181
  provider: "opencode",
@@ -2710,6 +2778,9 @@ class OpenCodeAgentSession {
2710
2778
  sessionTotalCostUsd: this.sessionTotalCostUsd,
2711
2779
  streamedPartKeys: this.streamedPartKeys,
2712
2780
  emittedStructuredMessageIds: this.emittedStructuredMessageIds,
2781
+ compactionSummaryMessageIds: this.compactionSummaryMessageIds,
2782
+ emittedCompactionPartIds: this.emittedCompactionPartIds,
2783
+ suppressAssistantMessagesUntilIdle: this.suppressAssistantMessagesUntilIdle,
2713
2784
  partTypes: this.partTypes,
2714
2785
  subAgentsByCallId: this.subAgentsByCallId,
2715
2786
  subAgentCallIdByChildSessionId: this.subAgentCallIdByChildSessionId,
@@ -1,11 +1,20 @@
1
1
  import type { Logger } from "pino";
2
+ import { z } from "zod";
2
3
  import { type AgentCapabilityFlags, type AgentClient, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type ListPersistedAgentsOptions, type ListModesOptions, type ListModelsOptions, type PersistedAgentDescriptor } from "../../agent-sdk-types.js";
3
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,14 @@ 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
+ listPersistedAgents(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
100
122
  isAvailable(): Promise<boolean>;
101
123
  getDiagnostic(): Promise<{
102
124
  diagnostic: string;
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { homedir, tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
+ import { z } from "zod";
5
6
  import { runProviderTurn } from "../provider-runner.js";
6
7
  import { checkProviderLaunchAvailable, resolveProviderLaunch, } from "../../provider-launch-config.js";
7
8
  import { renderPromptAttachmentAsText } from "../../prompt-attachments.js";
@@ -10,6 +11,7 @@ import { buildBinaryDiagnosticRows, formatDiagnosticStatus, formatProviderDiagno
10
11
  import { getUserMessageText, streamPiHistory, } from "./history-mapper.js";
11
12
  import { PiCliRuntime } from "./cli-runtime.js";
12
13
  import { revertPiConversation } from "./rewind.js";
14
+ import { listPiPersistedAgents } from "./session-descriptor.js";
13
15
  import { mapToolDetail, parseToolArgs, parseToolResult, resolveToolCallName, } from "./tool-call-mapper.js";
14
16
  const PI_PROVIDER = "pi";
15
17
  const DEFAULT_PI_THINKING_LEVEL = "medium";
@@ -23,6 +25,23 @@ const QUESTION_RESPONSE_HEADER = "Response";
23
25
  const QUESTION_COMMENT_HEADER = "Comment";
24
26
  const PI_ASK_USER_FREEFORM_SENTINEL = "✏️ Type custom response...";
25
27
  const COMBINED_ASK_USER_METADATA = "ask_user_select_optional_comment";
28
+ export const PiProviderParamsSchema = z
29
+ .object({
30
+ sessionDir: z.string().min(1).optional(),
31
+ })
32
+ .strict();
33
+ const PI_HANDLED_BUILTIN_SLASH_COMMANDS = [
34
+ {
35
+ name: "compact",
36
+ description: "Manually compact the session context",
37
+ argumentHint: "[instructions]",
38
+ },
39
+ {
40
+ name: "autocompact",
41
+ description: "Toggle automatic context compaction",
42
+ argumentHint: "[on|off|toggle]",
43
+ },
44
+ ];
26
45
  const PI_CAPABILITIES = {
27
46
  supportsStreaming: true,
28
47
  supportsSessionPersistence: true,
@@ -76,6 +95,19 @@ function normalizePiThinkingOption(value) {
76
95
  }
77
96
  return isPiThinkingLevel(value) ? value : null;
78
97
  }
98
+ function parseAutoCompactMode(value) {
99
+ const mode = (value ?? "toggle").trim().toLowerCase();
100
+ if (mode === "on" || mode === "true" || mode === "enable" || mode === "enabled") {
101
+ return true;
102
+ }
103
+ if (mode === "off" || mode === "false" || mode === "disable" || mode === "disabled") {
104
+ return false;
105
+ }
106
+ if (mode === "toggle") {
107
+ return "toggle";
108
+ }
109
+ return "unknown";
110
+ }
79
111
  function mapThinkingOption(option) {
80
112
  const mappedOption = {
81
113
  id: option.id,
@@ -654,6 +686,9 @@ export class PiRpcAgentSession {
654
686
  this.seenUserEntryIds = new Set();
655
687
  this.pendingUserMessages = [];
656
688
  this.pendingExtensionResults = new Map();
689
+ this.outOfBandCompactionEmit = null;
690
+ this.outOfBandCompactionStarted = false;
691
+ this.outOfBandCompactionCompleted = false;
657
692
  this.closed = false;
658
693
  this.runtimeSession = options.runtimeSession;
659
694
  this.config = options.config;
@@ -821,11 +856,41 @@ export class PiRpcAgentSession {
821
856
  }
822
857
  async listCommands() {
823
858
  const commands = await this.runtimeSession.getCommands();
824
- return commands.map((command) => ({
825
- name: command.name,
826
- description: command.description ?? command.source,
827
- argumentHint: "",
828
- }));
859
+ const mappedCommands = new Map(PI_HANDLED_BUILTIN_SLASH_COMMANDS.map((command) => [command.name, { ...command }]));
860
+ for (const command of commands) {
861
+ const knownCommand = mappedCommands.get(command.name);
862
+ mappedCommands.set(command.name, {
863
+ name: command.name,
864
+ description: command.description ?? command.source,
865
+ argumentHint: knownCommand?.argumentHint ?? "",
866
+ });
867
+ }
868
+ return [...mappedCommands.values()];
869
+ }
870
+ tryHandleOutOfBand(prompt) {
871
+ if (typeof prompt !== "string") {
872
+ return null;
873
+ }
874
+ const parsed = this.parseSlashCommandInput(prompt);
875
+ if (!parsed) {
876
+ return null;
877
+ }
878
+ const commandName = parsed.commandName.toLowerCase();
879
+ if (commandName === "compact") {
880
+ return {
881
+ run: async ({ emit }) => {
882
+ await this.executeCompactCommand(parsed.args, emit);
883
+ },
884
+ };
885
+ }
886
+ if (commandName === "autocompact") {
887
+ return {
888
+ run: async ({ emit }) => {
889
+ await this.executeAutoCompactCommand(parsed.args, emit);
890
+ },
891
+ };
892
+ }
893
+ return null;
829
894
  }
830
895
  async setModel(modelId) {
831
896
  const parsedReference = parseModelReference(modelId);
@@ -860,6 +925,117 @@ export class PiRpcAgentSession {
860
925
  currentTurnIdForEvent() {
861
926
  return this.activeTurnId ?? undefined;
862
927
  }
928
+ parseSlashCommandInput(text) {
929
+ const trimmed = text.trim();
930
+ if (!trimmed.startsWith("/") || trimmed.length <= 1) {
931
+ return null;
932
+ }
933
+ const withoutPrefix = trimmed.slice(1);
934
+ const firstWhitespaceIdx = withoutPrefix.search(/\s/);
935
+ const commandName = firstWhitespaceIdx === -1 ? withoutPrefix : withoutPrefix.slice(0, firstWhitespaceIdx);
936
+ if (!commandName || commandName.includes("/")) {
937
+ return null;
938
+ }
939
+ const rawArgs = firstWhitespaceIdx === -1 ? "" : withoutPrefix.slice(firstWhitespaceIdx + 1).trim();
940
+ return rawArgs.length > 0 ? { commandName, args: rawArgs } : { commandName };
941
+ }
942
+ async executeCompactCommand(customInstructions, emit) {
943
+ if (this.outOfBandCompactionEmit) {
944
+ throw new Error("A Pi compact command is already running");
945
+ }
946
+ this.outOfBandCompactionEmit = emit;
947
+ this.outOfBandCompactionStarted = false;
948
+ this.outOfBandCompactionCompleted = false;
949
+ try {
950
+ await this.runtimeSession.compact(customInstructions);
951
+ }
952
+ catch (error) {
953
+ const message = error instanceof Error ? error.message : String(error);
954
+ if (this.outOfBandCompactionEmit === emit &&
955
+ this.outOfBandCompactionStarted &&
956
+ !this.outOfBandCompactionCompleted) {
957
+ this.emitCompactionTimeline({
958
+ turnId: undefined,
959
+ item: {
960
+ type: "compaction",
961
+ status: "completed",
962
+ trigger: "manual",
963
+ },
964
+ });
965
+ }
966
+ emit({
967
+ type: "timeline",
968
+ provider: PI_PROVIDER,
969
+ item: {
970
+ type: "assistant_message",
971
+ text: `[Error] Failed to compact context: ${message}`,
972
+ },
973
+ });
974
+ }
975
+ finally {
976
+ if (this.outOfBandCompactionEmit === emit && !this.outOfBandCompactionStarted) {
977
+ this.outOfBandCompactionEmit = null;
978
+ this.outOfBandCompactionStarted = false;
979
+ this.outOfBandCompactionCompleted = false;
980
+ }
981
+ }
982
+ }
983
+ async executeAutoCompactCommand(mode, emit) {
984
+ let enabled = parseAutoCompactMode(mode);
985
+ if (enabled === "unknown") {
986
+ emit({
987
+ type: "timeline",
988
+ provider: PI_PROVIDER,
989
+ item: {
990
+ type: "assistant_message",
991
+ text: "[Error] Usage: /autocompact [on|off|toggle]",
992
+ },
993
+ });
994
+ return;
995
+ }
996
+ if (enabled === "toggle") {
997
+ const state = await this.runtimeSession.getState();
998
+ if (typeof state.autoCompactionEnabled !== "boolean") {
999
+ emit({
1000
+ type: "timeline",
1001
+ provider: PI_PROVIDER,
1002
+ item: {
1003
+ type: "assistant_message",
1004
+ text: "[Error] Auto-compaction state is unavailable. Use /autocompact on or /autocompact off.",
1005
+ },
1006
+ });
1007
+ return;
1008
+ }
1009
+ enabled = !state.autoCompactionEnabled;
1010
+ }
1011
+ try {
1012
+ await this.runtimeSession.setAutoCompaction(enabled);
1013
+ }
1014
+ catch (error) {
1015
+ const message = error instanceof Error ? error.message : String(error);
1016
+ emit({
1017
+ type: "timeline",
1018
+ provider: PI_PROVIDER,
1019
+ item: {
1020
+ type: "assistant_message",
1021
+ text: `[Error] Failed to set auto-compaction: ${message}`,
1022
+ },
1023
+ });
1024
+ return;
1025
+ }
1026
+ this.state = {
1027
+ ...this.state,
1028
+ autoCompactionEnabled: enabled,
1029
+ };
1030
+ emit({
1031
+ type: "timeline",
1032
+ provider: PI_PROVIDER,
1033
+ item: {
1034
+ type: "assistant_message",
1035
+ text: `Auto-compaction ${enabled ? "enabled" : "disabled"}.`,
1036
+ },
1037
+ });
1038
+ }
863
1039
  async requestEntryCapture(reason) {
864
1040
  const requestId = randomUUID();
865
1041
  const resultPromise = this.waitForExtensionResult(requestId);
@@ -1090,9 +1266,7 @@ export class PiRpcAgentSession {
1090
1266
  return;
1091
1267
  }
1092
1268
  case "compaction_start":
1093
- this.emit({
1094
- type: "timeline",
1095
- provider: PI_PROVIDER,
1269
+ this.emitCompactionTimeline({
1096
1270
  turnId,
1097
1271
  item: {
1098
1272
  type: "compaction",
@@ -1102,13 +1276,12 @@ export class PiRpcAgentSession {
1102
1276
  });
1103
1277
  return;
1104
1278
  case "compaction_end":
1105
- this.emit({
1106
- type: "timeline",
1107
- provider: PI_PROVIDER,
1279
+ this.emitCompactionTimeline({
1108
1280
  turnId,
1109
1281
  item: {
1110
1282
  type: "compaction",
1111
1283
  status: "completed",
1284
+ trigger: event.reason === "manual" ? "manual" : "auto",
1112
1285
  },
1113
1286
  });
1114
1287
  return;
@@ -1119,6 +1292,33 @@ export class PiRpcAgentSession {
1119
1292
  return;
1120
1293
  }
1121
1294
  }
1295
+ emitCompactionTimeline(input) {
1296
+ const emitOutOfBand = this.outOfBandCompactionEmit;
1297
+ if (emitOutOfBand && input.item.type === "compaction") {
1298
+ if (input.item.status === "loading") {
1299
+ this.outOfBandCompactionStarted = true;
1300
+ }
1301
+ if (input.item.status === "completed") {
1302
+ this.outOfBandCompactionCompleted = true;
1303
+ }
1304
+ }
1305
+ const event = {
1306
+ type: "timeline",
1307
+ provider: PI_PROVIDER,
1308
+ ...(emitOutOfBand ? {} : { turnId: input.turnId }),
1309
+ item: input.item,
1310
+ };
1311
+ if (emitOutOfBand) {
1312
+ emitOutOfBand(event);
1313
+ if (input.item.type === "compaction" && input.item.status === "completed") {
1314
+ this.outOfBandCompactionEmit = null;
1315
+ this.outOfBandCompactionStarted = false;
1316
+ this.outOfBandCompactionCompleted = false;
1317
+ }
1318
+ return;
1319
+ }
1320
+ this.emit(event);
1321
+ }
1122
1322
  handleMessageUpdate(event, turnId) {
1123
1323
  if (event.message.role !== "assistant") {
1124
1324
  return;
@@ -1240,6 +1440,7 @@ export class PiRpcAgentClient {
1240
1440
  this.capabilities = PI_CAPABILITIES;
1241
1441
  this.logger = options.logger;
1242
1442
  this.runtimeSettings = options.runtimeSettings;
1443
+ this.providerParams = PiProviderParamsSchema.parse(options.providerParams ?? {});
1243
1444
  this.runtime = options.runtime ?? createRuntime(options.logger, options.runtimeSettings);
1244
1445
  }
1245
1446
  async createSession(config, launchContext) {
@@ -1332,8 +1533,13 @@ export class PiRpcAgentClient {
1332
1533
  async listModes(_options) {
1333
1534
  return [];
1334
1535
  }
1335
- async listPersistedAgents(_options) {
1336
- return [];
1536
+ async listPersistedAgents(options) {
1537
+ return await listPiPersistedAgents({
1538
+ ...options,
1539
+ provider: PI_PROVIDER,
1540
+ sessionDir: this.providerParams.sessionDir,
1541
+ runtimeSettings: this.runtimeSettings,
1542
+ });
1337
1543
  }
1338
1544
  async isAvailable() {
1339
1545
  const launch = await this.resolvePiLaunch();
@@ -76,6 +76,15 @@ class PiCliRuntimeSession {
76
76
  async prompt(message, images) {
77
77
  await this.request({ type: "prompt", message, ...(images?.length ? { images } : {}) });
78
78
  }
79
+ async compact(customInstructions) {
80
+ await this.request({
81
+ type: "compact",
82
+ ...(customInstructions ? { customInstructions } : {}),
83
+ });
84
+ }
85
+ async setAutoCompaction(enabled) {
86
+ await this.request({ type: "set_auto_compaction", enabled });
87
+ }
79
88
  async abort() {
80
89
  await this.request({ type: "abort" });
81
90
  }
@@ -66,6 +66,7 @@ export interface PiSessionState {
66
66
  thinkingLevel: PiThinkingLevel;
67
67
  isStreaming: boolean;
68
68
  isCompacting: boolean;
69
+ autoCompactionEnabled?: boolean;
69
70
  sessionFile?: string;
70
71
  sessionId: string;
71
72
  sessionName?: string;
@@ -98,6 +99,14 @@ export type PiRpcCommand = {
98
99
  type: "prompt";
99
100
  message: string;
100
101
  images?: PiImageContent[];
102
+ } | {
103
+ id?: string;
104
+ type: "compact";
105
+ customInstructions?: string;
106
+ } | {
107
+ id?: string;
108
+ type: "set_auto_compaction";
109
+ enabled: boolean;
101
110
  } | {
102
111
  id?: string;
103
112
  type: "abort";
@@ -28,6 +28,8 @@ export interface PiRuntimeSession {
28
28
  data: string;
29
29
  mimeType: string;
30
30
  }>): Promise<void>;
31
+ compact(customInstructions?: string): Promise<void>;
32
+ setAutoCompaction(enabled: boolean): Promise<void>;
31
33
  abort(): Promise<void>;
32
34
  getState(): Promise<PiSessionState>;
33
35
  getMessages(): Promise<PiAgentMessage[]>;
@@ -0,0 +1,12 @@
1
+ import type { ListPersistedAgentsOptions, PersistedAgentDescriptor } from "../../agent-sdk-types.js";
2
+ import type { ProviderRuntimeSettings } from "../../provider-launch-config.js";
3
+ interface PiSessionDescriptorOptions extends ListPersistedAgentsOptions {
4
+ provider?: string;
5
+ sessionDir?: string;
6
+ runtimeSettings?: ProviderRuntimeSettings;
7
+ env?: NodeJS.ProcessEnv;
8
+ homeDir?: string;
9
+ }
10
+ export declare function listPiPersistedAgents(options?: PiSessionDescriptorOptions): Promise<PersistedAgentDescriptor[]>;
11
+ export {};
12
+ //# sourceMappingURL=session-descriptor.d.ts.map