open-multi-agent-kit 0.90.3 → 0.90.4
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 +16 -0
- package/README.md +16 -14
- package/dist/config.d.ts +3 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +27 -19
- package/dist/config.js.map +1 -1
- package/dist/core/adaptorch-bridge.d.ts +257 -0
- package/dist/core/adaptorch-bridge.d.ts.map +1 -0
- package/dist/core/adaptorch-bridge.js +473 -0
- package/dist/core/adaptorch-bridge.js.map +1 -0
- package/dist/core/agent-session.d.ts +130 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +286 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bang-skill-invocation.d.ts.map +1 -1
- package/dist/core/bang-skill-invocation.js +149 -0
- package/dist/core/bang-skill-invocation.js.map +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +15 -2
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/domain-loadouts.d.ts.map +1 -1
- package/dist/core/domain-loadouts.js +1 -1
- package/dist/core/domain-loadouts.js.map +1 -1
- package/dist/core/reasoning-router-bias.d.ts +119 -0
- package/dist/core/reasoning-router-bias.d.ts.map +1 -0
- package/dist/core/reasoning-router-bias.js +287 -0
- package/dist/core/reasoning-router-bias.js.map +1 -0
- package/dist/core/reasoning-router-v2.d.ts +94 -0
- package/dist/core/reasoning-router-v2.d.ts.map +1 -0
- package/dist/core/reasoning-router-v2.js +288 -0
- package/dist/core/reasoning-router-v2.js.map +1 -0
- package/dist/core/reasoning-router-v3.d.ts +15 -0
- package/dist/core/reasoning-router-v3.d.ts.map +1 -0
- package/dist/core/reasoning-router-v3.js +193 -0
- package/dist/core/reasoning-router-v3.js.map +1 -0
- package/dist/core/reasoning-router-v4-weights.d.ts +124 -0
- package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -0
- package/dist/core/reasoning-router-v4-weights.js +112 -0
- package/dist/core/reasoning-router-v4-weights.js.map +1 -0
- package/dist/core/reasoning-router-v4.d.ts +163 -0
- package/dist/core/reasoning-router-v4.d.ts.map +1 -0
- package/dist/core/reasoning-router-v4.js +683 -0
- package/dist/core/reasoning-router-v4.js.map +1 -0
- package/dist/core/reasoning-router-weights.d.ts +155 -0
- package/dist/core/reasoning-router-weights.d.ts.map +1 -0
- package/dist/core/reasoning-router-weights.js +204 -0
- package/dist/core/reasoning-router-weights.js.map +1 -0
- package/dist/core/reasoning-router.d.ts +44 -0
- package/dist/core/reasoning-router.d.ts.map +1 -0
- package/dist/core/reasoning-router.js +138 -0
- package/dist/core/reasoning-router.js.map +1 -0
- package/dist/core/router-feedback-collector.d.ts +101 -0
- package/dist/core/router-feedback-collector.d.ts.map +1 -0
- package/dist/core/router-feedback-collector.js +239 -0
- package/dist/core/router-feedback-collector.js.map +1 -0
- package/dist/core/settings-manager.d.ts +28 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +16 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +4 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-runtime-status.d.ts +15 -0
- package/dist/modes/interactive/components/control-panel-runtime-status.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-runtime-status.js +95 -5
- package/dist/modes/interactive/components/control-panel-runtime-status.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +143 -18
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/loadout-domains/README.md +8 -6
- package/docs/loadout-domains/ai-agent-ops.md +3 -2
- package/docs/loadout-domains/backend-api.md +3 -2
- package/docs/loadout-domains/data-science.md +3 -2
- package/docs/loadout-domains/devops-infra.md +2 -1
- package/docs/loadout-domains/docs-writing.md +7 -2
- package/docs/loadout-domains/frontend-ui.md +42 -11
- package/docs/loadout-domains/korean-document.md +83 -0
- package/docs/loadout-domains/mobile.md +1 -1
- package/docs/loadout-domains/qa-testing.md +4 -2
- package/docs/loadout-domains/security-audit.md +2 -1
- package/docs/loadout-domains/visual-qa.md +94 -0
- package/docs/skills.md +4 -1
- package/docs/usage.md +37 -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/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/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/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
- package/dist/agents/jailbreak/index.d.ts +0 -7
- package/dist/agents/jailbreak/index.d.ts.map +0 -1
- package/dist/agents/jailbreak/index.js +0 -7
- package/dist/agents/jailbreak/index.js.map +0 -1
- package/dist/agents/jailbreak/subagent-f.d.ts +0 -44
- package/dist/agents/jailbreak/subagent-f.d.ts.map +0 -1
- package/dist/agents/jailbreak/subagent-f.js +0 -60
- package/dist/agents/jailbreak/subagent-f.js.map +0 -1
- package/dist/cli/jailbreak-args.d.ts +0 -26
- package/dist/cli/jailbreak-args.d.ts.map +0 -1
- package/dist/cli/jailbreak-args.js +0 -86
- package/dist/cli/jailbreak-args.js.map +0 -1
- package/dist/commands/jailbreak.d.ts +0 -49
- package/dist/commands/jailbreak.d.ts.map +0 -1
- package/dist/commands/jailbreak.js +0 -201
- package/dist/commands/jailbreak.js.map +0 -1
- package/dist/encoding/index.d.ts +0 -6
- package/dist/encoding/index.d.ts.map +0 -1
- package/dist/encoding/index.js +0 -6
- package/dist/encoding/index.js.map +0 -1
- package/dist/encoding/l4-encoder.d.ts +0 -96
- package/dist/encoding/l4-encoder.d.ts.map +0 -1
- package/dist/encoding/l4-encoder.js +0 -474
- package/dist/encoding/l4-encoder.js.map +0 -1
- package/dist/fuzzing/index.d.ts +0 -6
- package/dist/fuzzing/index.d.ts.map +0 -1
- package/dist/fuzzing/index.js +0 -6
- package/dist/fuzzing/index.js.map +0 -1
- package/dist/fuzzing/mutation-engine.d.ts +0 -93
- package/dist/fuzzing/mutation-engine.d.ts.map +0 -1
- package/dist/fuzzing/mutation-engine.js +0 -244
- package/dist/fuzzing/mutation-engine.js.map +0 -1
- package/dist/jailbreak-extension.d.ts +0 -48
- package/dist/jailbreak-extension.d.ts.map +0 -1
- package/dist/jailbreak-extension.js +0 -47
- package/dist/jailbreak-extension.js.map +0 -1
- package/dist/modules/index.d.ts +0 -8
- package/dist/modules/index.d.ts.map +0 -1
- package/dist/modules/index.js +0 -7
- package/dist/modules/index.js.map +0 -1
- package/dist/modules/lrl-bypass.d.ts +0 -40
- package/dist/modules/lrl-bypass.d.ts.map +0 -1
- package/dist/modules/lrl-bypass.js +0 -84
- package/dist/modules/lrl-bypass.js.map +0 -1
- package/dist/modules/lrl-deps.d.ts +0 -38
- package/dist/modules/lrl-deps.d.ts.map +0 -1
- package/dist/modules/lrl-deps.js +0 -128
- package/dist/modules/lrl-deps.js.map +0 -1
- package/dist/multiturn/easl-chain.d.ts +0 -113
- package/dist/multiturn/easl-chain.d.ts.map +0 -1
- package/dist/multiturn/easl-chain.js +0 -351
- package/dist/multiturn/easl-chain.js.map +0 -1
- package/dist/multiturn/index.d.ts +0 -6
- package/dist/multiturn/index.d.ts.map +0 -1
- package/dist/multiturn/index.js +0 -6
- package/dist/multiturn/index.js.map +0 -1
- package/dist/routing/fallback-router.d.ts +0 -123
- package/dist/routing/fallback-router.d.ts.map +0 -1
- package/dist/routing/fallback-router.js +0 -355
- package/dist/routing/fallback-router.js.map +0 -1
- package/dist/routing/index.d.ts +0 -6
- package/dist/routing/index.d.ts.map +0 -1
- package/dist/routing/index.js +0 -6
- package/dist/routing/index.js.map +0 -1
- package/dist/types/jailbreak.d.ts +0 -246
- package/dist/types/jailbreak.d.ts.map +0 -1
- package/dist/types/jailbreak.js +0 -8
- package/dist/types/jailbreak.js.map +0 -1
- package/dist/utils/jailbreak/common.d.ts +0 -63
- package/dist/utils/jailbreak/common.d.ts.map +0 -1
- package/dist/utils/jailbreak/common.js +0 -130
- package/dist/utils/jailbreak/common.js.map +0 -1
- package/dist/utils/jailbreak/index.d.ts +0 -7
- package/dist/utils/jailbreak/index.d.ts.map +0 -1
- package/dist/utils/jailbreak/index.js +0 -7
- package/dist/utils/jailbreak/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bang-skill-invocation.d.ts","sourceRoot":"","sources":["../../src/core/bang-skill-invocation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;
|
|
1
|
+
{"version":3,"file":"bang-skill-invocation.d.ts","sourceRoot":"","sources":["../../src/core/bang-skill-invocation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAmFD,MAAM,MAAM,cAAc,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,cAAc,CA4D9F","sourcesContent":["export interface BangSkillRegistry {\n\thasSkill(name: string): boolean;\n}\n\nconst OMK_INDEX_SKILL = \"omk-skills\";\n\ninterface OmkHubRoute {\n\tskillName: string;\n\taliases: readonly string[];\n\tkeywords: readonly string[];\n}\n\nconst OMK_HUB_ROUTES: readonly OmkHubRoute[] = [\n\t{\n\t\tskillName: \"omk-frontend\",\n\t\taliases: [\"front\", \"frontend\", \"fe\", \"ui\", \"ux\", \"react\", \"next\", \"vue\", \"svelte\", \"tailwind\"],\n\t\tkeywords: [\n\t\t\t\"component\",\n\t\t\t\"css\",\n\t\t\t\"html\",\n\t\t\t\"responsive\",\n\t\t\t\"a11y\",\n\t\t\t\"accessibility\",\n\t\t\t\"visual\",\n\t\t\t\"browser\",\n\t\t\t\"design-system\",\n\t\t],\n\t},\n\t{\n\t\tskillName: \"omk-backend-data\",\n\t\taliases: [\"back\", \"backend\", \"api\", \"db\", \"data\", \"database\", \"server\", \"postgres\", \"supabase\", \"redis\"],\n\t\tkeywords: [\"endpoint\", \"migration\", \"schema\", \"orm\", \"cache\", \"queue\", \"service\", \"auth\", \"prisma\", \"mysql\"],\n\t},\n\t{\n\t\tskillName: \"omk-loop\",\n\t\taliases: [\"loop\", \"run\", \"runner\", \"ralph\", \"evolve\", \"orchestrate\", \"orchestration\", \"team\", \"parallel\"],\n\t\tkeywords: [\"subagent\", \"workflow\", \"pipeline\", \"goal\", \"dag\", \"ouroboros\", \"adaptorch\", \"continuous\"],\n\t},\n\t{\n\t\tskillName: \"omk-plan\",\n\t\taliases: [\"plan\", \"planning\", \"spec\", \"prd\", \"pm\", \"blueprint\", \"interview\", \"requirements\"],\n\t\tkeywords: [\"roadmap\", \"scope\", \"acceptance\", \"criteria\", \"architecture\", \"proposal\", \"tasks\", \"design\"],\n\t},\n\t{\n\t\tskillName: \"omk-engineering\",\n\t\taliases: [\"code\", \"coding\", \"engineering\", \"eng\", \"debug\", \"test\", \"refactor\", \"review\", \"ponytail\"],\n\t\tkeywords: [\"typescript\", \"python\", \"rust\", \"go\", \"build\", \"lint\", \"bug\", \"fix\", \"minimal\", \"yagni\"],\n\t},\n\t{\n\t\tskillName: \"omk-security\",\n\t\taliases: [\"sec\", \"security\", \"audit\", \"vuln\", \"vulnerability\", \"semgrep\", \"codeql\", \"reverse\"],\n\t\tkeywords: [\"threat\", \"secret\", \"supply\", \"chain\", \"fuzz\", \"crypto\", \"sandbox\", \"malware\"],\n\t},\n\t{\n\t\tskillName: \"omk-devops-release\",\n\t\taliases: [\"devops\", \"release\", \"deploy\", \"ci\", \"cd\", \"github\", \"gh\", \"gh-repo\", \"git\", \"repo\", \"pr\"],\n\t\tkeywords: [\"docker\", \"kubernetes\", \"vercel\", \"canary\", \"workflow\", \"changelog\", \"version\"],\n\t},\n\t{\n\t\tskillName: \"omk-research-docs\",\n\t\taliases: [\"research\", \"docs\", \"doc\", \"documentation\", \"report\", \"pdf\", \"slides\", \"paper\"],\n\t\tkeywords: [\"citation\", \"literature\", \"academic\", \"write\", \"summarize\", \"evidence\", \"source\"],\n\t},\n\t{\n\t\tskillName: \"omk-design-media\",\n\t\taliases: [\"design\", \"media\", \"image\", \"video\", \"logo\", \"icon\", \"diagram\", \"asset\"],\n\t\tkeywords: [\"brand\", \"infographic\", \"svg\", \"gif\", \"audio\", \"poster\", \"visual\", \"animation\"],\n\t},\n\t{\n\t\tskillName: \"omk-agent-ops\",\n\t\taliases: [\"agent\", \"agents\", \"ops\", \"mcp\", \"skill\", \"skills\", \"headroom\", \"context\", \"memory\"],\n\t\tkeywords: [\"omk\", \"runtime\", \"hook\", \"loadout\", \"prompt\", \"harness\", \"adaptorch\", \"ouroboros\"],\n\t},\n\t{\n\t\tskillName: \"omk-product-ops\",\n\t\taliases: [\"product\", \"growth\", \"marketing\", \"seo\", \"cro\", \"analytics\", \"launch\", \"pricing\"],\n\t\tkeywords: [\"campaign\", \"content\", \"conversion\", \"copy\", \"sales\", \"investor\", \"market\"],\n\t},\n\t{\n\t\tskillName: \"omk-workspace-ops\",\n\t\taliases: [\"workspace\", \"gmail\", \"calendar\", \"drive\", \"sheets\", \"chat\", \"tasks\", \"email\"],\n\t\tkeywords: [\"google\", \"docs\", \"slides\", \"meet\", \"people\", \"message\", \"notification\"],\n\t},\n];\n\nexport type BangInvocation =\n\t| { kind: \"plain\"; prompt: string }\n\t| { kind: \"empty\" }\n\t| { kind: \"bash\"; command: string; includeContext: boolean }\n\t| { kind: \"skill\"; skillName: string; prompt: string; activeSkillNames: readonly string[]; source: \"bang\" }\n\t| { kind: \"unknownSkill\"; skillName: string; prompt: string; source: \"bang\" };\n\nexport function parseBangInvocation(input: string, registry: BangSkillRegistry): BangInvocation {\n\tif (!input.startsWith(\"!\")) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\n\tif (input.startsWith(\"!!\")) {\n\t\tconst command = input.slice(2).trim();\n\t\treturn command ? { kind: \"bash\", command, includeContext: false } : { kind: \"empty\" };\n\t}\n\n\tconst second = input[1];\n\tif (second === undefined) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\n\tif (/\\s/.test(second)) {\n\t\tconst command = input.slice(2).trim();\n\t\treturn command ? { kind: \"bash\", command, includeContext: true } : { kind: \"empty\" };\n\t}\n\n\tconst body = input.slice(1);\n\tconst omkInvocation = parseOmkBangInvocation(body, registry);\n\tif (omkInvocation) {\n\t\treturn omkInvocation;\n\t}\n\n\tif (body.startsWith(\"skill:\")) {\n\t\tconst explicit = body.slice(\"skill:\".length);\n\t\tconst { token: skillName, rest } = splitFirstToken(explicit);\n\t\tif (!skillName) {\n\t\t\treturn { kind: \"plain\", prompt: input };\n\t\t}\n\t\tif (!registry.hasSkill(skillName)) {\n\t\t\treturn { kind: \"unknownSkill\", skillName, prompt: rest, source: \"bang\" };\n\t\t}\n\t\treturn {\n\t\t\tkind: \"skill\",\n\t\t\tskillName,\n\t\t\tprompt: rest,\n\t\t\tactiveSkillNames: [skillName],\n\t\t\tsource: \"bang\",\n\t\t};\n\t}\n\n\tconst { token: skillName, rest } = splitFirstToken(body);\n\tif (!skillName) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\tif (registry.hasSkill(skillName)) {\n\t\treturn {\n\t\t\tkind: \"skill\",\n\t\t\tskillName,\n\t\t\tprompt: rest,\n\t\t\tactiveSkillNames: [skillName],\n\t\t\tsource: \"bang\",\n\t\t};\n\t}\n\n\tconst command = body.trim();\n\treturn command ? { kind: \"bash\", command, includeContext: true } : { kind: \"empty\" };\n}\n\nfunction parseOmkBangInvocation(body: string, registry: BangSkillRegistry): BangInvocation | null {\n\tconst { token, rest } = splitFirstToken(body);\n\tif (normalizeOmkToken(token) !== \"omk\") {\n\t\treturn null;\n\t}\n\n\tconst route = resolveOmkHubRoute(rest);\n\tconst skillName = availableOmkSkillName(route.skillName, registry);\n\tif (!skillName) {\n\t\treturn { kind: \"unknownSkill\", skillName: route.skillName, prompt: route.prompt, source: \"bang\" };\n\t}\n\n\treturn {\n\t\tkind: \"skill\",\n\t\tskillName,\n\t\tprompt: route.prompt,\n\t\tactiveSkillNames: activeOmkSkillNames(skillName, registry),\n\t\tsource: \"bang\",\n\t};\n}\n\nfunction resolveOmkHubRoute(prompt: string): { skillName: string; prompt: string } {\n\tconst { token, rest } = splitFirstToken(prompt);\n\tconst normalizedToken = normalizeOmkToken(token);\n\tif (normalizedToken) {\n\t\tconst exactRoute = OMK_HUB_ROUTES.find((route) => route.aliases.includes(normalizedToken));\n\t\tif (exactRoute) {\n\t\t\treturn { skillName: exactRoute.skillName, prompt: rest };\n\t\t}\n\t}\n\n\tconst scored = OMK_HUB_ROUTES.map((route, index) => ({ route, index, score: scoreOmkRoute(route, prompt) }))\n\t\t.filter((entry) => entry.score > 0)\n\t\t.sort((a, b) => b.score - a.score || a.index - b.index);\n\n\tconst best = scored[0];\n\tif (best) {\n\t\treturn { skillName: best.route.skillName, prompt: prompt.trimStart() };\n\t}\n\n\treturn { skillName: OMK_INDEX_SKILL, prompt: prompt.trimStart() };\n}\n\nfunction availableOmkSkillName(skillName: string, registry: BangSkillRegistry): string | null {\n\tif (registry.hasSkill(skillName)) {\n\t\treturn skillName;\n\t}\n\tif (skillName !== OMK_INDEX_SKILL && registry.hasSkill(OMK_INDEX_SKILL)) {\n\t\treturn OMK_INDEX_SKILL;\n\t}\n\treturn null;\n}\n\nfunction activeOmkSkillNames(skillName: string, registry: BangSkillRegistry): readonly string[] {\n\tif (skillName !== OMK_INDEX_SKILL && registry.hasSkill(OMK_INDEX_SKILL)) {\n\t\treturn [OMK_INDEX_SKILL, skillName];\n\t}\n\treturn [skillName];\n}\n\nfunction scoreOmkRoute(route: OmkHubRoute, prompt: string): number {\n\tconst tokens = new Set(\n\t\tprompt\n\t\t\t.split(/[^\\p{L}\\p{N}-]+/u)\n\t\t\t.map(normalizeOmkToken)\n\t\t\t.filter(Boolean),\n\t);\n\tlet score = 0;\n\tfor (const alias of route.aliases) {\n\t\tif (tokens.has(alias)) {\n\t\t\tscore += 4;\n\t\t}\n\t}\n\tfor (const keyword of route.keywords) {\n\t\tif (tokens.has(keyword)) {\n\t\t\tscore += 2;\n\t\t}\n\t}\n\treturn score;\n}\n\nfunction normalizeOmkToken(token: string): string {\n\treturn token.trim().toLowerCase().replace(/^omk-/, \"\").replace(/_/g, \"-\");\n}\n\nfunction splitFirstToken(input: string): { token: string; rest: string } {\n\tconst trimmed = input.trimStart();\n\tconst match = /^([^\\s]+)(?:\\s+([\\s\\S]*))?$/.exec(trimmed);\n\tif (!match) {\n\t\treturn { token: \"\", rest: \"\" };\n\t}\n\treturn { token: match[1] ?? \"\", rest: match[2]?.trimStart() ?? \"\" };\n}\n"]}
|
|
@@ -1,3 +1,76 @@
|
|
|
1
|
+
const OMK_INDEX_SKILL = "omk-skills";
|
|
2
|
+
const OMK_HUB_ROUTES = [
|
|
3
|
+
{
|
|
4
|
+
skillName: "omk-frontend",
|
|
5
|
+
aliases: ["front", "frontend", "fe", "ui", "ux", "react", "next", "vue", "svelte", "tailwind"],
|
|
6
|
+
keywords: [
|
|
7
|
+
"component",
|
|
8
|
+
"css",
|
|
9
|
+
"html",
|
|
10
|
+
"responsive",
|
|
11
|
+
"a11y",
|
|
12
|
+
"accessibility",
|
|
13
|
+
"visual",
|
|
14
|
+
"browser",
|
|
15
|
+
"design-system",
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
skillName: "omk-backend-data",
|
|
20
|
+
aliases: ["back", "backend", "api", "db", "data", "database", "server", "postgres", "supabase", "redis"],
|
|
21
|
+
keywords: ["endpoint", "migration", "schema", "orm", "cache", "queue", "service", "auth", "prisma", "mysql"],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
skillName: "omk-loop",
|
|
25
|
+
aliases: ["loop", "run", "runner", "ralph", "evolve", "orchestrate", "orchestration", "team", "parallel"],
|
|
26
|
+
keywords: ["subagent", "workflow", "pipeline", "goal", "dag", "ouroboros", "adaptorch", "continuous"],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
skillName: "omk-plan",
|
|
30
|
+
aliases: ["plan", "planning", "spec", "prd", "pm", "blueprint", "interview", "requirements"],
|
|
31
|
+
keywords: ["roadmap", "scope", "acceptance", "criteria", "architecture", "proposal", "tasks", "design"],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
skillName: "omk-engineering",
|
|
35
|
+
aliases: ["code", "coding", "engineering", "eng", "debug", "test", "refactor", "review", "ponytail"],
|
|
36
|
+
keywords: ["typescript", "python", "rust", "go", "build", "lint", "bug", "fix", "minimal", "yagni"],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
skillName: "omk-security",
|
|
40
|
+
aliases: ["sec", "security", "audit", "vuln", "vulnerability", "semgrep", "codeql", "reverse"],
|
|
41
|
+
keywords: ["threat", "secret", "supply", "chain", "fuzz", "crypto", "sandbox", "malware"],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
skillName: "omk-devops-release",
|
|
45
|
+
aliases: ["devops", "release", "deploy", "ci", "cd", "github", "gh", "gh-repo", "git", "repo", "pr"],
|
|
46
|
+
keywords: ["docker", "kubernetes", "vercel", "canary", "workflow", "changelog", "version"],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
skillName: "omk-research-docs",
|
|
50
|
+
aliases: ["research", "docs", "doc", "documentation", "report", "pdf", "slides", "paper"],
|
|
51
|
+
keywords: ["citation", "literature", "academic", "write", "summarize", "evidence", "source"],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
skillName: "omk-design-media",
|
|
55
|
+
aliases: ["design", "media", "image", "video", "logo", "icon", "diagram", "asset"],
|
|
56
|
+
keywords: ["brand", "infographic", "svg", "gif", "audio", "poster", "visual", "animation"],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
skillName: "omk-agent-ops",
|
|
60
|
+
aliases: ["agent", "agents", "ops", "mcp", "skill", "skills", "headroom", "context", "memory"],
|
|
61
|
+
keywords: ["omk", "runtime", "hook", "loadout", "prompt", "harness", "adaptorch", "ouroboros"],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
skillName: "omk-product-ops",
|
|
65
|
+
aliases: ["product", "growth", "marketing", "seo", "cro", "analytics", "launch", "pricing"],
|
|
66
|
+
keywords: ["campaign", "content", "conversion", "copy", "sales", "investor", "market"],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
skillName: "omk-workspace-ops",
|
|
70
|
+
aliases: ["workspace", "gmail", "calendar", "drive", "sheets", "chat", "tasks", "email"],
|
|
71
|
+
keywords: ["google", "docs", "slides", "meet", "people", "message", "notification"],
|
|
72
|
+
},
|
|
73
|
+
];
|
|
1
74
|
export function parseBangInvocation(input, registry) {
|
|
2
75
|
if (!input.startsWith("!")) {
|
|
3
76
|
return { kind: "plain", prompt: input };
|
|
@@ -15,6 +88,10 @@ export function parseBangInvocation(input, registry) {
|
|
|
15
88
|
return command ? { kind: "bash", command, includeContext: true } : { kind: "empty" };
|
|
16
89
|
}
|
|
17
90
|
const body = input.slice(1);
|
|
91
|
+
const omkInvocation = parseOmkBangInvocation(body, registry);
|
|
92
|
+
if (omkInvocation) {
|
|
93
|
+
return omkInvocation;
|
|
94
|
+
}
|
|
18
95
|
if (body.startsWith("skill:")) {
|
|
19
96
|
const explicit = body.slice("skill:".length);
|
|
20
97
|
const { token: skillName, rest } = splitFirstToken(explicit);
|
|
@@ -48,6 +125,78 @@ export function parseBangInvocation(input, registry) {
|
|
|
48
125
|
const command = body.trim();
|
|
49
126
|
return command ? { kind: "bash", command, includeContext: true } : { kind: "empty" };
|
|
50
127
|
}
|
|
128
|
+
function parseOmkBangInvocation(body, registry) {
|
|
129
|
+
const { token, rest } = splitFirstToken(body);
|
|
130
|
+
if (normalizeOmkToken(token) !== "omk") {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const route = resolveOmkHubRoute(rest);
|
|
134
|
+
const skillName = availableOmkSkillName(route.skillName, registry);
|
|
135
|
+
if (!skillName) {
|
|
136
|
+
return { kind: "unknownSkill", skillName: route.skillName, prompt: route.prompt, source: "bang" };
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
kind: "skill",
|
|
140
|
+
skillName,
|
|
141
|
+
prompt: route.prompt,
|
|
142
|
+
activeSkillNames: activeOmkSkillNames(skillName, registry),
|
|
143
|
+
source: "bang",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function resolveOmkHubRoute(prompt) {
|
|
147
|
+
const { token, rest } = splitFirstToken(prompt);
|
|
148
|
+
const normalizedToken = normalizeOmkToken(token);
|
|
149
|
+
if (normalizedToken) {
|
|
150
|
+
const exactRoute = OMK_HUB_ROUTES.find((route) => route.aliases.includes(normalizedToken));
|
|
151
|
+
if (exactRoute) {
|
|
152
|
+
return { skillName: exactRoute.skillName, prompt: rest };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const scored = OMK_HUB_ROUTES.map((route, index) => ({ route, index, score: scoreOmkRoute(route, prompt) }))
|
|
156
|
+
.filter((entry) => entry.score > 0)
|
|
157
|
+
.sort((a, b) => b.score - a.score || a.index - b.index);
|
|
158
|
+
const best = scored[0];
|
|
159
|
+
if (best) {
|
|
160
|
+
return { skillName: best.route.skillName, prompt: prompt.trimStart() };
|
|
161
|
+
}
|
|
162
|
+
return { skillName: OMK_INDEX_SKILL, prompt: prompt.trimStart() };
|
|
163
|
+
}
|
|
164
|
+
function availableOmkSkillName(skillName, registry) {
|
|
165
|
+
if (registry.hasSkill(skillName)) {
|
|
166
|
+
return skillName;
|
|
167
|
+
}
|
|
168
|
+
if (skillName !== OMK_INDEX_SKILL && registry.hasSkill(OMK_INDEX_SKILL)) {
|
|
169
|
+
return OMK_INDEX_SKILL;
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
function activeOmkSkillNames(skillName, registry) {
|
|
174
|
+
if (skillName !== OMK_INDEX_SKILL && registry.hasSkill(OMK_INDEX_SKILL)) {
|
|
175
|
+
return [OMK_INDEX_SKILL, skillName];
|
|
176
|
+
}
|
|
177
|
+
return [skillName];
|
|
178
|
+
}
|
|
179
|
+
function scoreOmkRoute(route, prompt) {
|
|
180
|
+
const tokens = new Set(prompt
|
|
181
|
+
.split(/[^\p{L}\p{N}-]+/u)
|
|
182
|
+
.map(normalizeOmkToken)
|
|
183
|
+
.filter(Boolean));
|
|
184
|
+
let score = 0;
|
|
185
|
+
for (const alias of route.aliases) {
|
|
186
|
+
if (tokens.has(alias)) {
|
|
187
|
+
score += 4;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
for (const keyword of route.keywords) {
|
|
191
|
+
if (tokens.has(keyword)) {
|
|
192
|
+
score += 2;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return score;
|
|
196
|
+
}
|
|
197
|
+
function normalizeOmkToken(token) {
|
|
198
|
+
return token.trim().toLowerCase().replace(/^omk-/, "").replace(/_/g, "-");
|
|
199
|
+
}
|
|
51
200
|
function splitFirstToken(input) {
|
|
52
201
|
const trimmed = input.trimStart();
|
|
53
202
|
const match = /^([^\s]+)(?:\s+([\s\S]*))?$/.exec(trimmed);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bang-skill-invocation.js","sourceRoot":"","sources":["../../src/core/bang-skill-invocation.ts"],"names":[],"mappings":"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","sourcesContent":["export interface BangSkillRegistry {\n\thasSkill(name: string): boolean;\n}\n\nexport type BangInvocation =\n\t| { kind: \"plain\"; prompt: string }\n\t| { kind: \"empty\" }\n\t| { kind: \"bash\"; command: string; includeContext: boolean }\n\t| { kind: \"skill\"; skillName: string; prompt: string; activeSkillNames: readonly string[]; source: \"bang\" }\n\t| { kind: \"unknownSkill\"; skillName: string; prompt: string; source: \"bang\" };\n\nexport function parseBangInvocation(input: string, registry: BangSkillRegistry): BangInvocation {\n\tif (!input.startsWith(\"!\")) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\n\tif (input.startsWith(\"!!\")) {\n\t\tconst command = input.slice(2).trim();\n\t\treturn command ? { kind: \"bash\", command, includeContext: false } : { kind: \"empty\" };\n\t}\n\n\tconst second = input[1];\n\tif (second === undefined) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\n\tif (/\\s/.test(second)) {\n\t\tconst command = input.slice(2).trim();\n\t\treturn command ? { kind: \"bash\", command, includeContext: true } : { kind: \"empty\" };\n\t}\n\n\tconst body = input.slice(1);\n\tif (body.startsWith(\"skill:\")) {\n\t\tconst explicit = body.slice(\"skill:\".length);\n\t\tconst { token: skillName, rest } = splitFirstToken(explicit);\n\t\tif (!skillName) {\n\t\t\treturn { kind: \"plain\", prompt: input };\n\t\t}\n\t\tif (!registry.hasSkill(skillName)) {\n\t\t\treturn { kind: \"unknownSkill\", skillName, prompt: rest, source: \"bang\" };\n\t\t}\n\t\treturn {\n\t\t\tkind: \"skill\",\n\t\t\tskillName,\n\t\t\tprompt: rest,\n\t\t\tactiveSkillNames: [skillName],\n\t\t\tsource: \"bang\",\n\t\t};\n\t}\n\n\tconst { token: skillName, rest } = splitFirstToken(body);\n\tif (!skillName) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\tif (registry.hasSkill(skillName)) {\n\t\treturn {\n\t\t\tkind: \"skill\",\n\t\t\tskillName,\n\t\t\tprompt: rest,\n\t\t\tactiveSkillNames: [skillName],\n\t\t\tsource: \"bang\",\n\t\t};\n\t}\n\n\tconst command = body.trim();\n\treturn command ? { kind: \"bash\", command, includeContext: true } : { kind: \"empty\" };\n}\n\nfunction splitFirstToken(input: string): { token: string; rest: string } {\n\tconst trimmed = input.trimStart();\n\tconst match = /^([^\\s]+)(?:\\s+([\\s\\S]*))?$/.exec(trimmed);\n\tif (!match) {\n\t\treturn { token: \"\", rest: \"\" };\n\t}\n\treturn { token: match[1] ?? \"\", rest: match[2]?.trimStart() ?? \"\" };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bang-skill-invocation.js","sourceRoot":"","sources":["../../src/core/bang-skill-invocation.ts"],"names":[],"mappings":"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","sourcesContent":["export interface BangSkillRegistry {\n\thasSkill(name: string): boolean;\n}\n\nconst OMK_INDEX_SKILL = \"omk-skills\";\n\ninterface OmkHubRoute {\n\tskillName: string;\n\taliases: readonly string[];\n\tkeywords: readonly string[];\n}\n\nconst OMK_HUB_ROUTES: readonly OmkHubRoute[] = [\n\t{\n\t\tskillName: \"omk-frontend\",\n\t\taliases: [\"front\", \"frontend\", \"fe\", \"ui\", \"ux\", \"react\", \"next\", \"vue\", \"svelte\", \"tailwind\"],\n\t\tkeywords: [\n\t\t\t\"component\",\n\t\t\t\"css\",\n\t\t\t\"html\",\n\t\t\t\"responsive\",\n\t\t\t\"a11y\",\n\t\t\t\"accessibility\",\n\t\t\t\"visual\",\n\t\t\t\"browser\",\n\t\t\t\"design-system\",\n\t\t],\n\t},\n\t{\n\t\tskillName: \"omk-backend-data\",\n\t\taliases: [\"back\", \"backend\", \"api\", \"db\", \"data\", \"database\", \"server\", \"postgres\", \"supabase\", \"redis\"],\n\t\tkeywords: [\"endpoint\", \"migration\", \"schema\", \"orm\", \"cache\", \"queue\", \"service\", \"auth\", \"prisma\", \"mysql\"],\n\t},\n\t{\n\t\tskillName: \"omk-loop\",\n\t\taliases: [\"loop\", \"run\", \"runner\", \"ralph\", \"evolve\", \"orchestrate\", \"orchestration\", \"team\", \"parallel\"],\n\t\tkeywords: [\"subagent\", \"workflow\", \"pipeline\", \"goal\", \"dag\", \"ouroboros\", \"adaptorch\", \"continuous\"],\n\t},\n\t{\n\t\tskillName: \"omk-plan\",\n\t\taliases: [\"plan\", \"planning\", \"spec\", \"prd\", \"pm\", \"blueprint\", \"interview\", \"requirements\"],\n\t\tkeywords: [\"roadmap\", \"scope\", \"acceptance\", \"criteria\", \"architecture\", \"proposal\", \"tasks\", \"design\"],\n\t},\n\t{\n\t\tskillName: \"omk-engineering\",\n\t\taliases: [\"code\", \"coding\", \"engineering\", \"eng\", \"debug\", \"test\", \"refactor\", \"review\", \"ponytail\"],\n\t\tkeywords: [\"typescript\", \"python\", \"rust\", \"go\", \"build\", \"lint\", \"bug\", \"fix\", \"minimal\", \"yagni\"],\n\t},\n\t{\n\t\tskillName: \"omk-security\",\n\t\taliases: [\"sec\", \"security\", \"audit\", \"vuln\", \"vulnerability\", \"semgrep\", \"codeql\", \"reverse\"],\n\t\tkeywords: [\"threat\", \"secret\", \"supply\", \"chain\", \"fuzz\", \"crypto\", \"sandbox\", \"malware\"],\n\t},\n\t{\n\t\tskillName: \"omk-devops-release\",\n\t\taliases: [\"devops\", \"release\", \"deploy\", \"ci\", \"cd\", \"github\", \"gh\", \"gh-repo\", \"git\", \"repo\", \"pr\"],\n\t\tkeywords: [\"docker\", \"kubernetes\", \"vercel\", \"canary\", \"workflow\", \"changelog\", \"version\"],\n\t},\n\t{\n\t\tskillName: \"omk-research-docs\",\n\t\taliases: [\"research\", \"docs\", \"doc\", \"documentation\", \"report\", \"pdf\", \"slides\", \"paper\"],\n\t\tkeywords: [\"citation\", \"literature\", \"academic\", \"write\", \"summarize\", \"evidence\", \"source\"],\n\t},\n\t{\n\t\tskillName: \"omk-design-media\",\n\t\taliases: [\"design\", \"media\", \"image\", \"video\", \"logo\", \"icon\", \"diagram\", \"asset\"],\n\t\tkeywords: [\"brand\", \"infographic\", \"svg\", \"gif\", \"audio\", \"poster\", \"visual\", \"animation\"],\n\t},\n\t{\n\t\tskillName: \"omk-agent-ops\",\n\t\taliases: [\"agent\", \"agents\", \"ops\", \"mcp\", \"skill\", \"skills\", \"headroom\", \"context\", \"memory\"],\n\t\tkeywords: [\"omk\", \"runtime\", \"hook\", \"loadout\", \"prompt\", \"harness\", \"adaptorch\", \"ouroboros\"],\n\t},\n\t{\n\t\tskillName: \"omk-product-ops\",\n\t\taliases: [\"product\", \"growth\", \"marketing\", \"seo\", \"cro\", \"analytics\", \"launch\", \"pricing\"],\n\t\tkeywords: [\"campaign\", \"content\", \"conversion\", \"copy\", \"sales\", \"investor\", \"market\"],\n\t},\n\t{\n\t\tskillName: \"omk-workspace-ops\",\n\t\taliases: [\"workspace\", \"gmail\", \"calendar\", \"drive\", \"sheets\", \"chat\", \"tasks\", \"email\"],\n\t\tkeywords: [\"google\", \"docs\", \"slides\", \"meet\", \"people\", \"message\", \"notification\"],\n\t},\n];\n\nexport type BangInvocation =\n\t| { kind: \"plain\"; prompt: string }\n\t| { kind: \"empty\" }\n\t| { kind: \"bash\"; command: string; includeContext: boolean }\n\t| { kind: \"skill\"; skillName: string; prompt: string; activeSkillNames: readonly string[]; source: \"bang\" }\n\t| { kind: \"unknownSkill\"; skillName: string; prompt: string; source: \"bang\" };\n\nexport function parseBangInvocation(input: string, registry: BangSkillRegistry): BangInvocation {\n\tif (!input.startsWith(\"!\")) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\n\tif (input.startsWith(\"!!\")) {\n\t\tconst command = input.slice(2).trim();\n\t\treturn command ? { kind: \"bash\", command, includeContext: false } : { kind: \"empty\" };\n\t}\n\n\tconst second = input[1];\n\tif (second === undefined) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\n\tif (/\\s/.test(second)) {\n\t\tconst command = input.slice(2).trim();\n\t\treturn command ? { kind: \"bash\", command, includeContext: true } : { kind: \"empty\" };\n\t}\n\n\tconst body = input.slice(1);\n\tconst omkInvocation = parseOmkBangInvocation(body, registry);\n\tif (omkInvocation) {\n\t\treturn omkInvocation;\n\t}\n\n\tif (body.startsWith(\"skill:\")) {\n\t\tconst explicit = body.slice(\"skill:\".length);\n\t\tconst { token: skillName, rest } = splitFirstToken(explicit);\n\t\tif (!skillName) {\n\t\t\treturn { kind: \"plain\", prompt: input };\n\t\t}\n\t\tif (!registry.hasSkill(skillName)) {\n\t\t\treturn { kind: \"unknownSkill\", skillName, prompt: rest, source: \"bang\" };\n\t\t}\n\t\treturn {\n\t\t\tkind: \"skill\",\n\t\t\tskillName,\n\t\t\tprompt: rest,\n\t\t\tactiveSkillNames: [skillName],\n\t\t\tsource: \"bang\",\n\t\t};\n\t}\n\n\tconst { token: skillName, rest } = splitFirstToken(body);\n\tif (!skillName) {\n\t\treturn { kind: \"plain\", prompt: input };\n\t}\n\tif (registry.hasSkill(skillName)) {\n\t\treturn {\n\t\t\tkind: \"skill\",\n\t\t\tskillName,\n\t\t\tprompt: rest,\n\t\t\tactiveSkillNames: [skillName],\n\t\t\tsource: \"bang\",\n\t\t};\n\t}\n\n\tconst command = body.trim();\n\treturn command ? { kind: \"bash\", command, includeContext: true } : { kind: \"empty\" };\n}\n\nfunction parseOmkBangInvocation(body: string, registry: BangSkillRegistry): BangInvocation | null {\n\tconst { token, rest } = splitFirstToken(body);\n\tif (normalizeOmkToken(token) !== \"omk\") {\n\t\treturn null;\n\t}\n\n\tconst route = resolveOmkHubRoute(rest);\n\tconst skillName = availableOmkSkillName(route.skillName, registry);\n\tif (!skillName) {\n\t\treturn { kind: \"unknownSkill\", skillName: route.skillName, prompt: route.prompt, source: \"bang\" };\n\t}\n\n\treturn {\n\t\tkind: \"skill\",\n\t\tskillName,\n\t\tprompt: route.prompt,\n\t\tactiveSkillNames: activeOmkSkillNames(skillName, registry),\n\t\tsource: \"bang\",\n\t};\n}\n\nfunction resolveOmkHubRoute(prompt: string): { skillName: string; prompt: string } {\n\tconst { token, rest } = splitFirstToken(prompt);\n\tconst normalizedToken = normalizeOmkToken(token);\n\tif (normalizedToken) {\n\t\tconst exactRoute = OMK_HUB_ROUTES.find((route) => route.aliases.includes(normalizedToken));\n\t\tif (exactRoute) {\n\t\t\treturn { skillName: exactRoute.skillName, prompt: rest };\n\t\t}\n\t}\n\n\tconst scored = OMK_HUB_ROUTES.map((route, index) => ({ route, index, score: scoreOmkRoute(route, prompt) }))\n\t\t.filter((entry) => entry.score > 0)\n\t\t.sort((a, b) => b.score - a.score || a.index - b.index);\n\n\tconst best = scored[0];\n\tif (best) {\n\t\treturn { skillName: best.route.skillName, prompt: prompt.trimStart() };\n\t}\n\n\treturn { skillName: OMK_INDEX_SKILL, prompt: prompt.trimStart() };\n}\n\nfunction availableOmkSkillName(skillName: string, registry: BangSkillRegistry): string | null {\n\tif (registry.hasSkill(skillName)) {\n\t\treturn skillName;\n\t}\n\tif (skillName !== OMK_INDEX_SKILL && registry.hasSkill(OMK_INDEX_SKILL)) {\n\t\treturn OMK_INDEX_SKILL;\n\t}\n\treturn null;\n}\n\nfunction activeOmkSkillNames(skillName: string, registry: BangSkillRegistry): readonly string[] {\n\tif (skillName !== OMK_INDEX_SKILL && registry.hasSkill(OMK_INDEX_SKILL)) {\n\t\treturn [OMK_INDEX_SKILL, skillName];\n\t}\n\treturn [skillName];\n}\n\nfunction scoreOmkRoute(route: OmkHubRoute, prompt: string): number {\n\tconst tokens = new Set(\n\t\tprompt\n\t\t\t.split(/[^\\p{L}\\p{N}-]+/u)\n\t\t\t.map(normalizeOmkToken)\n\t\t\t.filter(Boolean),\n\t);\n\tlet score = 0;\n\tfor (const alias of route.aliases) {\n\t\tif (tokens.has(alias)) {\n\t\t\tscore += 4;\n\t\t}\n\t}\n\tfor (const keyword of route.keywords) {\n\t\tif (tokens.has(keyword)) {\n\t\t\tscore += 2;\n\t\t}\n\t}\n\treturn score;\n}\n\nfunction normalizeOmkToken(token: string): string {\n\treturn token.trim().toLowerCase().replace(/^omk-/, \"\").replace(/_/g, \"-\");\n}\n\nfunction splitFirstToken(input: string): { token: string; rest: string } {\n\tconst trimmed = input.trimStart();\n\tconst match = /^([^\\s]+)(?:\\s+([\\s\\S]*))?$/.exec(trimmed);\n\tif (!match) {\n\t\treturn { token: \"\", rest: \"\" };\n\t}\n\treturn { token: match[1] ?? \"\", rest: match[2]?.trimStart() ?? \"\" };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,wBAAgB,aAAa,IAAI,cAAc,CAM9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CA2B9F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,CAK1G;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAUzF;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,wBAAgB,aAAa,IAAI,cAAc,CAM9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CA2B9F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,CAK1G;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAUzF;AAkCD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAqDjE;AAMD,eAAO,MAAM,2BAA2B,oUAEmF,CAAC","sourcesContent":["/**\n * Shared utilities for compaction and branch summarization.\n */\n\nimport type { AgentMessage } from \"omk-agent-core\";\nimport type { Message } from \"omk-ai\";\n\n// ============================================================================\n// File Operation Tracking\n// ============================================================================\n\nexport interface FileOperations {\n\tread: Set<string>;\n\twritten: Set<string>;\n\tedited: Set<string>;\n}\n\nexport function createFileOps(): FileOperations {\n\treturn {\n\t\tread: new Set(),\n\t\twritten: new Set(),\n\t\tedited: new Set(),\n\t};\n}\n\n/**\n * Extract file operations from tool calls in an assistant message.\n */\nexport function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void {\n\tif (message.role !== \"assistant\") return;\n\tif (!(\"content\" in message) || !Array.isArray(message.content)) return;\n\n\tfor (const block of message.content) {\n\t\tif (typeof block !== \"object\" || block === null) continue;\n\t\tif (!(\"type\" in block) || block.type !== \"toolCall\") continue;\n\t\tif (!(\"arguments\" in block) || !(\"name\" in block)) continue;\n\n\t\tconst args = block.arguments as Record<string, unknown> | undefined;\n\t\tif (!args) continue;\n\n\t\tconst path = typeof args.path === \"string\" ? args.path : undefined;\n\t\tif (!path) continue;\n\n\t\tswitch (block.name) {\n\t\t\tcase \"read\":\n\t\t\t\tfileOps.read.add(path);\n\t\t\t\tbreak;\n\t\t\tcase \"write\":\n\t\t\t\tfileOps.written.add(path);\n\t\t\t\tbreak;\n\t\t\tcase \"edit\":\n\t\t\t\tfileOps.edited.add(path);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/**\n * Compute final file lists from file operations.\n * Returns readFiles (files only read, not modified) and modifiedFiles.\n */\nexport function computeFileLists(fileOps: FileOperations): { readFiles: string[]; modifiedFiles: string[] } {\n\tconst modified = new Set([...fileOps.edited, ...fileOps.written]);\n\tconst readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n\tconst modifiedFiles = [...modified].sort();\n\treturn { readFiles: readOnly, modifiedFiles };\n}\n\n/**\n * Format file operations as XML tags for summary.\n */\nexport function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string {\n\tconst sections: string[] = [];\n\tif (readFiles.length > 0) {\n\t\tsections.push(`<read-files>\\n${readFiles.join(\"\\n\")}\\n</read-files>`);\n\t}\n\tif (modifiedFiles.length > 0) {\n\t\tsections.push(`<modified-files>\\n${modifiedFiles.join(\"\\n\")}\\n</modified-files>`);\n\t}\n\tif (sections.length === 0) return \"\";\n\treturn `\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\n// ============================================================================\n// Message Serialization\n// ============================================================================\n\n/** Maximum characters for a tool result in serialized summaries. */\nconst TOOL_RESULT_MAX_CHARS = 2000;\n\n/** Maximum characters for a single serialized tool-call argument. */\nconst TOOL_CALL_ARGUMENT_MAX_CHARS = 500;\n\n/** Maximum characters for all tool calls in one assistant message. */\nconst TOOL_CALLS_MAX_CHARS = 4000;\n\n/**\n * Truncate text to a maximum character length for summarization.\n * Keeps the beginning and appends a truncation marker.\n */\nfunction truncateForSummary(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\tconst truncatedChars = text.length - maxChars;\n\treturn `${text.slice(0, maxChars)}\\n\\n[... ${truncatedChars} more characters truncated]`;\n}\n\nfunction stringifyToolCallArgument(value: unknown): string {\n\ttry {\n\t\tconst serialized = JSON.stringify(value);\n\t\treturn truncateForSummary(serialized ?? String(value), TOOL_CALL_ARGUMENT_MAX_CHARS);\n\t} catch {\n\t\treturn truncateForSummary(String(value), TOOL_CALL_ARGUMENT_MAX_CHARS);\n\t}\n}\n\n/**\n * Serialize LLM messages to text for summarization.\n * This prevents the model from treating it as a conversation to continue.\n * Call convertToLlm() first to handle custom message types.\n *\n * Tool results are truncated to keep the summarization request within\n * reasonable token budgets. Full content is not needed for summarization.\n */\nexport function serializeConversation(messages: Message[]): string {\n\tconst parts: string[] = [];\n\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tconst content =\n\t\t\t\ttypeof msg.content === \"string\"\n\t\t\t\t\t? msg.content\n\t\t\t\t\t: msg.content\n\t\t\t\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t.join(\"\");\n\t\t\tif (content) parts.push(`[User]: ${content}`);\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\tconst textParts: string[] = [];\n\t\t\tconst thinkingParts: string[] = [];\n\t\t\tconst toolCalls: string[] = [];\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\ttextParts.push(block.text);\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\tthinkingParts.push(block.thinking);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst args = block.arguments as Record<string, unknown>;\n\t\t\t\t\tconst argsStr = Object.entries(args)\n\t\t\t\t\t\t.map(([k, v]) => `${k}=${stringifyToolCallArgument(v)}`)\n\t\t\t\t\t\t.join(\", \");\n\t\t\t\t\ttoolCalls.push(`${block.name}(${argsStr})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (thinkingParts.length > 0) {\n\t\t\t\tparts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n\t\t\t}\n\t\t\tif (textParts.length > 0) {\n\t\t\t\tparts.push(`[Assistant]: ${textParts.join(\"\\n\")}`);\n\t\t\t}\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tparts.push(`[Assistant tool calls]: ${truncateForSummary(toolCalls.join(\"; \"), TOOL_CALLS_MAX_CHARS)}`);\n\t\t\t}\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst content = msg.content\n\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t\tif (content) {\n\t\t\t\tparts.push(`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn parts.join(\"\\n\\n\");\n}\n\n// ============================================================================\n// Summarization System Prompt\n// ============================================================================\n\nexport const SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\n"]}
|
|
@@ -72,6 +72,10 @@ export function formatFileOperations(readFiles, modifiedFiles) {
|
|
|
72
72
|
// ============================================================================
|
|
73
73
|
/** Maximum characters for a tool result in serialized summaries. */
|
|
74
74
|
const TOOL_RESULT_MAX_CHARS = 2000;
|
|
75
|
+
/** Maximum characters for a single serialized tool-call argument. */
|
|
76
|
+
const TOOL_CALL_ARGUMENT_MAX_CHARS = 500;
|
|
77
|
+
/** Maximum characters for all tool calls in one assistant message. */
|
|
78
|
+
const TOOL_CALLS_MAX_CHARS = 4000;
|
|
75
79
|
/**
|
|
76
80
|
* Truncate text to a maximum character length for summarization.
|
|
77
81
|
* Keeps the beginning and appends a truncation marker.
|
|
@@ -82,6 +86,15 @@ function truncateForSummary(text, maxChars) {
|
|
|
82
86
|
const truncatedChars = text.length - maxChars;
|
|
83
87
|
return `${text.slice(0, maxChars)}\n\n[... ${truncatedChars} more characters truncated]`;
|
|
84
88
|
}
|
|
89
|
+
function stringifyToolCallArgument(value) {
|
|
90
|
+
try {
|
|
91
|
+
const serialized = JSON.stringify(value);
|
|
92
|
+
return truncateForSummary(serialized ?? String(value), TOOL_CALL_ARGUMENT_MAX_CHARS);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return truncateForSummary(String(value), TOOL_CALL_ARGUMENT_MAX_CHARS);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
85
98
|
/**
|
|
86
99
|
* Serialize LLM messages to text for summarization.
|
|
87
100
|
* This prevents the model from treating it as a conversation to continue.
|
|
@@ -117,7 +130,7 @@ export function serializeConversation(messages) {
|
|
|
117
130
|
else if (block.type === "toolCall") {
|
|
118
131
|
const args = block.arguments;
|
|
119
132
|
const argsStr = Object.entries(args)
|
|
120
|
-
.map(([k, v]) => `${k}=${
|
|
133
|
+
.map(([k, v]) => `${k}=${stringifyToolCallArgument(v)}`)
|
|
121
134
|
.join(", ");
|
|
122
135
|
toolCalls.push(`${block.name}(${argsStr})`);
|
|
123
136
|
}
|
|
@@ -129,7 +142,7 @@ export function serializeConversation(messages) {
|
|
|
129
142
|
parts.push(`[Assistant]: ${textParts.join("\n")}`);
|
|
130
143
|
}
|
|
131
144
|
if (toolCalls.length > 0) {
|
|
132
|
-
parts.push(`[Assistant tool calls]: ${toolCalls.join("; ")}`);
|
|
145
|
+
parts.push(`[Assistant tool calls]: ${truncateForSummary(toolCalls.join("; "), TOOL_CALLS_MAX_CHARS)}`);
|
|
133
146
|
}
|
|
134
147
|
}
|
|
135
148
|
else if (msg.role === "toolResult") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/core/compaction/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared utilities for compaction and branch summarization.\n */\n\nimport type { AgentMessage } from \"omk-agent-core\";\nimport type { Message } from \"omk-ai\";\n\n// ============================================================================\n// File Operation Tracking\n// ============================================================================\n\nexport interface FileOperations {\n\tread: Set<string>;\n\twritten: Set<string>;\n\tedited: Set<string>;\n}\n\nexport function createFileOps(): FileOperations {\n\treturn {\n\t\tread: new Set(),\n\t\twritten: new Set(),\n\t\tedited: new Set(),\n\t};\n}\n\n/**\n * Extract file operations from tool calls in an assistant message.\n */\nexport function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void {\n\tif (message.role !== \"assistant\") return;\n\tif (!(\"content\" in message) || !Array.isArray(message.content)) return;\n\n\tfor (const block of message.content) {\n\t\tif (typeof block !== \"object\" || block === null) continue;\n\t\tif (!(\"type\" in block) || block.type !== \"toolCall\") continue;\n\t\tif (!(\"arguments\" in block) || !(\"name\" in block)) continue;\n\n\t\tconst args = block.arguments as Record<string, unknown> | undefined;\n\t\tif (!args) continue;\n\n\t\tconst path = typeof args.path === \"string\" ? args.path : undefined;\n\t\tif (!path) continue;\n\n\t\tswitch (block.name) {\n\t\t\tcase \"read\":\n\t\t\t\tfileOps.read.add(path);\n\t\t\t\tbreak;\n\t\t\tcase \"write\":\n\t\t\t\tfileOps.written.add(path);\n\t\t\t\tbreak;\n\t\t\tcase \"edit\":\n\t\t\t\tfileOps.edited.add(path);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/**\n * Compute final file lists from file operations.\n * Returns readFiles (files only read, not modified) and modifiedFiles.\n */\nexport function computeFileLists(fileOps: FileOperations): { readFiles: string[]; modifiedFiles: string[] } {\n\tconst modified = new Set([...fileOps.edited, ...fileOps.written]);\n\tconst readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n\tconst modifiedFiles = [...modified].sort();\n\treturn { readFiles: readOnly, modifiedFiles };\n}\n\n/**\n * Format file operations as XML tags for summary.\n */\nexport function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string {\n\tconst sections: string[] = [];\n\tif (readFiles.length > 0) {\n\t\tsections.push(`<read-files>\\n${readFiles.join(\"\\n\")}\\n</read-files>`);\n\t}\n\tif (modifiedFiles.length > 0) {\n\t\tsections.push(`<modified-files>\\n${modifiedFiles.join(\"\\n\")}\\n</modified-files>`);\n\t}\n\tif (sections.length === 0) return \"\";\n\treturn `\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\n// ============================================================================\n// Message Serialization\n// ============================================================================\n\n/** Maximum characters for a tool result in serialized summaries. */\nconst TOOL_RESULT_MAX_CHARS = 2000;\n\n/**\n * Truncate text to a maximum character length for summarization.\n * Keeps the beginning and appends a truncation marker.\n */\nfunction truncateForSummary(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\tconst truncatedChars = text.length - maxChars;\n\treturn `${text.slice(0, maxChars)}\\n\\n[... ${truncatedChars} more characters truncated]`;\n}\n\n/**\n * Serialize LLM messages to text for summarization.\n * This prevents the model from treating it as a conversation to continue.\n * Call convertToLlm() first to handle custom message types.\n *\n * Tool results are truncated to keep the summarization request within\n * reasonable token budgets. Full content is not needed for summarization.\n */\nexport function serializeConversation(messages: Message[]): string {\n\tconst parts: string[] = [];\n\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tconst content =\n\t\t\t\ttypeof msg.content === \"string\"\n\t\t\t\t\t? msg.content\n\t\t\t\t\t: msg.content\n\t\t\t\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t.join(\"\");\n\t\t\tif (content) parts.push(`[User]: ${content}`);\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\tconst textParts: string[] = [];\n\t\t\tconst thinkingParts: string[] = [];\n\t\t\tconst toolCalls: string[] = [];\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\ttextParts.push(block.text);\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\tthinkingParts.push(block.thinking);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst args = block.arguments as Record<string, unknown>;\n\t\t\t\t\tconst argsStr = Object.entries(args)\n\t\t\t\t\t\t.map(([k, v]) => `${k}=${JSON.stringify(v)}`)\n\t\t\t\t\t\t.join(\", \");\n\t\t\t\t\ttoolCalls.push(`${block.name}(${argsStr})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (thinkingParts.length > 0) {\n\t\t\t\tparts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n\t\t\t}\n\t\t\tif (textParts.length > 0) {\n\t\t\t\tparts.push(`[Assistant]: ${textParts.join(\"\\n\")}`);\n\t\t\t}\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tparts.push(`[Assistant tool calls]: ${toolCalls.join(\"; \")}`);\n\t\t\t}\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst content = msg.content\n\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t\tif (content) {\n\t\t\t\tparts.push(`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn parts.join(\"\\n\\n\");\n}\n\n// ============================================================================\n// Summarization System Prompt\n// ============================================================================\n\nexport const SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/core/compaction/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared utilities for compaction and branch summarization.\n */\n\nimport type { AgentMessage } from \"omk-agent-core\";\nimport type { Message } from \"omk-ai\";\n\n// ============================================================================\n// File Operation Tracking\n// ============================================================================\n\nexport interface FileOperations {\n\tread: Set<string>;\n\twritten: Set<string>;\n\tedited: Set<string>;\n}\n\nexport function createFileOps(): FileOperations {\n\treturn {\n\t\tread: new Set(),\n\t\twritten: new Set(),\n\t\tedited: new Set(),\n\t};\n}\n\n/**\n * Extract file operations from tool calls in an assistant message.\n */\nexport function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void {\n\tif (message.role !== \"assistant\") return;\n\tif (!(\"content\" in message) || !Array.isArray(message.content)) return;\n\n\tfor (const block of message.content) {\n\t\tif (typeof block !== \"object\" || block === null) continue;\n\t\tif (!(\"type\" in block) || block.type !== \"toolCall\") continue;\n\t\tif (!(\"arguments\" in block) || !(\"name\" in block)) continue;\n\n\t\tconst args = block.arguments as Record<string, unknown> | undefined;\n\t\tif (!args) continue;\n\n\t\tconst path = typeof args.path === \"string\" ? args.path : undefined;\n\t\tif (!path) continue;\n\n\t\tswitch (block.name) {\n\t\t\tcase \"read\":\n\t\t\t\tfileOps.read.add(path);\n\t\t\t\tbreak;\n\t\t\tcase \"write\":\n\t\t\t\tfileOps.written.add(path);\n\t\t\t\tbreak;\n\t\t\tcase \"edit\":\n\t\t\t\tfileOps.edited.add(path);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/**\n * Compute final file lists from file operations.\n * Returns readFiles (files only read, not modified) and modifiedFiles.\n */\nexport function computeFileLists(fileOps: FileOperations): { readFiles: string[]; modifiedFiles: string[] } {\n\tconst modified = new Set([...fileOps.edited, ...fileOps.written]);\n\tconst readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n\tconst modifiedFiles = [...modified].sort();\n\treturn { readFiles: readOnly, modifiedFiles };\n}\n\n/**\n * Format file operations as XML tags for summary.\n */\nexport function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string {\n\tconst sections: string[] = [];\n\tif (readFiles.length > 0) {\n\t\tsections.push(`<read-files>\\n${readFiles.join(\"\\n\")}\\n</read-files>`);\n\t}\n\tif (modifiedFiles.length > 0) {\n\t\tsections.push(`<modified-files>\\n${modifiedFiles.join(\"\\n\")}\\n</modified-files>`);\n\t}\n\tif (sections.length === 0) return \"\";\n\treturn `\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\n// ============================================================================\n// Message Serialization\n// ============================================================================\n\n/** Maximum characters for a tool result in serialized summaries. */\nconst TOOL_RESULT_MAX_CHARS = 2000;\n\n/** Maximum characters for a single serialized tool-call argument. */\nconst TOOL_CALL_ARGUMENT_MAX_CHARS = 500;\n\n/** Maximum characters for all tool calls in one assistant message. */\nconst TOOL_CALLS_MAX_CHARS = 4000;\n\n/**\n * Truncate text to a maximum character length for summarization.\n * Keeps the beginning and appends a truncation marker.\n */\nfunction truncateForSummary(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\tconst truncatedChars = text.length - maxChars;\n\treturn `${text.slice(0, maxChars)}\\n\\n[... ${truncatedChars} more characters truncated]`;\n}\n\nfunction stringifyToolCallArgument(value: unknown): string {\n\ttry {\n\t\tconst serialized = JSON.stringify(value);\n\t\treturn truncateForSummary(serialized ?? String(value), TOOL_CALL_ARGUMENT_MAX_CHARS);\n\t} catch {\n\t\treturn truncateForSummary(String(value), TOOL_CALL_ARGUMENT_MAX_CHARS);\n\t}\n}\n\n/**\n * Serialize LLM messages to text for summarization.\n * This prevents the model from treating it as a conversation to continue.\n * Call convertToLlm() first to handle custom message types.\n *\n * Tool results are truncated to keep the summarization request within\n * reasonable token budgets. Full content is not needed for summarization.\n */\nexport function serializeConversation(messages: Message[]): string {\n\tconst parts: string[] = [];\n\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tconst content =\n\t\t\t\ttypeof msg.content === \"string\"\n\t\t\t\t\t? msg.content\n\t\t\t\t\t: msg.content\n\t\t\t\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t.join(\"\");\n\t\t\tif (content) parts.push(`[User]: ${content}`);\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\tconst textParts: string[] = [];\n\t\t\tconst thinkingParts: string[] = [];\n\t\t\tconst toolCalls: string[] = [];\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\ttextParts.push(block.text);\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\tthinkingParts.push(block.thinking);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst args = block.arguments as Record<string, unknown>;\n\t\t\t\t\tconst argsStr = Object.entries(args)\n\t\t\t\t\t\t.map(([k, v]) => `${k}=${stringifyToolCallArgument(v)}`)\n\t\t\t\t\t\t.join(\", \");\n\t\t\t\t\ttoolCalls.push(`${block.name}(${argsStr})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (thinkingParts.length > 0) {\n\t\t\t\tparts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n\t\t\t}\n\t\t\tif (textParts.length > 0) {\n\t\t\t\tparts.push(`[Assistant]: ${textParts.join(\"\\n\")}`);\n\t\t\t}\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tparts.push(`[Assistant tool calls]: ${truncateForSummary(toolCalls.join(\"; \"), TOOL_CALLS_MAX_CHARS)}`);\n\t\t\t}\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst content = msg.content\n\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t\tif (content) {\n\t\t\t\tparts.push(`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn parts.join(\"\\n\\n\");\n}\n\n// ============================================================================\n// Summarization System Prompt\n// ============================================================================\n\nexport const SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\n"]}
|