sparkecoder 0.1.123 → 0.1.125
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.d.ts +3 -3
- package/dist/agent/index.js +145 -71
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +265 -131
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/{index-Bcz0aCAR.d.ts → index-DczYH89U.d.ts} +104 -104
- package/dist/index.d.ts +5 -5
- package/dist/index.js +188 -89
- package/dist/index.js.map +1 -1
- package/dist/{schema-BWbWmfDQ.d.ts → schema-DxrKyetI.d.ts} +3 -3
- package/dist/{search-DOzC4ojH.d.ts → search-CVVfuBPZ.d.ts} +4 -4
- 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/recording.md +2 -2
- package/dist/skills/default/skill-authoring.md +96 -0
- package/dist/tools/index.d.ts +3 -3
- 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/recording.md +2 -2
- 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/(main)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
- 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 +3 -3
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +2 -2
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
- 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/chunks/ssr/{2374f_c87abaf4._.js → 2374f_12d55e68._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_1f3f2d00._.js → 2374f_1c0639c2._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_a0d5caeb._.js → 2374f_28cd6777._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_570c34dc._.js → 2374f_5f47a9b7._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_d8122230._.js → 2374f_aa218457._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_9c560f3a._.js → 2374f_f678a96f._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_38945fd9._.js → 2374f_fac4000d._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__4de426bd._.js → [root-of-the-server]__e5911ea8._.js} +4 -4
- package/web/.next/standalone/web/.next/server/chunks/ssr/{web_62ca4286._.js → web_2966b3a3._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_4fe3c244._.js +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/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
- package/web/.next/standalone/web/.next/static/chunks/780c93257fac7d43.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
- package/web/.next/standalone/web/.next/static/static/chunks/780c93257fac7d43.js +1 -0
- package/web/.next/standalone/web/src/components/chat-interface.tsx +112 -1
- package/web/.next/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
- package/web/.next/static/chunks/780c93257fac7d43.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/f0f19357f3fb7cf8.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/f0f19357f3fb7cf8.js +0 -1
- package/web/.next/static/chunks/f0f19357f3fb7cf8.js +0 -1
- /package/web/.next/standalone/web/.next/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_ssgManifest.js +0 -0
- /package/web/.next/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_buildManifest.js +0 -0
- /package/web/.next/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{MP4p8_EldjbZ69dONoEcM → qtMOCCjmqN22PUb49g4j-}/_ssgManifest.js +0 -0
package/dist/server/index.js
CHANGED
|
@@ -705,7 +705,10 @@ var init_types = __esm({
|
|
|
705
705
|
// not listed here. Values match `process.platform`
|
|
706
706
|
// (darwin, linux, win32, freebsd, ...). If omitted or empty, the skill is
|
|
707
707
|
// available on all platforms.
|
|
708
|
-
platforms: z.array(z.string()).optional().default([])
|
|
708
|
+
platforms: z.array(z.string()).optional().default([]),
|
|
709
|
+
// Optional approximate token budget for always-loaded content. If set,
|
|
710
|
+
// the prompt builder truncates this skill/rule before injecting it.
|
|
711
|
+
contextBudgetTokens: z.number().int().positive().optional()
|
|
709
712
|
});
|
|
710
713
|
TaskConfigSchema = z.object({
|
|
711
714
|
enabled: z.boolean(),
|
|
@@ -944,6 +947,7 @@ __export(config_exports, {
|
|
|
944
947
|
TaskConfigSchema: () => TaskConfigSchema,
|
|
945
948
|
ToolApprovalConfigSchema: () => ToolApprovalConfigSchema,
|
|
946
949
|
VectorGatewayConfigSchema: () => VectorGatewayConfigSchema,
|
|
950
|
+
autoApproveAllTools: () => autoApproveAllTools,
|
|
947
951
|
clearSlackConfig: () => clearSlackConfig,
|
|
948
952
|
createDefaultConfig: () => createDefaultConfig,
|
|
949
953
|
discoverSkillDirectories: () => discoverSkillDirectories,
|
|
@@ -1339,6 +1343,16 @@ function requiresApproval(toolName, sessionConfig) {
|
|
|
1339
1343
|
}
|
|
1340
1344
|
return false;
|
|
1341
1345
|
}
|
|
1346
|
+
function autoApproveAllTools(sessionConfig) {
|
|
1347
|
+
const currentApprovals = sessionConfig.toolApprovals;
|
|
1348
|
+
return {
|
|
1349
|
+
...sessionConfig,
|
|
1350
|
+
toolApprovals: {
|
|
1351
|
+
...currentApprovals ?? {},
|
|
1352
|
+
...AUTO_APPROVE_ALL_TOOLS
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
}
|
|
1342
1356
|
function createDefaultConfig() {
|
|
1343
1357
|
return {
|
|
1344
1358
|
defaultModel: "anthropic/claude-opus-4.7",
|
|
@@ -1569,7 +1583,7 @@ function maskApiKey(key2) {
|
|
|
1569
1583
|
}
|
|
1570
1584
|
return key2.slice(0, 4) + "..." + key2.slice(-4);
|
|
1571
1585
|
}
|
|
1572
|
-
var CONFIG_FILE_NAMES, cachedConfig, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
1586
|
+
var CONFIG_FILE_NAMES, cachedConfig, AUTO_APPROVE_ALL_TOOLS, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
1573
1587
|
var init_config = __esm({
|
|
1574
1588
|
"src/config/index.ts"() {
|
|
1575
1589
|
"use strict";
|
|
@@ -1581,6 +1595,7 @@ var init_config = __esm({
|
|
|
1581
1595
|
".sparkecoder.json"
|
|
1582
1596
|
];
|
|
1583
1597
|
cachedConfig = null;
|
|
1598
|
+
AUTO_APPROVE_ALL_TOOLS = { "*": false };
|
|
1584
1599
|
AUTH_KEY_FILE = "auth-key.json";
|
|
1585
1600
|
API_KEYS_FILE = "api-keys.json";
|
|
1586
1601
|
PROVIDER_ENV_MAP = {
|
|
@@ -4035,6 +4050,8 @@ function parseSkillFrontmatter(content) {
|
|
|
4035
4050
|
data[key2] = true;
|
|
4036
4051
|
} else if (value === "false") {
|
|
4037
4052
|
data[key2] = false;
|
|
4053
|
+
} else if (/^\d+$/.test(value)) {
|
|
4054
|
+
data[key2] = Number(value);
|
|
4038
4055
|
} else {
|
|
4039
4056
|
data[key2] = value;
|
|
4040
4057
|
}
|
|
@@ -4094,7 +4111,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4094
4111
|
loadType,
|
|
4095
4112
|
priority,
|
|
4096
4113
|
sourceDir: directory,
|
|
4097
|
-
platforms: parsed.metadata.platforms
|
|
4114
|
+
platforms: parsed.metadata.platforms,
|
|
4115
|
+
contextBudgetTokens: parsed.metadata.contextBudgetTokens
|
|
4098
4116
|
});
|
|
4099
4117
|
} else {
|
|
4100
4118
|
const name = getSkillNameFromPath(filePath);
|
|
@@ -4108,7 +4126,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4108
4126
|
loadType: forceAlwaysApply ? "always" : defaultLoadType,
|
|
4109
4127
|
priority,
|
|
4110
4128
|
sourceDir: directory,
|
|
4111
|
-
platforms: []
|
|
4129
|
+
platforms: [],
|
|
4130
|
+
contextBudgetTokens: void 0
|
|
4112
4131
|
});
|
|
4113
4132
|
}
|
|
4114
4133
|
}
|
|
@@ -4238,11 +4257,12 @@ function formatSkillsForContext(skills2) {
|
|
|
4238
4257
|
if (onDemandSkills.length === 0) {
|
|
4239
4258
|
return "No on-demand skills available.";
|
|
4240
4259
|
}
|
|
4241
|
-
const lines = ["
|
|
4260
|
+
const lines = ["<available_skills>", "Use the load_skill tool to load one of these into context:"];
|
|
4242
4261
|
for (const skill of onDemandSkills) {
|
|
4243
4262
|
const globInfo = skill.globs?.length ? ` [auto-loads for: ${skill.globs.join(", ")}]` : "";
|
|
4244
4263
|
lines.push(`- ${skill.name}: ${skill.description}${globInfo}`);
|
|
4245
4264
|
}
|
|
4265
|
+
lines.push("</available_skills>");
|
|
4246
4266
|
return lines.join("\n");
|
|
4247
4267
|
}
|
|
4248
4268
|
function formatAlwaysLoadedSkills(skills2) {
|
|
@@ -4251,13 +4271,22 @@ function formatAlwaysLoadedSkills(skills2) {
|
|
|
4251
4271
|
}
|
|
4252
4272
|
const sections = [];
|
|
4253
4273
|
for (const skill of skills2) {
|
|
4254
|
-
sections.push(
|
|
4255
|
-
|
|
4256
|
-
|
|
4274
|
+
sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
|
|
4275
|
+
${truncateSkillContent(skill)}
|
|
4276
|
+
</skill>`);
|
|
4257
4277
|
}
|
|
4258
|
-
return
|
|
4278
|
+
return `<always_loaded_rules_and_skills>
|
|
4279
|
+
${sections.join("\n\n")}
|
|
4280
|
+
</always_loaded_rules_and_skills>`;
|
|
4281
|
+
}
|
|
4282
|
+
function truncateSkillContent(skill) {
|
|
4283
|
+
if (!skill.contextBudgetTokens) return skill.content;
|
|
4284
|
+
const maxChars = Math.max(200, skill.contextBudgetTokens * 4);
|
|
4285
|
+
if (skill.content.length <= maxChars) return skill.content;
|
|
4286
|
+
const omitted = skill.content.length - maxChars;
|
|
4287
|
+
return `${skill.content.slice(0, maxChars).trimEnd()}
|
|
4259
4288
|
|
|
4260
|
-
${
|
|
4289
|
+
... [${skill.name} truncated by contextBudgetTokens=${skill.contextBudgetTokens}; ${omitted} chars omitted. Read ${skill.filePath} for the full file.]`;
|
|
4261
4290
|
}
|
|
4262
4291
|
function formatGlobMatchedSkills(skills2) {
|
|
4263
4292
|
if (skills2.length === 0) {
|
|
@@ -4265,21 +4294,24 @@ function formatGlobMatchedSkills(skills2) {
|
|
|
4265
4294
|
}
|
|
4266
4295
|
const sections = [];
|
|
4267
4296
|
for (const skill of skills2) {
|
|
4268
|
-
sections.push(
|
|
4269
|
-
|
|
4270
|
-
|
|
4297
|
+
sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
|
|
4298
|
+
${skill.content}
|
|
4299
|
+
</skill>`);
|
|
4271
4300
|
}
|
|
4272
|
-
return
|
|
4273
|
-
|
|
4274
|
-
|
|
4301
|
+
return `<glob_matched_skills>
|
|
4302
|
+
${sections.join("\n\n")}
|
|
4303
|
+
</glob_matched_skills>`;
|
|
4275
4304
|
}
|
|
4276
4305
|
function formatAgentsMdContent(content) {
|
|
4277
4306
|
if (!content) {
|
|
4278
4307
|
return "";
|
|
4279
4308
|
}
|
|
4280
|
-
return
|
|
4281
|
-
|
|
4282
|
-
|
|
4309
|
+
return `<project_instructions source="AGENTS.md">
|
|
4310
|
+
${content}
|
|
4311
|
+
</project_instructions>`;
|
|
4312
|
+
}
|
|
4313
|
+
function escapeXmlAttribute(value) {
|
|
4314
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
4283
4315
|
}
|
|
4284
4316
|
var init_skills = __esm({
|
|
4285
4317
|
"src/skills/index.ts"() {
|
|
@@ -6544,14 +6576,18 @@ async function buildSystemPrompt(options) {
|
|
|
6544
6576
|
const platform3 = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
|
|
6545
6577
|
const currentDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" });
|
|
6546
6578
|
const searchInstructions = getSearchInstructions();
|
|
6547
|
-
const systemPrompt =
|
|
6579
|
+
const systemPrompt = `<system_prompt>
|
|
6580
|
+
<identity>
|
|
6581
|
+
You are SparkECoder, an expert AI coding assistant. You help developers write, debug, and improve code.
|
|
6582
|
+
</identity>
|
|
6548
6583
|
|
|
6549
|
-
|
|
6584
|
+
<environment>
|
|
6550
6585
|
- **Platform**: ${platform3} (${os.release()})
|
|
6551
6586
|
- **Date**: ${currentDate}
|
|
6552
6587
|
- **Working Directory**: ${workingDirectory}
|
|
6588
|
+
</environment>
|
|
6553
6589
|
|
|
6554
|
-
|
|
6590
|
+
<core_capabilities>
|
|
6555
6591
|
You have access to powerful tools for:
|
|
6556
6592
|
- **bash**: Execute commands in the terminal (see below for details)
|
|
6557
6593
|
- **read_file**: Read file contents to understand code and context
|
|
@@ -6565,8 +6601,9 @@ You have access to powerful tools for:
|
|
|
6565
6601
|
|
|
6566
6602
|
|
|
6567
6603
|
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.
|
|
6604
|
+
</core_capabilities>
|
|
6568
6605
|
|
|
6569
|
-
|
|
6606
|
+
<planning_and_task_management>
|
|
6570
6607
|
Use the **todo tool** to manage both immediate tasks AND persistent plans:
|
|
6571
6608
|
|
|
6572
6609
|
**For simple tasks (< 5 steps):** Just use regular todos (add/mark/clear).
|
|
@@ -6586,8 +6623,9 @@ Use the **todo tool** to manage both immediate tasks AND persistent plans:
|
|
|
6586
6623
|
- Only top-level checklist items (- [ ]) become todos \u2014 indented sub-items are part of the task detail
|
|
6587
6624
|
- Sections named Overview, Notes, Key Decisions, etc. are not treated as phases
|
|
6588
6625
|
- You can clear the todo list and restart it, and do multiple things inside of one session
|
|
6626
|
+
</planning_and_task_management>
|
|
6589
6627
|
|
|
6590
|
-
|
|
6628
|
+
<bash_tool>
|
|
6591
6629
|
The bash tool runs commands in the terminal. Every command runs in its own session with logs saved to disk.
|
|
6592
6630
|
|
|
6593
6631
|
**Run a command (default - waits for completion):**
|
|
@@ -6634,22 +6672,25 @@ bash({ id: "abc123", input: "my text" }) // send text input
|
|
|
6634
6672
|
- Use \`input: "text"\` for text input prompts
|
|
6635
6673
|
|
|
6636
6674
|
Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.
|
|
6675
|
+
</bash_tool>
|
|
6637
6676
|
|
|
6638
|
-
|
|
6677
|
+
<guidelines>
|
|
6639
6678
|
|
|
6640
|
-
|
|
6679
|
+
<code_quality>
|
|
6641
6680
|
- Write clean, maintainable, well-documented code
|
|
6642
6681
|
- Follow existing code style and conventions in the project
|
|
6643
6682
|
- Use meaningful variable and function names
|
|
6644
6683
|
- Add comments for complex logic
|
|
6684
|
+
</code_quality>
|
|
6645
6685
|
|
|
6646
|
-
|
|
6686
|
+
<problem_solving>
|
|
6647
6687
|
- Before making changes, understand the existing code structure
|
|
6648
6688
|
- Break complex tasks into smaller, manageable steps using the todo tool
|
|
6649
6689
|
- Test changes when possible using the bash tool
|
|
6650
6690
|
- Handle errors gracefully and provide helpful error messages
|
|
6691
|
+
</problem_solving>
|
|
6651
6692
|
|
|
6652
|
-
|
|
6693
|
+
<file_operations>
|
|
6653
6694
|
- Use \`read_file\` to understand code before modifying
|
|
6654
6695
|
- Use \`write_file\` with mode "str_replace" for targeted edits to existing files
|
|
6655
6696
|
- Use \`write_file\` with mode "full" only for new files or complete rewrites
|
|
@@ -6658,8 +6699,9 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
6658
6699
|
- If the user asks to write/create a file, always use \`write_file\` rather than printing the full contents
|
|
6659
6700
|
- If the user requests a file but does not provide a path, choose a sensible default (e.g. \`index.html\`) and proceed
|
|
6660
6701
|
- For large content (hundreds of lines), avoid placing it in chat output; write to a file instead
|
|
6702
|
+
</file_operations>
|
|
6661
6703
|
|
|
6662
|
-
|
|
6704
|
+
<linter_tool>
|
|
6663
6705
|
The linter tool uses Language Server Protocol (LSP) to detect type errors and lint issues:
|
|
6664
6706
|
\`\`\`
|
|
6665
6707
|
linter({}) // Check all recently edited files
|
|
@@ -6667,8 +6709,9 @@ linter({ paths: ["src/app.ts"] }) // Check specific files
|
|
|
6667
6709
|
linter({ paths: ["src/"] }) // Check all files in a directory
|
|
6668
6710
|
\`\`\`
|
|
6669
6711
|
Use this proactively after making code changes to catch errors early.
|
|
6712
|
+
</linter_tool>
|
|
6670
6713
|
|
|
6671
|
-
|
|
6714
|
+
<code_graph_tool>
|
|
6672
6715
|
The code_graph tool uses the TypeScript language server to inspect a symbol's type hierarchy and usage graph:
|
|
6673
6716
|
\`\`\`
|
|
6674
6717
|
code_graph({ symbol: "UserCard" }) // Search workspace for symbol
|
|
@@ -6694,8 +6737,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
|
|
|
6694
6737
|
- For exploratory "how does X work?" questions \u2014 use \`explore_agent\` instead
|
|
6695
6738
|
- For exact string searches \u2014 use grep/rg directly
|
|
6696
6739
|
- For non-TypeScript/JavaScript files \u2014 code_graph only supports TS/JS/TSX/JSX
|
|
6740
|
+
</code_graph_tool>
|
|
6697
6741
|
|
|
6698
|
-
|
|
6742
|
+
<searching_and_exploration>
|
|
6699
6743
|
|
|
6700
6744
|
**Choose the right search approach:**
|
|
6701
6745
|
|
|
@@ -6746,8 +6790,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
|
|
|
6746
6790
|
- "Find files named config" \u2192 Use \`find . -name "*config*"\`
|
|
6747
6791
|
|
|
6748
6792
|
${searchInstructions}
|
|
6793
|
+
</searching_and_exploration>
|
|
6749
6794
|
|
|
6750
|
-
|
|
6795
|
+
<software_design_principles>
|
|
6751
6796
|
|
|
6752
6797
|
1. **Modularity** \u2014 Write simple parts connected by clean interfaces
|
|
6753
6798
|
2. **Clarity** \u2014 Clarity is better than cleverness
|
|
@@ -6766,8 +6811,9 @@ ${searchInstructions}
|
|
|
6766
6811
|
15. **Optimization** \u2014 Prototype before polishing. Get it working before you optimize it
|
|
6767
6812
|
16. **Diversity** \u2014 Distrust all claims for "one true way"
|
|
6768
6813
|
17. **Extensibility** \u2014 Design for the future, because it will be here sooner than you think
|
|
6814
|
+
</software_design_principles>
|
|
6769
6815
|
|
|
6770
|
-
|
|
6816
|
+
<ui_design_principles>
|
|
6771
6817
|
|
|
6772
6818
|
1. **Simplicity** \u2014 Simplicity is the ultimate sophistication. Remove everything unnecessary.
|
|
6773
6819
|
2. **Focus** \u2014 Say no to 1,000 things to say yes to the few that matter most.
|
|
@@ -6779,8 +6825,9 @@ ${searchInstructions}
|
|
|
6779
6825
|
8. **Feedback** \u2014 Every action deserves a response. Make interactions feel alive.
|
|
6780
6826
|
9. **Forgiveness** \u2014 Make it easy to undo. Never punish exploration.
|
|
6781
6827
|
10. **Beauty** \u2014 Aesthetics are not superficial. Beautiful things work better because people care about them.
|
|
6828
|
+
</ui_design_principles>
|
|
6782
6829
|
|
|
6783
|
-
|
|
6830
|
+
<agent_behavior_rules>
|
|
6784
6831
|
|
|
6785
6832
|
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.
|
|
6786
6833
|
2. Plan for complexity - If the task involves 3+ steps or has meaningful trade-offs, create a todo list to track progress before implementing.
|
|
@@ -6789,13 +6836,16 @@ ${searchInstructions}
|
|
|
6789
6836
|
5. Be direct - Focus on technical accuracy rather than validation. If see issues with an approach or need clarification, say so.
|
|
6790
6837
|
6. Verify my work - After making changes, check for linter errors and fix any introduced.
|
|
6791
6838
|
7. Respect boundaries - Only commit code when explicitly asked, avoid creating unnecessary files, and don't make assumptions about things uncertain about.
|
|
6839
|
+
</agent_behavior_rules>
|
|
6792
6840
|
|
|
6793
6841
|
|
|
6794
|
-
|
|
6842
|
+
<communication>
|
|
6795
6843
|
- Explain your reasoning and approach
|
|
6796
6844
|
- Be concise but thorough
|
|
6797
6845
|
- Ask clarifying questions when requirements are ambiguous
|
|
6798
6846
|
- Report progress on multi-step tasks
|
|
6847
|
+
</communication>
|
|
6848
|
+
</guidelines>
|
|
6799
6849
|
|
|
6800
6850
|
${agentsMdContent}
|
|
6801
6851
|
|
|
@@ -6803,18 +6853,24 @@ ${alwaysLoadedContent}
|
|
|
6803
6853
|
|
|
6804
6854
|
${globMatchedContent}
|
|
6805
6855
|
|
|
6806
|
-
|
|
6856
|
+
<on_demand_skills>
|
|
6807
6857
|
${onDemandSkillsContext}
|
|
6858
|
+
</on_demand_skills>
|
|
6808
6859
|
|
|
6809
|
-
|
|
6860
|
+
<current_task_list>
|
|
6810
6861
|
${todosContext}
|
|
6862
|
+
</current_task_list>
|
|
6811
6863
|
|
|
6812
6864
|
${plansContext}
|
|
6813
6865
|
|
|
6814
|
-
${customInstructions ?
|
|
6815
|
-
${customInstructions}
|
|
6866
|
+
${customInstructions ? `<custom_instructions>
|
|
6867
|
+
${customInstructions}
|
|
6868
|
+
</custom_instructions>` : ""}
|
|
6816
6869
|
|
|
6817
|
-
|
|
6870
|
+
<final_reminder>
|
|
6871
|
+
Remember: You are a helpful, capable coding assistant. Take initiative, be thorough, and deliver high-quality results.
|
|
6872
|
+
</final_reminder>
|
|
6873
|
+
</system_prompt>`;
|
|
6818
6874
|
return systemPrompt;
|
|
6819
6875
|
}
|
|
6820
6876
|
function formatTodosForContext(todos) {
|
|
@@ -6838,7 +6894,7 @@ function formatPlansForContext(plans, shouldContinue) {
|
|
|
6838
6894
|
if (plans.length === 0) return "";
|
|
6839
6895
|
let totalChars = 0;
|
|
6840
6896
|
const sections = [];
|
|
6841
|
-
sections.push(
|
|
6897
|
+
sections.push(`<persistent_plans count="${plans.length}">`);
|
|
6842
6898
|
sections.push("");
|
|
6843
6899
|
sections.push("These plans persist across context compaction \u2014 they are always available.");
|
|
6844
6900
|
sections.push("When you finish your current todos, check these plans for the next uncompleted phase,");
|
|
@@ -6859,34 +6915,39 @@ function formatPlansForContext(plans, shouldContinue) {
|
|
|
6859
6915
|
... [plan truncated \u2014 ${content.length - MAX_PLAN_CHARS} chars omitted. Use get_plan to read the full plan.]`;
|
|
6860
6916
|
}
|
|
6861
6917
|
if (totalChars + content.length > MAX_TOTAL_PLANS_CHARS) {
|
|
6862
|
-
sections.push(
|
|
6918
|
+
sections.push(`<plan name="${plan.name}" truncated="true">Use get_plan("${plan.name}") to read.</plan>`);
|
|
6863
6919
|
continue;
|
|
6864
6920
|
}
|
|
6865
|
-
sections.push(
|
|
6866
|
-
sections.push("");
|
|
6921
|
+
sections.push(`<plan name="${plan.name}">`);
|
|
6867
6922
|
sections.push(content);
|
|
6868
|
-
sections.push("");
|
|
6923
|
+
sections.push("</plan>");
|
|
6869
6924
|
totalChars += content.length;
|
|
6870
6925
|
}
|
|
6926
|
+
sections.push("</persistent_plans>");
|
|
6871
6927
|
return sections.join("\n");
|
|
6872
6928
|
}
|
|
6873
6929
|
function buildTaskPromptAddendum(outputSchema) {
|
|
6874
6930
|
return `
|
|
6875
|
-
|
|
6931
|
+
<task_mode>
|
|
6876
6932
|
|
|
6877
6933
|
You are running in **task mode**. You have been given a specific task to complete autonomously.
|
|
6878
6934
|
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.
|
|
6879
6935
|
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.
|
|
6880
6936
|
|
|
6881
|
-
|
|
6937
|
+
<rules>
|
|
6882
6938
|
1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
|
|
6883
6939
|
2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
|
|
6884
6940
|
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.
|
|
6885
6941
|
4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
|
|
6886
6942
|
5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
|
|
6887
6943
|
6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
|
|
6944
|
+
</rules>
|
|
6945
|
+
|
|
6946
|
+
<memory_guidance>
|
|
6947
|
+
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.
|
|
6948
|
+
</memory_guidance>
|
|
6888
6949
|
|
|
6889
|
-
|
|
6950
|
+
<verification>
|
|
6890
6951
|
Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
|
|
6891
6952
|
|
|
6892
6953
|
**After making code changes:**
|
|
@@ -6937,35 +6998,40 @@ Before calling \`complete_task\`, you MUST verify your work completely. Do not j
|
|
|
6937
6998
|
\`\`\`
|
|
6938
6999
|
- In task results, NEVER return local filesystem paths for screenshots/reports. Return only the \`downloadUrl\` from \`upload_file\`.
|
|
6939
7000
|
- This is especially valuable for UI/visual changes, successful test runs, and browser verification \u2014 show, don't just tell.
|
|
7001
|
+
</verification>
|
|
6940
7002
|
|
|
6941
|
-
|
|
7003
|
+
<use_all_available_tools>
|
|
6942
7004
|
- **load_skill**: Load specialized skills/knowledge relevant to the task. Check what skills are available and use them.
|
|
6943
7005
|
- **explore_agent**: Use for codebase exploration and understanding before making changes.
|
|
6944
7006
|
- **code_graph**: Use to understand type hierarchies, references, and impact before refactoring.
|
|
6945
7007
|
- **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.
|
|
6946
7008
|
- **bash**: Full shell access \u2014 run builds, tests, dev servers, open browsers, curl endpoints, anything.
|
|
6947
7009
|
- **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.
|
|
7010
|
+
</use_all_available_tools>
|
|
6948
7011
|
|
|
6949
|
-
|
|
7012
|
+
<output_schema>
|
|
6950
7013
|
The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
|
|
6951
7014
|
\`\`\`json
|
|
6952
7015
|
${JSON.stringify(outputSchema, null, 2)}
|
|
6953
7016
|
\`\`\`
|
|
7017
|
+
</output_schema>
|
|
6954
7018
|
|
|
6955
|
-
|
|
7019
|
+
<completion_tools>
|
|
6956
7020
|
- **\`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.
|
|
6957
7021
|
- **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
|
|
6958
7022
|
- **\`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.
|
|
7023
|
+
</completion_tools>
|
|
7024
|
+
</task_mode>
|
|
6959
7025
|
`;
|
|
6960
7026
|
}
|
|
6961
7027
|
function buildOrchestratorPromptAddendum() {
|
|
6962
7028
|
const desktopAvailable = process.platform === "darwin";
|
|
6963
7029
|
return `
|
|
6964
|
-
|
|
7030
|
+
<orchestrator_mode>
|
|
6965
7031
|
|
|
6966
|
-
You are the **orchestrator agent**. You triage everything that comes in, spawn worker agents to do
|
|
7032
|
+
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.
|
|
6967
7033
|
|
|
6968
|
-
|
|
7034
|
+
<channels>
|
|
6969
7035
|
|
|
6970
7036
|
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.
|
|
6971
7037
|
|
|
@@ -6981,23 +7047,28 @@ Pill formats:
|
|
|
6981
7047
|
- \`[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})\`.
|
|
6982
7048
|
- \`[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.
|
|
6983
7049
|
- \`[WEBHOOK name] ...\` \u2014 an external service hit one of your webhook URLs. Body is the request body (verbatim or per the webhook's template).
|
|
7050
|
+
</channels>
|
|
6984
7051
|
|
|
6985
|
-
|
|
7052
|
+
<delivery_failures>
|
|
6986
7053
|
|
|
6987
7054
|
If \`messenger({action:'post', ...})\` returns \`{ok:false, error:'...'}\` (e.g. invalid Slack token, channel not found): the user did NOT receive your reply. Try:
|
|
6988
7055
|
1. Re-checking the destination (channel id, thread ts).
|
|
6989
7056
|
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).
|
|
6990
7057
|
3. If nothing works, log a clear message in the chat so a human can fix the integration (Settings \u2192 Integrations).
|
|
6991
7058
|
**Never silently swallow a delivery failure.**
|
|
7059
|
+
</delivery_failures>
|
|
6992
7060
|
|
|
6993
|
-
|
|
7061
|
+
<hard_rules>
|
|
6994
7062
|
|
|
6995
|
-
-
|
|
7063
|
+
- Avoid direct workspace work. Do not directly edit product code, run builds, or perform substantive implementation yourself; spawn workers for that.
|
|
7064
|
+
- 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.
|
|
7065
|
+
- Prefer workers for implementation, long-running verification, and independent sub-tasks so work can run in parallel and report back cleanly.
|
|
6996
7066
|
- Give workers **clear, self-contained goals**. Include any context they'd otherwise have to ask you about.
|
|
6997
7067
|
- Prefer \`agent({action:'message'})\` (queued) over \`agent({action:'stop'})\` for course corrections.
|
|
6998
7068
|
- Don't poll. Worker completions wake you automatically via SYSTEM events.
|
|
7069
|
+
</hard_rules>
|
|
6999
7070
|
|
|
7000
|
-
|
|
7071
|
+
<tools>
|
|
7001
7072
|
|
|
7002
7073
|
\`\`\`
|
|
7003
7074
|
agent({action: 'list' | 'get' | 'spawn' | 'message' | 'answer_question' | 'stop', ...})
|
|
@@ -7007,17 +7078,21 @@ webhook({action: 'create' | 'list' | 'update' | 'delete', ...})
|
|
|
7007
7078
|
\`\`\`
|
|
7008
7079
|
|
|
7009
7080
|
You ALSO have the regular agent toolset (\`bash\`, \`read_file\`, \`write_file\`, \`load_skill\`, \`linter\`, \`explore_agent\`, \`code_graph\`, etc.) for low-level work.
|
|
7081
|
+
</tools>
|
|
7010
7082
|
|
|
7011
|
-
|
|
7083
|
+
<self_extension>
|
|
7012
7084
|
|
|
7013
7085
|
You manage your own configuration by editing files. Load the relevant skill first to get the file path and schema:
|
|
7014
7086
|
|
|
7015
7087
|
- **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.
|
|
7088
|
+
- **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.
|
|
7089
|
+
- **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/\`.
|
|
7016
7090
|
- **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.
|
|
7017
7091
|
|
|
7018
|
-
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.
|
|
7092
|
+
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.
|
|
7093
|
+
</self_extension>
|
|
7019
7094
|
|
|
7020
|
-
|
|
7095
|
+
<common_shapes>
|
|
7021
7096
|
- Spawn a worker:
|
|
7022
7097
|
\`agent({action:'spawn', name:'count-tests', goal:'Run X and report Y as summary', outputSchema?: { type:'object', properties:{...}, required:[...] }})\`
|
|
7023
7098
|
- Answer a worker's question:
|
|
@@ -7028,15 +7103,17 @@ If the user asks "add the GitHub MCP" or "remember that I prefer Python", load t
|
|
|
7028
7103
|
\`schedule({action:'create', name:'standup-9am', cron:'0 9 * * 1-5', prompt:'Summarize yesterday\\'s git activity in this repo'})\`
|
|
7029
7104
|
- Create a webhook:
|
|
7030
7105
|
\`webhook({action:'create', name:'github-prs', wake:'now'})\` \u2014 returns the URL.
|
|
7106
|
+
</common_shapes>
|
|
7031
7107
|
|
|
7032
|
-
|
|
7108
|
+
<typical_flow>
|
|
7033
7109
|
|
|
7034
7110
|
1. Inbound event arrives (any channel).
|
|
7035
7111
|
2. You **decompose** the request into independent sub-tasks, then \`spawn\` one worker per sub-task \u2014 in parallel \u2014 with explicit, scoped goals.
|
|
7036
7112
|
3. Workers run autonomously. They wake you via SYSTEM events when done / failed / blocked.
|
|
7037
7113
|
4. On each wake, you decide: notify the user (via the original channel) / spawn follow-up work / wait for more events.
|
|
7114
|
+
</typical_flow>
|
|
7038
7115
|
|
|
7039
|
-
|
|
7116
|
+
<decomposition_rule>
|
|
7040
7117
|
|
|
7041
7118
|
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:
|
|
7042
7119
|
|
|
@@ -7052,18 +7129,22 @@ When NOT to split (keep as one worker):
|
|
|
7052
7129
|
- The asks share state (one's output feeds the other).
|
|
7053
7130
|
- The asks are tightly coupled (e.g. *"refactor X and run its tests"* \u2014 the tests depend on the refactor).
|
|
7054
7131
|
- The asks are trivially small (one or two tool calls each); spawning overhead exceeds the parallelism win.
|
|
7132
|
+
</decomposition_rule>
|
|
7055
7133
|
|
|
7056
|
-
|
|
7134
|
+
<prefer_headless_tools>
|
|
7057
7135
|
|
|
7058
7136
|
When spawning a worker, push it toward the *cheapest tool that gets the job done*:
|
|
7059
7137
|
|
|
7060
7138
|
1. **Bash / file tools** for anything with a CLI (git, npm, brew, builds, tests, file editing, HTTP via curl, scripting).
|
|
7061
|
-
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
|
|
7139
|
+
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.
|
|
7140
|
+
</prefer_headless_tools>${desktopAvailable ? `
|
|
7141
|
+
|
|
7142
|
+
<desktop_automation_guidance>
|
|
7062
7143
|
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.
|
|
7063
7144
|
|
|
7064
7145
|
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."*
|
|
7065
7146
|
|
|
7066
|
-
|
|
7147
|
+
<serialize_desktop_automation_tasks>
|
|
7067
7148
|
|
|
7068
7149
|
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.
|
|
7069
7150
|
|
|
@@ -7086,11 +7167,13 @@ Example: *"Take a screenshot of Calculator AND run the test suite AND open Syste
|
|
|
7086
7167
|
|
|
7087
7168
|
Headless workers never interfere with desktop workers (they don't touch the screen), so they always run in parallel.
|
|
7088
7169
|
|
|
7089
|
-
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
|
|
7170
|
+
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.
|
|
7171
|
+
</serialize_desktop_automation_tasks>
|
|
7172
|
+
</desktop_automation_guidance>` : ""}
|
|
7090
7173
|
|
|
7091
7174
|
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.
|
|
7092
7175
|
|
|
7093
|
-
|
|
7176
|
+
<user_communication>
|
|
7094
7177
|
|
|
7095
7178
|
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.
|
|
7096
7179
|
|
|
@@ -7109,8 +7192,9 @@ When replying to the user (Slack, web, or any channel), be a normal helpful assi
|
|
|
7109
7192
|
| *"I'll relay the user's instructions to the worker verbatim."* | *(say nothing \u2014 just do it)* |
|
|
7110
7193
|
|
|
7111
7194
|
If the user explicitly asks how you work, *then* you can explain the orchestrator/worker split. Otherwise: less is more.
|
|
7195
|
+
</user_communication>
|
|
7112
7196
|
|
|
7113
|
-
|
|
7197
|
+
<worker_goal_guidance>
|
|
7114
7198
|
|
|
7115
7199
|
You delegate; the worker executes. Stay at the **what** level, not the **how**.
|
|
7116
7200
|
|
|
@@ -7151,6 +7235,8 @@ Bad goal (don't do this):
|
|
|
7151
7235
|
|
|
7152
7236
|
Good goal (do this):
|
|
7153
7237
|
> "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."
|
|
7238
|
+
</worker_goal_guidance>
|
|
7239
|
+
</orchestrator_mode>
|
|
7154
7240
|
`;
|
|
7155
7241
|
}
|
|
7156
7242
|
function createSummaryPrompt(conversationHistory) {
|
|
@@ -9952,9 +10038,9 @@ ${buildOrchestratorPromptAddendum()}`;
|
|
|
9952
10038
|
if (personality && personality.trim()) {
|
|
9953
10039
|
systemPrompt = `${systemPrompt}
|
|
9954
10040
|
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
10041
|
+
<personality>
|
|
10042
|
+
${personality.trim()}
|
|
10043
|
+
</personality>`;
|
|
9958
10044
|
}
|
|
9959
10045
|
}
|
|
9960
10046
|
const messages = await this.context.getMessages();
|
|
@@ -10933,13 +11019,20 @@ async function ensureOrchestratorSession(opts = {}) {
|
|
|
10933
11019
|
try {
|
|
10934
11020
|
const all = await sessionQueries.list(500, 0);
|
|
10935
11021
|
const existing = all.find((s) => s.config?.role === "orchestrator");
|
|
10936
|
-
if (existing)
|
|
11022
|
+
if (existing) {
|
|
11023
|
+
if (existing.config?.toolApprovals?.["*"] !== false) {
|
|
11024
|
+
await sessionQueries.update(existing.id, {
|
|
11025
|
+
config: autoApproveAllTools(existing.config ?? { role: "orchestrator" })
|
|
11026
|
+
});
|
|
11027
|
+
}
|
|
11028
|
+
return existing.id;
|
|
11029
|
+
}
|
|
10937
11030
|
const cfg = getConfig();
|
|
10938
11031
|
const created = await sessionQueries.create({
|
|
10939
11032
|
name: "Orchestrator",
|
|
10940
11033
|
workingDirectory: cfg.resolvedWorkingDirectory,
|
|
10941
11034
|
model: cfg.defaultModel,
|
|
10942
|
-
config: { role: "orchestrator" }
|
|
11035
|
+
config: autoApproveAllTools({ role: "orchestrator" })
|
|
10943
11036
|
});
|
|
10944
11037
|
if (!opts.quiet) {
|
|
10945
11038
|
console.log(`[orchestrator] auto-created session ${created.id}`);
|
|
@@ -11204,11 +11297,14 @@ sessions2.post(
|
|
|
11204
11297
|
const body = c.req.valid("json");
|
|
11205
11298
|
const config = getConfig();
|
|
11206
11299
|
const baseConfig = body.config || {};
|
|
11207
|
-
|
|
11300
|
+
let mergedConfig = {
|
|
11208
11301
|
...baseConfig,
|
|
11209
11302
|
...body.toolApprovals ? { toolApprovals: body.toolApprovals } : {},
|
|
11210
11303
|
...body.role ? { role: body.role } : {}
|
|
11211
11304
|
};
|
|
11305
|
+
if (mergedConfig.role === "orchestrator") {
|
|
11306
|
+
mergedConfig = autoApproveAllTools(mergedConfig);
|
|
11307
|
+
}
|
|
11212
11308
|
const agent = await Agent.create({
|
|
11213
11309
|
name: body.name,
|
|
11214
11310
|
workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
|
|
@@ -13936,10 +14032,11 @@ tasks.post(
|
|
|
13936
14032
|
workingDirectory: body.workingDirectory || parentSession.workingDirectory,
|
|
13937
14033
|
model: body.model || parentSession.model,
|
|
13938
14034
|
sessionConfig: {
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
14035
|
+
...autoApproveAllTools({
|
|
14036
|
+
task: taskConfig,
|
|
14037
|
+
role: "worker",
|
|
14038
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
14039
|
+
})
|
|
13943
14040
|
}
|
|
13944
14041
|
});
|
|
13945
14042
|
const parentMessages = await messageQueries.getBySession(body.parentTaskId);
|
|
@@ -13954,10 +14051,11 @@ tasks.post(
|
|
|
13954
14051
|
workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
|
|
13955
14052
|
model: body.model || config.defaultModel,
|
|
13956
14053
|
sessionConfig: {
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
|
|
14054
|
+
...autoApproveAllTools({
|
|
14055
|
+
task: taskConfig,
|
|
14056
|
+
role: "worker",
|
|
14057
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
14058
|
+
})
|
|
13961
14059
|
}
|
|
13962
14060
|
});
|
|
13963
14061
|
}
|
|
@@ -14004,10 +14102,11 @@ tasks.post(
|
|
|
14004
14102
|
error: errorMsg
|
|
14005
14103
|
};
|
|
14006
14104
|
await sessionQueries.update(taskId, {
|
|
14007
|
-
config: {
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
|
|
14105
|
+
config: autoApproveAllTools({
|
|
14106
|
+
task: failedTask,
|
|
14107
|
+
role: "worker",
|
|
14108
|
+
...body.orchestratorSessionId ? { orchestratorSessionId: body.orchestratorSessionId } : {}
|
|
14109
|
+
})
|
|
14011
14110
|
});
|
|
14012
14111
|
if (taskConfig.webhookUrl) {
|
|
14013
14112
|
const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook2(), webhook_exports));
|
|
@@ -14301,13 +14400,13 @@ async function findOrCreateOrchestratorId() {
|
|
|
14301
14400
|
const all = await sessionQueries.list(500, 0);
|
|
14302
14401
|
const existing = all.find((s) => s.config?.role === "orchestrator");
|
|
14303
14402
|
if (existing) return existing.id;
|
|
14304
|
-
const { getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
14403
|
+
const { autoApproveAllTools: autoApproveAllTools2, getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
14305
14404
|
const cfg = getConfig2();
|
|
14306
14405
|
const created = await sessionQueries.create({
|
|
14307
14406
|
name: getDefaultOrchestratorName() || "Orchestrator",
|
|
14308
14407
|
workingDirectory: cfg.resolvedWorkingDirectory,
|
|
14309
14408
|
model: cfg.defaultModel,
|
|
14310
|
-
config: { role: "orchestrator" }
|
|
14409
|
+
config: autoApproveAllTools2({ role: "orchestrator" })
|
|
14311
14410
|
});
|
|
14312
14411
|
return created.id;
|
|
14313
14412
|
} catch (err) {
|