perchai-cli 2.4.24 → 2.4.25
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/dist/perch.mjs +302 -32
- package/package.json +1 -1
package/dist/perch.mjs
CHANGED
|
@@ -75566,6 +75566,7 @@ var init_payroll = __esm({
|
|
|
75566
75566
|
// lib/perchBusinessTools/index.ts
|
|
75567
75567
|
var init_perchBusinessTools = __esm({
|
|
75568
75568
|
"lib/perchBusinessTools/index.ts"() {
|
|
75569
|
+
"use strict";
|
|
75569
75570
|
init_generateAPAuditPacket();
|
|
75570
75571
|
init_inventoryFolder();
|
|
75571
75572
|
init_loadBusinessTables();
|
|
@@ -75917,6 +75918,7 @@ function isTurnAbortedError(error) {
|
|
|
75917
75918
|
var TURN_STOPPED_BY_USER_MESSAGE;
|
|
75918
75919
|
var init_turnAbort = __esm({
|
|
75919
75920
|
"features/perchTerminal/runtime/turnAbort.ts"() {
|
|
75921
|
+
"use strict";
|
|
75920
75922
|
TURN_STOPPED_BY_USER_MESSAGE = "Turn stopped by user.";
|
|
75921
75923
|
}
|
|
75922
75924
|
});
|
|
@@ -76217,7 +76219,6 @@ function getToolDisplayName(toolName) {
|
|
|
76217
76219
|
var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
|
|
76218
76220
|
var init_catalog = __esm({
|
|
76219
76221
|
"features/perchTerminal/runtime/toolSystem/catalog.ts"() {
|
|
76220
|
-
"use strict";
|
|
76221
76222
|
init_toolNames();
|
|
76222
76223
|
NON_MODULE_TOOL_OWNERS = {
|
|
76223
76224
|
[TOOL_NAMES.listSources]: "lane",
|
|
@@ -76921,6 +76922,7 @@ function buildTranscriptSegments(state) {
|
|
|
76921
76922
|
const terminalSegmentIdx = /* @__PURE__ */ new Map();
|
|
76922
76923
|
const workerRunIdx = /* @__PURE__ */ new Map();
|
|
76923
76924
|
const flockRunIdx = /* @__PURE__ */ new Map();
|
|
76925
|
+
const diagnosticIdxByKey = /* @__PURE__ */ new Map();
|
|
76924
76926
|
const capabilityIdx = /* @__PURE__ */ new Map();
|
|
76925
76927
|
const liveCardIdx = /* @__PURE__ */ new Map();
|
|
76926
76928
|
const workflowCardIdx = /* @__PURE__ */ new Map();
|
|
@@ -77542,6 +77544,38 @@ function buildTranscriptSegments(state) {
|
|
|
77542
77544
|
case "diagnostic": {
|
|
77543
77545
|
flushReasoning();
|
|
77544
77546
|
if (!ev.message.trim()) break;
|
|
77547
|
+
if (ev.code === "tool_call_budget_exhausted") {
|
|
77548
|
+
let attributed = false;
|
|
77549
|
+
if (ev.workerId) {
|
|
77550
|
+
for (const [flockId, idx] of flockRunIdx) {
|
|
77551
|
+
const seg = segments[idx];
|
|
77552
|
+
if (seg?.kind !== "flock_run") continue;
|
|
77553
|
+
if (!seg.workers.some((worker) => worker.workerId === ev.workerId)) continue;
|
|
77554
|
+
segments[idx] = {
|
|
77555
|
+
...seg,
|
|
77556
|
+
workers: seg.workers.map(
|
|
77557
|
+
(worker) => worker.workerId === ev.workerId ? { ...worker, note: "tool limit \u2014 finishing from gathered evidence" } : worker
|
|
77558
|
+
)
|
|
77559
|
+
};
|
|
77560
|
+
attributed = Boolean(flockId);
|
|
77561
|
+
break;
|
|
77562
|
+
}
|
|
77563
|
+
}
|
|
77564
|
+
if (!attributed) {
|
|
77565
|
+
const key = `tool-budget-${ev.workerId ?? "turn"}`;
|
|
77566
|
+
const existingIdx = diagnosticIdxByKey.get(key);
|
|
77567
|
+
if (existingIdx !== void 0 && segments[existingIdx]?.kind === "diagnostic") {
|
|
77568
|
+
segments[existingIdx] = {
|
|
77569
|
+
...segments[existingIdx],
|
|
77570
|
+
message: ev.message
|
|
77571
|
+
};
|
|
77572
|
+
} else {
|
|
77573
|
+
diagnosticIdxByKey.set(key, segments.length);
|
|
77574
|
+
segments.push({ kind: "diagnostic", message: ev.message, seq: seq++, timestamp: ev.ts });
|
|
77575
|
+
}
|
|
77576
|
+
}
|
|
77577
|
+
break;
|
|
77578
|
+
}
|
|
77545
77579
|
segments.push({
|
|
77546
77580
|
kind: "diagnostic",
|
|
77547
77581
|
message: ev.message,
|
|
@@ -77849,6 +77883,7 @@ function buildTranscriptSegments(state) {
|
|
|
77849
77883
|
plannerSource: ev.plannerSource,
|
|
77850
77884
|
workers: ev.workers.map((worker) => ({
|
|
77851
77885
|
flockWorkerId: worker.flockWorkerId,
|
|
77886
|
+
workerId: worker.workerId,
|
|
77852
77887
|
displayName: worker.displayName,
|
|
77853
77888
|
nickname: worker.nickname,
|
|
77854
77889
|
status: "queued"
|
|
@@ -77868,6 +77903,7 @@ function buildTranscriptSegments(state) {
|
|
|
77868
77903
|
...seg.workers,
|
|
77869
77904
|
{
|
|
77870
77905
|
flockWorkerId: ev.flockWorkerId,
|
|
77906
|
+
workerId: ev.workerId,
|
|
77871
77907
|
displayName: ev.displayName,
|
|
77872
77908
|
nickname: ev.nickname,
|
|
77873
77909
|
status: ev.status
|
|
@@ -83022,7 +83058,6 @@ function listFinancialRoleIds() {
|
|
|
83022
83058
|
var FINANCIAL_ROLE_REGISTRY, evidenceScoutManifest;
|
|
83023
83059
|
var init_financialRoles = __esm({
|
|
83024
83060
|
"features/perchTerminal/agentPlatform/financialRoles.ts"() {
|
|
83025
|
-
"use strict";
|
|
83026
83061
|
FINANCIAL_ROLE_REGISTRY = /* @__PURE__ */ new Map();
|
|
83027
83062
|
evidenceScoutManifest = {
|
|
83028
83063
|
workerId: "evidence_scout",
|
|
@@ -86588,7 +86623,6 @@ function truncateHistoryLine(value, max2) {
|
|
|
86588
86623
|
}
|
|
86589
86624
|
var init_operatorTruth = __esm({
|
|
86590
86625
|
"features/perchTerminal/runtime/operatorTruth.ts"() {
|
|
86591
|
-
"use strict";
|
|
86592
86626
|
}
|
|
86593
86627
|
});
|
|
86594
86628
|
|
|
@@ -90875,6 +90909,7 @@ Final answers lead with findings, name artifacts or delivery status, and give on
|
|
|
90875
90909
|
var MARKET_DESK_TOOL_NAMES;
|
|
90876
90910
|
var init_marketDeskAccess = __esm({
|
|
90877
90911
|
"features/perchTerminal/runtime/marketDesk/marketDeskAccess.ts"() {
|
|
90912
|
+
"use strict";
|
|
90878
90913
|
init_toolNames();
|
|
90879
90914
|
MARKET_DESK_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
90880
90915
|
TOOL_NAMES.getMarketSignal,
|
|
@@ -200036,7 +200071,6 @@ function recordDispatchBatchResult(tasks, result2, ctx, opts = {}) {
|
|
|
200036
200071
|
var lifecycleByRun, MAX_LIFECYCLE_RUNS;
|
|
200037
200072
|
var init_workerLifecycle = __esm({
|
|
200038
200073
|
"features/perchTerminal/runtime/workers/workerLifecycle.ts"() {
|
|
200039
|
-
"use strict";
|
|
200040
200074
|
init_workerManifest();
|
|
200041
200075
|
lifecycleByRun = /* @__PURE__ */ new Map();
|
|
200042
200076
|
MAX_LIFECYCLE_RUNS = 200;
|
|
@@ -217708,10 +217742,18 @@ async function runModelToolLoop(input) {
|
|
|
217708
217742
|
batch.slice(remainingRealToolCalls).map((toolCall) => toolCall.id)
|
|
217709
217743
|
);
|
|
217710
217744
|
if (skippedForToolBudget.size > 0) {
|
|
217745
|
+
const skippedToolNames = [
|
|
217746
|
+
...new Set(
|
|
217747
|
+
batch.filter((toolCall) => skippedForToolBudget.has(toolCall.id)).map((toolCall) => toolCall.name)
|
|
217748
|
+
)
|
|
217749
|
+
];
|
|
217711
217750
|
onEvent({
|
|
217712
217751
|
type: "diagnostic",
|
|
217713
217752
|
code: "tool_call_budget_exhausted",
|
|
217714
|
-
message: `Tool
|
|
217753
|
+
message: `Tool budget reached after ${realToolCallsStarted} call(s) \u2014 finishing from gathered evidence.`,
|
|
217754
|
+
toolNames: skippedToolNames,
|
|
217755
|
+
skippedCount: skippedForToolBudget.size,
|
|
217756
|
+
maxToolCalls: maxToolCalls ?? 0,
|
|
217715
217757
|
ts: now5()
|
|
217716
217758
|
});
|
|
217717
217759
|
}
|
|
@@ -217725,6 +217767,7 @@ async function runModelToolLoop(input) {
|
|
|
217725
217767
|
firstPartyToolIntentUsed = true;
|
|
217726
217768
|
}
|
|
217727
217769
|
const batchTerminalIds = batch.map((toolCall) => {
|
|
217770
|
+
if (skippedForToolBudget.has(toolCall.id)) return null;
|
|
217728
217771
|
onEvent({
|
|
217729
217772
|
type: "tool_call_requested",
|
|
217730
217773
|
toolName: toolCall.name,
|
|
@@ -217896,17 +217939,20 @@ async function runModelToolLoop(input) {
|
|
|
217896
217939
|
consecutiveRequiredArgFailures,
|
|
217897
217940
|
execution
|
|
217898
217941
|
);
|
|
217899
|
-
|
|
217900
|
-
|
|
217901
|
-
|
|
217902
|
-
|
|
217903
|
-
|
|
217904
|
-
|
|
217905
|
-
|
|
217906
|
-
|
|
217907
|
-
|
|
217908
|
-
|
|
217909
|
-
|
|
217942
|
+
const isToolBudgetSuppressed = execution.errorCode === "tool_call_budget_exhausted";
|
|
217943
|
+
if (!isToolBudgetSuppressed) {
|
|
217944
|
+
onEvent({
|
|
217945
|
+
type: execution.ok ? "tool_call_completed" : "tool_call_failed",
|
|
217946
|
+
toolName: toolCall.name,
|
|
217947
|
+
toolCallId: toolCall.id,
|
|
217948
|
+
riskLevel: execution.riskLevel,
|
|
217949
|
+
ok: execution.ok,
|
|
217950
|
+
errorCode: execution.errorCode,
|
|
217951
|
+
error: execution.error,
|
|
217952
|
+
metadata: browserPerceptionMetadata(execution),
|
|
217953
|
+
ts: now5()
|
|
217954
|
+
});
|
|
217955
|
+
}
|
|
217910
217956
|
if (execution.ok && (toolCall.name === "writeLocalFile" || toolCall.name === "editLocalFile")) {
|
|
217911
217957
|
const out = typeof execution.output === "object" && execution.output !== null ? execution.output : null;
|
|
217912
217958
|
const filePath = typeof out?.relativePath === "string" ? out.relativePath : null;
|
|
@@ -217965,7 +218011,7 @@ async function runModelToolLoop(input) {
|
|
|
217965
218011
|
});
|
|
217966
218012
|
}
|
|
217967
218013
|
const toolResultText = execution.outputSummary?.trim() ? execution.outputSummary : execution.result.slice(0, 1500);
|
|
217968
|
-
if (toolResultText.trim() && !isTerminalTool) {
|
|
218014
|
+
if (toolResultText.trim() && !isTerminalTool && !isToolBudgetSuppressed) {
|
|
217969
218015
|
onEvent({
|
|
217970
218016
|
type: "tool_output_delta",
|
|
217971
218017
|
toolName: toolCall.name,
|
|
@@ -217982,7 +218028,7 @@ async function runModelToolLoop(input) {
|
|
|
217982
218028
|
});
|
|
217983
218029
|
}
|
|
217984
218030
|
const persistOption = autoRouterActive && lastAutoHopModelId ? getFounderModelOption(lastAutoHopModelId) ?? option : option;
|
|
217985
|
-
if (persistToolCall && !isSyntheticReadSuppressionExecution(execution)) {
|
|
218031
|
+
if (persistToolCall && !isSyntheticReadSuppressionExecution(execution) && !isToolBudgetSuppressed) {
|
|
217986
218032
|
await persistToolCall({
|
|
217987
218033
|
toolName: execution.toolName,
|
|
217988
218034
|
toolCallId: execution.toolCallId,
|
|
@@ -219469,7 +219515,7 @@ ${contextBlock}
|
|
|
219469
219515
|
return;
|
|
219470
219516
|
}
|
|
219471
219517
|
if (event.type === "diagnostic") {
|
|
219472
|
-
ctx.onEvent(event);
|
|
219518
|
+
ctx.onEvent({ ...event, workerId: args.workerId });
|
|
219473
219519
|
return;
|
|
219474
219520
|
}
|
|
219475
219521
|
if (event.type === "model_call_failed") {
|
|
@@ -220309,7 +220355,7 @@ function flockCaps() {
|
|
|
220309
220355
|
function resolveFlockWriteWorkerCap(input) {
|
|
220310
220356
|
return input.permissionMode === "take_the_wheel" && input.planJustifiesMoreWriters ? FLOCK_MAX_WRITE_WORKERS_TAKE_THE_WHEEL : FLOCK_MAX_WRITE_WORKERS;
|
|
220311
220357
|
}
|
|
220312
|
-
var FLOCK_MIN_WORKERS, FLOCK_MAX_WORKERS, FLOCK_PREFERRED_WORKERS, FLOCK_DEFAULT_WALL_MS, FLOCK_MAX_WALL_MS, FLOCK_MAX_TOTAL_TOOL_CALLS, FLOCK_MAX_WORKER_ITERATIONS, FLOCK_MAX_WRITE_WORKERS, FLOCK_MAX_WRITE_WORKERS_TAKE_THE_WHEEL, FLOCK_MIN_TASK_CHARS, FLOCK_MIN_TASK_WORDS, FLOCK_MAX_TASK_CHARS;
|
|
220358
|
+
var FLOCK_MIN_WORKERS, FLOCK_MAX_WORKERS, FLOCK_PREFERRED_WORKERS, FLOCK_DEFAULT_WALL_MS, FLOCK_MAX_WALL_MS, FLOCK_MAX_TOTAL_TOOL_CALLS, FLOCK_MIN_WORKER_TOOL_CALLS, FLOCK_MAX_WORKER_TOOL_CALLS, FLOCK_MAX_WORKER_ITERATIONS, FLOCK_MAX_WRITE_WORKERS, FLOCK_MAX_WRITE_WORKERS_TAKE_THE_WHEEL, FLOCK_MIN_TASK_CHARS, FLOCK_MIN_TASK_WORDS, FLOCK_MAX_TASK_CHARS;
|
|
220313
220359
|
var init_flockLimits = __esm({
|
|
220314
220360
|
"features/perchTerminal/runtime/flock/flockLimits.ts"() {
|
|
220315
220361
|
"use strict";
|
|
@@ -220319,7 +220365,9 @@ var init_flockLimits = __esm({
|
|
|
220319
220365
|
FLOCK_PREFERRED_WORKERS = { min: 3, max: 6 };
|
|
220320
220366
|
FLOCK_DEFAULT_WALL_MS = 8 * 6e4;
|
|
220321
220367
|
FLOCK_MAX_WALL_MS = 10 * 6e4;
|
|
220322
|
-
FLOCK_MAX_TOTAL_TOOL_CALLS =
|
|
220368
|
+
FLOCK_MAX_TOTAL_TOOL_CALLS = 160;
|
|
220369
|
+
FLOCK_MIN_WORKER_TOOL_CALLS = 12;
|
|
220370
|
+
FLOCK_MAX_WORKER_TOOL_CALLS = 40;
|
|
220323
220371
|
FLOCK_MAX_WORKER_ITERATIONS = Math.min(10, MAX_WORKER_ITERATIONS);
|
|
220324
220372
|
FLOCK_MAX_WRITE_WORKERS = 2;
|
|
220325
220373
|
FLOCK_MAX_WRITE_WORKERS_TAKE_THE_WHEEL = 4;
|
|
@@ -220329,6 +220377,118 @@ var init_flockLimits = __esm({
|
|
|
220329
220377
|
}
|
|
220330
220378
|
});
|
|
220331
220379
|
|
|
220380
|
+
// features/perchTerminal/runtime/flock/flockModelHints.ts
|
|
220381
|
+
function parseFlockModelHints(task) {
|
|
220382
|
+
const hints = [];
|
|
220383
|
+
const seen = /* @__PURE__ */ new Set();
|
|
220384
|
+
const push2 = (modelText, roleText, explicit) => {
|
|
220385
|
+
const model = modelText.trim().replace(/\s+/g, " ");
|
|
220386
|
+
const role = roleText.trim().toLowerCase();
|
|
220387
|
+
if (!model || !(role in ROLE_WORD_MAP)) return;
|
|
220388
|
+
const key = `${model.toLowerCase()}\u2192${role}`;
|
|
220389
|
+
if (seen.has(key)) return;
|
|
220390
|
+
seen.add(key);
|
|
220391
|
+
hints.push({ modelText: model, roleText: role, explicit });
|
|
220392
|
+
};
|
|
220393
|
+
const usePattern = new RegExp(
|
|
220394
|
+
`\\buse\\s+([A-Za-z0-9][A-Za-z0-9 ._/-]{0,30}?)\\s+(?:as|for)\\s+(?:an?\\s+|the\\s+)?(${ROLE_WORDS})\\b`,
|
|
220395
|
+
"gi"
|
|
220396
|
+
);
|
|
220397
|
+
for (const match of task.matchAll(usePattern)) {
|
|
220398
|
+
push2(match[1], match[2], true);
|
|
220399
|
+
}
|
|
220400
|
+
const pairPattern = new RegExp(
|
|
220401
|
+
`\\b([A-Z][A-Za-z0-9._-]{1,24})\\s+(${ROLE_WORDS})\\b`,
|
|
220402
|
+
"g"
|
|
220403
|
+
);
|
|
220404
|
+
for (const match of task.matchAll(pairPattern)) {
|
|
220405
|
+
if (/^(use|using|the|a|an|as|and|with|for)$/i.test(match[1])) continue;
|
|
220406
|
+
push2(match[1], match[2], false);
|
|
220407
|
+
}
|
|
220408
|
+
return hints;
|
|
220409
|
+
}
|
|
220410
|
+
function resolveFlockModelOption(modelText) {
|
|
220411
|
+
const needle = modelText.trim().toLowerCase();
|
|
220412
|
+
if (needle.length < 2) return null;
|
|
220413
|
+
const usable = FOUNDER_MODEL_OPTIONS.filter(
|
|
220414
|
+
(option) => isOptionAllowedForLane(option, "fast_worker") || isOptionAllowedForLane(option, "code_worker") || isOptionAllowedForLane(option, "verifier")
|
|
220415
|
+
);
|
|
220416
|
+
const haystacks = (option) => [option.label, option.vendor ?? "", option.family ?? "", option.modelId, option.id].join(" ").toLowerCase();
|
|
220417
|
+
const ranked = [...usable].sort(
|
|
220418
|
+
(a, b2) => Number(b2.userFacing === true) - Number(a.userFacing === true)
|
|
220419
|
+
);
|
|
220420
|
+
return ranked.find((option) => haystacks(option).includes(needle)) ?? null;
|
|
220421
|
+
}
|
|
220422
|
+
function applyFlockModelOverrides(plan, task) {
|
|
220423
|
+
const report = { applied: [], unavailable: [] };
|
|
220424
|
+
const hints = parseFlockModelHints(task);
|
|
220425
|
+
for (const hint of hints) {
|
|
220426
|
+
const option = resolveFlockModelOption(hint.modelText);
|
|
220427
|
+
if (!option) {
|
|
220428
|
+
if (hint.explicit) report.unavailable.push(hint);
|
|
220429
|
+
continue;
|
|
220430
|
+
}
|
|
220431
|
+
const roles = new Set(ROLE_WORD_MAP[hint.roleText] ?? []);
|
|
220432
|
+
const targets = plan.workers.filter(
|
|
220433
|
+
(worker) => roles.has(worker.role) || worker.displayName.toLowerCase().includes(hint.roleText)
|
|
220434
|
+
);
|
|
220435
|
+
if (targets.length === 0) continue;
|
|
220436
|
+
for (const worker of targets) {
|
|
220437
|
+
if (worker.modelOverride) continue;
|
|
220438
|
+
worker.modelOverride = { optionId: option.id, label: option.label };
|
|
220439
|
+
report.applied.push({
|
|
220440
|
+
flockWorkerId: worker.flockWorkerId,
|
|
220441
|
+
displayName: worker.displayName,
|
|
220442
|
+
modelText: hint.modelText,
|
|
220443
|
+
label: option.label
|
|
220444
|
+
});
|
|
220445
|
+
}
|
|
220446
|
+
}
|
|
220447
|
+
return report;
|
|
220448
|
+
}
|
|
220449
|
+
function founderSelectionWithModelOverride(base, optionId) {
|
|
220450
|
+
const selection = base ?? DEFAULT_FOUNDER_MODEL_SELECTION;
|
|
220451
|
+
return {
|
|
220452
|
+
...selection,
|
|
220453
|
+
chatModelId: optionId,
|
|
220454
|
+
supervisorModelId: optionId,
|
|
220455
|
+
fastWorkerModelId: optionId,
|
|
220456
|
+
codeWorkerModelId: optionId,
|
|
220457
|
+
dataWorkerModelId: optionId,
|
|
220458
|
+
writerModelId: optionId,
|
|
220459
|
+
verifierModelId: optionId
|
|
220460
|
+
};
|
|
220461
|
+
}
|
|
220462
|
+
var ROLE_WORD_MAP, ROLE_WORDS;
|
|
220463
|
+
var init_flockModelHints = __esm({
|
|
220464
|
+
"features/perchTerminal/runtime/flock/flockModelHints.ts"() {
|
|
220465
|
+
"use strict";
|
|
220466
|
+
init_modelRegistry();
|
|
220467
|
+
ROLE_WORD_MAP = {
|
|
220468
|
+
scout: ["scout"],
|
|
220469
|
+
scouts: ["scout"],
|
|
220470
|
+
explorer: ["scout"],
|
|
220471
|
+
worker: ["worker"],
|
|
220472
|
+
workers: ["worker"],
|
|
220473
|
+
coder: ["worker"],
|
|
220474
|
+
patcher: ["worker"],
|
|
220475
|
+
builder: ["worker"],
|
|
220476
|
+
reviewer: ["verifier", "reducer"],
|
|
220477
|
+
reviewers: ["verifier", "reducer"],
|
|
220478
|
+
verifier: ["verifier"],
|
|
220479
|
+
verifiers: ["verifier"],
|
|
220480
|
+
tester: ["verifier"],
|
|
220481
|
+
checker: ["verifier"],
|
|
220482
|
+
reducer: ["reducer"],
|
|
220483
|
+
synthesizer: ["reducer"],
|
|
220484
|
+
synthesiser: ["reducer"],
|
|
220485
|
+
synth: ["reducer"],
|
|
220486
|
+
summarizer: ["reducer"]
|
|
220487
|
+
};
|
|
220488
|
+
ROLE_WORDS = Object.keys(ROLE_WORD_MAP).join("|");
|
|
220489
|
+
}
|
|
220490
|
+
});
|
|
220491
|
+
|
|
220332
220492
|
// features/perchTerminal/runtime/flock/flockNicknames.ts
|
|
220333
220493
|
function seedFromFlockId(flockId) {
|
|
220334
220494
|
let hash = 2166136261;
|
|
@@ -220622,6 +220782,7 @@ function buildPlanWorker(spec, index, flockId, task, writeScope, caps) {
|
|
|
220622
220782
|
writeScope: spec.writesWorkspace ? writeScope : null,
|
|
220623
220783
|
outputContract: spec.outputContract,
|
|
220624
220784
|
dependsOn: [],
|
|
220785
|
+
modelOverride: null,
|
|
220625
220786
|
dynamicManifest: null
|
|
220626
220787
|
};
|
|
220627
220788
|
}
|
|
@@ -220685,7 +220846,7 @@ function buildFlockPlannerPrompts(ctx) {
|
|
|
220685
220846
|
"- allowedTools: choose ONLY from availableTools in the input. Never request orchestration or delegation tools.",
|
|
220686
220847
|
`- At most ${writeCap} workers with writesWorkspace=true; each writer needs a disjoint, clearly scoped responsibility, and writeJustification is required for more than ${resolveFlockWriteWorkerCap({ permissionMode: null, planJustifiesMoreWriters: false })}.`,
|
|
220687
220848
|
`- maxIterations: 1-${caps.maxIterationsPerWorker}.`,
|
|
220688
|
-
"- dependsOn: ids of earlier workers whose output this worker needs. No cycles.",
|
|
220849
|
+
"- dependsOn: ids of earlier workers whose output this worker needs. No cycles. You decide the graph: parallel where independent, chained where not. Final verifier/reducer workers usually benefit from depending on the workers they check \u2014 guidance, not a requirement.",
|
|
220689
220850
|
"- baseWorkerId: set ONLY to reuse an id from existingWorkers; otherwise null.",
|
|
220690
220851
|
"- Decline (accepted=false, with reason) tasks that are trivial, conversational, or need no fanout."
|
|
220691
220852
|
].join("\n");
|
|
@@ -220814,6 +220975,8 @@ function validateLlmFlockPlan(record, ctx) {
|
|
|
220814
220975
|
outputContract,
|
|
220815
220976
|
dependsOn: [],
|
|
220816
220977
|
// resolved below once all ids are known
|
|
220978
|
+
modelOverride: null,
|
|
220979
|
+
// applied later from explicit task hints only
|
|
220817
220980
|
dynamicManifest: reusedManifest ? null : buildDynamicManifest({
|
|
220818
220981
|
workerId: dynamicWorkerId,
|
|
220819
220982
|
displayName,
|
|
@@ -221024,6 +221187,13 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
221024
221187
|
flockId
|
|
221025
221188
|
});
|
|
221026
221189
|
}
|
|
221190
|
+
if (plan.accepted && typeof options.totalToolCallBudget === "number") {
|
|
221191
|
+
plan.caps.maxTotalToolCalls = Math.max(
|
|
221192
|
+
1,
|
|
221193
|
+
Math.min(Math.floor(options.totalToolCallBudget), plan.caps.maxTotalToolCalls)
|
|
221194
|
+
);
|
|
221195
|
+
}
|
|
221196
|
+
const modelOverrides = plan.accepted ? applyFlockModelOverrides(plan, task) : { applied: [], unavailable: [] };
|
|
221027
221197
|
emitPlanEvent(emit, plan);
|
|
221028
221198
|
if (!plan.accepted) {
|
|
221029
221199
|
emit({
|
|
@@ -221070,9 +221240,12 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
221070
221240
|
const sharedContext = { task };
|
|
221071
221241
|
let toolCallsUsed = 0;
|
|
221072
221242
|
let toolCallsReserved = 0;
|
|
221243
|
+
let workersAwaitingLaunch = plan.workers.length;
|
|
221073
221244
|
try {
|
|
221074
221245
|
const phases = [...new Set(plan.workers.map((worker) => FLOCK_ROLE_ORDER[worker.role]))].sort((a, b2) => a - b2);
|
|
221075
221246
|
const runReadyWorker = async (worker) => {
|
|
221247
|
+
const workersLeftIncludingThis = Math.max(1, workersAwaitingLaunch);
|
|
221248
|
+
workersAwaitingLaunch = Math.max(0, workersAwaitingLaunch - 1);
|
|
221076
221249
|
if (flockRun.controller.signal.aborted) {
|
|
221077
221250
|
const outcome = {
|
|
221078
221251
|
worker,
|
|
@@ -221094,9 +221267,13 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
221094
221267
|
emitWorkerUpdate(emit, plan, worker, "skipped", outcome.detail);
|
|
221095
221268
|
return outcome;
|
|
221096
221269
|
}
|
|
221097
|
-
const
|
|
221098
|
-
|
|
221099
|
-
|
|
221270
|
+
const fairShare = Math.floor(remainingToolCalls / workersLeftIncludingThis);
|
|
221271
|
+
const reservedToolCalls = Math.min(
|
|
221272
|
+
remainingToolCalls,
|
|
221273
|
+
Math.max(
|
|
221274
|
+
FLOCK_MIN_WORKER_TOOL_CALLS,
|
|
221275
|
+
Math.min(FLOCK_MAX_WORKER_TOOL_CALLS, fairShare)
|
|
221276
|
+
)
|
|
221100
221277
|
);
|
|
221101
221278
|
toolCallsReserved += reservedToolCalls;
|
|
221102
221279
|
emitWorkerUpdate(emit, plan, worker, "running");
|
|
@@ -221109,7 +221286,7 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
221109
221286
|
maxIterations: worker.maxIterations,
|
|
221110
221287
|
maxToolCalls: reservedToolCalls
|
|
221111
221288
|
},
|
|
221112
|
-
buildSpawnContext(input, plan.flockId, flockRun.controller.signal, emit)
|
|
221289
|
+
buildSpawnContext(input, plan.flockId, flockRun.controller.signal, emit, worker)
|
|
221113
221290
|
);
|
|
221114
221291
|
toolCallsReserved -= reservedToolCalls;
|
|
221115
221292
|
toolCallsUsed += Math.min(result2.toolCalls ?? 0, reservedToolCalls);
|
|
@@ -221183,7 +221360,15 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
221183
221360
|
const workersDone = outcomes.filter((outcome) => outcome.status === "done").length;
|
|
221184
221361
|
const workersFailed = outcomes.filter((outcome) => outcome.status === "failed").length;
|
|
221185
221362
|
const flockStatus = userCancelled || wallTimeHit && workersDone === 0 ? "cancelled" : workersFailed === 0 && workersDone === plan.workers.length ? "completed" : workersDone > 0 ? "partial" : "failed";
|
|
221186
|
-
const assistantText =
|
|
221363
|
+
const assistantText = [
|
|
221364
|
+
buildFlockSummary(plan, outcomes, flockStatus, toolCallsUsed, wallTimeHit),
|
|
221365
|
+
...modelOverrides.applied.map(
|
|
221366
|
+
(override) => `Model override: ${override.displayName} ran on ${override.label}.`
|
|
221367
|
+
),
|
|
221368
|
+
...modelOverrides.unavailable.map(
|
|
221369
|
+
(override) => `Requested model "${override.modelText}"${override.roleText ? ` for ${override.roleText}` : ""} is not available \u2014 that worker stayed on the default model path.`
|
|
221370
|
+
)
|
|
221371
|
+
].join("\n");
|
|
221187
221372
|
emit({
|
|
221188
221373
|
type: "flock_run_completed",
|
|
221189
221374
|
flockId: plan.flockId,
|
|
@@ -221234,7 +221419,8 @@ function emitPlanEvent(emit, plan) {
|
|
|
221234
221419
|
maxIterations: worker.maxIterations,
|
|
221235
221420
|
allowedTools: worker.allowedTools,
|
|
221236
221421
|
writeScope: worker.writeScope,
|
|
221237
|
-
outputContract: worker.outputContract
|
|
221422
|
+
outputContract: worker.outputContract,
|
|
221423
|
+
modelOverride: worker.modelOverride?.label ?? null
|
|
221238
221424
|
})) : [],
|
|
221239
221425
|
caps: plan.accepted ? plan.caps : { maxWorkers: 0, maxWallMs: 0, maxTotalToolCalls: 0, maxIterationsPerWorker: 0 },
|
|
221240
221426
|
ts: now6()
|
|
@@ -221264,7 +221450,7 @@ function buildWorkerContext(worker, sharedContext, outputByFlockWorkerId, plan)
|
|
|
221264
221450
|
}
|
|
221265
221451
|
return { task: sharedContext.task, dependencies };
|
|
221266
221452
|
}
|
|
221267
|
-
function buildSpawnContext(input, flockId, signal, emit) {
|
|
221453
|
+
function buildSpawnContext(input, flockId, signal, emit, worker) {
|
|
221268
221454
|
return {
|
|
221269
221455
|
workspaceRoot: input.activeRootPath ?? "",
|
|
221270
221456
|
desktopConnected: input.desktopConnected,
|
|
@@ -221277,7 +221463,12 @@ function buildSpawnContext(input, flockId, signal, emit) {
|
|
|
221277
221463
|
supabaseConfigured: input.supabaseConfigured,
|
|
221278
221464
|
supabase: input.supabase ?? null,
|
|
221279
221465
|
runId: flockId,
|
|
221280
|
-
|
|
221466
|
+
// Default: the currently selected Perch model path. Only an explicit
|
|
221467
|
+
// "use <model> as <role>" request in the task pins this worker elsewhere.
|
|
221468
|
+
founderModelSelection: worker.modelOverride ? founderSelectionWithModelOverride(
|
|
221469
|
+
input.founderModelSelection ?? null,
|
|
221470
|
+
worker.modelOverride.optionId
|
|
221471
|
+
) : input.founderModelSelection ?? null,
|
|
221281
221472
|
onEvent: emit,
|
|
221282
221473
|
signal,
|
|
221283
221474
|
mcpTools: input.mcpTools ?? []
|
|
@@ -221312,6 +221503,7 @@ var init_runFlockTurn = __esm({
|
|
|
221312
221503
|
init_registry();
|
|
221313
221504
|
init_flockCommand();
|
|
221314
221505
|
init_flockLimits();
|
|
221506
|
+
init_flockModelHints();
|
|
221315
221507
|
init_flockLlmPlanner();
|
|
221316
221508
|
init_flockPlanner();
|
|
221317
221509
|
init_flockRoles();
|
|
@@ -285013,10 +285205,12 @@ var init_build2 = __esm({
|
|
|
285013
285205
|
// scripts/perch-cli.ts
|
|
285014
285206
|
var perch_cli_exports = {};
|
|
285015
285207
|
__export(perch_cli_exports, {
|
|
285208
|
+
FLOCK_NAME_ACCENTS: () => FLOCK_NAME_ACCENTS,
|
|
285016
285209
|
HELP_TEXT: () => HELP_TEXT,
|
|
285017
285210
|
INTERACTIVE_HELP_TEXT: () => INTERACTIVE_HELP_TEXT,
|
|
285018
285211
|
PERCH_SPLASH_COMMANDS: () => PERCH_SPLASH_COMMANDS,
|
|
285019
285212
|
flockEventToCliRow: () => flockEventToCliRow,
|
|
285213
|
+
flockNameAccentColor: () => flockNameAccentColor,
|
|
285020
285214
|
parseInteractiveSlashCommand: () => parseInteractiveSlashCommand,
|
|
285021
285215
|
parsePerchCli: () => parsePerchCli,
|
|
285022
285216
|
runPerchCli: () => runPerchCli
|
|
@@ -285648,6 +285842,8 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
285648
285842
|
setLiveText("");
|
|
285649
285843
|
liveTextRef.current = "";
|
|
285650
285844
|
const toolNamesById = /* @__PURE__ */ new Map();
|
|
285845
|
+
const flockWorkerNames = /* @__PURE__ */ new Map();
|
|
285846
|
+
const flockLimitMeta = /* @__PURE__ */ new Map();
|
|
285651
285847
|
const clientRunId = createCliRunId();
|
|
285652
285848
|
const externalController = new AbortController();
|
|
285653
285849
|
const runtimeRun = registerRuntimeRun({
|
|
@@ -285939,10 +286135,40 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
285939
286135
|
case "executor_waiting_for_user":
|
|
285940
286136
|
addItem({ label: "wait", text: event.prompt, tone: "muted" });
|
|
285941
286137
|
break;
|
|
286138
|
+
case "diagnostic": {
|
|
286139
|
+
if (event.code !== "tool_call_budget_exhausted") break;
|
|
286140
|
+
const limitKey = `limit-${event.workerId ?? "turn"}`;
|
|
286141
|
+
const meta2 = flockLimitMeta.get(limitKey) ?? { skipped: 0, tools: /* @__PURE__ */ new Set() };
|
|
286142
|
+
meta2.skipped += event.skippedCount ?? 0;
|
|
286143
|
+
for (const toolName of event.toolNames ?? []) meta2.tools.add(toolName);
|
|
286144
|
+
flockLimitMeta.set(limitKey, meta2);
|
|
286145
|
+
const who = event.workerId ? flockWorkerNames.get(event.workerId) ?? "A worker" : "The model";
|
|
286146
|
+
updateToolItem(limitKey, {
|
|
286147
|
+
label: "flock",
|
|
286148
|
+
text: `${who} hit its tool limit and is finishing from gathered evidence.`,
|
|
286149
|
+
tone: "muted",
|
|
286150
|
+
detailLines: [
|
|
286151
|
+
{ tone: "meta", text: `cap tool-call budget \xB7 ${event.maxToolCalls ?? "?"} real calls allowed` },
|
|
286152
|
+
{
|
|
286153
|
+
tone: "meta",
|
|
286154
|
+
text: `skipped ${meta2.skipped} call(s)${meta2.tools.size ? `: ${[...meta2.tools].join(", ")}` : ""}`
|
|
286155
|
+
}
|
|
286156
|
+
],
|
|
286157
|
+
expanded: false
|
|
286158
|
+
});
|
|
286159
|
+
break;
|
|
286160
|
+
}
|
|
285942
286161
|
case "flock_run_started":
|
|
285943
286162
|
case "flock_plan_ready":
|
|
285944
286163
|
case "flock_worker_update":
|
|
285945
286164
|
case "flock_run_completed": {
|
|
286165
|
+
if (event.type === "flock_plan_ready" && event.accepted) {
|
|
286166
|
+
for (const worker of event.workers) {
|
|
286167
|
+
flockWorkerNames.set(worker.workerId, worker.displayName);
|
|
286168
|
+
}
|
|
286169
|
+
} else if (event.type === "flock_worker_update") {
|
|
286170
|
+
flockWorkerNames.set(event.workerId, event.displayName);
|
|
286171
|
+
}
|
|
285946
286172
|
const row = flockEventToCliRow(event);
|
|
285947
286173
|
if (!row) break;
|
|
285948
286174
|
if (row.id) {
|
|
@@ -286102,6 +286328,38 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
286102
286328
|
renderInkDetailContent(React11, Ink2, line)
|
|
286103
286329
|
)
|
|
286104
286330
|
);
|
|
286331
|
+
const renderFlockRow = (key, line, tone, showLabel) => {
|
|
286332
|
+
const dotParts = line.split(" \xB7 ");
|
|
286333
|
+
const limitMatch = dotParts.length < 2 ? line.match(/^(.+?) (hit its tool limit .*)$/) : null;
|
|
286334
|
+
if (dotParts.length < 2 && !limitMatch) {
|
|
286335
|
+
return renderTranscriptRow(key, "flock", line, tone, showLabel);
|
|
286336
|
+
}
|
|
286337
|
+
const name = limitMatch ? limitMatch[1] : dotParts[0];
|
|
286338
|
+
const restText = limitMatch ? ` ${limitMatch[2]}` : ` \xB7 ${dotParts.slice(1).join(" \xB7 ")}`;
|
|
286339
|
+
return React11.createElement(
|
|
286340
|
+
Ink2.Box,
|
|
286341
|
+
{ key },
|
|
286342
|
+
React11.createElement(
|
|
286343
|
+
Ink2.Box,
|
|
286344
|
+
{ width: INK_LABEL_WIDTH, flexShrink: 0 },
|
|
286345
|
+
React11.createElement(
|
|
286346
|
+
Ink2.Text,
|
|
286347
|
+
{ color: colorForInkTone(tone) },
|
|
286348
|
+
showLabel ? renderInkSpeakerLabel("flock") : ""
|
|
286349
|
+
)
|
|
286350
|
+
),
|
|
286351
|
+
React11.createElement(
|
|
286352
|
+
Ink2.Box,
|
|
286353
|
+
{ flexGrow: 1 },
|
|
286354
|
+
React11.createElement(
|
|
286355
|
+
Ink2.Text,
|
|
286356
|
+
null,
|
|
286357
|
+
React11.createElement(Ink2.Text, { color: flockNameAccentColor(name), bold: true }, name),
|
|
286358
|
+
React11.createElement(Ink2.Text, { color: bodyColorForInkTone(tone) }, restText)
|
|
286359
|
+
)
|
|
286360
|
+
)
|
|
286361
|
+
);
|
|
286362
|
+
};
|
|
286105
286363
|
const renderTranscriptItem = (item, index) => {
|
|
286106
286364
|
const lines = item.text.split(/\r?\n/);
|
|
286107
286365
|
const previous = items[index - 1];
|
|
@@ -286115,7 +286373,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
286115
286373
|
React11.createElement(Ink2.Box, { width: INK_LABEL_WIDTH, flexShrink: 0 }),
|
|
286116
286374
|
React11.createElement(Ink2.Text, { color: CLI_BRAND.divider }, INK_DIVIDER)
|
|
286117
286375
|
) : null,
|
|
286118
|
-
lines.map((line, lineIndex) => renderTranscriptRow(
|
|
286376
|
+
lines.map((line, lineIndex) => item.label === "flock" ? renderFlockRow(`${item.id}-${lineIndex}`, line, item.tone, lineIndex === 0) : renderTranscriptRow(
|
|
286119
286377
|
`${item.id}-${lineIndex}`,
|
|
286120
286378
|
item.label,
|
|
286121
286379
|
line,
|
|
@@ -286851,6 +287109,13 @@ function colorForInkTone(tone) {
|
|
|
286851
287109
|
return CLI_BRAND.patina;
|
|
286852
287110
|
}
|
|
286853
287111
|
}
|
|
287112
|
+
function flockNameAccentColor(name) {
|
|
287113
|
+
let hash = 0;
|
|
287114
|
+
for (let i = 0; i < name.length; i++) {
|
|
287115
|
+
hash = hash * 31 + name.charCodeAt(i) >>> 0;
|
|
287116
|
+
}
|
|
287117
|
+
return FLOCK_NAME_ACCENTS[hash % FLOCK_NAME_ACCENTS.length];
|
|
287118
|
+
}
|
|
286854
287119
|
function bodyColorForInkTone(tone) {
|
|
286855
287120
|
switch (tone) {
|
|
286856
287121
|
case "danger":
|
|
@@ -287533,7 +287798,7 @@ function defaultWriter() {
|
|
|
287533
287798
|
stderr: (text) => process.stderr.write(text)
|
|
287534
287799
|
};
|
|
287535
287800
|
}
|
|
287536
|
-
var execFileAsync3, DEFAULT_CLI_LOGIN_APP_URL, CLI_PACKAGE_VERSION, CLI_BRAND, ANSI2, HELP_TEXT, INTERACTIVE_HELP_TEXT, FLOCK_STATUS_LABELS, INK_LABEL_WIDTH, INK_ROW_LIMIT, INK_DETAIL_LINE_LIMIT, INK_DIVIDER, PERCH_MOTION_FRAMES, PERCH_SPLASH_WIDTH, PERCH_SPLASH_SCENE, PERCH_SPLASH_COMMANDS;
|
|
287801
|
+
var execFileAsync3, DEFAULT_CLI_LOGIN_APP_URL, CLI_PACKAGE_VERSION, CLI_BRAND, ANSI2, HELP_TEXT, INTERACTIVE_HELP_TEXT, FLOCK_STATUS_LABELS, INK_LABEL_WIDTH, INK_ROW_LIMIT, INK_DETAIL_LINE_LIMIT, INK_DIVIDER, PERCH_MOTION_FRAMES, PERCH_SPLASH_WIDTH, PERCH_SPLASH_SCENE, PERCH_SPLASH_COMMANDS, FLOCK_NAME_ACCENTS;
|
|
287537
287802
|
var init_perch_cli = __esm({
|
|
287538
287803
|
"scripts/perch-cli.ts"() {
|
|
287539
287804
|
"use strict";
|
|
@@ -287669,6 +287934,11 @@ Commands:
|
|
|
287669
287934
|
["/permission", "change autonomy for the next turns"],
|
|
287670
287935
|
["/login", "connect your Perch account"]
|
|
287671
287936
|
];
|
|
287937
|
+
FLOCK_NAME_ACCENTS = [
|
|
287938
|
+
CLI_BRAND.patinaActive,
|
|
287939
|
+
CLI_BRAND.bronze,
|
|
287940
|
+
CLI_BRAND.bronzeGlint
|
|
287941
|
+
];
|
|
287672
287942
|
if (!process.env.PERCH_CLI_BUNDLE_ENTRY && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
287673
287943
|
runPerchCli(process.argv.slice(2)).then((code) => {
|
|
287674
287944
|
process.exitCode = code;
|