takomi 2.1.2 → 2.1.4
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 +124 -124
- package/.pi/agents/architect.md +15 -15
- package/.pi/agents/coder.md +14 -14
- package/.pi/agents/designer.md +17 -17
- package/.pi/agents/orchestrator.md +22 -22
- package/.pi/agents/reviewer.md +16 -16
- package/.pi/extensions/oauth-router/README.md +125 -125
- package/.pi/extensions/oauth-router/commands.ts +380 -380
- package/.pi/extensions/oauth-router/config.ts +200 -200
- package/.pi/extensions/oauth-router/index.ts +41 -41
- package/.pi/extensions/oauth-router/oauth-flow.ts +154 -154
- package/.pi/extensions/oauth-router/oauth-store.ts +121 -121
- package/.pi/extensions/oauth-router/package.json +14 -14
- package/.pi/extensions/oauth-router/policies.ts +27 -27
- package/.pi/extensions/oauth-router/provider.ts +492 -492
- package/.pi/extensions/oauth-router/scripts/vibe-verify.py +98 -98
- package/.pi/extensions/oauth-router/state.ts +174 -174
- package/.pi/extensions/oauth-router/types.ts +153 -153
- package/.pi/extensions/takomi-runtime/command-text.ts +130 -130
- package/.pi/extensions/takomi-runtime/commands.ts +179 -179
- package/.pi/extensions/takomi-runtime/context-panel.ts +282 -282
- package/.pi/extensions/takomi-runtime/index.ts +1288 -1288
- package/.pi/extensions/takomi-runtime/profile.ts +114 -114
- package/.pi/extensions/takomi-runtime/routing-policy.ts +105 -105
- package/.pi/extensions/takomi-runtime/shared.ts +511 -492
- package/.pi/extensions/takomi-runtime/subagent-controller.ts +364 -364
- package/.pi/extensions/takomi-runtime/subagent-render.ts +501 -501
- package/.pi/extensions/takomi-runtime/subagent-types.ts +90 -83
- package/.pi/extensions/takomi-runtime/ui.ts +133 -133
- package/.pi/extensions/takomi-subagents/agent-aliases.ts +18 -18
- package/.pi/extensions/takomi-subagents/agents.ts +113 -113
- package/.pi/extensions/takomi-subagents/delegation-plan.ts +95 -95
- package/.pi/extensions/takomi-subagents/dispatch-helpers.ts +26 -26
- package/.pi/extensions/takomi-subagents/dispatch.ts +306 -215
- package/.pi/extensions/takomi-subagents/index.ts +76 -75
- package/.pi/extensions/takomi-subagents/live-updates.ts +136 -83
- package/.pi/extensions/takomi-subagents/native-render.ts +5 -142
- package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +228 -0
- package/.pi/extensions/takomi-subagents/tool-runner.ts +209 -209
- package/.pi/themes/takomi-noir.json +81 -81
- package/package.json +59 -59
- package/src/cli.js +14 -0
- package/src/doctor.js +87 -84
- package/src/pi-harness.js +355 -351
- package/src/pi-installer.js +193 -171
- package/src/pi-takomi-core/index.ts +4 -4
- package/src/pi-takomi-core/orchestration.ts +402 -402
- package/src/pi-takomi-core/routing.ts +93 -93
- package/src/pi-takomi-core/types.ts +173 -173
- package/src/pi-takomi-core/workflows.ts +299 -299
- package/src/skills-installer.js +101 -101
- package/src/update-check.js +140 -0
|
@@ -1,113 +1,113 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { getAgentDir, parseFrontmatter } from "@mariozechner/pi-coding-agent";
|
|
4
|
-
import type { TakomiThinkingLevel } from "../../../src/pi-takomi-core";
|
|
5
|
-
|
|
6
|
-
export type TakomiAgentScope = "user" | "project" | "both";
|
|
7
|
-
|
|
8
|
-
export type TakomiAgentConfig = {
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
tools?: string[];
|
|
12
|
-
model?: string;
|
|
13
|
-
fallbackModels?: string[];
|
|
14
|
-
thinking?: TakomiThinkingLevel;
|
|
15
|
-
systemPrompt: string;
|
|
16
|
-
filePath: string;
|
|
17
|
-
source: "user" | "project";
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
function splitList(value?: string): string[] | undefined {
|
|
21
|
-
const parts = value
|
|
22
|
-
?.split(",")
|
|
23
|
-
.map((part) => part.trim())
|
|
24
|
-
.filter(Boolean);
|
|
25
|
-
return parts?.length ? parts : undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function normalizeThinking(value?: string): TakomiThinkingLevel | undefined {
|
|
29
|
-
if (
|
|
30
|
-
value === "off"
|
|
31
|
-
|| value === "minimal"
|
|
32
|
-
|| value === "low"
|
|
33
|
-
|| value === "medium"
|
|
34
|
-
|| value === "high"
|
|
35
|
-
|| value === "xhigh"
|
|
36
|
-
) {
|
|
37
|
-
return value;
|
|
38
|
-
}
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function loadAgentsFromDirectory(agentsDir: string, source: "user" | "project"): TakomiAgentConfig[] {
|
|
43
|
-
if (!fs.existsSync(agentsDir)) return [];
|
|
44
|
-
|
|
45
|
-
const entries = fs.readdirSync(agentsDir, { withFileTypes: true });
|
|
46
|
-
const agents: TakomiAgentConfig[] = [];
|
|
47
|
-
|
|
48
|
-
for (const entry of entries) {
|
|
49
|
-
if (!entry.name.endsWith(".md")) continue;
|
|
50
|
-
const filePath = path.join(agentsDir, entry.name);
|
|
51
|
-
const content = fs.readFileSync(filePath, "utf8");
|
|
52
|
-
const { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);
|
|
53
|
-
if (!frontmatter.name || !frontmatter.description) continue;
|
|
54
|
-
|
|
55
|
-
agents.push({
|
|
56
|
-
name: frontmatter.name,
|
|
57
|
-
description: frontmatter.description,
|
|
58
|
-
tools: splitList(frontmatter.tools),
|
|
59
|
-
model: frontmatter.model,
|
|
60
|
-
fallbackModels: splitList(frontmatter.fallbackModels ?? frontmatter.fallback_models),
|
|
61
|
-
thinking: normalizeThinking(frontmatter.thinking),
|
|
62
|
-
systemPrompt: body,
|
|
63
|
-
filePath,
|
|
64
|
-
source,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return agents;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function isDirectory(target: string): boolean {
|
|
72
|
-
try {
|
|
73
|
-
return fs.statSync(target).isDirectory();
|
|
74
|
-
} catch {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function findNearestProjectAgentsDirs(cwd: string): string[] {
|
|
80
|
-
let current = cwd;
|
|
81
|
-
while (true) {
|
|
82
|
-
const candidates = [
|
|
83
|
-
path.join(current, ".pi", "agents"),
|
|
84
|
-
path.join(current, ".agents"),
|
|
85
|
-
].filter(isDirectory);
|
|
86
|
-
if (candidates.length > 0) return candidates;
|
|
87
|
-
const parent = path.dirname(current);
|
|
88
|
-
if (parent === current) return [];
|
|
89
|
-
current = parent;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function discoverTakomiAgents(cwd: string, scope: TakomiAgentScope = "both"): TakomiAgentConfig[] {
|
|
94
|
-
const projectAgentsDirs = findNearestProjectAgentsDirs(cwd);
|
|
95
|
-
const localAgents = scope === "user"
|
|
96
|
-
? []
|
|
97
|
-
: projectAgentsDirs.flatMap((agentsDir) => loadAgentsFromDirectory(agentsDir, "project"));
|
|
98
|
-
const globalAgents = scope === "project" ? [] : loadAgentsFromDirectory(path.join(getAgentDir(), "agents"), "user");
|
|
99
|
-
const merged = new Map<string, TakomiAgentConfig>();
|
|
100
|
-
|
|
101
|
-
for (const agent of globalAgents) {
|
|
102
|
-
merged.set(agent.name, agent);
|
|
103
|
-
}
|
|
104
|
-
for (const agent of localAgents) {
|
|
105
|
-
merged.set(agent.name, agent);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return [...merged.values()];
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function discoverProjectAgents(cwd: string): TakomiAgentConfig[] {
|
|
112
|
-
return discoverTakomiAgents(cwd, "both");
|
|
113
|
-
}
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { getAgentDir, parseFrontmatter } from "@mariozechner/pi-coding-agent";
|
|
4
|
+
import type { TakomiThinkingLevel } from "../../../src/pi-takomi-core";
|
|
5
|
+
|
|
6
|
+
export type TakomiAgentScope = "user" | "project" | "both";
|
|
7
|
+
|
|
8
|
+
export type TakomiAgentConfig = {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
tools?: string[];
|
|
12
|
+
model?: string;
|
|
13
|
+
fallbackModels?: string[];
|
|
14
|
+
thinking?: TakomiThinkingLevel;
|
|
15
|
+
systemPrompt: string;
|
|
16
|
+
filePath: string;
|
|
17
|
+
source: "user" | "project";
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function splitList(value?: string): string[] | undefined {
|
|
21
|
+
const parts = value
|
|
22
|
+
?.split(",")
|
|
23
|
+
.map((part) => part.trim())
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
return parts?.length ? parts : undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function normalizeThinking(value?: string): TakomiThinkingLevel | undefined {
|
|
29
|
+
if (
|
|
30
|
+
value === "off"
|
|
31
|
+
|| value === "minimal"
|
|
32
|
+
|| value === "low"
|
|
33
|
+
|| value === "medium"
|
|
34
|
+
|| value === "high"
|
|
35
|
+
|| value === "xhigh"
|
|
36
|
+
) {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function loadAgentsFromDirectory(agentsDir: string, source: "user" | "project"): TakomiAgentConfig[] {
|
|
43
|
+
if (!fs.existsSync(agentsDir)) return [];
|
|
44
|
+
|
|
45
|
+
const entries = fs.readdirSync(agentsDir, { withFileTypes: true });
|
|
46
|
+
const agents: TakomiAgentConfig[] = [];
|
|
47
|
+
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
if (!entry.name.endsWith(".md")) continue;
|
|
50
|
+
const filePath = path.join(agentsDir, entry.name);
|
|
51
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
52
|
+
const { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);
|
|
53
|
+
if (!frontmatter.name || !frontmatter.description) continue;
|
|
54
|
+
|
|
55
|
+
agents.push({
|
|
56
|
+
name: frontmatter.name,
|
|
57
|
+
description: frontmatter.description,
|
|
58
|
+
tools: splitList(frontmatter.tools),
|
|
59
|
+
model: frontmatter.model,
|
|
60
|
+
fallbackModels: splitList(frontmatter.fallbackModels ?? frontmatter.fallback_models),
|
|
61
|
+
thinking: normalizeThinking(frontmatter.thinking),
|
|
62
|
+
systemPrompt: body,
|
|
63
|
+
filePath,
|
|
64
|
+
source,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return agents;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function isDirectory(target: string): boolean {
|
|
72
|
+
try {
|
|
73
|
+
return fs.statSync(target).isDirectory();
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function findNearestProjectAgentsDirs(cwd: string): string[] {
|
|
80
|
+
let current = cwd;
|
|
81
|
+
while (true) {
|
|
82
|
+
const candidates = [
|
|
83
|
+
path.join(current, ".pi", "agents"),
|
|
84
|
+
path.join(current, ".agents"),
|
|
85
|
+
].filter(isDirectory);
|
|
86
|
+
if (candidates.length > 0) return candidates;
|
|
87
|
+
const parent = path.dirname(current);
|
|
88
|
+
if (parent === current) return [];
|
|
89
|
+
current = parent;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function discoverTakomiAgents(cwd: string, scope: TakomiAgentScope = "both"): TakomiAgentConfig[] {
|
|
94
|
+
const projectAgentsDirs = findNearestProjectAgentsDirs(cwd);
|
|
95
|
+
const localAgents = scope === "user"
|
|
96
|
+
? []
|
|
97
|
+
: projectAgentsDirs.flatMap((agentsDir) => loadAgentsFromDirectory(agentsDir, "project"));
|
|
98
|
+
const globalAgents = scope === "project" ? [] : loadAgentsFromDirectory(path.join(getAgentDir(), "agents"), "user");
|
|
99
|
+
const merged = new Map<string, TakomiAgentConfig>();
|
|
100
|
+
|
|
101
|
+
for (const agent of globalAgents) {
|
|
102
|
+
merged.set(agent.name, agent);
|
|
103
|
+
}
|
|
104
|
+
for (const agent of localAgents) {
|
|
105
|
+
merged.set(agent.name, agent);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return [...merged.values()];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function discoverProjectAgents(cwd: string): TakomiAgentConfig[] {
|
|
112
|
+
return discoverTakomiAgents(cwd, "both");
|
|
113
|
+
}
|
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
TakomiDelegationPlan,
|
|
3
|
-
TakomiDelegationPlanTask,
|
|
4
|
-
TakomiDispatchPolicy,
|
|
5
|
-
TakomiLaunchMode,
|
|
6
|
-
TakomiProfile,
|
|
7
|
-
TakomiRole,
|
|
8
|
-
TakomiThinkingLevel,
|
|
9
|
-
TakomiWorkflowId,
|
|
10
|
-
VibeLifecycleStage,
|
|
11
|
-
} from "../../../src/pi-takomi-core";
|
|
12
|
-
import type { ChecklistInput } from "../takomi-runtime/shared";
|
|
13
|
-
|
|
14
|
-
type PlanTaskInput = {
|
|
15
|
-
id?: string;
|
|
16
|
-
title?: string;
|
|
17
|
-
agent: string;
|
|
18
|
-
task: string;
|
|
19
|
-
role?: TakomiRole;
|
|
20
|
-
stage?: VibeLifecycleStage;
|
|
21
|
-
workflow?: TakomiWorkflowId | string;
|
|
22
|
-
model?: string;
|
|
23
|
-
fallbackModels?: string[];
|
|
24
|
-
thinking?: TakomiThinkingLevel;
|
|
25
|
-
conversationId?: string;
|
|
26
|
-
checklist?: ChecklistInput;
|
|
27
|
-
dispatchPolicy?: TakomiDispatchPolicy;
|
|
28
|
-
review?: boolean;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type PlanInput = {
|
|
32
|
-
source: TakomiDelegationPlan["source"];
|
|
33
|
-
sessionId?: string;
|
|
34
|
-
launchMode: TakomiLaunchMode;
|
|
35
|
-
profile: TakomiProfile;
|
|
36
|
-
tasks: PlanTaskInput[];
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
function normalizeChecklist(checklist?: ChecklistInput): TakomiDelegationPlanTask["checklist"] {
|
|
40
|
-
if (!checklist?.length) return undefined;
|
|
41
|
-
return checklist.map((item) => typeof item === "string" ? { text: item, done: false } : { text: item.text, done: item.done ?? false });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function createTakomiDelegationPlan(input: PlanInput): TakomiDelegationPlan {
|
|
45
|
-
const reviewAfterImplementation = input.profile.reviewAfterImplementation ?? input.profile.review?.enabled ?? true;
|
|
46
|
-
return {
|
|
47
|
-
planId: `takomi-plan-${Date.now()}`,
|
|
48
|
-
source: input.source,
|
|
49
|
-
launchMode: input.launchMode,
|
|
50
|
-
placement: input.profile.background ? "background" : "foreground",
|
|
51
|
-
reviewAfterImplementation,
|
|
52
|
-
createdAt: new Date().toISOString(),
|
|
53
|
-
sessionId: input.sessionId,
|
|
54
|
-
tasks: input.tasks.map((task, index) => ({
|
|
55
|
-
id: task.id ?? `plan-task-${index + 1}`,
|
|
56
|
-
title: task.title ?? task.task.split(/\r?\n/).find(Boolean)?.slice(0, 80) ?? `Task ${index + 1}`,
|
|
57
|
-
agent: task.agent,
|
|
58
|
-
task: task.task,
|
|
59
|
-
role: task.role,
|
|
60
|
-
stage: task.stage,
|
|
61
|
-
workflow: task.workflow,
|
|
62
|
-
model: task.model,
|
|
63
|
-
fallbackModels: task.fallbackModels,
|
|
64
|
-
thinking: task.thinking,
|
|
65
|
-
conversationId: task.conversationId,
|
|
66
|
-
checklist: normalizeChecklist(task.checklist),
|
|
67
|
-
dispatchPolicy: task.dispatchPolicy,
|
|
68
|
-
review: task.review ?? reviewAfterImplementation,
|
|
69
|
-
status: "planned",
|
|
70
|
-
})),
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function renderTakomiDelegationPlan(plan: TakomiDelegationPlan): string {
|
|
75
|
-
const lines = [
|
|
76
|
-
`Takomi delegation plan ${plan.planId}`,
|
|
77
|
-
`mode=${plan.launchMode} | placement=${plan.placement} | reviewAfterImplementation=${plan.reviewAfterImplementation ? "on" : "off"}`,
|
|
78
|
-
];
|
|
79
|
-
for (const task of plan.tasks) {
|
|
80
|
-
const checklist = task.checklist?.length ? ` | checklist=${task.checklist.filter((item) => item.done).length}/${task.checklist.length}` : "";
|
|
81
|
-
const fallback = task.fallbackModels?.length ? ` | fallbacks=${task.fallbackModels.length}` : "";
|
|
82
|
-
lines.push([
|
|
83
|
-
`${task.id}: ${task.agent}`,
|
|
84
|
-
task.model ? `model=${task.model}` : "model=default",
|
|
85
|
-
task.thinking ? `thinking=${task.thinking}` : "thinking=default",
|
|
86
|
-
task.workflow ? `workflow=${task.workflow}` : "",
|
|
87
|
-
task.review ? "review=on" : "review=off",
|
|
88
|
-
`task=${task.title}${fallback}${checklist}`,
|
|
89
|
-
].filter(Boolean).join(" | "));
|
|
90
|
-
}
|
|
91
|
-
if (plan.launchMode === "manual") {
|
|
92
|
-
lines.push("", "Manual launch mode: review or edit agent/task/model/thinking/review settings, then rerun with confirmLaunch=true. Use previewOnly=true to keep reviewing without launch.");
|
|
93
|
-
}
|
|
94
|
-
return lines.join("\n");
|
|
95
|
-
}
|
|
1
|
+
import type {
|
|
2
|
+
TakomiDelegationPlan,
|
|
3
|
+
TakomiDelegationPlanTask,
|
|
4
|
+
TakomiDispatchPolicy,
|
|
5
|
+
TakomiLaunchMode,
|
|
6
|
+
TakomiProfile,
|
|
7
|
+
TakomiRole,
|
|
8
|
+
TakomiThinkingLevel,
|
|
9
|
+
TakomiWorkflowId,
|
|
10
|
+
VibeLifecycleStage,
|
|
11
|
+
} from "../../../src/pi-takomi-core";
|
|
12
|
+
import type { ChecklistInput } from "../takomi-runtime/shared";
|
|
13
|
+
|
|
14
|
+
type PlanTaskInput = {
|
|
15
|
+
id?: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
agent: string;
|
|
18
|
+
task: string;
|
|
19
|
+
role?: TakomiRole;
|
|
20
|
+
stage?: VibeLifecycleStage;
|
|
21
|
+
workflow?: TakomiWorkflowId | string;
|
|
22
|
+
model?: string;
|
|
23
|
+
fallbackModels?: string[];
|
|
24
|
+
thinking?: TakomiThinkingLevel;
|
|
25
|
+
conversationId?: string;
|
|
26
|
+
checklist?: ChecklistInput;
|
|
27
|
+
dispatchPolicy?: TakomiDispatchPolicy;
|
|
28
|
+
review?: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type PlanInput = {
|
|
32
|
+
source: TakomiDelegationPlan["source"];
|
|
33
|
+
sessionId?: string;
|
|
34
|
+
launchMode: TakomiLaunchMode;
|
|
35
|
+
profile: TakomiProfile;
|
|
36
|
+
tasks: PlanTaskInput[];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function normalizeChecklist(checklist?: ChecklistInput): TakomiDelegationPlanTask["checklist"] {
|
|
40
|
+
if (!checklist?.length) return undefined;
|
|
41
|
+
return checklist.map((item) => typeof item === "string" ? { text: item, done: false } : { text: item.text, done: item.done ?? false });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createTakomiDelegationPlan(input: PlanInput): TakomiDelegationPlan {
|
|
45
|
+
const reviewAfterImplementation = input.profile.reviewAfterImplementation ?? input.profile.review?.enabled ?? true;
|
|
46
|
+
return {
|
|
47
|
+
planId: `takomi-plan-${Date.now()}`,
|
|
48
|
+
source: input.source,
|
|
49
|
+
launchMode: input.launchMode,
|
|
50
|
+
placement: input.profile.background ? "background" : "foreground",
|
|
51
|
+
reviewAfterImplementation,
|
|
52
|
+
createdAt: new Date().toISOString(),
|
|
53
|
+
sessionId: input.sessionId,
|
|
54
|
+
tasks: input.tasks.map((task, index) => ({
|
|
55
|
+
id: task.id ?? `plan-task-${index + 1}`,
|
|
56
|
+
title: task.title ?? task.task.split(/\r?\n/).find(Boolean)?.slice(0, 80) ?? `Task ${index + 1}`,
|
|
57
|
+
agent: task.agent,
|
|
58
|
+
task: task.task,
|
|
59
|
+
role: task.role,
|
|
60
|
+
stage: task.stage,
|
|
61
|
+
workflow: task.workflow,
|
|
62
|
+
model: task.model,
|
|
63
|
+
fallbackModels: task.fallbackModels,
|
|
64
|
+
thinking: task.thinking,
|
|
65
|
+
conversationId: task.conversationId,
|
|
66
|
+
checklist: normalizeChecklist(task.checklist),
|
|
67
|
+
dispatchPolicy: task.dispatchPolicy,
|
|
68
|
+
review: task.review ?? reviewAfterImplementation,
|
|
69
|
+
status: "planned",
|
|
70
|
+
})),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function renderTakomiDelegationPlan(plan: TakomiDelegationPlan): string {
|
|
75
|
+
const lines = [
|
|
76
|
+
`Takomi delegation plan ${plan.planId}`,
|
|
77
|
+
`mode=${plan.launchMode} | placement=${plan.placement} | reviewAfterImplementation=${plan.reviewAfterImplementation ? "on" : "off"}`,
|
|
78
|
+
];
|
|
79
|
+
for (const task of plan.tasks) {
|
|
80
|
+
const checklist = task.checklist?.length ? ` | checklist=${task.checklist.filter((item) => item.done).length}/${task.checklist.length}` : "";
|
|
81
|
+
const fallback = task.fallbackModels?.length ? ` | fallbacks=${task.fallbackModels.length}` : "";
|
|
82
|
+
lines.push([
|
|
83
|
+
`${task.id}: ${task.agent}`,
|
|
84
|
+
task.model ? `model=${task.model}` : "model=default",
|
|
85
|
+
task.thinking ? `thinking=${task.thinking}` : "thinking=default",
|
|
86
|
+
task.workflow ? `workflow=${task.workflow}` : "",
|
|
87
|
+
task.review ? "review=on" : "review=off",
|
|
88
|
+
`task=${task.title}${fallback}${checklist}`,
|
|
89
|
+
].filter(Boolean).join(" | "));
|
|
90
|
+
}
|
|
91
|
+
if (plan.launchMode === "manual") {
|
|
92
|
+
lines.push("", "Manual launch mode: review or edit agent/task/model/thinking/review settings, then rerun with confirmLaunch=true. Use previewOnly=true to keep reviewing without launch.");
|
|
93
|
+
}
|
|
94
|
+
return lines.join("\n");
|
|
95
|
+
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import type { TakomiDispatchInput } from "./dispatch";
|
|
2
|
-
|
|
3
|
-
export function uniqueStrings(values: Array<string | undefined>): string[] {
|
|
4
|
-
return [...new Set(values.filter((value): value is string => Boolean(value?.trim())))];
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function hasThinkingSuffix(model?: string): boolean {
|
|
8
|
-
return /:(off|minimal|low|medium|high|xhigh)$/i.test(model ?? "");
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function buildFallbackModels(input: TakomiDispatchInput): string[] {
|
|
12
|
-
return uniqueStrings([
|
|
13
|
-
input.agent.model,
|
|
14
|
-
...(input.fallbackModels ?? []),
|
|
15
|
-
...(input.agent.fallbackModels ?? []),
|
|
16
|
-
]);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function buildSystemPrompt(input: TakomiDispatchInput): string {
|
|
20
|
-
return [
|
|
21
|
-
input.agent.systemPrompt,
|
|
22
|
-
input.workflow ? `\nUse the ${input.workflow} workflow for this task.` : "",
|
|
23
|
-
input.skills?.length ? `\nUse these skills when relevant: ${input.skills.join(", ")}.` : "",
|
|
24
|
-
input.thinking ? `\nUse Pi thinking level '${input.thinking}' for this delegated run when the selected model supports it.` : "",
|
|
25
|
-
].filter(Boolean).join("\n");
|
|
26
|
-
}
|
|
1
|
+
import type { TakomiDispatchInput } from "./dispatch";
|
|
2
|
+
|
|
3
|
+
export function uniqueStrings(values: Array<string | undefined>): string[] {
|
|
4
|
+
return [...new Set(values.filter((value): value is string => Boolean(value?.trim())))];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function hasThinkingSuffix(model?: string): boolean {
|
|
8
|
+
return /:(off|minimal|low|medium|high|xhigh)$/i.test(model ?? "");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function buildFallbackModels(input: TakomiDispatchInput): string[] {
|
|
12
|
+
return uniqueStrings([
|
|
13
|
+
input.agent.model,
|
|
14
|
+
...(input.fallbackModels ?? []),
|
|
15
|
+
...(input.agent.fallbackModels ?? []),
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function buildSystemPrompt(input: TakomiDispatchInput): string {
|
|
20
|
+
return [
|
|
21
|
+
input.agent.systemPrompt,
|
|
22
|
+
input.workflow ? `\nUse the ${input.workflow} workflow for this task.` : "",
|
|
23
|
+
input.skills?.length ? `\nUse these skills when relevant: ${input.skills.join(", ")}.` : "",
|
|
24
|
+
input.thinking ? `\nUse Pi thinking level '${input.thinking}' for this delegated run when the selected model supports it.` : "",
|
|
25
|
+
].filter(Boolean).join("\n");
|
|
26
|
+
}
|