@asm-agent/coding-agent 0.8.5 → 0.8.7
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/CHANGELOG.md +8 -0
- package/dist/bundle/{anthropic-BS3XM5BT.js → anthropic-XSMQHGYB.js} +1 -1
- package/dist/bundle/{azure-openai-responses-IENK6KME.js → azure-openai-responses-XLQAIKKH.js} +2 -2
- package/dist/bundle/{bundled-modules-VBE3REQM.js → bundled-modules-5OCN73BM.js} +4 -4
- package/dist/bundle/{chunk-D55J7N6R.js → chunk-2LPSALBF.js} +377 -299
- package/dist/bundle/{chunk-J6ATXG62.js → chunk-CMMSLBAW.js} +12 -8
- package/dist/bundle/{chunk-D5ZUG2IX.js → chunk-E3YE2Q7A.js} +66 -3
- package/dist/bundle/{chunk-KC3DQ3DI.js → chunk-IAQLPSMN.js} +609 -222
- package/dist/bundle/{chunk-G73LOLKD.js → chunk-YPNK4MRU.js} +1 -1
- package/dist/bundle/{cli-main-JCK7QTSE.js → cli-main-QYX5R3LF.js} +4 -4
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/{compile-UQNZ2TRI.js → compile-BYYUFOG3.js} +1 -1
- package/dist/bundle/{google-L6GUE5MM.js → google-ZXJEPWJA.js} +1 -1
- package/dist/bundle/{google-vertex-ALYRXEBH.js → google-vertex-WAF3RIJ6.js} +1 -1
- package/dist/bundle/{main-OA5G7OQN.js → main-EOUAQCJH.js} +4 -4
- package/dist/bundle/{mistral-NTC6RHCF.js → mistral-GDZXSXRS.js} +1 -1
- package/dist/bundle/{openai-codex-responses-FKZNCKA3.js → openai-codex-responses-7XMPW4LG.js} +2 -2
- package/dist/bundle/{openai-completions-LQJM5PDC.js → openai-completions-LNSVGDMF.js} +4 -1
- package/dist/bundle/{openai-responses-AHIOFAPZ.js → openai-responses-MFZOBMIT.js} +2 -2
- package/dist/core/always-applied-skills.d.ts +3 -0
- package/dist/core/always-applied-skills.d.ts.map +1 -0
- package/dist/core/always-applied-skills.js +47 -0
- package/dist/core/always-applied-skills.js.map +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +8 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/ollama-models.d.ts +4 -0
- package/dist/core/ollama-models.d.ts.map +1 -0
- package/dist/core/ollama-models.js +56 -0
- package/dist/core/ollama-models.js.map +1 -0
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +1 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +9 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/skills/final-response-summary/SKILL.md +39 -0
- package/dist/skills/request-report/SKILL.md +65 -0
- package/dist/skills/request-report/pyproject.toml +16 -0
- package/dist/skills/request-report/src/request_report/__init__.py +160 -0
- package/dist/skills/skill-creator/SKILL.md +2 -1
- package/dist/skills/solid-source-modularity/SKILL.md +48 -0
- package/dist/skills/solid-source-modularity/pyproject.toml +16 -0
- package/dist/skills/solid-source-modularity/src/solid_source_modularity/__init__.py +154 -0
- package/docs/models.md +2 -0
- package/docs/skills.md +8 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +5 -5
- package/skills/final-response-summary/SKILL.md +39 -0
- package/skills/request-report/SKILL.md +65 -0
- package/skills/request-report/pyproject.toml +16 -0
- package/skills/request-report/src/request_report/__init__.py +160 -0
- package/skills/skill-creator/SKILL.md +2 -1
- package/skills/solid-source-modularity/SKILL.md +48 -0
- package/skills/solid-source-modularity/pyproject.toml +16 -0
- package/skills/solid-source-modularity/src/solid_source_modularity/__init__.py +154 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama-models.js","sourceRoot":"","sources":["../../src/core/ollama-models.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AACrD,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEzC,MAAM,UAAU,gBAAgB,GAAW;IAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,mBAAmB,CAAC;IAC1E,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3C,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC;AAAA,CAClD;AAED,SAAS,gBAAgB,CAAC,OAAe,EAAU;IAClD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;AAAA,CAClD;AAOD,SAAS,YAAY,CAAC,GAAc,EAAE,OAAe,EAA2C;IAC/F,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IACvE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO;QACN,EAAE,EAAE,IAAI;QACR,IAAI;QACJ,GAAG,EAAE,oBAAoB;QACzB,QAAQ,EAAE,QAAQ;QAClB,OAAO;QACP,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;QAC1D,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,MAAM,EAAE;YACP,aAAa,EAAE,KAAK;YACpB,qBAAqB,EAAE,KAAK;YAC5B,uBAAuB,EAAE,KAAK;YAC9B,cAAc,EAAE,YAAY;YAC5B,wBAAwB,EAAE,KAAK;YAC/B,kBAAkB,EAAE,KAAK;SACzB;KACD,CAAC;AAAA,CACF;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,GAA2C;IACpF,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,2BAA2B,CAAC,CAAC;IAClF,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QACvF,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;QAChE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAC9C,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CACrC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAC9D,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;AAAA,CACD","sourcesContent":["import type { Model } from \"@asm-agent/ai\";\n\nconst DEFAULT_OLLAMA_HOST = \"http://127.0.0.1:11434\";\nconst OLLAMA_DISCOVERY_TIMEOUT_MS = 1500;\n\nexport function getOllamaBaseUrl(): string {\n\tconst configured = process.env.OLLAMA_HOST?.trim() || DEFAULT_OLLAMA_HOST;\n\tconst host = configured.replace(/\\/$/, \"\");\n\treturn host.endsWith(\"/v1\") ? host : `${host}/v1`;\n}\n\nfunction getOllamaTagsUrl(baseUrl: string): string {\n\treturn `${baseUrl.replace(/\\/v1$/, \"\")}/api/tags`;\n}\n\ninterface OllamaTag {\n\tname?: unknown;\n\tdetails?: { family?: unknown; parameter_size?: unknown };\n}\n\nfunction modelFromTag(tag: OllamaTag, baseUrl: string): Model<\"openai-completions\"> | undefined {\n\tif (typeof tag.name !== \"string\" || !tag.name.trim()) return undefined;\n\tconst name = tag.name.trim();\n\treturn {\n\t\tid: name,\n\t\tname,\n\t\tapi: \"openai-completions\",\n\t\tprovider: \"ollama\",\n\t\tbaseUrl,\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: 131072,\n\t\tmaxTokens: 8192,\n\t\tcompat: {\n\t\t\tsupportsStore: false,\n\t\t\tsupportsDeveloperRole: false,\n\t\t\tsupportsReasoningEffort: false,\n\t\t\tmaxTokensField: \"max_tokens\",\n\t\t\tsupportsUsageInStreaming: false,\n\t\t\tsupportsStrictMode: false,\n\t\t},\n\t};\n}\n\nexport async function discoverOllamaModels(): Promise<Model<\"openai-completions\">[]> {\n\tconst baseUrl = getOllamaBaseUrl();\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), OLLAMA_DISCOVERY_TIMEOUT_MS);\n\ttry {\n\t\tconst response = await fetch(getOllamaTagsUrl(baseUrl), { signal: controller.signal });\n\t\tif (!response.ok) return [];\n\t\tconst payload = (await response.json()) as { models?: unknown };\n\t\tif (!Array.isArray(payload.models)) return [];\n\t\treturn payload.models.flatMap((tag) =>\n\t\t\ttag && typeof tag === \"object\" ? [modelFromTag(tag as OllamaTag, baseUrl)].filter(Boolean) : [],\n\t\t) as Model<\"openai-completions\">[];\n\t} catch {\n\t\treturn [];\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-display-names.d.ts","sourceRoot":"","sources":["../../src/core/provider-display-names.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"provider-display-names.d.ts","sourceRoot":"","sources":["../../src/core/provider-display-names.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiClE,CAAC","sourcesContent":["export const BUILT_IN_PROVIDER_DISPLAY_NAMES: Record<string, string> = {\n\tanthropic: \"Anthropic\",\n\t\"amazon-bedrock\": \"Amazon Bedrock\",\n\t\"azure-openai-responses\": \"Azure OpenAI Responses\",\n\tcerebras: \"Cerebras\",\n\t\"cloudflare-ai-gateway\": \"Cloudflare AI Gateway\",\n\t\"cloudflare-workers-ai\": \"Cloudflare Workers AI\",\n\tdeepseek: \"DeepSeek\",\n\tfireworks: \"Fireworks\",\n\tgoogle: \"Google Gemini\",\n\t\"google-vertex\": \"Google Vertex AI\",\n\tgroq: \"Groq\",\n\thuggingface: \"Hugging Face\",\n\t\"kimi-coding\": \"Kimi For Coding\",\n\tmistral: \"Mistral\",\n\tminimax: \"MiniMax\",\n\t\"minimax-cn\": \"MiniMax (China)\",\n\tmoonshotai: \"Moonshot AI\",\n\t\"moonshotai-cn\": \"Moonshot AI (China)\",\n\topencode: \"OpenCode Zen\",\n\t\"opencode-go\": \"OpenCode Go\",\n\topenai: \"OpenAI\",\n\tollama: \"Ollama\",\n\topenrouter: \"OpenRouter\",\n\t\"asm-agent-traces\": \"ASM Agent Traces\",\n\t\"prime-inference\": \"Prime Inference\",\n\t\"vercel-ai-gateway\": \"Vercel AI Gateway\",\n\txai: \"xAI\",\n\tzai: \"ZAI\",\n\txiaomi: \"Xiaomi MiMo\",\n\t\"xiaomi-token-plan-cn\": \"Xiaomi MiMo Token Plan (China)\",\n\t\"xiaomi-token-plan-ams\": \"Xiaomi MiMo Token Plan (Amsterdam)\",\n\t\"xiaomi-token-plan-sgp\": \"Xiaomi MiMo Token Plan (Singapore)\",\n};\n"]}
|
|
@@ -20,6 +20,7 @@ export const BUILT_IN_PROVIDER_DISPLAY_NAMES = {
|
|
|
20
20
|
opencode: "OpenCode Zen",
|
|
21
21
|
"opencode-go": "OpenCode Go",
|
|
22
22
|
openai: "OpenAI",
|
|
23
|
+
ollama: "Ollama",
|
|
23
24
|
openrouter: "OpenRouter",
|
|
24
25
|
"asm-agent-traces": "ASM Agent Traces",
|
|
25
26
|
"prime-inference": "Prime Inference",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-display-names.js","sourceRoot":"","sources":["../../src/core/provider-display-names.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,+BAA+B,GAA2B;IACtE,SAAS,EAAE,WAAW;IACtB,gBAAgB,EAAE,gBAAgB;IAClC,wBAAwB,EAAE,wBAAwB;IAClD,QAAQ,EAAE,UAAU;IACpB,uBAAuB,EAAE,uBAAuB;IAChD,uBAAuB,EAAE,uBAAuB;IAChD,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,eAAe;IACvB,eAAe,EAAE,kBAAkB;IACnC,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,cAAc;IAC3B,aAAa,EAAE,iBAAiB;IAChC,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,iBAAiB;IAC/B,UAAU,EAAE,aAAa;IACzB,eAAe,EAAE,qBAAqB;IACtC,QAAQ,EAAE,cAAc;IACxB,aAAa,EAAE,aAAa;IAC5B,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,kBAAkB,EAAE,kBAAkB;IACtC,iBAAiB,EAAE,iBAAiB;IACpC,mBAAmB,EAAE,mBAAmB;IACxC,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,aAAa;IACrB,sBAAsB,EAAE,gCAAgC;IACxD,uBAAuB,EAAE,oCAAoC;IAC7D,uBAAuB,EAAE,oCAAoC;CAC7D,CAAC","sourcesContent":["export const BUILT_IN_PROVIDER_DISPLAY_NAMES: Record<string, string> = {\n\tanthropic: \"Anthropic\",\n\t\"amazon-bedrock\": \"Amazon Bedrock\",\n\t\"azure-openai-responses\": \"Azure OpenAI Responses\",\n\tcerebras: \"Cerebras\",\n\t\"cloudflare-ai-gateway\": \"Cloudflare AI Gateway\",\n\t\"cloudflare-workers-ai\": \"Cloudflare Workers AI\",\n\tdeepseek: \"DeepSeek\",\n\tfireworks: \"Fireworks\",\n\tgoogle: \"Google Gemini\",\n\t\"google-vertex\": \"Google Vertex AI\",\n\tgroq: \"Groq\",\n\thuggingface: \"Hugging Face\",\n\t\"kimi-coding\": \"Kimi For Coding\",\n\tmistral: \"Mistral\",\n\tminimax: \"MiniMax\",\n\t\"minimax-cn\": \"MiniMax (China)\",\n\tmoonshotai: \"Moonshot AI\",\n\t\"moonshotai-cn\": \"Moonshot AI (China)\",\n\topencode: \"OpenCode Zen\",\n\t\"opencode-go\": \"OpenCode Go\",\n\topenai: \"OpenAI\",\n\topenrouter: \"OpenRouter\",\n\t\"asm-agent-traces\": \"ASM Agent Traces\",\n\t\"prime-inference\": \"Prime Inference\",\n\t\"vercel-ai-gateway\": \"Vercel AI Gateway\",\n\txai: \"xAI\",\n\tzai: \"ZAI\",\n\txiaomi: \"Xiaomi MiMo\",\n\t\"xiaomi-token-plan-cn\": \"Xiaomi MiMo Token Plan (China)\",\n\t\"xiaomi-token-plan-ams\": \"Xiaomi MiMo Token Plan (Amsterdam)\",\n\t\"xiaomi-token-plan-sgp\": \"Xiaomi MiMo Token Plan (Singapore)\",\n};\n"]}
|
|
1
|
+
{"version":3,"file":"provider-display-names.js","sourceRoot":"","sources":["../../src/core/provider-display-names.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,+BAA+B,GAA2B;IACtE,SAAS,EAAE,WAAW;IACtB,gBAAgB,EAAE,gBAAgB;IAClC,wBAAwB,EAAE,wBAAwB;IAClD,QAAQ,EAAE,UAAU;IACpB,uBAAuB,EAAE,uBAAuB;IAChD,uBAAuB,EAAE,uBAAuB;IAChD,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,eAAe;IACvB,eAAe,EAAE,kBAAkB;IACnC,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,cAAc;IAC3B,aAAa,EAAE,iBAAiB;IAChC,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,iBAAiB;IAC/B,UAAU,EAAE,aAAa;IACzB,eAAe,EAAE,qBAAqB;IACtC,QAAQ,EAAE,cAAc;IACxB,aAAa,EAAE,aAAa;IAC5B,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,kBAAkB,EAAE,kBAAkB;IACtC,iBAAiB,EAAE,iBAAiB;IACpC,mBAAmB,EAAE,mBAAmB;IACxC,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,aAAa;IACrB,sBAAsB,EAAE,gCAAgC;IACxD,uBAAuB,EAAE,oCAAoC;IAC7D,uBAAuB,EAAE,oCAAoC;CAC7D,CAAC","sourcesContent":["export const BUILT_IN_PROVIDER_DISPLAY_NAMES: Record<string, string> = {\n\tanthropic: \"Anthropic\",\n\t\"amazon-bedrock\": \"Amazon Bedrock\",\n\t\"azure-openai-responses\": \"Azure OpenAI Responses\",\n\tcerebras: \"Cerebras\",\n\t\"cloudflare-ai-gateway\": \"Cloudflare AI Gateway\",\n\t\"cloudflare-workers-ai\": \"Cloudflare Workers AI\",\n\tdeepseek: \"DeepSeek\",\n\tfireworks: \"Fireworks\",\n\tgoogle: \"Google Gemini\",\n\t\"google-vertex\": \"Google Vertex AI\",\n\tgroq: \"Groq\",\n\thuggingface: \"Hugging Face\",\n\t\"kimi-coding\": \"Kimi For Coding\",\n\tmistral: \"Mistral\",\n\tminimax: \"MiniMax\",\n\t\"minimax-cn\": \"MiniMax (China)\",\n\tmoonshotai: \"Moonshot AI\",\n\t\"moonshotai-cn\": \"Moonshot AI (China)\",\n\topencode: \"OpenCode Zen\",\n\t\"opencode-go\": \"OpenCode Go\",\n\topenai: \"OpenAI\",\n\tollama: \"Ollama\",\n\topenrouter: \"OpenRouter\",\n\t\"asm-agent-traces\": \"ASM Agent Traces\",\n\t\"prime-inference\": \"Prime Inference\",\n\t\"vercel-ai-gateway\": \"Vercel AI Gateway\",\n\txai: \"xAI\",\n\tzai: \"ZAI\",\n\txiaomi: \"Xiaomi MiMo\",\n\t\"xiaomi-token-plan-cn\": \"Xiaomi MiMo Token Plan (China)\",\n\t\"xiaomi-token-plan-ams\": \"Xiaomi MiMo Token Plan (Amsterdam)\",\n\t\"xiaomi-token-plan-sgp\": \"Xiaomi MiMo Token Plan (Singapore)\",\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAA+B,KAAK,YAAY,EAAqB,MAAM,uBAAuB,CAAC;AAC1G,OAAO,EAAoD,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAE3F,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;IACjB,kEAAkE;IAClE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAmJ3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { formatAlwaysAppliedSkills } from \"./always-applied-skills.js\";\nimport { buildChildAgentDoctrine, buildRlmPrompt, buildSubagentGuidance } from \"./prompts/index.js\";\nimport { formatHarnessStateForPrompt, type HarnessState, REFINE_SKILL_NAME } from \"./refinement/index.js\";\nimport { formatSkillsForPrompt, getPythonSkillRuntimeInfo, type Skill } from \"./skills.js\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Active tools. Tool schemas carry tool descriptions outside the prompt body. */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. Used only for custom prompts. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the system prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Conversation log path. */\n\tmessagesPath?: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n\t/** Whether to include the model-facing rlm recursion guidance. */\n\tallowRecursion?: boolean;\n\t/** Fixed recursive-agent depth for this session. */\n\trlmDepth?: number;\n\t/** Human-readable parent name or id for child communication doctrine. */\n\trlmParentAgent?: string;\n\t/** Global harness state to inject as compact persistent context. */\n\tharnessState?: HarnessState;\n\t/** Enabled user-configured servers available through the generic kernel MCP API. */\n\tgenericMcpServers?: string[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tmessagesPath,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t\tallowRecursion,\n\t\tharnessState,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\tconst promptMessagesPath = (messagesPath ?? \"not persisted\").replace(/\\\\/g, \"/\");\n\n\tconst now = new Date();\n\tconst year = now.getFullYear();\n\tconst month = String(now.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(now.getDate()).padStart(2, \"0\");\n\tconst date = `${year}-${month}-${day}`;\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\tconst tools = selectedTools ?? [\"ipython\"];\n\tconst hasIpython = tools.includes(\"ipython\");\n\tconst hasBash = tools.includes(\"bash\");\n\tconst visibleSkills = skills.filter((skill) => !skill.disableModelInvocation);\n\tconst visiblePythonSkillImportNames = getPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName);\n\tconst hasRefineSkill = visibleSkills.some((skill) => skill.name === REFINE_SKILL_NAME);\n\tconst genericMcpSection = hasIpython ? formatGenericMcpGuidance(options.genericMcpServers) : \"\";\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section only when the model has a way to inspect skill files.\n\t\tconst customPromptHasFileAccess =\n\t\t\t!selectedTools || selectedTools.includes(\"ipython\") || selectedTools.includes(\"bash\");\n\t\tif (customPromptHasFileAccess && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\t\tconst alwaysAppliedSkills = formatAlwaysAppliedSkills(skills);\n\t\tif (alwaysAppliedSkills) {\n\t\t\tprompt += `\\n\\n${alwaysAppliedSkills}`;\n\t\t}\n\n\t\t// Add date and working directory last\n\t\tprompt += `\\nCurrent date: ${date}`;\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\tconst childDoctrine = buildChildAgentDoctrine({\n\t\t\tdepth: options.rlmDepth,\n\t\t\tparentAgent: options.rlmParentAgent,\n\t\t\tinstalledSkills: visiblePythonSkillImportNames,\n\t\t\tactiveTools: tools,\n\t\t});\n\t\tif (childDoctrine) {\n\t\t\tprompt += `\\n\\n${childDoctrine}`;\n\t\t}\n\n\t\tif (harnessState) {\n\t\t\tprompt += `\\n\\n${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill })}`;\n\t\t}\n\n\t\tif (genericMcpSection) {\n\t\t\tprompt += `\\n\\n${genericMcpSection}`;\n\t\t}\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\treturn prompt;\n\t}\n\n\tlet prompt = buildRlmPrompt({\n\t\tcwd: promptCwd,\n\t\tmessagesPath: promptMessagesPath,\n\t\tinstalledSkills: visiblePythonSkillImportNames,\n\t\tactiveTools: tools.filter((name) => name === \"ipython\" || name === \"bash\" || name === \"edit\"),\n\t\tallowRecursion,\n\t\tdepth: options.rlmDepth,\n\t\tparentAgent: options.rlmParentAgent,\n\t});\n\n\t// Appended AFTER the trained buildRlmPrompt prefix, and before the harness-state\n\t// menu, so the model reads when/why to delegate and then sees the concrete subagent\n\t// specs it can match against — the same ordering as Claude Code's Agent tool.\n\tif ((allowRecursion ?? true) && hasIpython) {\n\t\tconst visiblePythonSkillNames = new Set(\n\t\t\tgetPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName),\n\t\t);\n\t\tprompt += `\\n\\n${buildSubagentGuidance({\n\t\t\tincludeRefineExamples: hasRefineSkill,\n\t\t\thasAgentMessage: visiblePythonSkillNames.has(\"agent_message\"),\n\t\t\thasAgentObserve: visiblePythonSkillNames.has(\"agent_observe\"),\n\t\t})}`;\n\t}\n\n\tif (harnessState) {\n\t\tprompt += `\\n\\n${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill })}`;\n\t}\n\n\tif (genericMcpSection) {\n\t\tprompt += `\\n\\n${genericMcpSection}`;\n\t}\n\n\tconst guidelines = formatPromptGuidelines(promptGuidelines);\n\tif (guidelines) {\n\t\tprompt += `\\n\\n# Additional Guidance\\n\\n${guidelines}`;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section only when the model has a way to inspect skill files.\n\tconst hasFileAccess = tools.includes(\"ipython\") || tools.includes(\"bash\");\n\tif (hasFileAccess && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\tconst alwaysAppliedSkills = formatAlwaysAppliedSkills(skills);\n\tif (alwaysAppliedSkills) {\n\t\tprompt += `\\n\\n${alwaysAppliedSkills}`;\n\t}\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\treturn prompt;\n}\n\nfunction formatGenericMcpGuidance(servers: string[] | undefined): string {\n\tconst enabledServers = [...new Set(servers ?? [])].sort((left, right) => left.localeCompare(right));\n\tif (enabledServers.length === 0) return \"\";\n\n\treturn [\n\t\t\"# Generic MCP Connections\",\n\t\t\"\",\n\t\t\"Generic MCP connections are accessed through the pre-imported Python `mcp` object in the Python REPL, not as top-level native tool namespaces or installed Python skills.\",\n\t\t`Enabled generic MCP servers: ${enabledServers.map((server) => `\\`${server}\\``).join(\", \")}.`,\n\t\t...enabledServers.map(\n\t\t\t(server) =>\n\t\t\t\t`For \\`${server}\\`, first discover its tools with \\`await mcp.list_tools(\"${server}\")\\`, then call one with \\`await mcp.call_tool(\"${server}\", \"<tool>\", arguments)\\`.`,\n\t\t),\n\t].join(\"\\n\");\n}\n\nfunction formatPromptGuidelines(promptGuidelines: string[] | undefined): string {\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0 && !guidelinesSet.has(normalized)) {\n\t\t\tguidelinesSet.add(normalized);\n\t\t\tguidelinesList.push(normalized);\n\t\t}\n\t}\n\n\treturn guidelinesList.map((guideline) => `- ${guideline}`).join(\"\\n\");\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* System prompt construction and project context loading
|
|
3
3
|
*/
|
|
4
|
+
import { formatAlwaysAppliedSkills } from "./always-applied-skills.js";
|
|
4
5
|
import { buildChildAgentDoctrine, buildRlmPrompt, buildSubagentGuidance } from "./prompts/index.js";
|
|
5
6
|
import { formatHarnessStateForPrompt, REFINE_SKILL_NAME } from "./refinement/index.js";
|
|
6
7
|
import { formatSkillsForPrompt, getPythonSkillRuntimeInfo } from "./skills.js";
|
|
@@ -39,6 +40,10 @@ export function buildSystemPrompt(options) {
|
|
|
39
40
|
if (customPromptHasFileAccess && skills.length > 0) {
|
|
40
41
|
prompt += formatSkillsForPrompt(skills);
|
|
41
42
|
}
|
|
43
|
+
const alwaysAppliedSkills = formatAlwaysAppliedSkills(skills);
|
|
44
|
+
if (alwaysAppliedSkills) {
|
|
45
|
+
prompt += `\n\n${alwaysAppliedSkills}`;
|
|
46
|
+
}
|
|
42
47
|
// Add date and working directory last
|
|
43
48
|
prompt += `\nCurrent date: ${date}`;
|
|
44
49
|
prompt += `\nCurrent working directory: ${promptCwd}`;
|
|
@@ -105,6 +110,10 @@ export function buildSystemPrompt(options) {
|
|
|
105
110
|
if (hasFileAccess && skills.length > 0) {
|
|
106
111
|
prompt += formatSkillsForPrompt(skills);
|
|
107
112
|
}
|
|
113
|
+
const alwaysAppliedSkills = formatAlwaysAppliedSkills(skills);
|
|
114
|
+
if (alwaysAppliedSkills) {
|
|
115
|
+
prompt += `\n\n${alwaysAppliedSkills}`;
|
|
116
|
+
}
|
|
108
117
|
if (appendSection) {
|
|
109
118
|
prompt += appendSection;
|
|
110
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { buildChildAgentDoctrine, buildRlmPrompt, buildSubagentGuidance } from \"./prompts/index.js\";\nimport { formatHarnessStateForPrompt, type HarnessState, REFINE_SKILL_NAME } from \"./refinement/index.js\";\nimport { formatSkillsForPrompt, getPythonSkillRuntimeInfo, type Skill } from \"./skills.js\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Active tools. Tool schemas carry tool descriptions outside the prompt body. */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. Used only for custom prompts. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the system prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Conversation log path. */\n\tmessagesPath?: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n\t/** Whether to include the model-facing rlm recursion guidance. */\n\tallowRecursion?: boolean;\n\t/** Fixed recursive-agent depth for this session. */\n\trlmDepth?: number;\n\t/** Human-readable parent name or id for child communication doctrine. */\n\trlmParentAgent?: string;\n\t/** Global harness state to inject as compact persistent context. */\n\tharnessState?: HarnessState;\n\t/** Enabled user-configured servers available through the generic kernel MCP API. */\n\tgenericMcpServers?: string[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tmessagesPath,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t\tallowRecursion,\n\t\tharnessState,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\tconst promptMessagesPath = (messagesPath ?? \"not persisted\").replace(/\\\\/g, \"/\");\n\n\tconst now = new Date();\n\tconst year = now.getFullYear();\n\tconst month = String(now.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(now.getDate()).padStart(2, \"0\");\n\tconst date = `${year}-${month}-${day}`;\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\tconst tools = selectedTools ?? [\"ipython\"];\n\tconst hasIpython = tools.includes(\"ipython\");\n\tconst hasBash = tools.includes(\"bash\");\n\tconst visibleSkills = skills.filter((skill) => !skill.disableModelInvocation);\n\tconst visiblePythonSkillImportNames = getPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName);\n\tconst hasRefineSkill = visibleSkills.some((skill) => skill.name === REFINE_SKILL_NAME);\n\tconst genericMcpSection = hasIpython ? formatGenericMcpGuidance(options.genericMcpServers) : \"\";\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section only when the model has a way to inspect skill files.\n\t\tconst customPromptHasFileAccess =\n\t\t\t!selectedTools || selectedTools.includes(\"ipython\") || selectedTools.includes(\"bash\");\n\t\tif (customPromptHasFileAccess && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date and working directory last\n\t\tprompt += `\\nCurrent date: ${date}`;\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\tconst childDoctrine = buildChildAgentDoctrine({\n\t\t\tdepth: options.rlmDepth,\n\t\t\tparentAgent: options.rlmParentAgent,\n\t\t\tinstalledSkills: visiblePythonSkillImportNames,\n\t\t\tactiveTools: tools,\n\t\t});\n\t\tif (childDoctrine) {\n\t\t\tprompt += `\\n\\n${childDoctrine}`;\n\t\t}\n\n\t\tif (harnessState) {\n\t\t\tprompt += `\\n\\n${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill })}`;\n\t\t}\n\n\t\tif (genericMcpSection) {\n\t\t\tprompt += `\\n\\n${genericMcpSection}`;\n\t\t}\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\treturn prompt;\n\t}\n\n\tlet prompt = buildRlmPrompt({\n\t\tcwd: promptCwd,\n\t\tmessagesPath: promptMessagesPath,\n\t\tinstalledSkills: visiblePythonSkillImportNames,\n\t\tactiveTools: tools.filter((name) => name === \"ipython\" || name === \"bash\" || name === \"edit\"),\n\t\tallowRecursion,\n\t\tdepth: options.rlmDepth,\n\t\tparentAgent: options.rlmParentAgent,\n\t});\n\n\t// Appended AFTER the trained buildRlmPrompt prefix, and before the harness-state\n\t// menu, so the model reads when/why to delegate and then sees the concrete subagent\n\t// specs it can match against — the same ordering as Claude Code's Agent tool.\n\tif ((allowRecursion ?? true) && hasIpython) {\n\t\tconst visiblePythonSkillNames = new Set(\n\t\t\tgetPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName),\n\t\t);\n\t\tprompt += `\\n\\n${buildSubagentGuidance({\n\t\t\tincludeRefineExamples: hasRefineSkill,\n\t\t\thasAgentMessage: visiblePythonSkillNames.has(\"agent_message\"),\n\t\t\thasAgentObserve: visiblePythonSkillNames.has(\"agent_observe\"),\n\t\t})}`;\n\t}\n\n\tif (harnessState) {\n\t\tprompt += `\\n\\n${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill })}`;\n\t}\n\n\tif (genericMcpSection) {\n\t\tprompt += `\\n\\n${genericMcpSection}`;\n\t}\n\n\tconst guidelines = formatPromptGuidelines(promptGuidelines);\n\tif (guidelines) {\n\t\tprompt += `\\n\\n# Additional Guidance\\n\\n${guidelines}`;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section only when the model has a way to inspect skill files.\n\tconst hasFileAccess = tools.includes(\"ipython\") || tools.includes(\"bash\");\n\tif (hasFileAccess && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\treturn prompt;\n}\n\nfunction formatGenericMcpGuidance(servers: string[] | undefined): string {\n\tconst enabledServers = [...new Set(servers ?? [])].sort((left, right) => left.localeCompare(right));\n\tif (enabledServers.length === 0) return \"\";\n\n\treturn [\n\t\t\"# Generic MCP Connections\",\n\t\t\"\",\n\t\t\"Generic MCP connections are accessed through the pre-imported Python `mcp` object in the Python REPL, not as top-level native tool namespaces or installed Python skills.\",\n\t\t`Enabled generic MCP servers: ${enabledServers.map((server) => `\\`${server}\\``).join(\", \")}.`,\n\t\t...enabledServers.map(\n\t\t\t(server) =>\n\t\t\t\t`For \\`${server}\\`, first discover its tools with \\`await mcp.list_tools(\"${server}\")\\`, then call one with \\`await mcp.call_tool(\"${server}\", \"<tool>\", arguments)\\`.`,\n\t\t),\n\t].join(\"\\n\");\n}\n\nfunction formatPromptGuidelines(promptGuidelines: string[] | undefined): string {\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0 && !guidelinesSet.has(normalized)) {\n\t\t\tguidelinesSet.add(normalized);\n\t\t\tguidelinesList.push(normalized);\n\t\t}\n\t}\n\n\treturn guidelinesList.map((guideline) => `- ${guideline}`).join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { formatAlwaysAppliedSkills } from \"./always-applied-skills.js\";\nimport { buildChildAgentDoctrine, buildRlmPrompt, buildSubagentGuidance } from \"./prompts/index.js\";\nimport { formatHarnessStateForPrompt, type HarnessState, REFINE_SKILL_NAME } from \"./refinement/index.js\";\nimport { formatSkillsForPrompt, getPythonSkillRuntimeInfo, type Skill } from \"./skills.js\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Active tools. Tool schemas carry tool descriptions outside the prompt body. */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. Used only for custom prompts. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the system prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Conversation log path. */\n\tmessagesPath?: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n\t/** Whether to include the model-facing rlm recursion guidance. */\n\tallowRecursion?: boolean;\n\t/** Fixed recursive-agent depth for this session. */\n\trlmDepth?: number;\n\t/** Human-readable parent name or id for child communication doctrine. */\n\trlmParentAgent?: string;\n\t/** Global harness state to inject as compact persistent context. */\n\tharnessState?: HarnessState;\n\t/** Enabled user-configured servers available through the generic kernel MCP API. */\n\tgenericMcpServers?: string[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tmessagesPath,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t\tallowRecursion,\n\t\tharnessState,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\tconst promptMessagesPath = (messagesPath ?? \"not persisted\").replace(/\\\\/g, \"/\");\n\n\tconst now = new Date();\n\tconst year = now.getFullYear();\n\tconst month = String(now.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(now.getDate()).padStart(2, \"0\");\n\tconst date = `${year}-${month}-${day}`;\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\tconst tools = selectedTools ?? [\"ipython\"];\n\tconst hasIpython = tools.includes(\"ipython\");\n\tconst hasBash = tools.includes(\"bash\");\n\tconst visibleSkills = skills.filter((skill) => !skill.disableModelInvocation);\n\tconst visiblePythonSkillImportNames = getPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName);\n\tconst hasRefineSkill = visibleSkills.some((skill) => skill.name === REFINE_SKILL_NAME);\n\tconst genericMcpSection = hasIpython ? formatGenericMcpGuidance(options.genericMcpServers) : \"\";\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section only when the model has a way to inspect skill files.\n\t\tconst customPromptHasFileAccess =\n\t\t\t!selectedTools || selectedTools.includes(\"ipython\") || selectedTools.includes(\"bash\");\n\t\tif (customPromptHasFileAccess && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\t\tconst alwaysAppliedSkills = formatAlwaysAppliedSkills(skills);\n\t\tif (alwaysAppliedSkills) {\n\t\t\tprompt += `\\n\\n${alwaysAppliedSkills}`;\n\t\t}\n\n\t\t// Add date and working directory last\n\t\tprompt += `\\nCurrent date: ${date}`;\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\tconst childDoctrine = buildChildAgentDoctrine({\n\t\t\tdepth: options.rlmDepth,\n\t\t\tparentAgent: options.rlmParentAgent,\n\t\t\tinstalledSkills: visiblePythonSkillImportNames,\n\t\t\tactiveTools: tools,\n\t\t});\n\t\tif (childDoctrine) {\n\t\t\tprompt += `\\n\\n${childDoctrine}`;\n\t\t}\n\n\t\tif (harnessState) {\n\t\t\tprompt += `\\n\\n${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill })}`;\n\t\t}\n\n\t\tif (genericMcpSection) {\n\t\t\tprompt += `\\n\\n${genericMcpSection}`;\n\t\t}\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\treturn prompt;\n\t}\n\n\tlet prompt = buildRlmPrompt({\n\t\tcwd: promptCwd,\n\t\tmessagesPath: promptMessagesPath,\n\t\tinstalledSkills: visiblePythonSkillImportNames,\n\t\tactiveTools: tools.filter((name) => name === \"ipython\" || name === \"bash\" || name === \"edit\"),\n\t\tallowRecursion,\n\t\tdepth: options.rlmDepth,\n\t\tparentAgent: options.rlmParentAgent,\n\t});\n\n\t// Appended AFTER the trained buildRlmPrompt prefix, and before the harness-state\n\t// menu, so the model reads when/why to delegate and then sees the concrete subagent\n\t// specs it can match against — the same ordering as Claude Code's Agent tool.\n\tif ((allowRecursion ?? true) && hasIpython) {\n\t\tconst visiblePythonSkillNames = new Set(\n\t\t\tgetPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName),\n\t\t);\n\t\tprompt += `\\n\\n${buildSubagentGuidance({\n\t\t\tincludeRefineExamples: hasRefineSkill,\n\t\t\thasAgentMessage: visiblePythonSkillNames.has(\"agent_message\"),\n\t\t\thasAgentObserve: visiblePythonSkillNames.has(\"agent_observe\"),\n\t\t})}`;\n\t}\n\n\tif (harnessState) {\n\t\tprompt += `\\n\\n${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill })}`;\n\t}\n\n\tif (genericMcpSection) {\n\t\tprompt += `\\n\\n${genericMcpSection}`;\n\t}\n\n\tconst guidelines = formatPromptGuidelines(promptGuidelines);\n\tif (guidelines) {\n\t\tprompt += `\\n\\n# Additional Guidance\\n\\n${guidelines}`;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section only when the model has a way to inspect skill files.\n\tconst hasFileAccess = tools.includes(\"ipython\") || tools.includes(\"bash\");\n\tif (hasFileAccess && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\tconst alwaysAppliedSkills = formatAlwaysAppliedSkills(skills);\n\tif (alwaysAppliedSkills) {\n\t\tprompt += `\\n\\n${alwaysAppliedSkills}`;\n\t}\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\treturn prompt;\n}\n\nfunction formatGenericMcpGuidance(servers: string[] | undefined): string {\n\tconst enabledServers = [...new Set(servers ?? [])].sort((left, right) => left.localeCompare(right));\n\tif (enabledServers.length === 0) return \"\";\n\n\treturn [\n\t\t\"# Generic MCP Connections\",\n\t\t\"\",\n\t\t\"Generic MCP connections are accessed through the pre-imported Python `mcp` object in the Python REPL, not as top-level native tool namespaces or installed Python skills.\",\n\t\t`Enabled generic MCP servers: ${enabledServers.map((server) => `\\`${server}\\``).join(\", \")}.`,\n\t\t...enabledServers.map(\n\t\t\t(server) =>\n\t\t\t\t`For \\`${server}\\`, first discover its tools with \\`await mcp.list_tools(\"${server}\")\\`, then call one with \\`await mcp.call_tool(\"${server}\", \"<tool>\", arguments)\\`.`,\n\t\t),\n\t].join(\"\\n\");\n}\n\nfunction formatPromptGuidelines(promptGuidelines: string[] | undefined): string {\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0 && !guidelinesSet.has(normalized)) {\n\t\t\tguidelinesSet.add(normalized);\n\t\t\tguidelinesList.push(normalized);\n\t\t}\n\t}\n\n\treturn guidelinesList.map((guideline) => `- ${guideline}`).join(\"\\n\");\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: final-response-summary
|
|
3
|
+
always-apply: true
|
|
4
|
+
description: Ensure the root ASM Agent sends one concise final response that summarizes the complete user request after all delegated agents, agent follow-ups, validations, and other work have settled. MUST be used for every root user request that reaches completion.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Final Response Summary
|
|
8
|
+
|
|
9
|
+
Apply this workflow only to the root, user-facing agent. Child agents must report
|
|
10
|
+
their results to their parent instead of producing the user's final summary.
|
|
11
|
+
|
|
12
|
+
## Completion gate
|
|
13
|
+
|
|
14
|
+
Before sending a final answer:
|
|
15
|
+
|
|
16
|
+
1. Re-read the user's original request and all later user changes.
|
|
17
|
+
2. Collect every required reply from delegated agents and their follow-ups.
|
|
18
|
+
3. Confirm no relevant child is still running, queued, or expected to reply.
|
|
19
|
+
4. Complete required edits, checks, tests, and the request report.
|
|
20
|
+
5. Separate verified results from blockers or unverified claims.
|
|
21
|
+
|
|
22
|
+
If relevant delegated work is still active, send only a short progress update and
|
|
23
|
+
end the turn. Do not present that update as the final result. Resume when replies
|
|
24
|
+
arrive.
|
|
25
|
+
|
|
26
|
+
## Final response
|
|
27
|
+
|
|
28
|
+
Send one concise response that covers:
|
|
29
|
+
|
|
30
|
+
- what the user requested;
|
|
31
|
+
- what was completed;
|
|
32
|
+
- important files or behavior changed;
|
|
33
|
+
- checks and tests run;
|
|
34
|
+
- blockers, remaining work, or next steps, when applicable;
|
|
35
|
+
- the generated `docs/report/...` path when the request-report skill applies.
|
|
36
|
+
|
|
37
|
+
Do not repeat the full transcript. Do not invent completion, test results, or
|
|
38
|
+
agent findings. Keep simple requests short and use sections only when they make
|
|
39
|
+
the result clearer.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: request-report
|
|
3
|
+
always-apply: true
|
|
4
|
+
description: Create one numbered Markdown report at docs/report/<number_mil>_<feature>_<date>.md for the latest user request. MUST be used by the root ASM Agent for every completed project task or user request in a writable workspace, after all work and validation finish and before the final response.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Request Report
|
|
8
|
+
|
|
9
|
+
The root, user-facing agent must create exactly one report for each completed
|
|
10
|
+
user request in a writable project workspace. Child agents must send findings
|
|
11
|
+
to their parent and must not create request reports.
|
|
12
|
+
|
|
13
|
+
Create the report after edits and validation finish, but before the final user
|
|
14
|
+
response. Call the prepared Python skill:
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
path = await request_report(
|
|
18
|
+
root=".",
|
|
19
|
+
feature="short feature name",
|
|
20
|
+
request="The user's complete request, including later changes.",
|
|
21
|
+
summary="What was completed and the resulting behavior.",
|
|
22
|
+
modified_files=["packages/example/src/file.ts", "docs/example.md"],
|
|
23
|
+
changes=["Changed ...", "Added ..."],
|
|
24
|
+
validation=["npm run check — passed"],
|
|
25
|
+
status="completed",
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Content fidelity
|
|
30
|
+
|
|
31
|
+
The report is the durable, self-contained counterpart of the final response.
|
|
32
|
+
Preserve all substantive user-facing content that the final response will contain,
|
|
33
|
+
including explanations, interpretations, rationale, tables, metrics, constraints,
|
|
34
|
+
caveats, and next steps. A short statement that an explanation was provided is
|
|
35
|
+
not a substitute for the explanation itself.
|
|
36
|
+
|
|
37
|
+
This is especially important when the user asks for a translation, a human-readable
|
|
38
|
+
explanation, an analysis, or a detailed answer: put the complete substantive answer
|
|
39
|
+
in the report. The `summary` argument may contain multiline Markdown with sections;
|
|
40
|
+
use it when needed instead of reducing the deliverable to one short paragraph. Do
|
|
41
|
+
not copy routine greetings, progress chatter, raw tool logs, or the full transcript.
|
|
42
|
+
|
|
43
|
+
Before sending the final response, compare it with the report.
|
|
44
|
+
No substantive section may exist only in the final response.
|
|
45
|
+
If necessary, update the report before completion so that it preserves the complete
|
|
46
|
+
deliverable.
|
|
47
|
+
|
|
48
|
+
The skill:
|
|
49
|
+
|
|
50
|
+
- creates `docs/report/` when needed;
|
|
51
|
+
- allocates sequential numbers with at least four digits (`0001`, `0002`, ...);
|
|
52
|
+
- converts `feature` to a safe kebab-case slug;
|
|
53
|
+
- uses an ISO date (`YYYY-MM-DD`);
|
|
54
|
+
- requires `modified_files` and renders every path as a relative Markdown link;
|
|
55
|
+
- always links the generated report itself in the modified-files list;
|
|
56
|
+
- rejects modified-file paths outside the project root;
|
|
57
|
+
- creates the file atomically without overwriting an existing report;
|
|
58
|
+
- returns the created path.
|
|
59
|
+
|
|
60
|
+
Pass every created, modified, or deleted project file in `modified_files`. Use
|
|
61
|
+
paths relative to `root` when possible. Use `status="partial"` or
|
|
62
|
+
`status="blocked"` when appropriate. Record only checks
|
|
63
|
+
that actually ran. If the workspace is read-only or the request does not have a
|
|
64
|
+
project filesystem, state that limitation in the final response instead of
|
|
65
|
+
claiming a report was created.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "request-report"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Create numbered Markdown reports for completed ASM Agent requests."
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
dependencies = []
|
|
7
|
+
|
|
8
|
+
[project.scripts]
|
|
9
|
+
request_report = "rlm.skill:cli"
|
|
10
|
+
|
|
11
|
+
[build-system]
|
|
12
|
+
requires = ["hatchling"]
|
|
13
|
+
build-backend = "hatchling.build"
|
|
14
|
+
|
|
15
|
+
[tool.hatch.build.targets.wheel]
|
|
16
|
+
packages = ["src/request_report"]
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Create numbered Markdown reports for completed user requests."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import unicodedata
|
|
8
|
+
from datetime import date as date_type
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Iterable
|
|
12
|
+
from urllib.parse import quote
|
|
13
|
+
|
|
14
|
+
_REPORT_NUMBER_WIDTH = 4
|
|
15
|
+
_REPORT_NAME_PATTERN = re.compile(r"^(\d{4,})_.*\.md$")
|
|
16
|
+
_VALID_STATUSES = frozenset({"blocked", "completed", "partial"})
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _slugify(value: str) -> str:
|
|
20
|
+
normalized = unicodedata.normalize("NFKD", value)
|
|
21
|
+
ascii_value = normalized.encode("ascii", "ignore").decode("ascii").lower()
|
|
22
|
+
slug = re.sub(r"[^a-z0-9]+", "-", ascii_value).strip("-")
|
|
23
|
+
return (slug or "request")[:60].rstrip("-")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _validate_date(value: str | None) -> str:
|
|
27
|
+
if value is None:
|
|
28
|
+
return datetime.now(timezone.utc).date().isoformat()
|
|
29
|
+
try:
|
|
30
|
+
return date_type.fromisoformat(value).isoformat()
|
|
31
|
+
except ValueError as error:
|
|
32
|
+
raise ValueError("date must use YYYY-MM-DD format") from error
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _next_number(report_dir: Path) -> int:
|
|
36
|
+
highest = 0
|
|
37
|
+
for path in report_dir.glob("*.md"):
|
|
38
|
+
match = _REPORT_NAME_PATTERN.match(path.name)
|
|
39
|
+
if match:
|
|
40
|
+
highest = max(highest, int(match.group(1)))
|
|
41
|
+
return highest + 1
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _section(title: str, content: str) -> list[str]:
|
|
45
|
+
return [f"## {title}", "", content.strip() or "Not provided.", ""]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _bullet_section(title: str, values: Iterable[str] | None) -> list[str]:
|
|
49
|
+
items = [value.strip() for value in (values or []) if value.strip()]
|
|
50
|
+
content = "\n".join(f"- {item}" for item in items) or "- None recorded."
|
|
51
|
+
return _section(title, content)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _normalize_modified_files(root: Path, values: list[str]) -> list[str]:
|
|
55
|
+
if not isinstance(values, list):
|
|
56
|
+
raise TypeError("modified_files must be a list of project file paths")
|
|
57
|
+
normalized: list[str] = []
|
|
58
|
+
for value in values:
|
|
59
|
+
if not isinstance(value, str) or not value.strip():
|
|
60
|
+
raise ValueError("modified_files must contain non-empty strings")
|
|
61
|
+
candidate = Path(value).expanduser()
|
|
62
|
+
resolved = candidate.resolve() if candidate.is_absolute() else (root / candidate).resolve()
|
|
63
|
+
try:
|
|
64
|
+
relative = resolved.relative_to(root).as_posix()
|
|
65
|
+
except ValueError as error:
|
|
66
|
+
raise ValueError(f"modified file path is outside the project root: {value}") from error
|
|
67
|
+
if relative not in normalized:
|
|
68
|
+
normalized.append(relative)
|
|
69
|
+
return normalized
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _escape_link_label(value: str) -> str:
|
|
73
|
+
return value.replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _modified_files_section(root: Path, report_path: Path, modified_files: list[str]) -> list[str]:
|
|
77
|
+
report_relative = report_path.relative_to(root).as_posix()
|
|
78
|
+
paths = [*modified_files]
|
|
79
|
+
if report_relative not in paths:
|
|
80
|
+
paths.append(report_relative)
|
|
81
|
+
links = []
|
|
82
|
+
for path in paths:
|
|
83
|
+
target = Path(os.path.relpath(root / path, report_path.parent)).as_posix()
|
|
84
|
+
links.append(f"- [{_escape_link_label(path)}]({quote(target, safe='/-._')})")
|
|
85
|
+
return _section("Modified files", "\n".join(links))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _render_report(
|
|
89
|
+
root: Path,
|
|
90
|
+
report_path: Path,
|
|
91
|
+
request: str,
|
|
92
|
+
summary: str,
|
|
93
|
+
modified_files: list[str],
|
|
94
|
+
changes: list[str] | None,
|
|
95
|
+
validation: list[str] | None,
|
|
96
|
+
status: str,
|
|
97
|
+
generated_date: str,
|
|
98
|
+
) -> str:
|
|
99
|
+
lines = ["# Request Report", "", f"- Status: {status}", f"- Date: {generated_date}", ""]
|
|
100
|
+
lines.extend(_section("User request", request))
|
|
101
|
+
lines.extend(_section("Summary", summary))
|
|
102
|
+
lines.extend(_modified_files_section(root, report_path, modified_files))
|
|
103
|
+
lines.extend(_bullet_section("Changes", changes))
|
|
104
|
+
lines.extend(_bullet_section("Validation", validation))
|
|
105
|
+
return "\n".join(lines).rstrip() + "\n"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def run(
|
|
109
|
+
root: str,
|
|
110
|
+
feature: str,
|
|
111
|
+
request: str,
|
|
112
|
+
summary: str,
|
|
113
|
+
modified_files: list[str],
|
|
114
|
+
changes: list[str] | None = None,
|
|
115
|
+
validation: list[str] | None = None,
|
|
116
|
+
status: str = "completed",
|
|
117
|
+
date: str | None = None,
|
|
118
|
+
) -> str:
|
|
119
|
+
"""Create and return one atomic numbered report for a completed request."""
|
|
120
|
+
root_path = Path(root).expanduser().resolve()
|
|
121
|
+
if not root_path.is_dir():
|
|
122
|
+
raise NotADirectoryError(f"{root} is not an existing directory")
|
|
123
|
+
if not isinstance(feature, str) or not feature.strip():
|
|
124
|
+
raise ValueError("feature must be a non-empty string")
|
|
125
|
+
if not isinstance(request, str) or not request.strip():
|
|
126
|
+
raise ValueError("request must be a non-empty string")
|
|
127
|
+
if not isinstance(summary, str) or not summary.strip():
|
|
128
|
+
raise ValueError("summary must be a non-empty string")
|
|
129
|
+
if status not in _VALID_STATUSES:
|
|
130
|
+
raise ValueError(f"status must be one of: {', '.join(sorted(_VALID_STATUSES))}")
|
|
131
|
+
|
|
132
|
+
generated_date = _validate_date(date)
|
|
133
|
+
normalized_modified_files = _normalize_modified_files(root_path, modified_files)
|
|
134
|
+
report_dir = root_path / "docs" / "report"
|
|
135
|
+
report_dir.mkdir(parents=True, exist_ok=True)
|
|
136
|
+
slug = _slugify(feature)
|
|
137
|
+
number = _next_number(report_dir)
|
|
138
|
+
|
|
139
|
+
while True:
|
|
140
|
+
report_path = report_dir / f"{number:0{_REPORT_NUMBER_WIDTH}d}_{slug}_{generated_date}.md"
|
|
141
|
+
content = _render_report(
|
|
142
|
+
root_path,
|
|
143
|
+
report_path,
|
|
144
|
+
request,
|
|
145
|
+
summary,
|
|
146
|
+
normalized_modified_files,
|
|
147
|
+
changes,
|
|
148
|
+
validation,
|
|
149
|
+
status,
|
|
150
|
+
generated_date,
|
|
151
|
+
)
|
|
152
|
+
try:
|
|
153
|
+
with report_path.open("x", encoding="utf-8") as report_file:
|
|
154
|
+
report_file.write(content)
|
|
155
|
+
return str(report_path)
|
|
156
|
+
except FileExistsError:
|
|
157
|
+
number += 1
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
__all__ = ["run"]
|
|
@@ -5,7 +5,7 @@ description: Create, validate, and install ASM Agent skills - both markdown skil
|
|
|
5
5
|
|
|
6
6
|
# Skill Creator
|
|
7
7
|
|
|
8
|
-
A skill is a directory with a `SKILL.md` file (YAML frontmatter + markdown instructions). At startup ASM Agent reads
|
|
8
|
+
A skill is a directory with a `SKILL.md` file (YAML frontmatter + markdown instructions). At startup ASM Agent reads each skill's name and description into the system prompt. The full file normally loads on demand when a task matches. Skills marked `always-apply: true` are an ASM Agent extension whose full instructions are injected at startup. ASM Agent follows the [Agent Skills standard](https://agentskills.io/specification) and extends it with Python-backed and always-applied skills.
|
|
9
9
|
|
|
10
10
|
| Kind | What it is | When to use |
|
|
11
11
|
|---|---|---|
|
|
@@ -51,6 +51,7 @@ description: What this skill does and when to use it. Be specific.
|
|
|
51
51
|
|---|---|---|
|
|
52
52
|
| `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. No leading/trailing/consecutive hyphens. Must match the parent directory name. |
|
|
53
53
|
| `description` | Yes | Max 1024 chars. A skill with a missing or empty description is **silently not loaded**. |
|
|
54
|
+
| `always-apply` | No | `true` injects the full skill instructions into every system prompt. Reserve this for small, universal policies. |
|
|
54
55
|
| `disable-model-invocation` | No | `true` hides the skill from the system prompt; only explicit `/skill:<name>` invokes it. |
|
|
55
56
|
| `license` | No | License name or reference to a bundled file. |
|
|
56
57
|
| `compatibility` | No | Max 500 chars. Environment requirements. |
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: solid-source-modularity
|
|
3
|
+
always-apply: true
|
|
4
|
+
description: Enforce SOLID design, cohesive source modules, staged refactoring, and source-file size limits. MUST be used whenever the agent creates, modifies, reviews, or refactors authored source code in any project.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# SOLID Source Modularity
|
|
8
|
+
|
|
9
|
+
Apply this policy to all authored source-code work.
|
|
10
|
+
|
|
11
|
+
## Required policy
|
|
12
|
+
|
|
13
|
+
- Follow SOLID and give each module one cohesive responsibility.
|
|
14
|
+
- Separate orchestration, domain logic, I/O, rendering, and platform adapters.
|
|
15
|
+
- Prefer small contracts and explicit dependencies. Avoid generic catch-all modules.
|
|
16
|
+
- Target at most 300 physical lines per authored source file.
|
|
17
|
+
- Allow 301–500 lines only as a documented exception when splitting would reduce
|
|
18
|
+
cohesion or create artificial coupling.
|
|
19
|
+
- More than 500 lines is always a violation and requires modularization.
|
|
20
|
+
- Generated files and lockfiles are exempt.
|
|
21
|
+
|
|
22
|
+
## Required refactoring sequence
|
|
23
|
+
|
|
24
|
+
1. Inventory files and responsibilities.
|
|
25
|
+
2. Define boundaries, contracts, and dependency direction.
|
|
26
|
+
3. Create all destination modules before replacing the original implementation.
|
|
27
|
+
4. Validate new modules in isolation when possible.
|
|
28
|
+
5. Replace the original code with imports, delegation, and orchestration only
|
|
29
|
+
after the destination modules exist.
|
|
30
|
+
6. Organize tests by responsibility and run the project's required checks.
|
|
31
|
+
7. Run the source audit and document each 301–500-line exception.
|
|
32
|
+
|
|
33
|
+
Keep structural refactoring separate from new behavior. Preserve behavior during
|
|
34
|
+
structural changes. Never create a commit without explicit user authorization.
|
|
35
|
+
|
|
36
|
+
## Audit
|
|
37
|
+
|
|
38
|
+
Call the prepared Python skill from the repository root:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
report = await solid_source_modularity(
|
|
42
|
+
root=".",
|
|
43
|
+
extensions=[".ts", ".tsx", ".py"],
|
|
44
|
+
)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`report` separates `compliant`, `exceptions`, `violations`, and `skipped` files.
|
|
48
|
+
Do not raise `target_lines` above 300 or `hard_limit` above 500.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "solid-source-modularity"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Audit authored source files against ASM Agent modularity limits."
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
dependencies = []
|
|
7
|
+
|
|
8
|
+
[project.scripts]
|
|
9
|
+
solid_source_modularity = "rlm.skill:cli"
|
|
10
|
+
|
|
11
|
+
[build-system]
|
|
12
|
+
requires = ["hatchling"]
|
|
13
|
+
build-backend = "hatchling.build"
|
|
14
|
+
|
|
15
|
+
[tool.hatch.build.targets.wheel]
|
|
16
|
+
packages = ["src/solid_source_modularity"]
|