@byok-sdk/client 0.4.1 → 0.5.0

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.
package/README.md CHANGED
@@ -63,6 +63,24 @@ validated registry. Only those logical IDs are advertised in `conn.hello`
63
63
  and hosted presence; command, args, environment, headers, and credentials
64
64
  remain local.
65
65
 
66
+ Hosted deployments that enforce an activity-ingress byte ceiling should inject
67
+ the same ceiling into the daemon. The byte count is the UTF-8 length of
68
+ `JSON.stringify(events)`; it does not include envelope or transport overhead.
69
+ One event that cannot fit fails the task locally without truncation or network
70
+ delivery.
71
+
72
+ ```ts
73
+ createDaemon({
74
+ // ...normal device and transport configuration
75
+ progressBatch: {
76
+ maxBatchBytes: 64 * 1024,
77
+ },
78
+ });
79
+ ```
80
+
81
+ The value is intentionally host-owned and has no SDK default because it is a
82
+ deployment/read-model policy, not a frozen protocol limit.
83
+
66
84
  For a concrete private host composition, see the
67
85
  [`examples/salesko-connector-broker`](../../examples/salesko-connector-broker)
68
86
  reference. It keeps `@byok-sdk/client` credential-blind while combining
@@ -172,6 +172,24 @@ function mapPermissionPolicyToPiArgs(policy) {
172
172
  }
173
173
 
174
174
  // src/adapters/pi/events.ts
