@almadar/agent 1.3.2 → 1.6.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/agent/index.d.ts +4 -4
- package/dist/agent/index.js +1049 -31
- package/dist/agent/index.js.map +1 -1
- package/dist/{api-types-DVdGNr2M.d.ts → api-types-Bj2jeOU7.d.ts} +4 -0
- package/dist/event-transformer/index.d.ts +1 -1
- package/dist/event-transformer/index.js +3 -1
- package/dist/event-transformer/index.js.map +1 -1
- package/dist/{index-DFJdTDbo.d.ts → index-DGdLGf-L.d.ts} +189 -12
- package/dist/index.d.ts +357 -8
- package/dist/index.js +1593 -39
- package/dist/index.js.map +1 -1
- package/dist/{orbital-subagent-CCo-ONJY.d.ts → orbital-subagent-CHEeQQr_.d.ts} +1 -1
- package/dist/tools/index.d.ts +4 -3
- package/dist/tools/index.js +976 -20
- package/dist/tools/index.js.map +1 -1
- package/dist/{interrupt-config-Bib_RCTB.d.ts → workflow-tool-wrapper-CXD0A7l3.d.ts} +159 -3
- package/package.json +8 -5
package/dist/index.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { AgentDomainCategorySchema, isOrbitalDefinition, getTraitName, isPageReferenceString, isPageReferenceObject, isEntityReference } from '@almadar/core/types';
|
|
2
|
-
import {
|
|
2
|
+
import { getSubagentSystemPrompt, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection, getMinimalTypeReference, getFullOrbitalPrompt } from '@almadar/skills';
|
|
3
3
|
import { tool } from '@langchain/core/tools';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { LLMClient, isStructuredOutputAvailable, getStructuredOutputClient, createRequirementsClient, ANTHROPIC_MODELS, createAnthropicClient, OPENROUTER_MODELS, createOpenRouterClient, KIMI_MODELS, createKimiClient, OPENAI_MODELS, createOpenAIClient, DEEPSEEK_MODELS, createDeepSeekClient } from '@almadar/llm';
|
|
6
|
-
import { exec, spawn } from 'child_process';
|
|
6
|
+
import { exec, spawn, execSync } from 'child_process';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
+
import path__default from 'path';
|
|
8
9
|
import { promisify } from 'util';
|
|
9
10
|
import * as fs4 from 'fs/promises';
|
|
10
11
|
import * as domain_language_star from '@almadar/core/domain-language';
|
|
11
12
|
import * as fs3 from 'fs';
|
|
12
|
-
import
|
|
13
|
+
import fs3__default from 'fs';
|
|
14
|
+
import crypto, { createHash, randomUUID, createHmac, timingSafeEqual } from 'crypto';
|
|
15
|
+
import os from 'os';
|
|
13
16
|
import { GitHubIntegration } from '@almadar/integrations';
|
|
14
17
|
import '@langchain/core/messages';
|
|
15
18
|
import { FilesystemBackend, createDeepAgent } from 'deepagents';
|
|
@@ -254,20 +257,40 @@ ${guidance}
|
|
|
254
257
|
|
|
255
258
|
${CACHE_BREAK}
|
|
256
259
|
|
|
257
|
-
## Current Orbital Unit
|
|
260
|
+
## Current Orbital Unit (INPUT)
|
|
258
261
|
Name: ${orbital.name}
|
|
259
262
|
Entity: ${entityName}
|
|
260
263
|
Persistence: ${persistence}
|
|
261
264
|
Fields: ${fieldNames}
|
|
262
265
|
Traits: ${orbital.traits.map(getTraitName).join(", ")}
|
|
263
266
|
${contextSection}
|
|
264
|
-
|
|
267
|
+
|
|
268
|
+
## Required Output Structure
|
|
269
|
+
Generate a complete FullOrbitalUnit with this EXACT structure:
|
|
270
|
+
|
|
271
|
+
\`\`\`json
|
|
272
|
+
{
|
|
273
|
+
"name": "${orbital.name}",
|
|
274
|
+
"entity": { // \u2190 REQUIRED FIELD
|
|
275
|
+
"name": "${entityName}",
|
|
276
|
+
"collection": "${entityName.toLowerCase()}s",
|
|
277
|
+
"persistence": "${persistence}",
|
|
278
|
+
"fields": [ ... ]
|
|
279
|
+
},
|
|
280
|
+
"traits": [ ... ],
|
|
281
|
+
"pages": [ ... ]
|
|
282
|
+
}
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
**CRITICAL:** The "entity" field is REQUIRED at the orbital level. Do NOT omit it.
|
|
286
|
+
|
|
287
|
+
Additional requirements:
|
|
265
288
|
- Full field definitions with types and validation
|
|
266
289
|
- Trait state machines with transitions and effects
|
|
267
290
|
- Business rule validation using "guard" (singular, NOT "guards") S-expression on SAVE transitions
|
|
268
291
|
- Pages with trait references
|
|
269
292
|
- domainContext with category, vocabulary, and requestFragment
|
|
270
|
-
- design with style and uxHints
|
|
293
|
+
- design with style and uxHints
|
|
271
294
|
`;
|
|
272
295
|
return {
|
|
273
296
|
prompt,
|
|
@@ -307,7 +330,7 @@ ${guidance}`,
|
|
|
307
330
|
const userBlocks = [
|
|
308
331
|
{
|
|
309
332
|
type: "text",
|
|
310
|
-
text: `## Current Orbital Unit
|
|
333
|
+
text: `## Current Orbital Unit (INPUT)
|
|
311
334
|
Name: ${orbital.name}
|
|
312
335
|
Entity: ${entityName}
|
|
313
336
|
Persistence: ${persistence}
|
|
@@ -315,7 +338,40 @@ Fields: ${fieldNames}
|
|
|
315
338
|
Traits: ${orbital.traits.map(getTraitName).join(", ")}
|
|
316
339
|
${contextSection}${connectivitySection ? `
|
|
317
340
|
${connectivitySection}` : ""}
|
|
318
|
-
|
|
341
|
+
|
|
342
|
+
## REQUIRED OUTPUT - VERIFICATION CHECKLIST
|
|
343
|
+
|
|
344
|
+
Before generating output, verify:
|
|
345
|
+
- [ ] "entity" field is present at the TOP LEVEL of the orbital object
|
|
346
|
+
- [ ] entity.name = "${entityName}"
|
|
347
|
+
- [ ] entity.collection = "${entityName.toLowerCase()}s"
|
|
348
|
+
- [ ] entity.persistence = "${persistence}"
|
|
349
|
+
- [ ] entity.fields array has at least ${inlineEntity?.fields.length || 1} field(s)
|
|
350
|
+
- [ ] Full orbital structure includes: name, entity, traits, pages, domainContext, design
|
|
351
|
+
|
|
352
|
+
## Output Structure (Generate This Exact JSON)
|
|
353
|
+
|
|
354
|
+
\`\`\`json
|
|
355
|
+
{
|
|
356
|
+
"name": "${orbital.name}",
|
|
357
|
+
"entity": { // \u2190 THIS FIELD IS MANDATORY
|
|
358
|
+
"name": "${entityName}",
|
|
359
|
+
"collection": "${entityName.toLowerCase()}s",
|
|
360
|
+
"persistence": "${persistence}",
|
|
361
|
+
"fields": [${inlineEntity?.fields.map((f) => `
|
|
362
|
+
{ "name": "${f.name}", "type": "${f.type}"${f.required ? ', "required": true' : ""} }`).join(",") || ""}
|
|
363
|
+
]
|
|
364
|
+
},
|
|
365
|
+
"traits": [ ... trait definitions with state machines ... ],
|
|
366
|
+
"pages": [ ... page definitions ... ],
|
|
367
|
+
"domainContext": { ... domain info ... },
|
|
368
|
+
"design": { ... styling info ... }
|
|
369
|
+
}
|
|
370
|
+
\`\`\`
|
|
371
|
+
|
|
372
|
+
**MANDATORY:** If the output does not have an "entity" field at the orbital level, it is INVALID.
|
|
373
|
+
|
|
374
|
+
Additional requirements:
|
|
319
375
|
- Full field definitions with types and validation
|
|
320
376
|
- Trait state machines with transitions and effects
|
|
321
377
|
- Business rule validation using "guard" (singular, NOT "guards") S-expression on SAVE transitions
|
|
@@ -1505,7 +1561,9 @@ var GenerateRequestSchema = z.object({
|
|
|
1505
1561
|
owner: z.string().optional(),
|
|
1506
1562
|
/** Repository name (e.g., 'hello-world') */
|
|
1507
1563
|
repo: z.string().optional()
|
|
1508
|
-
}).optional()
|
|
1564
|
+
}).optional(),
|
|
1565
|
+
/** Optional: Use orchestrated generation with complexity-based provider routing (default: true) */
|
|
1566
|
+
useOrchestration: z.boolean().optional()
|
|
1509
1567
|
}).strict();
|
|
1510
1568
|
var ResumeRequestSchema = z.object({
|
|
1511
1569
|
/** Required: Thread ID to resume */
|
|
@@ -1571,6 +1629,40 @@ function isSSESubagentEvent(event) {
|
|
|
1571
1629
|
function isSSEGenerationLogEvent(event) {
|
|
1572
1630
|
return event.type === "generation_log";
|
|
1573
1631
|
}
|
|
1632
|
+
|
|
1633
|
+
// src/agent/interrupt-config.ts
|
|
1634
|
+
var TOOL_GATES = {
|
|
1635
|
+
// Always requires interrupt (handled by deepagents interruptOn)
|
|
1636
|
+
execute: "sensitive"
|
|
1637
|
+
};
|
|
1638
|
+
var CRITICAL_COMMAND_PATTERNS = [
|
|
1639
|
+
/\bpnpm\s+publish\b/,
|
|
1640
|
+
/\bnpm\s+publish\b/,
|
|
1641
|
+
/\bgit\s+push\b.*\bmain\b/,
|
|
1642
|
+
/\bgit\s+push\b.*\bmaster\b/,
|
|
1643
|
+
/\bgit\s+push\b.*--force\b/,
|
|
1644
|
+
/\brm\s+-rf\b/,
|
|
1645
|
+
/\brmdir\b/,
|
|
1646
|
+
/firebase\s+deploy/,
|
|
1647
|
+
/gcloud\s+.*deploy/,
|
|
1648
|
+
/\.env\b/
|
|
1649
|
+
];
|
|
1650
|
+
function classifyCommand(command) {
|
|
1651
|
+
for (const pattern of CRITICAL_COMMAND_PATTERNS) {
|
|
1652
|
+
if (pattern.test(command)) return "critical";
|
|
1653
|
+
}
|
|
1654
|
+
return "sensitive";
|
|
1655
|
+
}
|
|
1656
|
+
var DEFAULT_INTERRUPT_CONFIG = {
|
|
1657
|
+
// Shell commands always require approval
|
|
1658
|
+
execute: true
|
|
1659
|
+
};
|
|
1660
|
+
function getInterruptConfig(_skill) {
|
|
1661
|
+
const config = { ...DEFAULT_INTERRUPT_CONFIG };
|
|
1662
|
+
return config;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// src/tools/execute.ts
|
|
1574
1666
|
var DANGEROUS_COMMANDS = [
|
|
1575
1667
|
"rm",
|
|
1576
1668
|
"rmdir",
|
|
@@ -1687,14 +1779,26 @@ function validateCommandPaths(command, workDir) {
|
|
|
1687
1779
|
}
|
|
1688
1780
|
return null;
|
|
1689
1781
|
}
|
|
1690
|
-
function createExecuteTool(workDir) {
|
|
1782
|
+
function createExecuteTool(workDir, auditLog) {
|
|
1691
1783
|
const normalizedWorkDir = path.resolve(workDir);
|
|
1692
1784
|
return tool(
|
|
1693
1785
|
async ({ command, timeout = 6e4 }) => {
|
|
1694
1786
|
const validationError = validateCommandPaths(command, workDir);
|
|
1695
1787
|
if (validationError) {
|
|
1788
|
+
auditLog?.append({
|
|
1789
|
+
event: "EXECUTE_BLOCKED",
|
|
1790
|
+
command,
|
|
1791
|
+
reason: validationError,
|
|
1792
|
+
gate: classifyCommand(command)
|
|
1793
|
+
});
|
|
1696
1794
|
return validationError;
|
|
1697
1795
|
}
|
|
1796
|
+
auditLog?.append({
|
|
1797
|
+
event: "EXECUTE_START",
|
|
1798
|
+
command,
|
|
1799
|
+
gate: classifyCommand(command),
|
|
1800
|
+
workDir: normalizedWorkDir
|
|
1801
|
+
});
|
|
1698
1802
|
return new Promise((resolve2) => {
|
|
1699
1803
|
const parts = command.split(" ");
|
|
1700
1804
|
const cmd = parts[0];
|
|
@@ -1737,6 +1841,13 @@ function createExecuteTool(workDir) {
|
|
|
1737
1841
|
|
|
1738
1842
|
Stderr:
|
|
1739
1843
|
${stderr}` : "");
|
|
1844
|
+
auditLog?.append({
|
|
1845
|
+
event: "EXECUTE_COMPLETE",
|
|
1846
|
+
command,
|
|
1847
|
+
exitCode: code,
|
|
1848
|
+
outputLength: output.length,
|
|
1849
|
+
success: code === 0
|
|
1850
|
+
});
|
|
1740
1851
|
if (code === 0) {
|
|
1741
1852
|
resolve2(output || "Command completed successfully (no output)");
|
|
1742
1853
|
} else {
|
|
@@ -3113,7 +3224,8 @@ async function generateFullOrbital(client, orbital, options = {}) {
|
|
|
3113
3224
|
traitCount: orbital.traits.length,
|
|
3114
3225
|
hasRequirements: !!requirements
|
|
3115
3226
|
}));
|
|
3116
|
-
const
|
|
3227
|
+
const basePrompt = getSubagentSystemPrompt();
|
|
3228
|
+
const systemPrompt = requirements ? getRequirementsAwareFullOrbitalPrompt(requirements, basePrompt) : basePrompt;
|
|
3117
3229
|
const useCache = client.getProvider() === "anthropic";
|
|
3118
3230
|
let result;
|
|
3119
3231
|
let fingerprint;
|
|
@@ -3184,8 +3296,7 @@ Return valid JSON matching the FullOrbitalUnit schema.`;
|
|
|
3184
3296
|
logs
|
|
3185
3297
|
};
|
|
3186
3298
|
}
|
|
3187
|
-
function getRequirementsAwareFullOrbitalPrompt(requirements) {
|
|
3188
|
-
const basePrompt = getFullOrbitalPrompt();
|
|
3299
|
+
function getRequirementsAwareFullOrbitalPrompt(requirements, basePrompt = getSubagentSystemPrompt()) {
|
|
3189
3300
|
const requirementsGuidance = getRequirementsTraitPrompt();
|
|
3190
3301
|
const sections = [];
|
|
3191
3302
|
if (requirements.guards && requirements.guards.length > 0) {
|
|
@@ -3811,27 +3922,27 @@ var CombineSchemaInputSchema = z.object({
|
|
|
3811
3922
|
validate: z.boolean().optional().default(true)
|
|
3812
3923
|
});
|
|
3813
3924
|
async function autoCollectOrbitals(workDir) {
|
|
3814
|
-
const
|
|
3815
|
-
const
|
|
3816
|
-
const orbitalsDir =
|
|
3817
|
-
if (!
|
|
3818
|
-
const files2 =
|
|
3925
|
+
const fs8 = await import('fs');
|
|
3926
|
+
const path9 = await import('path');
|
|
3927
|
+
const orbitalsDir = path9.join(workDir, ".orbitals");
|
|
3928
|
+
if (!fs8.existsSync(orbitalsDir)) {
|
|
3929
|
+
const files2 = fs8.readdirSync(workDir).filter(
|
|
3819
3930
|
(f) => f.endsWith(".json") && (f.startsWith("orbital-") || f.includes("orbital"))
|
|
3820
3931
|
);
|
|
3821
3932
|
if (files2.length === 0) {
|
|
3822
3933
|
throw new Error("No orbitals found. Generate orbitals first using generate_orbital, or provide them directly.");
|
|
3823
3934
|
}
|
|
3824
3935
|
return files2.map((f) => {
|
|
3825
|
-
const content =
|
|
3936
|
+
const content = fs8.readFileSync(path9.join(workDir, f), "utf-8");
|
|
3826
3937
|
return JSON.parse(content);
|
|
3827
3938
|
});
|
|
3828
3939
|
}
|
|
3829
|
-
const files =
|
|
3940
|
+
const files = fs8.readdirSync(orbitalsDir).filter((f) => f.endsWith(".json"));
|
|
3830
3941
|
if (files.length === 0) {
|
|
3831
3942
|
throw new Error("No orbitals found in .orbitals/ directory.");
|
|
3832
3943
|
}
|
|
3833
3944
|
return files.map((f) => {
|
|
3834
|
-
const content =
|
|
3945
|
+
const content = fs8.readFileSync(path9.join(orbitalsDir, f), "utf-8");
|
|
3835
3946
|
return JSON.parse(content);
|
|
3836
3947
|
});
|
|
3837
3948
|
}
|
|
@@ -4153,6 +4264,825 @@ function createSchemaChunkingTools(workDir) {
|
|
|
4153
4264
|
applyChunk: createApplyChunkTool(workDir)
|
|
4154
4265
|
};
|
|
4155
4266
|
}
|
|
4267
|
+
|
|
4268
|
+
// src/orchestration/complexity-classifier.ts
|
|
4269
|
+
function classifyComplexity(orbitalCount) {
|
|
4270
|
+
if (orbitalCount <= 0) {
|
|
4271
|
+
throw new Error(`Invalid orbital count: ${orbitalCount}`);
|
|
4272
|
+
}
|
|
4273
|
+
if (orbitalCount === 1) {
|
|
4274
|
+
return {
|
|
4275
|
+
level: "simple",
|
|
4276
|
+
orbitalCount,
|
|
4277
|
+
recommendedProvider: "qwen",
|
|
4278
|
+
reasoning: "Single orbital - Qwen 397B is fast and cost-effective"
|
|
4279
|
+
};
|
|
4280
|
+
}
|
|
4281
|
+
if (orbitalCount <= 3) {
|
|
4282
|
+
return {
|
|
4283
|
+
level: "medium",
|
|
4284
|
+
orbitalCount,
|
|
4285
|
+
recommendedProvider: "qwen",
|
|
4286
|
+
reasoning: "2-3 orbitals - Qwen 397B handles well with good speed/cost"
|
|
4287
|
+
};
|
|
4288
|
+
}
|
|
4289
|
+
return {
|
|
4290
|
+
level: "complex",
|
|
4291
|
+
orbitalCount,
|
|
4292
|
+
recommendedProvider: "multi-provider",
|
|
4293
|
+
reasoning: "4+ orbitals - Multi-provider parallel for optimal speed"
|
|
4294
|
+
};
|
|
4295
|
+
}
|
|
4296
|
+
function estimateComplexity(prompt) {
|
|
4297
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
4298
|
+
const entityPatterns = [
|
|
4299
|
+
/entity[:s]/g,
|
|
4300
|
+
/entities:/g,
|
|
4301
|
+
/- \w+:/g,
|
|
4302
|
+
// List items like "- Task:"
|
|
4303
|
+
/model[s]?:/g,
|
|
4304
|
+
/table[s]?:/g
|
|
4305
|
+
];
|
|
4306
|
+
let entityMatches = 0;
|
|
4307
|
+
for (const pattern of entityPatterns) {
|
|
4308
|
+
const matches = lowerPrompt.match(pattern);
|
|
4309
|
+
if (matches) {
|
|
4310
|
+
entityMatches += matches.length;
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
const featureIndicators = [
|
|
4314
|
+
"dashboard",
|
|
4315
|
+
"workflow",
|
|
4316
|
+
"admin",
|
|
4317
|
+
"portal",
|
|
4318
|
+
"system",
|
|
4319
|
+
"management",
|
|
4320
|
+
"booking",
|
|
4321
|
+
"appointment",
|
|
4322
|
+
"inventory",
|
|
4323
|
+
"e-commerce",
|
|
4324
|
+
"healthcare",
|
|
4325
|
+
"patient",
|
|
4326
|
+
"doctor"
|
|
4327
|
+
];
|
|
4328
|
+
let featureMatches = 0;
|
|
4329
|
+
for (const indicator of featureIndicators) {
|
|
4330
|
+
if (lowerPrompt.includes(indicator)) {
|
|
4331
|
+
featureMatches++;
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
const lengthScore = prompt.length > 500 ? 2 : prompt.length > 200 ? 1 : 0;
|
|
4335
|
+
const score = entityMatches + featureMatches + lengthScore;
|
|
4336
|
+
if (score <= 2) {
|
|
4337
|
+
return { estimatedLevel: "simple", confidence: score === 0 ? "low" : "medium" };
|
|
4338
|
+
}
|
|
4339
|
+
if (score <= 5) {
|
|
4340
|
+
return { estimatedLevel: "medium", confidence: "medium" };
|
|
4341
|
+
}
|
|
4342
|
+
return { estimatedLevel: "complex", confidence: "high" };
|
|
4343
|
+
}
|
|
4344
|
+
function getExecutionStrategy(complexity) {
|
|
4345
|
+
switch (complexity.level) {
|
|
4346
|
+
case "simple":
|
|
4347
|
+
case "medium":
|
|
4348
|
+
return {
|
|
4349
|
+
type: "single",
|
|
4350
|
+
provider: "openrouter",
|
|
4351
|
+
model: "qwen/qwen3.5-397b-a17b",
|
|
4352
|
+
parallelization: 1
|
|
4353
|
+
};
|
|
4354
|
+
case "complex":
|
|
4355
|
+
return {
|
|
4356
|
+
type: "multi-provider",
|
|
4357
|
+
provider: "mixed",
|
|
4358
|
+
model: "deepseek-chat + qwen/qwen3.5-397b-a17b",
|
|
4359
|
+
parallelization: 2
|
|
4360
|
+
};
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
function buildOrbitalDefinition(unit) {
|
|
4364
|
+
const traits = unit.traits.map((t) => ({
|
|
4365
|
+
name: t,
|
|
4366
|
+
category: "interaction",
|
|
4367
|
+
linkedEntity: unit.entity,
|
|
4368
|
+
stateMachine: {
|
|
4369
|
+
states: [{ name: "Browsing", isInitial: true }],
|
|
4370
|
+
events: [{ key: "INIT", name: "Initialize" }],
|
|
4371
|
+
transitions: []
|
|
4372
|
+
}
|
|
4373
|
+
}));
|
|
4374
|
+
const pages = [
|
|
4375
|
+
{
|
|
4376
|
+
name: `${unit.name}Page`,
|
|
4377
|
+
path: `/${unit.entity.toLowerCase()}s`,
|
|
4378
|
+
traits: traits.map((t) => ({ ref: t.name }))
|
|
4379
|
+
}
|
|
4380
|
+
];
|
|
4381
|
+
return {
|
|
4382
|
+
name: unit.name,
|
|
4383
|
+
entity: {
|
|
4384
|
+
name: unit.entity,
|
|
4385
|
+
collection: `${unit.entity.toLowerCase()}s`,
|
|
4386
|
+
fields: [{ name: "id", type: "string", required: true }]
|
|
4387
|
+
},
|
|
4388
|
+
traits,
|
|
4389
|
+
pages
|
|
4390
|
+
};
|
|
4391
|
+
}
|
|
4392
|
+
function normalizeDecomposedUnit(unit) {
|
|
4393
|
+
const u = unit;
|
|
4394
|
+
let entityName;
|
|
4395
|
+
if (typeof u.entity === "string") {
|
|
4396
|
+
entityName = u.entity;
|
|
4397
|
+
} else if (u.entity && typeof u.entity === "object") {
|
|
4398
|
+
const entityObj = u.entity;
|
|
4399
|
+
entityName = typeof entityObj.name === "string" ? entityObj.name : "Unknown";
|
|
4400
|
+
} else {
|
|
4401
|
+
entityName = "Unknown";
|
|
4402
|
+
}
|
|
4403
|
+
let traitNames = [];
|
|
4404
|
+
if (Array.isArray(u.traits)) {
|
|
4405
|
+
traitNames = u.traits.map((t) => {
|
|
4406
|
+
if (typeof t === "string") return t;
|
|
4407
|
+
if (t && typeof t === "object") {
|
|
4408
|
+
const to = t;
|
|
4409
|
+
return typeof to.name === "string" ? to.name : String(t);
|
|
4410
|
+
}
|
|
4411
|
+
return String(t);
|
|
4412
|
+
});
|
|
4413
|
+
}
|
|
4414
|
+
return {
|
|
4415
|
+
name: typeof u.name === "string" ? u.name : "Unnamed",
|
|
4416
|
+
entity: entityName,
|
|
4417
|
+
traits: traitNames
|
|
4418
|
+
};
|
|
4419
|
+
}
|
|
4420
|
+
async function decomposeRequest(prompt, skillContent, _config) {
|
|
4421
|
+
const client = new LLMClient({
|
|
4422
|
+
provider: "anthropic",
|
|
4423
|
+
model: "claude-sonnet-4-20250514"
|
|
4424
|
+
});
|
|
4425
|
+
const systemPrompt = `${skillContent}
|
|
4426
|
+
|
|
4427
|
+
Your task is to decompose the user request into orbital units. Return ONLY a JSON array of orbital summaries. Each item should have: name (string), entity (string), traits (array of strings).`;
|
|
4428
|
+
const userPrompt = `Decompose this request into orbital units:
|
|
4429
|
+
|
|
4430
|
+
${prompt}
|
|
4431
|
+
|
|
4432
|
+
Return ONLY a JSON array. Each object must have:
|
|
4433
|
+
- name: orbital name (e.g., "Task Management")
|
|
4434
|
+
- entity: entity name as a STRING (e.g., "Task")
|
|
4435
|
+
- traits: array of trait names as strings (e.g., ["TaskInteraction"])`;
|
|
4436
|
+
const result = await client.call({
|
|
4437
|
+
systemPrompt,
|
|
4438
|
+
userPrompt,
|
|
4439
|
+
maxTokens: 4096,
|
|
4440
|
+
skipSchemaValidation: true
|
|
4441
|
+
});
|
|
4442
|
+
const rawUnits = Array.isArray(result) ? result : [result];
|
|
4443
|
+
return rawUnits.map(normalizeDecomposedUnit);
|
|
4444
|
+
}
|
|
4445
|
+
async function generateWithSingleProvider(units, config) {
|
|
4446
|
+
const client = new LLMClient({
|
|
4447
|
+
provider: "openrouter",
|
|
4448
|
+
model: "qwen/qwen3.5-397b-a17b"
|
|
4449
|
+
});
|
|
4450
|
+
if (config.verbose !== false) {
|
|
4451
|
+
console.log(`[Router] Using single provider (Qwen) for ${units.length} orbitals`);
|
|
4452
|
+
}
|
|
4453
|
+
const orbitals = [];
|
|
4454
|
+
for (const unit of units) {
|
|
4455
|
+
if (config.verbose !== false) {
|
|
4456
|
+
console.log(`[Router] Generating: ${unit.name}...`);
|
|
4457
|
+
}
|
|
4458
|
+
const startTime = Date.now();
|
|
4459
|
+
try {
|
|
4460
|
+
const orbitalDef = buildOrbitalDefinition(unit);
|
|
4461
|
+
const result = await generateFullOrbital(client, orbitalDef, {
|
|
4462
|
+
requirements: { entities: [unit.entity] },
|
|
4463
|
+
maxTokens: 8192
|
|
4464
|
+
});
|
|
4465
|
+
if (config.verbose !== false) {
|
|
4466
|
+
console.log(`[Router] \u2705 ${unit.name}: ${((Date.now() - startTime) / 1e3).toFixed(1)}s`);
|
|
4467
|
+
}
|
|
4468
|
+
orbitals.push(result.orbital);
|
|
4469
|
+
} catch (error) {
|
|
4470
|
+
if (config.verbose !== false) {
|
|
4471
|
+
console.log(`[Router] \u274C ${unit.name}: Failed - ${error instanceof Error ? error.message.slice(0, 50) : "Unknown"}`);
|
|
4472
|
+
}
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
return orbitals;
|
|
4476
|
+
}
|
|
4477
|
+
async function generateWithMultiProvider(units, config) {
|
|
4478
|
+
if (config.verbose !== false) {
|
|
4479
|
+
console.log(`[Router] Using multi-provider parallel for ${units.length} orbitals`);
|
|
4480
|
+
}
|
|
4481
|
+
const midpoint = Math.ceil(units.length / 2);
|
|
4482
|
+
const deepseekUnits = units.slice(0, midpoint);
|
|
4483
|
+
const qwenUnits = units.slice(midpoint);
|
|
4484
|
+
if (config.verbose !== false) {
|
|
4485
|
+
console.log(`[Router] Split: ${deepseekUnits.length} to DeepSeek, ${qwenUnits.length} to Qwen`);
|
|
4486
|
+
}
|
|
4487
|
+
const deepseekClient = new LLMClient({
|
|
4488
|
+
provider: "deepseek",
|
|
4489
|
+
model: "deepseek-chat"
|
|
4490
|
+
});
|
|
4491
|
+
const qwenClient = new LLMClient({
|
|
4492
|
+
provider: "openrouter",
|
|
4493
|
+
model: "qwen/qwen3.5-397b-a17b"
|
|
4494
|
+
});
|
|
4495
|
+
const [deepseekResults, qwenResults] = await Promise.all([
|
|
4496
|
+
Promise.all(
|
|
4497
|
+
deepseekUnits.map(async (unit) => {
|
|
4498
|
+
if (config.verbose !== false) {
|
|
4499
|
+
console.log(`[Router] [DeepSeek] Generating: ${unit.name}...`);
|
|
4500
|
+
}
|
|
4501
|
+
const startTime = Date.now();
|
|
4502
|
+
try {
|
|
4503
|
+
const orbitalDef = buildOrbitalDefinition(unit);
|
|
4504
|
+
const result = await generateFullOrbital(deepseekClient, orbitalDef, {
|
|
4505
|
+
requirements: { entities: [unit.entity] },
|
|
4506
|
+
maxTokens: 8192
|
|
4507
|
+
});
|
|
4508
|
+
if (config.verbose !== false) {
|
|
4509
|
+
console.log(`[Router] [DeepSeek] \u2705 ${unit.name}: ${((Date.now() - startTime) / 1e3).toFixed(1)}s`);
|
|
4510
|
+
}
|
|
4511
|
+
return result.orbital;
|
|
4512
|
+
} catch (error) {
|
|
4513
|
+
if (config.verbose !== false) {
|
|
4514
|
+
console.log(`[Router] [DeepSeek] \u274C ${unit.name}: Failed`);
|
|
4515
|
+
}
|
|
4516
|
+
return null;
|
|
4517
|
+
}
|
|
4518
|
+
})
|
|
4519
|
+
),
|
|
4520
|
+
Promise.all(
|
|
4521
|
+
qwenUnits.map(async (unit) => {
|
|
4522
|
+
if (config.verbose !== false) {
|
|
4523
|
+
console.log(`[Router] [Qwen] Generating: ${unit.name}...`);
|
|
4524
|
+
}
|
|
4525
|
+
const startTime = Date.now();
|
|
4526
|
+
try {
|
|
4527
|
+
const orbitalDef = buildOrbitalDefinition(unit);
|
|
4528
|
+
const result = await generateFullOrbital(qwenClient, orbitalDef, {
|
|
4529
|
+
requirements: { entities: [unit.entity] },
|
|
4530
|
+
maxTokens: 8192
|
|
4531
|
+
});
|
|
4532
|
+
if (config.verbose !== false) {
|
|
4533
|
+
console.log(`[Router] [Qwen] \u2705 ${unit.name}: ${((Date.now() - startTime) / 1e3).toFixed(1)}s`);
|
|
4534
|
+
}
|
|
4535
|
+
return result.orbital;
|
|
4536
|
+
} catch (error) {
|
|
4537
|
+
if (config.verbose !== false) {
|
|
4538
|
+
console.log(`[Router] [Qwen] \u274C ${unit.name}: Failed`);
|
|
4539
|
+
}
|
|
4540
|
+
return null;
|
|
4541
|
+
}
|
|
4542
|
+
})
|
|
4543
|
+
)
|
|
4544
|
+
]);
|
|
4545
|
+
return [...deepseekResults, ...qwenResults].filter((o) => o !== null);
|
|
4546
|
+
}
|
|
4547
|
+
async function routeGeneration(prompt, skillContent, config = {}) {
|
|
4548
|
+
const totalStart = Date.now();
|
|
4549
|
+
if (config.verbose !== false) {
|
|
4550
|
+
console.log("[Router] Step 1: Decomposing request...");
|
|
4551
|
+
}
|
|
4552
|
+
const decomposeStart = Date.now();
|
|
4553
|
+
const units = await decomposeRequest(prompt, skillContent);
|
|
4554
|
+
const decomposeMs = Date.now() - decomposeStart;
|
|
4555
|
+
if (config.verbose !== false) {
|
|
4556
|
+
console.log(`[Router] \u2705 Decomposed into ${units.length} orbitals (${(decomposeMs / 1e3).toFixed(1)}s)`);
|
|
4557
|
+
}
|
|
4558
|
+
const complexity = classifyComplexity(units.length);
|
|
4559
|
+
const strategy = getExecutionStrategy(complexity);
|
|
4560
|
+
if (config.verbose !== false) {
|
|
4561
|
+
console.log(`[Router] Complexity: ${complexity.level} (${units.length} orbitals)`);
|
|
4562
|
+
console.log(`[Router] Strategy: ${strategy.type} (${strategy.provider})`);
|
|
4563
|
+
}
|
|
4564
|
+
const generateStart = Date.now();
|
|
4565
|
+
let orbitals;
|
|
4566
|
+
if (complexity.level === "complex") {
|
|
4567
|
+
orbitals = await generateWithMultiProvider(units, config);
|
|
4568
|
+
} else {
|
|
4569
|
+
orbitals = await generateWithSingleProvider(units, config);
|
|
4570
|
+
}
|
|
4571
|
+
const generateMs = Date.now() - generateStart;
|
|
4572
|
+
const totalMs = Date.now() - totalStart;
|
|
4573
|
+
if (config.verbose !== false) {
|
|
4574
|
+
console.log(`[Router] \u2705 Generated ${orbitals.length}/${units.length} orbitals`);
|
|
4575
|
+
console.log(`[Router] Total time: ${(totalMs / 1e3).toFixed(1)}s`);
|
|
4576
|
+
}
|
|
4577
|
+
return {
|
|
4578
|
+
orbitals,
|
|
4579
|
+
complexity,
|
|
4580
|
+
timing: {
|
|
4581
|
+
decomposeMs,
|
|
4582
|
+
generateMs,
|
|
4583
|
+
totalMs
|
|
4584
|
+
},
|
|
4585
|
+
provider: strategy.provider
|
|
4586
|
+
};
|
|
4587
|
+
}
|
|
4588
|
+
function quickComplexityCheck(prompt) {
|
|
4589
|
+
const estimate = estimateComplexity(prompt);
|
|
4590
|
+
const estimatedCounts = {
|
|
4591
|
+
simple: 1,
|
|
4592
|
+
medium: 2,
|
|
4593
|
+
complex: 6
|
|
4594
|
+
};
|
|
4595
|
+
return {
|
|
4596
|
+
likelyComplex: estimate.estimatedLevel === "complex",
|
|
4597
|
+
confidence: estimate.confidence,
|
|
4598
|
+
estimatedOrbitals: estimatedCounts[estimate.estimatedLevel]
|
|
4599
|
+
};
|
|
4600
|
+
}
|
|
4601
|
+
async function createFixPlan(schema, errors, config) {
|
|
4602
|
+
const planStart = Date.now();
|
|
4603
|
+
const criticalErrors = errors.filter(
|
|
4604
|
+
(e) => e.code?.includes("ENTITY") || e.code?.includes("REQUIRED") || e.code?.includes("JSON")
|
|
4605
|
+
);
|
|
4606
|
+
const warningErrors = errors.filter((e) => !criticalErrors.includes(e));
|
|
4607
|
+
const orbitalErrors = /* @__PURE__ */ new Map();
|
|
4608
|
+
errors.forEach((error, index) => {
|
|
4609
|
+
let pathStr;
|
|
4610
|
+
if (Array.isArray(error.path)) {
|
|
4611
|
+
pathStr = error.path.join(".");
|
|
4612
|
+
} else if (typeof error.path === "string") {
|
|
4613
|
+
pathStr = error.path;
|
|
4614
|
+
} else {
|
|
4615
|
+
pathStr = String(error.path || "");
|
|
4616
|
+
}
|
|
4617
|
+
const match = pathStr.match(/orbitals\[(\d+)\]/);
|
|
4618
|
+
const orbitalIndex = match ? parseInt(match[1], 10) : -1;
|
|
4619
|
+
if (orbitalIndex >= 0) {
|
|
4620
|
+
if (!orbitalErrors.has(orbitalIndex)) {
|
|
4621
|
+
orbitalErrors.set(orbitalIndex, []);
|
|
4622
|
+
}
|
|
4623
|
+
orbitalErrors.get(orbitalIndex).push(index);
|
|
4624
|
+
}
|
|
4625
|
+
});
|
|
4626
|
+
const executionOrder = [];
|
|
4627
|
+
const affectedOrbitals = [];
|
|
4628
|
+
for (const [orbitalIndex, errorIndices] of orbitalErrors) {
|
|
4629
|
+
const orbital = schema.orbitals[orbitalIndex];
|
|
4630
|
+
if (orbital) {
|
|
4631
|
+
affectedOrbitals.push(orbital.name);
|
|
4632
|
+
const midPoint = Math.ceil(errorIndices.length / 2);
|
|
4633
|
+
const batches = [
|
|
4634
|
+
errorIndices.slice(0, midPoint),
|
|
4635
|
+
errorIndices.slice(midPoint)
|
|
4636
|
+
].filter((b) => b.length > 0);
|
|
4637
|
+
batches.forEach((batch, batchIndex) => {
|
|
4638
|
+
executionOrder.push({
|
|
4639
|
+
id: `fix-${orbitalIndex}-${batchIndex}`,
|
|
4640
|
+
description: `Fix ${batch.length} errors in ${orbital.name}`,
|
|
4641
|
+
orbitalIndex,
|
|
4642
|
+
errorIndices: batch,
|
|
4643
|
+
provider: batchIndex === 0 ? "deepseek" : "qwen",
|
|
4644
|
+
dependencies: []
|
|
4645
|
+
});
|
|
4646
|
+
});
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
let parallelizationStrategy = "single";
|
|
4650
|
+
if (executionOrder.length >= 4) {
|
|
4651
|
+
parallelizationStrategy = "multi-provider";
|
|
4652
|
+
} else if (JSON.stringify(schema).length > 5e4) {
|
|
4653
|
+
parallelizationStrategy = "chunked";
|
|
4654
|
+
}
|
|
4655
|
+
const plan = {
|
|
4656
|
+
summary: {
|
|
4657
|
+
totalErrors: errors.length,
|
|
4658
|
+
criticalErrors: criticalErrors.length,
|
|
4659
|
+
warningErrors: warningErrors.length,
|
|
4660
|
+
affectedOrbitals: [...new Set(affectedOrbitals)]
|
|
4661
|
+
},
|
|
4662
|
+
executionOrder,
|
|
4663
|
+
parallelizationStrategy
|
|
4664
|
+
};
|
|
4665
|
+
if (config.verbose) {
|
|
4666
|
+
console.log(`[Fixing] Plan created in ${Date.now() - planStart}ms`);
|
|
4667
|
+
console.log(`[Fixing] Strategy: ${parallelizationStrategy}`);
|
|
4668
|
+
console.log(`[Fixing] Steps: ${executionOrder.length}`);
|
|
4669
|
+
}
|
|
4670
|
+
return plan;
|
|
4671
|
+
}
|
|
4672
|
+
async function executeFixStep(schema, step, errors, config) {
|
|
4673
|
+
const orbital = schema.orbitals[step.orbitalIndex];
|
|
4674
|
+
if (!orbital) {
|
|
4675
|
+
return { success: false, updatedOrbital: null };
|
|
4676
|
+
}
|
|
4677
|
+
const client = step.provider === "deepseek" ? new LLMClient({
|
|
4678
|
+
provider: "deepseek",
|
|
4679
|
+
model: "deepseek-chat"
|
|
4680
|
+
}) : new LLMClient({
|
|
4681
|
+
provider: "openrouter",
|
|
4682
|
+
model: "qwen/qwen3.5-397b-a17b"
|
|
4683
|
+
});
|
|
4684
|
+
const stepErrors = step.errorIndices.map((i) => errors[i]);
|
|
4685
|
+
const skillContent = config.skillContent || "";
|
|
4686
|
+
const hasBindingErrors = stepErrors.some(
|
|
4687
|
+
(e) => e.message?.toLowerCase().includes("binding") || e.code?.toLowerCase().includes("binding")
|
|
4688
|
+
);
|
|
4689
|
+
const bindingGuidance = hasBindingErrors ? `
|
|
4690
|
+
## BINDING ERROR FIXES
|
|
4691
|
+
|
|
4692
|
+
Common binding mistakes and fixes:
|
|
4693
|
+
|
|
4694
|
+
\u274C INVALID:
|
|
4695
|
+
- "@count" \u2192 missing entity reference
|
|
4696
|
+
- "@status" \u2192 missing entity reference
|
|
4697
|
+
- "@count:status=active" \u2192 wrong syntax
|
|
4698
|
+
|
|
4699
|
+
\u2705 VALID (from skill):
|
|
4700
|
+
- "@entity.count" - entity field reference
|
|
4701
|
+
- "@entity.status" - enum field reference
|
|
4702
|
+
- "@payload.data" - event payload data
|
|
4703
|
+
- "@state" - current state name
|
|
4704
|
+
- "@now" - current timestamp
|
|
4705
|
+
|
|
4706
|
+
Replace bare field names like "@count" with proper entity references like "@entity.count".
|
|
4707
|
+
` : "";
|
|
4708
|
+
const systemPrompt = `${skillContent}
|
|
4709
|
+
|
|
4710
|
+
${bindingGuidance}
|
|
4711
|
+
|
|
4712
|
+
## FIXING INSTRUCTIONS
|
|
4713
|
+
|
|
4714
|
+
You are fixing validation errors in an OrbitalSchema orbital.
|
|
4715
|
+
|
|
4716
|
+
Rules:
|
|
4717
|
+
1. Preserve ALL valid content - only fix the reported errors
|
|
4718
|
+
2. Return the COMPLETE orbital with entity, traits, and pages
|
|
4719
|
+
3. Ensure entity has: name, collection, and fields array
|
|
4720
|
+
4. Use valid binding formats: @entity.field, @payload.field, @state
|
|
4721
|
+
|
|
4722
|
+
Return ONLY the fixed orbital as valid JSON.`;
|
|
4723
|
+
const userPrompt = `Fix these validation errors in orbital "${orbital.name}":
|
|
4724
|
+
|
|
4725
|
+
ERRORS:
|
|
4726
|
+
${stepErrors.map((e) => {
|
|
4727
|
+
const path9 = Array.isArray(e.path) ? e.path.join(".") : e.path;
|
|
4728
|
+
return `- Path: ${path9}
|
|
4729
|
+
Code: ${e.code}
|
|
4730
|
+
Message: ${e.message}`;
|
|
4731
|
+
}).join("\n")}
|
|
4732
|
+
|
|
4733
|
+
CURRENT ORBITAL (JSON):
|
|
4734
|
+
${JSON.stringify(orbital, null, 2)}
|
|
4735
|
+
|
|
4736
|
+
Return the COMPLETE fixed orbital as JSON with all fields (entity, traits, pages).`;
|
|
4737
|
+
try {
|
|
4738
|
+
const result = await client.call({
|
|
4739
|
+
systemPrompt,
|
|
4740
|
+
userPrompt,
|
|
4741
|
+
maxTokens: 8192,
|
|
4742
|
+
skipSchemaValidation: true
|
|
4743
|
+
});
|
|
4744
|
+
return {
|
|
4745
|
+
success: true,
|
|
4746
|
+
updatedOrbital: result
|
|
4747
|
+
};
|
|
4748
|
+
} catch (error) {
|
|
4749
|
+
return {
|
|
4750
|
+
success: false,
|
|
4751
|
+
updatedOrbital: null
|
|
4752
|
+
};
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
async function executeFixPlan(schema, plan, errors, config) {
|
|
4756
|
+
const executeStart = Date.now();
|
|
4757
|
+
const updatedSchema = { ...schema };
|
|
4758
|
+
if (plan.parallelizationStrategy === "multi-provider") {
|
|
4759
|
+
const deepseekSteps = plan.executionOrder.filter((s) => s.provider === "deepseek");
|
|
4760
|
+
const qwenSteps = plan.executionOrder.filter((s) => s.provider === "qwen");
|
|
4761
|
+
if (config.verbose) {
|
|
4762
|
+
console.log(`[Fixing] Executing ${deepseekSteps.length} steps on DeepSeek, ${qwenSteps.length} on Qwen`);
|
|
4763
|
+
}
|
|
4764
|
+
const [deepseekResults, qwenResults] = await Promise.all([
|
|
4765
|
+
Promise.all(deepseekSteps.map((step) => executeFixStep(schema, step, errors, config))),
|
|
4766
|
+
Promise.all(qwenSteps.map((step) => executeFixStep(schema, step, errors, config)))
|
|
4767
|
+
]);
|
|
4768
|
+
deepseekSteps.forEach((step, i) => {
|
|
4769
|
+
if (deepseekResults[i].success) {
|
|
4770
|
+
updatedSchema.orbitals[step.orbitalIndex] = deepseekResults[i].updatedOrbital;
|
|
4771
|
+
}
|
|
4772
|
+
});
|
|
4773
|
+
qwenSteps.forEach((step, i) => {
|
|
4774
|
+
if (qwenResults[i].success) {
|
|
4775
|
+
updatedSchema.orbitals[step.orbitalIndex] = qwenResults[i].updatedOrbital;
|
|
4776
|
+
}
|
|
4777
|
+
});
|
|
4778
|
+
} else {
|
|
4779
|
+
for (const step of plan.executionOrder) {
|
|
4780
|
+
if (config.verbose) {
|
|
4781
|
+
console.log(`[Fixing] Executing: ${step.description}`);
|
|
4782
|
+
}
|
|
4783
|
+
const result = await executeFixStep(schema, step, errors, config);
|
|
4784
|
+
if (result.success) {
|
|
4785
|
+
updatedSchema.orbitals[step.orbitalIndex] = result.updatedOrbital;
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
if (config.verbose) {
|
|
4790
|
+
console.log(`[Fixing] Execution completed in ${Date.now() - executeStart}ms`);
|
|
4791
|
+
}
|
|
4792
|
+
return updatedSchema;
|
|
4793
|
+
}
|
|
4794
|
+
function validateSchema(schema) {
|
|
4795
|
+
const tempDir = path__default.join(os.tmpdir(), "almadar-fixing");
|
|
4796
|
+
fs3__default.mkdirSync(tempDir, { recursive: true });
|
|
4797
|
+
const tempFile = path__default.join(tempDir, `schema-${Date.now()}.orb`);
|
|
4798
|
+
try {
|
|
4799
|
+
fs3__default.writeFileSync(tempFile, JSON.stringify(schema, null, 2));
|
|
4800
|
+
const output = execSync(`npx @almadar/cli validate --json "${tempFile}"`, {
|
|
4801
|
+
encoding: "utf-8",
|
|
4802
|
+
timeout: 3e4
|
|
4803
|
+
});
|
|
4804
|
+
fs3__default.unlinkSync(tempFile);
|
|
4805
|
+
const result = JSON.parse(output);
|
|
4806
|
+
return {
|
|
4807
|
+
valid: result.valid,
|
|
4808
|
+
errors: result.errors || []
|
|
4809
|
+
};
|
|
4810
|
+
} catch (error) {
|
|
4811
|
+
try {
|
|
4812
|
+
fs3__default.unlinkSync(tempFile);
|
|
4813
|
+
} catch {
|
|
4814
|
+
}
|
|
4815
|
+
try {
|
|
4816
|
+
const result = JSON.parse(error.stdout || "{}");
|
|
4817
|
+
return {
|
|
4818
|
+
valid: false,
|
|
4819
|
+
errors: result.errors || []
|
|
4820
|
+
};
|
|
4821
|
+
} catch {
|
|
4822
|
+
return {
|
|
4823
|
+
valid: false,
|
|
4824
|
+
errors: [{ code: "ERROR", message: error.message, path: [""], severity: "error" }]
|
|
4825
|
+
};
|
|
4826
|
+
}
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
async function orchestrateFixing(schema, config = {}) {
|
|
4830
|
+
const totalStart = Date.now();
|
|
4831
|
+
if (config.verbose) {
|
|
4832
|
+
console.log("[Fixing] Starting Plan-Then-Execute fixing workflow");
|
|
4833
|
+
}
|
|
4834
|
+
const initialValidation = validateSchema(schema);
|
|
4835
|
+
if (initialValidation.valid) {
|
|
4836
|
+
return {
|
|
4837
|
+
success: true,
|
|
4838
|
+
fixedSchema: schema,
|
|
4839
|
+
plan: {
|
|
4840
|
+
summary: { totalErrors: 0, criticalErrors: 0, warningErrors: 0, affectedOrbitals: [] },
|
|
4841
|
+
executionOrder: [],
|
|
4842
|
+
parallelizationStrategy: "single"
|
|
4843
|
+
},
|
|
4844
|
+
stepsCompleted: 0,
|
|
4845
|
+
stepsTotal: 0,
|
|
4846
|
+
remainingErrors: [],
|
|
4847
|
+
timing: {
|
|
4848
|
+
planMs: 0,
|
|
4849
|
+
executeMs: 0,
|
|
4850
|
+
verifyMs: 0,
|
|
4851
|
+
totalMs: Date.now() - totalStart
|
|
4852
|
+
}
|
|
4853
|
+
};
|
|
4854
|
+
}
|
|
4855
|
+
const planStart = Date.now();
|
|
4856
|
+
const plan = await createFixPlan(schema, initialValidation.errors, config);
|
|
4857
|
+
const planMs = Date.now() - planStart;
|
|
4858
|
+
const executeStart = Date.now();
|
|
4859
|
+
let fixedSchema = await executeFixPlan(schema, plan, initialValidation.errors, config);
|
|
4860
|
+
const executeMs = Date.now() - executeStart;
|
|
4861
|
+
const verifyStart = Date.now();
|
|
4862
|
+
const finalValidation = validateSchema(fixedSchema);
|
|
4863
|
+
const verifyMs = Date.now() - verifyStart;
|
|
4864
|
+
let retries = 0;
|
|
4865
|
+
const maxRetries = config.maxRetries || 2;
|
|
4866
|
+
while (!finalValidation.valid && retries < maxRetries) {
|
|
4867
|
+
if (config.verbose) {
|
|
4868
|
+
console.log(`[Fixing] Retrying (${retries + 1}/${maxRetries})...`);
|
|
4869
|
+
}
|
|
4870
|
+
const retryPlan = await createFixPlan(fixedSchema, finalValidation.errors, config);
|
|
4871
|
+
fixedSchema = await executeFixPlan(fixedSchema, retryPlan, finalValidation.errors, config);
|
|
4872
|
+
const retryValidation = validateSchema(fixedSchema);
|
|
4873
|
+
if (retryValidation.valid || retryValidation.errors.length < finalValidation.errors.length) {
|
|
4874
|
+
finalValidation.errors = retryValidation.errors;
|
|
4875
|
+
finalValidation.valid = retryValidation.valid;
|
|
4876
|
+
}
|
|
4877
|
+
retries++;
|
|
4878
|
+
}
|
|
4879
|
+
const totalMs = Date.now() - totalStart;
|
|
4880
|
+
if (config.verbose) {
|
|
4881
|
+
console.log("[Fixing] === Summary ===");
|
|
4882
|
+
console.log(`[Fixing] Plan: ${planMs}ms, Execute: ${executeMs}ms, Verify: ${verifyMs}ms`);
|
|
4883
|
+
console.log(`[Fixing] Total: ${totalMs}ms`);
|
|
4884
|
+
console.log(`[Fixing] Errors: ${initialValidation.errors.length} \u2192 ${finalValidation.errors.length}`);
|
|
4885
|
+
console.log(`[Fixing] Success: ${finalValidation.valid ? "YES" : "PARTIAL"}`);
|
|
4886
|
+
}
|
|
4887
|
+
return {
|
|
4888
|
+
success: finalValidation.valid,
|
|
4889
|
+
fixedSchema: finalValidation.valid ? fixedSchema : null,
|
|
4890
|
+
plan,
|
|
4891
|
+
stepsCompleted: plan.executionOrder.length - retries,
|
|
4892
|
+
stepsTotal: plan.executionOrder.length,
|
|
4893
|
+
remainingErrors: finalValidation.errors,
|
|
4894
|
+
timing: {
|
|
4895
|
+
planMs,
|
|
4896
|
+
executeMs,
|
|
4897
|
+
verifyMs,
|
|
4898
|
+
totalMs
|
|
4899
|
+
}
|
|
4900
|
+
};
|
|
4901
|
+
}
|
|
4902
|
+
|
|
4903
|
+
// src/tools/orchestrated-generation.ts
|
|
4904
|
+
function createOrchestratedGenerationTool(options) {
|
|
4905
|
+
const { skillContent, verbose = false } = options;
|
|
4906
|
+
return tool(
|
|
4907
|
+
async ({ prompt }) => {
|
|
4908
|
+
const startTime = Date.now();
|
|
4909
|
+
if (verbose) {
|
|
4910
|
+
console.log("[OrchestratedGeneration] Starting generation...");
|
|
4911
|
+
console.log(`[OrchestratedGeneration] Prompt length: ${prompt.length} chars`);
|
|
4912
|
+
}
|
|
4913
|
+
const quickCheck = quickComplexityCheck(prompt);
|
|
4914
|
+
if (verbose) {
|
|
4915
|
+
console.log(`[OrchestratedGeneration] Quick check: ~${quickCheck.estimatedOrbitals} orbitals (${quickCheck.confidence} confidence)`);
|
|
4916
|
+
}
|
|
4917
|
+
try {
|
|
4918
|
+
const result = await routeGeneration(prompt, skillContent, {
|
|
4919
|
+
verbose
|
|
4920
|
+
});
|
|
4921
|
+
const totalTime = Date.now() - startTime;
|
|
4922
|
+
if (verbose) {
|
|
4923
|
+
console.log(`[OrchestratedGeneration] \u2705 Success: ${result.orbitals.length} orbitals`);
|
|
4924
|
+
console.log(`[OrchestratedGeneration] Provider: ${result.provider}`);
|
|
4925
|
+
console.log(`[OrchestratedGeneration] Total time: ${totalTime}ms`);
|
|
4926
|
+
}
|
|
4927
|
+
const schema = {
|
|
4928
|
+
name: "GeneratedApp",
|
|
4929
|
+
version: "1.0.0",
|
|
4930
|
+
orbitals: result.orbitals
|
|
4931
|
+
};
|
|
4932
|
+
return {
|
|
4933
|
+
success: true,
|
|
4934
|
+
schema,
|
|
4935
|
+
complexity: result.complexity,
|
|
4936
|
+
provider: result.provider,
|
|
4937
|
+
timing: result.timing
|
|
4938
|
+
};
|
|
4939
|
+
} catch (error) {
|
|
4940
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4941
|
+
if (verbose) {
|
|
4942
|
+
console.log(`[OrchestratedGeneration] \u274C Failed: ${errorMessage}`);
|
|
4943
|
+
}
|
|
4944
|
+
return {
|
|
4945
|
+
success: false,
|
|
4946
|
+
error: errorMessage
|
|
4947
|
+
};
|
|
4948
|
+
}
|
|
4949
|
+
},
|
|
4950
|
+
{
|
|
4951
|
+
name: "generate_schema_orchestrated",
|
|
4952
|
+
description: `Generate an OrbitalSchema using complexity-based provider routing.
|
|
4953
|
+
|
|
4954
|
+
This tool automatically selects the best generation strategy:
|
|
4955
|
+
- Simple (1 orbital) \u2192 Fast single-provider generation
|
|
4956
|
+
- Medium (2-3 orbitals) \u2192 Efficient single-provider generation
|
|
4957
|
+
- Complex (4+ orbitals) \u2192 Parallel multi-provider generation
|
|
4958
|
+
|
|
4959
|
+
The tool handles decomposition, provider selection, and result combination automatically.`,
|
|
4960
|
+
schema: z.object({
|
|
4961
|
+
prompt: z.string().describe("User prompt describing the application to generate")
|
|
4962
|
+
})
|
|
4963
|
+
}
|
|
4964
|
+
);
|
|
4965
|
+
}
|
|
4966
|
+
function validateSchema2(schema) {
|
|
4967
|
+
const tempDir = path__default.join(os.tmpdir(), "almadar-fixing");
|
|
4968
|
+
fs3__default.mkdirSync(tempDir, { recursive: true });
|
|
4969
|
+
const tempFile = path__default.join(tempDir, `schema-${Date.now()}.orb`);
|
|
4970
|
+
try {
|
|
4971
|
+
fs3__default.writeFileSync(tempFile, JSON.stringify(schema, null, 2));
|
|
4972
|
+
const output = execSync(`npx @almadar/cli validate --json "${tempFile}"`, {
|
|
4973
|
+
encoding: "utf-8",
|
|
4974
|
+
timeout: 3e4
|
|
4975
|
+
});
|
|
4976
|
+
fs3__default.unlinkSync(tempFile);
|
|
4977
|
+
const result = JSON.parse(output);
|
|
4978
|
+
return {
|
|
4979
|
+
valid: result.valid,
|
|
4980
|
+
errors: result.errors || []
|
|
4981
|
+
};
|
|
4982
|
+
} catch (error) {
|
|
4983
|
+
try {
|
|
4984
|
+
fs3__default.unlinkSync(tempFile);
|
|
4985
|
+
} catch {
|
|
4986
|
+
}
|
|
4987
|
+
try {
|
|
4988
|
+
const result = JSON.parse(error.stdout || "{}");
|
|
4989
|
+
return {
|
|
4990
|
+
valid: false,
|
|
4991
|
+
errors: result.errors || []
|
|
4992
|
+
};
|
|
4993
|
+
} catch {
|
|
4994
|
+
return {
|
|
4995
|
+
valid: false,
|
|
4996
|
+
errors: [{ code: "ERROR", message: error.message }]
|
|
4997
|
+
};
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
function createOrchestratedFixingTool(options) {
|
|
5002
|
+
const { skillContent, maxRetries = 2, verbose = false } = options;
|
|
5003
|
+
return tool(
|
|
5004
|
+
async ({ schema }) => {
|
|
5005
|
+
const typedSchema = schema;
|
|
5006
|
+
if (verbose) {
|
|
5007
|
+
console.log("[OrchestratedFixing] Starting fixing workflow...");
|
|
5008
|
+
}
|
|
5009
|
+
const initialValidation = validateSchema2(typedSchema);
|
|
5010
|
+
if (initialValidation.valid) {
|
|
5011
|
+
if (verbose) {
|
|
5012
|
+
console.log("[OrchestratedFixing] Schema is already valid");
|
|
5013
|
+
}
|
|
5014
|
+
return {
|
|
5015
|
+
success: true,
|
|
5016
|
+
schema: typedSchema,
|
|
5017
|
+
fixSummary: {
|
|
5018
|
+
totalErrors: 0,
|
|
5019
|
+
errorsFixed: 0,
|
|
5020
|
+
errorsRemaining: 0,
|
|
5021
|
+
strategy: "none-needed",
|
|
5022
|
+
stepsExecuted: 0
|
|
5023
|
+
},
|
|
5024
|
+
timing: {
|
|
5025
|
+
planMs: 0,
|
|
5026
|
+
executeMs: 0,
|
|
5027
|
+
verifyMs: 0,
|
|
5028
|
+
totalMs: 0
|
|
5029
|
+
}
|
|
5030
|
+
};
|
|
5031
|
+
}
|
|
5032
|
+
if (verbose) {
|
|
5033
|
+
console.log(`[OrchestratedFixing] Found ${initialValidation.errors.length} errors to fix`);
|
|
5034
|
+
}
|
|
5035
|
+
try {
|
|
5036
|
+
const result = await orchestrateFixing(typedSchema, {
|
|
5037
|
+
maxRetries,
|
|
5038
|
+
verbose,
|
|
5039
|
+
skillContent
|
|
5040
|
+
});
|
|
5041
|
+
if (verbose) {
|
|
5042
|
+
console.log(`[OrchestratedFixing] ${result.success ? "\u2705" : "\u26A0\uFE0F"} Fix complete`);
|
|
5043
|
+
console.log(`[OrchestratedFixing] Errors: ${result.plan.summary.totalErrors} \u2192 ${result.remainingErrors.length}`);
|
|
5044
|
+
}
|
|
5045
|
+
return {
|
|
5046
|
+
success: result.success,
|
|
5047
|
+
schema: result.fixedSchema || typedSchema,
|
|
5048
|
+
fixSummary: {
|
|
5049
|
+
totalErrors: result.plan.summary.totalErrors,
|
|
5050
|
+
errorsFixed: result.plan.summary.totalErrors - result.remainingErrors.length,
|
|
5051
|
+
errorsRemaining: result.remainingErrors.length,
|
|
5052
|
+
strategy: result.plan.parallelizationStrategy,
|
|
5053
|
+
stepsExecuted: result.stepsCompleted
|
|
5054
|
+
},
|
|
5055
|
+
timing: result.timing
|
|
5056
|
+
};
|
|
5057
|
+
} catch (error) {
|
|
5058
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5059
|
+
if (verbose) {
|
|
5060
|
+
console.log(`[OrchestratedFixing] \u274C Failed: ${errorMessage}`);
|
|
5061
|
+
}
|
|
5062
|
+
return {
|
|
5063
|
+
success: false,
|
|
5064
|
+
schema: typedSchema,
|
|
5065
|
+
error: errorMessage
|
|
5066
|
+
};
|
|
5067
|
+
}
|
|
5068
|
+
},
|
|
5069
|
+
{
|
|
5070
|
+
name: "fix_schema_orchestrated",
|
|
5071
|
+
description: `Fix validation errors in an OrbitalSchema using Plan-Then-Execute strategy.
|
|
5072
|
+
|
|
5073
|
+
This tool:
|
|
5074
|
+
1. Validates the schema to identify errors
|
|
5075
|
+
2. Creates a fix plan based on error types
|
|
5076
|
+
3. Applies fixes using the fixing skill guidance
|
|
5077
|
+
4. Re-validates and retries if needed
|
|
5078
|
+
|
|
5079
|
+
Works with single or multi-orbital schemas, automatically selecting the best strategy.`,
|
|
5080
|
+
schema: z.object({
|
|
5081
|
+
schema: z.object({}).describe("The OrbitalSchema to fix")
|
|
5082
|
+
})
|
|
5083
|
+
}
|
|
5084
|
+
);
|
|
5085
|
+
}
|
|
4156
5086
|
function createGitHubTools(config) {
|
|
4157
5087
|
const { token, owner = "", repo = "", workDir } = config;
|
|
4158
5088
|
const integrationConfig = {
|
|
@@ -5662,16 +6592,6 @@ var SessionManager = class {
|
|
|
5662
6592
|
}
|
|
5663
6593
|
};
|
|
5664
6594
|
|
|
5665
|
-
// src/agent/interrupt-config.ts
|
|
5666
|
-
var DEFAULT_INTERRUPT_CONFIG = {
|
|
5667
|
-
// Shell commands always require approval
|
|
5668
|
-
execute: true
|
|
5669
|
-
};
|
|
5670
|
-
function getInterruptConfig(_skill) {
|
|
5671
|
-
const config = { ...DEFAULT_INTERRUPT_CONFIG };
|
|
5672
|
-
return config;
|
|
5673
|
-
}
|
|
5674
|
-
|
|
5675
6595
|
// src/agent/skill-agent.ts
|
|
5676
6596
|
var BASE_SYSTEM_PROMPT = `You are a KFlow agent that helps users create and manage application schemas.
|
|
5677
6597
|
|
|
@@ -5878,6 +6798,30 @@ ${skillContents}`;
|
|
|
5878
6798
|
const isOrbitalBatchSkill = ORBITAL_BATCH_SKILLS.includes(primarySkill.name);
|
|
5879
6799
|
const isLeanSkill = LEAN_SKILLS.includes(primarySkill.name);
|
|
5880
6800
|
const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name);
|
|
6801
|
+
const useOrchestration = options.useOrchestration ?? false;
|
|
6802
|
+
let orchestratedGenerationTool;
|
|
6803
|
+
let orchestratedFixingTool;
|
|
6804
|
+
if (useOrchestration) {
|
|
6805
|
+
if (isOrbitalSkill) {
|
|
6806
|
+
orchestratedGenerationTool = createOrchestratedGenerationTool({
|
|
6807
|
+
skillContent: primarySkill.content,
|
|
6808
|
+
verbose
|
|
6809
|
+
});
|
|
6810
|
+
if (verbose) {
|
|
6811
|
+
console.log(`[SkillAgent] Orchestrated generation enabled for ${primarySkill.name}`);
|
|
6812
|
+
}
|
|
6813
|
+
}
|
|
6814
|
+
if (primarySkill.name === "kflow-orbital-fixing") {
|
|
6815
|
+
orchestratedFixingTool = createOrchestratedFixingTool({
|
|
6816
|
+
skillContent: primarySkill.content,
|
|
6817
|
+
maxRetries: 2,
|
|
6818
|
+
verbose
|
|
6819
|
+
});
|
|
6820
|
+
if (verbose) {
|
|
6821
|
+
console.log(`[SkillAgent] Orchestrated fixing enabled for ${primarySkill.name}`);
|
|
6822
|
+
}
|
|
6823
|
+
}
|
|
6824
|
+
}
|
|
5881
6825
|
let orbitalTool;
|
|
5882
6826
|
let setOrbitalEventCallback;
|
|
5883
6827
|
let setOrbitalCompleteCallback;
|
|
@@ -5937,10 +6881,10 @@ ${skillContents}`;
|
|
|
5937
6881
|
if (githubTools && verbose) {
|
|
5938
6882
|
console.log(`[SkillAgent] GitHub tools enabled`);
|
|
5939
6883
|
}
|
|
5940
|
-
|
|
6884
|
+
let tools = [
|
|
5941
6885
|
executeTool,
|
|
5942
6886
|
finishTaskTool,
|
|
5943
|
-
|
|
6887
|
+
validateSchemaTool,
|
|
5944
6888
|
...orbitalTool ? [orbitalTool] : [],
|
|
5945
6889
|
...orbitalBatchTool ? [orbitalBatchTool] : [],
|
|
5946
6890
|
...domainOrbitalTools ? [
|
|
@@ -5952,8 +6896,14 @@ ${skillContents}`;
|
|
|
5952
6896
|
chunkingTools.extractChunk,
|
|
5953
6897
|
chunkingTools.applyChunk
|
|
5954
6898
|
] : [],
|
|
5955
|
-
...githubTools || []
|
|
6899
|
+
...githubTools || [],
|
|
6900
|
+
// Add orchestrated tools when enabled
|
|
6901
|
+
...orchestratedGenerationTool ? [orchestratedGenerationTool] : [],
|
|
6902
|
+
...orchestratedFixingTool ? [orchestratedFixingTool] : []
|
|
5956
6903
|
];
|
|
6904
|
+
if (options.toolWrapper) {
|
|
6905
|
+
tools = tools.map(options.toolWrapper);
|
|
6906
|
+
}
|
|
5957
6907
|
const checkpointer = sessions.getCheckpointer(threadId);
|
|
5958
6908
|
const interruptConfig = options.noInterrupt ? void 0 : getInterruptConfig();
|
|
5959
6909
|
const agent = createDeepAgent({
|
|
@@ -6792,11 +7742,11 @@ var WorkflowBuilder = class {
|
|
|
6792
7742
|
this.definition.inputs[name] = { type, required, default: defaultValue };
|
|
6793
7743
|
return this;
|
|
6794
7744
|
}
|
|
6795
|
-
step(id,
|
|
7745
|
+
step(id, tool14, input, options = {}) {
|
|
6796
7746
|
this.definition.steps.push({
|
|
6797
7747
|
id,
|
|
6798
7748
|
name: id,
|
|
6799
|
-
tool:
|
|
7749
|
+
tool: tool14,
|
|
6800
7750
|
input,
|
|
6801
7751
|
dependsOn: options.dependsOn,
|
|
6802
7752
|
condition: options.condition,
|
|
@@ -6865,6 +7815,119 @@ function createSchemaGenerationWorkflow(engine) {
|
|
|
6865
7815
|
function createWorkflowEngine(executor) {
|
|
6866
7816
|
return new WorkflowEngine(executor);
|
|
6867
7817
|
}
|
|
7818
|
+
|
|
7819
|
+
// src/agent/workflow-tool-wrapper.ts
|
|
7820
|
+
function createWorkflowToolWrapper(options = {}) {
|
|
7821
|
+
const {
|
|
7822
|
+
maxRetries = 3,
|
|
7823
|
+
enableTelemetry = true,
|
|
7824
|
+
timeoutMs = 6e4,
|
|
7825
|
+
backoffMs = 1e3
|
|
7826
|
+
} = options;
|
|
7827
|
+
const telemetry = [];
|
|
7828
|
+
return {
|
|
7829
|
+
wrap: (tool14) => {
|
|
7830
|
+
return {
|
|
7831
|
+
...tool14,
|
|
7832
|
+
invoke: async (...args) => {
|
|
7833
|
+
const startTime = Date.now();
|
|
7834
|
+
let retries = 0;
|
|
7835
|
+
let lastError;
|
|
7836
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
7837
|
+
try {
|
|
7838
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
7839
|
+
throw new Error(`Tool ${tool14.name} exceeded timeout of ${timeoutMs}ms`);
|
|
7840
|
+
}
|
|
7841
|
+
const result = await tool14.invoke(...args);
|
|
7842
|
+
if (enableTelemetry) {
|
|
7843
|
+
telemetry.push({
|
|
7844
|
+
toolName: tool14.name,
|
|
7845
|
+
durationMs: Date.now() - startTime,
|
|
7846
|
+
retries,
|
|
7847
|
+
success: true
|
|
7848
|
+
});
|
|
7849
|
+
}
|
|
7850
|
+
return result;
|
|
7851
|
+
} catch (error) {
|
|
7852
|
+
lastError = error;
|
|
7853
|
+
const errorMsg = lastError.message?.toLowerCase() || "";
|
|
7854
|
+
const isValidationError = errorMsg.includes("expected object, received string") || errorMsg.includes("expected array, received") || errorMsg.includes("required") || errorMsg.includes("invalid") || errorMsg.includes("validation");
|
|
7855
|
+
if (isValidationError) {
|
|
7856
|
+
console.log(`[Workflow] ${tool14.name} validation error (not retryable): ${lastError.message}`);
|
|
7857
|
+
if (enableTelemetry) {
|
|
7858
|
+
telemetry.push({
|
|
7859
|
+
toolName: tool14.name,
|
|
7860
|
+
durationMs: Date.now() - startTime,
|
|
7861
|
+
retries: 0,
|
|
7862
|
+
success: false,
|
|
7863
|
+
error: lastError.message
|
|
7864
|
+
});
|
|
7865
|
+
}
|
|
7866
|
+
return {
|
|
7867
|
+
error: lastError.message,
|
|
7868
|
+
status: "error",
|
|
7869
|
+
toolName: tool14.name,
|
|
7870
|
+
suggestion: "Check the tool input format and try again with corrected parameters"
|
|
7871
|
+
};
|
|
7872
|
+
}
|
|
7873
|
+
if (attempt < maxRetries) {
|
|
7874
|
+
retries++;
|
|
7875
|
+
const waitMs = backoffMs * Math.pow(2, attempt);
|
|
7876
|
+
console.log(`[Workflow Retry] ${tool14.name} attempt ${retries}/${maxRetries}, waiting ${waitMs}ms...`);
|
|
7877
|
+
await new Promise((resolve2) => setTimeout(resolve2, waitMs));
|
|
7878
|
+
}
|
|
7879
|
+
}
|
|
7880
|
+
}
|
|
7881
|
+
if (enableTelemetry) {
|
|
7882
|
+
telemetry.push({
|
|
7883
|
+
toolName: tool14.name,
|
|
7884
|
+
durationMs: Date.now() - startTime,
|
|
7885
|
+
retries,
|
|
7886
|
+
success: false,
|
|
7887
|
+
error: lastError?.message
|
|
7888
|
+
});
|
|
7889
|
+
}
|
|
7890
|
+
return {
|
|
7891
|
+
error: lastError?.message || "Tool execution failed after retries",
|
|
7892
|
+
status: "error",
|
|
7893
|
+
toolName: tool14.name,
|
|
7894
|
+
retries
|
|
7895
|
+
};
|
|
7896
|
+
}
|
|
7897
|
+
};
|
|
7898
|
+
},
|
|
7899
|
+
getTelemetry: () => [...telemetry],
|
|
7900
|
+
resetTelemetry: () => {
|
|
7901
|
+
telemetry.length = 0;
|
|
7902
|
+
}
|
|
7903
|
+
};
|
|
7904
|
+
}
|
|
7905
|
+
function createEvalWorkflowWrapper(options = {}) {
|
|
7906
|
+
const wrapper = createWorkflowToolWrapper(options);
|
|
7907
|
+
return {
|
|
7908
|
+
...wrapper,
|
|
7909
|
+
wrap: (tool14) => {
|
|
7910
|
+
const wrapped = wrapper.wrap(tool14);
|
|
7911
|
+
const originalInvoke = wrapped.invoke;
|
|
7912
|
+
wrapped.invoke = async (...args) => {
|
|
7913
|
+
console.log(`[Workflow] Starting ${tool14.name}...`);
|
|
7914
|
+
try {
|
|
7915
|
+
const result = await originalInvoke(...args);
|
|
7916
|
+
const allMetrics = wrapper.getTelemetry();
|
|
7917
|
+
const metrics = allMetrics[allMetrics.length - 1];
|
|
7918
|
+
console.log(`[Workflow] ${tool14.name} completed (${metrics?.durationMs}ms, ${metrics?.retries} retries)`);
|
|
7919
|
+
return result;
|
|
7920
|
+
} catch (error) {
|
|
7921
|
+
const allMetrics = wrapper.getTelemetry();
|
|
7922
|
+
const metrics = allMetrics[allMetrics.length - 1];
|
|
7923
|
+
console.log(`[Workflow] ${tool14.name} failed after ${metrics?.retries} retries`);
|
|
7924
|
+
throw error;
|
|
7925
|
+
}
|
|
7926
|
+
};
|
|
7927
|
+
return wrapped;
|
|
7928
|
+
}
|
|
7929
|
+
};
|
|
7930
|
+
}
|
|
6868
7931
|
var FirestoreStore = class extends BaseStore {
|
|
6869
7932
|
constructor(options) {
|
|
6870
7933
|
super();
|
|
@@ -7022,9 +8085,9 @@ var FirestoreStore = class extends BaseStore {
|
|
|
7022
8085
|
let query = this.db.collection(this.collection);
|
|
7023
8086
|
if (op.matchConditions) {
|
|
7024
8087
|
for (const condition of op.matchConditions) {
|
|
7025
|
-
const
|
|
8088
|
+
const path9 = condition.path.filter((p) => p !== "*").join("/");
|
|
7026
8089
|
if (condition.matchType === "prefix") {
|
|
7027
|
-
query = query.where("namespaceKey", ">=",
|
|
8090
|
+
query = query.where("namespaceKey", ">=", path9).where("namespaceKey", "<", path9 + "\uFFFF");
|
|
7028
8091
|
}
|
|
7029
8092
|
}
|
|
7030
8093
|
}
|
|
@@ -9574,11 +10637,502 @@ async function reviewSamples(sampler, options = {}) {
|
|
|
9574
10637
|
function createOnlineEvalSampler(config) {
|
|
9575
10638
|
return new OnlineEvalSampler(config);
|
|
9576
10639
|
}
|
|
10640
|
+
var GENESIS_HASH = createHash("sha256").update("IC-AGI-GENESIS").digest("hex");
|
|
10641
|
+
function stableStringify(value) {
|
|
10642
|
+
if (value === null || typeof value !== "object") {
|
|
10643
|
+
return JSON.stringify(value) ?? "null";
|
|
10644
|
+
}
|
|
10645
|
+
if (Array.isArray(value)) {
|
|
10646
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
10647
|
+
}
|
|
10648
|
+
const obj = value;
|
|
10649
|
+
const keys = Object.keys(obj).sort();
|
|
10650
|
+
const pairs = keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
|
|
10651
|
+
return `{${pairs.join(",")}}`;
|
|
10652
|
+
}
|
|
10653
|
+
function computeEntryHash(entry) {
|
|
10654
|
+
const content = stableStringify({
|
|
10655
|
+
data: entry.data,
|
|
10656
|
+
index: entry.index,
|
|
10657
|
+
prev_hash: entry.prevHash,
|
|
10658
|
+
timestamp: entry.timestamp
|
|
10659
|
+
});
|
|
10660
|
+
return createHash("sha256").update(content).digest("hex");
|
|
10661
|
+
}
|
|
10662
|
+
var AuditLog = class {
|
|
10663
|
+
constructor() {
|
|
10664
|
+
this.entries = [];
|
|
10665
|
+
}
|
|
10666
|
+
/**
|
|
10667
|
+
* Append a new entry to the chain.
|
|
10668
|
+
* The timestamp is set here — callers cannot supply it.
|
|
10669
|
+
*/
|
|
10670
|
+
append(data) {
|
|
10671
|
+
const prevHash = this.entries.length > 0 ? this.entries[this.entries.length - 1].entryHash : GENESIS_HASH;
|
|
10672
|
+
const partial = {
|
|
10673
|
+
index: this.entries.length,
|
|
10674
|
+
timestamp: Date.now() / 1e3,
|
|
10675
|
+
data,
|
|
10676
|
+
prevHash
|
|
10677
|
+
};
|
|
10678
|
+
const entry = { ...partial, entryHash: computeEntryHash(partial) };
|
|
10679
|
+
this.entries.push(entry);
|
|
10680
|
+
return entry;
|
|
10681
|
+
}
|
|
10682
|
+
/**
|
|
10683
|
+
* Verify the integrity of the entire chain.
|
|
10684
|
+
* Recomputes every entry hash and checks chain linkage.
|
|
10685
|
+
* Returns false immediately on the first mismatch.
|
|
10686
|
+
*/
|
|
10687
|
+
verify() {
|
|
10688
|
+
for (let i = 0; i < this.entries.length; i++) {
|
|
10689
|
+
const entry = this.entries[i];
|
|
10690
|
+
if (entry.entryHash !== computeEntryHash(entry)) return false;
|
|
10691
|
+
const expectedPrev = i === 0 ? GENESIS_HASH : this.entries[i - 1].entryHash;
|
|
10692
|
+
if (entry.prevHash !== expectedPrev) return false;
|
|
10693
|
+
}
|
|
10694
|
+
return true;
|
|
10695
|
+
}
|
|
10696
|
+
/** Return entries, optionally filtered by source, event type, or count limit. */
|
|
10697
|
+
getEntries(filter) {
|
|
10698
|
+
let results = this.entries;
|
|
10699
|
+
if (filter?.source) results = results.filter((e) => e.data["source"] === filter.source);
|
|
10700
|
+
if (filter?.event) results = results.filter((e) => e.data["event"] === filter.event);
|
|
10701
|
+
if (filter?.limit) results = results.slice(-filter.limit);
|
|
10702
|
+
return results;
|
|
10703
|
+
}
|
|
10704
|
+
getEntry(index) {
|
|
10705
|
+
return this.entries[index];
|
|
10706
|
+
}
|
|
10707
|
+
get length() {
|
|
10708
|
+
return this.entries.length;
|
|
10709
|
+
}
|
|
10710
|
+
};
|
|
10711
|
+
var MAX_TTL_SECONDS = 3600;
|
|
10712
|
+
var MAX_BUDGET = 100;
|
|
10713
|
+
function signablePayload(token) {
|
|
10714
|
+
const payload = JSON.stringify({
|
|
10715
|
+
budget: token.budget,
|
|
10716
|
+
expires_at: token.expiresAt,
|
|
10717
|
+
issued_at: token.issuedAt,
|
|
10718
|
+
issued_to: token.issuedTo,
|
|
10719
|
+
scope: [...token.scope].sort(),
|
|
10720
|
+
token_id: token.tokenId
|
|
10721
|
+
});
|
|
10722
|
+
return Buffer.from(payload);
|
|
10723
|
+
}
|
|
10724
|
+
function issueToken(params, signingKey) {
|
|
10725
|
+
const issuedAt = Date.now() / 1e3;
|
|
10726
|
+
const ttl = Math.min(params.ttlSeconds ?? 60, MAX_TTL_SECONDS);
|
|
10727
|
+
const budget = Math.min(params.budget ?? 1, MAX_BUDGET);
|
|
10728
|
+
const token = {
|
|
10729
|
+
tokenId: randomUUID(),
|
|
10730
|
+
issuedTo: params.issuedTo,
|
|
10731
|
+
scope: [...params.scope].sort(),
|
|
10732
|
+
issuedAt,
|
|
10733
|
+
expiresAt: issuedAt + ttl,
|
|
10734
|
+
budget,
|
|
10735
|
+
uses: 0,
|
|
10736
|
+
revoked: false,
|
|
10737
|
+
metadata: params.metadata ?? {},
|
|
10738
|
+
signature: ""
|
|
10739
|
+
};
|
|
10740
|
+
token.signature = createHmac("sha256", signingKey).update(signablePayload(token)).digest("hex");
|
|
10741
|
+
return token;
|
|
10742
|
+
}
|
|
10743
|
+
function verifyToken(token, signingKey) {
|
|
10744
|
+
if (!token.signature) return false;
|
|
10745
|
+
const expected = createHmac("sha256", signingKey).update(signablePayload(token)).digest("hex");
|
|
10746
|
+
const a = Buffer.from(token.signature, "hex");
|
|
10747
|
+
const b = Buffer.from(expected, "hex");
|
|
10748
|
+
if (a.length !== b.length) return false;
|
|
10749
|
+
return timingSafeEqual(a, b);
|
|
10750
|
+
}
|
|
10751
|
+
function isTokenValid(token) {
|
|
10752
|
+
return !token.revoked && Date.now() / 1e3 <= token.expiresAt && token.uses < token.budget;
|
|
10753
|
+
}
|
|
10754
|
+
function consumeToken(token) {
|
|
10755
|
+
if (!isTokenValid(token)) return false;
|
|
10756
|
+
token.uses++;
|
|
10757
|
+
return true;
|
|
10758
|
+
}
|
|
10759
|
+
function revokeToken(token) {
|
|
10760
|
+
token.revoked = true;
|
|
10761
|
+
}
|
|
10762
|
+
var ThresholdAuthorizer = class {
|
|
10763
|
+
/**
|
|
10764
|
+
* @param k Minimum approvals required (must be >= 2, P2)
|
|
10765
|
+
* @param approverIds List of registered approver IDs (length >= k)
|
|
10766
|
+
* @param auditLog Optional audit chain for all voting events
|
|
10767
|
+
*/
|
|
10768
|
+
constructor(k, approverIds, auditLog) {
|
|
10769
|
+
this.requests = /* @__PURE__ */ new Map();
|
|
10770
|
+
if (k < 2) throw new Error("Threshold must be >= 2 \u2014 no unilateral authority (P2)");
|
|
10771
|
+
if (k > approverIds.length) throw new Error("Threshold cannot exceed number of approvers");
|
|
10772
|
+
this.k = k;
|
|
10773
|
+
this.n = approverIds.length;
|
|
10774
|
+
this.approverIds = new Set(approverIds);
|
|
10775
|
+
this.auditLog = auditLog;
|
|
10776
|
+
}
|
|
10777
|
+
/**
|
|
10778
|
+
* Create a new approval request for a critical action.
|
|
10779
|
+
* The request window is 5 minutes (300s).
|
|
10780
|
+
*/
|
|
10781
|
+
createRequest(actionDescription, requester, criticality = "critical") {
|
|
10782
|
+
const req = {
|
|
10783
|
+
requestId: randomUUID(),
|
|
10784
|
+
actionDescription,
|
|
10785
|
+
criticality,
|
|
10786
|
+
requester,
|
|
10787
|
+
createdAt: Date.now() / 1e3,
|
|
10788
|
+
ttlSeconds: 300,
|
|
10789
|
+
approvals: /* @__PURE__ */ new Map(),
|
|
10790
|
+
resolved: false,
|
|
10791
|
+
resolution: null
|
|
10792
|
+
};
|
|
10793
|
+
this.requests.set(req.requestId, req);
|
|
10794
|
+
this.auditLog?.append({
|
|
10795
|
+
event: "APPROVAL_REQUEST_CREATED",
|
|
10796
|
+
requestId: req.requestId,
|
|
10797
|
+
action: actionDescription,
|
|
10798
|
+
requester,
|
|
10799
|
+
criticality
|
|
10800
|
+
});
|
|
10801
|
+
return req;
|
|
10802
|
+
}
|
|
10803
|
+
/**
|
|
10804
|
+
* Submit a vote for a pending request.
|
|
10805
|
+
* Auto-resolves the request when threshold is reached (approve)
|
|
10806
|
+
* or when threshold becomes mathematically unreachable (deny).
|
|
10807
|
+
*
|
|
10808
|
+
* @throws if request not found, already resolved, expired, approver not registered, or double-vote
|
|
10809
|
+
*/
|
|
10810
|
+
submitVote(requestId, approverId, vote) {
|
|
10811
|
+
const req = this.requests.get(requestId);
|
|
10812
|
+
if (!req) throw new Error(`Request ${requestId} not found`);
|
|
10813
|
+
if (req.resolved) throw new Error(`Request ${requestId} already resolved (P4)`);
|
|
10814
|
+
if (this.isExpired(requestId)) {
|
|
10815
|
+
req.resolved = true;
|
|
10816
|
+
req.resolution = "expired";
|
|
10817
|
+
this.auditLog?.append({ event: "REQUEST_EXPIRED", requestId });
|
|
10818
|
+
throw new Error(`Request ${requestId} has expired`);
|
|
10819
|
+
}
|
|
10820
|
+
if (!this.approverIds.has(approverId)) {
|
|
10821
|
+
throw new Error(`Approver ${approverId} is not registered`);
|
|
10822
|
+
}
|
|
10823
|
+
if (req.approvals.has(approverId)) {
|
|
10824
|
+
throw new Error(`Approver ${approverId} has already voted`);
|
|
10825
|
+
}
|
|
10826
|
+
req.approvals.set(approverId, vote);
|
|
10827
|
+
this.auditLog?.append({ event: "VOTE_SUBMITTED", requestId, approverId, vote });
|
|
10828
|
+
const yesVotes = [...req.approvals.values()].filter(Boolean).length;
|
|
10829
|
+
const noVotes = [...req.approvals.values()].filter((v) => !v).length;
|
|
10830
|
+
if (yesVotes >= this.k) {
|
|
10831
|
+
req.resolved = true;
|
|
10832
|
+
req.resolution = "approved";
|
|
10833
|
+
this.auditLog?.append({ event: "REQUEST_APPROVED", requestId, approvals: yesVotes });
|
|
10834
|
+
}
|
|
10835
|
+
if (!req.resolved && noVotes > this.n - this.k) {
|
|
10836
|
+
req.resolved = true;
|
|
10837
|
+
req.resolution = "denied";
|
|
10838
|
+
this.auditLog?.append({ event: "REQUEST_DENIED", requestId, denials: noVotes });
|
|
10839
|
+
}
|
|
10840
|
+
return {
|
|
10841
|
+
status: req.resolved ? req.resolution : "pending",
|
|
10842
|
+
approvals: yesVotes,
|
|
10843
|
+
denials: noVotes,
|
|
10844
|
+
threshold: this.k,
|
|
10845
|
+
remaining: Math.max(0, this.k - yesVotes)
|
|
10846
|
+
};
|
|
10847
|
+
}
|
|
10848
|
+
/** Returns true iff the request is resolved and approved (P1). */
|
|
10849
|
+
isApproved(requestId) {
|
|
10850
|
+
const req = this.requests.get(requestId);
|
|
10851
|
+
return !!req?.resolved && req.resolution === "approved";
|
|
10852
|
+
}
|
|
10853
|
+
/** Returns true iff the request is resolved and denied (P3). */
|
|
10854
|
+
isDenied(requestId) {
|
|
10855
|
+
const req = this.requests.get(requestId);
|
|
10856
|
+
return !!req?.resolved && req.resolution === "denied";
|
|
10857
|
+
}
|
|
10858
|
+
isExpired(requestId) {
|
|
10859
|
+
const req = this.requests.get(requestId);
|
|
10860
|
+
if (!req) return true;
|
|
10861
|
+
return Date.now() / 1e3 > req.createdAt + req.ttlSeconds;
|
|
10862
|
+
}
|
|
10863
|
+
getRequest(requestId) {
|
|
10864
|
+
return this.requests.get(requestId);
|
|
10865
|
+
}
|
|
10866
|
+
};
|
|
10867
|
+
|
|
10868
|
+
// src/security/rate-limiter.ts
|
|
10869
|
+
var SlidingWindowCounter = class {
|
|
10870
|
+
constructor(max, windowSeconds, cooldownSeconds) {
|
|
10871
|
+
this.max = max;
|
|
10872
|
+
this.windowSeconds = windowSeconds;
|
|
10873
|
+
this.cooldownSeconds = cooldownSeconds;
|
|
10874
|
+
this.timestamps = [];
|
|
10875
|
+
this.cooldownUntil = 0;
|
|
10876
|
+
}
|
|
10877
|
+
allow(now = Date.now() / 1e3) {
|
|
10878
|
+
if (now < this.cooldownUntil) return false;
|
|
10879
|
+
this.evict(now);
|
|
10880
|
+
if (this.timestamps.length >= this.max) {
|
|
10881
|
+
this.cooldownUntil = now + this.cooldownSeconds;
|
|
10882
|
+
return false;
|
|
10883
|
+
}
|
|
10884
|
+
this.timestamps.push(now);
|
|
10885
|
+
return true;
|
|
10886
|
+
}
|
|
10887
|
+
remaining(now = Date.now() / 1e3) {
|
|
10888
|
+
this.evict(now);
|
|
10889
|
+
return Math.max(0, this.max - this.timestamps.length);
|
|
10890
|
+
}
|
|
10891
|
+
get inCooldown() {
|
|
10892
|
+
return Date.now() / 1e3 < this.cooldownUntil;
|
|
10893
|
+
}
|
|
10894
|
+
reset() {
|
|
10895
|
+
this.timestamps = [];
|
|
10896
|
+
this.cooldownUntil = 0;
|
|
10897
|
+
}
|
|
10898
|
+
evict(now) {
|
|
10899
|
+
const cutoff = now - this.windowSeconds;
|
|
10900
|
+
while (this.timestamps.length > 0 && (this.timestamps[0] ?? 0) < cutoff) {
|
|
10901
|
+
this.timestamps.shift();
|
|
10902
|
+
}
|
|
10903
|
+
}
|
|
10904
|
+
};
|
|
10905
|
+
var RateLimiter = class {
|
|
10906
|
+
constructor(config = {}, auditLog) {
|
|
10907
|
+
this.counters = /* @__PURE__ */ new Map();
|
|
10908
|
+
this.config = {
|
|
10909
|
+
maxRequests: config.maxRequests ?? 20,
|
|
10910
|
+
windowSeconds: config.windowSeconds ?? 60,
|
|
10911
|
+
cooldownSeconds: config.cooldownSeconds ?? 30
|
|
10912
|
+
};
|
|
10913
|
+
this.global = new SlidingWindowCounter(
|
|
10914
|
+
this.config.maxRequests * 10,
|
|
10915
|
+
this.config.windowSeconds,
|
|
10916
|
+
this.config.cooldownSeconds
|
|
10917
|
+
);
|
|
10918
|
+
this.auditLog = auditLog;
|
|
10919
|
+
}
|
|
10920
|
+
/**
|
|
10921
|
+
* Check whether the (entity, scope) pair is allowed to proceed.
|
|
10922
|
+
* Checks the global counter first, then the per-entity counter.
|
|
10923
|
+
*/
|
|
10924
|
+
allow(entity, scope = "*") {
|
|
10925
|
+
if (!this.global.allow()) {
|
|
10926
|
+
this.auditLog?.append({ event: "GLOBAL_RATE_LIMIT", entity, scope });
|
|
10927
|
+
return false;
|
|
10928
|
+
}
|
|
10929
|
+
const key = `${entity}:${scope}`;
|
|
10930
|
+
if (!this.counters.has(key)) {
|
|
10931
|
+
this.counters.set(
|
|
10932
|
+
key,
|
|
10933
|
+
new SlidingWindowCounter(
|
|
10934
|
+
this.config.maxRequests,
|
|
10935
|
+
this.config.windowSeconds,
|
|
10936
|
+
this.config.cooldownSeconds
|
|
10937
|
+
)
|
|
10938
|
+
);
|
|
10939
|
+
}
|
|
10940
|
+
const counter = this.counters.get(key);
|
|
10941
|
+
if (!counter.allow()) {
|
|
10942
|
+
this.auditLog?.append({ event: "ENTITY_RATE_LIMIT", entity, scope });
|
|
10943
|
+
return false;
|
|
10944
|
+
}
|
|
10945
|
+
return true;
|
|
10946
|
+
}
|
|
10947
|
+
remaining(entity, scope = "*") {
|
|
10948
|
+
const key = `${entity}:${scope}`;
|
|
10949
|
+
return this.counters.get(key)?.remaining() ?? this.config.maxRequests;
|
|
10950
|
+
}
|
|
10951
|
+
inCooldown(entity, scope = "*") {
|
|
10952
|
+
const key = `${entity}:${scope}`;
|
|
10953
|
+
return this.counters.get(key)?.inCooldown ?? false;
|
|
10954
|
+
}
|
|
10955
|
+
reset(entity, scope = "*") {
|
|
10956
|
+
const key = `${entity}:${scope}`;
|
|
10957
|
+
this.counters.get(key)?.reset();
|
|
10958
|
+
this.auditLog?.append({ event: "RATE_LIMIT_RESET", entity, scope });
|
|
10959
|
+
}
|
|
10960
|
+
/** Reset all counters including global (test utility). */
|
|
10961
|
+
resetAll() {
|
|
10962
|
+
this.counters.clear();
|
|
10963
|
+
this.global.reset();
|
|
10964
|
+
}
|
|
10965
|
+
};
|
|
10966
|
+
|
|
10967
|
+
// src/security/circuit-breaker.ts
|
|
10968
|
+
var CircuitState = /* @__PURE__ */ ((CircuitState2) => {
|
|
10969
|
+
CircuitState2["CLOSED"] = "CLOSED";
|
|
10970
|
+
CircuitState2["OPEN"] = "OPEN";
|
|
10971
|
+
CircuitState2["HALF_OPEN"] = "HALF_OPEN";
|
|
10972
|
+
return CircuitState2;
|
|
10973
|
+
})(CircuitState || {});
|
|
10974
|
+
var CircuitBreaker = class {
|
|
10975
|
+
constructor(config = {}, auditLog) {
|
|
10976
|
+
this.circuits = /* @__PURE__ */ new Map();
|
|
10977
|
+
this.config = {
|
|
10978
|
+
failureThreshold: config.failureThreshold ?? 3,
|
|
10979
|
+
successThreshold: config.successThreshold ?? 2,
|
|
10980
|
+
recoveryTimeoutSeconds: config.recoveryTimeoutSeconds ?? 30,
|
|
10981
|
+
errorRateWindow: config.errorRateWindow ?? 120,
|
|
10982
|
+
errorRateThreshold: config.errorRateThreshold ?? 0.5
|
|
10983
|
+
};
|
|
10984
|
+
this.auditLog = auditLog;
|
|
10985
|
+
}
|
|
10986
|
+
getOrCreate(workerId) {
|
|
10987
|
+
if (!this.circuits.has(workerId)) {
|
|
10988
|
+
this.circuits.set(workerId, {
|
|
10989
|
+
workerId,
|
|
10990
|
+
state: "CLOSED" /* CLOSED */,
|
|
10991
|
+
consecutiveFailures: 0,
|
|
10992
|
+
consecutiveSuccesses: 0,
|
|
10993
|
+
totalRequests: 0,
|
|
10994
|
+
totalFailures: 0,
|
|
10995
|
+
lastFailureTime: 0,
|
|
10996
|
+
openedAt: 0,
|
|
10997
|
+
lastTransitionTime: Date.now() / 1e3,
|
|
10998
|
+
recent: []
|
|
10999
|
+
});
|
|
11000
|
+
}
|
|
11001
|
+
return this.circuits.get(workerId);
|
|
11002
|
+
}
|
|
11003
|
+
/** Compute error rate for the worker within the configured window. Prunes stale entries. */
|
|
11004
|
+
errorRate(circuit, now = Date.now() / 1e3) {
|
|
11005
|
+
const cutoff = now - this.config.errorRateWindow;
|
|
11006
|
+
circuit.recent = circuit.recent.filter((r) => r.timestamp >= cutoff);
|
|
11007
|
+
if (circuit.recent.length === 0) return 0;
|
|
11008
|
+
const failures = circuit.recent.filter((r) => !r.success).length;
|
|
11009
|
+
return failures / circuit.recent.length;
|
|
11010
|
+
}
|
|
11011
|
+
transition(circuit, newState) {
|
|
11012
|
+
const oldState = circuit.state;
|
|
11013
|
+
circuit.state = newState;
|
|
11014
|
+
circuit.lastTransitionTime = Date.now() / 1e3;
|
|
11015
|
+
if (newState === "OPEN" /* OPEN */) circuit.openedAt = circuit.lastTransitionTime;
|
|
11016
|
+
if (newState === "CLOSED" /* CLOSED */) circuit.consecutiveFailures = 0;
|
|
11017
|
+
this.auditLog?.append({
|
|
11018
|
+
event: "CIRCUIT_TRANSITION",
|
|
11019
|
+
workerId: circuit.workerId,
|
|
11020
|
+
from: oldState,
|
|
11021
|
+
to: newState
|
|
11022
|
+
});
|
|
11023
|
+
}
|
|
11024
|
+
/**
|
|
11025
|
+
* Check whether the worker is allowed to proceed.
|
|
11026
|
+
* - CLOSED: always allowed
|
|
11027
|
+
* - OPEN: blocked until recovery timeout, then transitions to HALF_OPEN
|
|
11028
|
+
* - HALF_OPEN: probe allowed through
|
|
11029
|
+
*/
|
|
11030
|
+
allow(workerId) {
|
|
11031
|
+
const now = Date.now() / 1e3;
|
|
11032
|
+
const c = this.getOrCreate(workerId);
|
|
11033
|
+
if (c.state === "CLOSED" /* CLOSED */) return true;
|
|
11034
|
+
if (c.state === "OPEN" /* OPEN */) {
|
|
11035
|
+
if (now - c.openedAt >= this.config.recoveryTimeoutSeconds) {
|
|
11036
|
+
this.transition(c, "HALF_OPEN" /* HALF_OPEN */);
|
|
11037
|
+
return true;
|
|
11038
|
+
}
|
|
11039
|
+
return false;
|
|
11040
|
+
}
|
|
11041
|
+
return true;
|
|
11042
|
+
}
|
|
11043
|
+
recordSuccess(workerId) {
|
|
11044
|
+
const now = Date.now() / 1e3;
|
|
11045
|
+
const c = this.getOrCreate(workerId);
|
|
11046
|
+
c.consecutiveFailures = 0;
|
|
11047
|
+
c.consecutiveSuccesses++;
|
|
11048
|
+
c.totalRequests++;
|
|
11049
|
+
c.recent.push({ timestamp: now, success: true });
|
|
11050
|
+
if (c.state === "HALF_OPEN" /* HALF_OPEN */ && c.consecutiveSuccesses >= this.config.successThreshold) {
|
|
11051
|
+
this.transition(c, "CLOSED" /* CLOSED */);
|
|
11052
|
+
}
|
|
11053
|
+
}
|
|
11054
|
+
recordFailure(workerId) {
|
|
11055
|
+
const now = Date.now() / 1e3;
|
|
11056
|
+
const c = this.getOrCreate(workerId);
|
|
11057
|
+
c.consecutiveFailures++;
|
|
11058
|
+
c.consecutiveSuccesses = 0;
|
|
11059
|
+
c.totalRequests++;
|
|
11060
|
+
c.totalFailures++;
|
|
11061
|
+
c.lastFailureTime = now;
|
|
11062
|
+
c.recent.push({ timestamp: now, success: false });
|
|
11063
|
+
if (c.state === "HALF_OPEN" /* HALF_OPEN */) {
|
|
11064
|
+
this.transition(c, "OPEN" /* OPEN */);
|
|
11065
|
+
return;
|
|
11066
|
+
}
|
|
11067
|
+
if (c.state === "CLOSED" /* CLOSED */) {
|
|
11068
|
+
if (c.consecutiveFailures >= this.config.failureThreshold) {
|
|
11069
|
+
this.transition(c, "OPEN" /* OPEN */);
|
|
11070
|
+
return;
|
|
11071
|
+
}
|
|
11072
|
+
if (c.totalRequests >= 5 && this.errorRate(c, now) >= this.config.errorRateThreshold) {
|
|
11073
|
+
this.transition(c, "OPEN" /* OPEN */);
|
|
11074
|
+
}
|
|
11075
|
+
}
|
|
11076
|
+
}
|
|
11077
|
+
getState(workerId) {
|
|
11078
|
+
return this.getOrCreate(workerId).state;
|
|
11079
|
+
}
|
|
11080
|
+
getStats(workerId) {
|
|
11081
|
+
const c = this.getOrCreate(workerId);
|
|
11082
|
+
return {
|
|
11083
|
+
state: c.state,
|
|
11084
|
+
consecutiveFailures: c.consecutiveFailures,
|
|
11085
|
+
totalRequests: c.totalRequests,
|
|
11086
|
+
totalFailures: c.totalFailures
|
|
11087
|
+
};
|
|
11088
|
+
}
|
|
11089
|
+
};
|
|
11090
|
+
|
|
11091
|
+
// src/tools/sandbox-executor.ts
|
|
11092
|
+
async function executeSandboxed(code, inputs = {}, options = {}) {
|
|
11093
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
11094
|
+
const memoryLimitMb = options.memoryLimitMb ?? 32;
|
|
11095
|
+
let ivm;
|
|
11096
|
+
try {
|
|
11097
|
+
ivm = await import('isolated-vm');
|
|
11098
|
+
} catch {
|
|
11099
|
+
return executeSandboxedFallback(code, inputs, timeoutMs);
|
|
11100
|
+
}
|
|
11101
|
+
const isolate = new ivm.Isolate({ memoryLimit: memoryLimitMb });
|
|
11102
|
+
try {
|
|
11103
|
+
const context = await isolate.createContext();
|
|
11104
|
+
const jail = context.global;
|
|
11105
|
+
await jail.set("global", jail.derefInto());
|
|
11106
|
+
await jail.set("inputs", new ivm.ExternalCopy(inputs).copyInto());
|
|
11107
|
+
const script = await isolate.compileScript(code);
|
|
11108
|
+
const result = await script.run(context, { timeout: timeoutMs });
|
|
11109
|
+
return { success: true, value: result };
|
|
11110
|
+
} catch (err) {
|
|
11111
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11112
|
+
const timedOut = message.includes("Script execution timed out");
|
|
11113
|
+
return { success: false, error: message, timedOut };
|
|
11114
|
+
} finally {
|
|
11115
|
+
isolate.dispose();
|
|
11116
|
+
}
|
|
11117
|
+
}
|
|
11118
|
+
async function executeSandboxedFallback(code, inputs, timeoutMs) {
|
|
11119
|
+
const vm = await import('vm');
|
|
11120
|
+
const sandbox = { inputs, result: void 0 };
|
|
11121
|
+
try {
|
|
11122
|
+
vm.createContext(sandbox);
|
|
11123
|
+
vm.runInContext(code, sandbox, { timeout: timeoutMs });
|
|
11124
|
+
return { success: true, value: sandbox.result };
|
|
11125
|
+
} catch (err) {
|
|
11126
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11127
|
+
const timedOut = message.includes("timed out");
|
|
11128
|
+
return { success: false, error: message, timedOut };
|
|
11129
|
+
}
|
|
11130
|
+
}
|
|
9577
11131
|
var export_applySectionUpdate = domain_language_exports.applySectionUpdate;
|
|
9578
11132
|
var export_convertDomainToSchema = domain_language_exports.convertDomainToSchema;
|
|
9579
11133
|
var export_convertSchemaToDomain = domain_language_exports.convertSchemaToDomain;
|
|
9580
11134
|
var export_deleteSection = domain_language_exports.deleteSection;
|
|
9581
11135
|
|
|
9582
|
-
export { AgenticSearchEngine, ContinueRequestSchema, DEFAULT_COMPACTION_CONFIG, EVENT_BUDGETS, ExtractedRequirementsSchema, FirestoreCheckpointer, FirestoreSessionStore, FirestoreStore, GenerateRequestSchema, MCPClient, MCPClientManager, MCPResourceRegistry, MCPServer, MCPToolRegistry, MemoryManager, MemoryOrbitalSchema, MemorySessionBackend, MetricsCollector, ModelRouter, MultiUserManager, ObservabilityCollector, OnlineEvalSampler, PreferenceLearner, QwenCircuitBreaker, ResumeRequestSchema, SessionManager, StateSyncManager, WorkflowBuilder, WorkflowEngine, analyzeFailures, applyConservativeBias, export_applySectionUpdate as applySectionUpdate, combineOrbitals, combineOrbitalsToSchema, export_convertDomainToSchema as convertDomainToSchema, export_convertSchemaToDomain as convertSchemaToDomain, createAgentTools, createAgenticSearchEngine, createAlmadarMCPServer, createApplyChunkTool, createCombineSchemasTool, createCompactSystemPrompt, createConstructCombinedDomainTool, createDefaultMCPClientManager, createDomainOrbitalTools, createErrorFixerSubagent, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createMCPClient, createMCPClientManager, createMCPServer, createModelRouter, createOnlineEvalSampler, createOrbitalSubagentTool, createPreferenceLearner, createQuerySchemaStructureTool, createSSEEvent, createSchemaChunkingTools, createSchemaGenerationWorkflow, createSchemaGeneratorSubagent, createSkillAgent, createSubagentConfigs, createSubagentEventWrapper, createSubagents, createSummaryPrompt, createSystemPrompt, createTestAnalyzerSubagent, createTraitEventWrapper, createTraitSubagentTool, createUserContext, createValidateSchemaTool, createWorkflowEngine, debounceSync, export_deleteSection as deleteSection, endObservabilitySession, estimateCacheSavings, estimateCombineComplexity, estimateOrbitalCount, estimateOrbitalCountBatch, estimateOrbitalCountHeuristic, estimateOrbitalCountLLM, estimateTokens, extractFileOperation, extractInterruptData, formatSSEEvent, formatSummary, generateFullOrbital, getBudgetWarningMessage, getCircuitBreaker, getEventBudget, getInterruptConfig, getModelRouter, getMultiUserManager, getObservabilityCollector, getPerformanceSnapshot, getStateSyncManager, hasDefiniteComplexIndicators, hasInterrupt, isAdmin, isCompleteEvent, isErrorEvent, isExecutionEvent, isFileOperation, isSSECompleteEvent, isSSEErrorEvent, isSSEGenerationLogEvent, isSSEInterruptEvent, isSSEMessageEvent, isSSEStartEvent, isSSESubagentEvent, isSSETodoDetailEvent, isSSETodoUpdateEvent, isSSEToolCallEvent, isSchemaEvent, isStartEvent, isTodoUpdate, makeSafeRoutingDecision, needsCompaction, parseDeepAgentEvent, parseSSEEvent, quickEstimate, recordEvent, requireOwnership, resetMultiUserManager, resetObservabilityCollector, resetStateSyncManager, resumeSkillAgent, reviewSamples, safeEstimate, startObservabilitySession, transformAgentEvent, transformAgentEventMulti, validateCommandPaths, withSync };
|
|
11136
|
+
export { AgenticSearchEngine, AuditLog, CRITICAL_COMMAND_PATTERNS, CircuitBreaker, CircuitState, ContinueRequestSchema, DEFAULT_COMPACTION_CONFIG, EVENT_BUDGETS, ExtractedRequirementsSchema, FirestoreCheckpointer, FirestoreSessionStore, FirestoreStore, GenerateRequestSchema, MCPClient, MCPClientManager, MCPResourceRegistry, MCPServer, MCPToolRegistry, MemoryManager, MemoryOrbitalSchema, MemorySessionBackend, MetricsCollector, ModelRouter, MultiUserManager, ObservabilityCollector, OnlineEvalSampler, PreferenceLearner, QwenCircuitBreaker, RateLimiter, ResumeRequestSchema, SessionManager, StateSyncManager, TOOL_GATES, ThresholdAuthorizer, WorkflowBuilder, WorkflowEngine, analyzeFailures, applyConservativeBias, export_applySectionUpdate as applySectionUpdate, classifyCommand, classifyComplexity, combineOrbitals, combineOrbitalsToSchema, consumeToken, export_convertDomainToSchema as convertDomainToSchema, export_convertSchemaToDomain as convertSchemaToDomain, createAgentTools, createAgenticSearchEngine, createAlmadarMCPServer, createApplyChunkTool, createCombineSchemasTool, createCompactSystemPrompt, createConstructCombinedDomainTool, createDefaultMCPClientManager, createDomainOrbitalTools, createErrorFixerSubagent, createEvalWorkflowWrapper, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createMCPClient, createMCPClientManager, createMCPServer, createModelRouter, createOnlineEvalSampler, createOrbitalSubagentTool, createPreferenceLearner, createQuerySchemaStructureTool, createSSEEvent, createSchemaChunkingTools, createSchemaGenerationWorkflow, createSchemaGeneratorSubagent, createSkillAgent, createSubagentConfigs, createSubagentEventWrapper, createSubagents, createSummaryPrompt, createSystemPrompt, createTestAnalyzerSubagent, createTraitEventWrapper, createTraitSubagentTool, createUserContext, createValidateSchemaTool, createWorkflowEngine, createWorkflowToolWrapper, debounceSync, export_deleteSection as deleteSection, endObservabilitySession, estimateCacheSavings, estimateCombineComplexity, estimateComplexity, estimateOrbitalCount, estimateOrbitalCountBatch, estimateOrbitalCountHeuristic, estimateOrbitalCountLLM, estimateTokens, executeSandboxed, extractFileOperation, extractInterruptData, formatSSEEvent, formatSummary, generateFullOrbital, getBudgetWarningMessage, getCircuitBreaker, getEventBudget, getExecutionStrategy, getInterruptConfig, getModelRouter, getMultiUserManager, getObservabilityCollector, getPerformanceSnapshot, getStateSyncManager, hasDefiniteComplexIndicators, hasInterrupt, isAdmin, isCompleteEvent, isErrorEvent, isExecutionEvent, isFileOperation, isSSECompleteEvent, isSSEErrorEvent, isSSEGenerationLogEvent, isSSEInterruptEvent, isSSEMessageEvent, isSSEStartEvent, isSSESubagentEvent, isSSETodoDetailEvent, isSSETodoUpdateEvent, isSSEToolCallEvent, isSchemaEvent, isStartEvent, isTodoUpdate, isTokenValid, issueToken, makeSafeRoutingDecision, needsCompaction, parseDeepAgentEvent, parseSSEEvent, quickComplexityCheck, quickEstimate, recordEvent, requireOwnership, resetMultiUserManager, resetObservabilityCollector, resetStateSyncManager, resumeSkillAgent, reviewSamples, revokeToken, routeGeneration, safeEstimate, startObservabilitySession, transformAgentEvent, transformAgentEventMulti, validateCommandPaths, verifyToken, withSync };
|
|
9583
11137
|
//# sourceMappingURL=index.js.map
|
|
9584
11138
|
//# sourceMappingURL=index.js.map
|