@hachej/boring-agent 0.1.55 → 0.1.57

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.
@@ -47,6 +47,7 @@ interface AgentHarnessFactoryInput {
47
47
  runtimeCwd?: string;
48
48
  systemPromptAppend?: string;
49
49
  sessionNamespace?: string;
50
+ sessionRoot?: string;
50
51
  sessionDir?: string;
51
52
  /**
52
53
  * Optional dynamic system-prompt source. Harness calls it whenever it
@@ -68,7 +68,7 @@ function rawWorkspaceFileUrl(path, opts) {
68
68
  }
69
69
 
70
70
  // src/front/chat/PiChatPanel.tsx
71
- import { lazy, Suspense, useCallback as useCallback18, useEffect as useEffect21, useMemo as useMemo12, useRef as useRef16, useState as useState20 } from "react";
71
+ import { lazy, Suspense, useCallback as useCallback18, useEffect as useEffect21, useMemo as useMemo13, useRef as useRef17, useState as useState20 } from "react";
72
72
 
73
73
  // src/front/ArtifactOpenContext.tsx
74
74
  import { createContext, useContext } from "react";
@@ -5091,6 +5091,12 @@ function usePiSessions(options = {}) {
5091
5091
  const loadedDataSourceRef = useRef8(dataSourceKey);
5092
5092
  const requestScopeRef = useRef8(requestScopeKey);
5093
5093
  requestScopeRef.current = requestScopeKey;
5094
+ const remoteSessionOptionsRef = useRef8(options.remoteSessionOptions);
5095
+ remoteSessionOptionsRef.current = options.remoteSessionOptions;
5096
+ const remoteSessionOptionsKey = useMemo3(
5097
+ () => remoteSessionOptionsIdentity(options.remoteSessionOptions),
5098
+ [options.remoteSessionOptions]
5099
+ );
5094
5100
  useEffect8(() => {
5095
5101
  sessionsRef.current = sessions;
5096
5102
  }, [sessions]);
@@ -5253,7 +5259,7 @@ function usePiSessions(options = {}) {
5253
5259
  return;
5254
5260
  }
5255
5261
  const session = createRemoteSession({
5256
- ...options.remoteSessionOptions,
5262
+ ...remoteSessionOptionsRef.current,
5257
5263
  sessionId: activeSessionId,
5258
5264
  workspaceId: options.workspaceId,
5259
5265
  storageScope,
@@ -5265,7 +5271,7 @@ function usePiSessions(options = {}) {
5265
5271
  return () => {
5266
5272
  session.dispose();
5267
5273
  };
5268
- }, [activeSessionId, activeSessionKnown, apiBaseUrl, connectActiveSession, createRemoteSession, enabled, fetchImpl, options.remoteSessionOptions, options.workspaceId, requestHeaders, storageScope]);
5274
+ }, [activeSessionId, activeSessionKnown, apiBaseUrl, connectActiveSession, createRemoteSession, enabled, fetchImpl, remoteSessionOptionsKey, options.workspaceId, requestHeaders, storageScope]);
5269
5275
  const create = useCallback7(async (init) => {
5270
5276
  if (!enabled) throw new Error("Pi sessions are disabled");
5271
5277
  const response = await fetchImpl(sessionsUrl(), {
@@ -5377,6 +5383,40 @@ function toSessionSummary(value) {
5377
5383
  function canonicalPageCount(data) {
5378
5384
  return Math.min(data.length, SESSION_PAGE_SIZE);
5379
5385
  }
5386
+ var remoteSessionOptionObjectIds = /* @__PURE__ */ new WeakMap();
5387
+ var remoteSessionOptionObjectSeq = 0;
5388
+ function remoteSessionOptionObjectIdentity(value) {
5389
+ if (typeof value !== "object" && typeof value !== "function" || value === null) return void 0;
5390
+ const object = value;
5391
+ let id = remoteSessionOptionObjectIds.get(object);
5392
+ if (!id) {
5393
+ id = ++remoteSessionOptionObjectSeq;
5394
+ remoteSessionOptionObjectIds.set(object, id);
5395
+ }
5396
+ return String(id);
5397
+ }
5398
+ function remoteSessionOptionsIdentity(options) {
5399
+ if (!options) return "{}";
5400
+ return JSON.stringify({
5401
+ autoStart: options.autoStart,
5402
+ requestTimeoutMs: options.requestTimeoutMs,
5403
+ onEvent: remoteSessionOptionObjectIdentity(options.onEvent),
5404
+ storeOptions: remoteSessionOptionObjectIdentity(options.storeOptions),
5405
+ setTimeoutFn: remoteSessionOptionObjectIdentity(options.setTimeoutFn),
5406
+ clearTimeoutFn: remoteSessionOptionObjectIdentity(options.clearTimeoutFn),
5407
+ reconnect: options.reconnect ? {
5408
+ baseMs: options.reconnect.baseMs,
5409
+ maxMs: options.reconnect.maxMs,
5410
+ jitterRatio: options.reconnect.jitterRatio,
5411
+ random: remoteSessionOptionObjectIdentity(options.reconnect.random)
5412
+ } : void 0,
5413
+ debug: options.debug ? {
5414
+ largeStateWarningBytes: options.debug.largeStateWarningBytes,
5415
+ largeStateWarningMessages: options.debug.largeStateWarningMessages,
5416
+ onWarning: remoteSessionOptionObjectIdentity(options.debug.onWarning)
5417
+ } : void 0
5418
+ });
5419
+ }
5380
5420
  function mergeSessions(...lists) {
5381
5421
  const seen = /* @__PURE__ */ new Set();
5382
5422
  const merged = [];
@@ -9178,7 +9218,7 @@ function getHeaderValue(headers, name) {
9178
9218
  }
9179
9219
 
9180
9220
  // src/front/chat/piChatPanelHooks.ts
9181
- import { useCallback as useCallback17, useEffect as useEffect20, useState as useState19, useSyncExternalStore } from "react";
9221
+ import { useCallback as useCallback17, useEffect as useEffect20, useMemo as useMemo12, useRef as useRef16, useState as useState19, useSyncExternalStore } from "react";
9182
9222
  function useExternalRemotePiSession({
9183
9223
  sessionId,
9184
9224
  workspaceId,
@@ -9190,13 +9230,19 @@ function useExternalRemotePiSession({
9190
9230
  remoteSessionOptions
9191
9231
  }) {
9192
9232
  const [session, setSession] = useState19();
9233
+ const remoteSessionOptionsRef = useRef16(remoteSessionOptions);
9234
+ remoteSessionOptionsRef.current = remoteSessionOptions;
9235
+ const remoteSessionOptionsKey = useMemo12(
9236
+ () => remoteSessionOptionsIdentity2(remoteSessionOptions),
9237
+ [remoteSessionOptions]
9238
+ );
9193
9239
  useEffect20(() => {
9194
9240
  if (!sessionId) {
9195
9241
  setSession(void 0);
9196
9242
  return;
9197
9243
  }
9198
9244
  const next = (createRemoteSession ?? createRemotePiSession)({
9199
- ...remoteSessionOptions,
9245
+ ...remoteSessionOptionsRef.current,
9200
9246
  sessionId,
9201
9247
  workspaceId,
9202
9248
  storageScope,
@@ -9206,9 +9252,43 @@ function useExternalRemotePiSession({
9206
9252
  });
9207
9253
  setSession(next);
9208
9254
  return () => next.dispose();
9209
- }, [apiBaseUrl, createRemoteSession, fetch2, remoteSessionOptions, requestHeaders, sessionId, storageScope, workspaceId]);
9255
+ }, [apiBaseUrl, createRemoteSession, fetch2, remoteSessionOptionsKey, requestHeaders, sessionId, storageScope, workspaceId]);
9210
9256
  return session;
9211
9257
  }
9258
+ var remoteSessionOptionObjectIds2 = /* @__PURE__ */ new WeakMap();
9259
+ var remoteSessionOptionObjectSeq2 = 0;
9260
+ function remoteSessionOptionObjectIdentity2(value) {
9261
+ if (typeof value !== "object" && typeof value !== "function" || value === null) return void 0;
9262
+ const object = value;
9263
+ let id = remoteSessionOptionObjectIds2.get(object);
9264
+ if (!id) {
9265
+ id = ++remoteSessionOptionObjectSeq2;
9266
+ remoteSessionOptionObjectIds2.set(object, id);
9267
+ }
9268
+ return String(id);
9269
+ }
9270
+ function remoteSessionOptionsIdentity2(options) {
9271
+ if (!options) return "{}";
9272
+ return JSON.stringify({
9273
+ autoStart: options.autoStart,
9274
+ requestTimeoutMs: options.requestTimeoutMs,
9275
+ onEvent: remoteSessionOptionObjectIdentity2(options.onEvent),
9276
+ storeOptions: remoteSessionOptionObjectIdentity2(options.storeOptions),
9277
+ setTimeoutFn: remoteSessionOptionObjectIdentity2(options.setTimeoutFn),
9278
+ clearTimeoutFn: remoteSessionOptionObjectIdentity2(options.clearTimeoutFn),
9279
+ reconnect: options.reconnect ? {
9280
+ baseMs: options.reconnect.baseMs,
9281
+ maxMs: options.reconnect.maxMs,
9282
+ jitterRatio: options.reconnect.jitterRatio,
9283
+ random: remoteSessionOptionObjectIdentity2(options.reconnect.random)
9284
+ } : void 0,
9285
+ debug: options.debug ? {
9286
+ largeStateWarningBytes: options.debug.largeStateWarningBytes,
9287
+ largeStateWarningMessages: options.debug.largeStateWarningMessages,
9288
+ onWarning: remoteSessionOptionObjectIdentity2(options.debug.onWarning)
9289
+ } : void 0
9290
+ });
9291
+ }
9212
9292
  function useRemotePiSessionState(session) {
9213
9293
  return useSyncExternalStore(
9214
9294
  useCallback17((listener) => session?.subscribe(listener) ?? (() => {
@@ -9392,14 +9472,14 @@ function PiChatPanel({
9392
9472
  }) {
9393
9473
  const externalSessionId = sessionId?.trim() || void 0;
9394
9474
  const showSessionSidebar = showSessions ?? externalSessionId === void 0;
9395
- const onDataRef = useRef16(onData);
9475
+ const onDataRef = useRef17(onData);
9396
9476
  onDataRef.current = onData;
9397
- const onTurnCompleteRef = useRef16(onTurnComplete);
9477
+ const onTurnCompleteRef = useRef17(onTurnComplete);
9398
9478
  onTurnCompleteRef.current = onTurnComplete;
9399
- const sessionListRefreshRef = useRef16(void 0);
9400
- const requestHeadersKey = useMemo12(() => headersContentKey(requestHeaders), [requestHeaders]);
9401
- const normalizedRequestHeaders = useMemo12(() => normalizedHeadersFromContentKey(requestHeadersKey), [requestHeadersKey]);
9402
- const remoteSessionOptionsWithEvents = useMemo12(() => ({
9479
+ const sessionListRefreshRef = useRef17(void 0);
9480
+ const requestHeadersKey = useMemo13(() => headersContentKey(requestHeaders), [requestHeaders]);
9481
+ const normalizedRequestHeaders = useMemo13(() => normalizedHeadersFromContentKey(requestHeadersKey), [requestHeadersKey]);
9482
+ const remoteSessionOptionsWithEvents = useMemo13(() => ({
9403
9483
  ...remoteSessionOptions,
9404
9484
  ...hydrateMessages ? {} : { autoStart: false },
9405
9485
  onEvent: (event) => {
@@ -9463,7 +9543,7 @@ function PiChatPanel({
9463
9543
  enabled: serverResourcesEnabled && availableModels === void 0
9464
9544
  });
9465
9545
  const selectedModel = model === void 0 ? modelDiscovery.model : model;
9466
- const modelOptions = useMemo12(
9546
+ const modelOptions = useMemo13(
9467
9547
  () => modelOptionsForSelection(availableModels ?? modelDiscovery.availableModels, selectedModel),
9468
9548
  [availableModels, modelDiscovery.availableModels, selectedModel]
9469
9549
  );
@@ -9495,13 +9575,13 @@ function PiChatPanel({
9495
9575
  const [modelPickerOpen, setModelPickerOpen] = useState20(false);
9496
9576
  const [thinkingPickerOpen, setThinkingPickerOpen] = useState20(false);
9497
9577
  const [draft, setDraft] = useState20(() => initialDraft ?? "");
9498
- const draftRef = useRef16(draft);
9578
+ const draftRef = useRef17(draft);
9499
9579
  draftRef.current = draft;
9500
- const initialDraftGuard = useRef16(new InitialDraftAutoSubmitGuard());
9501
- const pendingAutoSubmitSettleRef = useRef16(void 0);
9502
- const acceptedAutoSubmitSettleRef = useRef16(void 0);
9503
- const resetInProgressRef = useRef16(false);
9504
- const autoCreateInFlightRef = useRef16(false);
9580
+ const initialDraftGuard = useRef17(new InitialDraftAutoSubmitGuard());
9581
+ const pendingAutoSubmitSettleRef = useRef17(void 0);
9582
+ const acceptedAutoSubmitSettleRef = useRef17(void 0);
9583
+ const resetInProgressRef = useRef17(false);
9584
+ const autoCreateInFlightRef = useRef17(false);
9505
9585
  const settlePendingAutoSubmit = useCallback18((sessionId2) => {
9506
9586
  const pendingSessionId = pendingAutoSubmitSettleRef.current;
9507
9587
  if (!pendingSessionId || sessionId2 && pendingSessionId !== sessionId2) return false;
@@ -9510,19 +9590,19 @@ function PiChatPanel({
9510
9590
  onAutoSubmitInitialDraftSettled?.();
9511
9591
  return true;
9512
9592
  }, [onAutoSubmitInitialDraftSettled]);
9513
- const prevStatusRef = useRef16("idle");
9514
- const statusRef = useRef16("idle");
9515
- const scrollToBottomRef = useRef16(() => {
9593
+ const prevStatusRef = useRef17("idle");
9594
+ const statusRef = useRef17("idle");
9595
+ const scrollToBottomRef = useRef17(() => {
9516
9596
  });
9517
- const textareaRef = useRef16(null);
9597
+ const textareaRef = useRef17(null);
9518
9598
  const [localNotices, setLocalNotices] = useState20([]);
9519
9599
  const [dismissedNoticeIds, setDismissedNoticeIds] = useState20(() => /* @__PURE__ */ new Set());
9520
9600
  const [pluginUpdateState, setPluginUpdateState] = useState20(null);
9521
9601
  const [commandNotifyState, setCommandNotifyState] = useState20(null);
9522
- const commandRunIdRef = useRef16(0);
9602
+ const commandRunIdRef = useRef17(0);
9523
9603
  const [serverSkillsRefreshKey, setServerSkillsRefreshKey] = useState20(0);
9524
9604
  const [localSubmittedSessionId, setLocalSubmittedSessionId] = useState20();
9525
- const localSubmittedSessionRef = useRef16(void 0);
9605
+ const localSubmittedSessionRef = useRef17(void 0);
9526
9606
  const { attachmentNotice, setAttachmentNotice } = useAttachmentNotice();
9527
9607
  const markLocalSubmitted = useCallback18((sessionId2) => {
9528
9608
  localSubmittedSessionRef.current = sessionId2;
@@ -9533,7 +9613,7 @@ function PiChatPanel({
9533
9613
  localSubmittedSessionRef.current = void 0;
9534
9614
  setLocalSubmittedSessionId(void 0);
9535
9615
  }, []);
9536
- const registry = useMemo12(() => {
9616
+ const registry = useMemo13(() => {
9537
9617
  const excludedBuiltins = new Set(excludeBuiltinCommands);
9538
9618
  const effectiveBuiltins = builtinCommands.filter((command) => {
9539
9619
  if (!hotReloadEnabled && command.name === "reload") return false;
@@ -9554,12 +9634,12 @@ function PiChatPanel({
9554
9634
  refreshKey: serverSkillsRefreshKey,
9555
9635
  enabled: serverResourcesEnabled
9556
9636
  });
9557
- const allCommands = useMemo12(() => registry.list(), [registry, commandsStamp]);
9637
+ const allCommands = useMemo13(() => registry.list(), [registry, commandsStamp]);
9558
9638
  const activeChatSessionId = selectedChatState?.sessionId;
9559
9639
  const warmupNotice = composerNoticeForWarmup(workspaceWarmupStatus);
9560
9640
  const runtimeDependenciesNotice = composerNoticeForRuntimeDependencies(workspaceWarmupStatus);
9561
9641
  const workspaceWarmupBlocked = Boolean(warmupNotice);
9562
- const activeBlockers = useMemo12(
9642
+ const activeBlockers = useMemo13(
9563
9643
  // A missing active session id means a single/sessionless chat host. In that
9564
9644
  // mode, keep scoped blockers visible instead of hiding the only attention UI.
9565
9645
  // Multi-session hosts should pass a session id so unrelated blockers filter out.
@@ -9569,7 +9649,7 @@ function PiChatPanel({
9569
9649
  const canonicalMessages = selectedChatState ? selectMessagesForRender(selectedChatState) : [];
9570
9650
  const queuePreview = selectedChatState ? selectQueuePreview(selectedChatState) : [];
9571
9651
  const messages = canonicalMessages;
9572
- const userHistory = useMemo12(() => selectComposerHistoryFromCanonicalUsers(canonicalMessages), [canonicalMessages]);
9652
+ const userHistory = useMemo13(() => selectComposerHistoryFromCanonicalUsers(canonicalMessages), [canonicalMessages]);
9573
9653
  const emptyStateHydrating = statusForState(selectedChatState, sessionsLoading || chatStatePending || selectedSessionPending) === "hydrating";
9574
9654
  const emptyHero = emptyPlacement === "hero" && messages.length === 0 && queuePreview.length === 0 && !emptyStateHydrating;
9575
9655
  const debugState = selectedPiSession?.getDebugState();
@@ -9577,7 +9657,7 @@ function PiChatPanel({
9577
9657
  const primaryComposerBlocker = activeBlockers[0];
9578
9658
  const composerBlockerLabel = workspaceWarmupBlocked ? warmupNotice?.title ?? "Preparing workspace..." : primaryComposerBlocker?.label ?? primaryComposerBlocker?.reason ?? "Complete the pending workspace action to continue.";
9579
9659
  const composerStatusNotice = warmupNotice ?? runtimeDependenciesNotice;
9580
- const runtimeNotices = useMemo12(() => {
9660
+ const runtimeNotices = useMemo13(() => {
9581
9661
  const fromState = selectedChatState ? selectRuntimeNotices(selectedChatState) : [];
9582
9662
  const sessionNotice = sessionsError ? [{ id: "session-navigation-error", level: "error", text: sessionsError.message, dismissible: true }] : [];
9583
9663
  const largeStateNotice = debug && debugState?.largeStateWarning ? [{
@@ -9796,7 +9876,7 @@ function PiChatPanel({
9796
9876
  }
9797
9877
  insertSlashCommand(name);
9798
9878
  }, [dismissSlash, insertSlashCommand, openModelPicker, openThinkingPicker, setComposerDraft]);
9799
- const policy = useMemo12(() => {
9879
+ const policy = useMemo13(() => {
9800
9880
  if (!selectedPiSession || !activeChatSessionId) return void 0;
9801
9881
  const policySession = {
9802
9882
  getState: () => {
@@ -10005,8 +10085,8 @@ function PiChatPanel({
10005
10085
  const isStreaming = isPiBusyStatus(status);
10006
10086
  const submitStatus = toPromptSubmitStatus(status);
10007
10087
  const submitDisabled = !policy || sessionsLoading || composerBlocked && !isStreaming;
10008
- const mergedToolRenderers = useMemo12(() => mergeShadcnToolRenderers(toolRenderers), [toolRenderers]);
10009
- const debugMessages = useMemo12(() => messages.map(toDebugUiMessage), [messages]);
10088
+ const mergedToolRenderers = useMemo13(() => mergeShadcnToolRenderers(toolRenderers), [toolRenderers]);
10089
+ const debugMessages = useMemo13(() => messages.map(toDebugUiMessage), [messages]);
10010
10090
  const onTextareaChange = useCallback18((event) => {
10011
10091
  setModelPickerOpen(false);
10012
10092
  setThinkingPickerOpen(false);
@@ -1,5 +1,5 @@
1
- import { o as WorkspaceRuntimeContext, S as Sandbox, g as SandboxHandleStore, f as SandboxHandleRecord, W as Workspace, j as TelemetrySink, q as ToolReadinessRequirement, F as FileSearch, i as Stat, E as Entry, c as ExecResult, r as WorkspaceChangeEvent, b as ExecOptions, P as PluginRestartWarning, A as AgentTool, t as AgentHarnessFactory } from '../agentPluginEvents-BBqEQ_rc.js';
2
- export { u as AgentHarnessFactoryInput } from '../agentPluginEvents-BBqEQ_rc.js';
1
+ import { o as WorkspaceRuntimeContext, S as Sandbox, g as SandboxHandleStore, f as SandboxHandleRecord, W as Workspace, j as TelemetrySink, q as ToolReadinessRequirement, F as FileSearch, i as Stat, E as Entry, c as ExecResult, r as WorkspaceChangeEvent, b as ExecOptions, P as PluginRestartWarning, A as AgentTool, t as AgentHarnessFactory } from '../agentPluginEvents-Ddn5DQ5E.js';
2
+ export { u as AgentHarnessFactoryInput } from '../agentPluginEvents-Ddn5DQ5E.js';
3
3
  import { Sandbox as Sandbox$1 } from '@vercel/sandbox';
4
4
  import { FastifyInstance, FastifyRequest, FastifyPluginAsync } from 'fastify';
5
5
  import { PackageSource, ExtensionFactory, SettingsManager } from '@mariozechner/pi-coding-agent';
@@ -982,6 +982,8 @@ interface RegisterAgentRoutesOptions {
982
982
  request?: FastifyRequest;
983
983
  }) => PiHarnessOptions | undefined | Promise<PiHarnessOptions | undefined>;
984
984
  sessionNamespace?: string;
985
+ /** Optional explicit root for file-backed Pi chat transcript storage. */
986
+ sessionRoot?: string;
985
987
  /** Optional best-effort telemetry sink supplied by an embedding host. */
986
988
  telemetry?: TelemetrySink;
987
989
  /**
@@ -6175,24 +6175,26 @@ import {
6175
6175
  parseSessionEntries,
6176
6176
  CURRENT_SESSION_VERSION
6177
6177
  } from "@mariozechner/pi-coding-agent";
6178
- function sessionBaseDir() {
6178
+ function sessionBaseDir(explicitRoot) {
6179
+ const explicit = explicitRoot?.trim();
6180
+ if (explicit) return resolve7(explicit);
6179
6181
  const configured = getEnv(SESSION_ROOT_ENV)?.trim();
6180
6182
  return configured ? resolve7(configured) : join10(homedir3(), ".pi", "agent", "sessions");
6181
6183
  }
6182
- function defaultSessionDir(cwd) {
6184
+ function defaultSessionDir(cwd, explicitRoot) {
6183
6185
  const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
6184
- return join10(sessionBaseDir(), safePath);
6186
+ return join10(sessionBaseDir(explicitRoot), safePath);
6185
6187
  }
6186
6188
  var SAFE_ID = /^[a-zA-Z0-9_-]+$/;
6187
6189
  var SAFE_SESSION_NAMESPACE = /^[a-zA-Z0-9_-]+$/;
6188
6190
  var SESSION_ROOT_ENV = "BORING_AGENT_SESSION_ROOT";
6189
6191
  var SUMMARY_PREFIX_BYTES = 64 * 1024;
6190
- function sessionDirForNamespace(namespace) {
6192
+ function sessionDirForNamespace(namespace, explicitRoot) {
6191
6193
  const safeNamespace = namespace.trim();
6192
6194
  if (!SAFE_SESSION_NAMESPACE.test(safeNamespace)) {
6193
6195
  throw new Error("session namespace must contain only letters, numbers, underscores, and dashes");
6194
6196
  }
6195
- return join10(sessionBaseDir(), safeNamespace);
6197
+ return join10(sessionBaseDir(explicitRoot), safeNamespace);
6196
6198
  }
6197
6199
  function normalizeListOptions(options) {
6198
6200
  return {
@@ -6212,7 +6214,7 @@ var PiSessionStore = class {
6212
6214
  this.sessionDir = options;
6213
6215
  return;
6214
6216
  }
6215
- this.sessionDir = options?.sessionDir ?? (options?.sessionNamespace ? sessionDirForNamespace(options.sessionNamespace) : defaultSessionDir(options?.storageCwd ?? cwd));
6217
+ this.sessionDir = options?.sessionDir ?? (options?.sessionNamespace ? sessionDirForNamespace(options.sessionNamespace, options.sessionRoot) : defaultSessionDir(options?.storageCwd ?? cwd, options?.sessionRoot));
6216
6218
  }
6217
6219
  getSessionDir() {
6218
6220
  return this.sessionDir;
@@ -7211,6 +7213,7 @@ function createPiCodingAgentHarness(opts) {
7211
7213
  const pi = withPiHarnessDefaults(opts.pi);
7212
7214
  const sessionStore = new PiSessionStore(opts.runtimeCwd ?? opts.cwd, {
7213
7215
  sessionNamespace: opts.sessionNamespace,
7216
+ sessionRoot: opts.sessionRoot,
7214
7217
  sessionDir: opts.sessionDir,
7215
7218
  storageCwd: opts.cwd
7216
7219
  });
@@ -12834,6 +12837,7 @@ var registerAgentRoutes = async (app, opts) => {
12834
12837
  tools,
12835
12838
  cwd: root,
12836
12839
  sessionNamespace: scope.sessionNamespace,
12840
+ sessionRoot: opts.sessionRoot,
12837
12841
  systemPromptAppend: opts.systemPromptAppend,
12838
12842
  systemPromptDynamic: opts.getSystemPromptDynamic ? () => opts.getSystemPromptDynamic?.({ workspaceId, workspaceRoot: root }) : opts.systemPromptDynamic,
12839
12843
  telemetry: opts.telemetry
@@ -12967,6 +12971,7 @@ var registerAgentRoutes = async (app, opts) => {
12967
12971
  if (cached) return cached;
12968
12972
  const store = new PiSessionStore(scope.root, {
12969
12973
  sessionNamespace: scope.sessionNamespace,
12974
+ sessionRoot: opts.sessionRoot,
12970
12975
  storageCwd: scope.root
12971
12976
  });
12972
12977
  earlySessionStores.set(scope.key, store);
@@ -1,5 +1,5 @@
1
- import { W as Workspace, S as Sandbox, F as FileSearch, A as AgentTool } from '../agentPluginEvents-BBqEQ_rc.js';
2
- export { a as AgentHarness, C as CommandNotifyPayload, E as Entry, b as ExecOptions, c as ExecResult, I as IsolatedCodeInput, d as IsolatedCodeOutput, J as JSONSchema, R as RunContext, e as SandboxCapability, f as SandboxHandleRecord, g as SandboxHandleStore, h as SendMessageInput, i as Stat, T as TelemetryEvent, j as TelemetrySink, k as ToolExecContext, l as ToolResult, m as WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, n as WORKSPACE_COMMAND_NOTIFY_EVENT, o as WorkspaceRuntimeContext, p as noopTelemetry, s as safeCapture } from '../agentPluginEvents-BBqEQ_rc.js';
1
+ import { W as Workspace, S as Sandbox, F as FileSearch, A as AgentTool } from '../agentPluginEvents-Ddn5DQ5E.js';
2
+ export { a as AgentHarness, C as CommandNotifyPayload, E as Entry, b as ExecOptions, c as ExecResult, I as IsolatedCodeInput, d as IsolatedCodeOutput, J as JSONSchema, R as RunContext, e as SandboxCapability, f as SandboxHandleRecord, g as SandboxHandleStore, h as SendMessageInput, i as Stat, T as TelemetryEvent, j as TelemetrySink, k as ToolExecContext, l as ToolResult, m as WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, n as WORKSPACE_COMMAND_NOTIFY_EVENT, o as WorkspaceRuntimeContext, p as noopTelemetry, s as safeCapture } from '../agentPluginEvents-Ddn5DQ5E.js';
3
3
  import { B as BoringChatPart, T as ToolUiMetadata } from '../piChatEvent-B6GDifo2.js';
4
4
  export { A as ApiErrorPayload, a as ApiErrorPayloadSchema, b as ApiErrorResponse, c as ApiErrorResponseSchema, d as BoringChatMessage, C as ChatError, e as CommandReceipt, E as ERROR_CODES, f as ErrorCode, g as ErrorLogFields, h as ErrorLogFieldsSchema, F as FollowUpPayload, i as FollowUpReceipt, I as InterruptPayload, j as InterruptReceipt, P as PiChatEvent, k as PiChatHeartbeatFrame, l as PiChatSnapshot, m as PiChatStatus, n as PiChatStreamFrame, o as PromptPayload, p as PromptReceipt, Q as QueueClearPayload, q as QueueClearReceipt, r as QueuedUserMessage, S as StopPayload, s as StopReceipt, t as extractToolUiMetadata, u as isToolUiMetadata } from '../piChatEvent-B6GDifo2.js';
5
5
  export { C as ChatAttachmentPayload, a as ChatModelSelection, b as ChatSubmitPayload, S as SessionCtx, c as SessionDetail, d as SessionStore, e as SessionSummary, T as ThinkingLevel } from '../chatSubmitPayload-DHqQL2wD.js';
package/docs/runtime.md CHANGED
@@ -222,7 +222,9 @@ Those belong to the sandbox runtime root, `/workspace`.
222
222
 
223
223
  Production chat history also must not use the container root filesystem. Set
224
224
  `BORING_AGENT_SESSION_ROOT` to a mounted-volume path such as `/data/pi-sessions`
225
- so Pi wrapper/native transcripts survive Fly deploys and restarts.
225
+ so Pi wrapper/native transcripts survive Fly deploys and restarts. Core-hosted
226
+ apps that run `vercel-sandbox` with `BORING_AGENT_WORKSPACE_ROOT=/data/workspaces`
227
+ default this to the sibling `/data/pi-sessions` path when the env var is absent.
226
228
 
227
229
  ## Adding a custom runtime mode
228
230
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-agent",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Pane-embeddable coding agent. Ships direct/local/vercel-sandbox execution modes behind one interface.",
@@ -74,7 +74,7 @@
74
74
  "use-stick-to-bottom": "^1.1.3",
75
75
  "yaml": "^2.8.3",
76
76
  "zod": "^3.25.76",
77
- "@hachej/boring-ui-kit": "0.1.55"
77
+ "@hachej/boring-ui-kit": "0.1.57"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@antithesishq/bombadil": "0.5.0",