@linimin/pi-letscook 0.1.50 → 0.1.52
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/CHANGELOG.md +19 -0
- package/README.md +87 -52
- package/extensions/completion/driver.ts +199 -134
- package/extensions/completion/index.ts +20 -7
- package/extensions/completion/input-routing.ts +818 -0
- package/extensions/completion/prompt-surfaces.ts +375 -1
- package/extensions/completion/proposal.ts +1 -1
- package/extensions/completion/role-runner.ts +310 -3
- package/extensions/completion/types.ts +114 -0
- package/package.json +1 -1
- package/scripts/cook-trigger-routing-test.sh +1122 -0
- package/scripts/release-check.sh +29 -21
|
@@ -7,11 +7,17 @@ import { DynamicBorder, parseFrontmatter } from "@mariozechner/pi-coding-agent";
|
|
|
7
7
|
import { Container, Text } from "@mariozechner/pi-tui";
|
|
8
8
|
import {
|
|
9
9
|
buildContextProposalAnalystPromptFromEntries,
|
|
10
|
+
extractJsonObjectFromText,
|
|
10
11
|
parseContextProposalAnalystOutput,
|
|
12
|
+
serializeRecentDiscussionEntries,
|
|
11
13
|
type ContextProposal,
|
|
12
14
|
type RecentDiscussionEntry,
|
|
13
15
|
} from "./proposal";
|
|
14
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
buildCookTriggerClassifierPrompt,
|
|
18
|
+
contextProposalAnalystProgressLines,
|
|
19
|
+
maybeWriteCookTriggerClassifierSnapshot,
|
|
20
|
+
} from "./prompt-surfaces";
|
|
15
21
|
import {
|
|
16
22
|
applyLiveRoleEvent,
|
|
17
23
|
buildInlineRunningLines,
|
|
@@ -25,7 +31,13 @@ import {
|
|
|
25
31
|
} from "./status-surface";
|
|
26
32
|
import { completionRootKey, findCompletionRoot, findRepoRoot, loadCompletionDataForReminder } from "./state-store";
|
|
27
33
|
import { parseReportFields, transcribeRoleOutput, type TranscriptionResult } from "./transcription";
|
|
28
|
-
import type {
|
|
34
|
+
import type {
|
|
35
|
+
AgentDefinition,
|
|
36
|
+
CompletionRole,
|
|
37
|
+
CookTriggerClassification,
|
|
38
|
+
JsonRecord,
|
|
39
|
+
LiveRoleActivity,
|
|
40
|
+
} from "./types";
|
|
29
41
|
|
|
30
42
|
export type RunCompletionRoleParams = {
|
|
31
43
|
root: string;
|
|
@@ -67,6 +79,21 @@ export type AnalyzeContextProposalWithAgentParams = {
|
|
|
67
79
|
getCtxUi: <T extends { ui: any }>(ctx: T) => any | undefined;
|
|
68
80
|
};
|
|
69
81
|
|
|
82
|
+
export type ClassifyCookTriggerIntentWithAgentParams = {
|
|
83
|
+
ctx: { cwd: string; hasUI: boolean; ui: any; model?: any };
|
|
84
|
+
projectName: string;
|
|
85
|
+
inputText: string;
|
|
86
|
+
recentEntries: RecentDiscussionEntry[];
|
|
87
|
+
workflowContextLines?: string[];
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type CookTriggerClassifierResult = {
|
|
91
|
+
status: "classified" | "timeout" | "invalid_output" | "error";
|
|
92
|
+
classification?: CookTriggerClassification;
|
|
93
|
+
rawOutput?: string;
|
|
94
|
+
errorMessage?: string;
|
|
95
|
+
};
|
|
96
|
+
|
|
70
97
|
const AGENT_HOME = path.join(os.homedir(), ".pi", "agent");
|
|
71
98
|
const EXTENSION_DIR = typeof __dirname === "string" ? __dirname : process.cwd();
|
|
72
99
|
const PACKAGE_ROOT_CANDIDATE = path.resolve(EXTENSION_DIR, "..", "..");
|
|
@@ -93,6 +120,28 @@ const CONTEXT_PROPOSAL_ANALYST_SYSTEM_PROMPT = [
|
|
|
93
120
|
].join(" ");
|
|
94
121
|
const STARTUP_ANALYST_ROLE = "cook-proposal-analyst";
|
|
95
122
|
const ANALYST_HEARTBEAT_MS = 5_000;
|
|
123
|
+
const COOK_TRIGGER_CLASSIFIER_SYSTEM_PROMPT = [
|
|
124
|
+
"You classify whether the latest user input should stay in the main chat or be intercepted by the workflow-aware router into the canonical /cook workflow before the primary agent starts implementation work.",
|
|
125
|
+
"Assume router mode reviews every non-bypass normal user turn. Do not require short trigger phrases or explicit /cook text before choosing offer_workflow.",
|
|
126
|
+
"Do not emit markdown, code fences, or commentary.",
|
|
127
|
+
"Return exactly one JSON object with keys: decision, confidence, workflow_bias, reason, evidence, riskFlags, focusHint. You may also include optional keys requires_clarification, clarification_slots, and adopted_artifact when clearly supported.",
|
|
128
|
+
"decision must be exactly one of offer_workflow, normal_prompt, or unclear.",
|
|
129
|
+
"Use offer_workflow when the latest input is directly asking to start, resume, refocus, or continue workflow-worthy repo work through the completion boundary, or explicitly asking to let /cook take over.",
|
|
130
|
+
"Use normal_prompt for ordinary questions, explanations, analysis-only requests, or direct requests that should stay with the primary agent.",
|
|
131
|
+
"Use unclear for ambiguous approvals, acknowledgements, or mixed signals where false-positive routing risk is material.",
|
|
132
|
+
"workflow_bias must be exactly one of startup, resume, refocus, next_round, or unknown.",
|
|
133
|
+
"Use startup when there is no active workflow yet, resume when the user is clearly continuing the current workflow, refocus when the user is clearly switching the active workflow to a different goal, and next_round when the previous workflow is done and the user is starting a new round.",
|
|
134
|
+
"When decision is not offer_workflow, prefer workflow_bias=unknown unless a stronger routing hint would still aid debugging.",
|
|
135
|
+
"confidence must be a number from 0 to 1.",
|
|
136
|
+
"reason must be a single concise sentence.",
|
|
137
|
+
"evidence must be an array of short grounded strings.",
|
|
138
|
+
"riskFlags must be an array of short machine-readable strings such as ambiguous-approval, possible-normal-agent-request, or active-workflow-refocus-risk.",
|
|
139
|
+
"focusHint is optional, must stay short, and must never rewrite the workflow mission or invent scope.",
|
|
140
|
+
"When explicit user adoption of a recent plan or repo markdown artifact is evident, adopted_artifact may describe it with kind recent_plan|repo_markdown, path when known, and basis explicit_user_adoption.",
|
|
141
|
+
"requires_clarification may be true when chooser-style disambiguation is safer than guessing, and clarification_slots may list short needs such as goal, scope, or non_goal.",
|
|
142
|
+
"Short acknowledgements like 好, 可以, ok, sure, or 那就這樣 should usually be unclear unless the surrounding context makes the handoff explicit.",
|
|
143
|
+
].join(" ");
|
|
144
|
+
const COOK_TRIGGER_CLASSIFIER_TIMEOUT_MS = 10_000;
|
|
96
145
|
|
|
97
146
|
class StartupAnalystOverlay extends Container {
|
|
98
147
|
private readonly border: DynamicBorder;
|
|
@@ -175,7 +224,7 @@ async function runContextProposalAnalystSubprocess(params: AnalyzeContextProposa
|
|
|
175
224
|
const rootKey = completionRootKey(undefined, cwd);
|
|
176
225
|
const prompt = buildContextProposalAnalystPromptFromEntries(projectName, recentEntries, params.workflowContextLines);
|
|
177
226
|
const systemPromptTemp = await writeTempFile(runCwd, "pi-cook-proposal-analyst-", CONTEXT_PROPOSAL_ANALYST_SYSTEM_PROMPT);
|
|
178
|
-
const args: string[] = ["--mode", "json", "-p", "--no-session", "--append-system-prompt", systemPromptTemp.filePath, "--model", modelArg, prompt];
|
|
227
|
+
const args: string[] = ["--mode", "json", "-p", "--no-session", "--no-extensions", "--append-system-prompt", systemPromptTemp.filePath, "--model", modelArg, prompt];
|
|
179
228
|
const invocation = getPiInvocation(args);
|
|
180
229
|
const liveActivity = createLiveRoleActivity(STARTUP_ANALYST_ROLE);
|
|
181
230
|
liveActivity.progress = "Analyzing recent discussion";
|
|
@@ -324,6 +373,264 @@ export async function analyzeContextProposalWithAgent(params: AnalyzeContextProp
|
|
|
324
373
|
}
|
|
325
374
|
}
|
|
326
375
|
|
|
376
|
+
function uniqueStrings(items: string[]): string[] {
|
|
377
|
+
const seen = new Set<string>();
|
|
378
|
+
const result: string[] = [];
|
|
379
|
+
for (const item of items) {
|
|
380
|
+
const normalized = item.trim();
|
|
381
|
+
if (!normalized) continue;
|
|
382
|
+
const key = normalized.toLowerCase();
|
|
383
|
+
if (seen.has(key)) continue;
|
|
384
|
+
seen.add(key);
|
|
385
|
+
result.push(normalized);
|
|
386
|
+
}
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function localAsStringArray(value: unknown): string[] {
|
|
391
|
+
return Array.isArray(value)
|
|
392
|
+
? uniqueStrings(value.filter((item): item is string => typeof item === "string" && item.trim().length > 0))
|
|
393
|
+
: [];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function confidenceFromUnknown(value: unknown): number {
|
|
397
|
+
const parsed =
|
|
398
|
+
typeof value === "number"
|
|
399
|
+
? value
|
|
400
|
+
: typeof value === "string" && value.trim().length > 0
|
|
401
|
+
? Number.parseFloat(value)
|
|
402
|
+
: Number.NaN;
|
|
403
|
+
if (!Number.isFinite(parsed)) return 0;
|
|
404
|
+
return Math.min(1, Math.max(0, parsed));
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function parseCookTriggerClassification(raw: string): CookTriggerClassification | undefined {
|
|
408
|
+
const jsonText = extractJsonObjectFromText(raw);
|
|
409
|
+
if (!jsonText) return undefined;
|
|
410
|
+
let parsed: unknown;
|
|
411
|
+
try {
|
|
412
|
+
parsed = JSON.parse(jsonText);
|
|
413
|
+
} catch {
|
|
414
|
+
return undefined;
|
|
415
|
+
}
|
|
416
|
+
if (!isRecord(parsed)) return undefined;
|
|
417
|
+
const rawDecision = asString(parsed.decision ?? parsed.intent);
|
|
418
|
+
const decision =
|
|
419
|
+
rawDecision === "offer_workflow" || rawDecision === "normal_prompt" || rawDecision === "unclear"
|
|
420
|
+
? rawDecision
|
|
421
|
+
: rawDecision === "route_to_cook"
|
|
422
|
+
? "offer_workflow"
|
|
423
|
+
: undefined;
|
|
424
|
+
if (!decision) return undefined;
|
|
425
|
+
const rawWorkflowBias = asString(parsed.workflow_bias ?? parsed.workflowBias ?? parsed.routing_bias ?? parsed.routingBias);
|
|
426
|
+
const workflowBias =
|
|
427
|
+
rawWorkflowBias === "startup" ||
|
|
428
|
+
rawWorkflowBias === "resume" ||
|
|
429
|
+
rawWorkflowBias === "refocus" ||
|
|
430
|
+
rawWorkflowBias === "next_round" ||
|
|
431
|
+
rawWorkflowBias === "unknown"
|
|
432
|
+
? rawWorkflowBias
|
|
433
|
+
: decision === "offer_workflow" && rawDecision === "route_to_cook"
|
|
434
|
+
? "unknown"
|
|
435
|
+
: "unknown";
|
|
436
|
+
const evidence = localAsStringArray(parsed.evidence);
|
|
437
|
+
const riskFlags = localAsStringArray(parsed.riskFlags ?? parsed.risk_flags);
|
|
438
|
+
const reason = asString(parsed.reason) ?? asString(parsed.rationale) ?? evidence[0] ?? `Classifier returned ${decision}.`;
|
|
439
|
+
const focusHint = asString(parsed.focusHint ?? parsed.focus_hint);
|
|
440
|
+
return {
|
|
441
|
+
decision,
|
|
442
|
+
confidence: confidenceFromUnknown(parsed.confidence),
|
|
443
|
+
workflowBias,
|
|
444
|
+
reason,
|
|
445
|
+
focusHint,
|
|
446
|
+
evidence: evidence.length > 0 ? evidence : [reason],
|
|
447
|
+
riskFlags,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function triggerClassifierFailureModeFromEnv(): "timeout" | "error" | "invalid_output" | undefined {
|
|
452
|
+
const raw = asString(process.env.PI_COMPLETION_TEST_TRIGGER_CLASSIFIER_FAILURE)?.toLowerCase();
|
|
453
|
+
return raw === "timeout" || raw === "error" || raw === "invalid_output" ? raw : undefined;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function triggerClassifierSnapshotPath(): string | undefined {
|
|
457
|
+
return asString(process.env.PI_COMPLETION_TEST_TRIGGER_CLASSIFIER_SNAPSHOT_PATH);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
async function runCookTriggerClassifierSubprocess(
|
|
461
|
+
params: ClassifyCookTriggerIntentWithAgentParams & { prompt: string },
|
|
462
|
+
): Promise<CookTriggerClassifierResult> {
|
|
463
|
+
const cwd = params.ctx.cwd;
|
|
464
|
+
const runCwd = findCompletionRoot(cwd) ?? findRepoRoot(cwd) ?? cwd;
|
|
465
|
+
const modelArg = contextProposalAnalystModelArg(params.ctx.model);
|
|
466
|
+
const systemPromptTemp = await writeTempFile(runCwd, "pi-cook-trigger-classifier-", COOK_TRIGGER_CLASSIFIER_SYSTEM_PROMPT);
|
|
467
|
+
const args: string[] = ["--mode", "json", "-p", "--no-session", "--no-extensions", "--append-system-prompt", systemPromptTemp.filePath];
|
|
468
|
+
if (modelArg) args.push("--model", modelArg);
|
|
469
|
+
args.push(params.prompt);
|
|
470
|
+
const invocation = getPiInvocation(args);
|
|
471
|
+
const liveActivity = createLiveRoleActivity("cook-trigger-classifier");
|
|
472
|
+
const messages: RoleMessage[] = [];
|
|
473
|
+
let stderr = "";
|
|
474
|
+
let timedOut = false;
|
|
475
|
+
try {
|
|
476
|
+
const rawOutput = await new Promise<string | undefined>((resolve) => {
|
|
477
|
+
const proc = spawn(invocation.command, invocation.args, {
|
|
478
|
+
cwd: runCwd,
|
|
479
|
+
env: process.env,
|
|
480
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
481
|
+
shell: false,
|
|
482
|
+
});
|
|
483
|
+
let settled = false;
|
|
484
|
+
let buffer = "";
|
|
485
|
+
const resolveOnce = (value: string | undefined) => {
|
|
486
|
+
if (settled) return;
|
|
487
|
+
settled = true;
|
|
488
|
+
resolve(value);
|
|
489
|
+
};
|
|
490
|
+
const timeoutHandle = setTimeout(() => {
|
|
491
|
+
timedOut = true;
|
|
492
|
+
proc.kill("SIGTERM");
|
|
493
|
+
resolveOnce(undefined);
|
|
494
|
+
}, COOK_TRIGGER_CLASSIFIER_TIMEOUT_MS);
|
|
495
|
+
const processLine = (line: string) => {
|
|
496
|
+
if (!line.trim()) return;
|
|
497
|
+
try {
|
|
498
|
+
const event = JSON.parse(line) as JsonRecord;
|
|
499
|
+
applyLiveRoleEvent(liveActivity, event, messages);
|
|
500
|
+
} catch {
|
|
501
|
+
// ignore malformed lines from the subprocess event stream
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
proc.stdout.on("data", (chunk) => {
|
|
505
|
+
buffer += chunk.toString();
|
|
506
|
+
const lines = buffer.split("\n");
|
|
507
|
+
buffer = lines.pop() ?? "";
|
|
508
|
+
for (const line of lines) processLine(line);
|
|
509
|
+
});
|
|
510
|
+
proc.stderr.on("data", (chunk) => {
|
|
511
|
+
stderr += chunk.toString();
|
|
512
|
+
});
|
|
513
|
+
proc.on("close", (code) => {
|
|
514
|
+
clearTimeout(timeoutHandle);
|
|
515
|
+
if (buffer.trim()) processLine(buffer);
|
|
516
|
+
if (timedOut) return;
|
|
517
|
+
resolveOnce(code === 0 ? liveActivity.lastAssistantText?.trim() || undefined : undefined);
|
|
518
|
+
});
|
|
519
|
+
proc.on("error", () => {
|
|
520
|
+
clearTimeout(timeoutHandle);
|
|
521
|
+
resolveOnce(undefined);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
if (!rawOutput) {
|
|
525
|
+
if (timedOut) {
|
|
526
|
+
return {
|
|
527
|
+
status: "timeout",
|
|
528
|
+
errorMessage: `Trigger classifier timed out after ${COOK_TRIGGER_CLASSIFIER_TIMEOUT_MS}ms.`,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
return { status: "error", errorMessage: stderr.trim() || "Trigger classifier produced no assistant output." };
|
|
532
|
+
}
|
|
533
|
+
const classification = parseCookTriggerClassification(rawOutput);
|
|
534
|
+
if (!classification) {
|
|
535
|
+
return {
|
|
536
|
+
status: "invalid_output",
|
|
537
|
+
rawOutput,
|
|
538
|
+
errorMessage: "Trigger classifier returned invalid JSON output.",
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
return { status: "classified", classification, rawOutput };
|
|
542
|
+
} finally {
|
|
543
|
+
await fsp.rm(systemPromptTemp.dir, { recursive: true, force: true });
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export async function classifyCookTriggerIntentWithAgent(
|
|
548
|
+
params: ClassifyCookTriggerIntentWithAgentParams,
|
|
549
|
+
): Promise<CookTriggerClassifierResult> {
|
|
550
|
+
const recentDiscussion = serializeRecentDiscussionEntries(params.recentEntries);
|
|
551
|
+
const prompt = buildCookTriggerClassifierPrompt({
|
|
552
|
+
projectName: params.projectName,
|
|
553
|
+
inputText: params.inputText,
|
|
554
|
+
recentDiscussion,
|
|
555
|
+
workflowContextLines: params.workflowContextLines,
|
|
556
|
+
});
|
|
557
|
+
const snapshotPath = triggerClassifierSnapshotPath();
|
|
558
|
+
const testFailureMode = triggerClassifierFailureModeFromEnv();
|
|
559
|
+
if (testFailureMode) {
|
|
560
|
+
const result: CookTriggerClassifierResult = {
|
|
561
|
+
status: testFailureMode,
|
|
562
|
+
errorMessage: `Forced trigger classifier ${testFailureMode} for deterministic tests.`,
|
|
563
|
+
};
|
|
564
|
+
maybeWriteCookTriggerClassifierSnapshot(
|
|
565
|
+
{
|
|
566
|
+
projectName: params.projectName,
|
|
567
|
+
inputText: params.inputText,
|
|
568
|
+
recentEntries: params.recentEntries,
|
|
569
|
+
workflowContextLines: params.workflowContextLines ?? [],
|
|
570
|
+
prompt,
|
|
571
|
+
result,
|
|
572
|
+
},
|
|
573
|
+
snapshotPath,
|
|
574
|
+
);
|
|
575
|
+
return result;
|
|
576
|
+
}
|
|
577
|
+
const testOutput = asString(process.env.PI_COMPLETION_TEST_TRIGGER_CLASSIFIER_OUTPUT);
|
|
578
|
+
if (testOutput) {
|
|
579
|
+
const classification = parseCookTriggerClassification(testOutput);
|
|
580
|
+
const result: CookTriggerClassifierResult = classification
|
|
581
|
+
? { status: "classified", classification, rawOutput: testOutput }
|
|
582
|
+
: {
|
|
583
|
+
status: "invalid_output",
|
|
584
|
+
rawOutput: testOutput,
|
|
585
|
+
errorMessage: "Trigger classifier test override did not match the required JSON schema.",
|
|
586
|
+
};
|
|
587
|
+
maybeWriteCookTriggerClassifierSnapshot(
|
|
588
|
+
{
|
|
589
|
+
projectName: params.projectName,
|
|
590
|
+
inputText: params.inputText,
|
|
591
|
+
recentEntries: params.recentEntries,
|
|
592
|
+
workflowContextLines: params.workflowContextLines ?? [],
|
|
593
|
+
prompt,
|
|
594
|
+
result,
|
|
595
|
+
},
|
|
596
|
+
snapshotPath,
|
|
597
|
+
);
|
|
598
|
+
return result;
|
|
599
|
+
}
|
|
600
|
+
try {
|
|
601
|
+
const result = await runCookTriggerClassifierSubprocess({ ...params, prompt });
|
|
602
|
+
maybeWriteCookTriggerClassifierSnapshot(
|
|
603
|
+
{
|
|
604
|
+
projectName: params.projectName,
|
|
605
|
+
inputText: params.inputText,
|
|
606
|
+
recentEntries: params.recentEntries,
|
|
607
|
+
workflowContextLines: params.workflowContextLines ?? [],
|
|
608
|
+
prompt,
|
|
609
|
+
result,
|
|
610
|
+
},
|
|
611
|
+
snapshotPath,
|
|
612
|
+
);
|
|
613
|
+
return result;
|
|
614
|
+
} catch (error) {
|
|
615
|
+
const result: CookTriggerClassifierResult = {
|
|
616
|
+
status: "error",
|
|
617
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
618
|
+
};
|
|
619
|
+
maybeWriteCookTriggerClassifierSnapshot(
|
|
620
|
+
{
|
|
621
|
+
projectName: params.projectName,
|
|
622
|
+
inputText: params.inputText,
|
|
623
|
+
recentEntries: params.recentEntries,
|
|
624
|
+
workflowContextLines: params.workflowContextLines ?? [],
|
|
625
|
+
prompt,
|
|
626
|
+
result,
|
|
627
|
+
},
|
|
628
|
+
snapshotPath,
|
|
629
|
+
);
|
|
630
|
+
return result;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
327
634
|
export async function loadAgentDefinition(cwd: string, role: CompletionRole): Promise<AgentDefinition> {
|
|
328
635
|
const projectAgent = walkUpForDir(cwd, [".pi", "agents", `${role}.md`]);
|
|
329
636
|
const packageAgent = PACKAGE_AGENTS_DIR ? path.join(PACKAGE_AGENTS_DIR, `${role}.md`) : undefined;
|
|
@@ -85,3 +85,117 @@ export type CompletionStatusSurface = {
|
|
|
85
85
|
liveStateDeltas?: string[];
|
|
86
86
|
liveDetailsLines?: string[];
|
|
87
87
|
};
|
|
88
|
+
|
|
89
|
+
export type NaturalLanguageCookTriggerMode = "off" | "assist" | "router" | "auto";
|
|
90
|
+
export type CookTriggerClassifierDecision = "offer_workflow" | "normal_prompt" | "unclear";
|
|
91
|
+
export type CookTriggerWorkflowBias = "startup" | "resume" | "refocus" | "next_round" | "unknown";
|
|
92
|
+
|
|
93
|
+
export type CookTriggerClassification = {
|
|
94
|
+
decision: CookTriggerClassifierDecision;
|
|
95
|
+
confidence: number;
|
|
96
|
+
workflowBias: CookTriggerWorkflowBias;
|
|
97
|
+
reason: string;
|
|
98
|
+
focusHint?: string;
|
|
99
|
+
evidence: string[];
|
|
100
|
+
riskFlags: string[];
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export type CookTriggerConfirmationAction = "start_workflow" | "send_as_normal_chat" | "cancel";
|
|
104
|
+
export type CookTriggerClarificationAction =
|
|
105
|
+
| "route_startup"
|
|
106
|
+
| "route_resume"
|
|
107
|
+
| "route_refocus"
|
|
108
|
+
| "route_next_round"
|
|
109
|
+
| "send_as_normal_chat"
|
|
110
|
+
| "cancel";
|
|
111
|
+
export type CookTriggerRecoveryAction = "retry_routing" | "send_as_normal_chat" | "cancel";
|
|
112
|
+
export type CookTriggerAdoptedArtifactKind = "recent_plan" | "repo_markdown";
|
|
113
|
+
|
|
114
|
+
export type CookTriggerConfirmationActionItem = {
|
|
115
|
+
id: CookTriggerConfirmationAction;
|
|
116
|
+
label: string;
|
|
117
|
+
description: string;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export type CookTriggerClarificationActionItem = {
|
|
121
|
+
id: CookTriggerClarificationAction;
|
|
122
|
+
label: string;
|
|
123
|
+
description: string;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export type CookTriggerConfirmationLayout = {
|
|
127
|
+
title: string;
|
|
128
|
+
intro: string;
|
|
129
|
+
evidenceHeading?: string;
|
|
130
|
+
evidenceBody?: string;
|
|
131
|
+
riskHeading?: string;
|
|
132
|
+
riskBody?: string;
|
|
133
|
+
focusHintHeading?: string;
|
|
134
|
+
focusHintBody?: string;
|
|
135
|
+
actionsHeading: string;
|
|
136
|
+
actions: CookTriggerConfirmationActionItem[];
|
|
137
|
+
footer: string;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export type CookTriggerClarificationCapsule = {
|
|
141
|
+
goal?: string;
|
|
142
|
+
scope?: string[];
|
|
143
|
+
nonGoal?: string[];
|
|
144
|
+
doneWhen?: string[];
|
|
145
|
+
selectedWorkflowBias: CookTriggerWorkflowBias;
|
|
146
|
+
reason: string;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export type CookTriggerAdoptedArtifact = {
|
|
150
|
+
kind: CookTriggerAdoptedArtifactKind;
|
|
151
|
+
basis: "explicit_user_adoption";
|
|
152
|
+
title: string;
|
|
153
|
+
path?: string;
|
|
154
|
+
preview?: string;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export type CookNaturalLanguageHandoff = {
|
|
158
|
+
preferredRoutingBias?: CookTriggerWorkflowBias;
|
|
159
|
+
triggerText?: string;
|
|
160
|
+
hintText?: string;
|
|
161
|
+
clarificationCapsule?: CookTriggerClarificationCapsule;
|
|
162
|
+
adoptedArtifact?: CookTriggerAdoptedArtifact;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export type CookTriggerClarificationLayout = {
|
|
166
|
+
title: string;
|
|
167
|
+
intro: string;
|
|
168
|
+
currentMissionHeading?: string;
|
|
169
|
+
currentMissionBody?: string;
|
|
170
|
+
candidateMissionHeading?: string;
|
|
171
|
+
candidateMissionBody?: string;
|
|
172
|
+
adoptedArtifactHeading?: string;
|
|
173
|
+
adoptedArtifactBody?: string;
|
|
174
|
+
actionsHeading: string;
|
|
175
|
+
actions: CookTriggerClarificationActionItem[];
|
|
176
|
+
footer: string;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export type CookTriggerRecoveryActionItem = {
|
|
180
|
+
id: CookTriggerRecoveryAction;
|
|
181
|
+
label: string;
|
|
182
|
+
description: string;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export type CookTriggerRecoveryLayout = {
|
|
186
|
+
title: string;
|
|
187
|
+
intro: string;
|
|
188
|
+
failureHeading?: string;
|
|
189
|
+
failureBody?: string;
|
|
190
|
+
actionsHeading: string;
|
|
191
|
+
actions: CookTriggerRecoveryActionItem[];
|
|
192
|
+
footer: string;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export type CookTriggerDecision = {
|
|
196
|
+
mode: NaturalLanguageCookTriggerMode;
|
|
197
|
+
action: "continue" | "handled" | "routed_to_cook";
|
|
198
|
+
reason: string;
|
|
199
|
+
classification?: CookTriggerClassification;
|
|
200
|
+
bypassReason?: string;
|
|
201
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linimin/pi-letscook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.52",
|
|
4
4
|
"description": "Pi package for long-running completion workflows with canonical .agent state, role-based subagents, continuity, and verification helpers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|