@hachej/boring-agent 0.1.101 → 0.1.104

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 (36) hide show
  1. package/dist/{DebugDrawer-2TO5SE2D.js → DebugDrawer-JNA43SVR.js} +2 -1
  2. package/dist/chunk-2BGLZZ7T.js +10 -0
  3. package/dist/{chunk-46HJK2ES.js → chunk-4XOW57KJ.js} +3 -8
  4. package/dist/{chunk-XCZBICZS.js → chunk-6DRHERVK.js} +8 -6
  5. package/dist/{chunk-XTMY3PWI.js → chunk-BTYOMR7W.js} +118 -16
  6. package/dist/{chunk-T37OVD6L.js → chunk-I7KFNGB4.js} +28 -2
  7. package/dist/{chunk-3OEDBRKY.js → chunk-JNEKOVMJ.js} +1 -1
  8. package/dist/{chunk-VXF5DWS6.js → chunk-K25PK5EC.js} +1 -0
  9. package/dist/chunk-N6THTH7P.js +110 -0
  10. package/dist/core/index.d.ts +5 -5
  11. package/dist/core/index.js +1 -1
  12. package/dist/{createHarness-7C2A5UVH.js → createHarness-POZ4AXCZ.js} +2 -2
  13. package/dist/{errors-Ci0dzmcP.d.ts → errors-DH7C01Pm.d.ts} +2 -2
  14. package/dist/{file-search-DmoDnMan.d.ts → file-search-qcD5zItr.d.ts} +5 -5
  15. package/dist/front/artifacts.d.ts +34 -0
  16. package/dist/front/artifacts.js +21 -0
  17. package/dist/front/index.d.ts +8 -14
  18. package/dist/front/index.js +775 -762
  19. package/dist/front/styles.css +4 -0
  20. package/dist/{harness-s-kEgJkK.d.ts → harness-Dcd08yKr.d.ts} +2 -2
  21. package/dist/{lease-D5-CBoPs.d.ts → lease-DffrPrQn.d.ts} +3 -3
  22. package/dist/{middleware-Cq_cYHjJ.d.ts → middleware-CaAEXpi5.d.ts} +11 -2
  23. package/dist/{piChatEvent-Bzof4IEy.d.ts → piChatEvent-iNSXiFQq.d.ts} +19 -14
  24. package/dist/{piChatSessionService-BU4L5hxM.d.ts → piChatSessionService-DQSQ_kWZ.d.ts} +1 -1
  25. package/dist/{sandbox-KQiEdz4W.d.ts → sandbox-BMhut3kh.d.ts} +6 -1
  26. package/dist/server/agent-host/testing/gatewayConformance.d.ts +6 -6
  27. package/dist/server/agent-host/testing/gatewayConformance.js +3 -3
  28. package/dist/server/index.d.ts +21 -16
  29. package/dist/server/index.js +7 -5
  30. package/dist/server/worker/index.d.ts +3 -2
  31. package/dist/server/worker/index.js +25 -6
  32. package/dist/shared/index.d.ts +113 -39
  33. package/dist/shared/index.js +3 -3
  34. package/dist/{types-OwI_m-2p.d.ts → types-B1xDlBSo.d.ts} +13 -5
  35. package/docs/ERROR_CODES.md +1 -0
  36. package/package.json +16 -12
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  DebugDrawer
3
- } from "./chunk-46HJK2ES.js";
3
+ } from "./chunk-4XOW57KJ.js";
4
+ import "./chunk-2BGLZZ7T.js";
4
5
  import "./chunk-YGRQ4Q5P.js";
5
6
  export {
6
7
  DebugDrawer
@@ -0,0 +1,10 @@
1
+ // src/front/lib/index.ts
2
+ import { clsx } from "clsx";
3
+ import { twMerge } from "tailwind-merge";
4
+ function cn(...inputs) {
5
+ return twMerge(clsx(inputs));
6
+ }
7
+
8
+ export {
9
+ cn
10
+ };
@@ -1,3 +1,6 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-2BGLZZ7T.js";
1
4
  import {
2
5
  safeRandomUUID
3
6
  } from "./chunk-YGRQ4Q5P.js";
@@ -53,13 +56,6 @@ async function copyTextToClipboard(text) {
53
56
  }
54
57
  }
55
58
 
56
- // src/front/lib/index.ts
57
- import { clsx } from "clsx";
58
- import { twMerge } from "tailwind-merge";
59
- function cn(...inputs) {
60
- return twMerge(clsx(inputs));
61
- }
62
-
63
59
  // src/front/DebugDrawer.tsx
64
60
  import { Button, IconButton, Tabs, TabsContent, TabsList, TabsTrigger } from "@hachej/boring-ui-kit";
