@loom-node/amoeba 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/skill-catalog-provider.d.ts +19 -0
- package/dist/skill-catalog-provider.js +66 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type { AmoebaRuntimeConfig } from './runtime.js';
|
|
|
14
14
|
export { AuctionNoWinnerError, MitosisError, ApoptosisRejectedError } from './errors.js';
|
|
15
15
|
export { skillToNode } from './skill-node.js';
|
|
16
16
|
export { SkillNodeRegistry } from './skill-registry.js';
|
|
17
|
+
export { SkillCatalogProvider } from './skill-catalog-provider.js';
|
|
17
18
|
export { createSkillEvolver } from './skill-evolver.js';
|
|
18
19
|
export type { SkillDiscoverer } from './orchestrate-strategy.js';
|
|
19
20
|
export { AmoebaLoop } from './amoeba-loop.js';
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { AmoebaRuntime } from './runtime.js';
|
|
|
9
9
|
export { AuctionNoWinnerError, MitosisError, ApoptosisRejectedError } from './errors.js';
|
|
10
10
|
export { skillToNode } from './skill-node.js';
|
|
11
11
|
export { SkillNodeRegistry } from './skill-registry.js';
|
|
12
|
+
export { SkillCatalogProvider } from './skill-catalog-provider.js';
|
|
12
13
|
export { createSkillEvolver } from './skill-evolver.js';
|
|
13
14
|
export { AmoebaLoop } from './amoeba-loop.js';
|
|
14
15
|
export { MitosisScratchpad } from './mitosis-scratchpad.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillCatalogProvider — LLM semantic routing for progressive skill loading.
|
|
3
|
+
*
|
|
4
|
+
* Implements Progressive Disclosure as a ContextProvider:
|
|
5
|
+
* Level 1 — describeAll() summaries fed to LLM
|
|
6
|
+
* Level 2 — LLM selects best skill → loaded into SkillRegistry
|
|
7
|
+
* Level 3 — SkillProvider handles execution context
|
|
8
|
+
*/
|
|
9
|
+
import type { ContextProvider, ContextFragment, LLMProvider, SkillRegistry } from '@loom-node/core';
|
|
10
|
+
import type { SkillNodeRegistry } from './skill-registry.js';
|
|
11
|
+
export declare class SkillCatalogProvider implements ContextProvider {
|
|
12
|
+
private catalog;
|
|
13
|
+
private registry;
|
|
14
|
+
private llm;
|
|
15
|
+
readonly source: "skill";
|
|
16
|
+
constructor(catalog: SkillNodeRegistry, registry: SkillRegistry, llm: LLMProvider);
|
|
17
|
+
provide(query: string, budget: number): Promise<ContextFragment[]>;
|
|
18
|
+
private selectSkill;
|
|
19
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export class SkillCatalogProvider {
|
|
2
|
+
catalog;
|
|
3
|
+
registry;
|
|
4
|
+
llm;
|
|
5
|
+
source = 'skill';
|
|
6
|
+
constructor(catalog, registry, llm) {
|
|
7
|
+
this.catalog = catalog;
|
|
8
|
+
this.registry = registry;
|
|
9
|
+
this.llm = llm;
|
|
10
|
+
}
|
|
11
|
+
async provide(query, budget) {
|
|
12
|
+
const descs = this.catalog.describeAll()
|
|
13
|
+
.filter(d => !this.catalog.isLoaded(d.name));
|
|
14
|
+
if (descs.length === 0)
|
|
15
|
+
return [];
|
|
16
|
+
const name = await this.selectSkill(query, descs);
|
|
17
|
+
if (!name)
|
|
18
|
+
return [];
|
|
19
|
+
const skill = this.catalog.get(name);
|
|
20
|
+
if (!skill)
|
|
21
|
+
return [];
|
|
22
|
+
// Level 2: activate — load into SkillRegistry
|
|
23
|
+
this.registry.register(skill);
|
|
24
|
+
this.catalog.markLoaded(name);
|
|
25
|
+
if (!skill.instructions)
|
|
26
|
+
return [];
|
|
27
|
+
const tokens = Math.ceil(skill.instructions.length / 4);
|
|
28
|
+
if (tokens > budget)
|
|
29
|
+
return [];
|
|
30
|
+
return [{
|
|
31
|
+
source: 'skill',
|
|
32
|
+
content: skill.instructions,
|
|
33
|
+
tokens,
|
|
34
|
+
relevance: 0.9,
|
|
35
|
+
metadata: { skillName: name, reason: 'llm_semantic_route' },
|
|
36
|
+
}];
|
|
37
|
+
}
|
|
38
|
+
async selectSkill(query, skills) {
|
|
39
|
+
const listing = skills.map(s => `- ${s.name}: ${s.description}`).join('\n');
|
|
40
|
+
try {
|
|
41
|
+
const result = await this.llm.complete({
|
|
42
|
+
messages: [{
|
|
43
|
+
role: 'user',
|
|
44
|
+
content: 'You are a skill router. Given a task and available skills, ' +
|
|
45
|
+
'pick the BEST matching skill or reply null.\n\n' +
|
|
46
|
+
`Skills:\n${listing}\n\n` +
|
|
47
|
+
'Reply ONLY JSON: {"skill":"<name>"}\n' +
|
|
48
|
+
'If none match, reply: null\n\n' +
|
|
49
|
+
`Task: ${query}`,
|
|
50
|
+
}],
|
|
51
|
+
temperature: 0,
|
|
52
|
+
maxTokens: 64,
|
|
53
|
+
});
|
|
54
|
+
const match = result.content.match(/\{[\s\S]*?\}/);
|
|
55
|
+
if (!match)
|
|
56
|
+
return null;
|
|
57
|
+
const obj = JSON.parse(match[0]);
|
|
58
|
+
const picked = obj.skill ?? '';
|
|
59
|
+
const valid = new Set(skills.map(s => s.name));
|
|
60
|
+
return valid.has(picked) ? picked : null;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loom-node/amoeba",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@loom-node/core": "0.1.
|
|
21
|
+
"@loom-node/core": "0.1.2"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "tsc -b",
|