takomi 2.1.44 → 2.1.45
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/.pi/README.md +4 -3
- package/.pi/extensions/oauth-router/commands.ts +66 -35
- package/.pi/extensions/oauth-router/index.ts +51 -7
- package/.pi/extensions/oauth-router/report-ui.ts +205 -0
- package/.pi/extensions/takomi-context-manager/diagnostics-tools.ts +41 -3
- package/.pi/extensions/takomi-context-manager/diagnostics.ts +26 -0
- package/.pi/extensions/takomi-context-manager/index.ts +3 -2
- package/.pi/extensions/takomi-context-manager/model-policy-gate.ts +36 -15
- package/.pi/extensions/takomi-context-manager/policy-tools.ts +93 -42
- package/.pi/extensions/takomi-context-manager/skill-categories.d.ts +11 -0
- package/.pi/extensions/takomi-context-manager/skill-categories.js +212 -0
- package/.pi/extensions/takomi-context-manager/skill-registry.ts +179 -8
- package/.pi/extensions/takomi-context-manager/skill-tools.ts +208 -103
- package/.pi/extensions/takomi-context-manager/tool-renderers.ts +112 -0
- package/.pi/extensions/takomi-context-manager/types.ts +6 -0
- package/.pi/extensions/takomi-runtime/commands.ts +45 -12
- package/.pi/extensions/takomi-runtime/gate-provenance.ts +24 -0
- package/.pi/extensions/takomi-runtime/index.ts +111 -42
- package/.pi/extensions/takomi-runtime/routing-policy.ts +14 -2
- package/.pi/extensions/takomi-runtime/takomi-stats.js +46 -26
- package/.pi/extensions/takomi-runtime/tool-renderers.ts +234 -0
- package/.pi/extensions/takomi-runtime/workflow-catalog.ts +54 -0
- package/.pi/extensions/takomi-subagents/agents.ts +4 -0
- package/.pi/extensions/takomi-subagents/async-lifecycle.ts +401 -0
- package/.pi/extensions/takomi-subagents/detached-results.ts +940 -0
- package/.pi/extensions/takomi-subagents/index.ts +46 -1
- package/.pi/extensions/takomi-subagents/native-render.ts +250 -188
- package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +55 -46
- package/.pi/extensions/takomi-subagents/pi-subagents-internal.ts +11 -5
- package/.pi/extensions/takomi-subagents/result-heartbeat.ts +55 -0
- package/.pi/extensions/takomi-subagents/subagent-ux.ts +162 -0
- package/.pi/extensions/takomi-subagents/tool-runner.ts +158 -28
- package/.pi/takomi/model-routing.md +282 -3
- package/assets/.agent/skills/shared-resend-portfolio/SKILL.md +124 -0
- package/package.json +4 -3
- package/src/pi-takomi-core/types.ts +10 -0
- package/src/pi-takomi-core/workflows.ts +86 -45
- package/src/skills-catalog.js +2 -202
- package/src/skills-installer.js +4 -1
|
@@ -3,13 +3,17 @@ import path from "node:path";
|
|
|
3
3
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import type { TakomiLaunchMode, TakomiThinkingLevel } from "../../../src/pi-takomi-core";
|
|
5
5
|
import { loadTakomiProfile } from "../takomi-runtime/profile";
|
|
6
|
+
import { hasUserGateAutoProvenance } from "../takomi-runtime/gate-provenance";
|
|
6
7
|
import { applyTakomiRoutingDefaults, loadTakomiModelRoutingSnapshot } from "../takomi-runtime/model-routing-defaults";
|
|
7
8
|
import { resolveAgentName } from "./agent-aliases";
|
|
8
9
|
import { discoverTakomiAgents, type TakomiAgentConfig, type TakomiAgentScope } from "./agents";
|
|
9
10
|
import { createTakomiDelegationPlan, renderTakomiDelegationPlan } from "./delegation-plan";
|
|
11
|
+
import { rememberDetachedLaunch, resolveDetachedStatusResult } from "./detached-results";
|
|
10
12
|
import { createTakomiPiSubagentsEngine } from "./pi-subagents-engine";
|
|
13
|
+
import { createTakomiUxTasks, withTakomiUxDetails } from "./subagent-ux";
|
|
11
14
|
|
|
12
15
|
type ChecklistItem = string | { text: string; done?: boolean };
|
|
16
|
+
export type TakomiAcceptanceInput = false | "auto" | "none" | "attested" | "checked" | "verified" | "reviewed" | Record<string, unknown>;
|
|
13
17
|
|
|
14
18
|
export type TakomiSubagentToolTask = {
|
|
15
19
|
agent: string;
|
|
@@ -22,6 +26,7 @@ export type TakomiSubagentToolTask = {
|
|
|
22
26
|
conversationId?: string;
|
|
23
27
|
cwd?: string;
|
|
24
28
|
checklist?: ChecklistItem[];
|
|
29
|
+
acceptance?: TakomiAcceptanceInput;
|
|
25
30
|
};
|
|
26
31
|
|
|
27
32
|
export type TakomiSubagentToolParams = Partial<TakomiSubagentToolTask> & {
|
|
@@ -50,10 +55,18 @@ const MAX_PARALLEL_TASKS = 8;
|
|
|
50
55
|
const HARD_STOP_TTL_MS = 10 * 60 * 1000;
|
|
51
56
|
const ENGINES = new WeakMap<ExtensionAPI, ReturnType<typeof createTakomiPiSubagentsEngine>>();
|
|
52
57
|
|
|
58
|
+
type UserTurnMarker = {
|
|
59
|
+
sessionId?: string;
|
|
60
|
+
count: number;
|
|
61
|
+
lastEntryId?: string;
|
|
62
|
+
entryIds: string[];
|
|
63
|
+
};
|
|
64
|
+
|
|
53
65
|
type HardStopRecord = {
|
|
54
66
|
at: number;
|
|
55
67
|
reason: string;
|
|
56
68
|
message: string;
|
|
69
|
+
userTurnMarker?: UserTurnMarker;
|
|
57
70
|
};
|
|
58
71
|
|
|
59
72
|
const RECENT_HARD_STOPS = new WeakMap<ExtensionAPI, Map<string, HardStopRecord>>();
|
|
@@ -66,6 +79,11 @@ function getEngine(pi: ExtensionAPI): ReturnType<typeof createTakomiPiSubagentsE
|
|
|
66
79
|
return engine;
|
|
67
80
|
}
|
|
68
81
|
|
|
82
|
+
export function invalidateTakomiPiSubagentsEngine(pi: ExtensionAPI): void {
|
|
83
|
+
ENGINES.get(pi)?.dispose();
|
|
84
|
+
ENGINES.delete(pi);
|
|
85
|
+
}
|
|
86
|
+
|
|
69
87
|
function textResult<TDetails extends Record<string, unknown>>(text: string, details: TDetails, isError?: boolean) {
|
|
70
88
|
return { content: [{ type: "text" as const, text }], details, isError };
|
|
71
89
|
}
|
|
@@ -78,6 +96,10 @@ function hostTrustsProjectAgents(): boolean {
|
|
|
78
96
|
return /^(1|true|yes)$/i.test(process.env.TAKOMI_TRUST_PROJECT_AGENTS || "");
|
|
79
97
|
}
|
|
80
98
|
|
|
99
|
+
function isProjectAgentApprovalHardStop(record: HardStopRecord | undefined): boolean {
|
|
100
|
+
return record?.reason === "project-agent-approval-required" || record?.reason === "project-agent-denied";
|
|
101
|
+
}
|
|
102
|
+
|
|
81
103
|
function hardStopStore(pi: ExtensionAPI): Map<string, HardStopRecord> {
|
|
82
104
|
const existing = RECENT_HARD_STOPS.get(pi);
|
|
83
105
|
if (existing) return existing;
|
|
@@ -86,22 +108,78 @@ function hardStopStore(pi: ExtensionAPI): Map<string, HardStopRecord> {
|
|
|
86
108
|
return next;
|
|
87
109
|
}
|
|
88
110
|
|
|
111
|
+
type TakomiRunMode = "single" | "parallel" | "chain";
|
|
112
|
+
|
|
113
|
+
function compactChecklistForFingerprint(checklist: ChecklistItem[] | undefined): Array<{ text: string; done: boolean }> | undefined {
|
|
114
|
+
if (!checklist?.length) return undefined;
|
|
115
|
+
return checklist.map((item) => typeof item === "string" ? { text: item, done: false } : { text: item.text, done: item.done ?? false });
|
|
116
|
+
}
|
|
117
|
+
|
|
89
118
|
function compactTaskForFingerprint(task: TakomiSubagentToolTask): Record<string, unknown> {
|
|
90
119
|
return {
|
|
91
120
|
agent: task.agent,
|
|
92
121
|
task: task.task,
|
|
93
|
-
workflow: task.workflow,
|
|
94
|
-
skills: task.skills,
|
|
95
|
-
model: task.model,
|
|
96
|
-
fallbackModels: task.fallbackModels,
|
|
122
|
+
workflow: task.workflow || undefined,
|
|
123
|
+
skills: task.skills?.length ? task.skills : undefined,
|
|
124
|
+
model: task.model || undefined,
|
|
125
|
+
fallbackModels: task.fallbackModels?.length ? task.fallbackModels : undefined,
|
|
97
126
|
thinking: task.thinking,
|
|
98
|
-
conversationId: task.conversationId,
|
|
127
|
+
conversationId: task.conversationId || undefined,
|
|
99
128
|
cwd: task.cwd,
|
|
129
|
+
checklist: compactChecklistForFingerprint(task.checklist),
|
|
130
|
+
acceptance: task.acceptance,
|
|
100
131
|
};
|
|
101
132
|
}
|
|
102
133
|
|
|
103
|
-
|
|
104
|
-
|
|
134
|
+
const IMPLICIT_CONTEXT = "implicit" as const;
|
|
135
|
+
type CanonicalContext = typeof IMPLICIT_CONTEXT | "fresh" | "fork";
|
|
136
|
+
|
|
137
|
+
function canonicalContextForFingerprint(context: TakomiSubagentToolParams["context"]): CanonicalContext {
|
|
138
|
+
// Omission delegates context selection to native pi-subagents, whose built-in
|
|
139
|
+
// and settings defaults are authoritative. Never approximate that resolution
|
|
140
|
+
// with Takomi-only discovery: implicit input is its own approval semantic.
|
|
141
|
+
return context ?? IMPLICIT_CONTEXT;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function canonicalContextsForFingerprint(
|
|
145
|
+
params: TakomiSubagentToolParams,
|
|
146
|
+
tasks: TakomiSubagentToolTask[],
|
|
147
|
+
): CanonicalContext[] {
|
|
148
|
+
const context = canonicalContextForFingerprint(params.context);
|
|
149
|
+
// `context` is a global override. When omitted, each native task resolves its
|
|
150
|
+
// own default, but all retain the distinct implicit-input sentinel here.
|
|
151
|
+
return tasks.map(() => context);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function effectiveConcurrencyForFingerprint(mode: TakomiRunMode, concurrency: number | undefined): number | undefined {
|
|
155
|
+
if (mode !== "parallel") return undefined;
|
|
156
|
+
return typeof concurrency === "number" && Number.isInteger(concurrency) && concurrency >= 1 ? concurrency : 4;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function createRunFingerprint(
|
|
160
|
+
rootCwd: string,
|
|
161
|
+
mode: TakomiRunMode,
|
|
162
|
+
tasks: TakomiSubagentToolTask[],
|
|
163
|
+
params: TakomiSubagentToolParams,
|
|
164
|
+
agentScope: TakomiAgentScope,
|
|
165
|
+
): string {
|
|
166
|
+
const context = canonicalContextForFingerprint(params.context);
|
|
167
|
+
return JSON.stringify({
|
|
168
|
+
rootCwd,
|
|
169
|
+
mode,
|
|
170
|
+
tasks: tasks.map(compactTaskForFingerprint),
|
|
171
|
+
launch: {
|
|
172
|
+
context: {
|
|
173
|
+
global: context,
|
|
174
|
+
perTask: canonicalContextsForFingerprint(params, tasks),
|
|
175
|
+
},
|
|
176
|
+
async: params.async === true,
|
|
177
|
+
concurrency: effectiveConcurrencyForFingerprint(mode, params.concurrency),
|
|
178
|
+
worktree: mode === "parallel" && params.worktree === true,
|
|
179
|
+
clarify: params.clarify === true,
|
|
180
|
+
agentScope,
|
|
181
|
+
},
|
|
182
|
+
});
|
|
105
183
|
}
|
|
106
184
|
|
|
107
185
|
function hardStopResult(message: string, details: Record<string, unknown>) {
|
|
@@ -112,8 +190,34 @@ function hardStopResult(message: string, details: Record<string, unknown>) {
|
|
|
112
190
|
].join("\n"), { ...details, takomiHardStop: true }, true);
|
|
113
191
|
}
|
|
114
192
|
|
|
115
|
-
function rememberHardStop(
|
|
116
|
-
|
|
193
|
+
function rememberHardStop(
|
|
194
|
+
pi: ExtensionAPI,
|
|
195
|
+
fingerprint: string,
|
|
196
|
+
reason: string,
|
|
197
|
+
message: string,
|
|
198
|
+
userTurnMarker?: UserTurnMarker,
|
|
199
|
+
): void {
|
|
200
|
+
hardStopStore(pi).set(fingerprint, { at: Date.now(), reason, message, userTurnMarker });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function readUserTurnMarker(ctx: ExtensionContext): UserTurnMarker {
|
|
204
|
+
const userEntries = ctx.sessionManager.getEntries().filter((entry) => entry.type === "message" && entry.message.role === "user");
|
|
205
|
+
const entryIds = userEntries.map((entry) => entry.id);
|
|
206
|
+
return {
|
|
207
|
+
sessionId: ctx.sessionManager.getSessionId(),
|
|
208
|
+
count: userEntries.length,
|
|
209
|
+
lastEntryId: entryIds.at(-1),
|
|
210
|
+
entryIds,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function hasStrictlyNewerUserTurn(record: HardStopRecord, current: UserTurnMarker): boolean {
|
|
215
|
+
const recorded = record.userTurnMarker;
|
|
216
|
+
if (!recorded || recorded.sessionId !== current.sessionId || current.count <= recorded.count) return false;
|
|
217
|
+
if (!recorded.lastEntryId) return true;
|
|
218
|
+
|
|
219
|
+
const recordedTurnIndex = current.entryIds.indexOf(recorded.lastEntryId);
|
|
220
|
+
return recordedTurnIndex >= 0 && recordedTurnIndex < current.entryIds.length - 1;
|
|
117
221
|
}
|
|
118
222
|
|
|
119
223
|
function consumeExpiredHardStop(pi: ExtensionAPI, fingerprint: string): HardStopRecord | undefined {
|
|
@@ -146,12 +250,6 @@ async function resolveRelativeCwd(root: string, value: string | undefined, label
|
|
|
146
250
|
return realCandidate;
|
|
147
251
|
}
|
|
148
252
|
|
|
149
|
-
async function validateTaskCwds(root: string, tasks: TakomiSubagentToolTask[]): Promise<void> {
|
|
150
|
-
for (const [index, task] of tasks.entries()) {
|
|
151
|
-
await resolveRelativeCwd(root, task.cwd, `tasks[${index}].cwd`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
253
|
function getTextContent(result: any): string {
|
|
156
254
|
return (result?.content ?? [])
|
|
157
255
|
.map((item: any) => item?.type === "text" && typeof item.text === "string" ? item.text : "")
|
|
@@ -234,6 +332,7 @@ function resolveTasks(params: TakomiSubagentToolParams): TakomiSubagentToolTask[
|
|
|
234
332
|
conversationId: params.conversationId,
|
|
235
333
|
cwd: undefined,
|
|
236
334
|
checklist: params.checklist,
|
|
335
|
+
acceptance: params.acceptance,
|
|
237
336
|
}];
|
|
238
337
|
}
|
|
239
338
|
return [];
|
|
@@ -255,6 +354,10 @@ export async function executeTakomiSubagentTool(
|
|
|
255
354
|
}
|
|
256
355
|
const profile = await loadTakomiProfile(rootCwd);
|
|
257
356
|
const runtimeLaunchMode = readRuntimeLaunchMode(ctx);
|
|
357
|
+
const userTurnMarker = readUserTurnMarker(ctx);
|
|
358
|
+
// Auto launch mode may come from a model, profile, default, or restored
|
|
359
|
+
// runtime state. None of those are project-agent authorization.
|
|
360
|
+
const userGateAutoAuthorized = hasUserGateAutoProvenance(ctx.sessionManager.getEntries());
|
|
258
361
|
const agentScope = params.agentScope ?? "both";
|
|
259
362
|
|
|
260
363
|
if (params.action) {
|
|
@@ -266,10 +369,13 @@ export async function executeTakomiSubagentTool(
|
|
|
266
369
|
onUpdate as any,
|
|
267
370
|
ctx,
|
|
268
371
|
);
|
|
372
|
+
const resolvedResult = params.action === "status"
|
|
373
|
+
? await resolveDetachedStatusResult(pi, params, nativeResult)
|
|
374
|
+
: nativeResult;
|
|
269
375
|
return {
|
|
270
|
-
...
|
|
376
|
+
...resolvedResult,
|
|
271
377
|
details: {
|
|
272
|
-
...(
|
|
378
|
+
...(resolvedResult?.details ?? {}),
|
|
273
379
|
takomi: {
|
|
274
380
|
action: params.action,
|
|
275
381
|
agentScope,
|
|
@@ -289,11 +395,11 @@ export async function executeTakomiSubagentTool(
|
|
|
289
395
|
let tasks: TakomiSubagentToolTask[];
|
|
290
396
|
try {
|
|
291
397
|
const rawTasks = resolveTasks(params);
|
|
292
|
-
await
|
|
293
|
-
tasks = rawTasks.map((task) => applyTakomiRoutingDefaults({
|
|
398
|
+
tasks = await Promise.all(rawTasks.map(async (task, index) => applyTakomiRoutingDefaults({
|
|
294
399
|
...task,
|
|
295
400
|
agent: resolveAgentName(task.agent, byName),
|
|
296
|
-
|
|
401
|
+
cwd: await resolveRelativeCwd(rootCwd, task.cwd, `tasks[${index}].cwd`),
|
|
402
|
+
}, routingSnapshot)));
|
|
297
403
|
} catch (error) {
|
|
298
404
|
const message = error instanceof Error ? error.message : String(error);
|
|
299
405
|
return textResult(message, { results: [], availableAgents: agents.map((agent) => agent.name), agentScope }, true);
|
|
@@ -310,17 +416,23 @@ export async function executeTakomiSubagentTool(
|
|
|
310
416
|
return textResult(`Too many parallel tasks (${tasks.length}). Max is ${MAX_PARALLEL_TASKS}.`, { results: [], agentScope }, true);
|
|
311
417
|
}
|
|
312
418
|
|
|
313
|
-
const fingerprint = createRunFingerprint(rootCwd, mode, tasks);
|
|
419
|
+
const fingerprint = createRunFingerprint(rootCwd, mode, tasks, params, agentScope);
|
|
420
|
+
const projectAgentsAuthorized = userGateAutoAuthorized || hostTrustsProjectAgents();
|
|
314
421
|
const recentHardStop = consumeExpiredHardStop(pi, fingerprint);
|
|
315
|
-
|
|
422
|
+
const authorizationOverridesHardStop = projectAgentsAuthorized && isProjectAgentApprovalHardStop(recentHardStop);
|
|
423
|
+
const consumesReviewGate = recentHardStop?.reason === "review-gate"
|
|
424
|
+
&& params.confirmLaunch === true
|
|
425
|
+
&& params.previewOnly !== true
|
|
426
|
+
&& hasStrictlyNewerUserTurn(recentHardStop, userTurnMarker);
|
|
427
|
+
if (recentHardStop && !authorizationOverridesHardStop && !consumesReviewGate) {
|
|
316
428
|
return hardStopResult(
|
|
317
429
|
`Subagent launch blocked: the same request was already stopped (${recentHardStop.reason}).\n${recentHardStop.message}`,
|
|
318
430
|
{ results: [], availableAgents: agents.map((agent) => agent.name), agentScope, mode, blockedAt: recentHardStop.at, reason: recentHardStop.reason },
|
|
319
431
|
);
|
|
320
432
|
}
|
|
433
|
+
if (authorizationOverridesHardStop || consumesReviewGate) hardStopStore(pi).delete(fingerprint);
|
|
321
434
|
|
|
322
|
-
|
|
323
|
-
if (!projectAgentsTrusted && hasProjectAgents(tasks, byName)) {
|
|
435
|
+
if (!projectAgentsAuthorized && hasProjectAgents(tasks, byName)) {
|
|
324
436
|
const names = tasks.map((task) => byName.get(task.agent)).filter((agent): agent is TakomiAgentConfig => agent?.source === "project").map((agent) => agent.name);
|
|
325
437
|
const uniqueNames = [...new Set(names)].join(", ");
|
|
326
438
|
if (!ctx.hasUI) {
|
|
@@ -356,9 +468,9 @@ export async function executeTakomiSubagentTool(
|
|
|
356
468
|
if (params.previewOnly) {
|
|
357
469
|
return textResult(renderTakomiDelegationPlan(plan), { plan, availableAgents: agents.map((agent) => agent.name), agentScope, mode });
|
|
358
470
|
}
|
|
359
|
-
if (plan.launchMode === "manual" && !
|
|
471
|
+
if (plan.launchMode === "manual" && !consumesReviewGate) {
|
|
360
472
|
const message = `${renderTakomiDelegationPlan(plan)}\n\nReview gate is awaiting explicit user approval.`;
|
|
361
|
-
rememberHardStop(pi, fingerprint, "review-gate", "Review gate displayed a delegation plan and paused before launch.");
|
|
473
|
+
rememberHardStop(pi, fingerprint, "review-gate", "Review gate displayed a delegation plan and paused before launch.", userTurnMarker);
|
|
362
474
|
return hardStopResult(message, { plan, availableAgents: agents.map((agent) => agent.name), agentScope, mode });
|
|
363
475
|
}
|
|
364
476
|
try {
|
|
@@ -367,15 +479,33 @@ export async function executeTakomiSubagentTool(
|
|
|
367
479
|
: mode === "parallel"
|
|
368
480
|
? { ...params, cwd: rootCwd, tasks, agentScope }
|
|
369
481
|
: { ...params, cwd: rootCwd, chain: tasks, agentScope };
|
|
482
|
+
const uxTasks = createTakomiUxTasks(tasks);
|
|
483
|
+
const nativeOnUpdate = onUpdate
|
|
484
|
+
? (partial: any) => onUpdate({
|
|
485
|
+
...partial,
|
|
486
|
+
details: withTakomiUxDetails(partial?.details, uxTasks),
|
|
487
|
+
})
|
|
488
|
+
: undefined;
|
|
370
489
|
|
|
371
490
|
const nativeResult: any = await engine.execute(
|
|
372
491
|
"takomi-tool",
|
|
373
492
|
nativeParams,
|
|
374
493
|
signal,
|
|
375
|
-
|
|
494
|
+
nativeOnUpdate as any,
|
|
376
495
|
ctx,
|
|
377
496
|
);
|
|
378
497
|
|
|
498
|
+
if (params.async === true) {
|
|
499
|
+
await rememberDetachedLaunch(
|
|
500
|
+
pi,
|
|
501
|
+
nativeResult,
|
|
502
|
+
uxTasks,
|
|
503
|
+
ctx,
|
|
504
|
+
rootCwd,
|
|
505
|
+
mode === "single" ? tasks[0]?.cwd ?? rootCwd : rootCwd,
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
|
|
379
509
|
const takomi = {
|
|
380
510
|
plan,
|
|
381
511
|
agentScope,
|
|
@@ -390,7 +520,7 @@ export async function executeTakomiSubagentTool(
|
|
|
390
520
|
return {
|
|
391
521
|
...nativeResult,
|
|
392
522
|
details: {
|
|
393
|
-
...(nativeResult?.details
|
|
523
|
+
...withTakomiUxDetails(nativeResult?.details, uxTasks),
|
|
394
524
|
takomi,
|
|
395
525
|
},
|
|
396
526
|
};
|
|
@@ -1,3 +1,282 @@
|
|
|
1
|
-
# Takomi Model Routing Policy
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Takomi Model Routing Policy
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Choose the cheapest route likely to complete the task correctly.
|
|
6
|
+
|
|
7
|
+
When performance is close, prefer the stronger model at lower effort over a weaker model at extreme effort.
|
|
8
|
+
|
|
9
|
+
## Core routing rule
|
|
10
|
+
|
|
11
|
+
* **Sol** decides what should be done.
|
|
12
|
+
* **Terra** executes a clear direction.
|
|
13
|
+
* **Luna** handles bounded, repetitive, or parallel work.
|
|
14
|
+
* **Gemini Flash through the Antigravity CLI** explores visual directions. Antigravity is an external CLI execution route, not a model provider.
|
|
15
|
+
* **GPT-5.5** is a specialist fallback.
|
|
16
|
+
|
|
17
|
+
Route by task shape, not task length. A short ambiguous task may require Sol. A long clear task may be better for Terra.
|
|
18
|
+
|
|
19
|
+
## Default routes
|
|
20
|
+
|
|
21
|
+
### Sol Low — Intelligent default
|
|
22
|
+
|
|
23
|
+
Use for:
|
|
24
|
+
|
|
25
|
+
* vague or incomplete instructions
|
|
26
|
+
* normal tasks requiring judgment
|
|
27
|
+
* product thinking
|
|
28
|
+
* UI direction
|
|
29
|
+
* codebase exploration
|
|
30
|
+
* ordinary debugging
|
|
31
|
+
* research and synthesis
|
|
32
|
+
* reviewing plans or implementations
|
|
33
|
+
|
|
34
|
+
### Sol Medium — Serious default brain
|
|
35
|
+
|
|
36
|
+
Use for:
|
|
37
|
+
|
|
38
|
+
* architecture
|
|
39
|
+
* serious planning
|
|
40
|
+
* ambiguous implementation
|
|
41
|
+
* design-heavy product work
|
|
42
|
+
* cross-file changes requiring judgment
|
|
43
|
+
* difficult debugging
|
|
44
|
+
* important knowledge work
|
|
45
|
+
* final review of medium-risk work
|
|
46
|
+
|
|
47
|
+
### Sol High — Senior architect and reviewer
|
|
48
|
+
|
|
49
|
+
Use for:
|
|
50
|
+
|
|
51
|
+
* major architecture decisions
|
|
52
|
+
* hard debugging
|
|
53
|
+
* security-sensitive logic
|
|
54
|
+
* regression hunting
|
|
55
|
+
* high-risk refactors
|
|
56
|
+
* final deep review
|
|
57
|
+
* expensive failure cases
|
|
58
|
+
|
|
59
|
+
### Sol Max — Critical escalation
|
|
60
|
+
|
|
61
|
+
Use only for:
|
|
62
|
+
|
|
63
|
+
* critical security work
|
|
64
|
+
* severe ambiguity
|
|
65
|
+
* extremely difficult debugging
|
|
66
|
+
* final review of high-risk changes
|
|
67
|
+
* cases where failure costs far more than model usage
|
|
68
|
+
|
|
69
|
+
### Terra High — Default serious coder
|
|
70
|
+
|
|
71
|
+
Use for:
|
|
72
|
+
|
|
73
|
+
* substantial but clear implementation
|
|
74
|
+
* repository work across several files
|
|
75
|
+
* frontend and backend implementation
|
|
76
|
+
* tests and ordinary debugging
|
|
77
|
+
* implementing an established product or UI direction
|
|
78
|
+
* normal serious coding
|
|
79
|
+
|
|
80
|
+
### Terra Max — Long-horizon implementation engine
|
|
81
|
+
|
|
82
|
+
Use for:
|
|
83
|
+
|
|
84
|
+
* long autonomous coding tasks
|
|
85
|
+
* large clear refactors
|
|
86
|
+
* complex implementations with known requirements
|
|
87
|
+
* tasks where Terra High loses coherence
|
|
88
|
+
* cost-sensitive alternatives to Sol High or Max
|
|
89
|
+
|
|
90
|
+
### Luna Medium — Fast junior executor
|
|
91
|
+
|
|
92
|
+
Use for:
|
|
93
|
+
|
|
94
|
+
* small explicit edits
|
|
95
|
+
* boilerplate
|
|
96
|
+
* documentation
|
|
97
|
+
* simple tests
|
|
98
|
+
* renaming
|
|
99
|
+
* formatting
|
|
100
|
+
* repetitive transformations
|
|
101
|
+
* tightly scoped fixes
|
|
102
|
+
|
|
103
|
+
### Luna High — Parallel execution engine
|
|
104
|
+
|
|
105
|
+
Use for:
|
|
106
|
+
|
|
107
|
+
* bounded implementation
|
|
108
|
+
* parallel sub-agents
|
|
109
|
+
* executing a written plan
|
|
110
|
+
* repetitive cross-file changes
|
|
111
|
+
* medium tasks with clear acceptance criteria
|
|
112
|
+
* high-volume work that will be reviewed
|
|
113
|
+
|
|
114
|
+
### GPT-5.5 — Specialist fallback
|
|
115
|
+
|
|
116
|
+
Use only for:
|
|
117
|
+
|
|
118
|
+
* logic-heavy comparisons
|
|
119
|
+
* regression hunting
|
|
120
|
+
* prompts already tuned for GPT-5.5
|
|
121
|
+
* adversarial second opinions
|
|
122
|
+
|
|
123
|
+
Do not use GPT-5.5 as the default architect, coder, or designer.
|
|
124
|
+
|
|
125
|
+
### Gemini 3.5 Flash through Antigravity CLI — Visual exploration specialist
|
|
126
|
+
|
|
127
|
+
Invoke Gemini 3.5 Flash through the Antigravity CLI. Do not interpret Antigravity as a provider name.
|
|
128
|
+
|
|
129
|
+
Use for:
|
|
130
|
+
|
|
131
|
+
* rapid UI concepts
|
|
132
|
+
* visual exploration
|
|
133
|
+
* motion-graphics ideas
|
|
134
|
+
* reference-driven design
|
|
135
|
+
* multimodal analysis
|
|
136
|
+
* generating several creative directions
|
|
137
|
+
|
|
138
|
+
Do not use it as the default long-horizon repository agent.
|
|
139
|
+
|
|
140
|
+
## Role routing
|
|
141
|
+
|
|
142
|
+
### Architect
|
|
143
|
+
|
|
144
|
+
* Normal planning: Sol Low
|
|
145
|
+
* Serious architecture: Sol Medium
|
|
146
|
+
* High-risk architecture: Sol High
|
|
147
|
+
* Critical architecture or security: Sol Max
|
|
148
|
+
|
|
149
|
+
### Coder
|
|
150
|
+
|
|
151
|
+
* Small explicit task: Luna Medium
|
|
152
|
+
* Bounded or parallel task: Luna High
|
|
153
|
+
* Normal serious implementation: Terra High
|
|
154
|
+
* Long clear implementation: Terra Max
|
|
155
|
+
* Unclear implementation: Sol Medium
|
|
156
|
+
* High-risk implementation: Sol High
|
|
157
|
+
|
|
158
|
+
### Orchestrator
|
|
159
|
+
|
|
160
|
+
* Product direction or UX decisions: Sol Low or Medium
|
|
161
|
+
* Scaffold plus UI with ambiguity: Sol Medium
|
|
162
|
+
* Production implementation after direction is clear: Terra High
|
|
163
|
+
* Large build with clear requirements: Terra Max
|
|
164
|
+
* Parallel components and chores: Luna High
|
|
165
|
+
|
|
166
|
+
### Designer
|
|
167
|
+
|
|
168
|
+
* Visual exploration: Gemini 3.5 Flash
|
|
169
|
+
* Product and UI direction: Sol Low or Medium
|
|
170
|
+
* Production UI implementation: Terra High
|
|
171
|
+
* Premium design review: Sol High
|
|
172
|
+
|
|
173
|
+
### Reviewer
|
|
174
|
+
|
|
175
|
+
* Normal review: Sol Low
|
|
176
|
+
* Important review: Sol Medium
|
|
177
|
+
* Deep regression or security review: Sol High
|
|
178
|
+
* Critical final review: Sol Max
|
|
179
|
+
|
|
180
|
+
## Decision tree
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
Small, explicit, and isolated?
|
|
184
|
+
-> Luna Medium
|
|
185
|
+
|
|
186
|
+
Bounded, repetitive, or parallel?
|
|
187
|
+
-> Luna High
|
|
188
|
+
|
|
189
|
+
Must decide what should be built?
|
|
190
|
+
-> Sol Low
|
|
191
|
+
-> Sol Medium when serious or ambiguous
|
|
192
|
+
|
|
193
|
+
Direction clear and mainly implementation?
|
|
194
|
+
-> Terra High
|
|
195
|
+
-> Terra Max when large or long-running
|
|
196
|
+
|
|
197
|
+
High-risk, security-sensitive, or deeply uncertain?
|
|
198
|
+
-> Sol High
|
|
199
|
+
-> Sol Max when critical
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Model-body preference
|
|
203
|
+
|
|
204
|
+
When results are close:
|
|
205
|
+
|
|
206
|
+
* Prefer Sol Low over Luna xHigh.
|
|
207
|
+
* Prefer Sol Medium over Luna Max.
|
|
208
|
+
* Prefer Terra High over pushing Luna to xHigh or Max.
|
|
209
|
+
* Prefer the stronger model body unless the weaker route is materially cheaper and the task is well bounded.
|
|
210
|
+
|
|
211
|
+
Avoid xHigh and Max by default. Use them only when public evidence or task risk justifies them.
|
|
212
|
+
|
|
213
|
+
## Recommended handoff
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
Sol Low or Medium
|
|
217
|
+
-> interpret requirements
|
|
218
|
+
-> choose architecture
|
|
219
|
+
-> define acceptance criteria
|
|
220
|
+
|
|
221
|
+
Terra High or Max
|
|
222
|
+
-> implement
|
|
223
|
+
-> test
|
|
224
|
+
-> fix failures
|
|
225
|
+
|
|
226
|
+
Sol Low, Medium, or High
|
|
227
|
+
-> review correctness
|
|
228
|
+
-> check regressions
|
|
229
|
+
-> verify the right problem was solved
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Use Luna High for parallel subtasks with clear instructions.
|
|
233
|
+
|
|
234
|
+
## Escalation triggers
|
|
235
|
+
|
|
236
|
+
Escalate when:
|
|
237
|
+
|
|
238
|
+
* requirements become unclear
|
|
239
|
+
* scope expands
|
|
240
|
+
* architecture must change
|
|
241
|
+
* tests repeatedly fail
|
|
242
|
+
* the model loops or loses the plan
|
|
243
|
+
* security or data-loss risk appears
|
|
244
|
+
* hidden regressions are likely
|
|
245
|
+
* UI quality falls below the reference
|
|
246
|
+
|
|
247
|
+
Do not escalate mechanically. Move directly to Sol when the problem is judgment or ambiguity rather than execution capacity.
|
|
248
|
+
|
|
249
|
+
## Model and execution routes
|
|
250
|
+
|
|
251
|
+
```yaml
|
|
252
|
+
routes:
|
|
253
|
+
luna:
|
|
254
|
+
model: oauth-router/gpt-5.6-luna
|
|
255
|
+
sol:
|
|
256
|
+
model: oauth-router/gpt-5.6-sol
|
|
257
|
+
terra:
|
|
258
|
+
model: oauth-router/gpt-5.6-terra
|
|
259
|
+
visual_exploration:
|
|
260
|
+
execution: antigravity-cli
|
|
261
|
+
model_intent: Gemini 3.5 Flash
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Reasoning-effort labels such as Low, Medium, High, and Max are routing intent and remain part of this policy.
|
|
265
|
+
|
|
266
|
+
## Mental model
|
|
267
|
+
|
|
268
|
+
```text
|
|
269
|
+
Sol Low = intelligent default
|
|
270
|
+
Sol Medium = serious judgment and architecture
|
|
271
|
+
Sol High = senior reviewer and debugger
|
|
272
|
+
Sol Max = rare critical escalation
|
|
273
|
+
|
|
274
|
+
Terra High = default serious coder
|
|
275
|
+
Terra Max = long-horizon implementation engine
|
|
276
|
+
|
|
277
|
+
Luna Medium = small explicit execution
|
|
278
|
+
Luna High = parallel and bounded execution
|
|
279
|
+
|
|
280
|
+
GPT-5.5 = specialist fallback
|
|
281
|
+
Gemini Flash = visual and multimodal exploration through Antigravity CLI
|
|
282
|
+
```
|