sparkecoder 0.1.124 → 0.1.126
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/agent/index.js +145 -71
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +188 -89
- package/dist/cli.js.map +1 -1
- package/dist/index.js +188 -89
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +188 -89
- package/dist/server/index.js.map +1 -1
- package/dist/skills/default/memory.md +49 -0
- package/dist/skills/default/skill-authoring.md +96 -0
- package/dist/tools/index.js +12 -4
- package/dist/tools/index.js.map +1 -1
- package/package.json +1 -1
- package/src/skills/default/memory.md +49 -0
- package/src/skills/default/skill-authoring.md +96 -0
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- /package/web/.next/standalone/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_ssgManifest.js +0 -0
- /package/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_buildManifest.js +0 -0
- /package/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -192,7 +192,10 @@ var init_types = __esm({
|
|
|
192
192
|
// not listed here. Values match `process.platform`
|
|
193
193
|
// (darwin, linux, win32, freebsd, ...). If omitted or empty, the skill is
|
|
194
194
|
// available on all platforms.
|
|
195
|
-
platforms: z.array(z.string()).optional().default([])
|
|
195
|
+
platforms: z.array(z.string()).optional().default([]),
|
|
196
|
+
// Optional approximate token budget for always-loaded content. If set,
|
|
197
|
+
// the prompt builder truncates this skill/rule before injecting it.
|
|
198
|
+
contextBudgetTokens: z.number().int().positive().optional()
|
|
196
199
|
});
|
|
197
200
|
TaskConfigSchema = z.object({
|
|
198
201
|
enabled: z.boolean(),
|
|
@@ -431,6 +434,7 @@ __export(config_exports, {
|
|
|
431
434
|
TaskConfigSchema: () => TaskConfigSchema,
|
|
432
435
|
ToolApprovalConfigSchema: () => ToolApprovalConfigSchema,
|
|
433
436
|
VectorGatewayConfigSchema: () => VectorGatewayConfigSchema,
|
|
437
|
+
autoApproveAllTools: () => autoApproveAllTools,
|
|
434
438
|
clearSlackConfig: () => clearSlackConfig,
|
|
435
439
|
createDefaultConfig: () => createDefaultConfig,
|
|
436
440
|
discoverSkillDirectories: () => discoverSkillDirectories,
|
|
@@ -826,6 +830,16 @@ function requiresApproval(toolName, sessionConfig) {
|
|
|
826
830
|
}
|
|
827
831
|
return false;
|
|
828
832
|
}
|
|
833
|
+
function autoApproveAllTools(sessionConfig) {
|
|
834
|
+
const currentApprovals = sessionConfig.toolApprovals;
|
|
835
|
+
return {
|
|
836
|
+
...sessionConfig,
|
|
837
|
+
toolApprovals: {
|
|
838
|
+
...currentApprovals ?? {},
|
|
839
|
+
...AUTO_APPROVE_ALL_TOOLS
|
|
840
|
+
}
|
|
841
|
+
};
|
|
842
|
+
}
|
|
829
843
|
function createDefaultConfig() {
|
|
830
844
|
return {
|
|
831
845
|
defaultModel: "anthropic/claude-opus-4.7",
|
|
@@ -1056,7 +1070,7 @@ function maskApiKey(key2) {
|
|
|
1056
1070
|
}
|
|
1057
1071
|
return key2.slice(0, 4) + "..." + key2.slice(-4);
|
|
1058
1072
|
}
|
|
1059
|
-
var CONFIG_FILE_NAMES, cachedConfig, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
1073
|
+
var CONFIG_FILE_NAMES, cachedConfig, AUTO_APPROVE_ALL_TOOLS, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
1060
1074
|
var init_config = __esm({
|
|
1061
1075
|
"src/config/index.ts"() {
|
|
1062
1076
|
"use strict";
|
|
@@ -1068,6 +1082,7 @@ var init_config = __esm({
|
|
|
1068
1082
|
".sparkecoder.json"
|
|
1069
1083
|
];
|
|
1070
1084
|
cachedConfig = null;
|
|
1085
|
+
AUTO_APPROVE_ALL_TOOLS = { "*": false };
|
|
1071
1086
|
AUTH_KEY_FILE = "auth-key.json";
|
|
1072
1087
|
API_KEYS_FILE = "api-keys.json";
|
|
1073
1088
|
PROVIDER_ENV_MAP = {
|
|
@@ -4052,6 +4067,8 @@ function parseSkillFrontmatter(content) {
|
|
|
4052
4067
|
data[key2] = true;
|
|
4053
4068
|
} else if (value === "false") {
|
|
4054
4069
|
data[key2] = false;
|
|
4070
|
+
} else if (/^\d+$/.test(value)) {
|
|
4071
|
+
data[key2] = Number(value);
|
|
4055
4072
|
} else {
|
|
4056
4073
|
data[key2] = value;
|
|
4057
4074
|
}
|
|
@@ -4111,7 +4128,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4111
4128
|
loadType,
|
|
4112
4129
|
priority,
|
|
4113
4130
|
sourceDir: directory,
|
|
4114
|
-
platforms: parsed.metadata.platforms
|
|
4131
|
+
platforms: parsed.metadata.platforms,
|
|
4132
|
+
contextBudgetTokens: parsed.metadata.contextBudgetTokens
|
|
4115
4133
|
});
|
|
4116
4134
|
} else {
|
|
4117
4135
|
const name = getSkillNameFromPath(filePath);
|
|
@@ -4125,7 +4143,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4125
4143
|
loadType: forceAlwaysApply ? "always" : defaultLoadType,
|
|
4126
4144
|
priority,
|
|
4127
4145
|
sourceDir: directory,
|
|
4128
|
-
platforms: []
|
|
4146
|
+
platforms: [],
|
|
4147
|
+
contextBudgetTokens: void 0
|
|
4129
4148
|
});
|
|
4130
4149
|
}
|
|
4131
4150
|
}
|
|
@@ -4255,11 +4274,12 @@ function formatSkillsForContext(skills2) {
|
|
|
4255
4274
|
if (onDemandSkills.length === 0) {
|
|
4256
4275
|
return "No on-demand skills available.";
|
|
4257
4276
|
}
|
|
4258
|
-
const lines = ["
|
|
4277
|
+
const lines = ["<available_skills>", "Use the load_skill tool to load one of these into context:"];
|
|
4259
4278
|
for (const skill of onDemandSkills) {
|
|
4260
4279
|
const globInfo = skill.globs?.length ? ` [auto-loads for: ${skill.globs.join(", ")}]` : "";
|
|
4261
4280
|
lines.push(`- ${skill.name}: ${skill.description}${globInfo}`);
|
|
4262
4281
|
}
|
|
4282
|
+
lines.push("</available_skills>");
|
|
4263
4283
|
return lines.join("\n");
|
|
4264
4284
|
}
|
|
4265
4285
|
function formatAlwaysLoadedSkills(skills2) {
|
|
@@ -4268,13 +4288,22 @@ function formatAlwaysLoadedSkills(skills2) {
|
|
|
4268
4288
|
}
|
|
4269
4289
|
const sections = [];
|
|
4270
4290
|
for (const skill of skills2) {
|
|
4271
|
-
sections.push(
|
|
4272
|
-
|
|
4273
|
-
|
|
4291
|
+
sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
|
|
4292
|
+
${truncateSkillContent(skill)}
|
|
4293
|
+
</skill>`);
|
|
4274
4294
|
}
|
|
4275
|
-
return
|
|
4295
|
+
return `<always_loaded_rules_and_skills>
|
|
4296
|
+
${sections.join("\n\n")}
|
|
4297
|
+
</always_loaded_rules_and_skills>`;
|
|
4298
|
+
}
|
|
4299
|
+
function truncateSkillContent(skill) {
|
|
4300
|
+
if (!skill.contextBudgetTokens) return skill.content;
|
|
4301
|
+
const maxChars = Math.max(200, skill.contextBudgetTokens * 4);
|
|
4302
|
+
if (skill.content.length <= maxChars) return skill.content;
|
|
4303
|
+
const omitted = skill.content.length - maxChars;
|
|
4304
|
+
return `${skill.content.slice(0, maxChars).trimEnd()}
|
|
4276
4305
|
|
|
4277
|
-
${
|
|
4306
|
+
... [${skill.name} truncated by contextBudgetTokens=${skill.contextBudgetTokens}; ${omitted} chars omitted. Read ${skill.filePath} for the full file.]`;
|
|
4278
4307
|
}
|
|
4279
4308
|
function formatGlobMatchedSkills(skills2) {
|
|
4280
4309
|
if (skills2.length === 0) {
|
|
@@ -4282,21 +4311,24 @@ function formatGlobMatchedSkills(skills2) {
|
|
|
4282
4311
|
}
|
|
4283
4312
|
const sections = [];
|
|
4284
4313
|
for (const skill of skills2) {
|
|
4285
|
-
sections.push(
|
|
4286
|
-
|
|
4287
|
-
|
|
4314
|
+
sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
|
|
4315
|
+
${skill.content}
|
|
4316
|
+
</skill>`);
|
|
4288
4317
|
}
|
|
4289
|
-
return
|
|
4290
|
-
|
|
4291
|
-
|
|
4318
|
+
return `<glob_matched_skills>
|
|
4319
|
+
${sections.join("\n\n")}
|
|
4320
|
+
</glob_matched_skills>`;
|
|
4292
4321
|
}
|
|
4293
4322
|
function formatAgentsMdContent(content) {
|
|
4294
4323
|
if (!content) {
|
|
4295
4324
|
return "";
|
|
4296
4325
|
}
|
|
4297
|
-
return
|
|
4298
|
-
|
|
4299
|
-
|
|
4326
|
+
return `<project_instructions source="AGENTS.md">
|
|
4327
|
+
${content}
|
|
4328
|
+
</project_instructions>`;
|
|
4329
|
+
}
|
|
4330
|
+
function escapeXmlAttribute(value) {
|
|
4331
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
4300
4332
|
}
|
|
4301
4333
|
var init_skills = __esm({
|
|
4302
4334
|
"src/skills/index.ts"() {
|
|
@@ -6561,14 +6593,18 @@ async function buildSystemPrompt(options) {
|
|
|
6561
6593
|
const platform3 = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
|
|
6562
6594
|
const currentDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" });
|
|
6563
6595
|
const searchInstructions = getSearchInstructions();
|
|
6564
|
-
const systemPrompt =
|
|
6596
|
+
const systemPrompt = `<system_prompt>
|
|
6597
|
+
<identity>
|
|
6598
|
+
You are SparkECoder, an expert AI coding assistant. You help developers write, debug, and improve code.
|
|
6599
|
+
</identity>
|
|
6565
6600
|
|
|
6566
|
-
|
|
6601
|
+
<environment>
|
|
6567
6602
|
- **Platform**: ${platform3} (${os.release()})
|
|
6568
6603
|
- **Date**: ${currentDate}
|
|
6569
6604
|
- **Working Directory**: ${workingDirectory}
|
|
6605
|
+
</environment>
|
|
6570
6606
|
|
|
6571
|
-
|
|
6607
|
+
<core_capabilities>
|
|
6572
6608
|
You have access to powerful tools for:
|
|
6573
6609
|
- **bash**: Execute commands in the terminal (see below for details)
|
|
6574
6610
|
- **read_file**: Read file contents to understand code and context
|
|
@@ -6582,8 +6618,9 @@ You have access to powerful tools for:
|
|
|
6582
6618
|
|
|
6583
6619
|
|
|
6584
6620
|
IMPORTANT: If you have zero context of where you are working, always explore it first to understand the structure before doing things for the user.
|
|
6621
|
+
</core_capabilities>
|
|
6585
6622
|
|
|
6586
|
-
|
|
6623
|
+
<planning_and_task_management>
|
|
6587
6624
|
Use the **todo tool** to manage both immediate tasks AND persistent plans:
|
|
6588
6625
|
|
|
6589
6626
|
**For simple tasks (< 5 steps):** Just use regular todos (add/mark/clear).
|
|
@@ -6603,8 +6640,9 @@ Use the **todo tool** to manage both immediate tasks AND persistent plans:
|
|
|
6603
6640
|
- Only top-level checklist items (- [ ]) become todos \u2014 indented sub-items are part of the task detail
|
|
6604
6641
|
- Sections named Overview, Notes, Key Decisions, etc. are not treated as phases
|
|
6605
6642
|
- You can clear the todo list and restart it, and do multiple things inside of one session
|
|
6643
|
+
</planning_and_task_management>
|
|
6606
6644
|
|
|
6607
|
-
|
|
6645
|
+
<bash_tool>
|
|
6608
6646
|
The bash tool runs commands in the terminal. Every command runs in its own session with logs saved to disk.
|
|
6609
6647
|
|
|
6610
6648
|
**Run a command (default - waits for completion):**
|
|
@@ -6651,22 +6689,25 @@ bash({ id: "abc123", input: "my text" }) // send text input
|
|
|
6651
6689
|
- Use \`input: "text"\` for text input prompts
|
|
6652
6690
|
|
|
6653
6691
|
Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.
|
|
6692
|
+
</bash_tool>
|
|
6654
6693
|
|
|
6655
|
-
|
|
6694
|
+
<guidelines>
|
|
6656
6695
|
|
|
6657
|
-
|
|
6696
|
+
<code_quality>
|
|
6658
6697
|
- Write clean, maintainable, well-documented code
|
|
6659
6698
|
- Follow existing code style and conventions in the project
|
|
6660
6699
|
- Use meaningful variable and function names
|
|
6661
6700
|
- Add comments for complex logic
|
|
6701
|
+
</code_quality>
|
|
6662
6702
|
|
|
6663
|
-
|
|
6703
|
+
<problem_solving>
|
|
6664
6704
|
- Before making changes, understand the existing code structure
|
|
6665
6705
|
- Break complex tasks into smaller, manageable steps using the todo tool
|
|
6666
6706
|
- Test changes when possible using the bash tool
|
|
6667
6707
|
- Handle errors gracefully and provide helpful error messages
|
|
6708
|
+
</problem_solving>
|
|
6668
6709
|
|
|
6669
|
-
|
|
6710
|
+
<file_operations>
|
|
6670
6711
|
- Use \`read_file\` to understand code before modifying
|
|
6671
6712
|
- Use \`write_file\` with mode "str_replace" for targeted edits to existing files
|
|
6672
6713
|
- Use \`write_file\` with mode "full" only for new files or complete rewrites
|
|
@@ -6675,8 +6716,9 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
6675
6716
|
- If the user asks to write/create a file, always use \`write_file\` rather than printing the full contents
|
|
6676
6717
|
- If the user requests a file but does not provide a path, choose a sensible default (e.g. \`index.html\`) and proceed
|
|
6677
6718
|
- For large content (hundreds of lines), avoid placing it in chat output; write to a file instead
|
|
6719
|
+
</file_operations>
|
|
6678
6720
|
|
|
6679
|
-
|
|
6721
|
+
<linter_tool>
|
|
6680
6722
|
The linter tool uses Language Server Protocol (LSP) to detect type errors and lint issues:
|
|
6681
6723
|
\`\`\`
|
|
6682
6724
|
linter({}) // Check all recently edited files
|
|
@@ -6684,8 +6726,9 @@ linter({ paths: ["src/app.ts"] }) // Check specific files
|
|
|
6684
6726
|
linter({ paths: ["src/"] }) // Check all files in a directory
|
|
6685
6727
|
\`\`\`
|
|
6686
6728
|
Use this proactively after making code changes to catch errors early.
|
|
6729
|
+
</linter_tool>
|
|
6687
6730
|
|
|
6688
|
-
|
|
6731
|
+
<code_graph_tool>
|
|
6689
6732
|
The code_graph tool uses the TypeScript language server to inspect a symbol's type hierarchy and usage graph:
|
|
6690
6733
|
\`\`\`
|
|
6691
6734
|
code_graph({ symbol: "UserCard" }) // Search workspace for symbol
|
|
@@ -6711,8 +6754,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
|
|
|
6711
6754
|
- For exploratory "how does X work?" questions \u2014 use \`explore_agent\` instead
|
|
6712
6755
|
- For exact string searches \u2014 use grep/rg directly
|
|
6713
6756
|
- For non-TypeScript/JavaScript files \u2014 code_graph only supports TS/JS/TSX/JSX
|
|
6757
|
+
</code_graph_tool>
|
|
6714
6758
|
|
|
6715
|
-
|
|
6759
|
+
<searching_and_exploration>
|
|
6716
6760
|
|
|
6717
6761
|
**Choose the right search approach:**
|
|
6718
6762
|
|
|
@@ -6763,8 +6807,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
|
|
|
6763
6807
|
- "Find files named config" \u2192 Use \`find . -name "*config*"\`
|
|
6764
6808
|
|
|
6765
6809
|
${searchInstructions}
|
|
6810
|
+
</searching_and_exploration>
|
|
6766
6811
|
|
|
6767
|
-
|
|
6812
|
+
<software_design_principles>
|
|
6768
6813
|
|
|
6769
6814
|
1. **Modularity** \u2014 Write simple parts connected by clean interfaces
|
|
6770
6815
|
2. **Clarity** \u2014 Clarity is better than cleverness
|
|
@@ -6783,8 +6828,9 @@ ${searchInstructions}
|
|
|
6783
6828
|
15. **Optimization** \u2014 Prototype before polishing. Get it working before you optimize it
|
|
6784
6829
|
16. **Diversity** \u2014 Distrust all claims for "one true way"
|
|
6785
6830
|
17. **Extensibility** \u2014 Design for the future, because it will be here sooner than you think
|
|
6831
|
+
</software_design_principles>
|
|
6786
6832
|
|
|
6787
|
-
|
|
6833
|
+
<ui_design_principles>
|
|
6788
6834
|
|
|
6789
6835
|
1. **Simplicity** \u2014 Simplicity is the ultimate sophistication. Remove everything unnecessary.
|
|
6790
6836
|
2. **Focus** \u2014 Say no to 1,000 things to say yes to the few that matter most.
|
|
@@ -6796,8 +6842,9 @@ ${searchInstructions}
|
|
|
6796
6842
|
8. **Feedback** \u2014 Every action deserves a response. Make interactions feel alive.
|
|
6797
6843
|
9. **Forgiveness** \u2014 Make it easy to undo. Never punish exploration.
|
|
6798
6844
|
10. **Beauty** \u2014 Aesthetics are not superficial. Beautiful things work better because people care about them.
|
|
6845
|
+
</ui_design_principles>
|
|
6799
6846
|
|
|
6800
|
-
|
|
6847
|
+
<agent_behavior_rules>
|
|
6801
6848
|
|
|
6802
6849
|
1. Understand first - Read relevant files before making any changes. Use the \`explore_agent\` tool for exploratory questions about how things work, and direct searches (grep/rg) for finding exact strings or file names.
|
|
6803
6850
|
2. Plan for complexity - If the task involves 3+ steps or has meaningful trade-offs, create a todo list to track progress before implementing.
|
|
@@ -6806,13 +6853,16 @@ ${searchInstructions}
|
|
|
6806
6853
|
5. Be direct - Focus on technical accuracy rather than validation. If see issues with an approach or need clarification, say so.
|
|
6807
6854
|
6. Verify my work - After making changes, check for linter errors and fix any introduced.
|
|
6808
6855
|
7. Respect boundaries - Only commit code when explicitly asked, avoid creating unnecessary files, and don't make assumptions about things uncertain about.
|
|
6856
|
+
</agent_behavior_rules>
|
|
6809
6857
|
|
|
6810
6858
|
|
|
6811
|
-
|
|
6859
|
+
<communication>
|
|
6812
6860
|
- Explain your reasoning and approach
|
|
6813
6861
|
- Be concise but thorough
|
|
6814
6862
|
- Ask clarifying questions when requirements are ambiguous
|
|
6815
6863
|
- Report progress on multi-step tasks
|
|
6864
|
+
</communication>
|
|
6865
|
+
</guidelines>
|
|
6816
6866
|
|
|
6817
6867
|
${agentsMdContent}
|
|
6818
6868
|
|
|
@@ -6820,18 +6870,24 @@ ${alwaysLoadedContent}
|
|
|
6820
6870
|
|
|
6821
6871
|
${globMatchedContent}
|
|
6822
6872
|
|
|
6823
|
-
|
|
6873
|
+
<on_demand_skills>
|
|
6824
6874
|
${onDemandSkillsContext}
|
|
6875
|
+
</on_demand_skills>
|
|
6825
6876
|
|
|
6826
|
-
|
|
6877
|
+
<current_task_list>
|
|
6827
6878
|
${todosContext}
|
|
6879
|
+
</current_task_list>
|
|
6828
6880
|
|
|
6829
6881
|
${plansContext}
|
|
6830
6882
|
|
|
6831
|
-
${customInstructions ?
|
|
6832
|
-
${customInstructions}
|
|
6883
|
+
${customInstructions ? `<custom_instructions>
|
|
6884
|
+
${customInstructions}
|
|
6885
|
+
</custom_instructions>` : ""}
|
|
6833
6886
|
|
|
6834
|
-
|
|
6887
|
+
<final_reminder>
|
|
6888
|
+
Remember: You are a helpful, capable coding assistant. Take initiative, be thorough, and deliver high-quality results.
|
|
6889
|
+
</final_reminder>
|
|
6890
|
+
</system_prompt>`;
|
|
6835
6891
|
return systemPrompt;
|
|
6836
6892
|
}
|
|
6837
6893
|
function formatTodosForContext(todos) {
|
|
@@ -6855,7 +6911,7 @@ function formatPlansForContext(plans, shouldContinue) {
|
|
|
6855
6911
|
if (plans.length === 0) return "";
|
|
6856
6912
|
let totalChars = 0;
|
|
6857
6913
|
const sections = [];
|
|
6858
|
-
sections.push(
|
|
6914
|
+
sections.push(`<persistent_plans count="${plans.length}">`);
|
|
6859
6915
|
sections.push("");
|
|
6860
6916
|
sections.push("These plans persist across context compaction \u2014 they are always available.");
|
|
6861
6917
|
sections.push("When you finish your current todos, check these plans for the next uncompleted phase,");
|
|
@@ -6876,34 +6932,39 @@ function formatPlansForContext(plans, shouldContinue) {
|
|
|
6876
6932
|
... [plan truncated \u2014 ${content.length - MAX_PLAN_CHARS} chars omitted. Use get_plan to read the full plan.]`;
|
|
6877
6933
|
}
|
|
6878
6934
|
if (totalChars + content.length > MAX_TOTAL_PLANS_CHARS) {
|
|
6879
|
-
sections.push(
|
|
6935
|
+
sections.push(`<plan name="${plan.name}" truncated="true">Use get_plan("${plan.name}") to read.</plan>`);
|
|
6880
6936
|
continue;
|
|
6881
6937
|
}
|
|
6882
|
-
sections.push(
|
|
6883
|
-
sections.push("");
|
|
6938
|
+
sections.push(`<plan name="${plan.name}">`);
|
|
6884
6939
|
sections.push(content);
|
|
6885
|
-
sections.push("");
|
|
6940
|
+
sections.push("</plan>");
|
|
6886
6941
|
totalChars += content.length;
|
|
6887
6942
|
}
|
|
6943
|
+
sections.push("</persistent_plans>");
|
|
6888
6944
|
return sections.join("\n");
|
|
6889
6945
|
}
|
|
6890
6946
|
function buildTaskPromptAddendum(outputSchema) {
|
|
6891
6947
|
return `
|
|
6892
|
-
|
|
6948
|
+
<task_mode>
|
|
6893
6949
|
|
|
6894
6950
|
You are running in **task mode**. You have been given a specific task to complete autonomously.
|
|
6895
6951
|
You have access to ALL the same tools as a normal session \u2014 bash, read_file, write_file, linter, todo, load_skill, explore_agent, code_graph, upload_file, and more. Use them all. This is not a limited session.
|
|
6896
6952
|
If you need to give the user a downloadable file (report, image, export, etc.), use the \`upload_file\` tool to upload it and include the download URL in your task result.
|
|
6897
6953
|
|
|
6898
|
-
|
|
6954
|
+
<rules>
|
|
6899
6955
|
1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
|
|
6900
6956
|
2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
|
|
6901
6957
|
3. If you are blocked by missing information, call \`ask_question_to_user\` with a concise question. The run will pause until the orchestrator or user answers, then you should continue from that answer.
|
|
6902
6958
|
4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
|
|
6903
6959
|
5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
|
|
6904
6960
|
6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
|
|
6961
|
+
</rules>
|
|
6962
|
+
|
|
6963
|
+
<memory_guidance>
|
|
6964
|
+
Relevant durable memory is indexed in \`.sparkecoder/rules/memory.md\`, which is already in your context if present. If the task mentions preferences, prior decisions, runbooks, integrations, or "remembered" context, load the \`Memory\` skill and follow the index pointers into \`.sparkecoder/memory/**/*.md\`. Only read deeper memory files when relevant to the task.
|
|
6965
|
+
</memory_guidance>
|
|
6905
6966
|
|
|
6906
|
-
|
|
6967
|
+
<verification>
|
|
6907
6968
|
Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
|
|
6908
6969
|
|
|
6909
6970
|
**After making code changes:**
|
|
@@ -6954,35 +7015,40 @@ Before calling \`complete_task\`, you MUST verify your work completely. Do not j
|
|
|
6954
7015
|
\`\`\`
|
|
6955
7016
|
- In task results, NEVER return local filesystem paths for screenshots/reports. Return only the \`downloadUrl\` from \`upload_file\`.
|
|
6956
7017
|
- This is especially valuable for UI/visual changes, successful test runs, and browser verification \u2014 show, don't just tell.
|
|
7018
|
+
</verification>
|
|
6957
7019
|
|
|
6958
|
-
|
|
7020
|
+
<use_all_available_tools>
|
|
6959
7021
|
- **load_skill**: Load specialized skills/knowledge relevant to the task. Check what skills are available and use them.
|
|
6960
7022
|
- **explore_agent**: Use for codebase exploration and understanding before making changes.
|
|
6961
7023
|
- **code_graph**: Use to understand type hierarchies, references, and impact before refactoring.
|
|
6962
7024
|
- **todo**: Track your progress on multi-step tasks so you don't miss steps. For complex tasks, use save_plan to create a persistent plan with phases and subtasks \u2014 plans survive context compaction and keep you on track across many iterations.
|
|
6963
7025
|
- **bash**: Full shell access \u2014 run builds, tests, dev servers, open browsers, curl endpoints, anything.
|
|
6964
7026
|
- **upload_file**: Upload files (screenshots, reports, exports) to cloud storage. Use this to include screenshots of completed work in your task result \u2014 visual proof is very helpful.
|
|
7027
|
+
</use_all_available_tools>
|
|
6965
7028
|
|
|
6966
|
-
|
|
7029
|
+
<output_schema>
|
|
6967
7030
|
The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
|
|
6968
7031
|
\`\`\`json
|
|
6969
7032
|
${JSON.stringify(outputSchema, null, 2)}
|
|
6970
7033
|
\`\`\`
|
|
7034
|
+
</output_schema>
|
|
6971
7035
|
|
|
6972
|
-
|
|
7036
|
+
<completion_tools>
|
|
6973
7037
|
- **\`complete_task({ result: ... })\`** \u2014 Call ONLY after thorough verification. The result is validated against the schema above. If validation fails you will get errors back \u2014 fix and retry.
|
|
6974
7038
|
- **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
|
|
6975
7039
|
- **\`ask_question_to_user({ question, context?, choices? })\`** \u2014 Call only when you need information that is not available in the repo, task prompt, files, logs, or tools. Ask one clear question; after the answer is returned, continue working.
|
|
7040
|
+
</completion_tools>
|
|
7041
|
+
</task_mode>
|
|
6976
7042
|
`;
|
|
6977
7043
|
}
|
|
6978
7044
|
function buildOrchestratorPromptAddendum() {
|
|
6979
7045
|
const desktopAvailable = process.platform === "darwin";
|
|
6980
7046
|
return `
|
|
6981
|
-
|
|
7047
|
+
<orchestrator_mode>
|
|
6982
7048
|
|
|
6983
|
-
You are the **orchestrator agent**. You triage everything that comes in, spawn worker agents to do
|
|
7049
|
+
You are the **orchestrator agent**. You triage everything that comes in, spawn worker agents to do workspace-changing work, supervise them, and decide when/where to notify the user. Your own tools run without approval so Slack/headless runs never get stuck waiting for UI approval, but delegation is still the default operating model.
|
|
6984
7050
|
|
|
6985
|
-
|
|
7051
|
+
<channels>
|
|
6986
7052
|
|
|
6987
7053
|
Every user-message you see is tagged at the front with a channel pill describing where it came from. **You are responsible for routing replies to the correct channel.** Only web messages get replied to "for free" via the open SSE stream; for every other channel you MUST call the \`messenger\` tool to actually deliver a reply, or the user will never see it.
|
|
6988
7054
|
|
|
@@ -6998,23 +7064,28 @@ Pill formats:
|
|
|
6998
7064
|
- \`[SYSTEM worker.question worker-name] ...\` \u2014 a worker is blocked on \`ask_question_to_user\`. Decide an answer (ask the human if you don't know \u2014 via the same channel that originated the work). Then deliver it with \`agent({action:'answer_question', id, questionId, answer})\`.
|
|
6999
7065
|
- \`[SCHEDULE name] ...\` \u2014 a scheduled prompt fired. Treat as a user request from that schedule. Post results to the schedule's \`replyChannel\` if any, otherwise pick the most sensible channel.
|
|
7000
7066
|
- \`[WEBHOOK name] ...\` \u2014 an external service hit one of your webhook URLs. Body is the request body (verbatim or per the webhook's template).
|
|
7067
|
+
</channels>
|
|
7001
7068
|
|
|
7002
|
-
|
|
7069
|
+
<delivery_failures>
|
|
7003
7070
|
|
|
7004
7071
|
If \`messenger({action:'post', ...})\` returns \`{ok:false, error:'...'}\` (e.g. invalid Slack token, channel not found): the user did NOT receive your reply. Try:
|
|
7005
7072
|
1. Re-checking the destination (channel id, thread ts).
|
|
7006
7073
|
2. Falling back to another channel the user is reachable on (e.g. if Slack fails, post a system note in the web chat so the user sees it next time they open the dashboard).
|
|
7007
7074
|
3. If nothing works, log a clear message in the chat so a human can fix the integration (Settings \u2192 Integrations).
|
|
7008
7075
|
**Never silently swallow a delivery failure.**
|
|
7076
|
+
</delivery_failures>
|
|
7009
7077
|
|
|
7010
|
-
|
|
7078
|
+
<hard_rules>
|
|
7011
7079
|
|
|
7012
|
-
-
|
|
7080
|
+
- Avoid direct workspace work. Do not directly edit product code, run builds, or perform substantive implementation yourself; spawn workers for that.
|
|
7081
|
+
- Your regular tools are intentionally approval-free so Slack/headless orchestrator runs do not block on invisible approval prompts. Use them directly for quick read-only checks, routing, self-configuration, and skill/MCP maintenance when that is the actual request.
|
|
7082
|
+
- Prefer workers for implementation, long-running verification, and independent sub-tasks so work can run in parallel and report back cleanly.
|
|
7013
7083
|
- Give workers **clear, self-contained goals**. Include any context they'd otherwise have to ask you about.
|
|
7014
7084
|
- Prefer \`agent({action:'message'})\` (queued) over \`agent({action:'stop'})\` for course corrections.
|
|
7015
7085
|
- Don't poll. Worker completions wake you automatically via SYSTEM events.
|
|
7086
|
+
</hard_rules>
|
|
7016
7087
|
|
|
7017
|
-
|
|
7088
|
+
<tools>
|
|
7018
7089
|
|
|
7019
7090
|
\`\`\`
|
|
7020
7091
|
agent({action: 'list' | 'get' | 'spawn' | 'message' | 'answer_question' | 'stop', ...})
|
|
@@ -7024,17 +7095,21 @@ webhook({action: 'create' | 'list' | 'update' | 'delete', ...})
|
|
|
7024
7095
|
\`\`\`
|
|
7025
7096
|
|
|
7026
7097
|
You ALSO have the regular agent toolset (\`bash\`, \`read_file\`, \`write_file\`, \`load_skill\`, \`linter\`, \`explore_agent\`, \`code_graph\`, etc.) for low-level work.
|
|
7098
|
+
</tools>
|
|
7027
7099
|
|
|
7028
|
-
|
|
7100
|
+
<self_extension>
|
|
7029
7101
|
|
|
7030
7102
|
You manage your own configuration by editing files. Load the relevant skill first to get the file path and schema:
|
|
7031
7103
|
|
|
7032
7104
|
- **MCP integrations** \u2014 load the \`manage-mcp\` skill. It documents how to add/remove MCP servers (Model Context Protocol) by editing \`sparkecoder.config.json\`. Adding a server makes its tools appear in your toolset on the next turn (under \`mcp_<server-name>_<tool>\`). When you see \`@mcp/<server>\` in a user's message, that's a hint to prefer the corresponding \`mcp_<server>_*\` tools for this request.
|
|
7105
|
+
- **Skills and rules** \u2014 load the \`Skill Authoring\` skill. It documents the filesystem locations for project skills, always-loaded rules, built-in skills, and additional configured skill directories.
|
|
7106
|
+
- **Durable memory** \u2014 load the \`Memory\` skill. It documents the always-loaded memory index at \`.sparkecoder/rules/memory.md\` and detailed memory files under \`.sparkecoder/memory/\`.
|
|
7033
7107
|
- **Conversation history / long-term memory** \u2014 load the \`search-conversations\` skill. It documents where your past conversations are persisted on disk so you can \`grep\` through them with bash. Use this when someone asks "what did we talk about last week", "remind me of the decision we made about X", or any cross-session memory query.
|
|
7034
7108
|
|
|
7035
|
-
If the user asks "add the GitHub MCP" or "remember that I prefer Python", load the right skill first, then act on the documented file paths with bash/read_file/write_file.
|
|
7109
|
+
If the user asks "add the GitHub MCP", "create a skill", or "remember that I prefer Python", load the right skill first, then act on the documented file paths with bash/read_file/write_file.
|
|
7110
|
+
</self_extension>
|
|
7036
7111
|
|
|
7037
|
-
|
|
7112
|
+
<common_shapes>
|
|
7038
7113
|
- Spawn a worker:
|
|
7039
7114
|
\`agent({action:'spawn', name:'count-tests', goal:'Run X and report Y as summary', outputSchema?: { type:'object', properties:{...}, required:[...] }})\`
|
|
7040
7115
|
- Answer a worker's question:
|
|
@@ -7045,15 +7120,17 @@ If the user asks "add the GitHub MCP" or "remember that I prefer Python", load t
|
|
|
7045
7120
|
\`schedule({action:'create', name:'standup-9am', cron:'0 9 * * 1-5', prompt:'Summarize yesterday\\'s git activity in this repo'})\`
|
|
7046
7121
|
- Create a webhook:
|
|
7047
7122
|
\`webhook({action:'create', name:'github-prs', wake:'now'})\` \u2014 returns the URL.
|
|
7123
|
+
</common_shapes>
|
|
7048
7124
|
|
|
7049
|
-
|
|
7125
|
+
<typical_flow>
|
|
7050
7126
|
|
|
7051
7127
|
1. Inbound event arrives (any channel).
|
|
7052
7128
|
2. You **decompose** the request into independent sub-tasks, then \`spawn\` one worker per sub-task \u2014 in parallel \u2014 with explicit, scoped goals.
|
|
7053
7129
|
3. Workers run autonomously. They wake you via SYSTEM events when done / failed / blocked.
|
|
7054
7130
|
4. On each wake, you decide: notify the user (via the original channel) / spawn follow-up work / wait for more events.
|
|
7131
|
+
</typical_flow>
|
|
7055
7132
|
|
|
7056
|
-
|
|
7133
|
+
<decomposition_rule>
|
|
7057
7134
|
|
|
7058
7135
|
If a single user message contains **multiple independent asks** that don't share state, spawn **one worker per ask, all in the same turn** (parallel \`spawn\` calls). They run concurrently and finish faster. Examples of when to split:
|
|
7059
7136
|
|
|
@@ -7069,18 +7146,22 @@ When NOT to split (keep as one worker):
|
|
|
7069
7146
|
- The asks share state (one's output feeds the other).
|
|
7070
7147
|
- The asks are tightly coupled (e.g. *"refactor X and run its tests"* \u2014 the tests depend on the refactor).
|
|
7071
7148
|
- The asks are trivially small (one or two tool calls each); spawning overhead exceeds the parallelism win.
|
|
7149
|
+
</decomposition_rule>
|
|
7072
7150
|
|
|
7073
|
-
|
|
7151
|
+
<prefer_headless_tools>
|
|
7074
7152
|
|
|
7075
7153
|
When spawning a worker, push it toward the *cheapest tool that gets the job done*:
|
|
7076
7154
|
|
|
7077
7155
|
1. **Bash / file tools** for anything with a CLI (git, npm, brew, builds, tests, file editing, HTTP via curl, scripting).
|
|
7078
|
-
2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions
|
|
7156
|
+
2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions.
|
|
7157
|
+
</prefer_headless_tools>${desktopAvailable ? `
|
|
7158
|
+
|
|
7159
|
+
<desktop_automation_guidance>
|
|
7079
7160
|
3. **Desktop automation** (\`load_skill desktop-automation\`) is the last resort \u2014 only when the task genuinely requires a native macOS GUI app with no CLI / API equivalent (System Settings, Calculator, Finder operations that don't have CLI flags, complex cross-app drag/drop, demos where the user wants to *see* the screen). It's all shell \u2014 \`cliclick\`, \`screencapture\`, and \`osascript\` \u2014 invoked from \`bash\`. No special tool registration; no vendor lock-in.
|
|
7080
7161
|
|
|
7081
7162
|
A common anti-pattern: a worker reaches for desktop automation because the user phrased the request visually ("open the website and click the button"). Almost always wrong \u2014 that's a job for the browser skill, not the desktop. Coach the worker in its goal text: *"Use the browser skill (\`load_skill browser\` + \`agent-browser\` with refs from \`snapshot -i\`) to open the site and click the button. Don't use desktop automation for browser work."*
|
|
7082
7163
|
|
|
7083
|
-
|
|
7164
|
+
<serialize_desktop_automation_tasks>
|
|
7084
7165
|
|
|
7085
7166
|
There is exactly **one** desktop, mouse, and keyboard on the host. If two or more workers both drive the desktop (clicking with \`cliclick\`, taking screenshots with \`screencapture\`, opening apps, switching windows), they will **fight over the same screen** \u2014 windows will steal focus from each other, screenshots will catch the wrong app, mouse clicks will land on the wrong target.
|
|
7086
7167
|
|
|
@@ -7103,11 +7184,13 @@ Example: *"Take a screenshot of Calculator AND run the test suite AND open Syste
|
|
|
7103
7184
|
|
|
7104
7185
|
Headless workers never interfere with desktop workers (they don't touch the screen), so they always run in parallel.
|
|
7105
7186
|
|
|
7106
|
-
When you spawn a **desktop worker**, tell it to bracket the work with \`sparkecoder record start\` / \`sparkecoder record stop\` (per the \`recording\` skill) so the user can replay what happened on screen, unless the task is long-running / boring / contains sensitive content. When the worker reports back, mention the recording path in your reply via the original channel
|
|
7187
|
+
When you spawn a **desktop worker**, tell it to bracket the work with \`sparkecoder record start\` / \`sparkecoder record stop\` (per the \`recording\` skill) so the user can replay what happened on screen, unless the task is long-running / boring / contains sensitive content. When the worker reports back, mention the recording path in your reply via the original channel.
|
|
7188
|
+
</serialize_desktop_automation_tasks>
|
|
7189
|
+
</desktop_automation_guidance>` : ""}
|
|
7107
7190
|
|
|
7108
7191
|
Default bias: **when in doubt, decompose**. Two workers running in parallel and reporting independently is almost always better UX than one worker doing things sequentially.
|
|
7109
7192
|
|
|
7110
|
-
|
|
7193
|
+
<user_communication>
|
|
7111
7194
|
|
|
7112
7195
|
All of the rules below \u2014 decomposition, parallel spawning, "don't invent commands", load-the-skill, etc. \u2014 are **your internal operating procedure**. They are how you decide what to do. They are NOT something to recite back to the user.
|
|
7113
7196
|
|
|
@@ -7126,8 +7209,9 @@ When replying to the user (Slack, web, or any channel), be a normal helpful assi
|
|
|
7126
7209
|
| *"I'll relay the user's instructions to the worker verbatim."* | *(say nothing \u2014 just do it)* |
|
|
7127
7210
|
|
|
7128
7211
|
If the user explicitly asks how you work, *then* you can explain the orchestrator/worker split. Otherwise: less is more.
|
|
7212
|
+
</user_communication>
|
|
7129
7213
|
|
|
7130
|
-
|
|
7214
|
+
<worker_goal_guidance>
|
|
7131
7215
|
|
|
7132
7216
|
You delegate; the worker executes. Stay at the **what** level, not the **how**.
|
|
7133
7217
|
|
|
@@ -7168,6 +7252,8 @@ Bad goal (don't do this):
|
|
|
7168
7252
|
|
|
7169
7253
|
Good goal (do this):
|
|
7170
7254
|
> "Capture a 30\u201360s screen recording of opening the macOS Weather app and viewing the Anchorage, AK forecast. \`load_skill recording\` and \`load_skill desktop-automation\` first; use the canonical commands from those skills. Verify the Anchorage temperature is visible in a final screenshot before completing. Return the recording path + a one-line summary of the forecast."
|
|
7255
|
+
</worker_goal_guidance>
|
|
7256
|
+
</orchestrator_mode>
|
|
7171
7257
|
`;
|
|
7172
7258
|
}
|
|
7173
7259
|
function createSummaryPrompt(conversationHistory) {
|
|
@@ -9969,9 +10055,9 @@ ${buildOrchestratorPromptAddendum()}`;
|
|
|
9969
10055
|
if (personality && personality.trim()) {
|
|
9970
10056
|
systemPrompt = `${systemPrompt}
|
|
9971
10057
|
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
10058
|
+
<personality>
|
|
10059
|
+
${personality.trim()}
|
|
10060
|
+
</personality>`;
|
|
9975
10061
|
}
|
|
9976
10062
|
}
|
|
9977
10063
|
const messages = await this.context.getMessages();
|
|
@@ -10950,13 +11036,20 @@ async function ensureOrchestratorSession(opts = {}) {
|
|
|
10950
11036
|
try {
|
|
10951
11037
|
const all = await sessionQueries.list(500, 0);
|
|
10952
11038
|
const existing = all.find((s) => s.config?.role === "orchestrator");
|
|
10953
|
-
if (existing)
|
|
11039
|
+
if (existing) {
|
|
11040
|
+
if (existing.config?.toolApprovals?.["*"] !== false) {
|
|
11041
|
+
await sessionQueries.update(existing.id, {
|
|
11042
|
+
config: autoApproveAllTools(existing.config ?? { role: "orchestrator" })
|
|
11043
|
+
});
|
|
11044
|
+
}
|
|
11045
|
+
return existing.id;
|
|
11046
|
+
}
|
|
10954
11047
|
const cfg = getConfig();
|
|
10955
11048
|
const created = await sessionQueries.create({
|
|
10956
11049
|
name: "Orchestrator",
|
|
10957
11050
|
workingDirectory: cfg.resolvedWorkingDirectory,
|
|
10958
11051
|
model: cfg.defaultModel,
|
|
10959
|
-
config: { role: "orchestrator" }
|
|
11052
|
+
config: autoApproveAllTools({ role: "orchestrator" })
|
|
10960
11053
|
});
|
|
10961
11054
|
if (!opts.quiet) {
|
|
10962
11055
|
console.log(`[orchestrator] auto-created session ${created.id}`);
|
|
@@ -11224,11 +11317,14 @@ sessions2.post(
|
|
|
11224
11317
|
const body = c.req.valid("json");
|
|
11225
11318
|
const config = getConfig();
|
|
11226
11319
|
const baseConfig = body.config || {};
|
|
11227
|
-
|
|
11320
|
+
let mergedConfig = {
|
|
11228
11321
|
...baseConfig,
|
|
11229
11322
|
...body.toolApprovals ? { toolApprovals: body.toolApprovals } : {},
|
|
11230
11323
|
...body.role ? { role: body.role } : {}
|
|
11231
11324
|
};
|
|
11325
|
+
if (mergedConfig.role === "orchestrator") {
|
|
11326
|
+
mergedConfig = autoApproveAllTools(mergedConfig);
|
|
11327
|
+
}
|
|
11232
11328
|
const agent = await Agent.create({
|
|
11233
11329
|
name: body.name,
|
|
11234
11330
|
workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
|
|
@@ -13956,10 +14052,11 @@ tasks.post(
|
|
|
13956
14052
|
workingDirectory: body.workingDirectory || parentSession.workingDirectory,
|
|
13957
14053
|
model: body.model || parentSession.model,
|
|
13958
14054
|
sessionConfig: {
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
14055
|
+
...autoApproveAllTools({
|
|
14056
|
+
task: taskConfig,
|
|
14057
|
+
role: "worker",
|
|
14058
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
14059
|
+
})
|
|
13963
14060
|
}
|
|
13964
14061
|
});
|
|
13965
14062
|
const parentMessages = await messageQueries.getBySession(body.parentTaskId);
|
|
@@ -13974,10 +14071,11 @@ tasks.post(
|
|
|
13974
14071
|
workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
|
|
13975
14072
|
model: body.model || config.defaultModel,
|
|
13976
14073
|
sessionConfig: {
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
14074
|
+
...autoApproveAllTools({
|
|
14075
|
+
task: taskConfig,
|
|
14076
|
+
role: "worker",
|
|
14077
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
14078
|
+
})
|
|
13981
14079
|
}
|
|
13982
14080
|
});
|
|
13983
14081
|
}
|
|
@@ -14024,10 +14122,11 @@ tasks.post(
|
|
|
14024
14122
|
error: errorMsg
|
|
14025
14123
|
};
|
|
14026
14124
|
await sessionQueries.update(taskId, {
|
|
14027
|
-
config: {
|
|
14028
|
-
|
|
14029
|
-
|
|
14030
|
-
|
|
14125
|
+
config: autoApproveAllTools({
|
|
14126
|
+
task: failedTask,
|
|
14127
|
+
role: "worker",
|
|
14128
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
14129
|
+
})
|
|
14031
14130
|
});
|
|
14032
14131
|
if (taskConfig.webhookUrl) {
|
|
14033
14132
|
const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook2(), webhook_exports));
|
|
@@ -14321,13 +14420,13 @@ async function findOrCreateOrchestratorId() {
|
|
|
14321
14420
|
const all = await sessionQueries.list(500, 0);
|
|
14322
14421
|
const existing = all.find((s) => s.config?.role === "orchestrator");
|
|
14323
14422
|
if (existing) return existing.id;
|
|
14324
|
-
const { getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
14423
|
+
const { autoApproveAllTools: autoApproveAllTools2, getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
14325
14424
|
const cfg = getConfig2();
|
|
14326
14425
|
const created = await sessionQueries.create({
|
|
14327
14426
|
name: getDefaultOrchestratorName() || "Orchestrator",
|
|
14328
14427
|
workingDirectory: cfg.resolvedWorkingDirectory,
|
|
14329
14428
|
model: cfg.defaultModel,
|
|
14330
|
-
config: { role: "orchestrator" }
|
|
14429
|
+
config: autoApproveAllTools2({ role: "orchestrator" })
|
|
14331
14430
|
});
|
|
14332
14431
|
return created.id;
|
|
14333
14432
|
} catch (err) {
|