perchai-cli 2.4.50 → 2.4.51
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 +138 -26
- 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();
|
|
@@ -91149,7 +91150,6 @@ Final answers lead with findings, name artifacts or delivery status, and give on
|
|
|
91149
91150
|
var MARKET_DESK_TOOL_NAMES;
|
|
91150
91151
|
var init_marketDeskAccess = __esm({
|
|
91151
91152
|
"features/perchTerminal/runtime/marketDesk/marketDeskAccess.ts"() {
|
|
91152
|
-
"use strict";
|
|
91153
91153
|
init_toolNames();
|
|
91154
91154
|
MARKET_DESK_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
91155
91155
|
TOOL_NAMES.getMarketSignal,
|
|
@@ -139518,7 +139518,6 @@ function offSandboxEvent(runId, handler) {
|
|
|
139518
139518
|
var LOCAL_WORKSPACE_ACCESS_UNAVAILABLE;
|
|
139519
139519
|
var init_bridge = __esm({
|
|
139520
139520
|
"features/perchTerminal/desktop/bridge.ts"() {
|
|
139521
|
-
"use strict";
|
|
139522
139521
|
LOCAL_WORKSPACE_ACCESS_UNAVAILABLE = "Local workspace access is unavailable. Open Perch Desktop or update the app.";
|
|
139523
139522
|
}
|
|
139524
139523
|
});
|
|
@@ -197736,6 +197735,7 @@ function recordDispatchBatchResult(tasks, result2, ctx, opts = {}) {
|
|
|
197736
197735
|
var lifecycleByRun, MAX_LIFECYCLE_RUNS;
|
|
197737
197736
|
var init_workerLifecycle = __esm({
|
|
197738
197737
|
"features/perchTerminal/runtime/workers/workerLifecycle.ts"() {
|
|
197738
|
+
"use strict";
|
|
197739
197739
|
init_workerManifest();
|
|
197740
197740
|
lifecycleByRun = /* @__PURE__ */ new Map();
|
|
197741
197741
|
MAX_LIFECYCLE_RUNS = 200;
|
|
@@ -223760,7 +223760,13 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
223760
223760
|
turnInput: input
|
|
223761
223761
|
};
|
|
223762
223762
|
const modelCall = options.plannerModelCall ?? defaultFlockPlannerModelCall(llmCtx);
|
|
223763
|
-
|
|
223763
|
+
const plannerTimeoutMs = options.plannerTimeoutMs ?? FLOCK_PLANNER_TIMEOUT_MS;
|
|
223764
|
+
const first2 = await runLlmPlannerWithTimeout(llmCtx, modelCall, plannerTimeoutMs);
|
|
223765
|
+
plan = first2.plan;
|
|
223766
|
+
if (!plan && !first2.timedOut) {
|
|
223767
|
+
const retry = await runLlmPlannerWithTimeout(llmCtx, modelCall, plannerTimeoutMs);
|
|
223768
|
+
plan = retry.plan;
|
|
223769
|
+
}
|
|
223764
223770
|
}
|
|
223765
223771
|
if (!plan) {
|
|
223766
223772
|
plan = (options.planFn ?? planFlock)(task, {
|
|
@@ -223991,14 +223997,25 @@ ${FLOCK_GROUNDING_CONTRACT}` : worker.objective;
|
|
|
223991
223997
|
const workersFailed = outcomes.filter((outcome) => outcome.status === "failed").length + workersBlocked;
|
|
223992
223998
|
const flockStatus = userCancelled || wallTimeHit && workersDone === 0 ? "cancelled" : workersFailed === 0 && workersDone === plan.workers.length ? "completed" : workersDone > 0 ? "partial" : "failed";
|
|
223993
223999
|
const permissionHint = workersBlocked > 0 && (turnInput.permissionMode ?? "default") === "default" ? "\n\nTip: flock workers inherit default permissions \u2014 run `/permission take_the_wheel` before `/flock` so bash redirects and file writes do not stall on approval gates." : "";
|
|
224000
|
+
const deterministicSummary = buildFlockSummary(
|
|
224001
|
+
plan,
|
|
224002
|
+
[...outcomes, ...revisionOutcomes],
|
|
224003
|
+
flockStatus,
|
|
224004
|
+
toolCallsUsed,
|
|
224005
|
+
wallTimeHit
|
|
224006
|
+
);
|
|
224007
|
+
const synthesisModelCall = options.synthesisModelCall !== void 0 ? options.synthesisModelCall : options.plannerModelCall === void 0 ? defaultFlockSynthesisModelCall(input, plan.flockId) : null;
|
|
224008
|
+
let summaryBody = deterministicSummary;
|
|
224009
|
+
if (synthesisModelCall && !userCancelled && workersDone > 0) {
|
|
224010
|
+
const synthesized = await runFlockSynthesisWithTimeout(
|
|
224011
|
+
synthesisModelCall,
|
|
224012
|
+
buildFlockSynthesisPrompt(task, [...outcomes, ...revisionOutcomes], revisionReport),
|
|
224013
|
+
FLOCK_SYNTHESIS_TIMEOUT_MS
|
|
224014
|
+
);
|
|
224015
|
+
if (synthesized) summaryBody = synthesized;
|
|
224016
|
+
}
|
|
223994
224017
|
const assistantText = [
|
|
223995
|
-
|
|
223996
|
-
plan,
|
|
223997
|
-
[...outcomes, ...revisionOutcomes],
|
|
223998
|
-
flockStatus,
|
|
223999
|
-
toolCallsUsed,
|
|
224000
|
-
wallTimeHit
|
|
224001
|
-
),
|
|
224018
|
+
summaryBody,
|
|
224002
224019
|
...buildVerificationSection(revisionReport),
|
|
224003
224020
|
...modelOverrides.applied.map(
|
|
224004
224021
|
(override) => `Model override: ${override.displayName} ran on ${override.label}.`
|
|
@@ -224040,6 +224057,89 @@ ${FLOCK_GROUNDING_CONTRACT}` : worker.objective;
|
|
|
224040
224057
|
}
|
|
224041
224058
|
}
|
|
224042
224059
|
}
|
|
224060
|
+
async function runLlmPlannerWithTimeout(ctx, modelCall, timeoutMs) {
|
|
224061
|
+
let timer;
|
|
224062
|
+
const timeout = new Promise((resolve5) => {
|
|
224063
|
+
timer = setTimeout(() => resolve5("timeout"), Math.max(1, timeoutMs));
|
|
224064
|
+
});
|
|
224065
|
+
try {
|
|
224066
|
+
const race = await Promise.race([
|
|
224067
|
+
runLlmFlockPlanner(ctx, modelCall).then((plan) => ({ plan })).catch(() => ({ plan: null })),
|
|
224068
|
+
timeout
|
|
224069
|
+
]);
|
|
224070
|
+
if (race === "timeout") return { plan: null, timedOut: true };
|
|
224071
|
+
return { plan: race.plan, timedOut: false };
|
|
224072
|
+
} finally {
|
|
224073
|
+
if (timer) clearTimeout(timer);
|
|
224074
|
+
}
|
|
224075
|
+
}
|
|
224076
|
+
function defaultFlockSynthesisModelCall(input, flockId) {
|
|
224077
|
+
return async ({ systemPrompt, userPrompt }) => {
|
|
224078
|
+
const result2 = await runModelToolLoop({
|
|
224079
|
+
lane: "chat",
|
|
224080
|
+
founderModelSelection: input.founderModelSelection ?? null,
|
|
224081
|
+
systemPrompt,
|
|
224082
|
+
messages: [{ role: "user", content: userPrompt }],
|
|
224083
|
+
tools: [],
|
|
224084
|
+
workspaceRoot: input.activeRootPath ?? "",
|
|
224085
|
+
desktopConnected: input.desktopConnected,
|
|
224086
|
+
cliLocalTools: input.cliLocalTools === true,
|
|
224087
|
+
activeRootPath: input.activeRootPath,
|
|
224088
|
+
permissionMode: input.permissionMode,
|
|
224089
|
+
workspaceId: input.workspaceId,
|
|
224090
|
+
threadId: input.threadId,
|
|
224091
|
+
supabaseConfigured: input.supabaseConfigured,
|
|
224092
|
+
supabase: input.supabase ?? null,
|
|
224093
|
+
cliServerAppUrl: input.cliServerAppUrl ?? null,
|
|
224094
|
+
cliServerAccessToken: input.cliServerAccessToken ?? null,
|
|
224095
|
+
runId: flockId,
|
|
224096
|
+
chatMode: "ask",
|
|
224097
|
+
maxIterations: 1,
|
|
224098
|
+
onEvent: () => {
|
|
224099
|
+
}
|
|
224100
|
+
});
|
|
224101
|
+
return { ok: result2.ok, text: result2.text };
|
|
224102
|
+
};
|
|
224103
|
+
}
|
|
224104
|
+
function buildFlockSynthesisPrompt(task, outcomes, revisionReport) {
|
|
224105
|
+
const results = outcomes.filter((outcome) => outcome.status === "done" && outcome.result).map((outcome) => {
|
|
224106
|
+
const raw = outcome.result?.structuredOutput ?? outcome.result?.summary ?? "";
|
|
224107
|
+
const serialized = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
224108
|
+
return {
|
|
224109
|
+
role: outcome.worker.displayName,
|
|
224110
|
+
output: serialized.slice(0, FLOCK_SYNTHESIS_MAX_OUTPUT_PER_WORKER)
|
|
224111
|
+
};
|
|
224112
|
+
});
|
|
224113
|
+
const verification = revisionReport ? {
|
|
224114
|
+
verdict: revisionReport.recheckFindings?.verdict ?? revisionReport.findings.verdict ?? null,
|
|
224115
|
+
issues: (revisionReport.recheckFindings?.issues ?? revisionReport.findings.issues).slice(0, 6),
|
|
224116
|
+
revised: revisionReport.revised
|
|
224117
|
+
} : null;
|
|
224118
|
+
const systemPrompt = [
|
|
224119
|
+
"You are the coordinator that just ran a Flock: a team of sub-agents that worked in parallel on the user's task.",
|
|
224120
|
+
"The sub-agents have finished. Write the final answer to the user in your own voice \u2014 clear, direct, friendly, first person.",
|
|
224121
|
+
"Lead with what the user asked for. Present the actual results and fold in any important verification caveats.",
|
|
224122
|
+
"Do not mention sub-agents, workers, roles, nicknames, IDs, or orchestration mechanics unless directly useful to the user.",
|
|
224123
|
+
"Synthesize only from the provided results \u2014 do not invent facts and do not say you will do further work."
|
|
224124
|
+
].join("\n");
|
|
224125
|
+
const userPrompt = JSON.stringify({ task, results, verification });
|
|
224126
|
+
return { systemPrompt, userPrompt };
|
|
224127
|
+
}
|
|
224128
|
+
async function runFlockSynthesisWithTimeout(call, prompt, timeoutMs) {
|
|
224129
|
+
let timer;
|
|
224130
|
+
const timeout = new Promise((resolve5) => {
|
|
224131
|
+
timer = setTimeout(() => resolve5("timeout"), Math.max(1, timeoutMs));
|
|
224132
|
+
});
|
|
224133
|
+
try {
|
|
224134
|
+
const race = await Promise.race([
|
|
224135
|
+
call(prompt).then((result2) => result2.ok && result2.text.trim() ? result2.text.trim() : null).catch(() => null),
|
|
224136
|
+
timeout
|
|
224137
|
+
]);
|
|
224138
|
+
return race === "timeout" ? null : race;
|
|
224139
|
+
} finally {
|
|
224140
|
+
if (timer) clearTimeout(timer);
|
|
224141
|
+
}
|
|
224142
|
+
}
|
|
224043
224143
|
function emitPlanEvent(emit, plan) {
|
|
224044
224144
|
emit({
|
|
224045
224145
|
type: "flock_plan_ready",
|
|
@@ -224272,7 +224372,7 @@ function flockWorkerStatusFromSpawnResult(result2) {
|
|
|
224272
224372
|
function now11() {
|
|
224273
224373
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
224274
224374
|
}
|
|
224275
|
-
var FLOCK_GROUNDING_CONTRACT;
|
|
224375
|
+
var FLOCK_PLANNER_TIMEOUT_MS, FLOCK_SYNTHESIS_TIMEOUT_MS, FLOCK_SYNTHESIS_MAX_OUTPUT_PER_WORKER, FLOCK_GROUNDING_CONTRACT;
|
|
224276
224376
|
var init_runFlockTurn = __esm({
|
|
224277
224377
|
"features/perchTerminal/runtime/flock/runFlockTurn.ts"() {
|
|
224278
224378
|
"use strict";
|
|
@@ -224286,6 +224386,10 @@ var init_runFlockTurn = __esm({
|
|
|
224286
224386
|
init_flockLlmPlanner();
|
|
224287
224387
|
init_flockPlanner();
|
|
224288
224388
|
init_flockRoles();
|
|
224389
|
+
init_toolLoop();
|
|
224390
|
+
FLOCK_PLANNER_TIMEOUT_MS = 35e3;
|
|
224391
|
+
FLOCK_SYNTHESIS_TIMEOUT_MS = 3e4;
|
|
224392
|
+
FLOCK_SYNTHESIS_MAX_OUTPUT_PER_WORKER = 2e3;
|
|
224289
224393
|
FLOCK_GROUNDING_CONTRACT = [
|
|
224290
224394
|
"Grounding contract: your context includes sources[] gathered by research.",
|
|
224291
224395
|
"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.",
|
|
@@ -232698,15 +232802,13 @@ function getBackgroundTaskStore() {
|
|
|
232698
232802
|
var STORE_FILE, BackgroundTaskStore, singleton;
|
|
232699
232803
|
var init_backgroundTaskRegistry = __esm({
|
|
232700
232804
|
"features/perchTerminal/runtime/background/backgroundTaskRegistry.ts"() {
|
|
232805
|
+
"use strict";
|
|
232701
232806
|
init_backgroundTaskTypes();
|
|
232702
232807
|
STORE_FILE = "background-tasks.json";
|
|
232703
232808
|
BackgroundTaskStore = class {
|
|
232704
|
-
baseDir;
|
|
232705
|
-
storePath;
|
|
232706
|
-
outputDir;
|
|
232707
|
-
records = /* @__PURE__ */ new Map();
|
|
232708
|
-
loaded = false;
|
|
232709
232809
|
constructor(options = {}) {
|
|
232810
|
+
this.records = /* @__PURE__ */ new Map();
|
|
232811
|
+
this.loaded = false;
|
|
232710
232812
|
this.baseDir = options.baseDir ?? path11.join(os.homedir(), ".perch");
|
|
232711
232813
|
this.storePath = path11.join(this.baseDir, STORE_FILE);
|
|
232712
232814
|
this.outputDir = path11.join(this.baseDir, "background-output");
|
|
@@ -289977,9 +290079,17 @@ function flockEventToCliRow(event) {
|
|
|
289977
290079
|
switch (event.type) {
|
|
289978
290080
|
case "flock_run_started":
|
|
289979
290081
|
return { id: null, text: "gathering the flock\u2026", tone: "accent" };
|
|
289980
|
-
case "flock_plan_ready":
|
|
290082
|
+
case "flock_plan_ready": {
|
|
289981
290083
|
if (!event.accepted) return null;
|
|
289982
|
-
|
|
290084
|
+
const names = event.workers.map((worker) => worker.displayName);
|
|
290085
|
+
const shown = names.slice(0, 4).join(", ");
|
|
290086
|
+
const extra = names.length > 4 ? ` +${names.length - 4} more` : "";
|
|
290087
|
+
return {
|
|
290088
|
+
id: null,
|
|
290089
|
+
text: `flock plan \xB7 ${event.workers.length} agents \xB7 ${shown}${extra}`,
|
|
290090
|
+
tone: "accent"
|
|
290091
|
+
};
|
|
290092
|
+
}
|
|
289983
290093
|
case "flock_worker_update":
|
|
289984
290094
|
return {
|
|
289985
290095
|
id: `flock-${event.flockId}-${event.flockWorkerId}`,
|
|
@@ -290475,18 +290585,18 @@ async function runReadlineInteractivePerchCli(writer, deps, options) {
|
|
|
290475
290585
|
trimRecentMessages(state.recentMessages);
|
|
290476
290586
|
recordCliUsageRunId(state, result2.runId);
|
|
290477
290587
|
state.contextSnapshot = result2.contextSnapshot ?? state.contextSnapshot;
|
|
290478
|
-
|
|
290588
|
+
void admitCliLearningMemory(connection, {
|
|
290479
290589
|
prompt: turnPrompt,
|
|
290480
290590
|
assistantText: result2.assistantText,
|
|
290481
290591
|
status: result2.status,
|
|
290482
290592
|
personaId: state.personaId,
|
|
290483
290593
|
threadId: result2.threadId,
|
|
290484
290594
|
runId: result2.runId
|
|
290595
|
+
}).then((admitted) => {
|
|
290596
|
+
if (admitted > 0) writeModeLine(writer, "memory", `saved ${admitted}`);
|
|
290597
|
+
}).catch(() => {
|
|
290485
290598
|
});
|
|
290486
290599
|
await persistInteractiveCliState(state);
|
|
290487
|
-
if (admitted > 0) {
|
|
290488
|
-
writeModeLine(writer, "memory", `saved ${admitted}`);
|
|
290489
|
-
}
|
|
290490
290600
|
};
|
|
290491
290601
|
try {
|
|
290492
290602
|
while (true) {
|
|
@@ -291188,17 +291298,19 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
291188
291298
|
trimRecentMessages(state.recentMessages);
|
|
291189
291299
|
recordCliUsageRunId(state, result2.runId);
|
|
291190
291300
|
state.contextSnapshot = result2.contextSnapshot ?? state.contextSnapshot;
|
|
291191
|
-
|
|
291301
|
+
void admitCliLearningMemory(connection, {
|
|
291192
291302
|
prompt,
|
|
291193
291303
|
assistantText,
|
|
291194
291304
|
status: result2.status,
|
|
291195
291305
|
personaId: state.personaId,
|
|
291196
291306
|
threadId: result2.threadId,
|
|
291197
291307
|
runId: result2.runId
|
|
291308
|
+
}).then((admitted) => {
|
|
291309
|
+
if (admitted > 0) {
|
|
291310
|
+
addItem({ label: "memory", text: `saved ${admitted}`, tone: "muted" });
|
|
291311
|
+
}
|
|
291312
|
+
}).catch(() => {
|
|
291198
291313
|
});
|
|
291199
|
-
if (admitted > 0) {
|
|
291200
|
-
addItem({ label: "memory", text: `saved ${admitted}`, tone: "muted" });
|
|
291201
|
-
}
|
|
291202
291314
|
await persistInteractiveCliState(state);
|
|
291203
291315
|
} catch (error) {
|
|
291204
291316
|
addItem({ label: "stop", text: humanizeCliError(errorMessage(error)), tone: "danger" });
|