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/cli.js
CHANGED
|
@@ -706,7 +706,10 @@ var init_types = __esm({
|
|
|
706
706
|
// not listed here. Values match `process.platform`
|
|
707
707
|
// (darwin, linux, win32, freebsd, ...). If omitted or empty, the skill is
|
|
708
708
|
// available on all platforms.
|
|
709
|
-
platforms: z.array(z.string()).optional().default([])
|
|
709
|
+
platforms: z.array(z.string()).optional().default([]),
|
|
710
|
+
// Optional approximate token budget for always-loaded content. If set,
|
|
711
|
+
// the prompt builder truncates this skill/rule before injecting it.
|
|
712
|
+
contextBudgetTokens: z.number().int().positive().optional()
|
|
710
713
|
});
|
|
711
714
|
TaskConfigSchema = z.object({
|
|
712
715
|
enabled: z.boolean(),
|
|
@@ -945,6 +948,7 @@ __export(config_exports, {
|
|
|
945
948
|
TaskConfigSchema: () => TaskConfigSchema,
|
|
946
949
|
ToolApprovalConfigSchema: () => ToolApprovalConfigSchema,
|
|
947
950
|
VectorGatewayConfigSchema: () => VectorGatewayConfigSchema,
|
|
951
|
+
autoApproveAllTools: () => autoApproveAllTools,
|
|
948
952
|
clearSlackConfig: () => clearSlackConfig,
|
|
949
953
|
createDefaultConfig: () => createDefaultConfig,
|
|
950
954
|
discoverSkillDirectories: () => discoverSkillDirectories,
|
|
@@ -1340,6 +1344,16 @@ function requiresApproval(toolName, sessionConfig) {
|
|
|
1340
1344
|
}
|
|
1341
1345
|
return false;
|
|
1342
1346
|
}
|
|
1347
|
+
function autoApproveAllTools(sessionConfig) {
|
|
1348
|
+
const currentApprovals = sessionConfig.toolApprovals;
|
|
1349
|
+
return {
|
|
1350
|
+
...sessionConfig,
|
|
1351
|
+
toolApprovals: {
|
|
1352
|
+
...currentApprovals ?? {},
|
|
1353
|
+
...AUTO_APPROVE_ALL_TOOLS
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1343
1357
|
function createDefaultConfig() {
|
|
1344
1358
|
return {
|
|
1345
1359
|
defaultModel: "anthropic/claude-opus-4.7",
|
|
@@ -1570,7 +1584,7 @@ function maskApiKey(key2) {
|
|
|
1570
1584
|
}
|
|
1571
1585
|
return key2.slice(0, 4) + "..." + key2.slice(-4);
|
|
1572
1586
|
}
|
|
1573
|
-
var CONFIG_FILE_NAMES, cachedConfig, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
1587
|
+
var CONFIG_FILE_NAMES, cachedConfig, AUTO_APPROVE_ALL_TOOLS, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
1574
1588
|
var init_config = __esm({
|
|
1575
1589
|
"src/config/index.ts"() {
|
|
1576
1590
|
"use strict";
|
|
@@ -1582,6 +1596,7 @@ var init_config = __esm({
|
|
|
1582
1596
|
".sparkecoder.json"
|
|
1583
1597
|
];
|
|
1584
1598
|
cachedConfig = null;
|
|
1599
|
+
AUTO_APPROVE_ALL_TOOLS = { "*": false };
|
|
1585
1600
|
AUTH_KEY_FILE = "auth-key.json";
|
|
1586
1601
|
API_KEYS_FILE = "api-keys.json";
|
|
1587
1602
|
PROVIDER_ENV_MAP = {
|
|
@@ -4036,6 +4051,8 @@ function parseSkillFrontmatter(content) {
|
|
|
4036
4051
|
data[key2] = true;
|
|
4037
4052
|
} else if (value === "false") {
|
|
4038
4053
|
data[key2] = false;
|
|
4054
|
+
} else if (/^\d+$/.test(value)) {
|
|
4055
|
+
data[key2] = Number(value);
|
|
4039
4056
|
} else {
|
|
4040
4057
|
data[key2] = value;
|
|
4041
4058
|
}
|
|
@@ -4095,7 +4112,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4095
4112
|
loadType,
|
|
4096
4113
|
priority,
|
|
4097
4114
|
sourceDir: directory,
|
|
4098
|
-
platforms: parsed.metadata.platforms
|
|
4115
|
+
platforms: parsed.metadata.platforms,
|
|
4116
|
+
contextBudgetTokens: parsed.metadata.contextBudgetTokens
|
|
4099
4117
|
});
|
|
4100
4118
|
} else {
|
|
4101
4119
|
const name = getSkillNameFromPath(filePath);
|
|
@@ -4109,7 +4127,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4109
4127
|
loadType: forceAlwaysApply ? "always" : defaultLoadType,
|
|
4110
4128
|
priority,
|
|
4111
4129
|
sourceDir: directory,
|
|
4112
|
-
platforms: []
|
|
4130
|
+
platforms: [],
|
|
4131
|
+
contextBudgetTokens: void 0
|
|
4113
4132
|
});
|
|
4114
4133
|
}
|
|
4115
4134
|
}
|
|
@@ -4239,11 +4258,12 @@ function formatSkillsForContext(skills2) {
|
|
|
4239
4258
|
if (onDemandSkills.length === 0) {
|
|
4240
4259
|
return "No on-demand skills available.";
|
|
4241
4260
|
}
|
|
4242
|
-
const lines = ["
|
|
4261
|
+
const lines = ["<available_skills>", "Use the load_skill tool to load one of these into context:"];
|
|
4243
4262
|
for (const skill of onDemandSkills) {
|
|
4244
4263
|
const globInfo = skill.globs?.length ? ` [auto-loads for: ${skill.globs.join(", ")}]` : "";
|
|
4245
4264
|
lines.push(`- ${skill.name}: ${skill.description}${globInfo}`);
|
|
4246
4265
|
}
|
|
4266
|
+
lines.push("</available_skills>");
|
|
4247
4267
|
return lines.join("\n");
|
|
4248
4268
|
}
|
|
4249
4269
|
function formatAlwaysLoadedSkills(skills2) {
|
|
@@ -4252,13 +4272,22 @@ function formatAlwaysLoadedSkills(skills2) {
|
|
|
4252
4272
|
}
|
|
4253
4273
|
const sections = [];
|
|
4254
4274
|
for (const skill of skills2) {
|
|
4255
|
-
sections.push(
|
|
4256
|
-
|
|
4257
|
-
|
|
4275
|
+
sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
|
|
4276
|
+
${truncateSkillContent(skill)}
|
|
4277
|
+
</skill>`);
|
|
4258
4278
|
}
|
|
4259
|
-
return
|
|
4279
|
+
return `<always_loaded_rules_and_skills>
|
|
4280
|
+
${sections.join("\n\n")}
|
|
4281
|
+
</always_loaded_rules_and_skills>`;
|
|
4282
|
+
}
|
|
4283
|
+
function truncateSkillContent(skill) {
|
|
4284
|
+
if (!skill.contextBudgetTokens) return skill.content;
|
|
4285
|
+
const maxChars = Math.max(200, skill.contextBudgetTokens * 4);
|
|
4286
|
+
if (skill.content.length <= maxChars) return skill.content;
|
|
4287
|
+
const omitted = skill.content.length - maxChars;
|
|
4288
|
+
return `${skill.content.slice(0, maxChars).trimEnd()}
|
|
4260
4289
|
|
|
4261
|
-
${
|
|
4290
|
+
... [${skill.name} truncated by contextBudgetTokens=${skill.contextBudgetTokens}; ${omitted} chars omitted. Read ${skill.filePath} for the full file.]`;
|
|
4262
4291
|
}
|
|
4263
4292
|
function formatGlobMatchedSkills(skills2) {
|
|
4264
4293
|
if (skills2.length === 0) {
|
|
@@ -4266,21 +4295,24 @@ function formatGlobMatchedSkills(skills2) {
|
|
|
4266
4295
|
}
|
|
4267
4296
|
const sections = [];
|
|
4268
4297
|
for (const skill of skills2) {
|
|
4269
|
-
sections.push(
|
|
4270
|
-
|
|
4271
|
-
|
|
4298
|
+
sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
|
|
4299
|
+
${skill.content}
|
|
4300
|
+
</skill>`);
|
|
4272
4301
|
}
|
|
4273
|
-
return
|
|
4274
|
-
|
|
4275
|
-
|
|
4302
|
+
return `<glob_matched_skills>
|
|
4303
|
+
${sections.join("\n\n")}
|
|
4304
|
+
</glob_matched_skills>`;
|
|
4276
4305
|
}
|
|
4277
4306
|
function formatAgentsMdContent(content) {
|
|
4278
4307
|
if (!content) {
|
|
4279
4308
|
return "";
|
|
4280
4309
|
}
|
|
4281
|
-
return
|
|
4282
|
-
|
|
4283
|
-
|
|
4310
|
+
return `<project_instructions source="AGENTS.md">
|
|
4311
|
+
${content}
|
|
4312
|
+
</project_instructions>`;
|
|
4313
|
+
}
|
|
4314
|
+
function escapeXmlAttribute(value) {
|
|
4315
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
4284
4316
|
}
|
|
4285
4317
|
var init_skills = __esm({
|
|
4286
4318
|
"src/skills/index.ts"() {
|
|
@@ -7287,14 +7319,18 @@ async function buildSystemPrompt(options) {
|
|
|
7287
7319
|
const platform3 = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
|
|
7288
7320
|
const currentDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" });
|
|
7289
7321
|
const searchInstructions = getSearchInstructions();
|
|
7290
|
-
const systemPrompt =
|
|
7322
|
+
const systemPrompt = `<system_prompt>
|
|
7323
|
+
<identity>
|
|
7324
|
+
You are SparkECoder, an expert AI coding assistant. You help developers write, debug, and improve code.
|
|
7325
|
+
</identity>
|
|
7291
7326
|
|
|
7292
|
-
|
|
7327
|
+
<environment>
|
|
7293
7328
|
- **Platform**: ${platform3} (${os.release()})
|
|
7294
7329
|
- **Date**: ${currentDate}
|
|
7295
7330
|
- **Working Directory**: ${workingDirectory}
|
|
7331
|
+
</environment>
|
|
7296
7332
|
|
|
7297
|
-
|
|
7333
|
+
<core_capabilities>
|
|
7298
7334
|
You have access to powerful tools for:
|
|
7299
7335
|
- **bash**: Execute commands in the terminal (see below for details)
|
|
7300
7336
|
- **read_file**: Read file contents to understand code and context
|
|
@@ -7308,8 +7344,9 @@ You have access to powerful tools for:
|
|
|
7308
7344
|
|
|
7309
7345
|
|
|
7310
7346
|
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.
|
|
7347
|
+
</core_capabilities>
|
|
7311
7348
|
|
|
7312
|
-
|
|
7349
|
+
<planning_and_task_management>
|
|
7313
7350
|
Use the **todo tool** to manage both immediate tasks AND persistent plans:
|
|
7314
7351
|
|
|
7315
7352
|
**For simple tasks (< 5 steps):** Just use regular todos (add/mark/clear).
|
|
@@ -7329,8 +7366,9 @@ Use the **todo tool** to manage both immediate tasks AND persistent plans:
|
|
|
7329
7366
|
- Only top-level checklist items (- [ ]) become todos \u2014 indented sub-items are part of the task detail
|
|
7330
7367
|
- Sections named Overview, Notes, Key Decisions, etc. are not treated as phases
|
|
7331
7368
|
- You can clear the todo list and restart it, and do multiple things inside of one session
|
|
7369
|
+
</planning_and_task_management>
|
|
7332
7370
|
|
|
7333
|
-
|
|
7371
|
+
<bash_tool>
|
|
7334
7372
|
The bash tool runs commands in the terminal. Every command runs in its own session with logs saved to disk.
|
|
7335
7373
|
|
|
7336
7374
|
**Run a command (default - waits for completion):**
|
|
@@ -7377,22 +7415,25 @@ bash({ id: "abc123", input: "my text" }) // send text input
|
|
|
7377
7415
|
- Use \`input: "text"\` for text input prompts
|
|
7378
7416
|
|
|
7379
7417
|
Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.
|
|
7418
|
+
</bash_tool>
|
|
7380
7419
|
|
|
7381
|
-
|
|
7420
|
+
<guidelines>
|
|
7382
7421
|
|
|
7383
|
-
|
|
7422
|
+
<code_quality>
|
|
7384
7423
|
- Write clean, maintainable, well-documented code
|
|
7385
7424
|
- Follow existing code style and conventions in the project
|
|
7386
7425
|
- Use meaningful variable and function names
|
|
7387
7426
|
- Add comments for complex logic
|
|
7427
|
+
</code_quality>
|
|
7388
7428
|
|
|
7389
|
-
|
|
7429
|
+
<problem_solving>
|
|
7390
7430
|
- Before making changes, understand the existing code structure
|
|
7391
7431
|
- Break complex tasks into smaller, manageable steps using the todo tool
|
|
7392
7432
|
- Test changes when possible using the bash tool
|
|
7393
7433
|
- Handle errors gracefully and provide helpful error messages
|
|
7434
|
+
</problem_solving>
|
|
7394
7435
|
|
|
7395
|
-
|
|
7436
|
+
<file_operations>
|
|
7396
7437
|
- Use \`read_file\` to understand code before modifying
|
|
7397
7438
|
- Use \`write_file\` with mode "str_replace" for targeted edits to existing files
|
|
7398
7439
|
- Use \`write_file\` with mode "full" only for new files or complete rewrites
|
|
@@ -7401,8 +7442,9 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
7401
7442
|
- If the user asks to write/create a file, always use \`write_file\` rather than printing the full contents
|
|
7402
7443
|
- If the user requests a file but does not provide a path, choose a sensible default (e.g. \`index.html\`) and proceed
|
|
7403
7444
|
- For large content (hundreds of lines), avoid placing it in chat output; write to a file instead
|
|
7445
|
+
</file_operations>
|
|
7404
7446
|
|
|
7405
|
-
|
|
7447
|
+
<linter_tool>
|
|
7406
7448
|
The linter tool uses Language Server Protocol (LSP) to detect type errors and lint issues:
|
|
7407
7449
|
\`\`\`
|
|
7408
7450
|
linter({}) // Check all recently edited files
|
|
@@ -7410,8 +7452,9 @@ linter({ paths: ["src/app.ts"] }) // Check specific files
|
|
|
7410
7452
|
linter({ paths: ["src/"] }) // Check all files in a directory
|
|
7411
7453
|
\`\`\`
|
|
7412
7454
|
Use this proactively after making code changes to catch errors early.
|
|
7455
|
+
</linter_tool>
|
|
7413
7456
|
|
|
7414
|
-
|
|
7457
|
+
<code_graph_tool>
|
|
7415
7458
|
The code_graph tool uses the TypeScript language server to inspect a symbol's type hierarchy and usage graph:
|
|
7416
7459
|
\`\`\`
|
|
7417
7460
|
code_graph({ symbol: "UserCard" }) // Search workspace for symbol
|
|
@@ -7437,8 +7480,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
|
|
|
7437
7480
|
- For exploratory "how does X work?" questions \u2014 use \`explore_agent\` instead
|
|
7438
7481
|
- For exact string searches \u2014 use grep/rg directly
|
|
7439
7482
|
- For non-TypeScript/JavaScript files \u2014 code_graph only supports TS/JS/TSX/JSX
|
|
7483
|
+
</code_graph_tool>
|
|
7440
7484
|
|
|
7441
|
-
|
|
7485
|
+
<searching_and_exploration>
|
|
7442
7486
|
|
|
7443
7487
|
**Choose the right search approach:**
|
|
7444
7488
|
|
|
@@ -7489,8 +7533,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
|
|
|
7489
7533
|
- "Find files named config" \u2192 Use \`find . -name "*config*"\`
|
|
7490
7534
|
|
|
7491
7535
|
${searchInstructions}
|
|
7536
|
+
</searching_and_exploration>
|
|
7492
7537
|
|
|
7493
|
-
|
|
7538
|
+
<software_design_principles>
|
|
7494
7539
|
|
|
7495
7540
|
1. **Modularity** \u2014 Write simple parts connected by clean interfaces
|
|
7496
7541
|
2. **Clarity** \u2014 Clarity is better than cleverness
|
|
@@ -7509,8 +7554,9 @@ ${searchInstructions}
|
|
|
7509
7554
|
15. **Optimization** \u2014 Prototype before polishing. Get it working before you optimize it
|
|
7510
7555
|
16. **Diversity** \u2014 Distrust all claims for "one true way"
|
|
7511
7556
|
17. **Extensibility** \u2014 Design for the future, because it will be here sooner than you think
|
|
7557
|
+
</software_design_principles>
|
|
7512
7558
|
|
|
7513
|
-
|
|
7559
|
+
<ui_design_principles>
|
|
7514
7560
|
|
|
7515
7561
|
1. **Simplicity** \u2014 Simplicity is the ultimate sophistication. Remove everything unnecessary.
|
|
7516
7562
|
2. **Focus** \u2014 Say no to 1,000 things to say yes to the few that matter most.
|
|
@@ -7522,8 +7568,9 @@ ${searchInstructions}
|
|
|
7522
7568
|
8. **Feedback** \u2014 Every action deserves a response. Make interactions feel alive.
|
|
7523
7569
|
9. **Forgiveness** \u2014 Make it easy to undo. Never punish exploration.
|
|
7524
7570
|
10. **Beauty** \u2014 Aesthetics are not superficial. Beautiful things work better because people care about them.
|
|
7571
|
+
</ui_design_principles>
|
|
7525
7572
|
|
|
7526
|
-
|
|
7573
|
+
<agent_behavior_rules>
|
|
7527
7574
|
|
|
7528
7575
|
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.
|
|
7529
7576
|
2. Plan for complexity - If the task involves 3+ steps or has meaningful trade-offs, create a todo list to track progress before implementing.
|
|
@@ -7532,13 +7579,16 @@ ${searchInstructions}
|
|
|
7532
7579
|
5. Be direct - Focus on technical accuracy rather than validation. If see issues with an approach or need clarification, say so.
|
|
7533
7580
|
6. Verify my work - After making changes, check for linter errors and fix any introduced.
|
|
7534
7581
|
7. Respect boundaries - Only commit code when explicitly asked, avoid creating unnecessary files, and don't make assumptions about things uncertain about.
|
|
7582
|
+
</agent_behavior_rules>
|
|
7535
7583
|
|
|
7536
7584
|
|
|
7537
|
-
|
|
7585
|
+
<communication>
|
|
7538
7586
|
- Explain your reasoning and approach
|
|
7539
7587
|
- Be concise but thorough
|
|
7540
7588
|
- Ask clarifying questions when requirements are ambiguous
|
|
7541
7589
|
- Report progress on multi-step tasks
|
|
7590
|
+
</communication>
|
|
7591
|
+
</guidelines>
|
|
7542
7592
|
|
|
7543
7593
|
${agentsMdContent}
|
|
7544
7594
|
|
|
@@ -7546,18 +7596,24 @@ ${alwaysLoadedContent}
|
|
|
7546
7596
|
|
|
7547
7597
|
${globMatchedContent}
|
|
7548
7598
|
|
|
7549
|
-
|
|
7599
|
+
<on_demand_skills>
|
|
7550
7600
|
${onDemandSkillsContext}
|
|
7601
|
+
</on_demand_skills>
|
|
7551
7602
|
|
|
7552
|
-
|
|
7603
|
+
<current_task_list>
|
|
7553
7604
|
${todosContext}
|
|
7605
|
+
</current_task_list>
|
|
7554
7606
|
|
|
7555
7607
|
${plansContext}
|
|
7556
7608
|
|
|
7557
|
-
${customInstructions ?
|
|
7558
|
-
${customInstructions}
|
|
7609
|
+
${customInstructions ? `<custom_instructions>
|
|
7610
|
+
${customInstructions}
|
|
7611
|
+
</custom_instructions>` : ""}
|
|
7559
7612
|
|
|
7560
|
-
|
|
7613
|
+
<final_reminder>
|
|
7614
|
+
Remember: You are a helpful, capable coding assistant. Take initiative, be thorough, and deliver high-quality results.
|
|
7615
|
+
</final_reminder>
|
|
7616
|
+
</system_prompt>`;
|
|
7561
7617
|
return systemPrompt;
|
|
7562
7618
|
}
|
|
7563
7619
|
function formatTodosForContext(todos) {
|
|
@@ -7581,7 +7637,7 @@ function formatPlansForContext(plans, shouldContinue) {
|
|
|
7581
7637
|
if (plans.length === 0) return "";
|
|
7582
7638
|
let totalChars = 0;
|
|
7583
7639
|
const sections = [];
|
|
7584
|
-
sections.push(
|
|
7640
|
+
sections.push(`<persistent_plans count="${plans.length}">`);
|
|
7585
7641
|
sections.push("");
|
|
7586
7642
|
sections.push("These plans persist across context compaction \u2014 they are always available.");
|
|
7587
7643
|
sections.push("When you finish your current todos, check these plans for the next uncompleted phase,");
|
|
@@ -7602,34 +7658,39 @@ function formatPlansForContext(plans, shouldContinue) {
|
|
|
7602
7658
|
... [plan truncated \u2014 ${content.length - MAX_PLAN_CHARS} chars omitted. Use get_plan to read the full plan.]`;
|
|
7603
7659
|
}
|
|
7604
7660
|
if (totalChars + content.length > MAX_TOTAL_PLANS_CHARS) {
|
|
7605
|
-
sections.push(
|
|
7661
|
+
sections.push(`<plan name="${plan.name}" truncated="true">Use get_plan("${plan.name}") to read.</plan>`);
|
|
7606
7662
|
continue;
|
|
7607
7663
|
}
|
|
7608
|
-
sections.push(
|
|
7609
|
-
sections.push("");
|
|
7664
|
+
sections.push(`<plan name="${plan.name}">`);
|
|
7610
7665
|
sections.push(content);
|
|
7611
|
-
sections.push("");
|
|
7666
|
+
sections.push("</plan>");
|
|
7612
7667
|
totalChars += content.length;
|
|
7613
7668
|
}
|
|
7669
|
+
sections.push("</persistent_plans>");
|
|
7614
7670
|
return sections.join("\n");
|
|
7615
7671
|
}
|
|
7616
7672
|
function buildTaskPromptAddendum(outputSchema) {
|
|
7617
7673
|
return `
|
|
7618
|
-
|
|
7674
|
+
<task_mode>
|
|
7619
7675
|
|
|
7620
7676
|
You are running in **task mode**. You have been given a specific task to complete autonomously.
|
|
7621
7677
|
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.
|
|
7622
7678
|
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.
|
|
7623
7679
|
|
|
7624
|
-
|
|
7680
|
+
<rules>
|
|
7625
7681
|
1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
|
|
7626
7682
|
2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
|
|
7627
7683
|
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.
|
|
7628
7684
|
4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
|
|
7629
7685
|
5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
|
|
7630
7686
|
6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
|
|
7687
|
+
</rules>
|
|
7688
|
+
|
|
7689
|
+
<memory_guidance>
|
|
7690
|
+
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.
|
|
7691
|
+
</memory_guidance>
|
|
7631
7692
|
|
|
7632
|
-
|
|
7693
|
+
<verification>
|
|
7633
7694
|
Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
|
|
7634
7695
|
|
|
7635
7696
|
**After making code changes:**
|
|
@@ -7680,35 +7741,40 @@ Before calling \`complete_task\`, you MUST verify your work completely. Do not j
|
|
|
7680
7741
|
\`\`\`
|
|
7681
7742
|
- In task results, NEVER return local filesystem paths for screenshots/reports. Return only the \`downloadUrl\` from \`upload_file\`.
|
|
7682
7743
|
- This is especially valuable for UI/visual changes, successful test runs, and browser verification \u2014 show, don't just tell.
|
|
7744
|
+
</verification>
|
|
7683
7745
|
|
|
7684
|
-
|
|
7746
|
+
<use_all_available_tools>
|
|
7685
7747
|
- **load_skill**: Load specialized skills/knowledge relevant to the task. Check what skills are available and use them.
|
|
7686
7748
|
- **explore_agent**: Use for codebase exploration and understanding before making changes.
|
|
7687
7749
|
- **code_graph**: Use to understand type hierarchies, references, and impact before refactoring.
|
|
7688
7750
|
- **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.
|
|
7689
7751
|
- **bash**: Full shell access \u2014 run builds, tests, dev servers, open browsers, curl endpoints, anything.
|
|
7690
7752
|
- **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.
|
|
7753
|
+
</use_all_available_tools>
|
|
7691
7754
|
|
|
7692
|
-
|
|
7755
|
+
<output_schema>
|
|
7693
7756
|
The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
|
|
7694
7757
|
\`\`\`json
|
|
7695
7758
|
${JSON.stringify(outputSchema, null, 2)}
|
|
7696
7759
|
\`\`\`
|
|
7760
|
+
</output_schema>
|
|
7697
7761
|
|
|
7698
|
-
|
|
7762
|
+
<completion_tools>
|
|
7699
7763
|
- **\`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.
|
|
7700
7764
|
- **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
|
|
7701
7765
|
- **\`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.
|
|
7766
|
+
</completion_tools>
|
|
7767
|
+
</task_mode>
|
|
7702
7768
|
`;
|
|
7703
7769
|
}
|
|
7704
7770
|
function buildOrchestratorPromptAddendum() {
|
|
7705
7771
|
const desktopAvailable = process.platform === "darwin";
|
|
7706
7772
|
return `
|
|
7707
|
-
|
|
7773
|
+
<orchestrator_mode>
|
|
7708
7774
|
|
|
7709
|
-
You are the **orchestrator agent**. You triage everything that comes in, spawn worker agents to do
|
|
7775
|
+
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.
|
|
7710
7776
|
|
|
7711
|
-
|
|
7777
|
+
<channels>
|
|
7712
7778
|
|
|
7713
7779
|
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.
|
|
7714
7780
|
|
|
@@ -7724,23 +7790,28 @@ Pill formats:
|
|
|
7724
7790
|
- \`[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})\`.
|
|
7725
7791
|
- \`[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.
|
|
7726
7792
|
- \`[WEBHOOK name] ...\` \u2014 an external service hit one of your webhook URLs. Body is the request body (verbatim or per the webhook's template).
|
|
7793
|
+
</channels>
|
|
7727
7794
|
|
|
7728
|
-
|
|
7795
|
+
<delivery_failures>
|
|
7729
7796
|
|
|
7730
7797
|
If \`messenger({action:'post', ...})\` returns \`{ok:false, error:'...'}\` (e.g. invalid Slack token, channel not found): the user did NOT receive your reply. Try:
|
|
7731
7798
|
1. Re-checking the destination (channel id, thread ts).
|
|
7732
7799
|
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).
|
|
7733
7800
|
3. If nothing works, log a clear message in the chat so a human can fix the integration (Settings \u2192 Integrations).
|
|
7734
7801
|
**Never silently swallow a delivery failure.**
|
|
7802
|
+
</delivery_failures>
|
|
7735
7803
|
|
|
7736
|
-
|
|
7804
|
+
<hard_rules>
|
|
7737
7805
|
|
|
7738
|
-
-
|
|
7806
|
+
- Avoid direct workspace work. Do not directly edit product code, run builds, or perform substantive implementation yourself; spawn workers for that.
|
|
7807
|
+
- 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.
|
|
7808
|
+
- Prefer workers for implementation, long-running verification, and independent sub-tasks so work can run in parallel and report back cleanly.
|
|
7739
7809
|
- Give workers **clear, self-contained goals**. Include any context they'd otherwise have to ask you about.
|
|
7740
7810
|
- Prefer \`agent({action:'message'})\` (queued) over \`agent({action:'stop'})\` for course corrections.
|
|
7741
7811
|
- Don't poll. Worker completions wake you automatically via SYSTEM events.
|
|
7812
|
+
</hard_rules>
|
|
7742
7813
|
|
|
7743
|
-
|
|
7814
|
+
<tools>
|
|
7744
7815
|
|
|
7745
7816
|
\`\`\`
|
|
7746
7817
|
agent({action: 'list' | 'get' | 'spawn' | 'message' | 'answer_question' | 'stop', ...})
|
|
@@ -7750,17 +7821,21 @@ webhook({action: 'create' | 'list' | 'update' | 'delete', ...})
|
|
|
7750
7821
|
\`\`\`
|
|
7751
7822
|
|
|
7752
7823
|
You ALSO have the regular agent toolset (\`bash\`, \`read_file\`, \`write_file\`, \`load_skill\`, \`linter\`, \`explore_agent\`, \`code_graph\`, etc.) for low-level work.
|
|
7824
|
+
</tools>
|
|
7753
7825
|
|
|
7754
|
-
|
|
7826
|
+
<self_extension>
|
|
7755
7827
|
|
|
7756
7828
|
You manage your own configuration by editing files. Load the relevant skill first to get the file path and schema:
|
|
7757
7829
|
|
|
7758
7830
|
- **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.
|
|
7831
|
+
- **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.
|
|
7832
|
+
- **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/\`.
|
|
7759
7833
|
- **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.
|
|
7760
7834
|
|
|
7761
|
-
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.
|
|
7835
|
+
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.
|
|
7836
|
+
</self_extension>
|
|
7762
7837
|
|
|
7763
|
-
|
|
7838
|
+
<common_shapes>
|
|
7764
7839
|
- Spawn a worker:
|
|
7765
7840
|
\`agent({action:'spawn', name:'count-tests', goal:'Run X and report Y as summary', outputSchema?: { type:'object', properties:{...}, required:[...] }})\`
|
|
7766
7841
|
- Answer a worker's question:
|
|
@@ -7771,15 +7846,17 @@ If the user asks "add the GitHub MCP" or "remember that I prefer Python", load t
|
|
|
7771
7846
|
\`schedule({action:'create', name:'standup-9am', cron:'0 9 * * 1-5', prompt:'Summarize yesterday\\'s git activity in this repo'})\`
|
|
7772
7847
|
- Create a webhook:
|
|
7773
7848
|
\`webhook({action:'create', name:'github-prs', wake:'now'})\` \u2014 returns the URL.
|
|
7849
|
+
</common_shapes>
|
|
7774
7850
|
|
|
7775
|
-
|
|
7851
|
+
<typical_flow>
|
|
7776
7852
|
|
|
7777
7853
|
1. Inbound event arrives (any channel).
|
|
7778
7854
|
2. You **decompose** the request into independent sub-tasks, then \`spawn\` one worker per sub-task \u2014 in parallel \u2014 with explicit, scoped goals.
|
|
7779
7855
|
3. Workers run autonomously. They wake you via SYSTEM events when done / failed / blocked.
|
|
7780
7856
|
4. On each wake, you decide: notify the user (via the original channel) / spawn follow-up work / wait for more events.
|
|
7857
|
+
</typical_flow>
|
|
7781
7858
|
|
|
7782
|
-
|
|
7859
|
+
<decomposition_rule>
|
|
7783
7860
|
|
|
7784
7861
|
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:
|
|
7785
7862
|
|
|
@@ -7795,18 +7872,22 @@ When NOT to split (keep as one worker):
|
|
|
7795
7872
|
- The asks share state (one's output feeds the other).
|
|
7796
7873
|
- The asks are tightly coupled (e.g. *"refactor X and run its tests"* \u2014 the tests depend on the refactor).
|
|
7797
7874
|
- The asks are trivially small (one or two tool calls each); spawning overhead exceeds the parallelism win.
|
|
7875
|
+
</decomposition_rule>
|
|
7798
7876
|
|
|
7799
|
-
|
|
7877
|
+
<prefer_headless_tools>
|
|
7800
7878
|
|
|
7801
7879
|
When spawning a worker, push it toward the *cheapest tool that gets the job done*:
|
|
7802
7880
|
|
|
7803
7881
|
1. **Bash / file tools** for anything with a CLI (git, npm, brew, builds, tests, file editing, HTTP via curl, scripting).
|
|
7804
|
-
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
|
|
7882
|
+
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.
|
|
7883
|
+
</prefer_headless_tools>${desktopAvailable ? `
|
|
7884
|
+
|
|
7885
|
+
<desktop_automation_guidance>
|
|
7805
7886
|
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.
|
|
7806
7887
|
|
|
7807
7888
|
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."*
|
|
7808
7889
|
|
|
7809
|
-
|
|
7890
|
+
<serialize_desktop_automation_tasks>
|
|
7810
7891
|
|
|
7811
7892
|
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.
|
|
7812
7893
|
|
|
@@ -7829,11 +7910,13 @@ Example: *"Take a screenshot of Calculator AND run the test suite AND open Syste
|
|
|
7829
7910
|
|
|
7830
7911
|
Headless workers never interfere with desktop workers (they don't touch the screen), so they always run in parallel.
|
|
7831
7912
|
|
|
7832
|
-
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
|
|
7913
|
+
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.
|
|
7914
|
+
</serialize_desktop_automation_tasks>
|
|
7915
|
+
</desktop_automation_guidance>` : ""}
|
|
7833
7916
|
|
|
7834
7917
|
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.
|
|
7835
7918
|
|
|
7836
|
-
|
|
7919
|
+
<user_communication>
|
|
7837
7920
|
|
|
7838
7921
|
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.
|
|
7839
7922
|
|
|
@@ -7852,8 +7935,9 @@ When replying to the user (Slack, web, or any channel), be a normal helpful assi
|
|
|
7852
7935
|
| *"I'll relay the user's instructions to the worker verbatim."* | *(say nothing \u2014 just do it)* |
|
|
7853
7936
|
|
|
7854
7937
|
If the user explicitly asks how you work, *then* you can explain the orchestrator/worker split. Otherwise: less is more.
|
|
7938
|
+
</user_communication>
|
|
7855
7939
|
|
|
7856
|
-
|
|
7940
|
+
<worker_goal_guidance>
|
|
7857
7941
|
|
|
7858
7942
|
You delegate; the worker executes. Stay at the **what** level, not the **how**.
|
|
7859
7943
|
|
|
@@ -7894,6 +7978,8 @@ Bad goal (don't do this):
|
|
|
7894
7978
|
|
|
7895
7979
|
Good goal (do this):
|
|
7896
7980
|
> "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."
|
|
7981
|
+
</worker_goal_guidance>
|
|
7982
|
+
</orchestrator_mode>
|
|
7897
7983
|
`;
|
|
7898
7984
|
}
|
|
7899
7985
|
function createSummaryPrompt(conversationHistory) {
|
|
@@ -10695,9 +10781,9 @@ ${buildOrchestratorPromptAddendum()}`;
|
|
|
10695
10781
|
if (personality && personality.trim()) {
|
|
10696
10782
|
systemPrompt = `${systemPrompt}
|
|
10697
10783
|
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10784
|
+
<personality>
|
|
10785
|
+
${personality.trim()}
|
|
10786
|
+
</personality>`;
|
|
10701
10787
|
}
|
|
10702
10788
|
}
|
|
10703
10789
|
const messages = await this.context.getMessages();
|
|
@@ -11676,13 +11762,20 @@ async function ensureOrchestratorSession(opts = {}) {
|
|
|
11676
11762
|
try {
|
|
11677
11763
|
const all = await sessionQueries.list(500, 0);
|
|
11678
11764
|
const existing = all.find((s) => s.config?.role === "orchestrator");
|
|
11679
|
-
if (existing)
|
|
11765
|
+
if (existing) {
|
|
11766
|
+
if (existing.config?.toolApprovals?.["*"] !== false) {
|
|
11767
|
+
await sessionQueries.update(existing.id, {
|
|
11768
|
+
config: autoApproveAllTools(existing.config ?? { role: "orchestrator" })
|
|
11769
|
+
});
|
|
11770
|
+
}
|
|
11771
|
+
return existing.id;
|
|
11772
|
+
}
|
|
11680
11773
|
const cfg = getConfig();
|
|
11681
11774
|
const created = await sessionQueries.create({
|
|
11682
11775
|
name: "Orchestrator",
|
|
11683
11776
|
workingDirectory: cfg.resolvedWorkingDirectory,
|
|
11684
11777
|
model: cfg.defaultModel,
|
|
11685
|
-
config: { role: "orchestrator" }
|
|
11778
|
+
config: autoApproveAllTools({ role: "orchestrator" })
|
|
11686
11779
|
});
|
|
11687
11780
|
if (!opts.quiet) {
|
|
11688
11781
|
console.log(`[orchestrator] auto-created session ${created.id}`);
|
|
@@ -12175,11 +12268,14 @@ sessions2.post(
|
|
|
12175
12268
|
const body = c.req.valid("json");
|
|
12176
12269
|
const config = getConfig();
|
|
12177
12270
|
const baseConfig = body.config || {};
|
|
12178
|
-
|
|
12271
|
+
let mergedConfig = {
|
|
12179
12272
|
...baseConfig,
|
|
12180
12273
|
...body.toolApprovals ? { toolApprovals: body.toolApprovals } : {},
|
|
12181
12274
|
...body.role ? { role: body.role } : {}
|
|
12182
12275
|
};
|
|
12276
|
+
if (mergedConfig.role === "orchestrator") {
|
|
12277
|
+
mergedConfig = autoApproveAllTools(mergedConfig);
|
|
12278
|
+
}
|
|
12183
12279
|
const agent = await Agent.create({
|
|
12184
12280
|
name: body.name,
|
|
12185
12281
|
workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
|
|
@@ -14907,10 +15003,11 @@ tasks.post(
|
|
|
14907
15003
|
workingDirectory: body.workingDirectory || parentSession.workingDirectory,
|
|
14908
15004
|
model: body.model || parentSession.model,
|
|
14909
15005
|
sessionConfig: {
|
|
14910
|
-
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
15006
|
+
...autoApproveAllTools({
|
|
15007
|
+
task: taskConfig,
|
|
15008
|
+
role: "worker",
|
|
15009
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
15010
|
+
})
|
|
14914
15011
|
}
|
|
14915
15012
|
});
|
|
14916
15013
|
const parentMessages = await messageQueries.getBySession(body.parentTaskId);
|
|
@@ -14925,10 +15022,11 @@ tasks.post(
|
|
|
14925
15022
|
workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
|
|
14926
15023
|
model: body.model || config.defaultModel,
|
|
14927
15024
|
sessionConfig: {
|
|
14928
|
-
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
|
|
15025
|
+
...autoApproveAllTools({
|
|
15026
|
+
task: taskConfig,
|
|
15027
|
+
role: "worker",
|
|
15028
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
15029
|
+
})
|
|
14932
15030
|
}
|
|
14933
15031
|
});
|
|
14934
15032
|
}
|
|
@@ -14975,10 +15073,11 @@ tasks.post(
|
|
|
14975
15073
|
error: errorMsg
|
|
14976
15074
|
};
|
|
14977
15075
|
await sessionQueries.update(taskId, {
|
|
14978
|
-
config: {
|
|
14979
|
-
|
|
14980
|
-
|
|
14981
|
-
|
|
15076
|
+
config: autoApproveAllTools({
|
|
15077
|
+
task: failedTask,
|
|
15078
|
+
role: "worker",
|
|
15079
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
15080
|
+
})
|
|
14982
15081
|
});
|
|
14983
15082
|
if (taskConfig.webhookUrl) {
|
|
14984
15083
|
const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook2(), webhook_exports));
|
|
@@ -15272,13 +15371,13 @@ async function findOrCreateOrchestratorId() {
|
|
|
15272
15371
|
const all = await sessionQueries.list(500, 0);
|
|
15273
15372
|
const existing = all.find((s) => s.config?.role === "orchestrator");
|
|
15274
15373
|
if (existing) return existing.id;
|
|
15275
|
-
const { getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
15374
|
+
const { autoApproveAllTools: autoApproveAllTools2, getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
15276
15375
|
const cfg = getConfig2();
|
|
15277
15376
|
const created = await sessionQueries.create({
|
|
15278
15377
|
name: getDefaultOrchestratorName() || "Orchestrator",
|
|
15279
15378
|
workingDirectory: cfg.resolvedWorkingDirectory,
|
|
15280
15379
|
model: cfg.defaultModel,
|
|
15281
|
-
config: { role: "orchestrator" }
|
|
15380
|
+
config: autoApproveAllTools2({ role: "orchestrator" })
|
|
15282
15381
|
});
|
|
15283
15382
|
return created.id;
|
|
15284
15383
|
} catch (err) {
|