agentbnb 5.1.11 → 6.0.0
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/{card-RSGDCHCV.js → card-REW7BSWW.js} +1 -1
- package/dist/{chunk-EPIWHNB2.js → chunk-2TLZ6G2B.js} +446 -373
- package/dist/{chunk-WGZ5AGOX.js → chunk-3CIMVISQ.js} +24 -1
- package/dist/{chunk-NH2FIERR.js → chunk-574W3HHE.js} +1 -1
- package/dist/{chunk-B5FTAGFN.js → chunk-7XHDSWRD.js} +75 -75
- package/dist/{chunk-NLAWT4DT.js → chunk-7YLFLC5C.js} +6 -6
- package/dist/chunk-BP3L2TET.js +148 -0
- package/dist/{chunk-EGUOAHCW.js → chunk-C2T4BMRW.js} +12 -12
- package/dist/{chunk-5KFI5X7B.js → chunk-F53QQIM2.js} +1 -1
- package/dist/chunk-JR6TJDIF.js +425 -0
- package/dist/{chunk-DFBX3BBD.js → chunk-KA2VIEGM.js} +211 -16
- package/dist/chunk-NQTE577Q.js +159 -0
- package/dist/{chunk-WTXRY7R2.js → chunk-NYV3NE5Z.js} +157 -9
- package/dist/{chunk-UKT6H7YT.js → chunk-OZXCRLP3.js} +1 -1
- package/dist/{chunk-QITOPASZ.js → chunk-PSQHUZ7X.js} +1 -1
- package/dist/{chunk-EANI2N2V.js → chunk-RVYQSC6L.js} +2 -99
- package/dist/{chunk-MLS6IGGG.js → chunk-TQDV254A.js} +1 -1
- package/dist/{chunk-QQFBFV4V.js → chunk-TR6UZDNX.js} +57 -18
- package/dist/{chunk-ZX5623ER.js → chunk-VMH2YS2I.js} +1 -1
- package/dist/{chunk-XND2DWTZ.js → chunk-VPQ44XKE.js} +2 -2
- package/dist/{chunk-CSATDXZC.js → chunk-Y7T6IMM3.js} +1 -1
- package/dist/{chunk-FLY3WIQR.js → chunk-YRRVFTDR.js} +3 -3
- package/dist/cli/index.js +261 -125
- package/dist/{client-T5MTY3CS.js → client-HRYRJKSA.js} +3 -3
- package/dist/{conduct-WU3VEXB6.js → conduct-LF6FYPLD.js} +11 -11
- package/dist/conduct-QAFZIEY6.js +21 -0
- package/dist/{conductor-mode-ZMTFZGJP.js → conductor-mode-NUDQLZFM.js} +309 -13
- package/dist/conductor-mode-YQ6QSPPT.js +275 -0
- package/dist/{execute-4D4ITQCL.js → execute-ITHIYYOX.js} +4 -3
- package/dist/execute-PNJFABVJ.js +14 -0
- package/dist/index.d.ts +555 -0
- package/dist/index.js +592 -83
- package/dist/{process-guard-CC7CNRQJ.js → process-guard-QCCBGILS.js} +1 -1
- package/dist/publish-capability-TS6CNR5G.js +12 -0
- package/dist/{request-VOXBFUOG.js → request-P6QCTCCG.js} +14 -14
- package/dist/{serve-skill-IH7UAJNR.js → serve-skill-EZOL7UYN.js} +10 -9
- package/dist/{server-JVQW2TID.js → server-3G6ZTASA.js} +16 -16
- package/dist/{service-coordinator-EYRDTHL5.js → service-coordinator-CRSE4GWC.js} +174 -242
- package/dist/skill-config-4W5W5O6T.js +22 -0
- package/dist/skills/agentbnb/bootstrap.js +227 -67
- package/package.json +1 -1
- package/skills/agentbnb/SKILL.md +35 -0
- package/skills/agentbnb/bootstrap.ts +126 -8
- package/skills/agentbnb/install.sh +49 -9
- package/dist/chunk-CRFCWD6V.js +0 -366
- package/dist/conduct-6LKIJJKQ.js +0 -21
- package/dist/conductor-mode-Q4IIDY5E.js +0 -123
- package/dist/execute-T7Y6RKSW.js +0 -13
|
@@ -3,16 +3,154 @@ import {
|
|
|
3
3
|
interpolateObject,
|
|
4
4
|
requestCapability,
|
|
5
5
|
searchCards
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7XHDSWRD.js";
|
|
7
7
|
import "./chunk-HLUEOLSZ.js";
|
|
8
|
-
import "./chunk-IVOYM3WG.js";
|
|
9
8
|
import {
|
|
10
|
-
getBalance
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
getBalance,
|
|
10
|
+
getCardsByCapabilityType,
|
|
11
|
+
getCardsBySkillCapability
|
|
12
|
+
} from "./chunk-2TLZ6G2B.js";
|
|
13
|
+
import "./chunk-IVOYM3WG.js";
|
|
14
|
+
import "./chunk-3CIMVISQ.js";
|
|
13
15
|
|
|
14
16
|
// src/conductor/task-decomposer.ts
|
|
15
17
|
import { randomUUID } from "crypto";
|
|
18
|
+
|
|
19
|
+
// src/conductor/decomposition-validator.ts
|
|
20
|
+
function validateAndNormalizeSubtasks(raw, context) {
|
|
21
|
+
try {
|
|
22
|
+
return _validate(raw, context);
|
|
23
|
+
} catch {
|
|
24
|
+
return { valid: [], errors: ["internal validation error"] };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function _validate(raw, context) {
|
|
28
|
+
if (!Array.isArray(raw)) {
|
|
29
|
+
return { valid: [], errors: ["decomposition output must be an array"] };
|
|
30
|
+
}
|
|
31
|
+
if (raw.length === 0) {
|
|
32
|
+
return { valid: [], errors: [] };
|
|
33
|
+
}
|
|
34
|
+
const errors = [];
|
|
35
|
+
const validItems = [];
|
|
36
|
+
const validIds = [];
|
|
37
|
+
for (let i = 0; i < raw.length; i++) {
|
|
38
|
+
const item = raw[i];
|
|
39
|
+
if (typeof item !== "object" || item === null || Array.isArray(item)) {
|
|
40
|
+
errors.push(`subtask[${i}]: must be an object`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const obj = item;
|
|
44
|
+
let itemValid = true;
|
|
45
|
+
const id = obj["id"];
|
|
46
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
47
|
+
errors.push(`subtask[${i}]: id must be a non-empty string`);
|
|
48
|
+
itemValid = false;
|
|
49
|
+
}
|
|
50
|
+
const description = obj["description"];
|
|
51
|
+
if (typeof description !== "string" || description.length === 0) {
|
|
52
|
+
errors.push(`subtask[${i}]: description must be a non-empty string`);
|
|
53
|
+
itemValid = false;
|
|
54
|
+
}
|
|
55
|
+
const required_capability = obj["required_capability"];
|
|
56
|
+
if (typeof required_capability !== "string" || required_capability.length === 0) {
|
|
57
|
+
errors.push(`subtask[${i}]: required_capability must be a non-empty string`);
|
|
58
|
+
itemValid = false;
|
|
59
|
+
}
|
|
60
|
+
const estimated_credits = obj["estimated_credits"];
|
|
61
|
+
if (estimated_credits !== void 0) {
|
|
62
|
+
if (typeof estimated_credits !== "number" || estimated_credits <= 0) {
|
|
63
|
+
errors.push(`subtask[${i}]: estimated_credits must be a positive number`);
|
|
64
|
+
itemValid = false;
|
|
65
|
+
} else if (estimated_credits > context.max_credits) {
|
|
66
|
+
errors.push(
|
|
67
|
+
`subtask[${i}]: estimated_credits ${estimated_credits} exceeds max_credits ${context.max_credits}`
|
|
68
|
+
);
|
|
69
|
+
itemValid = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (itemValid) {
|
|
73
|
+
validItems.push(obj);
|
|
74
|
+
validIds.push(id);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const idSet = /* @__PURE__ */ new Set();
|
|
78
|
+
for (const id of validIds) {
|
|
79
|
+
if (idSet.has(id)) {
|
|
80
|
+
errors.push(`duplicate subtask id: ${id}`);
|
|
81
|
+
} else {
|
|
82
|
+
idSet.add(id);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (let i = 0; i < validItems.length; i++) {
|
|
86
|
+
const item = validItems[i];
|
|
87
|
+
const depends_on = item["depends_on"];
|
|
88
|
+
if (!Array.isArray(depends_on)) continue;
|
|
89
|
+
for (const dep of depends_on) {
|
|
90
|
+
if (typeof dep === "string" && !idSet.has(dep)) {
|
|
91
|
+
errors.push(`subtask[${i}]: depends_on references unknown id '${dep}'`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (errors.length === 0 && validItems.length > 0) {
|
|
96
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
97
|
+
const adjList = /* @__PURE__ */ new Map();
|
|
98
|
+
for (const id of validIds) {
|
|
99
|
+
inDegree.set(id, 0);
|
|
100
|
+
adjList.set(id, []);
|
|
101
|
+
}
|
|
102
|
+
for (const item of validItems) {
|
|
103
|
+
const depends_on = item["depends_on"];
|
|
104
|
+
if (!Array.isArray(depends_on)) continue;
|
|
105
|
+
for (const dep of depends_on) {
|
|
106
|
+
if (typeof dep !== "string" || !idSet.has(dep)) continue;
|
|
107
|
+
adjList.get(dep)?.push(item["id"]);
|
|
108
|
+
inDegree.set(item["id"], (inDegree.get(item["id"]) ?? 0) + 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const queue = [];
|
|
112
|
+
for (const [id, deg] of inDegree) {
|
|
113
|
+
if (deg === 0) queue.push(id);
|
|
114
|
+
}
|
|
115
|
+
let processed = 0;
|
|
116
|
+
while (queue.length > 0) {
|
|
117
|
+
const current = queue.shift();
|
|
118
|
+
processed++;
|
|
119
|
+
for (const neighbor of adjList.get(current) ?? []) {
|
|
120
|
+
const newDeg = (inDegree.get(neighbor) ?? 0) - 1;
|
|
121
|
+
inDegree.set(neighbor, newDeg);
|
|
122
|
+
if (newDeg === 0) queue.push(neighbor);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (processed < validItems.length) {
|
|
126
|
+
for (const [id, deg] of inDegree) {
|
|
127
|
+
if (deg > 0) {
|
|
128
|
+
errors.push(`circular dependency detected involving subtask id: ${id}`);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (errors.length > 0) {
|
|
135
|
+
return { valid: [], errors };
|
|
136
|
+
}
|
|
137
|
+
const normalized = validItems.map((item) => {
|
|
138
|
+
const depends_on = Array.isArray(item["depends_on"]) ? item["depends_on"].filter((x) => typeof x === "string") : [];
|
|
139
|
+
const params = typeof item["params"] === "object" && item["params"] !== null && !Array.isArray(item["params"]) ? item["params"] : {};
|
|
140
|
+
const estimated_credits = typeof item["estimated_credits"] === "number" ? item["estimated_credits"] : 0;
|
|
141
|
+
return {
|
|
142
|
+
id: item["id"],
|
|
143
|
+
description: item["description"],
|
|
144
|
+
required_capability: item["required_capability"],
|
|
145
|
+
params,
|
|
146
|
+
depends_on,
|
|
147
|
+
estimated_credits
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
return { valid: normalized, errors: [] };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/conductor/task-decomposer.ts
|
|
16
154
|
var TEMPLATES = {
|
|
17
155
|
"video-production": {
|
|
18
156
|
keywords: ["video", "demo", "clip", "animation"],
|
|
@@ -362,6 +500,12 @@ function computeWaves(subtasks) {
|
|
|
362
500
|
async function orchestrate(opts) {
|
|
363
501
|
const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs = 3e5, maxBudget, relayClient, requesterOwner } = opts;
|
|
364
502
|
const startTime = Date.now();
|
|
503
|
+
const teamMemberMap = /* @__PURE__ */ new Map();
|
|
504
|
+
if (opts.team) {
|
|
505
|
+
for (const member of opts.team.matched) {
|
|
506
|
+
teamMemberMap.set(member.subtask.id, member);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
365
509
|
if (subtasks.length === 0) {
|
|
366
510
|
return {
|
|
367
511
|
success: true,
|
|
@@ -373,6 +517,7 @@ async function orchestrate(opts) {
|
|
|
373
517
|
const results = /* @__PURE__ */ new Map();
|
|
374
518
|
const errors = [];
|
|
375
519
|
let totalCredits = 0;
|
|
520
|
+
const traceContext = /* @__PURE__ */ new Map();
|
|
376
521
|
const waves = computeWaves(subtasks);
|
|
377
522
|
const subtaskMap = new Map(subtasks.map((s) => [s.id, s]));
|
|
378
523
|
for (const wave of waves) {
|
|
@@ -409,7 +554,11 @@ async function orchestrate(opts) {
|
|
|
409
554
|
subtask.params,
|
|
410
555
|
interpContext
|
|
411
556
|
);
|
|
412
|
-
const
|
|
557
|
+
const teamMember = teamMemberMap.get(taskId);
|
|
558
|
+
const teamId = opts.team?.team_id ?? null;
|
|
559
|
+
const taskCapabilityType = teamMember?.capability_type ?? null;
|
|
560
|
+
const agentOwner = teamMember?.agent ?? m.selected_agent;
|
|
561
|
+
const primary = resolveAgentUrl(agentOwner);
|
|
413
562
|
try {
|
|
414
563
|
let res;
|
|
415
564
|
if (primary.url.startsWith("relay://") && relayClient) {
|
|
@@ -430,7 +579,7 @@ async function orchestrate(opts) {
|
|
|
430
579
|
timeoutMs
|
|
431
580
|
});
|
|
432
581
|
}
|
|
433
|
-
return { taskId, result: res, credits: m.credits };
|
|
582
|
+
return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: taskCapabilityType };
|
|
434
583
|
} catch (primaryErr) {
|
|
435
584
|
if (m.alternatives.length > 0) {
|
|
436
585
|
const alt = m.alternatives[0];
|
|
@@ -455,7 +604,7 @@ async function orchestrate(opts) {
|
|
|
455
604
|
timeoutMs
|
|
456
605
|
});
|
|
457
606
|
}
|
|
458
|
-
return { taskId, result: altRes, credits: alt.credits };
|
|
607
|
+
return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: taskCapabilityType };
|
|
459
608
|
} catch (altErr) {
|
|
460
609
|
throw new Error(
|
|
461
610
|
`Task ${taskId}: primary (${m.selected_agent}) failed: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}; alternative (${alt.agent}) failed: ${altErr instanceof Error ? altErr.message : String(altErr)}`
|
|
@@ -470,9 +619,10 @@ async function orchestrate(opts) {
|
|
|
470
619
|
);
|
|
471
620
|
for (const settlement of waveResults) {
|
|
472
621
|
if (settlement.status === "fulfilled") {
|
|
473
|
-
const { taskId, result, credits } = settlement.value;
|
|
622
|
+
const { taskId, result, credits, team_id, capability_type } = settlement.value;
|
|
474
623
|
results.set(taskId, result);
|
|
475
624
|
totalCredits += credits;
|
|
625
|
+
traceContext.set(taskId, { team_id: team_id ?? null, capability_type: capability_type ?? null });
|
|
476
626
|
} else {
|
|
477
627
|
errors.push(settlement.reason instanceof Error ? settlement.reason.message : String(settlement.reason));
|
|
478
628
|
}
|
|
@@ -483,10 +633,101 @@ async function orchestrate(opts) {
|
|
|
483
633
|
results,
|
|
484
634
|
total_credits: totalCredits,
|
|
485
635
|
latency_ms: Date.now() - startTime,
|
|
486
|
-
errors: errors.length > 0 ? errors : void 0
|
|
636
|
+
errors: errors.length > 0 ? errors : void 0,
|
|
637
|
+
trace: traceContext.size > 0 ? traceContext : void 0
|
|
487
638
|
};
|
|
488
639
|
}
|
|
489
640
|
|
|
641
|
+
// src/conductor/team-formation.ts
|
|
642
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
643
|
+
function selectByStrategy(matches, strategy) {
|
|
644
|
+
if (matches.length === 0) return void 0;
|
|
645
|
+
if (strategy === "balanced") {
|
|
646
|
+
return matches[0];
|
|
647
|
+
}
|
|
648
|
+
if (strategy === "quality_optimized") {
|
|
649
|
+
return matches.reduce((best, m) => m.score > best.score ? m : best, matches[0]);
|
|
650
|
+
}
|
|
651
|
+
return matches.reduce((best, m) => {
|
|
652
|
+
if (m.credits < best.credits) return m;
|
|
653
|
+
if (m.credits === best.credits && m.score > best.score) return m;
|
|
654
|
+
return best;
|
|
655
|
+
}, matches[0]);
|
|
656
|
+
}
|
|
657
|
+
async function formTeam(opts) {
|
|
658
|
+
const { subtasks, strategy, db, conductorOwner, registryUrl } = opts;
|
|
659
|
+
const team_id = randomUUID2();
|
|
660
|
+
if (subtasks.length === 0) {
|
|
661
|
+
return { team_id, strategy, matched: [], unrouted: [] };
|
|
662
|
+
}
|
|
663
|
+
const matched = [];
|
|
664
|
+
const unrouted = [];
|
|
665
|
+
for (const subtask of subtasks) {
|
|
666
|
+
const skillCards = getCardsBySkillCapability(db, subtask.required_capability).filter((c) => c.owner !== conductorOwner);
|
|
667
|
+
if (skillCards.length > 0) {
|
|
668
|
+
const candidates = skillCards.map((card) => {
|
|
669
|
+
const skills = card.skills ?? [];
|
|
670
|
+
const matchingSkill = skills.find(
|
|
671
|
+
(s) => s.capability_type === subtask.required_capability || (s.capability_types ?? []).includes(subtask.required_capability)
|
|
672
|
+
);
|
|
673
|
+
return {
|
|
674
|
+
subtask_id: subtask.id,
|
|
675
|
+
selected_agent: card.owner,
|
|
676
|
+
selected_skill: matchingSkill?.id ?? "",
|
|
677
|
+
selected_card_id: card.id,
|
|
678
|
+
score: 1,
|
|
679
|
+
credits: matchingSkill?.pricing.credits_per_call ?? 0,
|
|
680
|
+
alternatives: []
|
|
681
|
+
};
|
|
682
|
+
});
|
|
683
|
+
const selected2 = selectByStrategy(candidates, strategy);
|
|
684
|
+
matched.push({
|
|
685
|
+
subtask,
|
|
686
|
+
capability_type: subtask.required_capability,
|
|
687
|
+
agent: selected2.selected_agent,
|
|
688
|
+
skill: selected2.selected_skill,
|
|
689
|
+
card_id: selected2.selected_card_id,
|
|
690
|
+
credits: selected2.credits,
|
|
691
|
+
score: selected2.score
|
|
692
|
+
});
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
const matchResults = await matchSubTasks({
|
|
696
|
+
db,
|
|
697
|
+
subtasks: [subtask],
|
|
698
|
+
conductorOwner,
|
|
699
|
+
registryUrl
|
|
700
|
+
});
|
|
701
|
+
const m = matchResults[0];
|
|
702
|
+
if (!m || m.selected_agent === "") {
|
|
703
|
+
unrouted.push(subtask);
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
const allCandidates = [
|
|
707
|
+
m,
|
|
708
|
+
...m.alternatives.map((alt) => ({
|
|
709
|
+
subtask_id: m.subtask_id,
|
|
710
|
+
selected_agent: alt.agent,
|
|
711
|
+
selected_skill: alt.skill,
|
|
712
|
+
score: alt.score,
|
|
713
|
+
credits: alt.credits,
|
|
714
|
+
alternatives: []
|
|
715
|
+
}))
|
|
716
|
+
];
|
|
717
|
+
const selected = selectByStrategy(allCandidates, strategy);
|
|
718
|
+
matched.push({
|
|
719
|
+
subtask,
|
|
720
|
+
capability_type: subtask.required_capability,
|
|
721
|
+
agent: selected.selected_agent,
|
|
722
|
+
skill: selected.selected_skill,
|
|
723
|
+
card_id: selected === m ? m.selected_card_id : void 0,
|
|
724
|
+
credits: selected.credits,
|
|
725
|
+
score: selected.score
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
return { team_id, strategy, matched, unrouted };
|
|
729
|
+
}
|
|
730
|
+
|
|
490
731
|
// src/conductor/conductor-mode.ts
|
|
491
732
|
var ConductorMode = class {
|
|
492
733
|
db;
|
|
@@ -525,7 +766,48 @@ var ConductorMode = class {
|
|
|
525
766
|
error: 'Missing or empty "task" parameter'
|
|
526
767
|
};
|
|
527
768
|
}
|
|
528
|
-
const
|
|
769
|
+
const orchestrationDepth = typeof params.orchestration_depth === "number" ? params.orchestration_depth : 0;
|
|
770
|
+
const decompositionDepth = typeof params.decomposition_depth === "number" ? params.decomposition_depth : 0;
|
|
771
|
+
if (orchestrationDepth >= 2) {
|
|
772
|
+
return {
|
|
773
|
+
success: false,
|
|
774
|
+
error: "orchestration_depth limit exceeded: max 1 nested orchestration"
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
let subtasks = [];
|
|
778
|
+
if (decompositionDepth === 0) {
|
|
779
|
+
const allDecomposers = getCardsByCapabilityType(this.db, "task_decomposition");
|
|
780
|
+
const externalDecomposers = allDecomposers.filter((c) => c.owner !== this.conductorOwner);
|
|
781
|
+
if (externalDecomposers.length > 0) {
|
|
782
|
+
const provider = externalDecomposers[0];
|
|
783
|
+
try {
|
|
784
|
+
const providerUrl = this.resolveAgentUrl(provider.owner);
|
|
785
|
+
const response = await requestCapability({
|
|
786
|
+
gatewayUrl: providerUrl.url,
|
|
787
|
+
token: this.gatewayToken,
|
|
788
|
+
cardId: provider.id,
|
|
789
|
+
params: {
|
|
790
|
+
task,
|
|
791
|
+
decomposition_depth: decompositionDepth + 1,
|
|
792
|
+
orchestration_depth: orchestrationDepth + 1
|
|
793
|
+
},
|
|
794
|
+
timeoutMs: 3e4
|
|
795
|
+
});
|
|
796
|
+
if (Array.isArray(response)) {
|
|
797
|
+
const validation = validateAndNormalizeSubtasks(response, {
|
|
798
|
+
max_credits: this.maxBudget
|
|
799
|
+
});
|
|
800
|
+
if (validation.errors.length === 0) {
|
|
801
|
+
subtasks = validation.valid;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
} catch {
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
if (subtasks.length === 0) {
|
|
809
|
+
subtasks = decompose(task);
|
|
810
|
+
}
|
|
529
811
|
if (subtasks.length === 0) {
|
|
530
812
|
return {
|
|
531
813
|
success: false,
|
|
@@ -539,6 +821,17 @@ var ConductorMode = class {
|
|
|
539
821
|
conductorOwner: this.conductorOwner
|
|
540
822
|
});
|
|
541
823
|
onProgress?.({ step: 2, total: 5, message: `Matched ${matchResults.length} sub-tasks to agents` });
|
|
824
|
+
let team;
|
|
825
|
+
if (conductorSkill === "orchestrate") {
|
|
826
|
+
const strategy = typeof params.formation_strategy === "string" && ["cost_optimized", "quality_optimized", "balanced"].includes(params.formation_strategy) ? params.formation_strategy : "balanced";
|
|
827
|
+
team = await formTeam({
|
|
828
|
+
subtasks,
|
|
829
|
+
strategy,
|
|
830
|
+
db: this.db,
|
|
831
|
+
conductorOwner: this.conductorOwner
|
|
832
|
+
});
|
|
833
|
+
onProgress?.({ step: 2, total: 5, message: `Formed team: ${team.matched.length} members, ${team.unrouted.length} unrouted` });
|
|
834
|
+
}
|
|
542
835
|
const budgetManager = new BudgetManager(this.creditDb, this.conductorOwner);
|
|
543
836
|
const budgetController = new BudgetController(budgetManager, this.maxBudget);
|
|
544
837
|
const executionBudget = budgetController.calculateBudget(matchResults);
|
|
@@ -555,7 +848,9 @@ var ConductorMode = class {
|
|
|
555
848
|
result: {
|
|
556
849
|
subtasks,
|
|
557
850
|
matches: matchResults,
|
|
558
|
-
budget: executionBudget
|
|
851
|
+
budget: executionBudget,
|
|
852
|
+
team
|
|
853
|
+
// undefined when no role hints
|
|
559
854
|
}
|
|
560
855
|
};
|
|
561
856
|
}
|
|
@@ -567,7 +862,8 @@ var ConductorMode = class {
|
|
|
567
862
|
matches: matchMap,
|
|
568
863
|
gatewayToken: this.gatewayToken,
|
|
569
864
|
resolveAgentUrl: this.resolveAgentUrl,
|
|
570
|
-
maxBudget: this.maxBudget
|
|
865
|
+
maxBudget: this.maxBudget,
|
|
866
|
+
team
|
|
571
867
|
});
|
|
572
868
|
onProgress?.({ step: 4, total: 5, message: "Pipeline execution complete" });
|
|
573
869
|
const resultObj = {};
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BudgetController,
|
|
3
|
+
decompose,
|
|
4
|
+
matchSubTasks,
|
|
5
|
+
orchestrate,
|
|
6
|
+
validateAndNormalizeSubtasks
|
|
7
|
+
} from "./chunk-NYV3NE5Z.js";
|
|
8
|
+
import "./chunk-3MJT4PZG.js";
|
|
9
|
+
import {
|
|
10
|
+
BudgetManager
|
|
11
|
+
} from "./chunk-C2T4BMRW.js";
|
|
12
|
+
import "./chunk-VMH2YS2I.js";
|
|
13
|
+
import "./chunk-Y7T6IMM3.js";
|
|
14
|
+
import "./chunk-574W3HHE.js";
|
|
15
|
+
import "./chunk-RVYQSC6L.js";
|
|
16
|
+
import {
|
|
17
|
+
requestCapability
|
|
18
|
+
} from "./chunk-VPQ44XKE.js";
|
|
19
|
+
import "./chunk-F53QQIM2.js";
|
|
20
|
+
import "./chunk-5AH3CMOX.js";
|
|
21
|
+
import "./chunk-75OC6E4F.js";
|
|
22
|
+
import {
|
|
23
|
+
getCardsByCapabilityType,
|
|
24
|
+
getCardsBySkillCapability
|
|
25
|
+
} from "./chunk-KA2VIEGM.js";
|
|
26
|
+
import "./chunk-3CIMVISQ.js";
|
|
27
|
+
|
|
28
|
+
// src/conductor/team-formation.ts
|
|
29
|
+
import { randomUUID } from "crypto";
|
|
30
|
+
function selectByStrategy(matches, strategy) {
|
|
31
|
+
if (matches.length === 0) return void 0;
|
|
32
|
+
if (strategy === "balanced") {
|
|
33
|
+
return matches[0];
|
|
34
|
+
}
|
|
35
|
+
if (strategy === "quality_optimized") {
|
|
36
|
+
return matches.reduce((best, m) => m.score > best.score ? m : best, matches[0]);
|
|
37
|
+
}
|
|
38
|
+
return matches.reduce((best, m) => {
|
|
39
|
+
if (m.credits < best.credits) return m;
|
|
40
|
+
if (m.credits === best.credits && m.score > best.score) return m;
|
|
41
|
+
return best;
|
|
42
|
+
}, matches[0]);
|
|
43
|
+
}
|
|
44
|
+
async function formTeam(opts) {
|
|
45
|
+
const { subtasks, strategy, db, conductorOwner, registryUrl } = opts;
|
|
46
|
+
const team_id = randomUUID();
|
|
47
|
+
if (subtasks.length === 0) {
|
|
48
|
+
return { team_id, strategy, matched: [], unrouted: [] };
|
|
49
|
+
}
|
|
50
|
+
const matched = [];
|
|
51
|
+
const unrouted = [];
|
|
52
|
+
for (const subtask of subtasks) {
|
|
53
|
+
const skillCards = getCardsBySkillCapability(db, subtask.required_capability).filter((c) => c.owner !== conductorOwner);
|
|
54
|
+
if (skillCards.length > 0) {
|
|
55
|
+
const candidates = skillCards.map((card) => {
|
|
56
|
+
const skills = card.skills ?? [];
|
|
57
|
+
const matchingSkill = skills.find(
|
|
58
|
+
(s) => s.capability_type === subtask.required_capability || (s.capability_types ?? []).includes(subtask.required_capability)
|
|
59
|
+
);
|
|
60
|
+
return {
|
|
61
|
+
subtask_id: subtask.id,
|
|
62
|
+
selected_agent: card.owner,
|
|
63
|
+
selected_skill: matchingSkill?.id ?? "",
|
|
64
|
+
selected_card_id: card.id,
|
|
65
|
+
score: 1,
|
|
66
|
+
credits: matchingSkill?.pricing.credits_per_call ?? 0,
|
|
67
|
+
alternatives: []
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
const selected2 = selectByStrategy(candidates, strategy);
|
|
71
|
+
matched.push({
|
|
72
|
+
subtask,
|
|
73
|
+
capability_type: subtask.required_capability,
|
|
74
|
+
agent: selected2.selected_agent,
|
|
75
|
+
skill: selected2.selected_skill,
|
|
76
|
+
card_id: selected2.selected_card_id,
|
|
77
|
+
credits: selected2.credits,
|
|
78
|
+
score: selected2.score
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const matchResults = await matchSubTasks({
|
|
83
|
+
db,
|
|
84
|
+
subtasks: [subtask],
|
|
85
|
+
conductorOwner,
|
|
86
|
+
registryUrl
|
|
87
|
+
});
|
|
88
|
+
const m = matchResults[0];
|
|
89
|
+
if (!m || m.selected_agent === "") {
|
|
90
|
+
unrouted.push(subtask);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const allCandidates = [
|
|
94
|
+
m,
|
|
95
|
+
...m.alternatives.map((alt) => ({
|
|
96
|
+
subtask_id: m.subtask_id,
|
|
97
|
+
selected_agent: alt.agent,
|
|
98
|
+
selected_skill: alt.skill,
|
|
99
|
+
score: alt.score,
|
|
100
|
+
credits: alt.credits,
|
|
101
|
+
alternatives: []
|
|
102
|
+
}))
|
|
103
|
+
];
|
|
104
|
+
const selected = selectByStrategy(allCandidates, strategy);
|
|
105
|
+
matched.push({
|
|
106
|
+
subtask,
|
|
107
|
+
capability_type: subtask.required_capability,
|
|
108
|
+
agent: selected.selected_agent,
|
|
109
|
+
skill: selected.selected_skill,
|
|
110
|
+
card_id: selected === m ? m.selected_card_id : void 0,
|
|
111
|
+
credits: selected.credits,
|
|
112
|
+
score: selected.score
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return { team_id, strategy, matched, unrouted };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/conductor/conductor-mode.ts
|
|
119
|
+
var ConductorMode = class {
|
|
120
|
+
db;
|
|
121
|
+
creditDb;
|
|
122
|
+
conductorOwner;
|
|
123
|
+
gatewayToken;
|
|
124
|
+
resolveAgentUrl;
|
|
125
|
+
maxBudget;
|
|
126
|
+
constructor(opts) {
|
|
127
|
+
this.db = opts.db;
|
|
128
|
+
this.creditDb = opts.creditDb;
|
|
129
|
+
this.conductorOwner = opts.conductorOwner;
|
|
130
|
+
this.gatewayToken = opts.gatewayToken;
|
|
131
|
+
this.resolveAgentUrl = opts.resolveAgentUrl;
|
|
132
|
+
this.maxBudget = opts.maxBudget ?? 100;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Execute a conductor skill with the given config and params.
|
|
136
|
+
*
|
|
137
|
+
* @param config - SkillConfig with type 'conductor' and conductor_skill field.
|
|
138
|
+
* @param params - Must include `task` string.
|
|
139
|
+
* @returns Execution result without latency_ms (added by SkillExecutor).
|
|
140
|
+
*/
|
|
141
|
+
async execute(config, params, onProgress) {
|
|
142
|
+
const conductorSkill = config.conductor_skill;
|
|
143
|
+
if (conductorSkill !== "orchestrate" && conductorSkill !== "plan") {
|
|
144
|
+
return {
|
|
145
|
+
success: false,
|
|
146
|
+
error: `Unknown conductor skill: "${conductorSkill}"`
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const task = params.task;
|
|
150
|
+
if (typeof task !== "string" || task.length === 0) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
error: 'Missing or empty "task" parameter'
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const orchestrationDepth = typeof params.orchestration_depth === "number" ? params.orchestration_depth : 0;
|
|
157
|
+
const decompositionDepth = typeof params.decomposition_depth === "number" ? params.decomposition_depth : 0;
|
|
158
|
+
if (orchestrationDepth >= 2) {
|
|
159
|
+
return {
|
|
160
|
+
success: false,
|
|
161
|
+
error: "orchestration_depth limit exceeded: max 1 nested orchestration"
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
let subtasks = [];
|
|
165
|
+
if (decompositionDepth === 0) {
|
|
166
|
+
const allDecomposers = getCardsByCapabilityType(this.db, "task_decomposition");
|
|
167
|
+
const externalDecomposers = allDecomposers.filter((c) => c.owner !== this.conductorOwner);
|
|
168
|
+
if (externalDecomposers.length > 0) {
|
|
169
|
+
const provider = externalDecomposers[0];
|
|
170
|
+
try {
|
|
171
|
+
const providerUrl = this.resolveAgentUrl(provider.owner);
|
|
172
|
+
const response = await requestCapability({
|
|
173
|
+
gatewayUrl: providerUrl.url,
|
|
174
|
+
token: this.gatewayToken,
|
|
175
|
+
cardId: provider.id,
|
|
176
|
+
params: {
|
|
177
|
+
task,
|
|
178
|
+
decomposition_depth: decompositionDepth + 1,
|
|
179
|
+
orchestration_depth: orchestrationDepth + 1
|
|
180
|
+
},
|
|
181
|
+
timeoutMs: 3e4
|
|
182
|
+
});
|
|
183
|
+
if (Array.isArray(response)) {
|
|
184
|
+
const validation = validateAndNormalizeSubtasks(response, {
|
|
185
|
+
max_credits: this.maxBudget
|
|
186
|
+
});
|
|
187
|
+
if (validation.errors.length === 0) {
|
|
188
|
+
subtasks = validation.valid;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (subtasks.length === 0) {
|
|
196
|
+
subtasks = decompose(task);
|
|
197
|
+
}
|
|
198
|
+
if (subtasks.length === 0) {
|
|
199
|
+
return {
|
|
200
|
+
success: false,
|
|
201
|
+
error: "No template matches task"
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
onProgress?.({ step: 1, total: 5, message: `Decomposed into ${subtasks.length} sub-tasks` });
|
|
205
|
+
const matchResults = await matchSubTasks({
|
|
206
|
+
db: this.db,
|
|
207
|
+
subtasks,
|
|
208
|
+
conductorOwner: this.conductorOwner
|
|
209
|
+
});
|
|
210
|
+
onProgress?.({ step: 2, total: 5, message: `Matched ${matchResults.length} sub-tasks to agents` });
|
|
211
|
+
let team;
|
|
212
|
+
if (conductorSkill === "orchestrate") {
|
|
213
|
+
const strategy = typeof params.formation_strategy === "string" && ["cost_optimized", "quality_optimized", "balanced"].includes(params.formation_strategy) ? params.formation_strategy : "balanced";
|
|
214
|
+
team = await formTeam({
|
|
215
|
+
subtasks,
|
|
216
|
+
strategy,
|
|
217
|
+
db: this.db,
|
|
218
|
+
conductorOwner: this.conductorOwner
|
|
219
|
+
});
|
|
220
|
+
onProgress?.({ step: 2, total: 5, message: `Formed team: ${team.matched.length} members, ${team.unrouted.length} unrouted` });
|
|
221
|
+
}
|
|
222
|
+
const budgetManager = new BudgetManager(this.creditDb, this.conductorOwner);
|
|
223
|
+
const budgetController = new BudgetController(budgetManager, this.maxBudget);
|
|
224
|
+
const executionBudget = budgetController.calculateBudget(matchResults);
|
|
225
|
+
if (!budgetController.canExecute(executionBudget)) {
|
|
226
|
+
return {
|
|
227
|
+
success: false,
|
|
228
|
+
error: `Budget exceeded: estimated ${executionBudget.estimated_total} cr, max ${this.maxBudget} cr`
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
onProgress?.({ step: 3, total: 5, message: `Budget approved: ${executionBudget.estimated_total} cr` });
|
|
232
|
+
if (conductorSkill === "plan") {
|
|
233
|
+
return {
|
|
234
|
+
success: true,
|
|
235
|
+
result: {
|
|
236
|
+
subtasks,
|
|
237
|
+
matches: matchResults,
|
|
238
|
+
budget: executionBudget,
|
|
239
|
+
team
|
|
240
|
+
// undefined when no role hints
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const matchMap = new Map(
|
|
245
|
+
matchResults.map((m) => [m.subtask_id, m])
|
|
246
|
+
);
|
|
247
|
+
const orchResult = await orchestrate({
|
|
248
|
+
subtasks,
|
|
249
|
+
matches: matchMap,
|
|
250
|
+
gatewayToken: this.gatewayToken,
|
|
251
|
+
resolveAgentUrl: this.resolveAgentUrl,
|
|
252
|
+
maxBudget: this.maxBudget,
|
|
253
|
+
team
|
|
254
|
+
});
|
|
255
|
+
onProgress?.({ step: 4, total: 5, message: "Pipeline execution complete" });
|
|
256
|
+
const resultObj = {};
|
|
257
|
+
for (const [key, value] of orchResult.results) {
|
|
258
|
+
resultObj[key] = value;
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
success: orchResult.success,
|
|
262
|
+
result: {
|
|
263
|
+
plan: subtasks,
|
|
264
|
+
execution: resultObj,
|
|
265
|
+
total_credits: orchResult.total_credits,
|
|
266
|
+
latency_ms: orchResult.latency_ms,
|
|
267
|
+
errors: orchResult.errors
|
|
268
|
+
},
|
|
269
|
+
error: orchResult.success ? void 0 : orchResult.errors?.join("; ")
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
export {
|
|
274
|
+
ConductorMode
|
|
275
|
+
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeCapabilityBatch,
|
|
3
3
|
executeCapabilityRequest
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-JR6TJDIF.js";
|
|
5
|
+
import "./chunk-2TLZ6G2B.js";
|
|
6
|
+
import "./chunk-IVOYM3WG.js";
|
|
7
|
+
import "./chunk-3CIMVISQ.js";
|
|
7
8
|
export {
|
|
8
9
|
executeCapabilityBatch,
|
|
9
10
|
executeCapabilityRequest
|