@hachej/boring-agent 0.1.90 → 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 (37) hide show
  1. package/dist/{chunk-4PKGVPJA.js → chunk-2GBHYJVC.js} +27 -5
  2. package/dist/{chunk-BEFJNMKQ.js → chunk-CJ2BW2W2.js} +23 -8
  3. package/dist/{chunk-F7ZS27HE.js → chunk-IWBC6SF7.js} +93 -19
  4. package/dist/chunk-NITBKFG6.js +1246 -0
  5. package/dist/{chunk-JEDRQAR5.js → chunk-OFQ7J6SI.js} +8 -2
  6. package/dist/{chunk-5CYVBVP3.js → chunk-V3ZD3T3G.js} +4785 -2153
  7. package/dist/core/index.d.ts +5 -5
  8. package/dist/core/index.js +2 -2
  9. package/dist/{createHarness-UCCGMVQJ.js → createHarness-PMYRKDE4.js} +2 -2
  10. package/dist/errors-C38f6pol.d.ts +200 -0
  11. package/dist/front/index.d.ts +20 -4
  12. package/dist/front/index.js +172 -44
  13. package/dist/{harness-Rbkdpvse.d.ts → harness-Cc48o6uS.d.ts} +2 -2
  14. package/dist/{workspaceAgentDispatcher-50Uzuxhs.d.ts → lease-BqeCLGPL.d.ts} +266 -57
  15. package/dist/{protocol-CDA4bcP9.d.ts → middleware-CzW8n7B7.d.ts} +20 -2
  16. package/dist/piChatEvent-BsMp3MSo.d.ts +368 -0
  17. package/dist/{piChatSessionService-DDKPOj4x.d.ts → piChatSessionService-BrPqKrpY.d.ts} +5 -1
  18. package/dist/{sandbox-OEG_l9GE.d.ts → sandbox-DAD8cWQR.d.ts} +14 -1
  19. package/dist/server/agent-host/testing/gatewayConformance.d.ts +41 -0
  20. package/dist/server/agent-host/testing/gatewayConformance.js +465 -0
  21. package/dist/server/index.d.ts +451 -528
  22. package/dist/server/index.js +43 -9
  23. package/dist/server/worker/index.d.ts +2 -2
  24. package/dist/server/worker/index.js +7 -7
  25. package/dist/shared/index.d.ts +115 -41
  26. package/dist/shared/index.js +65 -282
  27. package/dist/types-uQozUhGt.d.ts +759 -0
  28. package/docs/ACCESSIBILITY.md +4 -5
  29. package/docs/API.md +3 -0
  30. package/docs/AUTHORING.md +68 -0
  31. package/docs/ERROR_CODES.md +27 -6
  32. package/docs/README.md +1 -0
  33. package/docs/runtime.md +3 -3
  34. package/package.json +22 -13
  35. package/dist/chunk-CFQQXJKK.js +0 -385
  36. package/dist/chunk-DGRKMMXO.js +0 -8
  37. package/dist/piChatEvent-CHgln6yx.d.ts +0 -367