175
+ function requireToolCallId(msg) {
176
+ if (typeof msg.toolCallId === "string" && msg.toolCallId.trim().length > 0) return msg.toolCallId;
177
+ throw new RuntimeExecutionFailure({
178
+ phase: "run",
179
+ category: "authority",
180
+ retry: "non-retryable",
181
+ reason: `pi ${msg.type} frame had no authoritative tool call id`
182
+ });
183
+ }
184
+ function requireToolResultOutcome(msg) {
185
+ if (typeof msg.isError === "boolean") return msg.isError;
186
+ throw new RuntimeExecutionFailure({
187
+ phase: "run",
188
+ category: "authority",
189
+ retry: "non-retryable",
190
+ reason: "pi tool_execution_end frame had no authoritative isError outcome"
191
+ });
192
+ }
175
193
  function mapPiMessageToAgentEvent(msg) {
176
194
  switch (msg.type) {
177
195
  case "message_update": {
@@ -182,16 +200,22 @@ function mapPiMessageToAgentEvent(msg) {
182
200
  return void 0;
183
201
  }
184
202
  case "tool_execution_start": {
203
+ const toolCallId = requireToolCallId(msg);
185
204
  if (typeof msg.toolName !== "string") return void 0;
186
- return { type: "tool_use", tool: msg.toolName, input: msg.args };
205
+ return { type: "tool_use", tool: msg.toolName, input: msg.args, toolCallId };
187
206
  }
188
207
  case "tool_execution_end": {
208
+ const toolCallId = requireToolCallId(msg);
209
+ const isError = requireToolResultOutcome(msg);
189
210
  if (typeof msg.toolName !== "string") return void 0;
190
- return {
211
+ const event = {
191
212
  type: "tool_result",
192
213
  tool: msg.toolName,
193
- output: { result: msg.result, isError: msg.isError === true }
214
+ output: { result: msg.result },
215
+ toolCallId,
216
+ isError
194
217
  };
218
+ return event;
195
219
  }
196
220
  case "agent_settled":
197
221
  return { type: "turn_end" };
@@ -1203,6 +1227,17 @@ function subtractDenied(tools, denyTools) {
1203
1227
  function createToolUseCorrelation() {
1204
1228
  return { toolNameByUseId: /* @__PURE__ */ new Map() };
1205
1229
  }
1230
+ function missingToolCallIdFailure(frame) {
1231
+ return new RuntimeExecutionFailure({
1232
+ phase: "run",
1233
+ category: "authority",
1234
+ retry: "non-retryable",
1235
+ reason: `claude ${frame} frame had no authoritative tool call id`
1236
+ });
1237
+ }
1238
+ function isAuthoritativeToolCallId(value) {
1239
+ return typeof value === "string" && value.trim().length > 0;
1240
+ }
1206
1241
  var ROUTINE_CLAUDE_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set([
1207
1242
  "init",
1208
1243
  "hook_started",
@@ -1246,9 +1281,12 @@ function mapAssistant(msg, correlation) {
1246
1281
  }
1247
1282
  break;
1248
1283
  case "tool_use":
1249
- if (typeof block.id === "string" && typeof block.name === "string") {
1284
+ if (!isAuthoritativeToolCallId(block.id)) {
1285
+ return { events: [], terminalFailure: missingToolCallIdFailure("tool_use") };
1286
+ }
1287
+ if (typeof block.name === "string") {
1250
1288
  correlation.toolNameByUseId.set(block.id, block.name);
1251
- events.push({ type: "tool_use", tool: block.name, input: block.input });
1289
+ events.push({ type: "tool_use", tool: block.name, input: block.input, toolCallId: block.id });
1252
1290
  }
1253
1291
  break;
1254
1292
  // Deliberately NOT mapped to `progress` — mirrors pi's own choice to
@@ -1284,11 +1322,20 @@ function mapUser(msg, correlation, options) {
1284
1322
  unmappedLabel = unmappedLabel ?? `user-block:${String(block.type)}`;
1285
1323
  continue;
1286
1324
  }
1287
- const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : void 0;
1288
- const tool = toolUseId && correlation.toolNameByUseId.get(toolUseId) || "unknown";
1289
- const isError = block.is_error === true;
1290
- events.push({ type: "tool_result", tool, output: { content: block.content, isError } });
1291
- if (!isError && FILE_WRITING_TOOLS.has(tool)) {
1325
+ if (!isAuthoritativeToolCallId(block.tool_use_id)) {
1326
+ return { events: [], terminalFailure: missingToolCallIdFailure("tool_result") };
1327
+ }
1328
+ const tool = correlation.toolNameByUseId.get(block.tool_use_id) ?? "unknown";
1329
+ const isError = typeof block.is_error === "boolean" ? block.is_error : void 0;
1330
+ const event = {
1331
+ type: "tool_result",
1332
+ tool,
1333
+ output: { content: block.content },
1334
+ toolCallId: block.tool_use_id
1335
+ };
1336
+ if (isError !== void 0) event.isError = isError;
1337
+ events.push(event);
1338
+ if (isError === false && FILE_WRITING_TOOLS.has(tool)) {
1292
1339
  const artifact = tryBuildArtifactEvent(msg, options.workspaceDir);
1293
1340
  if (artifact) events.push(artifact);
1294
1341
  }
@@ -1911,8 +1958,8 @@ var ClaudeSession = class {
1911
1958
  for (; ; ) {
1912
1959
  const buffered = pending.shift();
1913
1960
  if (buffered) return { value: buffered, done: false };
1961
+ if (terminalFailure) throw terminalFailure;
1914
1962
  if (turnSettled) {
1915
- if (terminalFailure) throw terminalFailure;
1916
1963
  return { value: void 0, done: true };
1917
1964
  }
1918
1965
  let raw;
@@ -2114,6 +2161,15 @@ function extractCodexUsageEvent(rawUsage) {
2114
2161
  function toNonNegativeInt2(value) {
2115
2162
  return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : void 0;
2116
2163
  }
2164
+ function requireToolCallId2(item) {
2165
+ if (typeof item.id === "string" && item.id.trim().length > 0) return item.id;
2166
+ throw new RuntimeExecutionFailure({
2167
+ phase: "run",
2168
+ category: "authority",
2169
+ retry: "non-retryable",
2170
+ reason: "codex tool item had no authoritative tool call id"
2171
+ });
2172
+ }
2117
2173
  function mapItem(rawItem, phase, workspaceDir) {
2118
2174
  if (!rawItem || typeof rawItem !== "object") return [];
2119
2175
  const item = rawItem;
@@ -2124,9 +2180,10 @@ function mapItem(rawItem, phase, workspaceDir) {
2124
2180
  return typeof item.text === "string" ? [{ type: "progress", text: item.text }] : [];
2125
2181
  }
2126
2182
  case "command_execution": {
2183
+ const toolCallId = requireToolCallId2(item);
2127
2184
  const command = typeof item.command === "string" ? item.command : void 0;
2128
2185
  if (phase === "started") {
2129
- return command !== void 0 ? [{ type: "tool_use", tool: "command_execution", input: { command } }] : [];
2186
+ return command !== void 0 ? [{ type: "tool_use", tool: "command_execution", input: { command }, toolCallId }] : [];
2130
2187
  }
2131
2188
  return [
2132
2189
  {
@@ -2137,17 +2194,19 @@ function mapItem(rawItem, phase, workspaceDir) {
2137
2194
  aggregatedOutput: item.aggregated_output,
2138
2195
  exitCode: item.exit_code,
2139
2196
  status: item.status
2140
- }
2197
+ },
2198
+ toolCallId
2141
2199
  }
2142
2200
  ];
2143
2201
  }
2144
2202
  case "file_change": {
2203
+ const toolCallId = requireToolCallId2(item);
2145
2204
  const changes = Array.isArray(item.changes) ? item.changes : [];
2146
2205
  if (phase === "started") {
2147
- return [{ type: "tool_use", tool: "file_change", input: { changes } }];
2206
+ return [{ type: "tool_use", tool: "file_change", input: { changes }, toolCallId }];
2148
2207
  }
2149
2208
  return [
2150
- { type: "tool_result", tool: "file_change", output: { changes, status: item.status } },
2209
+ { type: "tool_result", tool: "file_change", output: { changes, status: item.status }, toolCallId },
2151
2210
  ...extractArtifactEvents(changes, workspaceDir)
2152
2211
  ];
2153
2212
  }
@@ -2570,7 +2629,15 @@ async function runCodexTurn(params) {
2570
2629
  }
2571
2630
  return;
2572
2631
  }
2573
- const mapped = mapCodexEventToAgentEvents(evt, params.workspaceDir);
2632
+ let mapped;
2633
+ try {
2634
+ mapped = mapCodexEventToAgentEvents(evt, params.workspaceDir);
2635
+ } catch (cause) {
2636
+ if (!isRuntimeExecutionFailure(cause)) throw cause;
2637
+ params.terminal.failure = cause;
2638
+ params.queue.end();
2639
+ return;
2640
+ }
2574
2641
  for (const agentEvent of mapped) {
2575
2642
  if (agentEvent.type === "turn_end") turnEnded = true;
2576
2643
  params.queue.push(agentEvent);