@oxgeneral/orch 0.3.3 → 1.0.0
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/App-GJVTVGRU.js +6717 -0
- package/dist/agent-7ZJ3ZDJ7.js +183 -0
- package/dist/agent-shop-YN2BSLHM.js +2 -0
- package/dist/chunk-2C2TFQ7K.js +136 -0
- package/dist/chunk-45K2XID7.js +29 -0
- package/dist/chunk-4IFIOMCW.js +86 -0
- package/dist/chunk-7X2GI5OV.js +181 -0
- package/dist/{chunk-S3QYSBW4.js → chunk-C6XZ3FJT.js} +6 -3
- package/dist/chunk-C6XZ3FJT.js.map +1 -0
- package/dist/chunk-CHIP7O6V.js +83 -0
- package/dist/{chunk-BCPUTULS.js → chunk-DAVHOWGD.js} +188 -16
- package/dist/chunk-FRTKB575.js +87 -0
- package/dist/{chunk-BGHCY7WY.js → chunk-GBXUNDKN.js} +32 -13
- package/dist/chunk-GBXUNDKN.js.map +1 -0
- package/dist/chunk-HXYAZGLP.js +15 -0
- package/dist/chunk-I3SMISEF.js +29 -0
- package/dist/chunk-K6DMQERQ.js +89 -0
- package/dist/chunk-LV6GDBBI.js +297 -0
- package/dist/chunk-MGGSRXWJ.js +69 -0
- package/dist/chunk-P6ATSXGL.js +107 -0
- package/dist/chunk-PNE6LQRF.js +5 -0
- package/dist/chunk-U2VDNUZL.js +52 -0
- package/dist/chunk-VG4465AG.js +275 -0
- package/dist/chunk-VG4465AG.js.map +1 -0
- package/dist/{chunk-B4JQM4NU.js → chunk-VXS2CJFH.js} +119 -47
- package/dist/chunk-XJTJ2TJV.js +221 -0
- package/dist/{claude-INM52PTH.js → claude-WUJU5KIE.js} +6 -5
- package/dist/claude-WUJU5KIE.js.map +1 -0
- package/dist/claude-ZUEKJJ4X.js +5 -0
- package/dist/cli.js +199 -1
- package/dist/clipboard-service-RTDUUQQU.js +200 -0
- package/dist/codex-7IXXXG5U.js +123 -0
- package/dist/{codex-QGH2GRV6.js → codex-NYJWEPRQ.js} +4 -4
- package/dist/codex-NYJWEPRQ.js.map +1 -0
- package/dist/config-OTAVSMOD.js +75 -0
- package/dist/container-LUWGNBSS.js +1596 -0
- package/dist/context-OL4BVUV5.js +83 -0
- package/dist/{cursor-KQJTQ73D.js → cursor-3YHVD4NP.js} +4 -4
- package/dist/cursor-3YHVD4NP.js.map +1 -0
- package/dist/cursor-622RBRHH.js +97 -0
- package/dist/doctor-XSGQSD57.js +67 -0
- package/dist/doctor-service-TPOMFAIG.js +2 -0
- package/dist/goal-FMYYN2FR.js +138 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +25 -16
- package/dist/index.js.map +1 -1
- package/dist/init-JU343RXK.js +165 -0
- package/dist/logs-PHPYWQ6I.js +207 -0
- package/dist/msg-FUWWLEKM.js +95 -0
- package/dist/opencode-FAMPSA6X.js +100 -0
- package/dist/opencode-FAMPSA6X.js.map +1 -0
- package/dist/opencode-WOR53TSC.js +98 -0
- package/dist/orchestrator-IYWBVA7J.js +5 -0
- package/dist/{orchestrator-KF4UY5GD.js.map → orchestrator-IYWBVA7J.js.map} +1 -1
- package/dist/orchestrator-QNAD7MFH.js +1433 -0
- package/dist/process-manager-HUVNAPQV.js +2 -0
- package/dist/registry-PQWRVNF2.js +2 -0
- package/dist/run-N72G5V2H.js +95 -0
- package/dist/shell-DVFHHYAZ.js +5 -0
- package/dist/{shell-UXJNTNBC.js → shell-NJNW3O6K.js} +6 -4
- package/dist/shell-NJNW3O6K.js.map +1 -0
- package/dist/shop-picker-2HY67UWP.js +79 -0
- package/dist/status-RZWN2C6C.js +56 -0
- package/dist/task-3O2OFSP6.js +221 -0
- package/dist/team-PFLP4PPL.js +97 -0
- package/dist/template-engine-5ZKVJMYA.js +3 -0
- package/dist/{template-engine-MFL5B677.js.map → template-engine-5ZKVJMYA.js.map} +1 -1
- package/dist/template-engine-AWIS56BL.js +3 -0
- package/dist/tui-LN5XHSQY.js +245 -0
- package/dist/update-YLP7FPNY.js +64 -0
- package/dist/update-check-4YKLGBFB.js +2 -0
- package/dist/workspace-manager-JM6U7JOH.js +215 -0
- package/package.json +2 -1
- package/readme.md +11 -4
- package/scripts/load-test.ts +478 -0
- package/scripts/postinstall.js +44 -2
- package/dist/App-NN7HR7UE.js +0 -20
- package/dist/agent-S4DKSX63.js +0 -9
- package/dist/agent-shop-D2RS4BZK.js +0 -2
- package/dist/chunk-3MQNQ7QW.js +0 -2
- package/dist/chunk-5AJ4LYO5.js +0 -8
- package/dist/chunk-6MJ7V6VY.js +0 -2
- package/dist/chunk-B4JQM4NU.js.map +0 -1
- package/dist/chunk-BGHCY7WY.js.map +0 -1
- package/dist/chunk-CDFA4IIQ.js +0 -2
- package/dist/chunk-CHRW4CLD.js +0 -2
- package/dist/chunk-HMMPM7MF.js +0 -3
- package/dist/chunk-HSBYJ5C5.js +0 -112
- package/dist/chunk-HXOMNULD.js +0 -2
- package/dist/chunk-IS3YBE2B.js +0 -3
- package/dist/chunk-KPCT44WU.js +0 -2
- package/dist/chunk-L26TK7Y5.js +0 -2
- package/dist/chunk-LXNRCJ22.js +0 -2
- package/dist/chunk-OQKREZUF.js +0 -11
- package/dist/chunk-PJ5DKXGR.js +0 -2
- package/dist/chunk-QFKVCNKL.js +0 -2
- package/dist/chunk-S3QYSBW4.js.map +0 -1
- package/dist/chunk-UMZEA3JT.js +0 -5
- package/dist/claude-GQZNDJ6L.js +0 -2
- package/dist/claude-INM52PTH.js.map +0 -1
- package/dist/clipboard-service-MYLSWM5E.js +0 -25
- package/dist/codex-QGH2GRV6.js.map +0 -1
- package/dist/codex-SJV7ZZBY.js +0 -2
- package/dist/config-CCSS2P7R.js +0 -2
- package/dist/container-NEKK5W2B.js +0 -6
- package/dist/context-GSMQHQES.js +0 -7
- package/dist/cursor-4JQOCP5X.js +0 -2
- package/dist/cursor-KQJTQ73D.js.map +0 -1
- package/dist/doctor-UAII4VWN.js +0 -2
- package/dist/doctor-service-PB7YBH3F.js +0 -2
- package/dist/goal-RFKFPR7M.js +0 -8
- package/dist/init-2D4RAN7B.js +0 -53
- package/dist/logs-UXFXVYCP.js +0 -12
- package/dist/msg-4SCLBO4K.js +0 -9
- package/dist/orchestrator-KF4UY5GD.js +0 -5
- package/dist/orchestrator-MFL3XK5L.js +0 -13
- package/dist/process-manager-33H27MQF.js +0 -2
- package/dist/registry-BO2PPRNG.js +0 -2
- package/dist/run-HSHRELOP.js +0 -3
- package/dist/shell-F42UUF3U.js +0 -2
- package/dist/shell-UXJNTNBC.js.map +0 -1
- package/dist/shop-picker-LE3SKFOX.js +0 -5
- package/dist/status-DLBNWSWM.js +0 -2
- package/dist/task-AP2TIOOF.js +0 -20
- package/dist/team-MSIBKOQC.js +0 -4
- package/dist/template-engine-MFL5B677.js +0 -3
- package/dist/template-engine-ONIDVD4F.js +0 -2
- package/dist/tui-PIQT4ZZ2.js +0 -2
- package/dist/update-PC2ENCKU.js +0 -2
- package/dist/update-check-HGMBDYHL.js +0 -2
- package/dist/workspace-manager-DYN3XJ7X.js +0 -3
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// src/domain/task.ts
|
|
2
|
+
var AUTONOMOUS_LABEL = "autonomous";
|
|
3
|
+
|
|
4
|
+
// src/infrastructure/template/template-engine.ts
|
|
5
|
+
var LiquidTemplateEngine = class {
|
|
6
|
+
engine;
|
|
7
|
+
renderTimeoutMs;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.renderTimeoutMs = options?.renderTimeoutMs ?? 5e3;
|
|
10
|
+
}
|
|
11
|
+
async getEngine() {
|
|
12
|
+
if (!this.engine) {
|
|
13
|
+
const { Liquid } = await import('liquidjs');
|
|
14
|
+
this.engine = new Liquid({
|
|
15
|
+
strictFilters: false,
|
|
16
|
+
strictVariables: false
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return this.engine;
|
|
20
|
+
}
|
|
21
|
+
async render(template, context) {
|
|
22
|
+
const engine = await this.getEngine();
|
|
23
|
+
const renderPromise = engine.parseAndRender(template, context);
|
|
24
|
+
if (this.renderTimeoutMs <= 0) {
|
|
25
|
+
return renderPromise;
|
|
26
|
+
}
|
|
27
|
+
let timer;
|
|
28
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
29
|
+
timer = setTimeout(
|
|
30
|
+
() => reject(new Error(`Template render timed out after ${this.renderTimeoutMs}ms`)),
|
|
31
|
+
this.renderTimeoutMs
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
try {
|
|
35
|
+
return await Promise.race([renderPromise, timeoutPromise]);
|
|
36
|
+
} finally {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var MAX_CONTEXT_ENTRIES = 15;
|
|
42
|
+
function filterRelevantContext(allContext, filter) {
|
|
43
|
+
const entries = Object.entries(allContext);
|
|
44
|
+
if (entries.length === 0) return {};
|
|
45
|
+
const agentLower = filter.agentName.toLowerCase();
|
|
46
|
+
const roleKeywords = extractRoleKeywords(agentLower, filter.agentRole);
|
|
47
|
+
const scored = [];
|
|
48
|
+
for (const [key, value] of entries) {
|
|
49
|
+
let score = 0;
|
|
50
|
+
const keyLower = key.toLowerCase();
|
|
51
|
+
if (filter.goalId && keyLower.startsWith(filter.goalId.toLowerCase())) {
|
|
52
|
+
score += 10;
|
|
53
|
+
}
|
|
54
|
+
if (keyLower.includes(agentLower) || value.toLowerCase().includes(agentLower)) {
|
|
55
|
+
score += 8;
|
|
56
|
+
}
|
|
57
|
+
if (filter.taskScope?.length) {
|
|
58
|
+
for (const scopePattern of filter.taskScope) {
|
|
59
|
+
const scopeBase = scopePattern.replace(/\*+/g, "").replace(/\/+$/, "");
|
|
60
|
+
if (scopeBase && (keyLower.includes(scopeBase.toLowerCase()) || value.toLowerCase().includes(scopeBase.toLowerCase()))) {
|
|
61
|
+
score += 6;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const kw of roleKeywords) {
|
|
67
|
+
if (keyLower.startsWith(kw + "-") || keyLower.startsWith(kw + "_")) {
|
|
68
|
+
score += 4;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (/^(bug|perf|stability|docs|arch|spec)-/i.test(key)) {
|
|
73
|
+
score += 1;
|
|
74
|
+
}
|
|
75
|
+
scored.push({ key, value, score });
|
|
76
|
+
}
|
|
77
|
+
scored.sort((a, b) => b.score - a.score);
|
|
78
|
+
const relevant = scored.filter((e) => e.score > 0).slice(0, MAX_CONTEXT_ENTRIES);
|
|
79
|
+
if (relevant.length < MAX_CONTEXT_ENTRIES) {
|
|
80
|
+
const remaining = scored.filter((e) => e.score === 0).slice(0, MAX_CONTEXT_ENTRIES - relevant.length);
|
|
81
|
+
relevant.push(...remaining);
|
|
82
|
+
}
|
|
83
|
+
const result = {};
|
|
84
|
+
for (const { key, value } of relevant) {
|
|
85
|
+
result[key] = value;
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
function extractRoleKeywords(agentNameLower, role) {
|
|
90
|
+
const keywords = [];
|
|
91
|
+
const firstWord = agentNameLower.split(/[\s_-]/)[0];
|
|
92
|
+
if (firstWord && firstWord.length > 1) {
|
|
93
|
+
keywords.push(firstWord);
|
|
94
|
+
}
|
|
95
|
+
if (agentNameLower.includes("front") || agentNameLower.includes("tui")) {
|
|
96
|
+
keywords.push("front-end", "frontend", "tui");
|
|
97
|
+
}
|
|
98
|
+
if (agentNameLower.includes("market") || agentNameLower.includes("cmo")) {
|
|
99
|
+
keywords.push("marketer", "marketing", "cmo");
|
|
100
|
+
}
|
|
101
|
+
if (role) {
|
|
102
|
+
const roleFirstWord = role.toLowerCase().split(/[\s_-]/)[0];
|
|
103
|
+
if (roleFirstWord && roleFirstWord.length > 2 && !keywords.includes(roleFirstWord)) {
|
|
104
|
+
keywords.push(roleFirstWord);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return keywords;
|
|
108
|
+
}
|
|
109
|
+
function buildPromptContext(task, agent, attempt, workspacePath, config, options) {
|
|
110
|
+
const { allAgents, retryContext, sharedContext, feedback, messages: rawMessages, goal } = options ?? {};
|
|
111
|
+
const agentById = new Map((allAgents ?? []).map((a) => [a.id, a]));
|
|
112
|
+
const messages = rawMessages?.length ? rawMessages.map((m) => ({
|
|
113
|
+
id: m.id,
|
|
114
|
+
from: agentById.get(m.from_agent_id)?.name ?? m.from_agent_id,
|
|
115
|
+
subject: m.subject,
|
|
116
|
+
body: m.body,
|
|
117
|
+
sent_at: m.created_at,
|
|
118
|
+
reply_to: m.reply_to
|
|
119
|
+
})) : void 0;
|
|
120
|
+
return {
|
|
121
|
+
project: {
|
|
122
|
+
name: config.project.name,
|
|
123
|
+
description: config.project.description
|
|
124
|
+
},
|
|
125
|
+
task: {
|
|
126
|
+
id: task.id,
|
|
127
|
+
title: task.title,
|
|
128
|
+
description: task.description,
|
|
129
|
+
priority: task.priority,
|
|
130
|
+
labels: task.labels,
|
|
131
|
+
scope: task.scope,
|
|
132
|
+
is_autonomous: task.labels?.includes(AUTONOMOUS_LABEL) ?? false,
|
|
133
|
+
goal_id: task.goalId
|
|
134
|
+
},
|
|
135
|
+
agent: {
|
|
136
|
+
id: agent.id,
|
|
137
|
+
name: agent.name,
|
|
138
|
+
role: agent.role
|
|
139
|
+
},
|
|
140
|
+
agents: (allAgents ?? []).map((a) => ({
|
|
141
|
+
id: a.id,
|
|
142
|
+
name: a.name,
|
|
143
|
+
role: a.id === agent.id ? void 0 : a.role,
|
|
144
|
+
adapter: a.adapter
|
|
145
|
+
})),
|
|
146
|
+
attempt: attempt > 1 ? attempt : null,
|
|
147
|
+
workspace_path: workspacePath,
|
|
148
|
+
retry: attempt > 1 ? retryContext : void 0,
|
|
149
|
+
feedback,
|
|
150
|
+
shared_context: sharedContext && Object.keys(sharedContext).length > 0 ? filterRelevantContext(sharedContext, {
|
|
151
|
+
agentName: agent.name,
|
|
152
|
+
agentRole: agent.role,
|
|
153
|
+
goalId: task.goalId,
|
|
154
|
+
taskScope: task.scope
|
|
155
|
+
}) : void 0,
|
|
156
|
+
messages,
|
|
157
|
+
goal
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
var DEFAULT_SYSTEM_TEMPLATE = `You are {{ agent.name }}{% if agent.role %} ({{ agent.role }}){% endif %}.
|
|
161
|
+
|
|
162
|
+
## Orchestrator CLI
|
|
163
|
+
Manage tasks and coordinate with other agents using \`orch\`:
|
|
164
|
+
|
|
165
|
+
**Tasks:**
|
|
166
|
+
- \`orch task add "<title>" -d "<description>" -p <1-4> --assignee <agent-id>\` \u2014 create and assign a task
|
|
167
|
+
- \`orch task add "<title>" -d "<description>" --scope "src/path/**" --depends-on <task-id>\` \u2014 scoped task with dependency
|
|
168
|
+
- \`orch task list [--status todo|in_progress|done|failed]\` \u2014 list tasks
|
|
169
|
+
|
|
170
|
+
**Messaging:**
|
|
171
|
+
- \`orch msg send <agent-id> "<body>" -s "<subject>"\` \u2014 direct message
|
|
172
|
+
- \`orch msg broadcast "<body>" -s "<subject>"\` \u2014 broadcast to all
|
|
173
|
+
- \`orch msg inbox {{ agent.id }}\` \u2014 your pending messages
|
|
174
|
+
|
|
175
|
+
**Shared context:**
|
|
176
|
+
- \`orch context set <key> <value>\` / \`orch context get <key>\` / \`orch context list\`
|
|
177
|
+
|
|
178
|
+
{% if task.is_autonomous %}
|
|
179
|
+
## Autonomous Goal Mode
|
|
180
|
+
This is an autonomous task driven by a goal. Work in a continuous loop until the goal is achieved:
|
|
181
|
+
|
|
182
|
+
1. **Understand the goal** \u2014 read the Goal section above.
|
|
183
|
+
2. **Decompose** \u2014 break the goal into concrete subtasks via \`orch task add\`. {% if task.goal_id %}Pass \`--goal-id {{ task.goal_id }}\` so subtasks are linked to this goal. {% endif %}Assign yourself for your specialty, delegate other work to appropriate teammates by role.
|
|
184
|
+
3. **Execute** \u2014 follow your standard workflow for each subtask.
|
|
185
|
+
4. **Track progress** \u2014 after each iteration: \`orch context set {{ task.goal_id | default: "<goal>" }}-progress "<summary of what's done and what remains>"\`.
|
|
186
|
+
5. **Be proactive** \u2014 do NOT wait for tasks from others. Create your own subtasks and keep working.
|
|
187
|
+
6. **Do NOT finish** the [auto] task until the goal is achieved \u2014 keep creating subtasks.
|
|
188
|
+
7. **When done** \u2014 mark the goal as achieved: \`orch goal status {{ task.goal_id | default: "<goal-id>" }} achieved\`.
|
|
189
|
+
|
|
190
|
+
**Deep inspection:** Use \`orch goal show {{ task.goal_id | default: "<goal-id>" }}\` to see full goal details at any time.
|
|
191
|
+
{% endif %}
|
|
192
|
+
|
|
193
|
+
## Rules
|
|
194
|
+
- Do NOT ask clarifying questions. You are running autonomously without human input.
|
|
195
|
+
- Make reasonable assumptions and proceed with the best approach.
|
|
196
|
+
- If critical information is missing, document your assumptions and continue.
|
|
197
|
+
- When a task is too large or spans multiple domains, break it into subtasks using \`orch task add\`.
|
|
198
|
+
- When creating subtasks, use \`--scope\` to declare which files each task will touch, and \`--depends-on\` to order dependent work.
|
|
199
|
+
`;
|
|
200
|
+
var DEFAULT_USER_TEMPLATE = `## Task: {{ task.title }}
|
|
201
|
+
{{ task.description }}
|
|
202
|
+
|
|
203
|
+
Priority: {{ task.priority }}
|
|
204
|
+
{% if attempt %}Attempt: {{ attempt }}{% endif %}
|
|
205
|
+
{% if retry %}
|
|
206
|
+
## Previous attempt failed
|
|
207
|
+
**Error:** {{ retry.previous_error }}
|
|
208
|
+
{% if retry.previous_output != "" %}
|
|
209
|
+
**Last output:**
|
|
210
|
+
\`\`\`
|
|
211
|
+
{{ retry.previous_output }}
|
|
212
|
+
\`\`\`
|
|
213
|
+
{% endif %}
|
|
214
|
+
**Important:** The previous approach failed. Analyze the error above and try a different strategy. Do NOT repeat the same steps that led to the failure.
|
|
215
|
+
{% endif %}
|
|
216
|
+
|
|
217
|
+
## Context
|
|
218
|
+
Project: {{ project.name }}
|
|
219
|
+
Working directory: {{ workspace_path }}
|
|
220
|
+
|
|
221
|
+
## Team
|
|
222
|
+
You are part of a multi-agent team. Available agents:
|
|
223
|
+
{% for a in agents %}- **{{ a.name }}** ({{ a.adapter }}){% if a.role %} \u2014 {{ a.role }}{% endif %} \xB7 ID: \`{{ a.id }}\`
|
|
224
|
+
{% endfor %}
|
|
225
|
+
Use \`orch agent list\` to check current agent statuses. Find teammates by name/role \u2014 do NOT hardcode agent IDs.
|
|
226
|
+
|
|
227
|
+
{% if feedback %}
|
|
228
|
+
## Review Feedback
|
|
229
|
+
This task was previously completed but **rejected** during review with the following feedback:
|
|
230
|
+
> {{ feedback }}
|
|
231
|
+
|
|
232
|
+
**Important:** Address the feedback above. Focus on what the reviewer asked to change. Do NOT redo work that was already accepted.
|
|
233
|
+
{% endif %}
|
|
234
|
+
|
|
235
|
+
{% if shared_context %}
|
|
236
|
+
## Shared Context
|
|
237
|
+
Other agents have shared the following information:
|
|
238
|
+
{% for entry in shared_context %}- **{{ entry[0] }}**: {{ entry[1] }}
|
|
239
|
+
{% endfor %}
|
|
240
|
+
{% endif %}
|
|
241
|
+
|
|
242
|
+
{% if messages %}
|
|
243
|
+
## Inbox ({{ messages.size }} message{% if messages.size != 1 %}s{% endif %})
|
|
244
|
+
{% for msg in messages %}
|
|
245
|
+
---
|
|
246
|
+
**From:** {{ msg.from }}{% if msg.subject != "" %} \xB7 **Subject:** {{ msg.subject }}{% endif %}
|
|
247
|
+
{{ msg.body }}
|
|
248
|
+
{% if msg.reply_to %}*(Reply to: {{ msg.reply_to }})*{% endif %}
|
|
249
|
+
---
|
|
250
|
+
{% endfor %}
|
|
251
|
+
{% endif %}
|
|
252
|
+
|
|
253
|
+
{% if goal %}
|
|
254
|
+
## Goal: {{ goal.title }}
|
|
255
|
+
**Status:** {{ goal.status }} \xB7 **ID:** \`{{ goal.id }}\`
|
|
256
|
+
{% if goal.description != "" %}
|
|
257
|
+
{{ goal.description }}
|
|
258
|
+
{% endif %}
|
|
259
|
+
{% if goal.task_names.size > 0 %}
|
|
260
|
+
**Linked tasks ({{ goal.task_names.size }}):**
|
|
261
|
+
{% for name in goal.task_names %}- {{ name }}
|
|
262
|
+
{% endfor %}
|
|
263
|
+
Use \`orch task list --goal-id {{ goal.id }}\` and \`orch task show <id>\` to inspect details.
|
|
264
|
+
{% endif %}
|
|
265
|
+
{% if goal.progress %}
|
|
266
|
+
**Latest progress report:**
|
|
267
|
+
{{ goal.progress }}
|
|
268
|
+
{% endif %}
|
|
269
|
+
{% endif %}
|
|
270
|
+
`;
|
|
271
|
+
var DEFAULT_PROMPT_TEMPLATE = DEFAULT_SYSTEM_TEMPLATE + "\n" + DEFAULT_USER_TEMPLATE;
|
|
272
|
+
|
|
273
|
+
export { AUTONOMOUS_LABEL, DEFAULT_PROMPT_TEMPLATE, DEFAULT_SYSTEM_TEMPLATE, DEFAULT_USER_TEMPLATE, LiquidTemplateEngine, buildPromptContext, filterRelevantContext };
|
|
274
|
+
//# sourceMappingURL=chunk-VG4465AG.js.map
|
|
275
|
+
//# sourceMappingURL=chunk-VG4465AG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/task.ts","../src/infrastructure/template/template-engine.ts"],"names":[],"mappings":"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","file":"chunk-VG4465AG.js","sourcesContent":["/**\n * Task domain model.\n *\n * A Task is the unit of work in the orchestrator.\n * It moves through a state machine: todo → in_progress → review → done.\n */\n\nexport type TaskStatus =\n | 'todo'\n | 'in_progress'\n | 'retrying'\n | 'review'\n | 'done'\n | 'failed'\n | 'cancelled';\n\n/** Label applied to tasks auto-generated by the orchestrator for autonomous agents. */\nexport const AUTONOMOUS_LABEL = 'autonomous' as const;\n\nexport type WorkspaceMode = 'shared' | 'worktree' | 'isolated';\n\nexport type ReviewCriterion = 'test_pass' | 'typecheck' | 'lint';\n\nexport interface ReviewResult {\n criterion: ReviewCriterion;\n passed: boolean;\n output: string;\n}\n\nexport interface TaskProof {\n branch?: string;\n pr_url?: string;\n files_changed: string[];\n test_results?: string;\n agent_summary?: string;\n}\n\nexport interface Task {\n id: string;\n title: string;\n description: string;\n status: TaskStatus;\n priority: number;\n assignee?: string;\n labels: string[];\n depends_on: string[];\n created_at: string;\n updated_at: string;\n attempts: number;\n max_attempts: number;\n workspace_mode?: WorkspaceMode;\n workspace?: string;\n proof?: TaskProof;\n review_criteria?: ReviewCriterion[];\n review_results?: ReviewResult[];\n scope?: string[];\n feedback?: string;\n goalId?: string;\n attachments?: string[];\n}\n\nexport interface CreateTaskInput {\n title: string;\n description?: string;\n priority?: number;\n assignee?: string;\n labels?: string[];\n depends_on?: string[];\n max_attempts?: number;\n workspace_mode?: WorkspaceMode;\n review_criteria?: ReviewCriterion[];\n scope?: string[];\n goalId?: string;\n attachments?: string[];\n}\n","/**\n * Template engine for prompt construction.\n *\n * Uses LiquidJS for Liquid-compatible templating with\n * task, agent, project, and run context variables.\n */\n\nimport type { Liquid } from 'liquidjs';\nimport type { Agent } from '../../domain/agent.js';\nimport type { GoalStatus } from '../../domain/goal.js';\nimport type { OrchestratorConfig } from '../../domain/config.js';\nimport { AUTONOMOUS_LABEL, type Task } from '../../domain/task.js';\n\nexport interface ITemplateEngine {\n render(template: string, context: PromptContext): Promise<string>;\n}\n\nexport interface AgentInfo {\n id: string;\n name: string;\n role?: string;\n adapter: string;\n}\n\nexport interface RetryContext {\n previous_error: string;\n previous_output: string;\n}\n\nexport interface GoalContext {\n id: string;\n title: string;\n description: string;\n status: GoalStatus;\n task_names: string[];\n progress?: string;\n}\n\nexport interface PromptContext {\n project: {\n name: string;\n description?: string;\n };\n task: {\n id: string;\n title: string;\n description: string;\n priority: number;\n labels: string[];\n scope?: string[];\n is_autonomous: boolean;\n goal_id?: string;\n };\n agent: {\n id: string;\n name: string;\n role?: string;\n };\n agents: AgentInfo[];\n attempt: number | null;\n workspace_path: string;\n retry?: RetryContext;\n feedback?: string;\n shared_context?: Record<string, string>;\n messages?: Array<{\n id: string;\n from: string;\n subject: string;\n body: string;\n sent_at: string;\n reply_to?: string;\n }>;\n goal?: GoalContext;\n}\n\nexport class LiquidTemplateEngine implements ITemplateEngine {\n private engine: Liquid | undefined;\n private readonly renderTimeoutMs: number;\n\n constructor(options?: { renderTimeoutMs?: number }) {\n this.renderTimeoutMs = options?.renderTimeoutMs ?? 5_000;\n }\n\n private async getEngine(): Promise<Liquid> {\n if (!this.engine) {\n const { Liquid } = await import('liquidjs');\n this.engine = new Liquid({\n strictFilters: false,\n strictVariables: false,\n });\n }\n return this.engine;\n }\n\n async render(template: string, context: PromptContext): Promise<string> {\n const engine = await this.getEngine();\n const renderPromise = engine.parseAndRender(template, context);\n\n if (this.renderTimeoutMs <= 0) {\n return renderPromise;\n }\n\n let timer: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`Template render timed out after ${this.renderTimeoutMs}ms`)),\n this.renderTimeoutMs,\n );\n });\n\n try {\n return await Promise.race([renderPromise, timeoutPromise]);\n } finally {\n clearTimeout(timer!);\n }\n }\n}\n\n/** Max number of context entries injected into a single prompt. */\nconst MAX_CONTEXT_ENTRIES = 15;\n\nexport interface ContextFilterInput {\n agentName: string;\n agentRole?: string;\n goalId?: string;\n taskScope?: string[];\n}\n\n/**\n * Score and filter shared context entries by relevance to the current agent/task.\n * Returns at most MAX_CONTEXT_ENTRIES entries, sorted by relevance then freshness.\n */\nexport function filterRelevantContext(\n allContext: Record<string, string>,\n filter: ContextFilterInput,\n): Record<string, string> {\n const entries = Object.entries(allContext);\n if (entries.length === 0) return {};\n\n const agentLower = filter.agentName.toLowerCase();\n // Derive role keyword(s) from agent name — e.g. \"Backend A\" → \"backend\"\n const roleKeywords = extractRoleKeywords(agentLower, filter.agentRole);\n\n type Scored = { key: string; value: string; score: number };\n const scored: Scored[] = [];\n\n for (const [key, value] of entries) {\n let score = 0;\n const keyLower = key.toLowerCase();\n\n // 1. Goal match (highest priority)\n if (filter.goalId && keyLower.startsWith(filter.goalId.toLowerCase())) {\n score += 10;\n }\n\n // 2. Agent name match — context key or value mentions this agent\n if (keyLower.includes(agentLower) || value.toLowerCase().includes(agentLower)) {\n score += 8;\n }\n\n // 3. Scope path match — context mentions paths from task scope\n if (filter.taskScope?.length) {\n for (const scopePattern of filter.taskScope) {\n const scopeBase = scopePattern.replace(/\\*+/g, '').replace(/\\/+$/, '');\n if (scopeBase && (keyLower.includes(scopeBase.toLowerCase()) || value.toLowerCase().includes(scopeBase.toLowerCase()))) {\n score += 6;\n break;\n }\n }\n }\n\n // 4. Role-prefix match — e.g. \"backend-*\" keys for backend agents\n for (const kw of roleKeywords) {\n if (keyLower.startsWith(kw + '-') || keyLower.startsWith(kw + '_')) {\n score += 4;\n break;\n }\n }\n\n // 5. Generic project-wide context (bug-, perf-, stability-, docs-) gets a small boost\n if (/^(bug|perf|stability|docs|arch|spec)-/i.test(key)) {\n score += 1;\n }\n\n scored.push({ key, value, score });\n }\n\n // Sort by score desc; entries with score 0 are excluded unless we have fewer than limit\n scored.sort((a, b) => b.score - a.score);\n\n // Take top entries: all with score > 0, then pad with score-0 up to limit\n const relevant = scored.filter((e) => e.score > 0).slice(0, MAX_CONTEXT_ENTRIES);\n if (relevant.length < MAX_CONTEXT_ENTRIES) {\n const remaining = scored.filter((e) => e.score === 0).slice(0, MAX_CONTEXT_ENTRIES - relevant.length);\n relevant.push(...remaining);\n }\n\n // Build result — pass values through as-is (no truncation)\n const result: Record<string, string> = {};\n for (const { key, value } of relevant) {\n result[key] = value;\n }\n return result;\n}\n\n/**\n * Extract role keywords from agent name and role for prefix matching.\n * \"Backend A\" → [\"backend\"], \"QA B\" → [\"qa\"], \"Front-End\" → [\"front-end\", \"frontend\", \"tui\"]\n */\nfunction extractRoleKeywords(agentNameLower: string, role?: string): string[] {\n const keywords: string[] = [];\n // First word of agent name (e.g. \"backend\", \"qa\", \"reviewer\", \"cto\")\n const firstWord = agentNameLower.split(/[\\s_-]/)[0];\n if (firstWord && firstWord.length > 1) {\n keywords.push(firstWord);\n }\n // Special mappings\n if (agentNameLower.includes('front') || agentNameLower.includes('tui')) {\n keywords.push('front-end', 'frontend', 'tui');\n }\n if (agentNameLower.includes('market') || agentNameLower.includes('cmo')) {\n keywords.push('marketer', 'marketing', 'cmo');\n }\n // Extract from role first line\n if (role) {\n const roleFirstWord = role.toLowerCase().split(/[\\s_-]/)[0];\n if (roleFirstWord && roleFirstWord.length > 2 && !keywords.includes(roleFirstWord)) {\n keywords.push(roleFirstWord);\n }\n }\n return keywords;\n}\n\n/**\n * Build prompt context from domain objects.\n */\nexport interface BuildPromptOptions {\n allAgents?: Agent[];\n retryContext?: RetryContext;\n sharedContext?: Record<string, string>;\n feedback?: string;\n messages?: import('../../domain/message.js').Message[];\n goal?: GoalContext;\n}\n\nexport function buildPromptContext(\n task: Task,\n agent: Agent,\n attempt: number,\n workspacePath: string,\n config: OrchestratorConfig,\n options?: BuildPromptOptions,\n): PromptContext {\n const { allAgents, retryContext, sharedContext, feedback, messages: rawMessages, goal } = options ?? {};\n\n // Map messages to prompt-friendly shape\n const agentById = new Map((allAgents ?? []).map((a) => [a.id, a]));\n const messages = rawMessages?.length\n ? rawMessages.map((m) => ({\n id: m.id,\n from: agentById.get(m.from_agent_id)?.name ?? m.from_agent_id,\n subject: m.subject,\n body: m.body,\n sent_at: m.created_at,\n reply_to: m.reply_to,\n }))\n : undefined;\n\n return {\n project: {\n name: config.project.name,\n description: config.project.description,\n },\n task: {\n id: task.id,\n title: task.title,\n description: task.description,\n priority: task.priority,\n labels: task.labels,\n scope: task.scope,\n is_autonomous: task.labels?.includes(AUTONOMOUS_LABEL) ?? false,\n goal_id: task.goalId,\n },\n agent: {\n id: agent.id,\n name: agent.name,\n role: agent.role,\n },\n agents: (allAgents ?? []).map((a) => ({\n id: a.id,\n name: a.name,\n role: a.id === agent.id ? undefined : a.role,\n adapter: a.adapter,\n })),\n attempt: attempt > 1 ? attempt : null,\n workspace_path: workspacePath,\n retry: attempt > 1 ? retryContext : undefined,\n feedback,\n shared_context: sharedContext && Object.keys(sharedContext).length > 0\n ? filterRelevantContext(sharedContext, {\n agentName: agent.name,\n agentRole: agent.role,\n goalId: task.goalId,\n taskScope: task.scope,\n })\n : undefined,\n messages,\n goal,\n };\n}\n\n/**\n * Static system prompt template — cached by Claude API between runs.\n * Contains: agent identity, CLI reference, autonomous mode, rules.\n * Variables used: agent.name, agent.role, agent.id, task.is_autonomous, task.goal_id.\n */\nexport const DEFAULT_SYSTEM_TEMPLATE = `You are {{ agent.name }}{% if agent.role %} ({{ agent.role }}){% endif %}.\n\n## Orchestrator CLI\nManage tasks and coordinate with other agents using \\`orch\\`:\n\n**Tasks:**\n- \\`orch task add \"<title>\" -d \"<description>\" -p <1-4> --assignee <agent-id>\\` — create and assign a task\n- \\`orch task add \"<title>\" -d \"<description>\" --scope \"src/path/**\" --depends-on <task-id>\\` — scoped task with dependency\n- \\`orch task list [--status todo|in_progress|done|failed]\\` — list tasks\n\n**Messaging:**\n- \\`orch msg send <agent-id> \"<body>\" -s \"<subject>\"\\` — direct message\n- \\`orch msg broadcast \"<body>\" -s \"<subject>\"\\` — broadcast to all\n- \\`orch msg inbox {{ agent.id }}\\` — your pending messages\n\n**Shared context:**\n- \\`orch context set <key> <value>\\` / \\`orch context get <key>\\` / \\`orch context list\\`\n\n{% if task.is_autonomous %}\n## Autonomous Goal Mode\nThis is an autonomous task driven by a goal. Work in a continuous loop until the goal is achieved:\n\n1. **Understand the goal** — read the Goal section above.\n2. **Decompose** — break the goal into concrete subtasks via \\`orch task add\\`. {% if task.goal_id %}Pass \\`--goal-id {{ task.goal_id }}\\` so subtasks are linked to this goal. {% endif %}Assign yourself for your specialty, delegate other work to appropriate teammates by role.\n3. **Execute** — follow your standard workflow for each subtask.\n4. **Track progress** — after each iteration: \\`orch context set {{ task.goal_id | default: \"<goal>\" }}-progress \"<summary of what's done and what remains>\"\\`.\n5. **Be proactive** — do NOT wait for tasks from others. Create your own subtasks and keep working.\n6. **Do NOT finish** the [auto] task until the goal is achieved — keep creating subtasks.\n7. **When done** — mark the goal as achieved: \\`orch goal status {{ task.goal_id | default: \"<goal-id>\" }} achieved\\`.\n\n**Deep inspection:** Use \\`orch goal show {{ task.goal_id | default: \"<goal-id>\" }}\\` to see full goal details at any time.\n{% endif %}\n\n## Rules\n- Do NOT ask clarifying questions. You are running autonomously without human input.\n- Make reasonable assumptions and proceed with the best approach.\n- If critical information is missing, document your assumptions and continue.\n- When a task is too large or spans multiple domains, break it into subtasks using \\`orch task add\\`.\n- When creating subtasks, use \\`--scope\\` to declare which files each task will touch, and \\`--depends-on\\` to order dependent work.\n`;\n\n/**\n * Dynamic user prompt template — changes every run.\n * Contains: task details, attempt/retry, team, context, messages, goal, feedback.\n */\nexport const DEFAULT_USER_TEMPLATE = `## Task: {{ task.title }}\n{{ task.description }}\n\nPriority: {{ task.priority }}\n{% if attempt %}Attempt: {{ attempt }}{% endif %}\n{% if retry %}\n## Previous attempt failed\n**Error:** {{ retry.previous_error }}\n{% if retry.previous_output != \"\" %}\n**Last output:**\n\\`\\`\\`\n{{ retry.previous_output }}\n\\`\\`\\`\n{% endif %}\n**Important:** The previous approach failed. Analyze the error above and try a different strategy. Do NOT repeat the same steps that led to the failure.\n{% endif %}\n\n## Context\nProject: {{ project.name }}\nWorking directory: {{ workspace_path }}\n\n## Team\nYou are part of a multi-agent team. Available agents:\n{% for a in agents %}- **{{ a.name }}** ({{ a.adapter }}){% if a.role %} — {{ a.role }}{% endif %} · ID: \\`{{ a.id }}\\`\n{% endfor %}\nUse \\`orch agent list\\` to check current agent statuses. Find teammates by name/role — do NOT hardcode agent IDs.\n\n{% if feedback %}\n## Review Feedback\nThis task was previously completed but **rejected** during review with the following feedback:\n> {{ feedback }}\n\n**Important:** Address the feedback above. Focus on what the reviewer asked to change. Do NOT redo work that was already accepted.\n{% endif %}\n\n{% if shared_context %}\n## Shared Context\nOther agents have shared the following information:\n{% for entry in shared_context %}- **{{ entry[0] }}**: {{ entry[1] }}\n{% endfor %}\n{% endif %}\n\n{% if messages %}\n## Inbox ({{ messages.size }} message{% if messages.size != 1 %}s{% endif %})\n{% for msg in messages %}\n---\n**From:** {{ msg.from }}{% if msg.subject != \"\" %} · **Subject:** {{ msg.subject }}{% endif %}\n{{ msg.body }}\n{% if msg.reply_to %}*(Reply to: {{ msg.reply_to }})*{% endif %}\n---\n{% endfor %}\n{% endif %}\n\n{% if goal %}\n## Goal: {{ goal.title }}\n**Status:** {{ goal.status }} · **ID:** \\`{{ goal.id }}\\`\n{% if goal.description != \"\" %}\n{{ goal.description }}\n{% endif %}\n{% if goal.task_names.size > 0 %}\n**Linked tasks ({{ goal.task_names.size }}):**\n{% for name in goal.task_names %}- {{ name }}\n{% endfor %}\nUse \\`orch task list --goal-id {{ goal.id }}\\` and \\`orch task show <id>\\` to inspect details.\n{% endif %}\n{% if goal.progress %}\n**Latest progress report:**\n{{ goal.progress }}\n{% endif %}\n{% endif %}\n`;\n\n/** @deprecated Use DEFAULT_SYSTEM_TEMPLATE + DEFAULT_USER_TEMPLATE instead */\nexport const DEFAULT_PROMPT_TEMPLATE = DEFAULT_SYSTEM_TEMPLATE + '\\n' + DEFAULT_USER_TEMPLATE;\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { AUTONOMOUS_LABEL } from './chunk-PNE6LQRF.js';
|
|
3
3
|
|
|
4
4
|
// src/infrastructure/template/template-engine.ts
|
|
5
5
|
var LiquidTemplateEngine = class {
|
|
@@ -38,6 +38,74 @@ var LiquidTemplateEngine = class {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
|
+
var MAX_CONTEXT_ENTRIES = 15;
|
|
42
|
+
function filterRelevantContext(allContext, filter) {
|
|
43
|
+
const entries = Object.entries(allContext);
|
|
44
|
+
if (entries.length === 0) return {};
|
|
45
|
+
const agentLower = filter.agentName.toLowerCase();
|
|
46
|
+
const roleKeywords = extractRoleKeywords(agentLower, filter.agentRole);
|
|
47
|
+
const scored = [];
|
|
48
|
+
for (const [key, value] of entries) {
|
|
49
|
+
let score = 0;
|
|
50
|
+
const keyLower = key.toLowerCase();
|
|
51
|
+
if (filter.goalId && keyLower.startsWith(filter.goalId.toLowerCase())) {
|
|
52
|
+
score += 10;
|
|
53
|
+
}
|
|
54
|
+
if (keyLower.includes(agentLower) || value.toLowerCase().includes(agentLower)) {
|
|
55
|
+
score += 8;
|
|
56
|
+
}
|
|
57
|
+
if (filter.taskScope?.length) {
|
|
58
|
+
for (const scopePattern of filter.taskScope) {
|
|
59
|
+
const scopeBase = scopePattern.replace(/\*+/g, "").replace(/\/+$/, "");
|
|
60
|
+
if (scopeBase && (keyLower.includes(scopeBase.toLowerCase()) || value.toLowerCase().includes(scopeBase.toLowerCase()))) {
|
|
61
|
+
score += 6;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const kw of roleKeywords) {
|
|
67
|
+
if (keyLower.startsWith(kw + "-") || keyLower.startsWith(kw + "_")) {
|
|
68
|
+
score += 4;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (/^(bug|perf|stability|docs|arch|spec)-/i.test(key)) {
|
|
73
|
+
score += 1;
|
|
74
|
+
}
|
|
75
|
+
scored.push({ key, value, score });
|
|
76
|
+
}
|
|
77
|
+
scored.sort((a, b) => b.score - a.score);
|
|
78
|
+
const relevant = scored.filter((e) => e.score > 0).slice(0, MAX_CONTEXT_ENTRIES);
|
|
79
|
+
if (relevant.length < MAX_CONTEXT_ENTRIES) {
|
|
80
|
+
const remaining = scored.filter((e) => e.score === 0).slice(0, MAX_CONTEXT_ENTRIES - relevant.length);
|
|
81
|
+
relevant.push(...remaining);
|
|
82
|
+
}
|
|
83
|
+
const result = {};
|
|
84
|
+
for (const { key, value } of relevant) {
|
|
85
|
+
result[key] = value;
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
function extractRoleKeywords(agentNameLower, role) {
|
|
90
|
+
const keywords = [];
|
|
91
|
+
const firstWord = agentNameLower.split(/[\s_-]/)[0];
|
|
92
|
+
if (firstWord && firstWord.length > 1) {
|
|
93
|
+
keywords.push(firstWord);
|
|
94
|
+
}
|
|
95
|
+
if (agentNameLower.includes("front") || agentNameLower.includes("tui")) {
|
|
96
|
+
keywords.push("front-end", "frontend", "tui");
|
|
97
|
+
}
|
|
98
|
+
if (agentNameLower.includes("market") || agentNameLower.includes("cmo")) {
|
|
99
|
+
keywords.push("marketer", "marketing", "cmo");
|
|
100
|
+
}
|
|
101
|
+
if (role) {
|
|
102
|
+
const roleFirstWord = role.toLowerCase().split(/[\s_-]/)[0];
|
|
103
|
+
if (roleFirstWord && roleFirstWord.length > 2 && !keywords.includes(roleFirstWord)) {
|
|
104
|
+
keywords.push(roleFirstWord);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return keywords;
|
|
108
|
+
}
|
|
41
109
|
function buildPromptContext(task, agent, attempt, workspacePath, config, options) {
|
|
42
110
|
const { allAgents, retryContext, sharedContext, feedback, messages: rawMessages, goal } = options ?? {};
|
|
43
111
|
const agentById = new Map((allAgents ?? []).map((a) => [a.id, a]));
|
|
@@ -72,21 +140,64 @@ function buildPromptContext(task, agent, attempt, workspacePath, config, options
|
|
|
72
140
|
agents: (allAgents ?? []).map((a) => ({
|
|
73
141
|
id: a.id,
|
|
74
142
|
name: a.name,
|
|
75
|
-
role: a.role,
|
|
143
|
+
role: a.id === agent.id ? void 0 : a.role,
|
|
76
144
|
adapter: a.adapter
|
|
77
145
|
})),
|
|
78
146
|
attempt: attempt > 1 ? attempt : null,
|
|
79
147
|
workspace_path: workspacePath,
|
|
80
148
|
retry: attempt > 1 ? retryContext : void 0,
|
|
81
149
|
feedback,
|
|
82
|
-
shared_context: sharedContext && Object.keys(sharedContext).length > 0 ? sharedContext
|
|
150
|
+
shared_context: sharedContext && Object.keys(sharedContext).length > 0 ? filterRelevantContext(sharedContext, {
|
|
151
|
+
agentName: agent.name,
|
|
152
|
+
agentRole: agent.role,
|
|
153
|
+
goalId: task.goalId,
|
|
154
|
+
taskScope: task.scope
|
|
155
|
+
}) : void 0,
|
|
83
156
|
messages,
|
|
84
157
|
goal
|
|
85
158
|
};
|
|
86
159
|
}
|
|
87
|
-
var
|
|
160
|
+
var DEFAULT_SYSTEM_TEMPLATE = `You are {{ agent.name }}{% if agent.role %} ({{ agent.role }}){% endif %}.
|
|
161
|
+
|
|
162
|
+
## Orchestrator CLI
|
|
163
|
+
Manage tasks and coordinate with other agents using \`orch\`:
|
|
164
|
+
|
|
165
|
+
**Tasks:**
|
|
166
|
+
- \`orch task add "<title>" -d "<description>" -p <1-4> --assignee <agent-id>\` \u2014 create and assign a task
|
|
167
|
+
- \`orch task add "<title>" -d "<description>" --scope "src/path/**" --depends-on <task-id>\` \u2014 scoped task with dependency
|
|
168
|
+
- \`orch task list [--status todo|in_progress|done|failed]\` \u2014 list tasks
|
|
169
|
+
|
|
170
|
+
**Messaging:**
|
|
171
|
+
- \`orch msg send <agent-id> "<body>" -s "<subject>"\` \u2014 direct message
|
|
172
|
+
- \`orch msg broadcast "<body>" -s "<subject>"\` \u2014 broadcast to all
|
|
173
|
+
- \`orch msg inbox {{ agent.id }}\` \u2014 your pending messages
|
|
174
|
+
|
|
175
|
+
**Shared context:**
|
|
176
|
+
- \`orch context set <key> <value>\` / \`orch context get <key>\` / \`orch context list\`
|
|
177
|
+
|
|
178
|
+
{% if task.is_autonomous %}
|
|
179
|
+
## Autonomous Goal Mode
|
|
180
|
+
This is an autonomous task driven by a goal. Work in a continuous loop until the goal is achieved:
|
|
181
|
+
|
|
182
|
+
1. **Understand the goal** \u2014 read the Goal section above.
|
|
183
|
+
2. **Decompose** \u2014 break the goal into concrete subtasks via \`orch task add\`. {% if task.goal_id %}Pass \`--goal-id {{ task.goal_id }}\` so subtasks are linked to this goal. {% endif %}Assign yourself for your specialty, delegate other work to appropriate teammates by role.
|
|
184
|
+
3. **Execute** \u2014 follow your standard workflow for each subtask.
|
|
185
|
+
4. **Track progress** \u2014 after each iteration: \`orch context set {{ task.goal_id | default: "<goal>" }}-progress "<summary of what's done and what remains>"\`.
|
|
186
|
+
5. **Be proactive** \u2014 do NOT wait for tasks from others. Create your own subtasks and keep working.
|
|
187
|
+
6. **Do NOT finish** the [auto] task until the goal is achieved \u2014 keep creating subtasks.
|
|
188
|
+
7. **When done** \u2014 mark the goal as achieved: \`orch goal status {{ task.goal_id | default: "<goal-id>" }} achieved\`.
|
|
189
|
+
|
|
190
|
+
**Deep inspection:** Use \`orch goal show {{ task.goal_id | default: "<goal-id>" }}\` to see full goal details at any time.
|
|
191
|
+
{% endif %}
|
|
88
192
|
|
|
89
|
-
##
|
|
193
|
+
## Rules
|
|
194
|
+
- Do NOT ask clarifying questions. You are running autonomously without human input.
|
|
195
|
+
- Make reasonable assumptions and proceed with the best approach.
|
|
196
|
+
- If critical information is missing, document your assumptions and continue.
|
|
197
|
+
- When a task is too large or spans multiple domains, break it into subtasks using \`orch task add\`.
|
|
198
|
+
- When creating subtasks, use \`--scope\` to declare which files each task will touch, and \`--depends-on\` to order dependent work.
|
|
199
|
+
`;
|
|
200
|
+
var DEFAULT_USER_TEMPLATE = `## Task: {{ task.title }}
|
|
90
201
|
{{ task.description }}
|
|
91
202
|
|
|
92
203
|
Priority: {{ task.priority }}
|
|
@@ -139,22 +250,6 @@ Other agents have shared the following information:
|
|
|
139
250
|
{% endfor %}
|
|
140
251
|
{% endif %}
|
|
141
252
|
|
|
142
|
-
## Orchestrator CLI
|
|
143
|
-
Manage tasks and coordinate with other agents using \`orch\`:
|
|
144
|
-
|
|
145
|
-
**Tasks:**
|
|
146
|
-
- \`orch task add "<title>" -d "<description>" -p <1-4> --assignee <agent-id>\` \u2014 create and assign a task
|
|
147
|
-
- \`orch task add "<title>" -d "<description>" --scope "src/path/**" --depends-on <task-id>\` \u2014 scoped task with dependency
|
|
148
|
-
- \`orch task list [--status todo|in_progress|done|failed]\` \u2014 list tasks
|
|
149
|
-
|
|
150
|
-
**Messaging:**
|
|
151
|
-
- \`orch msg send <agent-id> "<body>" -s "<subject>"\` \u2014 direct message
|
|
152
|
-
- \`orch msg broadcast "<body>" -s "<subject>"\` \u2014 broadcast to all
|
|
153
|
-
- \`orch msg inbox {{ agent.id }}\` \u2014 your pending messages
|
|
154
|
-
|
|
155
|
-
**Shared context:**
|
|
156
|
-
- \`orch context set <key> <value>\` / \`orch context get <key>\` / \`orch context list\`
|
|
157
|
-
|
|
158
253
|
{% if goal %}
|
|
159
254
|
## Goal: {{ goal.title }}
|
|
160
255
|
**Status:** {{ goal.status }} \xB7 **ID:** \`{{ goal.id }}\`
|
|
@@ -172,30 +267,7 @@ Use \`orch task list --goal-id {{ goal.id }}\` and \`orch task show <id>\` to in
|
|
|
172
267
|
{{ goal.progress }}
|
|
173
268
|
{% endif %}
|
|
174
269
|
{% endif %}
|
|
175
|
-
|
|
176
|
-
{% if task.is_autonomous %}
|
|
177
|
-
## Autonomous Goal Mode
|
|
178
|
-
This is an autonomous task driven by a goal. Work in a continuous loop until the goal is achieved:
|
|
179
|
-
|
|
180
|
-
1. **Understand the goal** \u2014 read the Goal section above.
|
|
181
|
-
2. **Decompose** \u2014 break the goal into concrete subtasks via \`orch task add\`. {% if task.goal_id %}Pass \`--goal-id {{ task.goal_id }}\` so subtasks are linked to this goal. {% endif %}Assign yourself for your specialty, delegate other work to appropriate teammates by role.
|
|
182
|
-
3. **Execute** \u2014 follow your standard workflow for each subtask.
|
|
183
|
-
4. **Track progress** \u2014 after each iteration: \`orch context set {{ task.goal_id | default: "<goal>" }}-progress "<summary of what's done and what remains>"\`.
|
|
184
|
-
5. **Be proactive** \u2014 do NOT wait for tasks from others. Create your own subtasks and keep working.
|
|
185
|
-
6. **Do NOT finish** the [auto] task until the goal is achieved \u2014 keep creating subtasks.
|
|
186
|
-
7. **When done** \u2014 mark the goal as achieved: \`orch goal status {{ task.goal_id | default: "<goal-id>" }} achieved\`.
|
|
187
|
-
|
|
188
|
-
**Deep inspection:** Use \`orch goal show {{ task.goal_id | default: "<goal-id>" }}\` to see full goal details at any time.
|
|
189
|
-
{% endif %}
|
|
190
|
-
|
|
191
|
-
## Rules
|
|
192
|
-
- Do NOT ask clarifying questions. You are running autonomously without human input.
|
|
193
|
-
- Make reasonable assumptions and proceed with the best approach.
|
|
194
|
-
- If critical information is missing, document your assumptions and continue.
|
|
195
|
-
- When a task is too large or spans multiple domains, break it into subtasks using \`orch task add\`.
|
|
196
|
-
- When creating subtasks, use \`--scope\` to declare which files each task will touch, and \`--depends-on\` to order dependent work.
|
|
197
270
|
`;
|
|
271
|
+
var DEFAULT_PROMPT_TEMPLATE = DEFAULT_SYSTEM_TEMPLATE + "\n" + DEFAULT_USER_TEMPLATE;
|
|
198
272
|
|
|
199
|
-
export {
|
|
200
|
-
//# sourceMappingURL=chunk-B4JQM4NU.js.map
|
|
201
|
-
//# sourceMappingURL=chunk-B4JQM4NU.js.map
|
|
273
|
+
export { DEFAULT_PROMPT_TEMPLATE, DEFAULT_SYSTEM_TEMPLATE, DEFAULT_USER_TEMPLATE, LiquidTemplateEngine, buildPromptContext, filterRelevantContext };
|