0xray 3.2.0 → 3.3.1
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/.opencode/codex.codex +1 -1
- package/dist/CHANGELOG.md +36 -0
- package/dist/core/features-config.js +3 -0
- package/dist/integrations/grok/grok-cli.js +6 -0
- package/dist/mcps/index.js +1 -0
- package/dist/mcps/knowledge-skills/skill-invocation.server.js +3 -2
- package/dist/mcps/knowledge-skills/storyteller.server.js +167 -0
- package/dist/mcps/orchestrator/config/agent-capabilities.js +30 -11
- package/dist/mcps/orchestrator/config/memory-routing-bridge.js +70 -0
- package/dist/mcps/orchestrator/execution/execution-planner.js +38 -8
- package/dist/mcps/orchestrator/handlers/task-handler.js +55 -2
- package/dist/mcps/researcher-confidence.js +92 -0
- package/dist/mcps/researcher.server.js +19 -3
- package/dist/memory-routing/index.js +4 -0
- package/dist/memory-routing/null-provider.js +63 -0
- package/dist/memory-routing/provider-loader.js +91 -0
- package/dist/memory-routing/provider-registry.js +40 -0
- package/dist/memory-routing/types.js +7 -0
- package/dist/memory-routing/validate-config.js +32 -0
- package/dist/nucleus/thin-dispatch.js +29 -1
- package/package.json +1 -1
- package/scripts/node/install-bridges.cjs +364 -0
- package/scripts/node/postinstall.cjs +24 -83
- package/scripts/node/setup.cjs +2 -6
- package/scripts/node/universal-version-manager.js +2 -2
- package/src/mcps/index.ts +1 -0
- package/src/mcps/knowledge-skills/skill-invocation.server.ts +3 -2
- package/src/mcps/knowledge-skills/storyteller.server.ts +206 -0
- package/src/mcps/orchestrator/config/agent-capabilities.ts +49 -14
- package/src/mcps/orchestrator/config/memory-routing-bridge.ts +80 -0
- package/src/mcps/orchestrator/execution/execution-planner.ts +49 -10
- package/src/mcps/orchestrator/handlers/task-handler.ts +71 -2
- package/src/mcps/orchestrator/types.ts +17 -0
- package/src/mcps/researcher-confidence.ts +144 -0
- package/src/mcps/researcher.server.ts +28 -3
- package/src/opencode/codex.codex +1 -1
package/.opencode/codex.codex
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.
|
|
2
|
+
"version": "3.3.1",
|
|
3
3
|
"terms": [
|
|
4
4
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
|
|
5
5
|
],
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Conventional Commits](https://www.conventionalcommits.org/).
|
|
6
6
|
|
|
7
|
+
## [3.3.0] - 2026-06-18
|
|
8
|
+
|
|
9
|
+
### 🔄 Changes
|
|
10
|
+
|
|
11
|
+
### 🔎 Other Changes
|
|
12
|
+
- Wire orchestrator confidence gate into execution planning (d7910b610)
|
|
13
|
+
- tweet: v3.3.0 release tweet — Pluggable Memory Routing (7fb6c9f70)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## [3.2.0] - 2026-06-17
|
|
18
|
+
|
|
19
|
+
### 🔄 Changes
|
|
20
|
+
|
|
21
|
+
### ✨ Features
|
|
22
|
+
- Orphan file resolution: 5 dead files deleted, ~39 files integrated under typecheck
|
|
23
|
+
- feat: 58 type errors fixed across 6 source files
|
|
24
|
+
- feat: pre-existing e2e failures fixed (OpenClaw 9/9, Grok CLI 62/0)
|
|
25
|
+
- feat: vitest config testTimeout added for processor-logger stability
|
|
26
|
+
- feat: pre-tool-use hook rewritten from skeleton to full hook with resonance/decision-matrix/JSON
|
|
27
|
+
- feat: SelfProposalEngine integrated under typecheck with metamorphosis type support
|
|
28
|
+
|
|
29
|
+
### 🐛 Bug Fixes
|
|
30
|
+
- fix: postinstall e2e version assertions (3.1.1 → 0.5.2)
|
|
31
|
+
- fix: AGENTS.md session entry and test assertions cleaned
|
|
32
|
+
- fix: enforcement-gate fallback dynamic imports `as string` cast
|
|
33
|
+
|
|
34
|
+
### ♻️ Refactoring
|
|
35
|
+
- chore: removed ~180 stale @version JSDoc tags from source files
|
|
36
|
+
- chore: cleaned stale version badges from README, AGENTS.md, docs-site docs
|
|
37
|
+
- chore: removed "xray 2.0" from command docs (26 files)
|
|
38
|
+
- chore: release.mjs checks npm view 0xray version (was xray)
|
|
39
|
+
- chore: release.mjs push target master → main
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
7
43
|
## [3.1.1] - 2026-06-17
|
|
8
44
|
|
|
9
45
|
### 🔄 Changes
|
|
@@ -55,6 +55,12 @@ export async function installForGrokCLI(options = {}) {
|
|
|
55
55
|
console.log(`\x1b[32m✓ Synced ${skillsCopied} builtin skills to Grok plugin\x1b[0m`);
|
|
56
56
|
}
|
|
57
57
|
frameworkLogger.log('grok-integration', 'skills-synced', 'info', { count: skillsCopied });
|
|
58
|
+
// Grok Build / Cursor also reads ~/.grok/skills/ for agent_skills
|
|
59
|
+
const globalSkillsDir = path.join(home, '.grok', 'skills');
|
|
60
|
+
const globalCopied = syncBuiltinSkills(globalSkillsDir);
|
|
61
|
+
if (globalCopied > 0) {
|
|
62
|
+
console.log(`\x1b[32m✓ Synced ${globalCopied} builtin skills to ~/.grok/skills/\x1b[0m`);
|
|
63
|
+
}
|
|
58
64
|
// Attempt auto-trust (best effort)
|
|
59
65
|
try {
|
|
60
66
|
execSync(`grok plugins trust "${targetPluginDir}"`, { stdio: 'ignore' });
|
package/dist/mcps/index.js
CHANGED
|
@@ -40,6 +40,7 @@ export const MCP_SERVERS = [
|
|
|
40
40
|
{ serverName: "refactoring-strategies", sourceFile: "mcps/knowledge-skills/refactoring-strategies.server.ts", type: "knowledge-skill", registered: true, description: "Refactoring strategies" },
|
|
41
41
|
{ serverName: "security-audit", sourceFile: "mcps/knowledge-skills/security-audit.server.ts", type: "knowledge-skill", registered: true, description: "Security auditing" },
|
|
42
42
|
{ serverName: "seo-consultant", sourceFile: "mcps/knowledge-skills/seo-consultant.server.ts", type: "knowledge-skill", registered: false, description: "SEO consulting" },
|
|
43
|
+
{ serverName: "storyteller", sourceFile: "mcps/knowledge-skills/storyteller.server.ts", type: "knowledge-skill", registered: false, description: "Reflections, sagas, and technical narratives" },
|
|
43
44
|
{ serverName: "session-management", sourceFile: "mcps/knowledge-skills/session-management.server.ts", type: "knowledge-skill", registered: true, description: "Session management" },
|
|
44
45
|
{ serverName: "skill-invocation", sourceFile: "mcps/knowledge-skills/skill-invocation.server.ts", type: "knowledge-skill", registered: true, description: "Skill invocation" },
|
|
45
46
|
{ serverName: "strategist", sourceFile: "mcps/knowledge-skills/strategist.server.ts", type: "knowledge-skill", registered: false, description: "Strategic planning" },
|
|
@@ -87,7 +87,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
|
|
|
87
87
|
"strategist", "skill-invocation",
|
|
88
88
|
];
|
|
89
89
|
const knowledgeSkills = [
|
|
90
|
-
"architecture-patterns", "strategist", "tech-writer",
|
|
90
|
+
"architecture-patterns", "strategist", "tech-writer", "storyteller",
|
|
91
91
|
"seo-consultant", "content-creator", "growth-strategist",
|
|
92
92
|
"bug-triage-specialist", "log-monitor",
|
|
93
93
|
"mobile-development", "git-workflow", "session-management",
|
|
@@ -132,6 +132,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
|
|
|
132
132
|
"tech-writer": "documentation-generation",
|
|
133
133
|
"frontend-ui-ux-engineer": "ui-ux-design",
|
|
134
134
|
"frontend-engineer": "project-analysis",
|
|
135
|
+
"storyteller": "storyteller",
|
|
135
136
|
};
|
|
136
137
|
const resolvedSkill = skillAliases[skillName] || skillName;
|
|
137
138
|
const availableServers = [
|
|
@@ -147,7 +148,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
|
|
|
147
148
|
"git-workflow", "content-creator", "ui-ux-design",
|
|
148
149
|
"multimodal-looker", "refactoring-strategies",
|
|
149
150
|
"project-analysis", "testing-best-practices",
|
|
150
|
-
"architecture-patterns",
|
|
151
|
+
"architecture-patterns", "storyteller",
|
|
151
152
|
];
|
|
152
153
|
if (!availableServers.includes(resolvedSkill)) {
|
|
153
154
|
return {
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storyteller MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Returns storyteller SKILL.md guidance plus a session-aware writing prompt.
|
|
5
|
+
* The host LLM writes the story; this server supplies the contract.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { XrayKnowledgeSkillBase } from '../shared/knowledge-skill-base.js';
|
|
12
|
+
const STORY_TYPES = ['reflection', 'saga', 'journey', 'narrative'];
|
|
13
|
+
function resolveSkillMd() {
|
|
14
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const candidates = [
|
|
16
|
+
join(here, '../../../skills/storyteller/SKILL.md'),
|
|
17
|
+
join(here, '../../skills/storyteller/SKILL.md'),
|
|
18
|
+
join(process.cwd(), 'node_modules/0xray/dist/skills/storyteller/SKILL.md'),
|
|
19
|
+
join(process.cwd(), 'node_modules/xray/dist/skills/storyteller/SKILL.md'),
|
|
20
|
+
];
|
|
21
|
+
for (const path of candidates) {
|
|
22
|
+
if (existsSync(path)) {
|
|
23
|
+
return readFileSync(path, 'utf-8');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return '# Storyteller\n\nWrite warmly candid technical reflections with scene-first openings.';
|
|
27
|
+
}
|
|
28
|
+
function getStoryMeta(storyType) {
|
|
29
|
+
const defaults = {
|
|
30
|
+
reflection: {
|
|
31
|
+
location: 'docs/reflections/',
|
|
32
|
+
min_words: 2000,
|
|
33
|
+
ideal_words: 5000,
|
|
34
|
+
framework: 'three_act_structure',
|
|
35
|
+
},
|
|
36
|
+
saga: {
|
|
37
|
+
location: 'docs/reflections/deep/',
|
|
38
|
+
min_words: 5000,
|
|
39
|
+
ideal_words: 15000,
|
|
40
|
+
framework: 'hero_journey',
|
|
41
|
+
},
|
|
42
|
+
journey: {
|
|
43
|
+
location: 'docs/reflections/deep/',
|
|
44
|
+
min_words: 1500,
|
|
45
|
+
ideal_words: 4000,
|
|
46
|
+
framework: 'three_act_structure',
|
|
47
|
+
},
|
|
48
|
+
narrative: {
|
|
49
|
+
location: 'docs/reflections/',
|
|
50
|
+
min_words: 1000,
|
|
51
|
+
ideal_words: 3000,
|
|
52
|
+
framework: 'three_act_structure',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
return defaults[storyType];
|
|
56
|
+
}
|
|
57
|
+
function gitContext() {
|
|
58
|
+
try {
|
|
59
|
+
const commits = execSync('git log --oneline -20 2>/dev/null', { encoding: 'utf-8' });
|
|
60
|
+
const files = execSync('git diff --name-only HEAD~10 2>/dev/null || git ls-files 2>/dev/null | head -50', { encoding: 'utf-8' });
|
|
61
|
+
return `Recent commits:\n${commits}\n\nRecent files:\n${files}`;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return 'No git context available in this workspace.';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function buildPrompt(storyType, title, meta, extraContext) {
|
|
68
|
+
const contextBlock = extraContext
|
|
69
|
+
? `\n## Provided context\n${JSON.stringify(extraContext, null, 2)}\n`
|
|
70
|
+
: '';
|
|
71
|
+
return `Write a ${storyType} titled "${title}".
|
|
72
|
+
|
|
73
|
+
## Requirements
|
|
74
|
+
- Framework: ${meta.framework}
|
|
75
|
+
- Target length: ${meta.ideal_words} words (minimum: ${meta.min_words})
|
|
76
|
+
- Save to: ${meta.location}
|
|
77
|
+
- Follow storyteller SKILL.md voice (warmly candid, scene-first, no executive summary)
|
|
78
|
+
- Include Key Takeaways and What Next sections
|
|
79
|
+
|
|
80
|
+
## Session / repo context
|
|
81
|
+
${gitContext()}
|
|
82
|
+
${contextBlock}
|
|
83
|
+
|
|
84
|
+
Write the complete ${storyType} now.`;
|
|
85
|
+
}
|
|
86
|
+
function writeStoryTool(storyType, args) {
|
|
87
|
+
const meta = getStoryMeta(storyType);
|
|
88
|
+
if (args.framework)
|
|
89
|
+
meta.framework = args.framework;
|
|
90
|
+
const title = args.title ??
|
|
91
|
+
`${storyType.charAt(0).toUpperCase() + storyType.slice(1)} - ${new Date().toISOString().split('T')[0]}`;
|
|
92
|
+
const skillMd = resolveSkillMd();
|
|
93
|
+
const prompt = buildPrompt(storyType, title, meta, args.context);
|
|
94
|
+
const slug = title
|
|
95
|
+
.toLowerCase()
|
|
96
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
97
|
+
.replace(/^-|-$/g, '');
|
|
98
|
+
const filename = `${storyType}-${slug}-${new Date().toISOString().split('T')[0]}.md`;
|
|
99
|
+
const outputPath = args.output ?? join(meta.location, filename);
|
|
100
|
+
const outputDir = join(process.cwd(), dirname(outputPath));
|
|
101
|
+
if (!existsSync(outputDir))
|
|
102
|
+
mkdirSync(outputDir, { recursive: true });
|
|
103
|
+
const fullPath = join(process.cwd(), outputPath);
|
|
104
|
+
const frontmatter = `---
|
|
105
|
+
story_type: ${storyType}
|
|
106
|
+
title: "${title}"
|
|
107
|
+
framework: ${meta.framework}
|
|
108
|
+
target_words: ${meta.ideal_words}
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
`;
|
|
112
|
+
writeFileSync(fullPath, `${frontmatter}\n${prompt}\n`, 'utf-8');
|
|
113
|
+
return {
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: 'text',
|
|
117
|
+
text: [
|
|
118
|
+
`Storyteller ${storyType} brief prepared.`,
|
|
119
|
+
`Output template: ${outputPath}`,
|
|
120
|
+
'',
|
|
121
|
+
'--- SKILL (excerpt) ---',
|
|
122
|
+
skillMd.slice(0, 4000),
|
|
123
|
+
skillMd.length > 4000 ? '\n...(truncated; full SKILL.md on disk)' : '',
|
|
124
|
+
'',
|
|
125
|
+
'--- WRITING PROMPT ---',
|
|
126
|
+
prompt,
|
|
127
|
+
'',
|
|
128
|
+
'Host LLM: write the full story into the output path using the prompt above.',
|
|
129
|
+
].join('\n'),
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
class StorytellerServer extends XrayKnowledgeSkillBase {
|
|
135
|
+
constructor() {
|
|
136
|
+
super('storyteller', '1.0.0');
|
|
137
|
+
const writeSchema = {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: {
|
|
140
|
+
title: { type: 'string', description: 'Story title' },
|
|
141
|
+
context: { type: 'object', description: 'Session context (commits, changes, notes)' },
|
|
142
|
+
framework: { type: 'string', description: 'Storytelling framework override' },
|
|
143
|
+
output: { type: 'string', description: 'Relative output path' },
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
this.tools = STORY_TYPES.map((storyType) => ({
|
|
147
|
+
name: `write_${storyType}`,
|
|
148
|
+
description: `Prepare ${storyType} story brief using storyteller SKILL.md`,
|
|
149
|
+
inputSchema: writeSchema,
|
|
150
|
+
}));
|
|
151
|
+
this.handlers = {
|
|
152
|
+
write_reflection: async (args) => writeStoryTool('reflection', args),
|
|
153
|
+
write_saga: async (args) => writeStoryTool('saga', args),
|
|
154
|
+
write_journey: async (args) => writeStoryTool('journey', args),
|
|
155
|
+
write_narrative: async (args) => writeStoryTool('narrative', args),
|
|
156
|
+
};
|
|
157
|
+
this.setupToolHandlers();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (import.meta.url === `file://${fileURLToPath(import.meta.url)}`) {
|
|
161
|
+
const server = new StorytellerServer();
|
|
162
|
+
server.run().catch((error) => {
|
|
163
|
+
process.stderr.write(`FATAL: ${String(error)}\n`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
export { StorytellerServer };
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Capabilities Configuration
|
|
3
3
|
*
|
|
4
|
-
* Centralized agent capability definitions for orchestration decisions
|
|
4
|
+
* Centralized agent capability definitions for orchestration decisions.
|
|
5
|
+
* Enriched at runtime by the active MemoryRoutingProvider (Repertoire, etc.).
|
|
5
6
|
*/
|
|
6
7
|
import { AGENT_REGISTRY } from "../../../agents/registry.js";
|
|
8
|
+
import { initializeMemoryRouting } from '../../../memory-routing/index.js';
|
|
9
|
+
import { getProvider, toMemoryCapabilityMap, fromMemoryCapabilityMap, } from './memory-routing-bridge.js';
|
|
7
10
|
const DEFAULT_AGENT_CAPABILITIES = Object.fromEntries(Object.entries(AGENT_REGISTRY).map(([name, entry]) => [
|
|
8
11
|
name,
|
|
9
12
|
{
|
|
@@ -12,17 +15,28 @@ const DEFAULT_AGENT_CAPABILITIES = Object.fromEntries(Object.entries(AGENT_REGIS
|
|
|
12
15
|
concurrentTasks: entry.concurrentTasks,
|
|
13
16
|
},
|
|
14
17
|
]));
|
|
18
|
+
initializeMemoryRouting();
|
|
15
19
|
/**
|
|
16
20
|
* Agent Capabilities Manager
|
|
17
21
|
* Manages agent capabilities for orchestration decisions
|
|
18
22
|
*/
|
|
19
23
|
export class AgentCapabilitiesManager {
|
|
20
24
|
capabilities = new Map();
|
|
25
|
+
enriched = false;
|
|
21
26
|
constructor() {
|
|
22
|
-
// Initialize with default capabilities
|
|
23
27
|
Object.entries(DEFAULT_AGENT_CAPABILITIES).forEach(([agent, config]) => {
|
|
24
28
|
this.capabilities.set(agent, config);
|
|
25
29
|
});
|
|
30
|
+
this.applyMemoryRoutingEnrichment();
|
|
31
|
+
}
|
|
32
|
+
applyMemoryRoutingEnrichment() {
|
|
33
|
+
const provider = getProvider();
|
|
34
|
+
if (provider.id === 'null')
|
|
35
|
+
return;
|
|
36
|
+
const memoryCaps = toMemoryCapabilityMap(this.capabilities);
|
|
37
|
+
const enriched = provider.enhanceAgentCapabilities(memoryCaps);
|
|
38
|
+
this.capabilities = fromMemoryCapabilityMap(enriched);
|
|
39
|
+
this.enriched = true;
|
|
26
40
|
}
|
|
27
41
|
/**
|
|
28
42
|
* Get capabilities for a specific agent
|
|
@@ -34,6 +48,8 @@ export class AgentCapabilitiesManager {
|
|
|
34
48
|
* Get all registered agent capabilities
|
|
35
49
|
*/
|
|
36
50
|
getAllCapabilities() {
|
|
51
|
+
if (!this.enriched)
|
|
52
|
+
this.applyMemoryRoutingEnrichment();
|
|
37
53
|
return new Map(this.capabilities);
|
|
38
54
|
}
|
|
39
55
|
/**
|
|
@@ -43,19 +59,20 @@ export class AgentCapabilitiesManager {
|
|
|
43
59
|
this.capabilities.set(agentType, capability);
|
|
44
60
|
}
|
|
45
61
|
/**
|
|
46
|
-
* Select the best agent for a task based on complexity and
|
|
62
|
+
* Select the best agent for a task based on complexity, capabilities, and memory routing.
|
|
47
63
|
*/
|
|
48
|
-
selectAgentForTask(requiredCapabilities, complexity) {
|
|
64
|
+
selectAgentForTask(requiredCapabilities, complexity, operationDescription = '') {
|
|
65
|
+
const provider = getProvider();
|
|
66
|
+
if (provider.id !== 'null' && operationDescription) {
|
|
67
|
+
const memoryCaps = toMemoryCapabilityMap(this.getAllCapabilities());
|
|
68
|
+
return provider.selectAgent(memoryCaps, requiredCapabilities, complexity, operationDescription);
|
|
69
|
+
}
|
|
49
70
|
let bestAgent = null;
|
|
50
71
|
let bestScore = -1;
|
|
51
72
|
for (const [agent, caps] of this.capabilities) {
|
|
52
|
-
|
|
53
|
-
if (complexity > caps.complexityThreshold) {
|
|
73
|
+
if (complexity > caps.complexityThreshold)
|
|
54
74
|
continue;
|
|
55
|
-
|
|
56
|
-
// Calculate capability match score
|
|
57
|
-
const matchCount = requiredCapabilities.filter(cap => caps.capabilities.includes(cap)).length;
|
|
58
|
-
// Prefer agents with more concurrent tasks available
|
|
75
|
+
const matchCount = requiredCapabilities.filter((cap) => caps.capabilities.includes(cap)).length;
|
|
59
76
|
const score = matchCount * 10 + caps.concurrentTasks;
|
|
60
77
|
if (score > bestScore) {
|
|
61
78
|
bestScore = score;
|
|
@@ -77,7 +94,6 @@ export class AgentCapabilitiesManager {
|
|
|
77
94
|
return available;
|
|
78
95
|
}
|
|
79
96
|
}
|
|
80
|
-
// Singleton instance
|
|
81
97
|
let capabilitiesManagerInstance = null;
|
|
82
98
|
export function getAgentCapabilitiesManager() {
|
|
83
99
|
if (!capabilitiesManagerInstance) {
|
|
@@ -85,3 +101,6 @@ export function getAgentCapabilitiesManager() {
|
|
|
85
101
|
}
|
|
86
102
|
return capabilitiesManagerInstance;
|
|
87
103
|
}
|
|
104
|
+
export function resetAgentCapabilitiesManager() {
|
|
105
|
+
capabilitiesManagerInstance = null;
|
|
106
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge between orchestrator types and the pluggable MemoryRoutingProvider.
|
|
3
|
+
*/
|
|
4
|
+
import { getMemoryRoutingProviderSync, } from '../../../memory-routing/index.js';
|
|
5
|
+
export function toMemoryCapability(caps) {
|
|
6
|
+
const result = {
|
|
7
|
+
capabilities: caps.capabilities,
|
|
8
|
+
complexityThreshold: caps.complexityThreshold,
|
|
9
|
+
concurrentTasks: caps.concurrentTasks,
|
|
10
|
+
};
|
|
11
|
+
if (caps.memorySignals)
|
|
12
|
+
result.memorySignals = caps.memorySignals;
|
|
13
|
+
if (caps.memoryTags)
|
|
14
|
+
result.memoryTags = caps.memoryTags;
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
export function fromMemoryCapability(caps) {
|
|
18
|
+
const result = {
|
|
19
|
+
capabilities: caps.capabilities,
|
|
20
|
+
complexityThreshold: caps.complexityThreshold,
|
|
21
|
+
concurrentTasks: caps.concurrentTasks,
|
|
22
|
+
};
|
|
23
|
+
if (caps.memorySignals)
|
|
24
|
+
result.memorySignals = caps.memorySignals;
|
|
25
|
+
if (caps.memoryTags)
|
|
26
|
+
result.memoryTags = caps.memoryTags;
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
export function toMemoryTask(task) {
|
|
30
|
+
const result = {
|
|
31
|
+
id: task.id,
|
|
32
|
+
description: task.description,
|
|
33
|
+
type: task.type,
|
|
34
|
+
};
|
|
35
|
+
if (task.priority)
|
|
36
|
+
result.priority = task.priority;
|
|
37
|
+
if (task.dependencies)
|
|
38
|
+
result.dependencies = task.dependencies;
|
|
39
|
+
if (task.estimatedComplexity !== undefined)
|
|
40
|
+
result.estimatedComplexity = task.estimatedComplexity;
|
|
41
|
+
if (task.metadata)
|
|
42
|
+
result.metadata = task.metadata;
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
export function fromMemoryTask(task) {
|
|
46
|
+
const result = {
|
|
47
|
+
id: task.id,
|
|
48
|
+
description: task.description,
|
|
49
|
+
type: task.type,
|
|
50
|
+
};
|
|
51
|
+
if (task.priority)
|
|
52
|
+
result.priority = task.priority;
|
|
53
|
+
if (task.dependencies)
|
|
54
|
+
result.dependencies = task.dependencies;
|
|
55
|
+
if (task.estimatedComplexity !== undefined)
|
|
56
|
+
result.estimatedComplexity = task.estimatedComplexity;
|
|
57
|
+
const metadata = task.metadata;
|
|
58
|
+
if (metadata)
|
|
59
|
+
result.metadata = metadata;
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
export function toMemoryCapabilityMap(caps) {
|
|
63
|
+
return new Map(Array.from(caps.entries()).map(([k, v]) => [k, toMemoryCapability(v)]));
|
|
64
|
+
}
|
|
65
|
+
export function fromMemoryCapabilityMap(caps) {
|
|
66
|
+
return new Map(Array.from(caps.entries()).map(([k, v]) => [k, fromMemoryCapability(v)]));
|
|
67
|
+
}
|
|
68
|
+
export function getProvider() {
|
|
69
|
+
return getMemoryRoutingProviderSync();
|
|
70
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Creates optimized execution plans for orchestration tasks
|
|
5
5
|
*/
|
|
6
6
|
import { getAgentCapabilitiesManager } from '../config/agent-capabilities.js';
|
|
7
|
+
import { getProvider, toMemoryTask, fromMemoryTask, } from '../config/memory-routing-bridge.js';
|
|
7
8
|
/**
|
|
8
9
|
* Execution Planner
|
|
9
10
|
* Plans and optimizes task execution strategies
|
|
@@ -48,26 +49,35 @@ export class ExecutionPlanner {
|
|
|
48
49
|
* Create an execution plan based on tasks and mode
|
|
49
50
|
*/
|
|
50
51
|
async createExecutionPlan(tasks, executionMode) {
|
|
52
|
+
const provider = getProvider();
|
|
53
|
+
const memoryTasks = provider.enrichTasks(tasks.map(toMemoryTask));
|
|
54
|
+
const enrichedTasks = memoryTasks.map(fromMemoryTask);
|
|
51
55
|
const agentAssignments = new Map();
|
|
52
56
|
switch (executionMode) {
|
|
53
57
|
case 'parallel':
|
|
54
|
-
this.createParallelPlan(
|
|
58
|
+
this.createParallelPlan(enrichedTasks, agentAssignments);
|
|
55
59
|
break;
|
|
56
60
|
case 'sequential':
|
|
57
|
-
this.createSequentialPlan(
|
|
61
|
+
this.createSequentialPlan(enrichedTasks, agentAssignments);
|
|
58
62
|
break;
|
|
59
63
|
case 'optimized':
|
|
60
64
|
default:
|
|
61
|
-
await this.createOptimizedPlan(
|
|
65
|
+
await this.createOptimizedPlan(enrichedTasks, agentAssignments);
|
|
62
66
|
break;
|
|
63
67
|
}
|
|
64
68
|
const estimatedDuration = this.estimateExecutionDuration(agentAssignments);
|
|
65
|
-
|
|
66
|
-
tasks,
|
|
69
|
+
const plan = {
|
|
70
|
+
tasks: enrichedTasks,
|
|
67
71
|
strategy: executionMode,
|
|
68
72
|
agentAssignments,
|
|
69
73
|
estimatedDuration,
|
|
70
74
|
};
|
|
75
|
+
if (provider.id !== 'null') {
|
|
76
|
+
plan.memoryContext = {
|
|
77
|
+
...provider.buildInheritedContext(memoryTasks),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return plan;
|
|
71
81
|
}
|
|
72
82
|
/**
|
|
73
83
|
* Create a parallel execution plan
|
|
@@ -149,8 +159,15 @@ export class ExecutionPlanner {
|
|
|
149
159
|
*/
|
|
150
160
|
assignTasksToAgents(tasks, agentAssignments) {
|
|
151
161
|
for (const task of tasks) {
|
|
152
|
-
const complexity = task
|
|
153
|
-
const
|
|
162
|
+
const complexity = this.calculateTaskComplexity(task);
|
|
163
|
+
const requiredCaps = [
|
|
164
|
+
task.type,
|
|
165
|
+
...(task.metadata?.memorySignals ?? []),
|
|
166
|
+
];
|
|
167
|
+
const operationDescription = task.metadata?.memoryHighConfidenceTrap
|
|
168
|
+
? `${task.description} TYPE: ontological-trap`
|
|
169
|
+
: task.description;
|
|
170
|
+
const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, operationDescription) || 'orchestrator';
|
|
154
171
|
if (!agentAssignments.has(agent)) {
|
|
155
172
|
agentAssignments.set(agent, []);
|
|
156
173
|
}
|
|
@@ -188,7 +205,11 @@ export class ExecutionPlanner {
|
|
|
188
205
|
category: task.type,
|
|
189
206
|
});
|
|
190
207
|
// Assign to agent
|
|
191
|
-
const
|
|
208
|
+
const requiredCaps = [
|
|
209
|
+
task.type,
|
|
210
|
+
...(task.metadata?.memorySignals ?? []),
|
|
211
|
+
];
|
|
212
|
+
const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, task.description) || 'orchestrator';
|
|
192
213
|
if (!assignments.has(agent)) {
|
|
193
214
|
assignments.set(agent, []);
|
|
194
215
|
}
|
|
@@ -246,6 +267,15 @@ export class ExecutionPlanner {
|
|
|
246
267
|
if (task.dependencies) {
|
|
247
268
|
complexity += task.dependencies.length * 5;
|
|
248
269
|
}
|
|
270
|
+
if (task.metadata?.memoryComplexityBoost !== undefined) {
|
|
271
|
+
complexity += task.metadata.memoryComplexityBoost;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
const provider = getProvider();
|
|
275
|
+
if (provider.id !== 'null' && provider.getTaskConfidence) {
|
|
276
|
+
complexity += provider.getTaskConfidence(toMemoryTask(task)).complexityBoost;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
249
279
|
return Math.min(Math.max(Math.round(complexity), 1), 100);
|
|
250
280
|
}
|
|
251
281
|
/**
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import { frameworkLogger } from '../../../core/framework-logger.js';
|
|
7
7
|
import { getExecutionPlanner } from '../execution/execution-planner.js';
|
|
8
8
|
import { mcpClientManager } from '../../../mcps/mcp-client.js';
|
|
9
|
-
import { addObservations, extractOrchestrationObservations } from '../aside-context.js';
|
|
9
|
+
import { addObservations, extractOrchestrationObservations, spawnAside } from '../aside-context.js';
|
|
10
|
+
import { getProvider } from '../config/memory-routing-bridge.js';
|
|
10
11
|
/**
|
|
11
12
|
* Task Handler
|
|
12
13
|
* Processes orchestrate-task requests
|
|
@@ -38,8 +39,37 @@ export class TaskHandler {
|
|
|
38
39
|
}
|
|
39
40
|
// Analyze complexity and create execution plan
|
|
40
41
|
const executionPlan = await this.planner.createExecutionPlan(tasks, executionMode);
|
|
42
|
+
const memoryProvider = getProvider();
|
|
43
|
+
if (memoryProvider.id !== 'null' && executionPlan.memoryContext) {
|
|
44
|
+
await spawnAside({
|
|
45
|
+
description: `Orchestrate: ${description}`,
|
|
46
|
+
sessionId,
|
|
47
|
+
inheritedContext: {
|
|
48
|
+
memoryRouting: executionPlan.memoryContext,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
41
52
|
// Execute orchestration (simulated for MCP server)
|
|
42
53
|
const results = await this.executePlan(executionPlan, sessionId, timeout);
|
|
54
|
+
// Feed per-task outcomes back to memory provider (not aggregate session stats)
|
|
55
|
+
if (memoryProvider.ingestFeedback) {
|
|
56
|
+
const outcomeByKey = new Map(results.taskOutcomes.map((o) => [`${o.agent}:${o.taskId}`, o]));
|
|
57
|
+
for (const [agent, assignedTasks] of executionPlan.agentAssignments) {
|
|
58
|
+
for (const task of assignedTasks) {
|
|
59
|
+
const outcome = outcomeByKey.get(`${agent}:${task.id}`);
|
|
60
|
+
memoryProvider.ingestFeedback({
|
|
61
|
+
timestamp: new Date().toISOString(),
|
|
62
|
+
sessionId,
|
|
63
|
+
taskId: task.id,
|
|
64
|
+
assignedAgent: agent,
|
|
65
|
+
memorySignals: task.metadata?.memorySignals ?? [],
|
|
66
|
+
complexity: task.estimatedComplexity ?? 30,
|
|
67
|
+
success: outcome?.success ?? false,
|
|
68
|
+
durationMs: outcome?.durationMs ?? 0,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
43
73
|
// Update result
|
|
44
74
|
orchestrationResult.success = results.success;
|
|
45
75
|
orchestrationResult.completedTasks = results.completedTasks;
|
|
@@ -82,6 +112,7 @@ export class TaskHandler {
|
|
|
82
112
|
let completedTasks = 0;
|
|
83
113
|
let failedTasks = 0;
|
|
84
114
|
const agentOutputs = {};
|
|
115
|
+
const taskOutcomes = [];
|
|
85
116
|
const skillServers = new Set([
|
|
86
117
|
'code-review', 'code-reviewer',
|
|
87
118
|
'security-audit', 'security-auditor',
|
|
@@ -96,6 +127,7 @@ export class TaskHandler {
|
|
|
96
127
|
agentUtilization[agent] = tasks.length;
|
|
97
128
|
if (skillServers.has(agent)) {
|
|
98
129
|
for (const task of tasks) {
|
|
130
|
+
const taskStart = Date.now();
|
|
99
131
|
try {
|
|
100
132
|
const toolName = this.mapAgentToTool(agent);
|
|
101
133
|
const result = await mcpClientManager.callServerTool(agent, toolName, {
|
|
@@ -106,10 +138,22 @@ export class TaskHandler {
|
|
|
106
138
|
const outputText = this.extractTextFromMcpResult(result);
|
|
107
139
|
agentOutputs[`${agent}:${task.id}`] = outputText;
|
|
108
140
|
completedTasks++;
|
|
141
|
+
taskOutcomes.push({
|
|
142
|
+
taskId: task.id,
|
|
143
|
+
agent,
|
|
144
|
+
success: true,
|
|
145
|
+
durationMs: Date.now() - taskStart,
|
|
146
|
+
});
|
|
109
147
|
}
|
|
110
148
|
catch (err) {
|
|
111
149
|
failedTasks++;
|
|
112
150
|
agentOutputs[`${agent}:${task.id}`] = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
151
|
+
taskOutcomes.push({
|
|
152
|
+
taskId: task.id,
|
|
153
|
+
agent,
|
|
154
|
+
success: false,
|
|
155
|
+
durationMs: Date.now() - taskStart,
|
|
156
|
+
});
|
|
113
157
|
frameworkLogger.log('orchestrator.task-handler', 'task-execution-failed', 'warning', {
|
|
114
158
|
agent,
|
|
115
159
|
taskId: task.id,
|
|
@@ -120,7 +164,15 @@ export class TaskHandler {
|
|
|
120
164
|
}
|
|
121
165
|
else {
|
|
122
166
|
// For non-MCP agents we still count them as "assigned" (they will be handled by the caller or legacy path)
|
|
123
|
-
|
|
167
|
+
for (const task of tasks) {
|
|
168
|
+
completedTasks++;
|
|
169
|
+
taskOutcomes.push({
|
|
170
|
+
taskId: task.id,
|
|
171
|
+
agent,
|
|
172
|
+
success: true,
|
|
173
|
+
durationMs: 0,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
124
176
|
}
|
|
125
177
|
}
|
|
126
178
|
const recommendations = [];
|
|
@@ -141,6 +193,7 @@ export class TaskHandler {
|
|
|
141
193
|
bottlenecks,
|
|
142
194
|
recommendations,
|
|
143
195
|
agentOutputs,
|
|
196
|
+
taskOutcomes,
|
|
144
197
|
};
|
|
145
198
|
}
|
|
146
199
|
mapAgentToTool(agent) {
|