@@ -22,6 +22,9 @@ var ErrorCode = z.enum([
22
22
  "AGENT_RUNTIME_NOT_READY",
23
23
  "AGENT_BINDING_DISPOSED",
24
24
  "AGENT_CONTROL_RECEIPT_INVALID",
25
+ "AGENT_FLEET_PLUGIN_UNKNOWN",
26
+ "AGENT_FLEET_CONFIG_BINDING_UNKNOWN",
27
+ "AGENT_FLEET_MODEL_POLICY_UNCOMPILED",
25
28
  "RUNTIME_PROVISIONING_FAILED",
26
29
  "RUNTIME_PROVISIONING_LOCKED",
27
30
  // Sandbox / exec
@@ -31,6 +34,28 @@ var ErrorCode = z.enum([
31
34
  "SANDBOX_NOT_READY",
32
35
  "SANDBOX_EXPIRED",
33
36
  "VERCEL_API_ERROR",
37
+ "REMOTE_WORKER_CONFIG_INVALID",
38
+ "REMOTE_WORKER_PROTOCOL_MISMATCH",
39
+ "REMOTE_WORKER_UNAUTHENTICATED",
40
+ "REMOTE_WORKER_UNAVAILABLE",
41
+ "REMOTE_WORKER_UNQUALIFIED",
42
+ "REMOTE_WORKER_REQUEST_INVALID",
43
+ "REMOTE_WORKER_RESPONSE_INVALID",
44
+ "REMOTE_WORKER_CAPABILITY_EXPIRED",
45
+ "REMOTE_WORKER_AUTHORIZED_WORKSPACE_REQUIRED",
46
+ "REMOTE_WORKER_BINDING_RECEIPT_INVALID",
47
+ "REMOTE_WORKER_SANDBOX_WORKSPACE_MISMATCH",
48
+ "REMOTE_WORKER_SANDBOX_NOT_FOUND",
49
+ "REMOTE_WORKER_SANDBOX_EXPIRED",
50
+ "REMOTE_WORKER_SANDBOX_DISPOSED",
51
+ "REMOTE_WORKER_CREATE_CONCURRENCY_EXHAUSTED",
52
+ "REMOTE_WORKER_EXEC_CONCURRENCY_EXHAUSTED",
53
+ "REMOTE_WORKER_IDEMPOTENCY_CONFLICT",
54
+ "REMOTE_WORKER_EXEC_IN_PROGRESS",
55
+ "REMOTE_WORKER_SECRET_INVOCATION_NOT_REPLAYABLE",
56
+ "REMOTE_WORKER_OUTCOME_UNKNOWN",
57
+ "REMOTE_WORKER_INCOMPLETE_CLEANUP",
58
+ "REMOTE_WORKER_DOCKER_COMMAND_FAILED",
34
59
  "REMOTE_WORKER_TIMEOUT",
35
60
  "REMOTE_WORKER_STREAM_CLOSED",
36
61
  "CIRCUIT_OPEN",
@@ -51,11 +76,7 @@ var ErrorCode = z.enum([
51
76
  "TOOL_EXECUTION_ERROR",
52
77
  "AUTHORED_AGENT_ID_INVALID",
53
78
  "AUTHORED_AGENT_TYPE_MISMATCH",
54
- "AUTHORED_AGENT_CATALOG_REQUIRED",
55
- "AUTHORED_AGENT_CATALOG_INVALID",
56
- "AUTHORED_AGENT_REFERENCE_UNKNOWN",
57
79
  "AUTHORED_AGENT_REFERENCE_UNSUPPORTED",
58
- "AUTHORED_AGENT_TOOL_INVALID",
59
80
  "AUTHORED_AGENT_TOOL_COLLISION",
60
81
  "MCP_AGENT_ARTIFACT_INVALID",
61
82
  "MCP_AGENT_ARTIFACT_TOO_LARGE",
@@ -91,7 +112,8 @@ var ErrorCode = z.enum([
91
112
  var ERROR_CODES = ErrorCode.options;
92
113
  var AgentDefinitionErrorCode = z.enum([
93
114
  "AGENT_DEFINITION_INVALID",
94
- "AGENT_DEFINITION_UNSUPPORTED_FIELD"
115
+ "AGENT_DEFINITION_UNSUPPORTED_FIELD",
116
+ "AUTHORED_AGENT_REFERENCE_UNSUPPORTED"
95
117
  ]);
96
118
  var AgentDeploymentErrorCode = z.enum([
97
119
  "AGENT_DEPLOYMENT_INVALID",
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-WSQ5QNIY.js";
4
4
  import {
5
5
  ErrorCode
6
- } from "./chunk-4PKGVPJA.js";
6
+ } from "./chunk-2GBHYJVC.js";
7
7
 
8
8
  // src/core/piChatSessionService.ts
9
9
  var AgentEffectAdmissionError = class extends Error {
@@ -17,6 +17,20 @@ var AgentEffectAdmissionError = class extends Error {
17
17
  details;
18
18
  statusCode = 500;
19
19
  };
20
+ var observedSynchronousServiceErrors = /* @__PURE__ */ new WeakSet();
21
+ function invokeObservedServiceEffect(effect) {
22
+ try {
23
+ return effect();
24
+ } catch (error) {
25
+ if (typeof error === "object" && error !== null || typeof error === "function") {
26
+ observedSynchronousServiceErrors.add(error);
27
+ }
28
+ throw error;
29
+ }
30
+ }
31
+ function isObservedSynchronousServiceError(error) {
32
+ return (typeof error === "object" && error !== null || typeof error === "function") && observedSynchronousServiceErrors.has(error);
33
+ }
20
34
  var AGENT_EFFECT_METHODS = {
21
35
  createSession: true,
22
36
  deleteSession: true,
@@ -31,34 +45,34 @@ function withAgentEffectAdmission(service, admit) {
31
45
  ...service.listSessions ? { listSessions: (ctx, options) => service.listSessions(ctx, options) } : {},
32
46
  async createSession(ctx, init) {
33
47
  await admit(ctx);
34
- return service.createSession(ctx, init);
48
+ return invokeObservedServiceEffect(() => service.createSession(ctx, init));
35
49
  },
36
50
  async deleteSession(ctx, sessionId) {
37
51
  await admit(ctx);
38
- return service.deleteSession(ctx, sessionId);
52
+ return invokeObservedServiceEffect(() => service.deleteSession(ctx, sessionId));
39
53
  },
40
54
  ...service.readAttachment ? { readAttachment: (ctx, sessionId, messageId, index) => service.readAttachment(ctx, sessionId, messageId, index) } : {},
41
55
  readState: (ctx, sessionId) => service.readState(ctx, sessionId),
42
56
  subscribe: (ctx, sessionId, cursor, subscriber) => service.subscribe(ctx, sessionId, cursor, subscriber),
43
57
  async prompt(ctx, sessionId, payload) {
44
58
  await admit(ctx);
45
- return service.prompt(ctx, sessionId, payload);
59
+ return invokeObservedServiceEffect(() => service.prompt(ctx, sessionId, payload));
46
60
  },
47
61
  async followUp(ctx, sessionId, payload) {
48
62
  await admit(ctx);
49
- return service.followUp(ctx, sessionId, payload);
63
+ return invokeObservedServiceEffect(() => service.followUp(ctx, sessionId, payload));
50
64
  },
51
65
  async clearQueue(ctx, sessionId, payload) {
52
66
  await admit(ctx);
53
- return service.clearQueue(ctx, sessionId, payload);
67
+ return invokeObservedServiceEffect(() => service.clearQueue(ctx, sessionId, payload));
54
68
  },
55
69
  async interrupt(ctx, sessionId, payload) {
56
70
  await admit(ctx);
57
- return service.interrupt(ctx, sessionId, payload);
71
+ return invokeObservedServiceEffect(() => service.interrupt(ctx, sessionId, payload));
58
72
  },
59
73
  async stop(ctx, sessionId, payload) {
60
74
  await admit(ctx);
61
- return service.stop(ctx, sessionId, payload);
75
+ return invokeObservedServiceEffect(() => service.stop(ctx, sessionId, payload));
62
76
  },
63
77
  ...service.dispose ? { dispose: () => service.dispose() } : {}
64
78
  };
@@ -596,6 +610,7 @@ function createLiveIterator(state, startIndex) {
596
610
 
597
611
  export {
598
612
  AgentEffectAdmissionError,
613
+ isObservedSynchronousServiceError,
599
614
  AGENT_EFFECT_METHODS,
600
615
  withAgentEffectAdmission,
601
616
  createAgent,
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-AQBXNPMD.js";
5
5
  import {
6
6
  ErrorCode
7
- } from "./chunk-4PKGVPJA.js";
7
+ } from "./chunk-2GBHYJVC.js";
8
8
 
9
9
  // src/server/harness/pi-coding-agent/createHarness.ts
10
10
  import { AsyncLocalStorage } from "async_hooks";
@@ -360,6 +360,7 @@ var PiSessionStore = class {
360
360
  allowLegacyUnscopedAccess;
361
361
  prefixCache = /* @__PURE__ */ new Map();
362
362
  listInFlight = /* @__PURE__ */ new Map();
363
+ writerTails = /* @__PURE__ */ new Map();
363
364
  constructor(cwd, options) {
364
365
  this.cwd = cwd;
365
366
  if (typeof options === "string") {
@@ -373,6 +374,14 @@ var PiSessionStore = class {
373
374
  getSessionDir() {
374
375
  return this.sessionDir;
375
376
  }
377
+ /** Reads the Host execution pin from authoritative session metadata. */
378
+ async readRuntimeScopeIdentity(ctx, sessionId) {
379
+ const filepath = await this.resolveSessionFile(sessionId, ctx);
380
+ const entries = parseJsonlPrefixEntries(await readJsonlPrefix(filepath));
381
+ const header = entries.find((entry) => entry.type === "session");
382
+ if (!this.headerBelongsToCtx(header, ctx)) throw new Error(`Session not found: ${sessionId}`);
383
+ return readHeaderRuntimeScopeIdentity(header);
384
+ }
376
385
  async list(ctx, options) {
377
386
  const normalizedOptions = normalizeListOptions(options);
378
387
  const inFlightKey = JSON.stringify([
@@ -452,7 +461,7 @@ var PiSessionStore = class {
452
461
  }
453
462
  async load(ctx, sessionId) {
454
463
  const resolved = await this.resolveSessionTranscript(ctx, sessionId);
455
- const title = extractTitle(resolved.sessionEntries) ?? extractTitle(resolved.linkedEntries) ?? "New session";
464
+ const title = newestDurableTitle(resolved.sessionEntries, resolved.linkedEntries) ?? "New session";
456
465
  const turnCount = countUserTurns(resolved.transcriptEntries);
457
466
  const updatedAtMs = Math.max(resolved.fileStat.mtime.getTime(), resolved.linkedMtimeMs ?? 0);
458
467
  return {
@@ -527,9 +536,53 @@ var PiSessionStore = class {
527
536
  linkedEntries,
528
537
  transcriptEntries,
529
538
  fileStat,
530
- linkedMtimeMs: linked?.mtime.getTime()
539
+ linkedMtimeMs: linked?.mtime.getTime(),
540
+ filepath,
541
+ ...linkedPiFile && linked ? { linkedFilepath: linkedPiFile } : {}
531
542
  };
532
543
  }
544
+ /**
545
+ * Addressed rename capability. Every resolved wrapper/native transcript is
546
+ * appended through the same JSONL path under one process-local writer lock.
547
+ */
548
+ async rename(ctx, sessionId, title) {
549
+ const trimmed = title.trim();
550
+ if (!trimmed) throw new Error("Session title must not be empty");
551
+ return await this.withWriter(sessionId, async () => {
552
+ const resolved = await this.resolveSessionTranscript(ctx, sessionId);
553
+ const entry = {
554
+ type: "session_info",
555
+ id: randomUUID(),
556
+ parentId: null,
557
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
558
+ name: trimmed
559
+ };
560
+ const line = `${JSON.stringify(entry)}
561
+ `;
562
+ const targets = [resolved.filepath, resolved.linkedFilepath].filter((path) => Boolean(path));
563
+ for (const filepath of targets) {
564
+ await appendFile(filepath, line);
565
+ this.prefixCache.delete(filepath);
566
+ }
567
+ return await this.load(ctx, sessionId);
568
+ });
569
+ }
570
+ async withWriter(key, action) {
571
+ const previous = this.writerTails.get(key) ?? Promise.resolve();
572
+ let release;
573
+ const current = new Promise((resolve2) => {
574
+ release = resolve2;
575
+ });
576
+ const tail = previous.then(() => current);
577
+ this.writerTails.set(key, tail);
578
+ await previous;
579
+ try {
580
+ return await action();
581
+ } finally {
582
+ release();
583
+ if (this.writerTails.get(key) === tail) this.writerTails.delete(key);
584
+ }
585
+ }
533
586
  // Synchronous variant used during session initialization so that no async
534
587
  // I/O hop is introduced before createAgentSession (which would break test
535
588
  // timing when fake timers are in use). The file is tiny (metadata only).
@@ -733,7 +786,7 @@ var PiSessionStore = class {
733
786
  const linkedEntries = linked?.entries.filter(
734
787
  (e) => e.type !== "session"
735
788
  ) ?? [];
736
- const title = extractTitle(sessionEntries) ?? extractTitle(linkedEntries) ?? firstUserMessage(linkedEntries) ?? firstUserMessage(sessionEntries) ?? "New session";
789
+ const title = newestDurableTitle(sessionEntries, linkedEntries) ?? firstUserMessage(linkedEntries) ?? firstUserMessage(sessionEntries) ?? "New session";
737
790
  const turnCount = [...sessionEntries, ...linkedEntries].filter(
738
791
  (e) => e.type === "message" && e.message?.role === "user"
739
792
  ).length;
@@ -972,11 +1025,19 @@ function readHeaderSessionCtx(header) {
972
1025
  if (!raw || typeof raw !== "object") return {};
973
1026
  return normalizeSessionCtx(raw) ?? {};
974
1027
  }
1028
+ function readHeaderRuntimeScopeIdentity(header) {
1029
+ const raw = header?.boringSessionCtx?.runtimeScopeIdentity;
1030
+ if (raw === void 0) return void 0;
1031
+ if (typeof raw !== "string" || !raw.trim()) throw new Error("Session runtime scope identity is invalid");
1032
+ return raw;
1033
+ }
975
1034
  function normalizeSessionCtx(ctx) {
976
- if (!ctx?.workspaceId && !ctx?.userId) return void 0;
1035
+ const runtimeScopeIdentity = typeof ctx?.runtimeScopeIdentity === "string" && ctx.runtimeScopeIdentity.trim() ? ctx.runtimeScopeIdentity : "";
1036
+ if (!ctx?.workspaceId && !ctx?.userId && !runtimeScopeIdentity) return void 0;
977
1037
  return {
978
- ...ctx.workspaceId ? { workspaceId: ctx.workspaceId } : {},
979
- ...ctx.userId ? { userId: ctx.userId } : {}
1038
+ ...ctx?.workspaceId ? { workspaceId: ctx.workspaceId } : {},
1039
+ ...ctx?.userId ? { userId: ctx.userId } : {},
1040
+ ...runtimeScopeIdentity ? { runtimeScopeIdentity } : {}
980
1041
  };
981
1042
  }
982
1043
  function sameSessionCtx(a, b) {
@@ -1020,9 +1081,16 @@ function countUserTurns(entries) {
1020
1081
  (e) => e.type === "message" && e.message?.role === "user"
1021
1082
  ).length;
1022
1083
  }
1023
- function extractTitle(entries) {
1024
- const last = entries.filter((e) => e.type === "session_info").pop();
1025
- return last?.name;
1084
+ function newestDurableTitle(wrapperEntries, nativeEntries) {
1085
+ const candidates = [
1086
+ ...wrapperEntries.flatMap((entry, offset) => entry.type === "session_info" ? [{ entry, native: 0, offset }] : []),
1087
+ ...nativeEntries.flatMap((entry, offset) => entry.type === "session_info" ? [{ entry, native: 1, offset }] : [])
1088
+ ];
1089
+ candidates.sort((a, b) => {
1090
+ const timestamp = Date.parse(b.entry.timestamp) - Date.parse(a.entry.timestamp);
1091
+ return timestamp || b.native - a.native || b.offset - a.offset;
1092
+ });
1093
+ return candidates[0]?.entry.name;
1026
1094
  }
1027
1095
  function firstUserMessage(entries) {
1028
1096
  for (const e of entries) {
@@ -1119,6 +1187,12 @@ function clean(value) {
1119
1187
  const trimmed = value?.trim();
1120
1188
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
1121
1189
  }
1190
+ function parseEncodedModelSelection(value) {
1191
+ const encoded = clean(value);
1192
+ if (!encoded) return void 0;
1193
+ const idx = encoded.indexOf(":");
1194
+ return idx > 0 && idx < encoded.length - 1 ? { provider: encoded.slice(0, idx), id: encoded.slice(idx + 1) } : void 0;
1195
+ }
1122
1196
  function readPositiveInt(name, fallback) {
1123
1197
  const raw = clean(getEnv(name));
1124
1198
  if (!raw) return fallback;
@@ -1282,13 +1356,8 @@ function readPiSettingsDefaultModel() {
1282
1356
  }
1283
1357
  }
1284
1358
  function readConfiguredDefaultModel() {
1285
- const encoded = clean(getEnv("BORING_AGENT_DEFAULT_MODEL"));
1286
- if (encoded) {
1287
- const idx = encoded.indexOf(":");
1288
- if (idx > 0 && idx < encoded.length - 1) {
1289
- return { provider: encoded.slice(0, idx), id: encoded.slice(idx + 1) };
1290
- }
1291
- }
1359
+ const encoded = parseEncodedModelSelection(getEnv("BORING_AGENT_DEFAULT_MODEL"));
1360
+ if (encoded) return encoded;
1292
1361
  const explicitProvider = clean(getEnv("BORING_AGENT_DEFAULT_MODEL_PROVIDER"));
1293
1362
  const explicitId = clean(getEnv("BORING_AGENT_DEFAULT_MODEL_ID"));
1294
1363
  if (explicitProvider && explicitId) {
@@ -1426,7 +1495,10 @@ function resolveRequestedModel(modelRegistry, input, options = {}) {
1426
1495
  }
1427
1496
  return model;
1428
1497
  }
1429
- function resolveDefaultModel(modelRegistry) {
1498
+ function resolveDefaultModel(modelRegistry, override, strict) {
1499
+ if (override) {
1500
+ return resolveRequestedModel(modelRegistry, { model: override }, { strict });
1501
+ }
1430
1502
  const configured = readConfiguredDefaultModel();
1431
1503
  if (configured) {
1432
1504
  const model = modelRegistry.find(configured.provider, configured.id);
@@ -1636,7 +1708,7 @@ function createPiCodingAgentHarness(opts) {
1636
1708
  isNewPiSession = true;
1637
1709
  }
1638
1710
  const resolvedModel = resolveRequestedModel(modelRegistry, input, { strict: pi.strictModelResolution });
1639
- const model = resolvedModel ?? resolveDefaultModel(modelRegistry);
1711
+ const model = resolvedModel ?? resolveDefaultModel(modelRegistry, pi.defaultModel, pi.strictModelResolution);
1640
1712
  refreshEffectiveResources();
1641
1713
  const composedSystemPromptAppend = composeSystemPromptAppend(opts.systemPromptAppend);
1642
1714
  const dynamicPromptExtension = opts.systemPromptDynamic ? buildDynamicPromptExtension(opts.systemPromptDynamic) : void 0;
@@ -1839,6 +1911,8 @@ ${entry.message}`;
1839
1911
 
1840
1912
  export {
1841
1913
  getEnv,
1914
+ PiSessionStore,
1915
+ parseEncodedModelSelection,
1842
1916
  registerConfiguredModelProviders,
1843
1917
  readConfiguredDefaultModel,
1844
1918
  PI_PACKAGE_RESOURCE_FILTERS,