perchai-cli 2.4.32 → 2.4.34
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 +598 -90
- package/package.json +1 -1
package/dist/perch.mjs
CHANGED
|
@@ -76219,6 +76219,7 @@ function getToolDisplayName(toolName) {
|
|
|
76219
76219
|
var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
|
|
76220
76220
|
var init_catalog = __esm({
|
|
76221
76221
|
"features/perchTerminal/runtime/toolSystem/catalog.ts"() {
|
|
76222
|
+
"use strict";
|
|
76222
76223
|
init_toolNames();
|
|
76223
76224
|
NON_MODULE_TOOL_OWNERS = {
|
|
76224
76225
|
[TOOL_NAMES.listSources]: "lane",
|
|
@@ -83126,7 +83127,6 @@ function listFinancialRoleIds() {
|
|
|
83126
83127
|
var FINANCIAL_ROLE_REGISTRY, evidenceScoutManifest;
|
|
83127
83128
|
var init_financialRoles = __esm({
|
|
83128
83129
|
"features/perchTerminal/agentPlatform/financialRoles.ts"() {
|
|
83129
|
-
"use strict";
|
|
83130
83130
|
FINANCIAL_ROLE_REGISTRY = /* @__PURE__ */ new Map();
|
|
83131
83131
|
evidenceScoutManifest = {
|
|
83132
83132
|
workerId: "evidence_scout",
|
|
@@ -86724,6 +86724,7 @@ function truncateHistoryLine(value, max2) {
|
|
|
86724
86724
|
}
|
|
86725
86725
|
var init_operatorTruth = __esm({
|
|
86726
86726
|
"features/perchTerminal/runtime/operatorTruth.ts"() {
|
|
86727
|
+
"use strict";
|
|
86727
86728
|
}
|
|
86728
86729
|
});
|
|
86729
86730
|
|
|
@@ -91010,7 +91011,6 @@ Final answers lead with findings, name artifacts or delivery status, and give on
|
|
|
91010
91011
|
var MARKET_DESK_TOOL_NAMES;
|
|
91011
91012
|
var init_marketDeskAccess = __esm({
|
|
91012
91013
|
"features/perchTerminal/runtime/marketDesk/marketDeskAccess.ts"() {
|
|
91013
|
-
"use strict";
|
|
91014
91014
|
init_toolNames();
|
|
91015
91015
|
MARKET_DESK_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
91016
91016
|
TOOL_NAMES.getMarketSignal,
|
|
@@ -135930,13 +135930,38 @@ function getDesktopToolDefinitions() {
|
|
|
135930
135930
|
type: "function",
|
|
135931
135931
|
function: {
|
|
135932
135932
|
name: TOOL_NAMES.spawnWorker,
|
|
135933
|
-
description: "Spawn one bounded specialist sub-agent. Use simple capability-shaped workers when possible: source_reader for scoped local-file evidence, math_checker for exact sandbox totals/reconciliation, contradiction_verifier for conflict checks, financial_writer/general_writer for narrative from provided facts. Best for independent work where the main loop only needs the conclusion. Do not use context-only managed analysts as raw-folder readers; give them pre-read JSON. The main loop remains owner of decisions, writing, and real actions. Prefer dispatch_agent for parallel batches. Do not repeat source_reader after it returns a DONE/PARTIAL manifest; advance to math_checker or verification.",
|
|
135933
|
+
description: "Spawn one bounded specialist sub-agent. Use simple capability-shaped workers when possible: source_reader for scoped local-file evidence, math_checker for exact sandbox totals/reconciliation, contradiction_verifier for conflict checks, financial_writer/general_writer for narrative from provided facts. When no registered worker fits, pass custom{} instead of workerId to spawn a one-off ad-hoc worker with its own name and minimal tool scope. Best for independent work where the main loop only needs the conclusion. Do not use context-only managed analysts as raw-folder readers; give them pre-read JSON. The main loop remains owner of decisions, writing, and real actions. Prefer dispatch_agent for parallel batches. Do not repeat source_reader after it returns a DONE/PARTIAL manifest; advance to math_checker or verification.",
|
|
135934
135934
|
parameters: {
|
|
135935
135935
|
type: "object",
|
|
135936
135936
|
properties: {
|
|
135937
135937
|
workerId: {
|
|
135938
135938
|
type: "string",
|
|
135939
|
-
description: "Registered worker or role id. Simple roles: source_reader, math_checker, contradiction_verifier, financial_writer, general_writer. Quill roles: legal_source_scout, legal_case_scout, source_verifier, doc_writer, email_sender, calendar_scheduler."
|
|
135939
|
+
description: "Registered worker or role id. Simple roles: source_reader, math_checker, contradiction_verifier, financial_writer, general_writer. Quill roles: legal_source_scout, legal_case_scout, source_verifier, doc_writer, email_sender, calendar_scheduler. Omit when passing custom."
|
|
135940
|
+
},
|
|
135941
|
+
custom: {
|
|
135942
|
+
type: "object",
|
|
135943
|
+
description: "Inline ad-hoc worker spec, used INSTEAD of workerId when no registered worker fits. The worker is run-scoped: registered for this spawn, unregistered after. Orchestration tools are never granted; write tools require writesWorkspace=true.",
|
|
135944
|
+
properties: {
|
|
135945
|
+
displayName: {
|
|
135946
|
+
type: "string",
|
|
135947
|
+
description: 'Short task-specific role name, e.g. "Changelog Summarizer".'
|
|
135948
|
+
},
|
|
135949
|
+
allowedTools: {
|
|
135950
|
+
type: "array",
|
|
135951
|
+
items: { type: "string" },
|
|
135952
|
+
description: "Minimal tool names this worker needs. Unknown/forbidden tools are dropped."
|
|
135953
|
+
},
|
|
135954
|
+
writesWorkspace: {
|
|
135955
|
+
type: "boolean",
|
|
135956
|
+
description: "True only if the worker must edit files inside the workspace root."
|
|
135957
|
+
},
|
|
135958
|
+
outputContract: {
|
|
135959
|
+
type: "string",
|
|
135960
|
+
description: "Short contract for the worker's structured output."
|
|
135961
|
+
}
|
|
135962
|
+
},
|
|
135963
|
+
required: ["displayName"],
|
|
135964
|
+
additionalProperties: false
|
|
135940
135965
|
},
|
|
135941
135966
|
objective: {
|
|
135942
135967
|
type: "string",
|
|
@@ -135965,7 +135990,7 @@ function getDesktopToolDefinitions() {
|
|
|
135965
135990
|
description: "Optional child loop cap. Defaults to the worker manifest cap."
|
|
135966
135991
|
}
|
|
135967
135992
|
},
|
|
135968
|
-
required: ["
|
|
135993
|
+
required: ["objective"],
|
|
135969
135994
|
additionalProperties: false
|
|
135970
135995
|
}
|
|
135971
135996
|
}
|
|
@@ -205268,7 +205293,159 @@ var init_sendWorkerMessage2 = __esm({
|
|
|
205268
205293
|
}
|
|
205269
205294
|
});
|
|
205270
205295
|
|
|
205296
|
+
// features/perchTerminal/runtime/workers/adhocManifest.ts
|
|
205297
|
+
function buildAdhocWorkerManifest(spec) {
|
|
205298
|
+
const displayName = spec.displayName.replace(/\s+/g, " ").trim().slice(0, MAX_NAME_CHARS) || "Ad-hoc Worker";
|
|
205299
|
+
const writesWorkspace = spec.writesWorkspace === true;
|
|
205300
|
+
const outputContract = (spec.outputContract ?? "").replace(/\s+/g, " ").trim().slice(0, MAX_CONTRACT_CHARS) || DEFAULT_OUTPUT_CONTRACT;
|
|
205301
|
+
const requested = [...new Set(spec.allowedTools ?? [])].filter(
|
|
205302
|
+
(tool) => typeof tool === "string" && tool.trim().length > 0
|
|
205303
|
+
);
|
|
205304
|
+
const droppedTools = [];
|
|
205305
|
+
const allowedTools = requested.filter((tool) => {
|
|
205306
|
+
if (ADHOC_FORBIDDEN_TOOLS.includes(tool)) {
|
|
205307
|
+
droppedTools.push(tool);
|
|
205308
|
+
return false;
|
|
205309
|
+
}
|
|
205310
|
+
if (!writesWorkspace && ADHOC_WRITE_TOOLS.has(tool)) {
|
|
205311
|
+
droppedTools.push(tool);
|
|
205312
|
+
return false;
|
|
205313
|
+
}
|
|
205314
|
+
return true;
|
|
205315
|
+
});
|
|
205316
|
+
const maxIterations = clampInt(spec.maxIterations, 1, ADHOC_MAX_ITERATIONS, 6);
|
|
205317
|
+
const workerId = uniqueAdhocWorkerId(displayName);
|
|
205318
|
+
const manifest = {
|
|
205319
|
+
workerId,
|
|
205320
|
+
name: displayName,
|
|
205321
|
+
description: `Ad-hoc worker (run-scoped): ${displayName}.`,
|
|
205322
|
+
lane: writesWorkspace ? "code_worker" : "fast_worker",
|
|
205323
|
+
systemPrompt: [
|
|
205324
|
+
`You are ${displayName}, one bounded ad-hoc worker spawned for a single objective.`,
|
|
205325
|
+
"Work only on the objective you are given. Never delegate, never spawn other workers, never start suites.",
|
|
205326
|
+
`Respect the output contract exactly: ${outputContract}.`,
|
|
205327
|
+
writesWorkspace ? "You may edit files, but only inside the active workspace root, and only edits the objective requires." : "You are read-only: never write, move, or delete files."
|
|
205328
|
+
].join("\n"),
|
|
205329
|
+
allowedTools,
|
|
205330
|
+
maxIterations,
|
|
205331
|
+
callableAgents: [],
|
|
205332
|
+
outputContract
|
|
205333
|
+
};
|
|
205334
|
+
return { manifest, droppedTools };
|
|
205335
|
+
}
|
|
205336
|
+
function uniqueAdhocWorkerId(displayName) {
|
|
205337
|
+
const slug = displayName.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 24) || "worker";
|
|
205338
|
+
const base = `adhoc_${Date.now().toString(36)}_${slug}`;
|
|
205339
|
+
let candidate = base;
|
|
205340
|
+
let bump = 0;
|
|
205341
|
+
while (getWorkerManifest(candidate)) {
|
|
205342
|
+
bump += 1;
|
|
205343
|
+
candidate = `${base}_${bump}`;
|
|
205344
|
+
}
|
|
205345
|
+
return candidate;
|
|
205346
|
+
}
|
|
205347
|
+
function clampInt(value, min2, max2, fallback) {
|
|
205348
|
+
const num = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
|
|
205349
|
+
return Math.min(Math.max(num, min2), max2);
|
|
205350
|
+
}
|
|
205351
|
+
var ADHOC_FORBIDDEN_TOOLS, ADHOC_WRITE_TOOLS, ADHOC_MAX_ITERATIONS, MAX_NAME_CHARS, MAX_CONTRACT_CHARS, DEFAULT_OUTPUT_CONTRACT;
|
|
205352
|
+
var init_adhocManifest = __esm({
|
|
205353
|
+
"features/perchTerminal/runtime/workers/adhocManifest.ts"() {
|
|
205354
|
+
"use strict";
|
|
205355
|
+
init_toolNames();
|
|
205356
|
+
init_registry();
|
|
205357
|
+
init_types();
|
|
205358
|
+
ADHOC_FORBIDDEN_TOOLS = [
|
|
205359
|
+
...WORKER_DISALLOWED_TOOLS,
|
|
205360
|
+
TOOL_NAMES.dispatchAgent,
|
|
205361
|
+
TOOL_NAMES.sendWorkerMessage,
|
|
205362
|
+
TOOL_NAMES.taskStop,
|
|
205363
|
+
TOOL_NAMES.runSuite,
|
|
205364
|
+
TOOL_NAMES.listSuiteCatalog,
|
|
205365
|
+
TOOL_NAMES.proposeSuitePlan,
|
|
205366
|
+
TOOL_NAMES.executeSuitePlan,
|
|
205367
|
+
TOOL_NAMES.proposeWork,
|
|
205368
|
+
TOOL_NAMES.executeWork,
|
|
205369
|
+
TOOL_NAMES.proposePlan
|
|
205370
|
+
];
|
|
205371
|
+
ADHOC_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
205372
|
+
TOOL_NAMES.writeLocalFile,
|
|
205373
|
+
TOOL_NAMES.editLocalFile,
|
|
205374
|
+
TOOL_NAMES.deleteLocalFile,
|
|
205375
|
+
TOOL_NAMES.moveLocalFile,
|
|
205376
|
+
TOOL_NAMES.copyLocalFile,
|
|
205377
|
+
TOOL_NAMES.createDirectory
|
|
205378
|
+
]);
|
|
205379
|
+
ADHOC_MAX_ITERATIONS = 10;
|
|
205380
|
+
MAX_NAME_CHARS = 40;
|
|
205381
|
+
MAX_CONTRACT_CHARS = 240;
|
|
205382
|
+
DEFAULT_OUTPUT_CONTRACT = "Return a short structured summary of what was found or done.";
|
|
205383
|
+
}
|
|
205384
|
+
});
|
|
205385
|
+
|
|
205386
|
+
// features/perchTerminal/runtime/flock/flockNicknames.ts
|
|
205387
|
+
function seedFromFlockId(flockId) {
|
|
205388
|
+
let hash = 2166136261;
|
|
205389
|
+
for (let i = 0; i < flockId.length; i++) {
|
|
205390
|
+
hash ^= flockId.charCodeAt(i);
|
|
205391
|
+
hash = Math.imul(hash, 16777619);
|
|
205392
|
+
}
|
|
205393
|
+
return hash >>> 0;
|
|
205394
|
+
}
|
|
205395
|
+
function flockNicknameRotation(flockId) {
|
|
205396
|
+
const names = [...FLOCK_NICKNAMES];
|
|
205397
|
+
let state = seedFromFlockId(flockId) || 1;
|
|
205398
|
+
const nextRandom = () => {
|
|
205399
|
+
state = Math.imul(state, 1664525) + 1013904223 >>> 0;
|
|
205400
|
+
return state / 4294967296;
|
|
205401
|
+
};
|
|
205402
|
+
for (let i = names.length - 1; i > 0; i--) {
|
|
205403
|
+
const j = Math.floor(nextRandom() * (i + 1));
|
|
205404
|
+
[names[i], names[j]] = [names[j], names[i]];
|
|
205405
|
+
}
|
|
205406
|
+
return names;
|
|
205407
|
+
}
|
|
205408
|
+
function flockNicknameFor(flockId, index) {
|
|
205409
|
+
const rotation = flockNicknameRotation(flockId);
|
|
205410
|
+
return rotation[index % rotation.length];
|
|
205411
|
+
}
|
|
205412
|
+
var FLOCK_NICKNAMES;
|
|
205413
|
+
var init_flockNicknames = __esm({
|
|
205414
|
+
"features/perchTerminal/runtime/flock/flockNicknames.ts"() {
|
|
205415
|
+
"use strict";
|
|
205416
|
+
FLOCK_NICKNAMES = [
|
|
205417
|
+
"Little Dum Dum",
|
|
205418
|
+
"Molly",
|
|
205419
|
+
"Boomer",
|
|
205420
|
+
"Shawarma",
|
|
205421
|
+
"Curie",
|
|
205422
|
+
"Eagle",
|
|
205423
|
+
"Noether",
|
|
205424
|
+
"Wonky",
|
|
205425
|
+
"Lovelace",
|
|
205426
|
+
"Bell",
|
|
205427
|
+
"Turing",
|
|
205428
|
+
"Faraday",
|
|
205429
|
+
"Biscuit",
|
|
205430
|
+
"Ice Cream",
|
|
205431
|
+
"Minsky"
|
|
205432
|
+
];
|
|
205433
|
+
}
|
|
205434
|
+
});
|
|
205435
|
+
|
|
205271
205436
|
// features/perchTerminal/runtime/toolSystem/tools/workers/spawnWorker.ts
|
|
205437
|
+
function parseAdhocSpec(raw) {
|
|
205438
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
205439
|
+
const record = raw;
|
|
205440
|
+
if (typeof record.displayName !== "string" || !record.displayName.trim()) return null;
|
|
205441
|
+
return {
|
|
205442
|
+
displayName: record.displayName,
|
|
205443
|
+
allowedTools: Array.isArray(record.allowedTools) ? record.allowedTools.filter((tool) => typeof tool === "string") : void 0,
|
|
205444
|
+
writesWorkspace: record.writesWorkspace === true,
|
|
205445
|
+
maxIterations: typeof record.maxIterations === "number" ? record.maxIterations : void 0,
|
|
205446
|
+
outputContract: typeof record.outputContract === "string" ? record.outputContract : void 0
|
|
205447
|
+
};
|
|
205448
|
+
}
|
|
205272
205449
|
var spawnWorkerTool;
|
|
205273
205450
|
var init_spawnWorker = __esm({
|
|
205274
205451
|
"features/perchTerminal/runtime/toolSystem/tools/workers/spawnWorker.ts"() {
|
|
@@ -205278,12 +205455,49 @@ var init_spawnWorker = __esm({
|
|
|
205278
205455
|
init_agentDispatch();
|
|
205279
205456
|
init_localScope();
|
|
205280
205457
|
init_toolNames();
|
|
205458
|
+
init_adhocManifest();
|
|
205459
|
+
init_registry();
|
|
205460
|
+
init_flockNicknames();
|
|
205281
205461
|
spawnWorkerTool = {
|
|
205282
205462
|
name: TOOL_NAMES.spawnWorker,
|
|
205283
205463
|
classification: { native: false },
|
|
205284
205464
|
handler: async (args, ctx) => {
|
|
205285
|
-
|
|
205465
|
+
let workerId = String(args.workerId ?? "");
|
|
205286
205466
|
const objective = String(args.objective ?? "");
|
|
205467
|
+
let adhocManifestId = null;
|
|
205468
|
+
let adhocNickname = null;
|
|
205469
|
+
const customSpec = parseAdhocSpec(args.custom);
|
|
205470
|
+
if (!workerId && args.custom !== void 0 && !customSpec) {
|
|
205471
|
+
return {
|
|
205472
|
+
ok: false,
|
|
205473
|
+
workerId: "",
|
|
205474
|
+
summary: "spawn_worker custom spec is invalid: custom.displayName (non-empty string) is required.",
|
|
205475
|
+
errorCode: "adhoc_spec_invalid"
|
|
205476
|
+
};
|
|
205477
|
+
}
|
|
205478
|
+
if (!workerId && customSpec) {
|
|
205479
|
+
const { manifest, droppedTools } = buildAdhocWorkerManifest(customSpec);
|
|
205480
|
+
registerWorkerManifest(manifest);
|
|
205481
|
+
adhocManifestId = manifest.workerId;
|
|
205482
|
+
adhocNickname = flockNicknameFor(manifest.workerId, 0);
|
|
205483
|
+
workerId = manifest.workerId;
|
|
205484
|
+
if (droppedTools.length > 0 && ctx.onEvent) {
|
|
205485
|
+
ctx.onEvent({
|
|
205486
|
+
type: "diagnostic",
|
|
205487
|
+
code: "adhoc_worker_tools_dropped",
|
|
205488
|
+
message: `Ad-hoc worker "${manifest.name}" was not granted: ${droppedTools.join(", ")} (orchestration or write tools outside its scope).`,
|
|
205489
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
205490
|
+
});
|
|
205491
|
+
}
|
|
205492
|
+
}
|
|
205493
|
+
if (!workerId) {
|
|
205494
|
+
return {
|
|
205495
|
+
ok: false,
|
|
205496
|
+
workerId: "",
|
|
205497
|
+
summary: "spawn_worker requires either workerId (registered worker) or custom { displayName, allowedTools, ... } for an ad-hoc worker.",
|
|
205498
|
+
errorCode: "worker_id_missing"
|
|
205499
|
+
};
|
|
205500
|
+
}
|
|
205287
205501
|
const context = typeof args.context === "string" || typeof args.context === "object" && args.context !== null && !Array.isArray(args.context) ? args.context : void 0;
|
|
205288
205502
|
const lane = typeof args.lane === "string" ? args.lane : void 0;
|
|
205289
205503
|
const maxIterations = typeof args.maxIterations === "number" ? args.maxIterations : void 0;
|
|
@@ -205314,26 +205528,31 @@ var init_spawnWorker = __esm({
|
|
|
205314
205528
|
Proceed with the available context. If a missing fact is essential, ask the user for that fact instead of stopping.` : "",
|
|
205315
205529
|
capabilityNote ? `Capability note: ${capabilityNote}` : ""
|
|
205316
205530
|
].filter(Boolean).join("\n\n");
|
|
205317
|
-
|
|
205318
|
-
|
|
205319
|
-
|
|
205320
|
-
|
|
205321
|
-
|
|
205322
|
-
|
|
205323
|
-
|
|
205324
|
-
|
|
205325
|
-
|
|
205326
|
-
|
|
205327
|
-
|
|
205328
|
-
|
|
205329
|
-
|
|
205330
|
-
|
|
205331
|
-
|
|
205332
|
-
|
|
205333
|
-
|
|
205334
|
-
|
|
205335
|
-
|
|
205336
|
-
|
|
205531
|
+
try {
|
|
205532
|
+
const result2 = await spawnWorker(
|
|
205533
|
+
{ workerId, objective: workerObjective, context: enrichedContext, lane, maxIterations },
|
|
205534
|
+
{
|
|
205535
|
+
workspaceRoot: effectiveWorkspaceRoot(ctx),
|
|
205536
|
+
desktopConnected: ctx.desktopConnected,
|
|
205537
|
+
activeRootPath: ctx.activeRootPath,
|
|
205538
|
+
permissionMode: ctx.permissionMode,
|
|
205539
|
+
workspaceId: ctx.workspaceId,
|
|
205540
|
+
threadId: ctx.threadId,
|
|
205541
|
+
selectedSourceId: ctx.selectedSourceId,
|
|
205542
|
+
supabaseConfigured: ctx.supabaseConfigured,
|
|
205543
|
+
supabase: ctx.supabase,
|
|
205544
|
+
runId: ctx.runId,
|
|
205545
|
+
founderModelSelection: ctx.founderModelSelection ?? null,
|
|
205546
|
+
onEvent: ctx.onEvent,
|
|
205547
|
+
signal: ctx.signal,
|
|
205548
|
+
parentToolCallId: ctx.parentToolCallId,
|
|
205549
|
+
mcpTools: ctx.mcpTools ?? []
|
|
205550
|
+
}
|
|
205551
|
+
);
|
|
205552
|
+
return adhocNickname ? { ...result2, nickname: adhocNickname } : result2;
|
|
205553
|
+
} finally {
|
|
205554
|
+
if (adhocManifestId) unregisterWorkerManifest(adhocManifestId);
|
|
205555
|
+
}
|
|
205337
205556
|
}
|
|
205338
205557
|
};
|
|
205339
205558
|
}
|
|
@@ -221147,56 +221366,6 @@ var init_flockModelHints = __esm({
|
|
|
221147
221366
|
}
|
|
221148
221367
|
});
|
|
221149
221368
|
|
|
221150
|
-
// features/perchTerminal/runtime/flock/flockNicknames.ts
|
|
221151
|
-
function seedFromFlockId(flockId) {
|
|
221152
|
-
let hash = 2166136261;
|
|
221153
|
-
for (let i = 0; i < flockId.length; i++) {
|
|
221154
|
-
hash ^= flockId.charCodeAt(i);
|
|
221155
|
-
hash = Math.imul(hash, 16777619);
|
|
221156
|
-
}
|
|
221157
|
-
return hash >>> 0;
|
|
221158
|
-
}
|
|
221159
|
-
function flockNicknameRotation(flockId) {
|
|
221160
|
-
const names = [...FLOCK_NICKNAMES];
|
|
221161
|
-
let state = seedFromFlockId(flockId) || 1;
|
|
221162
|
-
const nextRandom = () => {
|
|
221163
|
-
state = Math.imul(state, 1664525) + 1013904223 >>> 0;
|
|
221164
|
-
return state / 4294967296;
|
|
221165
|
-
};
|
|
221166
|
-
for (let i = names.length - 1; i > 0; i--) {
|
|
221167
|
-
const j = Math.floor(nextRandom() * (i + 1));
|
|
221168
|
-
[names[i], names[j]] = [names[j], names[i]];
|
|
221169
|
-
}
|
|
221170
|
-
return names;
|
|
221171
|
-
}
|
|
221172
|
-
function flockNicknameFor(flockId, index) {
|
|
221173
|
-
const rotation = flockNicknameRotation(flockId);
|
|
221174
|
-
return rotation[index % rotation.length];
|
|
221175
|
-
}
|
|
221176
|
-
var FLOCK_NICKNAMES;
|
|
221177
|
-
var init_flockNicknames = __esm({
|
|
221178
|
-
"features/perchTerminal/runtime/flock/flockNicknames.ts"() {
|
|
221179
|
-
"use strict";
|
|
221180
|
-
FLOCK_NICKNAMES = [
|
|
221181
|
-
"Little Dum Dum",
|
|
221182
|
-
"Molly",
|
|
221183
|
-
"Boomer",
|
|
221184
|
-
"Shawarma",
|
|
221185
|
-
"Curie",
|
|
221186
|
-
"Eagle",
|
|
221187
|
-
"Noether",
|
|
221188
|
-
"Wonky",
|
|
221189
|
-
"Lovelace",
|
|
221190
|
-
"Bell",
|
|
221191
|
-
"Turing",
|
|
221192
|
-
"Faraday",
|
|
221193
|
-
"Biscuit",
|
|
221194
|
-
"Ice Cream",
|
|
221195
|
-
"Minsky"
|
|
221196
|
-
];
|
|
221197
|
-
}
|
|
221198
|
-
});
|
|
221199
|
-
|
|
221200
221369
|
// features/perchTerminal/runtime/flock/flockRoles.ts
|
|
221201
221370
|
function listFlockRoleSpecs() {
|
|
221202
221371
|
return Object.values(FLOCK_ROLES);
|
|
@@ -221429,6 +221598,74 @@ var init_flockRoles = __esm({
|
|
|
221429
221598
|
"Return JSON with verificationStatus (pass|partial|fail), verifiedClaims, unsupportedClaims, warnings."
|
|
221430
221599
|
)
|
|
221431
221600
|
},
|
|
221601
|
+
consistency_checker: {
|
|
221602
|
+
roleId: "consistency_checker",
|
|
221603
|
+
workerId: "flock_consistency_checker",
|
|
221604
|
+
displayName: "Consistency Checker",
|
|
221605
|
+
role: "verifier",
|
|
221606
|
+
lane: "verifier",
|
|
221607
|
+
allowedTools: [
|
|
221608
|
+
TOOL_NAMES.searchKnowledge,
|
|
221609
|
+
TOOL_NAMES.readLocalFile,
|
|
221610
|
+
TOOL_NAMES.listLocalSources,
|
|
221611
|
+
TOOL_NAMES.readLocalSourceFile
|
|
221612
|
+
],
|
|
221613
|
+
writesWorkspace: false,
|
|
221614
|
+
maxIterations: 8,
|
|
221615
|
+
outputContract: "JSON { continuityStatus: 'pass'|'partial'|'fail', contradictions, styleIssues, warnings }",
|
|
221616
|
+
objectiveTemplate: (task) => bounded(
|
|
221617
|
+
task,
|
|
221618
|
+
"Review the provided draft for internal consistency and craft: continuity of characters, names, timeline, and established facts; tone and voice drift; pacing; clich\xE9s. Do not fact-check against external sources.",
|
|
221619
|
+
"Return JSON with continuityStatus (pass|partial|fail), contradictions (string[]), styleIssues (string[]), warnings (string[])."
|
|
221620
|
+
)
|
|
221621
|
+
},
|
|
221622
|
+
legal_drafter: {
|
|
221623
|
+
roleId: "legal_drafter",
|
|
221624
|
+
workerId: "flock_legal_drafter",
|
|
221625
|
+
displayName: "Legal Drafter",
|
|
221626
|
+
role: "worker",
|
|
221627
|
+
lane: "writer",
|
|
221628
|
+
allowedTools: [
|
|
221629
|
+
TOOL_NAMES.searchKnowledge,
|
|
221630
|
+
TOOL_NAMES.glob,
|
|
221631
|
+
TOOL_NAMES.grep,
|
|
221632
|
+
TOOL_NAMES.readLocalFile,
|
|
221633
|
+
TOOL_NAMES.listLocalSources,
|
|
221634
|
+
TOOL_NAMES.readLocalSourceFile,
|
|
221635
|
+
TOOL_NAMES.writeLocalFile
|
|
221636
|
+
],
|
|
221637
|
+
writesWorkspace: true,
|
|
221638
|
+
maxIterations: 10,
|
|
221639
|
+
outputContract: "JSON { title, markdown, irac: { issue, rules, application, conclusion }, authoritiesCited, needsVerification, notes }",
|
|
221640
|
+
objectiveTemplate: (task) => bounded(
|
|
221641
|
+
task,
|
|
221642
|
+
"Draft a legal memo in strict IRAC form \u2014 Issue, Rule, Application, Conclusion, every section present and labeled. First call searchKnowledge for IRAC memo exemplars or templates and imitate their structure and register when any exist. Closed universe: cite ONLY authorities found in the provided case packet (local sources), with pin cites; never invent or import outside authority. Propositions you cannot support from the packet go in needsVerification, never in the prose as settled law.",
|
|
221643
|
+
"Return JSON with title, markdown, irac {issue, rules, application, conclusion}, authoritiesCited (string[]), needsVerification (string[]), notes (string[])."
|
|
221644
|
+
)
|
|
221645
|
+
},
|
|
221646
|
+
legal_citation_checker: {
|
|
221647
|
+
roleId: "legal_citation_checker",
|
|
221648
|
+
workerId: "flock_legal_citation_checker",
|
|
221649
|
+
displayName: "Legal Citation Checker",
|
|
221650
|
+
role: "verifier",
|
|
221651
|
+
lane: "verifier",
|
|
221652
|
+
// Closed universe by construction: no web or global knowledge tools — the packet is the law.
|
|
221653
|
+
allowedTools: [
|
|
221654
|
+
TOOL_NAMES.glob,
|
|
221655
|
+
TOOL_NAMES.grep,
|
|
221656
|
+
TOOL_NAMES.readLocalFile,
|
|
221657
|
+
TOOL_NAMES.listLocalSources,
|
|
221658
|
+
TOOL_NAMES.readLocalSourceFile
|
|
221659
|
+
],
|
|
221660
|
+
writesWorkspace: false,
|
|
221661
|
+
maxIterations: 10,
|
|
221662
|
+
outputContract: "JSON { verificationStatus: 'pass'|'partial'|'fail', verifiedCitations, unsupportedCitations: [{ citation, claim, reason }], missingFromPacket, warnings }",
|
|
221663
|
+
objectiveTemplate: (task) => bounded(
|
|
221664
|
+
task,
|
|
221665
|
+
"Closed-universe citation check: for every authority cited in the provided draft or memo, locate it in the provided case packet (local sources via listLocalSources/grep/readLocalFile). Verify the authority exists in the packet, quoted language appears in it, and each pin cite supports the stated proposition. Mark pass only when the packet supports the citation. Never consult outside sources \u2014 an authority absent from the packet is reported in missingFromPacket, not assumed valid.",
|
|
221666
|
+
"Return JSON with verificationStatus (pass|partial|fail), verifiedCitations, unsupportedCitations ({citation, claim, reason}[]), missingFromPacket (string[]), warnings (string[])."
|
|
221667
|
+
)
|
|
221668
|
+
},
|
|
221432
221669
|
browser_operator: {
|
|
221433
221670
|
roleId: "browser_operator",
|
|
221434
221671
|
// Reuses the roster manifest from workers/registry — its system prompt and
|
|
@@ -221500,10 +221737,35 @@ function planFlock(rawTask, options = {}) {
|
|
|
221500
221737
|
if ((options.surface ?? detectFlockSurface()) === "cli") {
|
|
221501
221738
|
selected.delete("browser_operator");
|
|
221502
221739
|
}
|
|
221740
|
+
if (selected.has("legal_drafter")) {
|
|
221741
|
+
if (!/\b(write|draft|compose|prepare)\b/i.test(task)) {
|
|
221742
|
+
selected.delete("legal_drafter");
|
|
221743
|
+
selected.add("legal_citation_checker");
|
|
221744
|
+
}
|
|
221745
|
+
selected.delete("writer");
|
|
221746
|
+
selected.delete("researcher");
|
|
221747
|
+
selected.delete("citation_checker");
|
|
221748
|
+
selected.delete("consistency_checker");
|
|
221749
|
+
selected.delete("source_verifier");
|
|
221750
|
+
}
|
|
221751
|
+
if (selected.has("legal_drafter")) {
|
|
221752
|
+
selected.add("legal_citation_checker");
|
|
221753
|
+
} else if (selected.has("legal_citation_checker")) {
|
|
221754
|
+
selected.add("workspace_scout");
|
|
221755
|
+
}
|
|
221503
221756
|
if (selected.has("patch_worker") || selected.has("test_runner") || selected.has("ui_reviewer")) {
|
|
221504
221757
|
selected.add("workspace_scout");
|
|
221505
221758
|
}
|
|
221506
|
-
if (selected.has("writer"))
|
|
221759
|
+
if (selected.has("writer")) {
|
|
221760
|
+
const grounded = selected.has("researcher") || selected.has("citation_checker") || selected.has("source_verifier");
|
|
221761
|
+
if (grounded) {
|
|
221762
|
+
selected.add("researcher");
|
|
221763
|
+
selected.add("citation_checker");
|
|
221764
|
+
selected.delete("consistency_checker");
|
|
221765
|
+
} else {
|
|
221766
|
+
selected.add("consistency_checker");
|
|
221767
|
+
}
|
|
221768
|
+
}
|
|
221507
221769
|
if (selected.size === 0) {
|
|
221508
221770
|
selected.add("workspace_scout");
|
|
221509
221771
|
selected.add("evidence_reviewer");
|
|
@@ -221563,6 +221825,8 @@ var init_flockPlanner = __esm({
|
|
|
221563
221825
|
{ roleId: "researcher", pattern: /\b(research|sources?|find|look up|references?|citations?|academic|papers?|literature|background)\b/i },
|
|
221564
221826
|
{ roleId: "writer", pattern: /\b(write|draft|compose|essay|memo|report|article|document|copy)\b/i },
|
|
221565
221827
|
{ roleId: "citation_checker", pattern: /\b(citations?|verify|check sources?|fact.?check|references?)\b/i },
|
|
221828
|
+
{ roleId: "consistency_checker", pattern: /\b(fiction|stor(?:y|ies)|novel|chapters?|poems?|screenplay|scripts?|lyrics)\b/i },
|
|
221829
|
+
{ roleId: "legal_drafter", pattern: /\b(irac|memorandum|legal (?:memo|brief|writing|citations?)|case ?packet|bluebook|pin ?cites?)\b/i },
|
|
221566
221830
|
{ roleId: "browser_operator", pattern: /\b(browser|open|navigate|click|fill|submit|login|webpage|url|site)\b/i }
|
|
221567
221831
|
];
|
|
221568
221832
|
ROLE_TRIM_PRIORITY = [
|
|
@@ -221570,8 +221834,11 @@ var init_flockPlanner = __esm({
|
|
|
221570
221834
|
"writer",
|
|
221571
221835
|
"test_runner",
|
|
221572
221836
|
"workspace_scout",
|
|
221837
|
+
"legal_drafter",
|
|
221838
|
+
"legal_citation_checker",
|
|
221573
221839
|
"researcher",
|
|
221574
221840
|
"citation_checker",
|
|
221841
|
+
"consistency_checker",
|
|
221575
221842
|
"evidence_reviewer",
|
|
221576
221843
|
"source_verifier",
|
|
221577
221844
|
"ui_reviewer",
|
|
@@ -221609,7 +221876,9 @@ function buildFlockPlannerPrompts(ctx) {
|
|
|
221609
221876
|
`- 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 })}.`,
|
|
221610
221877
|
`- maxIterations: 1-${caps.maxIterationsPerWorker}.`,
|
|
221611
221878
|
"- 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.",
|
|
221612
|
-
"- baseWorkerId: set ONLY to reuse an id from existingWorkers; otherwise null.",
|
|
221879
|
+
"- baseWorkerId: set ONLY to reuse an id from existingWorkers; otherwise null. Prefer reusing existingWorkers ids when a role matches instead of inventing a near-duplicate.",
|
|
221880
|
+
"- Writing tasks: pair the draft with exactly ONE draft verifier \u2014 reuse flock_citation_checker (together with flock_researcher) when the piece makes factual or source-backed claims, or flock_consistency_checker for creative/fiction drafts (continuity, voice, pacing \u2014 no researcher, never demand citations from fiction).",
|
|
221881
|
+
"- Legal writing or citation-checking tasks (IRAC memos, briefs, case packets, pin cites): reuse flock_legal_drafter and flock_legal_citation_checker instead of the generic writing roles. Closed universe \u2014 verification runs ONLY against the user's provided case packet/local sources, never the open web; a legal draft must include flock_legal_citation_checker.",
|
|
221613
221882
|
"- Decline (accepted=false, with reason) tasks that are trivial, conversational, or need no fanout."
|
|
221614
221883
|
].join("\n");
|
|
221615
221884
|
ensureFlockWorkersRegistered();
|
|
@@ -221715,7 +221984,7 @@ function validateLlmFlockPlan(record, ctx) {
|
|
|
221715
221984
|
const objective = sanitizeText(worker.objective, MAX_OBJECTIVE_CHARS);
|
|
221716
221985
|
if (!displayName || !objective) return null;
|
|
221717
221986
|
const role = VALID_ROLES.has(worker.phase) ? worker.phase : "worker";
|
|
221718
|
-
const outputContract = sanitizeLine(worker.outputContract,
|
|
221987
|
+
const outputContract = sanitizeLine(worker.outputContract, MAX_CONTRACT_CHARS2) || "Return a short structured summary of what was found or done.";
|
|
221719
221988
|
const requestedTools = Array.isArray(worker.allowedTools) ? worker.allowedTools.filter((tool) => typeof tool === "string") : [];
|
|
221720
221989
|
let allowedTools = [...new Set(requestedTools)].filter(
|
|
221721
221990
|
(tool) => available.has(tool) && !FLOCK_FORBIDDEN_TOOLS.includes(tool)
|
|
@@ -221726,7 +221995,7 @@ function validateLlmFlockPlan(record, ctx) {
|
|
|
221726
221995
|
if (!writesWorkspace) {
|
|
221727
221996
|
allowedTools = allowedTools.filter((tool) => !WRITE_TOOLS.has(tool));
|
|
221728
221997
|
}
|
|
221729
|
-
const maxIterations =
|
|
221998
|
+
const maxIterations = clampInt2(worker.maxIterations, 1, caps.maxIterationsPerWorker, 6);
|
|
221730
221999
|
const baseWorkerId = typeof worker.baseWorkerId === "string" && worker.baseWorkerId.trim() ? worker.baseWorkerId.trim() : null;
|
|
221731
222000
|
const reusedManifest = baseWorkerId ? resolveWorkerManifest(baseWorkerId) : null;
|
|
221732
222001
|
const flockWorkerId = `fw${index + 1}_${slugify(displayName)}`;
|
|
@@ -221792,6 +222061,74 @@ function validateLlmFlockPlan(record, ctx) {
|
|
|
221792
222061
|
}
|
|
221793
222062
|
}
|
|
221794
222063
|
}
|
|
222064
|
+
const legalDrafterWorker = surfacedWorkers.find(
|
|
222065
|
+
(worker) => worker.workerId === FLOCK_ROLES.legal_drafter.workerId
|
|
222066
|
+
);
|
|
222067
|
+
if (legalDrafterWorker && !surfacedWorkers.some((worker) => worker.workerId === FLOCK_ROLES.legal_citation_checker.workerId)) {
|
|
222068
|
+
const spec = FLOCK_ROLES.legal_citation_checker;
|
|
222069
|
+
const genericVerifierIndex = surfacedWorkers.findIndex(
|
|
222070
|
+
(worker) => worker.workerId === FLOCK_ROLES.citation_checker.workerId || worker.workerId === FLOCK_ROLES.consistency_checker.workerId
|
|
222071
|
+
);
|
|
222072
|
+
if (genericVerifierIndex >= 0) {
|
|
222073
|
+
const existing = surfacedWorkers[genericVerifierIndex];
|
|
222074
|
+
surfacedWorkers[genericVerifierIndex] = {
|
|
222075
|
+
...existing,
|
|
222076
|
+
workerId: spec.workerId,
|
|
222077
|
+
displayName: spec.displayName,
|
|
222078
|
+
role: spec.role,
|
|
222079
|
+
objective: spec.objectiveTemplate(ctx.task),
|
|
222080
|
+
maxIterations: Math.min(spec.maxIterations, caps.maxIterationsPerWorker),
|
|
222081
|
+
allowedTools: [...spec.allowedTools],
|
|
222082
|
+
writesWorkspace: false,
|
|
222083
|
+
writeScope: null,
|
|
222084
|
+
outputContract: spec.outputContract,
|
|
222085
|
+
dependsOn: [legalDrafterWorker.flockWorkerId],
|
|
222086
|
+
dynamicManifest: null
|
|
222087
|
+
};
|
|
222088
|
+
} else if (surfacedWorkers.length < FLOCK_MAX_WORKERS) {
|
|
222089
|
+
const index = surfacedWorkers.length;
|
|
222090
|
+
surfacedWorkers.push({
|
|
222091
|
+
flockWorkerId: `fw${index + 1}_${spec.roleId}`,
|
|
222092
|
+
workerId: spec.workerId,
|
|
222093
|
+
displayName: spec.displayName,
|
|
222094
|
+
nickname: flockNicknameFor(ctx.flockId, index),
|
|
222095
|
+
role: spec.role,
|
|
222096
|
+
objective: spec.objectiveTemplate(ctx.task),
|
|
222097
|
+
maxIterations: Math.min(spec.maxIterations, caps.maxIterationsPerWorker),
|
|
222098
|
+
allowedTools: [...spec.allowedTools],
|
|
222099
|
+
writesWorkspace: false,
|
|
222100
|
+
writeScope: null,
|
|
222101
|
+
outputContract: spec.outputContract,
|
|
222102
|
+
dependsOn: [legalDrafterWorker.flockWorkerId],
|
|
222103
|
+
modelOverride: null,
|
|
222104
|
+
dynamicManifest: null
|
|
222105
|
+
});
|
|
222106
|
+
}
|
|
222107
|
+
}
|
|
222108
|
+
const writerWorker = legalDrafterWorker ?? surfacedWorkers.find((worker) => worker.workerId === FLOCK_ROLES.writer.workerId);
|
|
222109
|
+
if (writerWorker && !surfacedWorkers.some((worker) => worker.role === "verifier") && surfacedWorkers.length < FLOCK_MAX_WORKERS) {
|
|
222110
|
+
const hasResearch = surfacedWorkers.some(
|
|
222111
|
+
(worker) => worker.workerId === FLOCK_ROLES.researcher.workerId
|
|
222112
|
+
);
|
|
222113
|
+
const spec = legalDrafterWorker ? FLOCK_ROLES.legal_citation_checker : hasResearch ? FLOCK_ROLES.citation_checker : FLOCK_ROLES.consistency_checker;
|
|
222114
|
+
const index = surfacedWorkers.length;
|
|
222115
|
+
surfacedWorkers.push({
|
|
222116
|
+
flockWorkerId: `fw${index + 1}_${spec.roleId}`,
|
|
222117
|
+
workerId: spec.workerId,
|
|
222118
|
+
displayName: spec.displayName,
|
|
222119
|
+
nickname: flockNicknameFor(ctx.flockId, index),
|
|
222120
|
+
role: spec.role,
|
|
222121
|
+
objective: spec.objectiveTemplate(ctx.task),
|
|
222122
|
+
maxIterations: Math.min(spec.maxIterations, caps.maxIterationsPerWorker),
|
|
222123
|
+
allowedTools: [...spec.allowedTools],
|
|
222124
|
+
writesWorkspace: false,
|
|
222125
|
+
writeScope: null,
|
|
222126
|
+
outputContract: spec.outputContract,
|
|
222127
|
+
dependsOn: [writerWorker.flockWorkerId],
|
|
222128
|
+
modelOverride: null,
|
|
222129
|
+
dynamicManifest: null
|
|
222130
|
+
});
|
|
222131
|
+
}
|
|
221795
222132
|
surfacedWorkers.sort((a, b2) => FLOCK_ROLE_ORDER[a.role] - FLOCK_ROLE_ORDER[b2.role]);
|
|
221796
222133
|
const summary = sanitizeLine(record.summary, 200) || `${surfacedWorkers.length} workers: ${surfacedWorkers.map((worker) => worker.displayName).join(", ")}`;
|
|
221797
222134
|
return {
|
|
@@ -221843,11 +222180,11 @@ function sanitizeText(value, max2) {
|
|
|
221843
222180
|
if (typeof value !== "string") return "";
|
|
221844
222181
|
return value.trim().slice(0, max2);
|
|
221845
222182
|
}
|
|
221846
|
-
function
|
|
222183
|
+
function clampInt2(value, min2, max2, fallback) {
|
|
221847
222184
|
const num = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
|
|
221848
222185
|
return Math.min(Math.max(num, min2), max2);
|
|
221849
222186
|
}
|
|
221850
|
-
var FLOCK_FORBIDDEN_TOOLS, WRITE_TOOLS, GUI_ONLY_WORKER_IDS, GUI_ONLY_TOOLS, VALID_ROLES, MAX_DISPLAY_NAME_CHARS, MAX_OBJECTIVE_CHARS,
|
|
222187
|
+
var FLOCK_FORBIDDEN_TOOLS, WRITE_TOOLS, GUI_ONLY_WORKER_IDS, GUI_ONLY_TOOLS, VALID_ROLES, MAX_DISPLAY_NAME_CHARS, MAX_OBJECTIVE_CHARS, MAX_CONTRACT_CHARS2, MAX_ROSTER_IN_PROMPT, MAX_TOOLS_IN_PROMPT;
|
|
221851
222188
|
var init_flockLlmPlanner = __esm({
|
|
221852
222189
|
"features/perchTerminal/runtime/flock/flockLlmPlanner.ts"() {
|
|
221853
222190
|
"use strict";
|
|
@@ -221888,7 +222225,7 @@ var init_flockLlmPlanner = __esm({
|
|
|
221888
222225
|
VALID_ROLES = /* @__PURE__ */ new Set(["scout", "worker", "verifier", "reducer"]);
|
|
221889
222226
|
MAX_DISPLAY_NAME_CHARS = 40;
|
|
221890
222227
|
MAX_OBJECTIVE_CHARS = 1200;
|
|
221891
|
-
|
|
222228
|
+
MAX_CONTRACT_CHARS2 = 240;
|
|
221892
222229
|
MAX_ROSTER_IN_PROMPT = 24;
|
|
221893
222230
|
MAX_TOOLS_IN_PROMPT = 80;
|
|
221894
222231
|
}
|
|
@@ -222031,14 +222368,19 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
222031
222368
|
}
|
|
222032
222369
|
const spawnFn = options.spawnWorkerFn ?? spawnWorker;
|
|
222033
222370
|
const outcomes = [];
|
|
222371
|
+
const revisionOutcomes = [];
|
|
222372
|
+
let revisionReport = null;
|
|
222034
222373
|
const outputByFlockWorkerId = /* @__PURE__ */ new Map();
|
|
222035
|
-
const sharedContext = {
|
|
222374
|
+
const sharedContext = {
|
|
222375
|
+
task,
|
|
222376
|
+
currentDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
|
|
222377
|
+
};
|
|
222036
222378
|
let toolCallsUsed = 0;
|
|
222037
222379
|
let toolCallsReserved = 0;
|
|
222038
222380
|
let workersAwaitingLaunch = plan.workers.length;
|
|
222039
222381
|
try {
|
|
222040
222382
|
const phases = [...new Set(plan.workers.map((worker) => FLOCK_ROLE_ORDER[worker.role]))].sort((a, b2) => a - b2);
|
|
222041
|
-
const runReadyWorker = async (worker) => {
|
|
222383
|
+
const runReadyWorker = async (worker, contextOverride) => {
|
|
222042
222384
|
const workersLeftIncludingThis = Math.max(1, workersAwaitingLaunch);
|
|
222043
222385
|
workersAwaitingLaunch = Math.max(0, workersAwaitingLaunch - 1);
|
|
222044
222386
|
if (flockRun.controller.signal.aborted) {
|
|
@@ -222073,11 +222415,14 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
222073
222415
|
toolCallsReserved += reservedToolCalls;
|
|
222074
222416
|
emitWorkerUpdate(emit, plan, worker, "running");
|
|
222075
222417
|
try {
|
|
222418
|
+
const context = contextOverride ?? buildWorkerContext(worker, sharedContext, outputByFlockWorkerId, plan);
|
|
222419
|
+
const objective = worker.role === "worker" && contextContainsSources(context) ? `${worker.objective}
|
|
222420
|
+
${FLOCK_GROUNDING_CONTRACT}` : worker.objective;
|
|
222076
222421
|
const result2 = await spawnFn(
|
|
222077
222422
|
{
|
|
222078
222423
|
workerId: worker.workerId,
|
|
222079
|
-
objective
|
|
222080
|
-
context
|
|
222424
|
+
objective,
|
|
222425
|
+
context,
|
|
222081
222426
|
maxIterations: worker.maxIterations,
|
|
222082
222427
|
maxToolCalls: reservedToolCalls
|
|
222083
222428
|
},
|
|
@@ -222134,7 +222479,9 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
222134
222479
|
break;
|
|
222135
222480
|
}
|
|
222136
222481
|
for (const worker of readyWorkers) pending.delete(worker.flockWorkerId);
|
|
222137
|
-
const batchOutcomes = await Promise.all(
|
|
222482
|
+
const batchOutcomes = await Promise.all(
|
|
222483
|
+
readyWorkers.map((worker) => runReadyWorker(worker))
|
|
222484
|
+
);
|
|
222138
222485
|
for (const outcome of batchOutcomes) {
|
|
222139
222486
|
outcomes.push(outcome);
|
|
222140
222487
|
if (!outcome.result) continue;
|
|
@@ -222144,6 +222491,43 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
222144
222491
|
}
|
|
222145
222492
|
}
|
|
222146
222493
|
}
|
|
222494
|
+
const candidate = findRevisionCandidate(plan, outcomes, outputByFlockWorkerId);
|
|
222495
|
+
if (candidate && !flockRun.controller.signal.aborted) {
|
|
222496
|
+
revisionReport = candidate;
|
|
222497
|
+
const revisionWorker = {
|
|
222498
|
+
...candidate.draftWorker,
|
|
222499
|
+
flockWorkerId: `${candidate.draftWorker.flockWorkerId}_r1`,
|
|
222500
|
+
displayName: `${candidate.draftWorker.displayName} (revision)`,
|
|
222501
|
+
objective: buildRevisionObjective(task, candidate),
|
|
222502
|
+
dependsOn: []
|
|
222503
|
+
};
|
|
222504
|
+
const revisionOutcome = await runReadyWorker(revisionWorker, {
|
|
222505
|
+
task,
|
|
222506
|
+
currentDate: sharedContext.currentDate,
|
|
222507
|
+
draft: candidate.draftOutput,
|
|
222508
|
+
verifierFindings: candidate.findings.raw
|
|
222509
|
+
});
|
|
222510
|
+
revisionOutcomes.push(revisionOutcome);
|
|
222511
|
+
candidate.revised = revisionOutcome.status === "done";
|
|
222512
|
+
if (revisionOutcome.result) {
|
|
222513
|
+
const revisedOutput = revisionOutcome.result.structuredOutput ?? clampLine(revisionOutcome.result.summary, 1200);
|
|
222514
|
+
sharedContext[revisionWorker.displayName] = revisedOutput;
|
|
222515
|
+
outputByFlockWorkerId.set(revisionWorker.flockWorkerId, revisedOutput);
|
|
222516
|
+
const recheckWorker = {
|
|
222517
|
+
...candidate.verifierWorker,
|
|
222518
|
+
flockWorkerId: `${candidate.verifierWorker.flockWorkerId}_r1`,
|
|
222519
|
+
displayName: `${candidate.verifierWorker.displayName} (recheck)`,
|
|
222520
|
+
dependsOn: []
|
|
222521
|
+
};
|
|
222522
|
+
const recheckOutcome = await runReadyWorker(recheckWorker, {
|
|
222523
|
+
task,
|
|
222524
|
+
currentDate: sharedContext.currentDate,
|
|
222525
|
+
dependencies: { [revisionWorker.displayName]: revisedOutput }
|
|
222526
|
+
});
|
|
222527
|
+
revisionOutcomes.push(recheckOutcome);
|
|
222528
|
+
candidate.recheckFindings = recheckOutcome.result ? extractVerifierFindings(recheckOutcome.result.structuredOutput) : null;
|
|
222529
|
+
}
|
|
222530
|
+
}
|
|
222147
222531
|
} finally {
|
|
222148
222532
|
clearTimeout(wallTimer);
|
|
222149
222533
|
finishRuntimeRun(
|
|
@@ -222156,7 +222540,14 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
222156
222540
|
const workersFailed = outcomes.filter((outcome) => outcome.status === "failed").length;
|
|
222157
222541
|
const flockStatus = userCancelled || wallTimeHit && workersDone === 0 ? "cancelled" : workersFailed === 0 && workersDone === plan.workers.length ? "completed" : workersDone > 0 ? "partial" : "failed";
|
|
222158
222542
|
const assistantText = [
|
|
222159
|
-
buildFlockSummary(
|
|
222543
|
+
buildFlockSummary(
|
|
222544
|
+
plan,
|
|
222545
|
+
[...outcomes, ...revisionOutcomes],
|
|
222546
|
+
flockStatus,
|
|
222547
|
+
toolCallsUsed,
|
|
222548
|
+
wallTimeHit
|
|
222549
|
+
),
|
|
222550
|
+
...buildVerificationSection(revisionReport),
|
|
222160
222551
|
...modelOverrides.applied.map(
|
|
222161
222552
|
(override) => `Model override: ${override.displayName} ran on ${override.label}.`
|
|
222162
222553
|
),
|
|
@@ -222243,7 +222634,117 @@ function buildWorkerContext(worker, sharedContext, outputByFlockWorkerId, plan)
|
|
|
222243
222634
|
const depWorker = plan.workers.find((candidate) => candidate.flockWorkerId === dep);
|
|
222244
222635
|
dependencies[depWorker?.displayName ?? dep] = output;
|
|
222245
222636
|
}
|
|
222246
|
-
return { task: sharedContext.task, dependencies };
|
|
222637
|
+
return { task: sharedContext.task, currentDate: sharedContext.currentDate, dependencies };
|
|
222638
|
+
}
|
|
222639
|
+
function contextContainsSources(context) {
|
|
222640
|
+
const scan = (value, depth) => {
|
|
222641
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || depth > 3) return false;
|
|
222642
|
+
const record = value;
|
|
222643
|
+
const sources = record.sources;
|
|
222644
|
+
if (Array.isArray(sources) && sources.some(
|
|
222645
|
+
(source) => source && typeof source === "object" && typeof source.url === "string"
|
|
222646
|
+
)) {
|
|
222647
|
+
return true;
|
|
222648
|
+
}
|
|
222649
|
+
return Object.values(record).some((nested) => scan(nested, depth + 1));
|
|
222650
|
+
};
|
|
222651
|
+
return scan(context, 0);
|
|
222652
|
+
}
|
|
222653
|
+
function extractVerifierFindings(output) {
|
|
222654
|
+
if (!output || typeof output !== "object" || Array.isArray(output)) return null;
|
|
222655
|
+
const record = output;
|
|
222656
|
+
const verdictRaw = record.verificationStatus ?? record.continuityStatus ?? record.verdict;
|
|
222657
|
+
const verdict = typeof verdictRaw === "string" ? verdictRaw.trim().toLowerCase() : null;
|
|
222658
|
+
const issues = [];
|
|
222659
|
+
for (const key of [
|
|
222660
|
+
"unsupportedClaims",
|
|
222661
|
+
"unsupportedCitations",
|
|
222662
|
+
"missingFromPacket",
|
|
222663
|
+
"contradictions",
|
|
222664
|
+
"styleIssues",
|
|
222665
|
+
"unsupported"
|
|
222666
|
+
]) {
|
|
222667
|
+
const value = record[key];
|
|
222668
|
+
if (!Array.isArray(value)) continue;
|
|
222669
|
+
for (const item of value) {
|
|
222670
|
+
const text = typeof item === "string" ? item : JSON.stringify(item);
|
|
222671
|
+
const clean = clampLine(text, 200);
|
|
222672
|
+
if (clean && clean !== "{}") issues.push(clean);
|
|
222673
|
+
}
|
|
222674
|
+
}
|
|
222675
|
+
return { verdict, issues, raw: record };
|
|
222676
|
+
}
|
|
222677
|
+
function verifierFindingsNeedRevision(findings) {
|
|
222678
|
+
if (!findings) return false;
|
|
222679
|
+
return findings.issues.length > 0 || findings.verdict === "fail" || findings.verdict === "partial";
|
|
222680
|
+
}
|
|
222681
|
+
function findRevisionCandidate(plan, outcomes, outputByFlockWorkerId) {
|
|
222682
|
+
for (const outcome of outcomes) {
|
|
222683
|
+
if (outcome.worker.role !== "verifier" || outcome.status !== "done" || !outcome.result) {
|
|
222684
|
+
continue;
|
|
222685
|
+
}
|
|
222686
|
+
const findings = extractVerifierFindings(outcome.result.structuredOutput);
|
|
222687
|
+
if (!verifierFindingsNeedRevision(findings)) continue;
|
|
222688
|
+
const draftWorker = resolveDraftWorkerForVerifier(plan, outcome.worker, outcomes);
|
|
222689
|
+
if (!draftWorker) continue;
|
|
222690
|
+
const draftOutput = outputByFlockWorkerId.get(draftWorker.flockWorkerId);
|
|
222691
|
+
if (draftOutput === void 0) continue;
|
|
222692
|
+
return {
|
|
222693
|
+
verifierWorker: outcome.worker,
|
|
222694
|
+
draftWorker,
|
|
222695
|
+
draftOutput,
|
|
222696
|
+
findings,
|
|
222697
|
+
revised: false,
|
|
222698
|
+
recheckFindings: null
|
|
222699
|
+
};
|
|
222700
|
+
}
|
|
222701
|
+
return null;
|
|
222702
|
+
}
|
|
222703
|
+
function resolveDraftWorkerForVerifier(plan, verifier, outcomes) {
|
|
222704
|
+
for (const dep of verifier.dependsOn) {
|
|
222705
|
+
const worker = plan.workers.find((candidate) => candidate.flockWorkerId === dep);
|
|
222706
|
+
if (worker?.role === "worker") return worker;
|
|
222707
|
+
}
|
|
222708
|
+
const doneWorkers = outcomes.filter((outcome) => outcome.status === "done" && outcome.worker.role === "worker").map((outcome) => outcome.worker);
|
|
222709
|
+
const writer = doneWorkers.find(
|
|
222710
|
+
(worker) => worker.workerId === "flock_legal_drafter" || worker.workerId === "flock_writer"
|
|
222711
|
+
);
|
|
222712
|
+
if (writer) return writer;
|
|
222713
|
+
const writingWorkers = doneWorkers.filter((worker) => worker.writesWorkspace);
|
|
222714
|
+
if (writingWorkers.length === 1) return writingWorkers[0];
|
|
222715
|
+
return doneWorkers.length === 1 ? doneWorkers[0] : null;
|
|
222716
|
+
}
|
|
222717
|
+
function buildRevisionObjective(task, candidate) {
|
|
222718
|
+
return [
|
|
222719
|
+
"Bounded Flock revision \u2014 stay strictly inside this scope.",
|
|
222720
|
+
`Task: ${task}`,
|
|
222721
|
+
`A verifier (${candidate.verifierWorker.displayName}) reviewed your draft (context key "draft") and reported findings (context key "verifierFindings").`,
|
|
222722
|
+
"Revise the draft: fix what the findings support fixing; remove or explicitly flag any claim you cannot support. Keep the draft's purpose, format, and output contract. Do not start over.",
|
|
222723
|
+
`Output contract: ${candidate.draftWorker.outputContract}`,
|
|
222724
|
+
"Do not delegate, spawn workers, or start suites. Stop when the findings are addressed."
|
|
222725
|
+
].join("\n");
|
|
222726
|
+
}
|
|
222727
|
+
function buildVerificationSection(report) {
|
|
222728
|
+
if (!report) return [];
|
|
222729
|
+
const lines = [];
|
|
222730
|
+
lines.push(
|
|
222731
|
+
`Verification (${report.verifierWorker.displayName}): ${report.findings.verdict ?? "issues found"} \u2014 ${report.findings.issues.length} finding(s).`
|
|
222732
|
+
);
|
|
222733
|
+
const shown = report.findings.issues.slice(0, 6);
|
|
222734
|
+
for (const issue of shown) lines.push(`- ${issue}`);
|
|
222735
|
+
if (report.findings.issues.length > shown.length) {
|
|
222736
|
+
lines.push(`- \u2026and ${report.findings.issues.length - shown.length} more.`);
|
|
222737
|
+
}
|
|
222738
|
+
if (report.revised) {
|
|
222739
|
+
const recheck = report.recheckFindings;
|
|
222740
|
+
lines.push(
|
|
222741
|
+
recheck ? `The draft was revised once; recheck verdict: ${recheck.verdict ?? "no structured verdict"}${recheck.issues.length ? ` (${recheck.issues.length} remaining finding(s))` : ""}.` : "The draft was revised once; the recheck returned no structured verdict."
|
|
222742
|
+
);
|
|
222743
|
+
} else {
|
|
222744
|
+
lines.push("No revision pass ran \u2014 the findings above stand as reported.");
|
|
222745
|
+
}
|
|
222746
|
+
lines.push("Ask about any finding to discuss it, or rerun /flock to retry with adjustments.");
|
|
222747
|
+
return lines;
|
|
222247
222748
|
}
|
|
222248
222749
|
function buildSpawnContext(input, flockId, signal, emit, worker) {
|
|
222249
222750
|
return {
|
|
@@ -222308,6 +222809,7 @@ function makeFlockRunId() {
|
|
|
222308
222809
|
function now11() {
|
|
222309
222810
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
222310
222811
|
}
|
|
222812
|
+
var FLOCK_GROUNDING_CONTRACT;
|
|
222311
222813
|
var init_runFlockTurn = __esm({
|
|
222312
222814
|
"features/perchTerminal/runtime/flock/runFlockTurn.ts"() {
|
|
222313
222815
|
"use strict";
|
|
@@ -222321,6 +222823,12 @@ var init_runFlockTurn = __esm({
|
|
|
222321
222823
|
init_flockLlmPlanner();
|
|
222322
222824
|
init_flockPlanner();
|
|
222323
222825
|
init_flockRoles();
|
|
222826
|
+
FLOCK_GROUNDING_CONTRACT = [
|
|
222827
|
+
"Grounding contract: your context includes sources[] gathered by research.",
|
|
222828
|
+
"Every nontrivial factual claim in the draft must carry an inline [n] marker mapping to one of those sources, with a numbered source list at the end.",
|
|
222829
|
+
"Claims you cannot support from sources[] belong in needsVerification, never in the prose as fact.",
|
|
222830
|
+
"Do not cite anything that is not in sources[]."
|
|
222831
|
+
].join(" ");
|
|
222324
222832
|
}
|
|
222325
222833
|
});
|
|
222326
222834
|
|