65
61
  import {
@@ -339,7 +335,6 @@ function DebugDrawer({ agentTypeId, apiBaseUrl, fetch, sessionId, messages, requ
339
335
  }
340
336
 
341
337
  export {
342
- cn,
343
338
  copyTextToClipboard,
344
339
  agentResourceUrl,
345
340
  withStorageScope,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ErrorCode
3
- } from "./chunk-VXF5DWS6.js";
3
+ } from "./chunk-K25PK5EC.js";
4
4
 
5
5
  // src/shared/tool-ui.ts
6
6
  function isRecord(value) {
@@ -174,12 +174,17 @@ var QueuedUserMessageSchema = z.object({
174
174
  createdAt: z.string().optional()
175
175
  });
176
176
  var PiChatStatusSchema = z.enum(["idle", "hydrating", "submitted", "streaming", "aborting", "error"]);
177
+ var ChatModelSelectionSchema = z.object({
178
+ provider: nonEmptyString,
179
+ id: nonEmptyString
180
+ });
177
181
  var PiChatSnapshotSchema = z.object({
178
182
  protocolVersion: z.literal(1),
179
183
  sessionId: nonEmptyString,
180
184
  seq: seqNumber,
181
185
  status: PiChatStatusSchema,
182
186
  activeTurnId: z.string().optional(),
187
+ currentModel: ChatModelSelectionSchema.optional(),
183
188
  messages: z.array(BoringChatMessageSchema),
184
189
  queue: z.object({ followUps: z.array(QueuedUserMessageSchema) }),
185
190
  followUpMode: z.literal("one-at-a-time"),
@@ -188,6 +193,7 @@ var PiChatSnapshotSchema = z.object({
188
193
  var baseEvent = z.object({ seq: seqNumber });
189
194
  var PiChatEventSchema = z.discriminatedUnion("type", [
190
195
  baseEvent.extend({ type: z.literal("agent-start"), turnId: nonEmptyString }),
196
+ baseEvent.extend({ type: z.literal("model-changed"), currentModel: ChatModelSelectionSchema }),
191
197
  baseEvent.extend({ type: z.literal("agent-end"), turnId: nonEmptyString, status: z.enum(["ok", "aborted", "error"]), willRetry: z.boolean().optional() }),
192
198
  baseEvent.extend({
193
199
  type: z.literal("message-start"),
@@ -258,10 +264,6 @@ var PiChatEventSchema = z.discriminatedUnion("type", [
258
264
  ]);
259
265
  var PiChatHeartbeatFrameSchema = z.object({ type: z.literal("heartbeat"), now: z.string() });
260
266
  var PiChatStreamFrameSchema = z.union([PiChatEventSchema, PiChatHeartbeatFrameSchema]);
261
- var ChatModelSelectionSchema = z.object({
262
- provider: nonEmptyString,
263
- id: nonEmptyString
264
- });
265
267
  var ThinkingLevelSchema = z.enum(["off", "low", "medium", "high"]);
266
268
  var ChatAttachmentPayloadSchema = z.object({
267
269
  filename: z.string().optional(),
@@ -330,11 +332,11 @@ export {
330
332
  BoringChatMessageSchema,
331
333
  QueuedUserMessageSchema,
332
334
  PiChatStatusSchema,
335
+ ChatModelSelectionSchema,
333
336
  PiChatSnapshotSchema,
334
337
  PiChatEventSchema,
335
338
  PiChatHeartbeatFrameSchema,
336
339
  PiChatStreamFrameSchema,
337
- ChatModelSelectionSchema,
338
340
  ThinkingLevelSchema,
339
341
  ChatAttachmentPayloadSchema,
340
342
  PromptPayloadSchema,
@@ -7,7 +7,7 @@ import {
7
7
  readConfiguredDefaultModel,
8
8
  registerConfiguredModelProviders,
9
9
  withPiHarnessDefaults
10
- } from "./chunk-T37OVD6L.js";
10
+ } from "./chunk-I7KFNGB4.js";
11
11
  import {
12
12
  AGENT_KNOWLEDGE_FILESYSTEM_ID,
13
13
  AgentDefinitionValidationError,
@@ -29,7 +29,7 @@ import {
29
29
  validateAgentDefinition,
30
30
  validateAgentDeployment,
31
31
  validateTool
32
- } from "./chunk-3OEDBRKY.js";
32
+ } from "./chunk-JNEKOVMJ.js";
33
33
  import {
34
34
  safeCapture
35
35
  } from "./chunk-4IQ4HHBG.js";
@@ -41,12 +41,12 @@ import {
41
41
  AgentGatewayErrorCode,
42
42
  extractToolUiMetadata,
43
43
  sanitizeToolUiMetadata2 as sanitizeToolUiMetadata
44
- } from "./chunk-XCZBICZS.js";
44
+ } from "./chunk-6DRHERVK.js";
45
45
  import {
46
46
  AgentDefinitionErrorCode,
47
47
  AgentDeploymentErrorCode,
48
48
  ErrorCode
49
- } from "./chunk-VXF5DWS6.js";
49
+ } from "./chunk-K25PK5EC.js";
50
50
 
51
51
  // src/server/sandbox/snapshots/deploymentSnapshot.ts
52
52
  var VERCEL_UV_BIN_DIR = "/workspace/.boring-agent/sdk/uv/bin";
@@ -147,6 +147,7 @@ function createServerFileSearch(workspace, sandbox) {
147
147
  // src/server/sandbox/remote-worker/protocol.ts
148
148
  var REMOTE_WORKER_RUNTIME_CWD = "/workspace";
149
149
  var REMOTE_WORKER_PROVIDER = "remote-worker";
150
+ var REMOTE_WORKER_EXCLUSIVE_BINARY_CREATE_CAPABILITY = "exclusive-binary-create";
150
151
  var WORKER_INTERNAL_TOKEN_HEADER = "x-boring-internal-token";
151
152
  var WORKER_WORKSPACE_ID_HEADER = "x-boring-workspace-id";
152
153
  var WORKER_REQUEST_ID_HEADER = "x-boring-request-id";
@@ -314,6 +315,9 @@ var RemoteWorkerClient = class {
314
315
  headers: makeHeaders({ token: this.token, workspaceId: this.workspaceId, requestId: this.requestId })
315
316
  }, this.requestTimeoutMs);
316
317
  if (!response.ok) throw await parseError(response);
318
+ const body2 = await response.json().catch(() => ({}));
319
+ const capabilities2 = Array.isArray(body2.capabilities) ? body2.capabilities.filter((capability) => capability === "exclusive-binary-create") : void 0;
320
+ return { ok: true, ...capabilities2 ? { capabilities: capabilities2 } : {} };
317
321
  }
318
322
  async workspace(op) {
319
323
  const response = await this.fetchWithTimeout(`${this.baseUrl}/internal/workspaces/${encodeWorkspaceId(this.workspaceId)}/fs`, {
@@ -412,6 +416,7 @@ function constantTimeTokenEqual(a, b) {
412
416
  }
413
417
 
414
418
  // src/server/workspace/createRemoteWorkerWorkspace.ts
419
+ var EEXIST_CODE = "EEXIST";
415
420
  function expectContent(result) {
416
421
  if ("content" in result && typeof result.content === "string") return result.content;
417
422
  throw new Error("remote worker returned invalid file content response");
@@ -492,7 +497,7 @@ function createRemoteWatcher(client) {
492
497
  }
493
498
  };
494
499
  }
495
- function createRemoteWorkerWorkspace(client) {
500
+ function createRemoteWorkerWorkspace(client, supportsExclusiveBinaryCreate = false) {
496
501
  let watcher = null;
497
502
  return {
498
503
  root: REMOTE_WORKER_RUNTIME_CWD,
@@ -514,6 +519,18 @@ function createRemoteWorkerWorkspace(client) {
514
519
  async writeBinaryFile(path, data) {
515
520
  await client.workspace({ op: "writeBinaryFile", path, dataBase64: encodeBytesForWorker(data) });
516
521
  },
522
+ ...supportsExclusiveBinaryCreate ? {
523
+ async createBinaryFile(path, data) {
524
+ try {
525
+ await client.workspace({ op: "createBinaryFile", path, dataBase64: encodeBytesForWorker(data) });
526
+ } catch (error) {
527
+ if (error?.code === ErrorCode.enum.REMOTE_WORKER_ALREADY_EXISTS) {
528
+ throw Object.assign(new Error("EEXIST: file already exists"), { code: EEXIST_CODE });
529
+ }
530
+ throw error;
531
+ }
532
+ }
533
+ } : {},
517
534
  async readFileWithStat(path) {
518
535
  const result = await client.workspace({ op: "readFileWithStat", path });
519
536
  if ("content" in result && "stat" in result) return { content: result.content, stat: result.stat };
@@ -562,9 +579,14 @@ function createRemoteWorkerModeAdapter(opts = {}) {
562
579
  requestId: ctx.requestId,
563
580
  fetchImpl: opts.fetchImpl
564
581
  });
565
- const workspace = createRemoteWorkerWorkspace(client);
582
+ const health = await client.health();
583
+ const workspace = createRemoteWorkerWorkspace(
584
+ client,
585
+ health.capabilities?.includes(
586
+ REMOTE_WORKER_EXCLUSIVE_BINARY_CREATE_CAPABILITY
587
+ ) ?? false
588
+ );
566
589
  const sandbox = createRemoteWorkerSandbox(client);
567
- await sandbox.init?.({ workspace, sessionId: ctx.sessionId });
568
590
  return {
569
591
  runtimeContext: { runtimeCwd: REMOTE_WORKER_RUNTIME_CWD },
570
592
  bash: { kind: "remote" },
@@ -2190,6 +2212,28 @@ var agentSandboxRuntimeHostOperations = {
2190
2212
  withWorkspacePythonEnv
2191
2213
  };
2192
2214
  var sandboxRuntimeHostOperations = agentSandboxRuntimeHostOperations;
2215
+ function resolveBwrapPolicy(options) {
2216
+ const sandbox = options?.sandbox;
2217
+ const namespaceProfile = sandbox?.namespaceProfile ?? "full";
2218
+ return {
2219
+ namespaceProfile,
2220
+ network: sandbox?.network ?? "shared",
2221
+ // Docker mode runs outside a nested user namespace. Never allow the outer
2222
+ // container's SYS_ADMIN capability to reach any local execution path.
2223
+ dropAllCapabilities: namespaceProfile === "docker" || sandbox?.dropAllCapabilities === true
2224
+ };
2225
+ }
2226
+ function withBwrapPolicy(runtimeHost, policy) {
2227
+ return {
2228
+ ...runtimeHost,
2229
+ buildBwrapArgs(workspaceRoot, executionOptions) {
2230
+ return runtimeHost.buildBwrapArgs(workspaceRoot, {
2231
+ ...executionOptions,
2232
+ ...policy
2233
+ });
2234
+ }
2235
+ };
2236
+ }
2193
2237
  function resolveBuiltinRuntimeLayoutRoot(mode, workspaceRoot) {
2194
2238
  return mode === "blaxel" ? BLAXEL_WORKSPACE_ROOT : mode === "vercel-sandbox" ? VERCEL_SANDBOX_WORKSPACE_ROOT : workspaceRoot;
2195
2239
  }
@@ -2200,11 +2244,20 @@ function createSandboxRuntimeModeAdapter(mode, options = {}) {
2200
2244
  provider: createDirectSandboxProvider(),
2201
2245
  runtimeHost: agentSandboxRuntimeHostOperations
2202
2246
  });
2203
- case "local":
2247
+ case "local": {
2248
+ const policy = resolveBwrapPolicy(options.bwrap);
2249
+ const runtimeHost = withBwrapPolicy(agentSandboxRuntimeHostOperations, policy);
2204
2250
  return createLocalModeAdapter({
2205
- provider: createBwrapSandboxProvider(),
2206
- runtimeHost: agentSandboxRuntimeHostOperations
2251
+ provider: createBwrapSandboxProvider({
2252
+ ...options.bwrap,
2253
+ sandbox: {
2254
+ ...options.bwrap?.sandbox,
2255
+ ...policy
2256
+ }
2257
+ }),
2258
+ runtimeHost
2207
2259
  });
2260
+ }
2208
2261
  case "vercel-sandbox":
2209
2262
  return createVercelSandboxModeAdapter({
2210
2263
  provider: createVercelSandboxProvider({
@@ -4713,6 +4766,7 @@ function toolInputFromCall(part) {
4713
4766
  }
4714
4767
  function assistantParts(message, messageId) {
4715
4768
  const content = message.content;
4769
+ const assistantAborted = message.stopReason === "aborted";
4716
4770
  if (typeof content === "string") return [{ type: "text", id: `${messageId}:text:0`, text: content }];
4717
4771
  if (!Array.isArray(content)) return [];
4718
4772
  return content.flatMap((part, index) => {
@@ -4732,7 +4786,7 @@ function assistantParts(message, messageId) {
4732
4786
  }
4733
4787
  if (part.type === "toolCall") {
4734
4788
  const toolCallId = optionalString(part.id) ?? `${messageId}:tool:${index}`;
4735
- const state = part.state === "output-error" ? "output-error" : part.state === "output-available" ? "output-available" : "input-available";
4789
+ const state = part.state === "output-error" ? "output-error" : part.state === "output-available" ? "output-available" : part.state === "aborted" || assistantAborted ? "aborted" : "input-available";
4736
4790
  return [
4737
4791
  {
4738
4792
  type: "tool-call",
@@ -4866,6 +4920,7 @@ function buildPiChatSnapshot(adapter, options) {
4866
4920
  seq: options.seq,
4867
4921
  status,
4868
4922
  activeTurnId: options.activeTurnId,
4923
+ currentModel: adapter.currentModel?.(),
4869
4924
  messages: buildPiChatHistory(piSnapshot.messages, {
4870
4925
  sessionId,
4871
4926
  messageTurnIds: options.messageTurnIds,
@@ -6334,6 +6389,9 @@ function codedError(message, code, statusCode, extra) {
6334
6389
  // src/server/pi-chat/harnessPiChatService.ts
6335
6390
  var MAX_PROMPT_IMAGE_BYTES = 10 * 1024 * 1024;
6336
6391
  var PROMPT_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".avif", ".gif", ".jpg", ".jpeg", ".png", ".webp"]);
6392
+ function sameModelSelection(left, right) {
6393
+ return left?.provider === right.provider && left.id === right.id;
6394
+ }
6337
6395
  var HarnessPiChatService = class {
6338
6396
  harness;
6339
6397
  sessionStore;
@@ -6589,12 +6647,13 @@ var HarnessPiChatService = class {
6589
6647
  async readPersistedState(ctx, sessionId) {
6590
6648
  if (!this.sessionStore.loadEntries) return null;
6591
6649
  try {
6592
- const { id, messages } = await this.sessionStore.loadEntries(toSessionCtx(ctx), sessionId);
6650
+ const { id, messages, currentModel } = await this.sessionStore.loadEntries(toSessionCtx(ctx), sessionId);
6593
6651
  return {
6594
6652
  protocolVersion: 1,
6595
6653
  sessionId: id,
6596
6654
  seq: await this.readDurableLatestPiChatSeq(sessionStreamPath(this.sessionKey(ctx, id))),
6597
6655
  status: "idle",
6656
+ currentModel,
6598
6657
  messages: buildPiChatHistory(messages, {
6599
6658
  sessionId: id,
6600
6659
  attachmentUrl: this.attachmentUrlFor(id)
@@ -6643,6 +6702,13 @@ var HarnessPiChatService = class {
6643
6702
  };
6644
6703
  }
6645
6704
  if (outcome === "cancelled") throw promptCancelledError();
6705
+ const currentModel = adapter.currentModel?.();
6706
+ if (currentModel && !sameModelSelection(channel.advertisedModel, currentModel)) {
6707
+ channel.advertisedModel = currentModel;
6708
+ this.publishChannelEvents(sessionId, channel, [
6709
+ channel.mapper.mapSynthetic({ type: "model-changed", currentModel })
6710
+ ]);
6711
+ }
6646
6712
  this.messageMetadata.recordPrompt(sessionKey, payload);
6647
6713
  const receiptCursor = nextPromptReceiptCursor(channel);
6648
6714
  try {
@@ -7089,7 +7155,8 @@ var HarnessPiChatService = class {
7089
7155
  closed: closed.promise,
7090
7156
  resolveClosed: () => closed.resolve(),
7091
7157
  rejectClosed: closed.reject,
7092
- messageTurnIds: /* @__PURE__ */ new Map()
7158
+ messageTurnIds: /* @__PURE__ */ new Map(),
7159
+ advertisedModel: adapter.currentModel?.()
7093
7160
  };
7094
7161
  const unsubscribe = adapter.subscribe((event) => {
7095
7162
  const mappedEvents = mapper.map(event);
@@ -7587,6 +7654,7 @@ function assertUniqueRuntimeFilesystemBindings(bindings) {
7587
7654
  var MUTATION_CAPABILITY = {
7588
7655
  write: "write",
7589
7656
  writeBinary: "write",
7657
+ createBinary: "write",
7590
7658
  delete: "delete",
7591
7659
  mkdir: "create-child"
7592
7660
  };
@@ -7607,6 +7675,7 @@ function intersectRuntimeFilesystemBinding(host, request) {
7607
7675
  ...request.operations,
7608
7676
  write: guarded(request.operations.write?.bind(request.operations), MUTATION_CAPABILITY.write),
7609
7677
  writeBinary: guarded(request.operations.writeBinary?.bind(request.operations), MUTATION_CAPABILITY.writeBinary),
7678
+ createBinary: guarded(request.operations.createBinary?.bind(request.operations), MUTATION_CAPABILITY.createBinary),
7610
7679
  delete: guarded(request.operations.delete?.bind(request.operations), MUTATION_CAPABILITY.delete),
7611
7680
  mkdir: guarded(request.operations.mkdir?.bind(request.operations), MUTATION_CAPABILITY.mkdir),
7612
7681
  move: request.operations.move ? async (args) => {
@@ -7916,7 +7985,7 @@ async function buildAgentComposition(input) {
7916
7985
  sessionNamespace: configuredNamespace,
7917
7986
  sessionDir: runtimeScope.sessionDir ?? factoryInput.sessionDir
7918
7987
  }) : async (factoryInput) => {
7919
- const { createPiCodingAgentHarness } = await import("./createHarness-7C2A5UVH.js");
7988
+ const { createPiCodingAgentHarness } = await import("./createHarness-POZ4AXCZ.js");
7920
7989
  return createPiCodingAgentHarness({
7921
7990
  ...factoryInput,
7922
7991
  pi,
@@ -12069,7 +12138,7 @@ import { lstat as lstat4, open as open2, opendir, realpath as realpath5, stat as
12069
12138
  import { homedir as homedir2 } from "node:os";
12070
12139
  import { dirname as dirname8, isAbsolute as isAbsolute7, join as join9, parse, relative as relative9, resolve as resolve8, sep as sep8 } from "node:path";
12071
12140
  import { fileURLToPath as fileURLToPath7 } from "node:url";
12072
- import { DefaultPackageManager as DefaultPackageManager2, getAgentDir as getAgentDir2 } from "@mariozechner/pi-coding-agent";
12141
+ import { DefaultPackageManager as DefaultPackageManager2, getAgentDir as getAgentDir2, loadProjectContextFiles } from "@mariozechner/pi-coding-agent";
12073
12142
  var DEFAULT_PI_RESOURCE_DIGEST_LIMITS = Object.freeze({
12074
12143
  maxDepth: 32,
12075
12144
  maxFiles: 1e4,
@@ -12081,11 +12150,13 @@ function createPiResourceDigestInput(input) {
12081
12150
  const piAgentDir = resolvePiPath(input.piAgentDir ?? getAgentDir2(), process.cwd());
12082
12151
  const piUserHome = resolvePiPath(input.piUserHome ?? homedir2(), process.cwd());
12083
12152
  const noSkills = input.noSkills ?? true;
12153
+ const noContextFiles = input.noContextFiles ?? true;
12084
12154
  return {
12085
12155
  piCwd,
12086
12156
  piAgentDir,
12087
12157
  piUserHome,
12088
12158
  noSkills,
12159
+ noContextFiles,
12089
12160
  promptParts: input.resourceSets.flatMap((set) => set.promptParts ?? []),
12090
12161
  additionalSkillPaths: uniqueStrings(input.resourceSets.flatMap((set) => set.additionalSkillPaths ?? [])),
12091
12162
  packages: compactPiPackages(input.resourceSets.flatMap((set) => set.packages ?? [])),
@@ -12099,7 +12170,7 @@ function createPiResourceDigestInput(input) {
12099
12170
  ...input.limits ? { limits: input.limits } : {}
12100
12171
  };
12101
12172
  }
12102
- var FORMAT_VERSION = "boring-pi-resource-digest-v4";
12173
+ var FORMAT_VERSION = "boring-pi-resource-digest-v5";
12103
12174
  var EXCLUDED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
12104
12175
  var EXCLUDED_FILES = /* @__PURE__ */ new Set([".boring-signature.json"]);
12105
12176
  async function digestPiResourceInputs(input) {
@@ -12108,6 +12179,7 @@ async function digestPiResourceInputs(input) {
12108
12179
  const piAgentDir = resolvePiPath(input.piAgentDir, process.cwd());
12109
12180
  const piUserHome = resolvePiPath(input.piUserHome, process.cwd());
12110
12181
  const projectSettingsDir = join9(piCwd, ".pi");
12182
+ const noContextFiles = input.noContextFiles ?? true;
12111
12183
  const authorizedRoots = [...new Set(input.authorizedRoots.map((path) => resolvePiPath(path, piCwd)))];
12112
12184
  if (authorizedRoots.length === 0) {
12113
12185
  throw stableError(ErrorCode.enum.CONFIG_INVALID, 400, "Pi resource digest requires at least one independently authorized root");
@@ -12119,8 +12191,28 @@ async function digestPiResourceInputs(input) {
12119
12191
  frameString(hash, "project-settings-dir", projectSettingsDir);
12120
12192
  frameString(hash, "user-agent-dir", piAgentDir);
12121
12193
  frameString(hash, "user-home", piUserHome);
12194
+ frameString(hash, "context-policy", noContextFiles ? "sealed" : "ambient");
12122
12195
  const promptText = (input.promptParts ?? []).map((part) => part?.trim()).filter((part) => Boolean(part)).join("\n\n");
12123
12196
  frameString(hash, "prompt", promptText);
12197
+ if (!noContextFiles) {
12198
+ const contextFiles = loadProjectContextFiles({ cwd: piCwd, agentDir: piAgentDir });
12199
+ for (const contextFile of contextFiles) {
12200
+ const bytes = Buffer.byteLength(contextFile.content);
12201
+ state.nodes += 1;
12202
+ if (state.nodes > state.limits.maxFiles) {
12203
+ throw limitError(`Pi resource tree exceeds maximum node count ${state.limits.maxFiles}`);
12204
+ }
12205
+ if (bytes > state.limits.maxFileBytes) {
12206
+ throw limitError(`Pi context file exceeds maximum bytes ${state.limits.maxFileBytes}: ${contextFile.path}`);
12207
+ }
12208
+ if (state.bytes + bytes > state.limits.maxTotalBytes) {
12209
+ throw limitError(`Pi resource tree exceeds maximum total bytes ${state.limits.maxTotalBytes}`);
12210
+ }
12211
+ frameString(hash, "context-path", contextFile.path);
12212
+ frameString(hash, "context-content", contextFile.content);
12213
+ state.bytes += bytes;
12214
+ }
12215
+ }
12124
12216
  await hashResourceCollection(state, piCwd, "settings", [
12125
12217
  join9(projectSettingsDir, "settings.json"),
12126
12218
  join9(piAgentDir, "settings.json")
@@ -12564,6 +12656,7 @@ async function createStandaloneAgentHostApp(options = {}) {
12564
12656
  return createPiResourceDigestInput({
12565
12657
  piCwd: workspaceRoot,
12566
12658
  noSkills: pi.noSkills,
12659
+ noContextFiles: pi.noContextFiles,
12567
12660
  resourceSets: [{
12568
12661
  promptParts: [
12569
12662
  options.systemPromptAppend,
@@ -13054,6 +13147,14 @@ function createUserFilesystemBinding(workspace, policy, resolvePolicyPath) {
13054
13147
  const stat7 = await workspace.stat(target);
13055
13148
  return { mtimeMs: stat7.kind === "file" ? stat7.mtimeMs : void 0 };
13056
13149
  },
13150
+ ...workspace.createBinaryFile ? {
13151
+ async createBinary({ path, content }) {
13152
+ await requireCapability(path, "write");
13153
+ const target = workspacePath(workspace, path);
13154
+ await workspace.createBinaryFile(target, content);
13155
+ return {};
13156
+ }
13157
+ } : {},
13057
13158
  async delete({ path }) {
13058
13159
  await requireCapability(path, "delete");
13059
13160
  await workspace.unlink(workspacePath(workspace, path));
@@ -13439,6 +13540,7 @@ export {
13439
13540
  resolveWorkspaceRoot,
13440
13541
  REMOTE_WORKER_RUNTIME_CWD,
13441
13542
  REMOTE_WORKER_PROVIDER,
13543
+ REMOTE_WORKER_EXCLUSIVE_BINARY_CREATE_CAPABILITY,
13442
13544
  WORKER_INTERNAL_TOKEN_HEADER,
13443
13545
  WORKER_WORKSPACE_ID_HEADER,
13444
13546
  WORKER_REQUEST_ID_HEADER,
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-4IQ4HHBG.js";
6
6
  import {
7
7
  ErrorCode
8
- } from "./chunk-VXF5DWS6.js";
8
+ } from "./chunk-K25PK5EC.js";
9
9
 
10
10
  // src/server/harness/pi-coding-agent/createHarness.ts
11
11
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -567,6 +567,28 @@ async function summarizeNativeTranscript(filepath) {
567
567
  }
568
568
 
569
569
  // src/server/harness/pi-coding-agent/sessions.ts
570
+ function legacyAssistantModel(entry) {
571
+ const message = entry.message;
572
+ if (message.role !== "assistant") return void 0;
573
+ if (typeof message.provider === "string" && typeof message.model === "string") {
574
+ return { provider: message.provider, id: message.model };
575
+ }
576
+ if (typeof message.model !== "object" || message.model === null) return void 0;
577
+ const model = message.model;
578
+ return typeof model.provider === "string" && typeof model.id === "string" ? { provider: model.provider, id: model.id } : void 0;
579
+ }
580
+ function currentModelFromTranscript(entries) {
581
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
582
+ const entry = entries[index];
583
+ if (!entry) continue;
584
+ if (entry.type === "model_change") return { provider: entry.provider, id: entry.modelId };
585
+ if (entry.type === "message") {
586
+ const model = legacyAssistantModel(entry);
587
+ if (model) return model;
588
+ }
589
+ }
590
+ return void 0;
591
+ }
570
592
  function sessionBaseDir(explicitRoot) {
571
593
  const explicit = explicitRoot?.trim();
572
594
  if (explicit) return resolve(explicit);
@@ -745,7 +767,11 @@ var PiSessionStore = class {
745
767
  async loadEntries(ctx, sessionId) {
746
768
  const resolved = await this.resolveSessionTranscript(ctx, sessionId);
747
769
  const messages = resolved.transcriptEntries.filter((entry) => entry.type === "message").map((entry) => withStableMessageId(entry.message, entry.id));
748
- return { id: resolved.resolvedSessionId, messages };
770
+ return {
771
+ id: resolved.resolvedSessionId,
772
+ messages,
773
+ currentModel: currentModelFromTranscript(resolved.transcriptEntries)
774
+ };
749
775
  }
750
776
  async loadAttachment(ctx, sessionId, messageId, index) {
751
777
  const resolved = await this.resolveSessionTranscript(ctx, sessionId);
@@ -6,7 +6,7 @@ import {
6
6
  AgentDefinitionErrorCode,
7
7
  AgentDeploymentErrorCode,
8
8
  ErrorCode
9
- } from "./chunk-VXF5DWS6.js";
9
+ } from "./chunk-K25PK5EC.js";
10
10
 
11
11
  // src/shared/skill-resource.ts
12
12
  var AGENT_RESOURCES_FILESYSTEM_ID = "agent_resources";
@@ -70,6 +70,7 @@ var ErrorCode = z.enum([
70
70
  "REMOTE_WORKER_INCOMPLETE_CLEANUP",
71
71
  "REMOTE_WORKER_DOCKER_COMMAND_FAILED",
72
72
  "REMOTE_WORKER_PATH_UNSAFE",
73
+ "REMOTE_WORKER_ALREADY_EXISTS",
73
74
  "REMOTE_WORKER_PATH_PRIMITIVE_UNAVAILABLE",
74
75
  "REMOTE_WORKER_QUOTA_EXCEEDED",
75
76
  "REMOTE_WORKER_SECRET_REFERENCE_REJECTED",
@@ -0,0 +1,110 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-2BGLZZ7T.js";
4
+
5
+ // src/front/ArtifactOpenContext.tsx
6
+ import { createContext, useContext } from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var ArtifactOpenContext = createContext(null);
9
+ function ArtifactOpenProvider({ onOpenArtifact, children }) {
10
+ const inheritedOpenArtifact = useContext(ArtifactOpenContext);
11
+ return /* @__PURE__ */ jsx(ArtifactOpenContext.Provider, { value: onOpenArtifact ?? inheritedOpenArtifact, children });
12
+ }
13
+ function useOpenArtifact() {
14
+ return useContext(ArtifactOpenContext);
15
+ }
16
+
17
+ // src/front/primitives/artifact.tsx
18
+ import { Button } from "@hachej/boring-ui-kit";
19
+ import {
20
+ Tooltip,
21
+ TooltipContent,
22
+ TooltipProvider,
23
+ TooltipTrigger
24
+ } from "@hachej/boring-ui-kit";
25
+ import { XIcon } from "lucide-react";
26
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
27
+ var Artifact = ({ className, ...props }) => /* @__PURE__ */ jsx2(
28
+ "div",
29
+ {
30
+ className: cn(
31
+ "flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm",
32
+ className
33
+ ),
34
+ ...props
35
+ }
36
+ );
37
+ var ArtifactHeader = ({
38
+ className,
39
+ ...props
40
+ }) => /* @__PURE__ */ jsx2(
41
+ "div",
42
+ {
43
+ className: cn(
44
+ "flex items-center justify-between border-b bg-muted/50 px-4 py-3",
45
+ className
46
+ ),
47
+ ...props
48
+ }
49
+ );
50
+ var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ jsx2(
51
+ "p",
52
+ {
53
+ className: cn("font-medium text-foreground text-sm", className),
54
+ ...props
55
+ }
56
+ );
57
+ var ArtifactDescription = ({
58
+ className,
59
+ ...props
60
+ }) => /* @__PURE__ */ jsx2("p", { className: cn("text-muted-foreground text-sm", className), ...props });
61
+ var ArtifactActions = ({
62
+ className,
63
+ ...props
64
+ }) => /* @__PURE__ */ jsx2("div", { className: cn("flex items-center gap-1", className), ...props });
65
+ var ArtifactAction = ({
66
+ tooltip,
67
+ label,
68
+ icon: Icon,
69
+ children,
70
+ className,
71
+ size = "sm",
72
+ variant = "ghost",
73
+ ...props
74
+ }) => {
75
+ const button = /* @__PURE__ */ jsxs(
76
+ Button,
77
+ {
78
+ className: cn(
79
+ "size-8 p-0 text-muted-foreground hover:text-foreground",
80
+ className
81
+ ),
82
+ size,
83
+ type: "button",
84
+ variant,
85
+ ...props,
86
+ children: [
87
+ Icon ? /* @__PURE__ */ jsx2(Icon, { className: "size-4" }) : children,
88
+ /* @__PURE__ */ jsx2("span", { className: "sr-only", children: label || tooltip })
89
+ ]
90
+ }
91
+ );
92
+ if (tooltip) {
93
+ return /* @__PURE__ */ jsx2(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
94
+ /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: button }),
95
+ /* @__PURE__ */ jsx2(TooltipContent, { children: /* @__PURE__ */ jsx2("p", { children: tooltip }) })
96
+ ] }) });
97
+ }
98
+ return button;
99
+ };
100
+
101
+ export {
102
+ ArtifactOpenProvider,
103
+ useOpenArtifact,
104
+ Artifact,
105
+ ArtifactHeader,
106
+ ArtifactTitle,
107
+ ArtifactDescription,
108
+ ArtifactActions,
109
+ ArtifactAction
110
+ };
@@ -1,8 +1,8 @@
1
- import { A as AgentHarness, a as AgentReadiness, b as Agent } from '../harness-s-kEgJkK.js';
2
- export { c as AGENT_NOT_IMPLEMENTED_UNTIL_T1, d as AgentActor, e as AgentCoreHarness, f as AgentCoreHarnessFactory, g as AgentCorePromptInput, h as AgentCoreSessionAdapter, i as AgentCoreSessionSnapshot, j as AgentEvent, k as AgentMessageContent, l as AgentMessagePart, m as AgentNotImplementedError, n as AgentReadinessStatus, o as AgentResolveInputResponse, p as AgentSendInput, q as AgentStartReceipt, r as AgentStreamOptions } from '../harness-s-kEgJkK.js';
3
- import { S as SessionStore } from '../piChatEvent-Bzof4IEy.js';
4
- import { A as AgentCoreSessionService, a as AgentEffectAdmission } from '../piChatSessionService-BU4L5hxM.js';
5
- export { b as AGENT_EFFECT_METHODS, c as AgentEffectAdmissionError, P as PiChatEventStreamResult, d as PiChatEventStreamSubscription, e as PiChatEventSubscriber, f as PiChatReplayRangeError, g as PiChatSessionService, h as PiSessionCreateInit, i as PiSessionRequestContext, w as withAgentEffectAdmission } from '../piChatSessionService-BU4L5hxM.js';
1
+ import { A as AgentHarness, a as AgentReadiness, b as Agent } from '../harness-Dcd08yKr.js';
2
+ export { c as AGENT_NOT_IMPLEMENTED_UNTIL_T1, d as AgentActor, e as AgentCoreHarness, f as AgentCoreHarnessFactory, g as AgentCorePromptInput, h as AgentCoreSessionAdapter, i as AgentCoreSessionSnapshot, j as AgentEvent, k as AgentMessageContent, l as AgentMessagePart, m as AgentNotImplementedError, n as AgentReadinessStatus, o as AgentResolveInputResponse, p as AgentSendInput, q as AgentStartReceipt, r as AgentStreamOptions } from '../harness-Dcd08yKr.js';
3
+ import { S as SessionStore } from '../piChatEvent-iNSXiFQq.js';
4
+ import { A as AgentCoreSessionService, a as AgentEffectAdmission } from '../piChatSessionService-DQSQ_kWZ.js';
5
+ export { b as AGENT_EFFECT_METHODS, c as AgentEffectAdmissionError, P as PiChatEventStreamResult, d as PiChatEventStreamSubscription, e as PiChatEventSubscriber, f as PiChatReplayRangeError, g as PiChatSessionService, h as PiSessionCreateInit, i as PiSessionRequestContext, w as withAgentEffectAdmission } from '../piChatSessionService-DQSQ_kWZ.js';
6
6
  import '@mariozechner/pi-coding-agent';
7
7
  import 'zod';
8
8
 
@@ -4,7 +4,7 @@ import {
4
4
  } from "../chunk-WSQ5QNIY.js";
5
5
  import {
6
6
  ErrorCode
7
- } from "../chunk-VXF5DWS6.js";
7
+ } from "../chunk-K25PK5EC.js";
8
8
 
9
9
  // src/core/piChatSessionService.ts
10
10
  var AgentEffectAdmissionError = class extends Error {
@@ -5,9 +5,9 @@ import {
5
5
  mergePiPackageSources,
6
6
  projectSkillResourceLocations,
7
7
  withPiHarnessDefaults
8
- } from "./chunk-T37OVD6L.js";
8
+ } from "./chunk-I7KFNGB4.js";
9
9
  import "./chunk-4IQ4HHBG.js";
10
- import "./chunk-VXF5DWS6.js";
10
+ import "./chunk-K25PK5EC.js";
11
11
  export {
12
12
  createPiCodingAgentHarness,
13
13
  createResourceSettingsManager,