perchai-cli 2.4.36 → 2.4.37

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 (2) hide show
  1. package/dist/perch.mjs +43 -25
  2. package/package.json +1 -1
package/dist/perch.mjs CHANGED
@@ -75917,7 +75917,6 @@ function isTurnAbortedError(error) {
75917
75917
  var TURN_STOPPED_BY_USER_MESSAGE;
75918
75918
  var init_turnAbort = __esm({
75919
75919
  "features/perchTerminal/runtime/turnAbort.ts"() {
75920
- "use strict";
75921
75920
  TURN_STOPPED_BY_USER_MESSAGE = "Turn stopped by user.";
75922
75921
  }
75923
75922
  });
@@ -76218,7 +76217,6 @@ function getToolDisplayName(toolName) {
76218
76217
  var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
76219
76218
  var init_catalog = __esm({
76220
76219
  "features/perchTerminal/runtime/toolSystem/catalog.ts"() {
76221
- "use strict";
76222
76220
  init_toolNames();
76223
76221
  NON_MODULE_TOOL_OWNERS = {
76224
76222
  [TOOL_NAMES.listSources]: "lane",
@@ -83126,7 +83124,6 @@ function listFinancialRoleIds() {
83126
83124
  var FINANCIAL_ROLE_REGISTRY, evidenceScoutManifest;
83127
83125
  var init_financialRoles = __esm({
83128
83126
  "features/perchTerminal/agentPlatform/financialRoles.ts"() {
83129
- "use strict";
83130
83127
  FINANCIAL_ROLE_REGISTRY = /* @__PURE__ */ new Map();
83131
83128
  evidenceScoutManifest = {
83132
83129
  workerId: "evidence_scout",
@@ -86724,7 +86721,6 @@ function truncateHistoryLine(value, max2) {
86724
86721
  }
86725
86722
  var init_operatorTruth = __esm({
86726
86723
  "features/perchTerminal/runtime/operatorTruth.ts"() {
86727
- "use strict";
86728
86724
  }
86729
86725
  });
86730
86726
 
@@ -138644,6 +138640,7 @@ function offSandboxEvent(runId, handler) {
138644
138640
  var LOCAL_WORKSPACE_ACCESS_UNAVAILABLE;
138645
138641
  var init_bridge = __esm({
138646
138642
  "features/perchTerminal/desktop/bridge.ts"() {
138643
+ "use strict";
138647
138644
  LOCAL_WORKSPACE_ACCESS_UNAVAILABLE = "Local workspace access is unavailable. Open Perch Desktop or update the app.";
138648
138645
  }
138649
138646
  });
@@ -205378,7 +205375,7 @@ function clampInt(value, min2, max2, fallback) {
205378
205375
  const num = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
205379
205376
  return Math.min(Math.max(num, min2), max2);
205380
205377
  }
205381
- var ADHOC_FORBIDDEN_TOOLS, ADHOC_WRITE_TOOLS, ADHOC_MAX_ITERATIONS, MAX_NAME_CHARS, MAX_CONTRACT_CHARS, DEFAULT_OUTPUT_CONTRACT;
205378
+ var ADHOC_FORBIDDEN_TOOLS, ADHOC_WRITE_TOOLS, ADHOC_MAX_ITERATIONS, ADHOC_MAX_TOOL_CALLS, MAX_NAME_CHARS, MAX_CONTRACT_CHARS, DEFAULT_OUTPUT_CONTRACT;
205382
205379
  var init_adhocManifest = __esm({
205383
205380
  "features/perchTerminal/runtime/workers/adhocManifest.ts"() {
205384
205381
  "use strict";
@@ -205407,6 +205404,7 @@ var init_adhocManifest = __esm({
205407
205404
  TOOL_NAMES.createDirectory
205408
205405
  ]);
205409
205406
  ADHOC_MAX_ITERATIONS = 10;
205407
+ ADHOC_MAX_TOOL_CALLS = 40;
205410
205408
  MAX_NAME_CHARS = 40;
205411
205409
  MAX_CONTRACT_CHARS = 240;
205412
205410
  DEFAULT_OUTPUT_CONTRACT = "Return a short structured summary of what was found or done.";
@@ -205495,6 +205493,14 @@ var init_spawnWorker = __esm({
205495
205493
  handler: async (args, ctx) => {
205496
205494
  let workerId = String(args.workerId ?? "");
205497
205495
  const objective = String(args.objective ?? "");
205496
+ if (!ctx.onEvent) {
205497
+ return {
205498
+ ok: false,
205499
+ workerId,
205500
+ summary: "spawn_worker requires an event sink from the parent tool loop.",
205501
+ errorCode: "worker_event_sink_missing"
205502
+ };
205503
+ }
205498
205504
  let adhocManifestId = null;
205499
205505
  let adhocNickname = null;
205500
205506
  const customSpec = parseAdhocSpec(args.custom);
@@ -205509,11 +205515,13 @@ var init_spawnWorker = __esm({
205509
205515
  if (workerId && customSpec && !resolveWorkerManifest(workerId)) {
205510
205516
  workerId = "";
205511
205517
  }
205518
+ let adhocDisplayTitle;
205512
205519
  if (!workerId && customSpec) {
205513
205520
  const { manifest, droppedTools } = buildAdhocWorkerManifest(customSpec);
205514
205521
  registerWorkerManifest(manifest);
205515
205522
  adhocManifestId = manifest.workerId;
205516
205523
  adhocNickname = flockNicknameFor(manifest.workerId, 0);
205524
+ adhocDisplayTitle = `${manifest.name} \xB7 ${adhocNickname}`;
205517
205525
  workerId = manifest.workerId;
205518
205526
  if (droppedTools.length > 0 && ctx.onEvent) {
205519
205527
  ctx.onEvent({
@@ -205534,15 +205542,7 @@ var init_spawnWorker = __esm({
205534
205542
  }
205535
205543
  const context = typeof args.context === "string" || typeof args.context === "object" && args.context !== null && !Array.isArray(args.context) ? args.context : void 0;
205536
205544
  const lane = typeof args.lane === "string" ? args.lane : void 0;
205537
- const maxIterations = typeof args.maxIterations === "number" ? args.maxIterations : void 0;
205538
- if (!ctx.onEvent) {
205539
- return {
205540
- ok: false,
205541
- workerId,
205542
- summary: "spawn_worker requires an event sink from the parent tool loop.",
205543
- errorCode: "worker_event_sink_missing"
205544
- };
205545
- }
205545
+ const maxIterations = typeof args.maxIterations === "number" ? adhocManifestId ? Math.min(args.maxIterations, ADHOC_MAX_ITERATIONS) : args.maxIterations : void 0;
205546
205546
  const enrichedContext = await threadPriorSpecialistContext({
205547
205547
  threadId: ctx.threadId,
205548
205548
  roleId: workerId,
@@ -205564,8 +205564,19 @@ Proceed with the available context. If a missing fact is essential, ask the user
205564
205564
  ].filter(Boolean).join("\n\n");
205565
205565
  try {
205566
205566
  const result2 = await spawnWorker(
205567
- { workerId, objective: workerObjective, context: enrichedContext, lane, maxIterations },
205568
205567
  {
205568
+ workerId,
205569
+ objective: workerObjective,
205570
+ context: enrichedContext,
205571
+ lane,
205572
+ maxIterations,
205573
+ // Ad-hoc workers get a hard real-tool-call ceiling (observed live:
205574
+ // an unbounded 66-call run). Registered workers keep their existing
205575
+ // behavior — suites and managed workflows own their own budgets.
205576
+ maxToolCalls: adhocManifestId ? ADHOC_MAX_TOOL_CALLS : void 0
205577
+ },
205578
+ {
205579
+ displayTitle: adhocDisplayTitle,
205569
205580
  workspaceRoot: effectiveWorkspaceRoot(ctx),
205570
205581
  desktopConnected: ctx.desktopConnected,
205571
205582
  // CLI surface: children inherit the local bridge and server auth,
@@ -220237,12 +220248,13 @@ async function spawnWorker(args, ctx) {
220237
220248
  errorCode: "worker_not_found"
220238
220249
  };
220239
220250
  }
220251
+ const eventTitle = ctx.displayTitle?.trim() || manifest.name;
220240
220252
  const runDiscriminator = ctx.runId ?? Date.now().toString(36);
220241
220253
  const childThreadId = args.childThreadId ?? (ctx.threadId ? `${ctx.threadId}::worker::${args.workerId}::${runDiscriminator}` : null);
220242
220254
  const workerRun = ctx.threadId ? await registerWorkerRun({
220243
220255
  threadId: ctx.threadId,
220244
220256
  workerId: args.workerId,
220245
- title: manifest.name,
220257
+ title: eventTitle,
220246
220258
  objective: args.objective,
220247
220259
  context: args.context,
220248
220260
  parentToolCallId: ctx.parentToolCallId ?? null,
@@ -220265,14 +220277,14 @@ async function spawnWorker(args, ctx) {
220265
220277
  childThreadId,
220266
220278
  workerRunId: runtimeWorkerRunId,
220267
220279
  workerId: args.workerId,
220268
- title: manifest.name
220280
+ title: eventTitle
220269
220281
  });
220270
220282
  }
220271
220283
  ctx.onEvent({
220272
220284
  type: "worker_run_started",
220273
220285
  workerId: args.workerId,
220274
220286
  workerRunId: runtimeWorkerRunId,
220275
- title: manifest.name,
220287
+ title: eventTitle,
220276
220288
  objective: args.objective,
220277
220289
  contextSummary: summarizeWorkerContextForTranscript(args.context),
220278
220290
  childThreadId,
@@ -220479,18 +220491,24 @@ ${contextBlock}
220479
220491
  attachOperatorScreenshots: isBrowserDeliveryRole(args.workerId)
220480
220492
  };
220481
220493
  const result2 = await runModelToolLoop(loopInput);
220494
+ const approvalBlocked = result2.stopReason === "approval_required" ? result2.pendingApproval ?? null : null;
220482
220495
  const recoveredStructuredOutput = recoverWorkerStructuredOutput(args.workerId, args.objective, args.context, result2.toolCalls);
220483
220496
  const structuredOutput = parseStructuredRecordFromModelText(result2.text) ?? recoveredStructuredOutput;
220484
220497
  const missingRequiredOutput = result2.ok && Boolean(manifest.outputSchema) && !structuredOutput;
220485
220498
  const verifierPartialOrFail = (args.workerId === "source_verifier" || args.workerId === "legal_citation_verifier") && structuredOutput !== null && typeof structuredOutput === "object" && structuredOutput.verificationStatus !== "pass";
220486
220499
  const hasUsableOutput = Boolean(structuredOutput) || Boolean(recoveredStructuredOutput) || (result2.text?.trim().length ?? 0) > 50;
220487
- const workerOk = (result2.ok || Boolean(recoveredStructuredOutput)) && !missingRequiredOutput;
220488
- const usabilityStatus = resolveWorkerUsability({
220500
+ const workerOk = !approvalBlocked && (result2.ok || Boolean(recoveredStructuredOutput)) && !missingRequiredOutput;
220501
+ const usabilityStatus = approvalBlocked ? "needs_user_input" : resolveWorkerUsability({
220489
220502
  workerOk,
220490
220503
  hasUsableOutput,
220491
220504
  verifierPartialOrFail
220492
220505
  });
220493
220506
  const workerWarnings = [];
220507
+ if (approvalBlocked) {
220508
+ workerWarnings.push(
220509
+ "Worker stopped at an approval gate \u2014 the gated action did not run."
220510
+ );
220511
+ }
220494
220512
  if (verifierPartialOrFail && hasUsableOutput) {
220495
220513
  workerWarnings.push(`Verification returned "${structuredOutput?.verificationStatus ?? "unknown"}" \u2014 output usable with caveat.`);
220496
220514
  }
@@ -220502,7 +220520,7 @@ ${contextBlock}
220502
220520
  }
220503
220521
  const recoveredSummary = recoveredStructuredOutput ? summarizeRecoveredWorkerOutput(args.workerId, recoveredStructuredOutput) : null;
220504
220522
  const summary = truncateSummary(
220505
- workerOk ? !result2.ok && recoveredSummary ? recoveredSummary : result2.text || recoveredSummary || (recoveredStructuredOutput ? JSON.stringify(recoveredStructuredOutput) : "") : missingRequiredOutput ? result2.text || "Worker stopped without returning the required structured JSON output." : result2.text || result2.error || "Worker failed before producing output."
220523
+ approvalBlocked ? `Blocked at an approval gate: ${approvalBlocked.toolName ?? "a gated tool"} requires approval in the current permission mode${approvalBlocked.reason ? ` (${approvalBlocked.reason})` : ""}. The action did not run. Approve it interactively, or re-run under /permission take_the_wheel.` : workerOk ? !result2.ok && recoveredSummary ? recoveredSummary : result2.text || recoveredSummary || (recoveredStructuredOutput ? JSON.stringify(recoveredStructuredOutput) : "") : missingRequiredOutput ? result2.text || "Worker stopped without returning the required structured JSON output." : result2.text || result2.error || "Worker failed before producing output."
220506
220524
  );
220507
220525
  const durationMs = Date.now() - startMs;
220508
220526
  let contextPacket = null;
@@ -220539,7 +220557,7 @@ ${contextBlock}
220539
220557
  type: "worker_run_completed",
220540
220558
  workerId: args.workerId,
220541
220559
  workerRunId: runtimeWorkerRunId,
220542
- title: manifest.name,
220560
+ title: eventTitle,
220543
220561
  childThreadId,
220544
220562
  persistedThreadId,
220545
220563
  parentToolCallId: ctx.parentToolCallId ?? null,
@@ -220573,7 +220591,7 @@ ${contextBlock}
220573
220591
  missingRequiredOutput,
220574
220592
  verifierPartialOrFail,
220575
220593
  error: result2.error
220576
- }) : void 0,
220594
+ }) : approvalBlocked ? "worker_approval_required" : void 0,
220577
220595
  workerOffThreadTokens: workerTokenEstimate,
220578
220596
  contextPacket
220579
220597
  }, { supabase: ctx.supabase ?? null });
@@ -220597,7 +220615,7 @@ ${contextBlock}
220597
220615
  missingRequiredOutput,
220598
220616
  verifierPartialOrFail,
220599
220617
  error: result2.error
220600
- }) : void 0,
220618
+ }) : approvalBlocked ? "worker_approval_required" : void 0,
220601
220619
  warnings: workerWarnings.length > 0 ? workerWarnings : void 0
220602
220620
  };
220603
220621
  } catch (error) {
@@ -220608,7 +220626,7 @@ ${contextBlock}
220608
220626
  type: "worker_run_completed",
220609
220627
  workerId: args.workerId,
220610
220628
  workerRunId: runtimeWorkerRunId,
220611
- title: manifest.name,
220629
+ title: eventTitle,
220612
220630
  childThreadId,
220613
220631
  parentToolCallId: ctx.parentToolCallId ?? null,
220614
220632
  ok: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perchai-cli",
3
- "version": "2.4.36",
3
+ "version": "2.4.37",
4
4
  "description": "Perch AI command-line interface",
5
5
  "bin": {
6
6
  "perch": "bin/perch"