@grackle-ai/server 0.55.0 → 0.56.1
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/adapters/codespace.d.ts.map +1 -1
- package/dist/adapters/codespace.js +1 -0
- package/dist/adapters/codespace.js.map +1 -1
- package/dist/adapters/docker.d.ts.map +1 -1
- package/dist/adapters/docker.js +1 -0
- package/dist/adapters/docker.js.map +1 -1
- package/dist/adapters/ssh.d.ts.map +1 -1
- package/dist/adapters/ssh.js +1 -0
- package/dist/adapters/ssh.js.map +1 -1
- package/dist/grpc-service.d.ts.map +1 -1
- package/dist/grpc-service.js +14 -3
- package/dist/grpc-service.js.map +1 -1
- package/dist/index.js +53 -3
- package/dist/index.js.map +1 -1
- package/dist/orchestrator-context.d.ts +31 -0
- package/dist/orchestrator-context.d.ts.map +1 -0
- package/dist/orchestrator-context.js +69 -0
- package/dist/orchestrator-context.js.map +1 -0
- package/dist/system-prompt-builder.d.ts +103 -2
- package/dist/system-prompt-builder.d.ts.map +1 -1
- package/dist/system-prompt-builder.js +226 -7
- package/dist/system-prompt-builder.js.map +1 -1
- package/dist/ws-bridge.d.ts +8 -1
- package/dist/ws-bridge.d.ts.map +1 -1
- package/dist/ws-bridge.js +27 -22
- package/dist/ws-bridge.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Builds system prompts for agent sessions, assembling sections
|
|
3
3
|
* dynamically based on the session type (task vs ad-hoc).
|
|
4
|
+
*
|
|
5
|
+
* Orchestrator tasks (canDecompose + depth <= 1) receive rich project
|
|
6
|
+
* context (task tree, persona roster, environments, findings).
|
|
7
|
+
* Leaf tasks receive the existing completion-contract template.
|
|
8
|
+
* Task title and description are NOT included in the system prompt — they
|
|
9
|
+
* belong in the user prompt (see {@link buildTaskPrompt}).
|
|
4
10
|
*/
|
|
11
|
+
/** Build the user-facing prompt from task title, description, and optional notes. */
|
|
12
|
+
export function buildTaskPrompt(title, description, notes) {
|
|
13
|
+
const parts = [title];
|
|
14
|
+
if (description) {
|
|
15
|
+
parts.push(description);
|
|
16
|
+
}
|
|
17
|
+
if (notes) {
|
|
18
|
+
parts.push(`## Notes\n${notes}`);
|
|
19
|
+
}
|
|
20
|
+
return parts.join("\n\n");
|
|
21
|
+
}
|
|
22
|
+
// ─── Builder ─────────────────────────────────────────────────
|
|
5
23
|
/**
|
|
6
24
|
* Assembles a system prompt from discrete sections based on session type.
|
|
7
25
|
*
|
|
8
|
-
*
|
|
26
|
+
* Orchestrator tasks get project state, task tree, persona roster, and
|
|
27
|
+
* decomposition guidelines. Leaf tasks get the existing completion contract.
|
|
9
28
|
* Ad-hoc sessions get only the MCP note and persona prompt.
|
|
29
|
+
* Task title and description are NOT included here — they belong in the user prompt
|
|
30
|
+
* (see {@link buildTaskPrompt}).
|
|
10
31
|
*/
|
|
11
32
|
export class SystemPromptBuilder {
|
|
12
33
|
options;
|
|
@@ -21,16 +42,214 @@ export class SystemPromptBuilder {
|
|
|
21
42
|
sections.push(this.options.personaPrompt);
|
|
22
43
|
}
|
|
23
44
|
if (this.options.task) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
if (this.isOrchestrator()) {
|
|
46
|
+
sections.push(this.buildOrchestratorTaskContext());
|
|
47
|
+
sections.push(this.buildWorkspaceContext());
|
|
48
|
+
sections.push(this.buildTaskTree());
|
|
49
|
+
sections.push(this.buildAvailablePersonas());
|
|
50
|
+
sections.push(this.buildAvailableEnvironments());
|
|
51
|
+
sections.push(this.buildOrchestratorFindingsSection());
|
|
52
|
+
sections.push(this.buildTriggerContext());
|
|
53
|
+
sections.push(this.buildDecompositionGuidelines());
|
|
54
|
+
sections.push(this.buildOrchestratorTools());
|
|
55
|
+
sections.push(this.buildOrchestratorCompletionContract());
|
|
56
|
+
sections.push(this.buildSignalSection());
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Leaf task: title/description go in the user prompt (buildTaskPrompt), not here.
|
|
60
|
+
sections.push(this.buildCompletionContract());
|
|
61
|
+
sections.push(this.buildSubtaskSection());
|
|
62
|
+
sections.push(this.buildSignalSection());
|
|
63
|
+
sections.push(this.buildFindingsSection());
|
|
64
|
+
}
|
|
29
65
|
}
|
|
30
66
|
// MCP note (always included)
|
|
31
67
|
sections.push(this.buildMcpNote());
|
|
32
68
|
return sections.filter(Boolean).join("\n\n");
|
|
33
69
|
}
|
|
70
|
+
// ─── Orchestrator Detection ──────────────────────────────
|
|
71
|
+
/**
|
|
72
|
+
* Determine whether this is an orchestrator task.
|
|
73
|
+
* Requires canDecompose, shallow depth, AND orchestrator data fields to be
|
|
74
|
+
* present. This ensures existing callers that pass canDecompose without
|
|
75
|
+
* the new fields still get the leaf template.
|
|
76
|
+
*/
|
|
77
|
+
isOrchestrator() {
|
|
78
|
+
return this.options.canDecompose === true
|
|
79
|
+
&& this.options.taskDepth !== undefined
|
|
80
|
+
&& this.options.taskDepth <= 1
|
|
81
|
+
&& this.options.taskTree !== undefined;
|
|
82
|
+
}
|
|
83
|
+
// ─── Orchestrator Sections ───────────────────────────────
|
|
84
|
+
/** Orchestrator task context with role framing. */
|
|
85
|
+
buildOrchestratorTaskContext() {
|
|
86
|
+
const { title, description, notes } = this.options.task;
|
|
87
|
+
const parts = [
|
|
88
|
+
`## Your Task: ${title}`,
|
|
89
|
+
`You are an **orchestrator agent** responsible for decomposing and coordinating work. You do not write code directly — you break work into subtasks, assign personas, manage dependencies, and monitor progress.`,
|
|
90
|
+
];
|
|
91
|
+
if (description) {
|
|
92
|
+
parts.push(description);
|
|
93
|
+
}
|
|
94
|
+
if (notes) {
|
|
95
|
+
parts.push(`### Notes (from previous attempt or user feedback)\n${notes}`);
|
|
96
|
+
}
|
|
97
|
+
return parts.join("\n\n");
|
|
98
|
+
}
|
|
99
|
+
/** Workspace metadata section. */
|
|
100
|
+
buildWorkspaceContext() {
|
|
101
|
+
const ws = this.options.workspace;
|
|
102
|
+
if (!ws) {
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
const lines = [`## Workspace Context`];
|
|
106
|
+
lines.push(`- **Name**: ${ws.name}`);
|
|
107
|
+
if (ws.description) {
|
|
108
|
+
lines.push(`- **Description**: ${ws.description}`);
|
|
109
|
+
}
|
|
110
|
+
if (ws.repoUrl) {
|
|
111
|
+
lines.push(`- **Repository**: ${ws.repoUrl}`);
|
|
112
|
+
}
|
|
113
|
+
return lines.join("\n");
|
|
114
|
+
}
|
|
115
|
+
/** Hierarchical task tree with statuses, personas, and dependencies. */
|
|
116
|
+
buildTaskTree() {
|
|
117
|
+
const nodes = this.options.taskTree;
|
|
118
|
+
if (!nodes || nodes.length === 0) {
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
// Build parent → children map
|
|
122
|
+
const childMap = new Map();
|
|
123
|
+
for (const node of nodes) {
|
|
124
|
+
const key = node.parentTaskId || "";
|
|
125
|
+
const children = childMap.get(key);
|
|
126
|
+
if (children) {
|
|
127
|
+
children.push(node);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
childMap.set(key, [node]);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Status summary
|
|
134
|
+
const counts = new Map();
|
|
135
|
+
for (const node of nodes) {
|
|
136
|
+
counts.set(node.status, (counts.get(node.status) || 0) + 1);
|
|
137
|
+
}
|
|
138
|
+
const summary = [...counts.entries()]
|
|
139
|
+
.map(([status, count]) => `${count} ${status}`)
|
|
140
|
+
.join(", ");
|
|
141
|
+
// Recursive render
|
|
142
|
+
const lines = [];
|
|
143
|
+
const renderNode = (node, indent) => {
|
|
144
|
+
const pad = " ".repeat(indent);
|
|
145
|
+
const persona = node.personaName ? ` (persona: ${node.personaName})` : "";
|
|
146
|
+
const deps = node.dependsOn.length > 0
|
|
147
|
+
? ` [depends on: ${node.dependsOn.join(", ")}]`
|
|
148
|
+
: "";
|
|
149
|
+
const branch = node.branch ? ` [branch: ${node.branch}]` : "";
|
|
150
|
+
const marker = node.id === this.options.taskId ? " <-- YOU" : "";
|
|
151
|
+
lines.push(`${pad}- [${node.status}] ${node.title}${persona}${deps}${branch}${marker}`);
|
|
152
|
+
const children = childMap.get(node.id);
|
|
153
|
+
if (children) {
|
|
154
|
+
for (const child of children) {
|
|
155
|
+
renderNode(child, indent + 1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
// Start from root nodes
|
|
160
|
+
const roots = childMap.get("") || [];
|
|
161
|
+
for (const root of roots) {
|
|
162
|
+
renderNode(root, 0);
|
|
163
|
+
}
|
|
164
|
+
return `## Task Tree\n\nStatus: ${summary}\n\n${lines.join("\n")}`;
|
|
165
|
+
}
|
|
166
|
+
/** Available personas table. */
|
|
167
|
+
buildAvailablePersonas() {
|
|
168
|
+
const personas = this.options.availablePersonas;
|
|
169
|
+
if (!personas || personas.length === 0) {
|
|
170
|
+
return "";
|
|
171
|
+
}
|
|
172
|
+
const rows = personas.map((p) => `| ${p.name} | ${p.description || "—"} | ${p.runtime || "—"} | ${p.model || "—"} |`);
|
|
173
|
+
return [
|
|
174
|
+
`## Available Personas`,
|
|
175
|
+
``,
|
|
176
|
+
`| Name | Description | Runtime | Model |`,
|
|
177
|
+
`|------|-------------|---------|-------|`,
|
|
178
|
+
...rows,
|
|
179
|
+
].join("\n");
|
|
180
|
+
}
|
|
181
|
+
/** Available environments table. */
|
|
182
|
+
buildAvailableEnvironments() {
|
|
183
|
+
const envs = this.options.availableEnvironments;
|
|
184
|
+
if (!envs || envs.length === 0) {
|
|
185
|
+
return "";
|
|
186
|
+
}
|
|
187
|
+
const rows = envs.map((e) => `| ${e.displayName} | ${e.adapterType} | ${e.status} | ${e.defaultRuntime || "—"} |`);
|
|
188
|
+
return [
|
|
189
|
+
`## Available Environments`,
|
|
190
|
+
``,
|
|
191
|
+
`| Name | Adapter | Status | Runtime |`,
|
|
192
|
+
`|------|---------|--------|---------|`,
|
|
193
|
+
...rows,
|
|
194
|
+
].join("\n");
|
|
195
|
+
}
|
|
196
|
+
/** Orchestrator findings section with actual findings data. */
|
|
197
|
+
buildOrchestratorFindingsSection() {
|
|
198
|
+
if (!this.options.findingsContext) {
|
|
199
|
+
return "";
|
|
200
|
+
}
|
|
201
|
+
return this.options.findingsContext;
|
|
202
|
+
}
|
|
203
|
+
/** Trigger context describing why this invocation happened. */
|
|
204
|
+
buildTriggerContext() {
|
|
205
|
+
if (this.options.triggerMode === "resume") {
|
|
206
|
+
return [
|
|
207
|
+
`## Trigger Context`,
|
|
208
|
+
`You are being re-invoked after one or more child tasks completed. Review the task tree above for current statuses and decide what to do next.`,
|
|
209
|
+
].join("\n");
|
|
210
|
+
}
|
|
211
|
+
return [
|
|
212
|
+
`## Trigger Context`,
|
|
213
|
+
`You are being invoked for the first time to orchestrate this workspace. Assess the current state, then decompose your task into subtasks.`,
|
|
214
|
+
].join("\n");
|
|
215
|
+
}
|
|
216
|
+
/** Decomposition heuristics and guardrails. */
|
|
217
|
+
buildDecompositionGuidelines() {
|
|
218
|
+
return [
|
|
219
|
+
`## Decomposition Guidelines`,
|
|
220
|
+
``,
|
|
221
|
+
`- Estimate task complexity before decomposing. Do not decompose simple tasks (under ~100 lines of code or touching fewer than 3 files).`,
|
|
222
|
+
`- Favor context-boundary decomposition over role-boundary decomposition: the agent implementing a feature should also write its tests.`,
|
|
223
|
+
`- Consider coordination cost vs. parallel benefit. Decomposition multiplies token usage by 3-10x.`,
|
|
224
|
+
`- Keep the number of direct subtasks reasonable (aim for 3-7 per parent).`,
|
|
225
|
+
`- Each subtask description must be self-contained — the child agent has no context beyond what you provide in the description.`,
|
|
226
|
+
`- Set dependencies between subtasks when ordering matters. Independent subtasks can run in parallel.`,
|
|
227
|
+
`- Grant decomposition rights (\`canDecompose: true\`) only to subtasks that genuinely need to coordinate further work.`,
|
|
228
|
+
].join("\n");
|
|
229
|
+
}
|
|
230
|
+
/** Orchestrator-specific MCP tool documentation. */
|
|
231
|
+
buildOrchestratorTools() {
|
|
232
|
+
return [
|
|
233
|
+
`## Orchestrator Tools`,
|
|
234
|
+
``,
|
|
235
|
+
`Use these tools on your \`grackle\` MCP server to coordinate work:`,
|
|
236
|
+
`- \`task_create\` — Create a subtask with title, description, dependencies, persona, and decomposition rights.`,
|
|
237
|
+
`- \`task_list\` — List all tasks in the workspace with their current statuses.`,
|
|
238
|
+
`- \`task_show\` — Show details of a specific task including its sessions and output.`,
|
|
239
|
+
`- \`task_start\` — Start a task (begins agent execution on the assigned environment).`,
|
|
240
|
+
`- \`task_complete\` — Signal that your task is complete.`,
|
|
241
|
+
`- \`finding_post\` — Share a discovery (architecture decisions, patterns, bugs) with other agents.`,
|
|
242
|
+
`- \`finding_list\` — List recent findings from all agents in this workspace.`,
|
|
243
|
+
].join("\n");
|
|
244
|
+
}
|
|
245
|
+
/** Orchestrator-specific completion contract. */
|
|
246
|
+
buildOrchestratorCompletionContract() {
|
|
247
|
+
return [
|
|
248
|
+
`## Completion`,
|
|
249
|
+
`When all subtasks are complete and you have verified the results, use \`task_complete\` to signal your own completion. If any subtasks failed, decide whether to retry, reassign, or handle the failure before completing.`,
|
|
250
|
+
].join("\n");
|
|
251
|
+
}
|
|
252
|
+
// ─── Leaf Sections (unchanged) ───────────────────────────
|
|
34
253
|
/** Task title, description, and notes. */
|
|
35
254
|
buildTaskContext() {
|
|
36
255
|
const { title, description, notes } = this.options.task;
|
|
@@ -73,7 +292,7 @@ export class SystemPromptBuilder {
|
|
|
73
292
|
`3. If the child failed or was interrupted, decide whether to retry, reassign, or handle the failure yourself.`,
|
|
74
293
|
].join("\n");
|
|
75
294
|
}
|
|
76
|
-
/** Guidance on using findings. */
|
|
295
|
+
/** Guidance on using findings (leaf agents). */
|
|
77
296
|
buildFindingsSection() {
|
|
78
297
|
return [
|
|
79
298
|
`## Findings`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt-builder.js","sourceRoot":"","sources":["../src/system-prompt-builder.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"system-prompt-builder.js","sourceRoot":"","sources":["../src/system-prompt-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/ws-bridge.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import { WebSocketServer } from "ws";
|
|
1
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
2
2
|
import type { Server as HttpServer } from "node:http";
|
|
3
|
+
import * as taskStore from "./task-store.js";
|
|
3
4
|
/** Create a WebSocket server on top of an HTTP server that bridges JSON messages to gRPC operations. */
|
|
4
5
|
export declare function createWsBridge(httpServer: HttpServer, verifyApiKey: (token: string) => boolean, validateCookie?: (cookieHeader: string) => boolean): WebSocketServer;
|
|
6
|
+
/** Start a new agent session for a task. Returns an error message string on failure, undefined on success. */
|
|
7
|
+
export declare function startTaskSession(ws: WebSocket | undefined, task: taskStore.TaskRow, options?: {
|
|
8
|
+
personaId?: string;
|
|
9
|
+
environmentId?: string;
|
|
10
|
+
notes?: string;
|
|
11
|
+
}): Promise<string | undefined>;
|
|
5
12
|
//# sourceMappingURL=ws-bridge.d.ts.map
|
package/dist/ws-bridge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-bridge.d.ts","sourceRoot":"","sources":["../src/ws-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"ws-bridge.d.ts","sourceRoot":"","sources":["../src/ws-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAetD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAmD7C,wGAAwG;AACxG,wBAAgB,cAAc,CAC5B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EACxC,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,GACjD,eAAe,CA6CjB;AA0HD,8GAA8G;AAC9G,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,SAAS,GAAG,SAAS,EACzB,IAAI,EAAE,SAAS,CAAC,OAAO,EACvB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA6I7B"}
|
package/dist/ws-bridge.js
CHANGED
|
@@ -16,13 +16,14 @@ import { v4 as uuid } from "uuid";
|
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
import { LOGS_DIR, SESSION_STATUS, TERMINAL_SESSION_STATUSES, TASK_STATUS, DEFAULT_MCP_PORT, ROOT_TASK_ID, eventTypeToString, } from "@grackle-ai/common";
|
|
18
18
|
import { resolvePersona } from "./resolve-persona.js";
|
|
19
|
+
import { fetchOrchestratorContext } from "./orchestrator-context.js";
|
|
19
20
|
import * as settingsStore from "./settings-store.js";
|
|
20
21
|
import { isAllowedSettingKey } from "./settings-store.js";
|
|
21
22
|
import { grackleHome } from "./paths.js";
|
|
22
23
|
import * as logWriter from "./log-writer.js";
|
|
23
24
|
import { safeParseJsonArray } from "./json-helpers.js";
|
|
24
25
|
import { logger } from "./logger.js";
|
|
25
|
-
import { SystemPromptBuilder } from "./system-prompt-builder.js";
|
|
26
|
+
import { SystemPromptBuilder, buildTaskPrompt } from "./system-prompt-builder.js";
|
|
26
27
|
import { slugify } from "./utils/slugify.js";
|
|
27
28
|
import { processEventStream } from "./event-processor.js";
|
|
28
29
|
import * as processorRegistry from "./processor-registry.js";
|
|
@@ -119,6 +120,7 @@ async function autoProvisionEnvironment(ws, environmentId, env, logContext) {
|
|
|
119
120
|
emit("environment.changed", {});
|
|
120
121
|
try {
|
|
121
122
|
const config = safeParseAdapterConfig(env.adapterConfig, environmentId);
|
|
123
|
+
config.defaultRuntime = env.defaultRuntime;
|
|
122
124
|
const powerlineToken = env.powerlineToken || "";
|
|
123
125
|
for await (const provEvent of reconnectOrProvision(environmentId, adapter, config, powerlineToken, !!env.bootstrapped)) {
|
|
124
126
|
logger.info({ environmentId, stage: provEvent.stage, ...logContext }, "Auto-provision progress");
|
|
@@ -165,15 +167,8 @@ async function autoProvisionEnvironment(ws, environmentId, env, logContext) {
|
|
|
165
167
|
return undefined;
|
|
166
168
|
}
|
|
167
169
|
}
|
|
168
|
-
/**
|
|
169
|
-
|
|
170
|
-
* auto-provisioning, session creation, spawning, and completion wiring.
|
|
171
|
-
*
|
|
172
|
-
* Returns undefined on success (or if the failure was already reported
|
|
173
|
-
* to the client via WS, e.g. provisioning errors), or an error message
|
|
174
|
-
* string for failures that need the caller to surface to the client.
|
|
175
|
-
*/
|
|
176
|
-
async function startTaskSession(ws, task, options) {
|
|
170
|
+
/** Start a new agent session for a task. Returns an error message string on failure, undefined on success. */
|
|
171
|
+
export async function startTaskSession(ws, task, options) {
|
|
177
172
|
const workspace = task.workspaceId ? workspaceStore.getWorkspace(task.workspaceId) : undefined;
|
|
178
173
|
if (task.workspaceId && !workspace) {
|
|
179
174
|
logger.warn({ taskId: task.id }, "startTaskSession failed: workspace not found");
|
|
@@ -185,11 +180,17 @@ async function startTaskSession(ws, task, options) {
|
|
|
185
180
|
logger.warn({ taskId: task.id, environmentId }, "startTaskSession failed: environment not found");
|
|
186
181
|
return `Environment not found: ${environmentId}`;
|
|
187
182
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
183
|
+
let conn;
|
|
184
|
+
if (ws) {
|
|
185
|
+
conn = await autoProvisionEnvironment(ws, environmentId, env, {
|
|
186
|
+
taskId: task.id,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
conn = adapterManager.getConnection(environmentId) ?? undefined;
|
|
191
|
+
}
|
|
191
192
|
if (!conn) {
|
|
192
|
-
return undefined
|
|
193
|
+
return ws ? undefined : `Environment not connected: ${environmentId}`;
|
|
193
194
|
}
|
|
194
195
|
// Resolve persona via cascade (request → task → workspace → app default)
|
|
195
196
|
let resolved;
|
|
@@ -205,16 +206,19 @@ async function startTaskSession(ws, task, options) {
|
|
|
205
206
|
const freshTask = taskStore.getTask(task.id) || task;
|
|
206
207
|
// For the root/System task, use the user's chat message (passed as notes)
|
|
207
208
|
// as the initial prompt instead of the task title "System".
|
|
208
|
-
// For regular tasks, the
|
|
209
|
-
const
|
|
209
|
+
// For regular tasks, build the prompt from title + description.
|
|
210
|
+
const taskPrompt = freshTask.id === ROOT_TASK_ID
|
|
210
211
|
? (options?.notes || "")
|
|
211
|
-
: freshTask.title;
|
|
212
|
+
: buildTaskPrompt(freshTask.title, freshTask.description, options?.notes);
|
|
213
|
+
const orchestratorCtx = freshTask.canDecompose && freshTask.depth <= 1
|
|
214
|
+
? fetchOrchestratorContext(freshTask.workspaceId || "") : undefined;
|
|
212
215
|
const systemContext = new SystemPromptBuilder({
|
|
213
216
|
task: { title: freshTask.title, description: freshTask.description, notes: options?.notes || "" },
|
|
214
|
-
canDecompose: freshTask.canDecompose,
|
|
215
|
-
|
|
217
|
+
taskId: freshTask.id, canDecompose: freshTask.canDecompose, personaPrompt: systemPrompt,
|
|
218
|
+
taskDepth: freshTask.depth, ...orchestratorCtx,
|
|
219
|
+
...(orchestratorCtx && { triggerMode: "fresh" }),
|
|
216
220
|
}).build();
|
|
217
|
-
sessionStore.createSession(sessionId, environmentId, runtime,
|
|
221
|
+
sessionStore.createSession(sessionId, environmentId, runtime, freshTask.title, model, logPath, freshTask.id, resolved.personaId);
|
|
218
222
|
emit("task.started", {
|
|
219
223
|
taskId: freshTask.id,
|
|
220
224
|
sessionId,
|
|
@@ -245,7 +249,7 @@ async function startTaskSession(ws, task, options) {
|
|
|
245
249
|
const powerlineReq = create(powerline.SpawnRequestSchema, {
|
|
246
250
|
sessionId,
|
|
247
251
|
runtime,
|
|
248
|
-
prompt:
|
|
252
|
+
prompt: taskPrompt,
|
|
249
253
|
model,
|
|
250
254
|
maxTurns,
|
|
251
255
|
branch: freshTask.branch,
|
|
@@ -266,7 +270,7 @@ async function startTaskSession(ws, task, options) {
|
|
|
266
270
|
workspaceId: freshTask.workspaceId ?? undefined,
|
|
267
271
|
taskId: freshTask.id,
|
|
268
272
|
systemContext,
|
|
269
|
-
prompt:
|
|
273
|
+
prompt: taskPrompt,
|
|
270
274
|
});
|
|
271
275
|
return undefined;
|
|
272
276
|
}
|
|
@@ -1285,6 +1289,7 @@ async function handleMessage(ws, msg, subscriptions) {
|
|
|
1285
1289
|
(async () => {
|
|
1286
1290
|
try {
|
|
1287
1291
|
const config = safeParseAdapterConfig(env.adapterConfig, environmentId);
|
|
1292
|
+
config.defaultRuntime = env.defaultRuntime;
|
|
1288
1293
|
const powerlineToken = env.powerlineToken || "";
|
|
1289
1294
|
for await (const event of reconnectOrProvision(environmentId, adapter, config, powerlineToken, !!env.bootstrapped)) {
|
|
1290
1295
|
logger.info({ environmentId, stage: event.stage, message: event.message }, "Provision progress");
|