maskweaver 0.7.26 → 0.7.28
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/assets/agents/squad-operator.md +56 -16
- package/assets/commands/weave-craft.md +189 -92
- package/assets/commands/weave-design.md +59 -31
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +73 -14
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/tools/squad.d.ts +1 -0
- package/dist/plugin/tools/squad.d.ts.map +1 -1
- package/dist/plugin/tools/squad.js +49 -2
- package/dist/plugin/tools/squad.js.map +1 -1
- package/dist/plugin/tools/weave.js +8 -12
- package/dist/plugin/tools/weave.js.map +1 -1
- package/dist/shared/config.d.ts +46 -1
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/shared/config.js +34 -0
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/model-registry.d.ts +126 -0
- package/dist/shared/model-registry.d.ts.map +1 -0
- package/dist/shared/model-registry.js +318 -0
- package/dist/shared/model-registry.js.map +1 -0
- package/dist/weave/bridge.d.ts +61 -0
- package/dist/weave/bridge.d.ts.map +1 -0
- package/dist/weave/bridge.js +143 -0
- package/dist/weave/bridge.js.map +1 -0
- package/dist/weave/orchestrator.d.ts +59 -1
- package/dist/weave/orchestrator.d.ts.map +1 -1
- package/dist/weave/orchestrator.js +228 -0
- package/dist/weave/orchestrator.js.map +1 -1
- package/dist/weave/stages/execute.d.ts +35 -7
- package/dist/weave/stages/execute.d.ts.map +1 -1
- package/dist/weave/stages/execute.js +136 -267
- package/dist/weave/stages/execute.js.map +1 -1
- package/dist/weave/types.d.ts +20 -0
- package/dist/weave/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages the pool of available AI models with:
|
|
5
|
+
* - Concurrency tracking (max N simultaneous uses per model)
|
|
6
|
+
* - Capability-based matching (task → best model)
|
|
7
|
+
* - Tier-based fallback (if preferred model is full, find similar)
|
|
8
|
+
* - Cost-aware scheduling (prefer cheaper models for simple tasks)
|
|
9
|
+
*
|
|
10
|
+
* "The art of programming is the art of organizing complexity." - Dijkstra
|
|
11
|
+
*
|
|
12
|
+
* @author Mask Weaver
|
|
13
|
+
*/
|
|
14
|
+
import type { ModelPoolEntry, ModelTier, ModelCapability } from './config.js';
|
|
15
|
+
/** Runtime state for a model in the pool */
|
|
16
|
+
export interface ModelSlot {
|
|
17
|
+
/** The model definition from config */
|
|
18
|
+
entry: ModelPoolEntry;
|
|
19
|
+
/** Current number of active uses */
|
|
20
|
+
activeCount: number;
|
|
21
|
+
/** Whether this model has available slots */
|
|
22
|
+
available: boolean;
|
|
23
|
+
/** Remaining available slots */
|
|
24
|
+
remainingSlots: number;
|
|
25
|
+
}
|
|
26
|
+
/** Options for acquiring a model */
|
|
27
|
+
export interface AcquireOptions {
|
|
28
|
+
/** Preferred tier (flash/human/premium) */
|
|
29
|
+
tier?: ModelTier;
|
|
30
|
+
/** Required capabilities (at least one must match) */
|
|
31
|
+
capabilities?: ModelCapability[];
|
|
32
|
+
/** Prefer lower cost when multiple models match */
|
|
33
|
+
preferCheap?: boolean;
|
|
34
|
+
/** Specific model ID to request */
|
|
35
|
+
modelId?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Result of a model acquisition attempt */
|
|
38
|
+
export interface AcquireResult {
|
|
39
|
+
/** Whether a model was successfully acquired */
|
|
40
|
+
success: boolean;
|
|
41
|
+
/** The acquired model slot (if success) */
|
|
42
|
+
slot?: ModelSlot;
|
|
43
|
+
/** The agent name to use (e.g., "dummy-gemini-flash") */
|
|
44
|
+
agentName?: string;
|
|
45
|
+
/** Reason for failure (if not success) */
|
|
46
|
+
reason?: string;
|
|
47
|
+
/** Suggested alternative if primary choice unavailable */
|
|
48
|
+
suggestion?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Snapshot of all model statuses */
|
|
51
|
+
export interface RegistryStatus {
|
|
52
|
+
/** All model slots with their current state */
|
|
53
|
+
models: ModelSlot[];
|
|
54
|
+
/** Total capacity across all models */
|
|
55
|
+
totalCapacity: number;
|
|
56
|
+
/** Currently in use */
|
|
57
|
+
totalActive: number;
|
|
58
|
+
/** Available slots */
|
|
59
|
+
totalAvailable: number;
|
|
60
|
+
}
|
|
61
|
+
export declare class ModelRegistry {
|
|
62
|
+
private pool;
|
|
63
|
+
private activeCountMap;
|
|
64
|
+
constructor(pool: ModelPoolEntry[]);
|
|
65
|
+
/**
|
|
66
|
+
* Acquire a model from the pool.
|
|
67
|
+
*
|
|
68
|
+
* Selection strategy:
|
|
69
|
+
* 1. If modelId specified → try that exact model
|
|
70
|
+
* 2. Filter by tier preference
|
|
71
|
+
* 3. Filter by required capabilities
|
|
72
|
+
* 4. Among candidates, pick best available (cost-aware)
|
|
73
|
+
* 5. If no match in preferred tier, try fallback tiers
|
|
74
|
+
*/
|
|
75
|
+
acquire(options?: AcquireOptions): AcquireResult;
|
|
76
|
+
/**
|
|
77
|
+
* Release a model back to the pool.
|
|
78
|
+
* Must be called when a task using this model completes.
|
|
79
|
+
*/
|
|
80
|
+
release(modelId: string): boolean;
|
|
81
|
+
/** Get the current status of all models in the pool */
|
|
82
|
+
getStatus(): RegistryStatus;
|
|
83
|
+
/** Get available models for a specific tier */
|
|
84
|
+
getAvailableForTier(tier: ModelTier): ModelSlot[];
|
|
85
|
+
/** Get all models with a specific capability */
|
|
86
|
+
getModelsWithCapability(capability: ModelCapability): ModelSlot[];
|
|
87
|
+
/** Get the total concurrency available for a tier (including fallbacks) */
|
|
88
|
+
getTierConcurrency(tier: ModelTier): {
|
|
89
|
+
total: number;
|
|
90
|
+
available: number;
|
|
91
|
+
models: string[];
|
|
92
|
+
};
|
|
93
|
+
/** Get the pool entries */
|
|
94
|
+
getPool(): ModelPoolEntry[];
|
|
95
|
+
/** Get the agent name for a pool entry */
|
|
96
|
+
getAgentName(entry: ModelPoolEntry): string;
|
|
97
|
+
/**
|
|
98
|
+
* Recommend the best model for a task based on its capabilities.
|
|
99
|
+
* Does NOT acquire — just suggests.
|
|
100
|
+
*/
|
|
101
|
+
recommend(options?: AcquireOptions): ModelPoolEntry | null;
|
|
102
|
+
/**
|
|
103
|
+
* Compute maximum parallelism for a set of tasks.
|
|
104
|
+
* Given N tasks of different tiers, returns how many can run simultaneously.
|
|
105
|
+
*/
|
|
106
|
+
computeMaxParallelism(taskTiers: ModelTier[]): number;
|
|
107
|
+
private getSlot;
|
|
108
|
+
private tryAcquire;
|
|
109
|
+
private findCandidates;
|
|
110
|
+
private sortCandidates;
|
|
111
|
+
private suggestWait;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get the global model registry.
|
|
115
|
+
* Lazily initialized from maskweaver.config.json.
|
|
116
|
+
*/
|
|
117
|
+
export declare function getModelRegistry(basePath?: string): ModelRegistry;
|
|
118
|
+
/**
|
|
119
|
+
* Reset the registry (for testing or config reload).
|
|
120
|
+
*/
|
|
121
|
+
export declare function resetModelRegistry(): void;
|
|
122
|
+
/**
|
|
123
|
+
* Create a fresh registry from explicit pool entries.
|
|
124
|
+
*/
|
|
125
|
+
export declare function createModelRegistry(pool: ModelPoolEntry[]): ModelRegistry;
|
|
126
|
+
//# sourceMappingURL=model-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-registry.d.ts","sourceRoot":"","sources":["../../src/shared/model-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAiB,MAAM,aAAa,CAAC;AAO7F,4CAA4C;AAC5C,MAAM,WAAW,SAAS;IACxB,uCAAuC;IACvC,KAAK,EAAE,cAAc,CAAC;IACtB,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,oCAAoC;AACpC,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sDAAsD;IACtD,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AA0BD,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAmB;IAC/B,OAAO,CAAC,cAAc,CAAkC;gBAE5C,IAAI,EAAE,cAAc,EAAE;IAYlC;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa;IA+CpD;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAgBjC,uDAAuD;IACvD,SAAS,IAAI,cAAc;IAc3B,+CAA+C;IAC/C,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,EAAE;IAOjD,gDAAgD;IAChD,uBAAuB,CAAC,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE;IAMjE,2EAA2E;IAC3E,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAkB3F,2BAA2B;IAC3B,OAAO,IAAI,cAAc,EAAE;IAI3B,0CAA0C;IAC1C,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM;IAQ3C;;;OAGG;IACH,SAAS,CAAC,OAAO,GAAE,cAAmB,GAAG,cAAc,GAAG,IAAI;IAsB9D;;;OAGG;IACH,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM;IAsBrD,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,WAAW;CAgBpB;AAQD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,CASjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,aAAa,CAGzE"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages the pool of available AI models with:
|
|
5
|
+
* - Concurrency tracking (max N simultaneous uses per model)
|
|
6
|
+
* - Capability-based matching (task → best model)
|
|
7
|
+
* - Tier-based fallback (if preferred model is full, find similar)
|
|
8
|
+
* - Cost-aware scheduling (prefer cheaper models for simple tasks)
|
|
9
|
+
*
|
|
10
|
+
* "The art of programming is the art of organizing complexity." - Dijkstra
|
|
11
|
+
*
|
|
12
|
+
* @author Mask Weaver
|
|
13
|
+
*/
|
|
14
|
+
import { loadRuntimeConfig, normalizeDummyHumansConfig } from './config.js';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Cost tier ordering
|
|
17
|
+
// ============================================================================
|
|
18
|
+
const COST_ORDER = {
|
|
19
|
+
low: 1,
|
|
20
|
+
medium: 2,
|
|
21
|
+
high: 3,
|
|
22
|
+
};
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Tier fallback chain - when preferred tier is full
|
|
25
|
+
// ============================================================================
|
|
26
|
+
const TIER_FALLBACK = {
|
|
27
|
+
flash: ['human', 'premium'], // Flash full → try human → premium
|
|
28
|
+
human: ['premium', 'flash'], // Human full → try premium → flash
|
|
29
|
+
premium: ['human', 'flash'], // Premium full → try human → flash
|
|
30
|
+
};
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Model Registry
|
|
33
|
+
// ============================================================================
|
|
34
|
+
export class ModelRegistry {
|
|
35
|
+
pool;
|
|
36
|
+
activeCountMap = new Map();
|
|
37
|
+
constructor(pool) {
|
|
38
|
+
this.pool = pool;
|
|
39
|
+
// Initialize all counts to 0
|
|
40
|
+
for (const entry of pool) {
|
|
41
|
+
this.activeCountMap.set(entry.id, 0);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// --------------------------------------------------------------------------
|
|
45
|
+
// Core: Acquire / Release
|
|
46
|
+
// --------------------------------------------------------------------------
|
|
47
|
+
/**
|
|
48
|
+
* Acquire a model from the pool.
|
|
49
|
+
*
|
|
50
|
+
* Selection strategy:
|
|
51
|
+
* 1. If modelId specified → try that exact model
|
|
52
|
+
* 2. Filter by tier preference
|
|
53
|
+
* 3. Filter by required capabilities
|
|
54
|
+
* 4. Among candidates, pick best available (cost-aware)
|
|
55
|
+
* 5. If no match in preferred tier, try fallback tiers
|
|
56
|
+
*/
|
|
57
|
+
acquire(options = {}) {
|
|
58
|
+
const { tier, capabilities, preferCheap = true, modelId } = options;
|
|
59
|
+
// Specific model requested
|
|
60
|
+
if (modelId) {
|
|
61
|
+
const entry = this.pool.find(e => e.id === modelId);
|
|
62
|
+
if (!entry) {
|
|
63
|
+
return { success: false, reason: `Model "${modelId}" not found in pool` };
|
|
64
|
+
}
|
|
65
|
+
return this.tryAcquire(entry);
|
|
66
|
+
}
|
|
67
|
+
// Tier + capabilities based selection
|
|
68
|
+
const tiersToTry = [];
|
|
69
|
+
if (tier) {
|
|
70
|
+
tiersToTry.push(tier, ...TIER_FALLBACK[tier]);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// No tier specified → try all from cheapest
|
|
74
|
+
tiersToTry.push('flash', 'human', 'premium');
|
|
75
|
+
}
|
|
76
|
+
for (const tryTier of tiersToTry) {
|
|
77
|
+
const candidates = this.findCandidates(tryTier, capabilities);
|
|
78
|
+
// Sort by availability then cost
|
|
79
|
+
const sorted = this.sortCandidates(candidates, preferCheap);
|
|
80
|
+
for (const entry of sorted) {
|
|
81
|
+
const result = this.tryAcquire(entry);
|
|
82
|
+
if (result.success) {
|
|
83
|
+
// If we fell back to a different tier, note it
|
|
84
|
+
if (tier && tryTier !== tier) {
|
|
85
|
+
result.suggestion = `Preferred tier "${tier}" was full. Using "${tryTier}" model "${entry.id}" instead.`;
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// All models exhausted
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
reason: 'All suitable models are at maximum concurrency',
|
|
95
|
+
suggestion: this.suggestWait(tier, capabilities),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Release a model back to the pool.
|
|
100
|
+
* Must be called when a task using this model completes.
|
|
101
|
+
*/
|
|
102
|
+
release(modelId) {
|
|
103
|
+
const current = this.activeCountMap.get(modelId);
|
|
104
|
+
if (current === undefined) {
|
|
105
|
+
return false; // Unknown model
|
|
106
|
+
}
|
|
107
|
+
if (current <= 0) {
|
|
108
|
+
return false; // Already at 0
|
|
109
|
+
}
|
|
110
|
+
this.activeCountMap.set(modelId, current - 1);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
// --------------------------------------------------------------------------
|
|
114
|
+
// Query: Status and availability
|
|
115
|
+
// --------------------------------------------------------------------------
|
|
116
|
+
/** Get the current status of all models in the pool */
|
|
117
|
+
getStatus() {
|
|
118
|
+
const models = this.pool.map(entry => this.getSlot(entry));
|
|
119
|
+
const totalCapacity = models.reduce((sum, m) => sum + m.entry.maxConcurrent, 0);
|
|
120
|
+
const totalActive = models.reduce((sum, m) => sum + m.activeCount, 0);
|
|
121
|
+
return {
|
|
122
|
+
models,
|
|
123
|
+
totalCapacity,
|
|
124
|
+
totalActive,
|
|
125
|
+
totalAvailable: totalCapacity - totalActive,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Get available models for a specific tier */
|
|
129
|
+
getAvailableForTier(tier) {
|
|
130
|
+
return this.pool
|
|
131
|
+
.filter(e => e.tier === tier)
|
|
132
|
+
.map(e => this.getSlot(e))
|
|
133
|
+
.filter(s => s.available);
|
|
134
|
+
}
|
|
135
|
+
/** Get all models with a specific capability */
|
|
136
|
+
getModelsWithCapability(capability) {
|
|
137
|
+
return this.pool
|
|
138
|
+
.filter(e => e.capabilities.includes(capability))
|
|
139
|
+
.map(e => this.getSlot(e));
|
|
140
|
+
}
|
|
141
|
+
/** Get the total concurrency available for a tier (including fallbacks) */
|
|
142
|
+
getTierConcurrency(tier) {
|
|
143
|
+
const tiersToInclude = [tier, ...TIER_FALLBACK[tier]];
|
|
144
|
+
const entries = this.pool.filter(e => tiersToInclude.includes(e.tier));
|
|
145
|
+
let total = 0;
|
|
146
|
+
let available = 0;
|
|
147
|
+
const models = [];
|
|
148
|
+
for (const entry of entries) {
|
|
149
|
+
const slot = this.getSlot(entry);
|
|
150
|
+
total += entry.maxConcurrent;
|
|
151
|
+
available += slot.remainingSlots;
|
|
152
|
+
if (slot.available)
|
|
153
|
+
models.push(entry.id);
|
|
154
|
+
}
|
|
155
|
+
return { total, available, models };
|
|
156
|
+
}
|
|
157
|
+
/** Get the pool entries */
|
|
158
|
+
getPool() {
|
|
159
|
+
return [...this.pool];
|
|
160
|
+
}
|
|
161
|
+
/** Get the agent name for a pool entry */
|
|
162
|
+
getAgentName(entry) {
|
|
163
|
+
return `dummy-${entry.id}`;
|
|
164
|
+
}
|
|
165
|
+
// --------------------------------------------------------------------------
|
|
166
|
+
// Recommend: Smart model selection
|
|
167
|
+
// --------------------------------------------------------------------------
|
|
168
|
+
/**
|
|
169
|
+
* Recommend the best model for a task based on its capabilities.
|
|
170
|
+
* Does NOT acquire — just suggests.
|
|
171
|
+
*/
|
|
172
|
+
recommend(options = {}) {
|
|
173
|
+
const { tier, capabilities, preferCheap = true } = options;
|
|
174
|
+
const tiersToTry = tier
|
|
175
|
+
? [tier, ...TIER_FALLBACK[tier]]
|
|
176
|
+
: ['flash', 'human', 'premium'];
|
|
177
|
+
for (const tryTier of tiersToTry) {
|
|
178
|
+
const candidates = this.findCandidates(tryTier, capabilities);
|
|
179
|
+
const sorted = this.sortCandidates(candidates, preferCheap);
|
|
180
|
+
for (const entry of sorted) {
|
|
181
|
+
const slot = this.getSlot(entry);
|
|
182
|
+
if (slot.available) {
|
|
183
|
+
return entry;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Compute maximum parallelism for a set of tasks.
|
|
191
|
+
* Given N tasks of different tiers, returns how many can run simultaneously.
|
|
192
|
+
*/
|
|
193
|
+
computeMaxParallelism(taskTiers) {
|
|
194
|
+
// Count tasks per tier
|
|
195
|
+
const tierCounts = new Map();
|
|
196
|
+
for (const tier of taskTiers) {
|
|
197
|
+
tierCounts.set(tier, (tierCounts.get(tier) ?? 0) + 1);
|
|
198
|
+
}
|
|
199
|
+
// For each tier, compute available concurrency
|
|
200
|
+
let maxParallel = 0;
|
|
201
|
+
for (const [tier, count] of tierCounts) {
|
|
202
|
+
const entries = this.pool.filter(e => e.tier === tier);
|
|
203
|
+
const tierCapacity = entries.reduce((sum, e) => sum + e.maxConcurrent, 0);
|
|
204
|
+
maxParallel += Math.min(count, tierCapacity);
|
|
205
|
+
}
|
|
206
|
+
return maxParallel;
|
|
207
|
+
}
|
|
208
|
+
// --------------------------------------------------------------------------
|
|
209
|
+
// Internal helpers
|
|
210
|
+
// --------------------------------------------------------------------------
|
|
211
|
+
getSlot(entry) {
|
|
212
|
+
const activeCount = this.activeCountMap.get(entry.id) ?? 0;
|
|
213
|
+
const remainingSlots = entry.maxConcurrent - activeCount;
|
|
214
|
+
return {
|
|
215
|
+
entry,
|
|
216
|
+
activeCount,
|
|
217
|
+
available: remainingSlots > 0,
|
|
218
|
+
remainingSlots: Math.max(0, remainingSlots),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
tryAcquire(entry) {
|
|
222
|
+
const slot = this.getSlot(entry);
|
|
223
|
+
if (!slot.available) {
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
reason: `Model "${entry.id}" at max concurrency (${entry.maxConcurrent})`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// Increment active count
|
|
230
|
+
this.activeCountMap.set(entry.id, slot.activeCount + 1);
|
|
231
|
+
return {
|
|
232
|
+
success: true,
|
|
233
|
+
slot: {
|
|
234
|
+
...slot,
|
|
235
|
+
activeCount: slot.activeCount + 1,
|
|
236
|
+
remainingSlots: slot.remainingSlots - 1,
|
|
237
|
+
available: slot.remainingSlots - 1 > 0,
|
|
238
|
+
},
|
|
239
|
+
agentName: this.getAgentName(entry),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
findCandidates(tier, capabilities) {
|
|
243
|
+
return this.pool.filter(entry => {
|
|
244
|
+
// Must match tier
|
|
245
|
+
if (entry.tier !== tier)
|
|
246
|
+
return false;
|
|
247
|
+
// If capabilities specified, at least one must match
|
|
248
|
+
if (capabilities && capabilities.length > 0) {
|
|
249
|
+
const hasMatch = capabilities.some(c => entry.capabilities.includes(c));
|
|
250
|
+
if (!hasMatch)
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
sortCandidates(entries, preferCheap) {
|
|
257
|
+
return [...entries].sort((a, b) => {
|
|
258
|
+
// 1. Available slots first
|
|
259
|
+
const slotA = this.getSlot(a);
|
|
260
|
+
const slotB = this.getSlot(b);
|
|
261
|
+
if (slotA.available && !slotB.available)
|
|
262
|
+
return -1;
|
|
263
|
+
if (!slotA.available && slotB.available)
|
|
264
|
+
return 1;
|
|
265
|
+
// 2. Cost ordering
|
|
266
|
+
if (preferCheap) {
|
|
267
|
+
const costDiff = COST_ORDER[a.costTier] - COST_ORDER[b.costTier];
|
|
268
|
+
if (costDiff !== 0)
|
|
269
|
+
return costDiff;
|
|
270
|
+
}
|
|
271
|
+
// 3. More remaining slots = better
|
|
272
|
+
return slotB.remainingSlots - slotA.remainingSlots;
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
suggestWait(tier, capabilities) {
|
|
276
|
+
const status = this.getStatus();
|
|
277
|
+
const busiest = status.models
|
|
278
|
+
.filter(m => m.activeCount > 0)
|
|
279
|
+
.sort((a, b) => b.activeCount - a.activeCount);
|
|
280
|
+
if (busiest.length === 0) {
|
|
281
|
+
return 'No models are configured in the pool.';
|
|
282
|
+
}
|
|
283
|
+
const hints = busiest.slice(0, 3).map(m => ` - ${m.entry.id}: ${m.activeCount}/${m.entry.maxConcurrent} in use`);
|
|
284
|
+
return `All models are busy. Current usage:\n${hints.join('\n')}\nWait for a task to complete or add more models to the pool.`;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// ============================================================================
|
|
288
|
+
// Singleton Instance
|
|
289
|
+
// ============================================================================
|
|
290
|
+
let registryInstance = null;
|
|
291
|
+
/**
|
|
292
|
+
* Get the global model registry.
|
|
293
|
+
* Lazily initialized from maskweaver.config.json.
|
|
294
|
+
*/
|
|
295
|
+
export function getModelRegistry(basePath) {
|
|
296
|
+
if (!registryInstance) {
|
|
297
|
+
const config = loadRuntimeConfig(basePath);
|
|
298
|
+
const pool = config.dummyHumans
|
|
299
|
+
? normalizeDummyHumansConfig(config.dummyHumans)
|
|
300
|
+
: [];
|
|
301
|
+
registryInstance = new ModelRegistry(pool);
|
|
302
|
+
}
|
|
303
|
+
return registryInstance;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Reset the registry (for testing or config reload).
|
|
307
|
+
*/
|
|
308
|
+
export function resetModelRegistry() {
|
|
309
|
+
registryInstance = null;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Create a fresh registry from explicit pool entries.
|
|
313
|
+
*/
|
|
314
|
+
export function createModelRegistry(pool) {
|
|
315
|
+
registryInstance = new ModelRegistry(pool);
|
|
316
|
+
return registryInstance;
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=model-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-registry.js","sourceRoot":"","sources":["../../src/shared/model-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weave-Squad Bridge
|
|
3
|
+
*
|
|
4
|
+
* Converts between Weave types (WeaveTask, WeavePhase) and Squad types (TaskState)
|
|
5
|
+
* to enable parallel execution of Weave phase tasks through the Squad system.
|
|
6
|
+
*
|
|
7
|
+
* This is the missing link between the two systems:
|
|
8
|
+
* - Weave: Project-level milestone tracking (YAML plans)
|
|
9
|
+
* - Squad: Multi-agent parallel execution (JSON sessions)
|
|
10
|
+
*/
|
|
11
|
+
import type { WeaveTask, PhaseExecutionPlan, TaskExecutionPlan } from './types.js';
|
|
12
|
+
import type { TaskState, Priority } from '../shared-context/types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Convert a WeaveTask to a TaskState for use in the Squad system.
|
|
15
|
+
* Maps Weave concepts to Squad concepts:
|
|
16
|
+
* - WeaveTask.id -> TaskState.taskId
|
|
17
|
+
* - WeaveTask.status -> TaskState.status (with mapping)
|
|
18
|
+
* - Complexity -> TaskState.priority
|
|
19
|
+
*/
|
|
20
|
+
export declare function weaveTaskToSquadTask(task: WeaveTask, options: {
|
|
21
|
+
assignee: string;
|
|
22
|
+
priority?: Priority;
|
|
23
|
+
dependencies?: string[];
|
|
24
|
+
}): TaskState;
|
|
25
|
+
/**
|
|
26
|
+
* Map TaskComplexity to Squad Priority.
|
|
27
|
+
*/
|
|
28
|
+
export declare function complexityToPriority(complexity: 'simple' | 'standard' | 'complex'): Priority;
|
|
29
|
+
/**
|
|
30
|
+
* Convert a PhaseExecutionPlan into a list of TaskStates for the Squad system.
|
|
31
|
+
* Each TaskExecutionPlan determines the assignee (agent tier) and priority.
|
|
32
|
+
*/
|
|
33
|
+
export declare function executionPlanToSquadTasks(plan: PhaseExecutionPlan): TaskState[];
|
|
34
|
+
/**
|
|
35
|
+
* Analyze a PhaseExecutionPlan for parallel execution opportunities.
|
|
36
|
+
*
|
|
37
|
+
* Since Weave tasks within a phase don't have explicit dependencies by default,
|
|
38
|
+
* this function uses a heuristic:
|
|
39
|
+
* - Tasks that touch the same file patterns are grouped sequentially
|
|
40
|
+
* - Independent tasks are grouped into parallel waves
|
|
41
|
+
*
|
|
42
|
+
* Returns DAG analysis with wave grouping for parallel execution.
|
|
43
|
+
*/
|
|
44
|
+
export declare function analyzeParallelOpportunities(plan: PhaseExecutionPlan): ParallelAnalysis;
|
|
45
|
+
export interface WaveDetail {
|
|
46
|
+
waveIndex: number;
|
|
47
|
+
tasks: TaskExecutionPlan[];
|
|
48
|
+
}
|
|
49
|
+
export interface ParallelAnalysis {
|
|
50
|
+
totalTasks: number;
|
|
51
|
+
totalWaves: number;
|
|
52
|
+
parallelismFactor: number;
|
|
53
|
+
isFullyParallel: boolean;
|
|
54
|
+
waves: WaveDetail[];
|
|
55
|
+
criticalPath: string[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Format parallel analysis as markdown for the Mask Weaver.
|
|
59
|
+
*/
|
|
60
|
+
export declare function formatParallelAnalysis(analysis: ParallelAnalysis): string;
|
|
61
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/weave/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAc,kBAAkB,EAAE,iBAAiB,EAAa,MAAM,YAAY,CAAC;AAC1G,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAOtE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,SAAS,EACf,OAAO,EAAE;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,GACF,SAAS,CAUX;AAcD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAM5F;AAMD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,kBAAkB,GAAG,SAAS,EAAE,CAK/E;AAMD;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,kBAAkB,GAAG,gBAAgB,CAuCvF;AAMD,MAAM,WAAW,UAAU;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CA2BzE"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weave-Squad Bridge
|
|
3
|
+
*
|
|
4
|
+
* Converts between Weave types (WeaveTask, WeavePhase) and Squad types (TaskState)
|
|
5
|
+
* to enable parallel execution of Weave phase tasks through the Squad system.
|
|
6
|
+
*
|
|
7
|
+
* This is the missing link between the two systems:
|
|
8
|
+
* - Weave: Project-level milestone tracking (YAML plans)
|
|
9
|
+
* - Squad: Multi-agent parallel execution (JSON sessions)
|
|
10
|
+
*/
|
|
11
|
+
import { buildDAG } from '../shared-context/dag.js';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// WeaveTask -> TaskState Conversion
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Convert a WeaveTask to a TaskState for use in the Squad system.
|
|
17
|
+
* Maps Weave concepts to Squad concepts:
|
|
18
|
+
* - WeaveTask.id -> TaskState.taskId
|
|
19
|
+
* - WeaveTask.status -> TaskState.status (with mapping)
|
|
20
|
+
* - Complexity -> TaskState.priority
|
|
21
|
+
*/
|
|
22
|
+
export function weaveTaskToSquadTask(task, options) {
|
|
23
|
+
return {
|
|
24
|
+
taskId: task.id,
|
|
25
|
+
assignee: options.assignee,
|
|
26
|
+
status: mapWeaveStatusToSquad(task.status),
|
|
27
|
+
priority: options.priority || 'medium',
|
|
28
|
+
description: task.name,
|
|
29
|
+
dependencies: options.dependencies || [],
|
|
30
|
+
createdAt: new Date().toISOString(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Map Weave task status to Squad task status.
|
|
35
|
+
*/
|
|
36
|
+
function mapWeaveStatusToSquad(weaveStatus) {
|
|
37
|
+
switch (weaveStatus) {
|
|
38
|
+
case 'pending': return 'pending';
|
|
39
|
+
case 'in_progress': return 'active';
|
|
40
|
+
case 'passed': return 'completed';
|
|
41
|
+
case 'failed': return 'failed';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Map TaskComplexity to Squad Priority.
|
|
46
|
+
*/
|
|
47
|
+
export function complexityToPriority(complexity) {
|
|
48
|
+
switch (complexity) {
|
|
49
|
+
case 'simple': return 'low';
|
|
50
|
+
case 'standard': return 'medium';
|
|
51
|
+
case 'complex': return 'high';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// Phase -> Squad Task List Conversion
|
|
56
|
+
// ============================================================================
|
|
57
|
+
/**
|
|
58
|
+
* Convert a PhaseExecutionPlan into a list of TaskStates for the Squad system.
|
|
59
|
+
* Each TaskExecutionPlan determines the assignee (agent tier) and priority.
|
|
60
|
+
*/
|
|
61
|
+
export function executionPlanToSquadTasks(plan) {
|
|
62
|
+
return plan.taskPlans.map(tp => weaveTaskToSquadTask(tp.task, {
|
|
63
|
+
assignee: tp.agentTier,
|
|
64
|
+
priority: complexityToPriority(tp.complexity),
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// Parallel Execution Analysis
|
|
69
|
+
// ============================================================================
|
|
70
|
+
/**
|
|
71
|
+
* Analyze a PhaseExecutionPlan for parallel execution opportunities.
|
|
72
|
+
*
|
|
73
|
+
* Since Weave tasks within a phase don't have explicit dependencies by default,
|
|
74
|
+
* this function uses a heuristic:
|
|
75
|
+
* - Tasks that touch the same file patterns are grouped sequentially
|
|
76
|
+
* - Independent tasks are grouped into parallel waves
|
|
77
|
+
*
|
|
78
|
+
* Returns DAG analysis with wave grouping for parallel execution.
|
|
79
|
+
*/
|
|
80
|
+
export function analyzeParallelOpportunities(plan) {
|
|
81
|
+
const squadTasks = executionPlanToSquadTasks(plan);
|
|
82
|
+
// If no dependencies, all tasks are in wave 0 (fully parallel)
|
|
83
|
+
const allIndependent = squadTasks.every(t => !t.dependencies || t.dependencies.length === 0);
|
|
84
|
+
let dagAnalysis;
|
|
85
|
+
if (allIndependent && squadTasks.length > 1) {
|
|
86
|
+
// All tasks are independent — one big parallel wave
|
|
87
|
+
dagAnalysis = {
|
|
88
|
+
nodes: new Map(),
|
|
89
|
+
waves: [{ waveIndex: 0, taskIds: squadTasks.map(t => t.taskId) }],
|
|
90
|
+
criticalPath: [squadTasks[0].taskId],
|
|
91
|
+
hasCycle: false,
|
|
92
|
+
parallelismFactor: squadTasks.length,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// Use DAG analysis for dependency-aware wave grouping
|
|
97
|
+
dagAnalysis = buildDAG(squadTasks);
|
|
98
|
+
}
|
|
99
|
+
// Map waves back to execution plans
|
|
100
|
+
const waveDetails = dagAnalysis.waves.map(wave => ({
|
|
101
|
+
waveIndex: wave.waveIndex,
|
|
102
|
+
tasks: wave.taskIds.map(taskId => {
|
|
103
|
+
const tp = plan.taskPlans.find(p => p.task.id === taskId);
|
|
104
|
+
return tp;
|
|
105
|
+
}).filter(Boolean),
|
|
106
|
+
}));
|
|
107
|
+
return {
|
|
108
|
+
totalTasks: plan.taskPlans.length,
|
|
109
|
+
totalWaves: dagAnalysis.waves.length,
|
|
110
|
+
parallelismFactor: dagAnalysis.parallelismFactor,
|
|
111
|
+
isFullyParallel: allIndependent,
|
|
112
|
+
waves: waveDetails,
|
|
113
|
+
criticalPath: dagAnalysis.criticalPath,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Format parallel analysis as markdown for the Mask Weaver.
|
|
118
|
+
*/
|
|
119
|
+
export function formatParallelAnalysis(analysis) {
|
|
120
|
+
const lines = [];
|
|
121
|
+
lines.push('### Parallel Execution Analysis');
|
|
122
|
+
lines.push('');
|
|
123
|
+
lines.push(`- Total tasks: ${analysis.totalTasks}`);
|
|
124
|
+
lines.push(`- Execution waves: ${analysis.totalWaves}`);
|
|
125
|
+
lines.push(`- Parallelism factor: ${analysis.parallelismFactor.toFixed(1)}x`);
|
|
126
|
+
lines.push(`- Fully parallel: ${analysis.isFullyParallel ? 'yes' : 'no'}`);
|
|
127
|
+
lines.push('');
|
|
128
|
+
for (const wave of analysis.waves) {
|
|
129
|
+
lines.push(`**Wave ${wave.waveIndex}** (${wave.tasks.length} tasks in parallel):`);
|
|
130
|
+
for (const tp of wave.tasks) {
|
|
131
|
+
const tierLabel = tp.agentTier === 'dummy-flash' ? 'flash'
|
|
132
|
+
: tp.agentTier === 'dummy-human' ? 'human'
|
|
133
|
+
: 'premium';
|
|
134
|
+
lines.push(` - [${tierLabel}] ${tp.task.name} (${tp.mask || 'auto'})`);
|
|
135
|
+
}
|
|
136
|
+
lines.push('');
|
|
137
|
+
}
|
|
138
|
+
if (analysis.criticalPath.length > 1) {
|
|
139
|
+
lines.push(`Critical path: ${analysis.criticalPath.join(' -> ')}`);
|
|
140
|
+
}
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=bridge.js.map
|