@dotsetlabs/bellwether 0.10.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/CHANGELOG.md +291 -0
- package/LICENSE +21 -0
- package/README.md +739 -0
- package/dist/auth/credentials.d.ts +64 -0
- package/dist/auth/credentials.js +218 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.js +6 -0
- package/dist/auth/keychain.d.ts +64 -0
- package/dist/auth/keychain.js +268 -0
- package/dist/baseline/ab-testing.d.ts +80 -0
- package/dist/baseline/ab-testing.js +236 -0
- package/dist/baseline/ai-compatibility-scorer.d.ts +95 -0
- package/dist/baseline/ai-compatibility-scorer.js +606 -0
- package/dist/baseline/calibration.d.ts +77 -0
- package/dist/baseline/calibration.js +136 -0
- package/dist/baseline/category-matching.d.ts +85 -0
- package/dist/baseline/category-matching.js +289 -0
- package/dist/baseline/change-impact-analyzer.d.ts +98 -0
- package/dist/baseline/change-impact-analyzer.js +592 -0
- package/dist/baseline/comparator.d.ts +64 -0
- package/dist/baseline/comparator.js +916 -0
- package/dist/baseline/confidence.d.ts +55 -0
- package/dist/baseline/confidence.js +122 -0
- package/dist/baseline/converter.d.ts +61 -0
- package/dist/baseline/converter.js +585 -0
- package/dist/baseline/dependency-analyzer.d.ts +89 -0
- package/dist/baseline/dependency-analyzer.js +567 -0
- package/dist/baseline/deprecation-tracker.d.ts +133 -0
- package/dist/baseline/deprecation-tracker.js +322 -0
- package/dist/baseline/diff.d.ts +55 -0
- package/dist/baseline/diff.js +1584 -0
- package/dist/baseline/documentation-scorer.d.ts +205 -0
- package/dist/baseline/documentation-scorer.js +466 -0
- package/dist/baseline/embeddings.d.ts +118 -0
- package/dist/baseline/embeddings.js +251 -0
- package/dist/baseline/error-analyzer.d.ts +198 -0
- package/dist/baseline/error-analyzer.js +721 -0
- package/dist/baseline/evaluation/evaluator.d.ts +42 -0
- package/dist/baseline/evaluation/evaluator.js +323 -0
- package/dist/baseline/evaluation/expanded-dataset.d.ts +45 -0
- package/dist/baseline/evaluation/expanded-dataset.js +1164 -0
- package/dist/baseline/evaluation/golden-dataset.d.ts +58 -0
- package/dist/baseline/evaluation/golden-dataset.js +717 -0
- package/dist/baseline/evaluation/index.d.ts +15 -0
- package/dist/baseline/evaluation/index.js +15 -0
- package/dist/baseline/evaluation/types.d.ts +186 -0
- package/dist/baseline/evaluation/types.js +8 -0
- package/dist/baseline/external-dependency-detector.d.ts +181 -0
- package/dist/baseline/external-dependency-detector.js +524 -0
- package/dist/baseline/golden-output.d.ts +162 -0
- package/dist/baseline/golden-output.js +636 -0
- package/dist/baseline/health-scorer.d.ts +174 -0
- package/dist/baseline/health-scorer.js +451 -0
- package/dist/baseline/incremental-checker.d.ts +97 -0
- package/dist/baseline/incremental-checker.js +174 -0
- package/dist/baseline/index.d.ts +31 -0
- package/dist/baseline/index.js +42 -0
- package/dist/baseline/migration-generator.d.ts +137 -0
- package/dist/baseline/migration-generator.js +554 -0
- package/dist/baseline/migrations.d.ts +60 -0
- package/dist/baseline/migrations.js +197 -0
- package/dist/baseline/performance-tracker.d.ts +214 -0
- package/dist/baseline/performance-tracker.js +577 -0
- package/dist/baseline/pr-comment-generator.d.ts +117 -0
- package/dist/baseline/pr-comment-generator.js +546 -0
- package/dist/baseline/response-fingerprint.d.ts +127 -0
- package/dist/baseline/response-fingerprint.js +728 -0
- package/dist/baseline/response-schema-tracker.d.ts +129 -0
- package/dist/baseline/response-schema-tracker.js +420 -0
- package/dist/baseline/risk-scorer.d.ts +54 -0
- package/dist/baseline/risk-scorer.js +434 -0
- package/dist/baseline/saver.d.ts +89 -0
- package/dist/baseline/saver.js +554 -0
- package/dist/baseline/scenario-generator.d.ts +151 -0
- package/dist/baseline/scenario-generator.js +905 -0
- package/dist/baseline/schema-compare.d.ts +86 -0
- package/dist/baseline/schema-compare.js +557 -0
- package/dist/baseline/schema-evolution.d.ts +189 -0
- package/dist/baseline/schema-evolution.js +467 -0
- package/dist/baseline/semantic.d.ts +203 -0
- package/dist/baseline/semantic.js +908 -0
- package/dist/baseline/synonyms.d.ts +60 -0
- package/dist/baseline/synonyms.js +386 -0
- package/dist/baseline/telemetry.d.ts +165 -0
- package/dist/baseline/telemetry.js +294 -0
- package/dist/baseline/test-pruner.d.ts +120 -0
- package/dist/baseline/test-pruner.js +387 -0
- package/dist/baseline/types.d.ts +449 -0
- package/dist/baseline/types.js +5 -0
- package/dist/baseline/version.d.ts +138 -0
- package/dist/baseline/version.js +206 -0
- package/dist/cache/index.d.ts +5 -0
- package/dist/cache/index.js +5 -0
- package/dist/cache/response-cache.d.ts +151 -0
- package/dist/cache/response-cache.js +287 -0
- package/dist/ci/index.d.ts +60 -0
- package/dist/ci/index.js +342 -0
- package/dist/cli/commands/auth.d.ts +12 -0
- package/dist/cli/commands/auth.js +352 -0
- package/dist/cli/commands/badge.d.ts +3 -0
- package/dist/cli/commands/badge.js +74 -0
- package/dist/cli/commands/baseline-accept.d.ts +15 -0
- package/dist/cli/commands/baseline-accept.js +178 -0
- package/dist/cli/commands/baseline-migrate.d.ts +12 -0
- package/dist/cli/commands/baseline-migrate.js +164 -0
- package/dist/cli/commands/baseline.d.ts +14 -0
- package/dist/cli/commands/baseline.js +449 -0
- package/dist/cli/commands/beta.d.ts +10 -0
- package/dist/cli/commands/beta.js +231 -0
- package/dist/cli/commands/check.d.ts +11 -0
- package/dist/cli/commands/check.js +820 -0
- package/dist/cli/commands/cloud/badge.d.ts +3 -0
- package/dist/cli/commands/cloud/badge.js +74 -0
- package/dist/cli/commands/cloud/diff.d.ts +6 -0
- package/dist/cli/commands/cloud/diff.js +79 -0
- package/dist/cli/commands/cloud/history.d.ts +6 -0
- package/dist/cli/commands/cloud/history.js +102 -0
- package/dist/cli/commands/cloud/link.d.ts +9 -0
- package/dist/cli/commands/cloud/link.js +119 -0
- package/dist/cli/commands/cloud/login.d.ts +7 -0
- package/dist/cli/commands/cloud/login.js +499 -0
- package/dist/cli/commands/cloud/projects.d.ts +6 -0
- package/dist/cli/commands/cloud/projects.js +44 -0
- package/dist/cli/commands/cloud/shared.d.ts +7 -0
- package/dist/cli/commands/cloud/shared.js +42 -0
- package/dist/cli/commands/cloud/teams.d.ts +8 -0
- package/dist/cli/commands/cloud/teams.js +169 -0
- package/dist/cli/commands/cloud/upload.d.ts +8 -0
- package/dist/cli/commands/cloud/upload.js +181 -0
- package/dist/cli/commands/contract.d.ts +11 -0
- package/dist/cli/commands/contract.js +280 -0
- package/dist/cli/commands/discover.d.ts +3 -0
- package/dist/cli/commands/discover.js +82 -0
- package/dist/cli/commands/eval.d.ts +9 -0
- package/dist/cli/commands/eval.js +187 -0
- package/dist/cli/commands/explore.d.ts +11 -0
- package/dist/cli/commands/explore.js +437 -0
- package/dist/cli/commands/feedback.d.ts +9 -0
- package/dist/cli/commands/feedback.js +174 -0
- package/dist/cli/commands/golden.d.ts +12 -0
- package/dist/cli/commands/golden.js +407 -0
- package/dist/cli/commands/history.d.ts +10 -0
- package/dist/cli/commands/history.js +202 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.js +219 -0
- package/dist/cli/commands/interview.d.ts +3 -0
- package/dist/cli/commands/interview.js +903 -0
- package/dist/cli/commands/link.d.ts +10 -0
- package/dist/cli/commands/link.js +169 -0
- package/dist/cli/commands/login.d.ts +7 -0
- package/dist/cli/commands/login.js +499 -0
- package/dist/cli/commands/preset.d.ts +33 -0
- package/dist/cli/commands/preset.js +297 -0
- package/dist/cli/commands/profile.d.ts +33 -0
- package/dist/cli/commands/profile.js +286 -0
- package/dist/cli/commands/registry.d.ts +11 -0
- package/dist/cli/commands/registry.js +146 -0
- package/dist/cli/commands/shared.d.ts +79 -0
- package/dist/cli/commands/shared.js +196 -0
- package/dist/cli/commands/teams.d.ts +8 -0
- package/dist/cli/commands/teams.js +169 -0
- package/dist/cli/commands/test.d.ts +9 -0
- package/dist/cli/commands/test.js +500 -0
- package/dist/cli/commands/upload.d.ts +8 -0
- package/dist/cli/commands/upload.js +223 -0
- package/dist/cli/commands/validate-config.d.ts +6 -0
- package/dist/cli/commands/validate-config.js +35 -0
- package/dist/cli/commands/verify.d.ts +11 -0
- package/dist/cli/commands/verify.js +283 -0
- package/dist/cli/commands/watch.d.ts +12 -0
- package/dist/cli/commands/watch.js +253 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +178 -0
- package/dist/cli/interactive.d.ts +47 -0
- package/dist/cli/interactive.js +216 -0
- package/dist/cli/output/terminal-reporter.d.ts +19 -0
- package/dist/cli/output/terminal-reporter.js +104 -0
- package/dist/cli/output.d.ts +226 -0
- package/dist/cli/output.js +438 -0
- package/dist/cli/utils/env.d.ts +5 -0
- package/dist/cli/utils/env.js +14 -0
- package/dist/cli/utils/progress.d.ts +59 -0
- package/dist/cli/utils/progress.js +206 -0
- package/dist/cli/utils/server-context.d.ts +10 -0
- package/dist/cli/utils/server-context.js +36 -0
- package/dist/cloud/auth.d.ts +144 -0
- package/dist/cloud/auth.js +374 -0
- package/dist/cloud/client.d.ts +24 -0
- package/dist/cloud/client.js +65 -0
- package/dist/cloud/http-client.d.ts +38 -0
- package/dist/cloud/http-client.js +215 -0
- package/dist/cloud/index.d.ts +23 -0
- package/dist/cloud/index.js +25 -0
- package/dist/cloud/mock-client.d.ts +107 -0
- package/dist/cloud/mock-client.js +545 -0
- package/dist/cloud/types.d.ts +515 -0
- package/dist/cloud/types.js +15 -0
- package/dist/config/defaults.d.ts +160 -0
- package/dist/config/defaults.js +169 -0
- package/dist/config/loader.d.ts +24 -0
- package/dist/config/loader.js +122 -0
- package/dist/config/template.d.ts +42 -0
- package/dist/config/template.js +647 -0
- package/dist/config/validator.d.ts +2112 -0
- package/dist/config/validator.js +658 -0
- package/dist/constants/cloud.d.ts +107 -0
- package/dist/constants/cloud.js +110 -0
- package/dist/constants/core.d.ts +521 -0
- package/dist/constants/core.js +556 -0
- package/dist/constants/testing.d.ts +1283 -0
- package/dist/constants/testing.js +1568 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.js +10 -0
- package/dist/contract/index.d.ts +6 -0
- package/dist/contract/index.js +5 -0
- package/dist/contract/validator.d.ts +177 -0
- package/dist/contract/validator.js +574 -0
- package/dist/cost/index.d.ts +6 -0
- package/dist/cost/index.js +5 -0
- package/dist/cost/tracker.d.ts +134 -0
- package/dist/cost/tracker.js +313 -0
- package/dist/discovery/discovery.d.ts +16 -0
- package/dist/discovery/discovery.js +173 -0
- package/dist/discovery/types.d.ts +51 -0
- package/dist/discovery/types.js +2 -0
- package/dist/docs/agents.d.ts +3 -0
- package/dist/docs/agents.js +995 -0
- package/dist/docs/contract.d.ts +51 -0
- package/dist/docs/contract.js +1681 -0
- package/dist/docs/generator.d.ts +4 -0
- package/dist/docs/generator.js +4 -0
- package/dist/docs/html-reporter.d.ts +9 -0
- package/dist/docs/html-reporter.js +757 -0
- package/dist/docs/index.d.ts +10 -0
- package/dist/docs/index.js +11 -0
- package/dist/docs/junit-reporter.d.ts +18 -0
- package/dist/docs/junit-reporter.js +210 -0
- package/dist/docs/report.d.ts +14 -0
- package/dist/docs/report.js +44 -0
- package/dist/docs/sarif-reporter.d.ts +19 -0
- package/dist/docs/sarif-reporter.js +335 -0
- package/dist/docs/shared.d.ts +35 -0
- package/dist/docs/shared.js +162 -0
- package/dist/docs/templates.d.ts +12 -0
- package/dist/docs/templates.js +76 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.js +6 -0
- package/dist/errors/retry.d.ts +92 -0
- package/dist/errors/retry.js +323 -0
- package/dist/errors/types.d.ts +321 -0
- package/dist/errors/types.js +584 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +32 -0
- package/dist/interview/dependency-resolver.d.ts +11 -0
- package/dist/interview/dependency-resolver.js +32 -0
- package/dist/interview/interviewer.d.ts +232 -0
- package/dist/interview/interviewer.js +1939 -0
- package/dist/interview/mock-response-generator.d.ts +7 -0
- package/dist/interview/mock-response-generator.js +102 -0
- package/dist/interview/orchestrator.d.ts +237 -0
- package/dist/interview/orchestrator.js +1296 -0
- package/dist/interview/rate-limiter.d.ts +15 -0
- package/dist/interview/rate-limiter.js +55 -0
- package/dist/interview/response-validator.d.ts +10 -0
- package/dist/interview/response-validator.js +132 -0
- package/dist/interview/schema-inferrer.d.ts +8 -0
- package/dist/interview/schema-inferrer.js +71 -0
- package/dist/interview/schema-test-generator.d.ts +71 -0
- package/dist/interview/schema-test-generator.js +834 -0
- package/dist/interview/smart-value-generator.d.ts +155 -0
- package/dist/interview/smart-value-generator.js +554 -0
- package/dist/interview/stateful-test-runner.d.ts +19 -0
- package/dist/interview/stateful-test-runner.js +106 -0
- package/dist/interview/types.d.ts +561 -0
- package/dist/interview/types.js +2 -0
- package/dist/llm/anthropic.d.ts +41 -0
- package/dist/llm/anthropic.js +355 -0
- package/dist/llm/client.d.ts +123 -0
- package/dist/llm/client.js +42 -0
- package/dist/llm/factory.d.ts +38 -0
- package/dist/llm/factory.js +145 -0
- package/dist/llm/fallback.d.ts +140 -0
- package/dist/llm/fallback.js +379 -0
- package/dist/llm/index.d.ts +18 -0
- package/dist/llm/index.js +15 -0
- package/dist/llm/ollama.d.ts +37 -0
- package/dist/llm/ollama.js +330 -0
- package/dist/llm/openai.d.ts +25 -0
- package/dist/llm/openai.js +320 -0
- package/dist/llm/token-budget.d.ts +161 -0
- package/dist/llm/token-budget.js +395 -0
- package/dist/logging/logger.d.ts +70 -0
- package/dist/logging/logger.js +130 -0
- package/dist/metrics/collector.d.ts +106 -0
- package/dist/metrics/collector.js +547 -0
- package/dist/metrics/index.d.ts +7 -0
- package/dist/metrics/index.js +7 -0
- package/dist/metrics/prometheus.d.ts +20 -0
- package/dist/metrics/prometheus.js +241 -0
- package/dist/metrics/types.d.ts +209 -0
- package/dist/metrics/types.js +5 -0
- package/dist/persona/builtins.d.ts +54 -0
- package/dist/persona/builtins.js +219 -0
- package/dist/persona/index.d.ts +8 -0
- package/dist/persona/index.js +8 -0
- package/dist/persona/loader.d.ts +30 -0
- package/dist/persona/loader.js +190 -0
- package/dist/persona/types.d.ts +144 -0
- package/dist/persona/types.js +5 -0
- package/dist/persona/validation.d.ts +94 -0
- package/dist/persona/validation.js +332 -0
- package/dist/prompts/index.d.ts +5 -0
- package/dist/prompts/index.js +5 -0
- package/dist/prompts/templates.d.ts +180 -0
- package/dist/prompts/templates.js +431 -0
- package/dist/registry/client.d.ts +49 -0
- package/dist/registry/client.js +191 -0
- package/dist/registry/index.d.ts +7 -0
- package/dist/registry/index.js +6 -0
- package/dist/registry/types.d.ts +140 -0
- package/dist/registry/types.js +6 -0
- package/dist/scenarios/evaluator.d.ts +43 -0
- package/dist/scenarios/evaluator.js +206 -0
- package/dist/scenarios/index.d.ts +10 -0
- package/dist/scenarios/index.js +9 -0
- package/dist/scenarios/loader.d.ts +20 -0
- package/dist/scenarios/loader.js +285 -0
- package/dist/scenarios/types.d.ts +153 -0
- package/dist/scenarios/types.js +8 -0
- package/dist/security/index.d.ts +17 -0
- package/dist/security/index.js +18 -0
- package/dist/security/payloads.d.ts +61 -0
- package/dist/security/payloads.js +268 -0
- package/dist/security/security-tester.d.ts +42 -0
- package/dist/security/security-tester.js +582 -0
- package/dist/security/types.d.ts +166 -0
- package/dist/security/types.js +8 -0
- package/dist/transport/base-transport.d.ts +59 -0
- package/dist/transport/base-transport.js +38 -0
- package/dist/transport/http-transport.d.ts +67 -0
- package/dist/transport/http-transport.js +238 -0
- package/dist/transport/mcp-client.d.ts +141 -0
- package/dist/transport/mcp-client.js +496 -0
- package/dist/transport/sse-transport.d.ts +88 -0
- package/dist/transport/sse-transport.js +316 -0
- package/dist/transport/stdio-transport.d.ts +43 -0
- package/dist/transport/stdio-transport.js +238 -0
- package/dist/transport/types.d.ts +125 -0
- package/dist/transport/types.js +16 -0
- package/dist/utils/concurrency.d.ts +123 -0
- package/dist/utils/concurrency.js +213 -0
- package/dist/utils/formatters.d.ts +16 -0
- package/dist/utils/formatters.js +37 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/jsonpath.d.ts +87 -0
- package/dist/utils/jsonpath.js +326 -0
- package/dist/utils/markdown.d.ts +113 -0
- package/dist/utils/markdown.js +265 -0
- package/dist/utils/network.d.ts +14 -0
- package/dist/utils/network.js +17 -0
- package/dist/utils/sanitize.d.ts +92 -0
- package/dist/utils/sanitize.js +191 -0
- package/dist/utils/semantic.d.ts +194 -0
- package/dist/utils/semantic.js +1051 -0
- package/dist/utils/smart-truncate.d.ts +94 -0
- package/dist/utils/smart-truncate.js +361 -0
- package/dist/utils/timeout.d.ts +153 -0
- package/dist/utils/timeout.js +205 -0
- package/dist/utils/yaml-parser.d.ts +58 -0
- package/dist/utils/yaml-parser.js +86 -0
- package/dist/validation/index.d.ts +32 -0
- package/dist/validation/index.js +32 -0
- package/dist/validation/semantic-test-generator.d.ts +50 -0
- package/dist/validation/semantic-test-generator.js +176 -0
- package/dist/validation/semantic-types.d.ts +66 -0
- package/dist/validation/semantic-types.js +94 -0
- package/dist/validation/semantic-validator.d.ts +38 -0
- package/dist/validation/semantic-validator.js +340 -0
- package/dist/verification/index.d.ts +6 -0
- package/dist/verification/index.js +5 -0
- package/dist/verification/types.d.ts +133 -0
- package/dist/verification/types.js +5 -0
- package/dist/verification/verifier.d.ts +30 -0
- package/dist/verification/verifier.js +309 -0
- package/dist/version.d.ts +19 -0
- package/dist/version.js +48 -0
- package/dist/workflow/auto-generator.d.ts +27 -0
- package/dist/workflow/auto-generator.js +513 -0
- package/dist/workflow/discovery.d.ts +40 -0
- package/dist/workflow/discovery.js +195 -0
- package/dist/workflow/executor.d.ts +82 -0
- package/dist/workflow/executor.js +611 -0
- package/dist/workflow/index.d.ts +10 -0
- package/dist/workflow/index.js +10 -0
- package/dist/workflow/loader.d.ts +24 -0
- package/dist/workflow/loader.js +194 -0
- package/dist/workflow/state-tracker.d.ts +98 -0
- package/dist/workflow/state-tracker.js +424 -0
- package/dist/workflow/types.d.ts +337 -0
- package/dist/workflow/types.js +5 -0
- package/package.json +94 -0
- package/schemas/bellwether-check.schema.json +651 -0
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow executor - runs workflows and tracks data flow.
|
|
3
|
+
*/
|
|
4
|
+
import { StateTracker } from './state-tracker.js';
|
|
5
|
+
import { buildWorkflowStepAnalysisPrompt, buildWorkflowSummaryPrompt, COMPLETION_OPTIONS, } from '../prompts/templates.js';
|
|
6
|
+
import { getLogger, startTiming } from '../logging/logger.js';
|
|
7
|
+
import { withTimeout, DEFAULT_TIMEOUTS, checkAborted } from '../utils/timeout.js';
|
|
8
|
+
/**
|
|
9
|
+
* Default executor options (excluding callbacks and signal).
|
|
10
|
+
*/
|
|
11
|
+
const DEFAULT_OPTIONS = {
|
|
12
|
+
continueOnError: false,
|
|
13
|
+
stepTimeout: DEFAULT_TIMEOUTS.toolCall,
|
|
14
|
+
analyzeSteps: true,
|
|
15
|
+
generateSummary: true,
|
|
16
|
+
requireSuccessfulDependencies: true,
|
|
17
|
+
timeouts: {
|
|
18
|
+
toolCall: DEFAULT_TIMEOUTS.toolCall,
|
|
19
|
+
stateSnapshot: DEFAULT_TIMEOUTS.stateSnapshot,
|
|
20
|
+
probeTool: DEFAULT_TIMEOUTS.probeTool,
|
|
21
|
+
llmAnalysis: DEFAULT_TIMEOUTS.responseAnalysis,
|
|
22
|
+
llmSummary: DEFAULT_TIMEOUTS.profileSynthesis,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Executes workflows against an MCP server.
|
|
27
|
+
*/
|
|
28
|
+
export class WorkflowExecutor {
|
|
29
|
+
client;
|
|
30
|
+
llm;
|
|
31
|
+
tools;
|
|
32
|
+
options;
|
|
33
|
+
stepResults = [];
|
|
34
|
+
onProgress;
|
|
35
|
+
logger = getLogger('workflow-executor');
|
|
36
|
+
stateTracker;
|
|
37
|
+
timeouts;
|
|
38
|
+
constructor(client, llm, tools, options = {}) {
|
|
39
|
+
this.client = client;
|
|
40
|
+
this.llm = llm;
|
|
41
|
+
this.tools = tools;
|
|
42
|
+
this.options = options;
|
|
43
|
+
// Merge options with defaults, including nested timeouts
|
|
44
|
+
this.options = {
|
|
45
|
+
...DEFAULT_OPTIONS,
|
|
46
|
+
...options,
|
|
47
|
+
timeouts: { ...DEFAULT_OPTIONS.timeouts, ...options.timeouts },
|
|
48
|
+
};
|
|
49
|
+
this.timeouts = this.options.timeouts;
|
|
50
|
+
this.onProgress = options.onProgress;
|
|
51
|
+
// Initialize state tracker if enabled and LLM is available
|
|
52
|
+
// State tracking requires LLM for analysis
|
|
53
|
+
if (this.options.stateTracking?.enabled && llm) {
|
|
54
|
+
this.stateTracker = new StateTracker(client, tools, llm, this.options.stateTracking, {
|
|
55
|
+
snapshotTimeout: this.timeouts.stateSnapshot,
|
|
56
|
+
probeTimeout: this.timeouts.probeTool,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Emit progress event if callback is registered.
|
|
62
|
+
*/
|
|
63
|
+
emitProgress(workflow, phase, currentStep, startTime, currentStepInfo) {
|
|
64
|
+
if (!this.onProgress)
|
|
65
|
+
return;
|
|
66
|
+
const stepsFailed = this.stepResults.filter(r => !r.success).length;
|
|
67
|
+
this.onProgress({
|
|
68
|
+
phase,
|
|
69
|
+
workflow,
|
|
70
|
+
currentStep,
|
|
71
|
+
totalSteps: workflow.steps.length,
|
|
72
|
+
currentStepInfo,
|
|
73
|
+
stepsCompleted: this.stepResults.length,
|
|
74
|
+
stepsFailed,
|
|
75
|
+
elapsedMs: Date.now() - startTime,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Execute a workflow.
|
|
80
|
+
*
|
|
81
|
+
* @param workflow - The workflow to execute
|
|
82
|
+
* @throws AbortError if the operation is aborted via signal
|
|
83
|
+
*/
|
|
84
|
+
async execute(workflow) {
|
|
85
|
+
const signal = this.options.signal;
|
|
86
|
+
const done = startTiming(this.logger, `workflow:${workflow.id}`);
|
|
87
|
+
const startTime = Date.now();
|
|
88
|
+
this.stepResults = [];
|
|
89
|
+
// Check if already aborted before starting
|
|
90
|
+
checkAborted(signal, `Workflow '${workflow.id}'`);
|
|
91
|
+
this.logger.info({
|
|
92
|
+
workflowId: workflow.id,
|
|
93
|
+
workflowName: workflow.name,
|
|
94
|
+
stepCount: workflow.steps.length,
|
|
95
|
+
stateTrackingEnabled: !!this.stateTracker,
|
|
96
|
+
}, 'Starting workflow execution');
|
|
97
|
+
let success = true;
|
|
98
|
+
let failureReason;
|
|
99
|
+
let failedStepIndex;
|
|
100
|
+
// State tracking data
|
|
101
|
+
const snapshots = [];
|
|
102
|
+
const changes = [];
|
|
103
|
+
// Emit starting progress
|
|
104
|
+
this.emitProgress(workflow, 'starting', 0, startTime);
|
|
105
|
+
// Take initial state snapshot if enabled
|
|
106
|
+
if (this.stateTracker && this.options.stateTracking?.snapshotBefore) {
|
|
107
|
+
checkAborted(signal, 'Initial state snapshot');
|
|
108
|
+
this.logger.debug('Taking initial state snapshot');
|
|
109
|
+
const initialSnapshot = await this.stateTracker.takeSnapshot(-1);
|
|
110
|
+
snapshots.push(initialSnapshot);
|
|
111
|
+
}
|
|
112
|
+
for (let i = 0; i < workflow.steps.length; i++) {
|
|
113
|
+
const step = workflow.steps[i];
|
|
114
|
+
// Check for abort before each step
|
|
115
|
+
checkAborted(signal, `Workflow step ${i + 1}/${workflow.steps.length}`);
|
|
116
|
+
// Check if any dependency steps have failed (when requireSuccessfulDependencies is enabled)
|
|
117
|
+
const requireSuccessfulDeps = this.options.requireSuccessfulDependencies ?? DEFAULT_OPTIONS.requireSuccessfulDependencies;
|
|
118
|
+
if (requireSuccessfulDeps) {
|
|
119
|
+
const failedDependencies = this.getFailedDependencies(step, i);
|
|
120
|
+
if (failedDependencies.length > 0) {
|
|
121
|
+
const failedStepNames = failedDependencies.map((idx) => `step ${idx + 1} (${workflow.steps[idx]?.tool ?? 'unknown'})`).join(', ');
|
|
122
|
+
this.logger.debug({
|
|
123
|
+
stepIndex: i,
|
|
124
|
+
tool: step.tool,
|
|
125
|
+
failedDependencies,
|
|
126
|
+
}, 'Skipping step due to failed dependencies');
|
|
127
|
+
const skipResult = {
|
|
128
|
+
step,
|
|
129
|
+
stepIndex: i,
|
|
130
|
+
success: false,
|
|
131
|
+
response: null,
|
|
132
|
+
error: `Skipped: depends on failed ${failedStepNames}`,
|
|
133
|
+
resolvedArgs: step.args ?? {},
|
|
134
|
+
durationMs: 0,
|
|
135
|
+
};
|
|
136
|
+
this.stepResults.push(skipResult);
|
|
137
|
+
// Continue to next step (don't break, let the workflow continue)
|
|
138
|
+
// The step failure will be handled by the existing logic
|
|
139
|
+
if (!step.optional && !this.options.continueOnError) {
|
|
140
|
+
success = false;
|
|
141
|
+
failureReason = skipResult.error;
|
|
142
|
+
failedStepIndex = i;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Emit executing progress before step
|
|
149
|
+
this.emitProgress(workflow, 'executing', i, startTime, step);
|
|
150
|
+
const stepResult = await this.executeStep(step, i, workflow);
|
|
151
|
+
this.stepResults.push(stepResult);
|
|
152
|
+
// Take snapshot after each step if enabled
|
|
153
|
+
if (this.stateTracker && this.options.stateTracking?.snapshotAfterEachStep) {
|
|
154
|
+
checkAborted(signal, `State snapshot after step ${i + 1}`);
|
|
155
|
+
const snapshot = await this.stateTracker.takeSnapshot(i);
|
|
156
|
+
snapshots.push(snapshot);
|
|
157
|
+
// Compare with previous snapshot to detect changes
|
|
158
|
+
if (snapshots.length >= 2) {
|
|
159
|
+
const prevSnapshot = snapshots[snapshots.length - 2];
|
|
160
|
+
const stepChanges = this.stateTracker.compareSnapshots(prevSnapshot, snapshot, i);
|
|
161
|
+
changes.push(...stepChanges);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (!stepResult.success) {
|
|
165
|
+
if (!step.optional && !this.options.continueOnError) {
|
|
166
|
+
success = false;
|
|
167
|
+
failureReason = stepResult.error ?? 'Step failed';
|
|
168
|
+
failedStepIndex = i;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Take final state snapshot if enabled
|
|
174
|
+
if (this.stateTracker && this.options.stateTracking?.snapshotAfter) {
|
|
175
|
+
checkAborted(signal, 'Final state snapshot');
|
|
176
|
+
this.logger.debug('Taking final state snapshot');
|
|
177
|
+
const finalSnapshot = await this.stateTracker.takeSnapshot(this.stepResults.length - 1);
|
|
178
|
+
// If we haven't been taking per-step snapshots, compare initial to final
|
|
179
|
+
if (!this.options.stateTracking?.snapshotAfterEachStep && snapshots.length > 0) {
|
|
180
|
+
const initialSnapshot = snapshots[0];
|
|
181
|
+
const overallChanges = this.stateTracker.compareSnapshots(initialSnapshot, finalSnapshot, this.stepResults.length - 1);
|
|
182
|
+
changes.push(...overallChanges);
|
|
183
|
+
}
|
|
184
|
+
snapshots.push(finalSnapshot);
|
|
185
|
+
}
|
|
186
|
+
// Build data flow graph
|
|
187
|
+
const dataFlow = this.buildDataFlowGraph(workflow);
|
|
188
|
+
// Build state tracking result
|
|
189
|
+
let stateTracking;
|
|
190
|
+
if (this.stateTracker) {
|
|
191
|
+
checkAborted(signal, 'State tracking summary');
|
|
192
|
+
const toolRoles = this.stateTracker.getAllToolInfo();
|
|
193
|
+
let dependencies = this.stateTracker.inferDependencies(this.stepResults);
|
|
194
|
+
// Verify dependencies if we have snapshots
|
|
195
|
+
if (snapshots.length > 0 && changes.length > 0) {
|
|
196
|
+
dependencies = this.stateTracker.verifyDependencies(dependencies, snapshots, changes);
|
|
197
|
+
}
|
|
198
|
+
const summary = await this.stateTracker.generateSummary({
|
|
199
|
+
snapshots,
|
|
200
|
+
changes,
|
|
201
|
+
dependencies,
|
|
202
|
+
toolRoles,
|
|
203
|
+
});
|
|
204
|
+
stateTracking = {
|
|
205
|
+
snapshots,
|
|
206
|
+
changes,
|
|
207
|
+
dependencies,
|
|
208
|
+
toolRoles,
|
|
209
|
+
summary,
|
|
210
|
+
};
|
|
211
|
+
this.logger.debug({
|
|
212
|
+
snapshotCount: snapshots.length,
|
|
213
|
+
changeCount: changes.length,
|
|
214
|
+
dependencyCount: dependencies.length,
|
|
215
|
+
}, 'State tracking complete');
|
|
216
|
+
}
|
|
217
|
+
// Generate summary if requested
|
|
218
|
+
let summary;
|
|
219
|
+
if (this.options.generateSummary) {
|
|
220
|
+
checkAborted(signal, 'Workflow summary generation');
|
|
221
|
+
// Emit summarizing progress
|
|
222
|
+
this.emitProgress(workflow, 'summarizing', workflow.steps.length, startTime);
|
|
223
|
+
summary = await this.generateWorkflowSummary(workflow, this.stepResults, success);
|
|
224
|
+
}
|
|
225
|
+
// Emit complete progress
|
|
226
|
+
this.emitProgress(workflow, 'complete', workflow.steps.length, startTime);
|
|
227
|
+
const durationMs = Date.now() - startTime;
|
|
228
|
+
this.logger.info({
|
|
229
|
+
workflowId: workflow.id,
|
|
230
|
+
success,
|
|
231
|
+
stepsCompleted: this.stepResults.length,
|
|
232
|
+
stepsFailed: this.stepResults.filter(r => !r.success).length,
|
|
233
|
+
durationMs,
|
|
234
|
+
}, 'Workflow execution complete');
|
|
235
|
+
done();
|
|
236
|
+
return {
|
|
237
|
+
workflow,
|
|
238
|
+
steps: this.stepResults,
|
|
239
|
+
success,
|
|
240
|
+
failureReason,
|
|
241
|
+
failedStepIndex,
|
|
242
|
+
durationMs,
|
|
243
|
+
dataFlow,
|
|
244
|
+
summary,
|
|
245
|
+
stateTracking,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Execute a single workflow step.
|
|
250
|
+
*/
|
|
251
|
+
async executeStep(step, stepIndex, workflow) {
|
|
252
|
+
const startTime = Date.now();
|
|
253
|
+
// Verify tool exists
|
|
254
|
+
const tool = this.tools.find(t => t.name === step.tool);
|
|
255
|
+
if (!tool) {
|
|
256
|
+
return {
|
|
257
|
+
step,
|
|
258
|
+
stepIndex,
|
|
259
|
+
success: false,
|
|
260
|
+
response: null,
|
|
261
|
+
error: `Tool not found: ${step.tool}`,
|
|
262
|
+
resolvedArgs: {},
|
|
263
|
+
durationMs: Date.now() - startTime,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
// Resolve arguments (apply mapping from previous steps)
|
|
267
|
+
let resolvedArgs;
|
|
268
|
+
try {
|
|
269
|
+
resolvedArgs = this.resolveArguments(step, stepIndex);
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
return {
|
|
273
|
+
step,
|
|
274
|
+
stepIndex,
|
|
275
|
+
success: false,
|
|
276
|
+
response: null,
|
|
277
|
+
error: `Failed to resolve arguments: ${error instanceof Error ? error.message : String(error)}`,
|
|
278
|
+
resolvedArgs: step.args ?? {},
|
|
279
|
+
durationMs: Date.now() - startTime,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
// Execute the tool call with timeout
|
|
283
|
+
let response = null;
|
|
284
|
+
let error;
|
|
285
|
+
const stepTimeout = this.options.stepTimeout ?? DEFAULT_OPTIONS.stepTimeout;
|
|
286
|
+
try {
|
|
287
|
+
response = await withTimeout(this.client.callTool(step.tool, resolvedArgs), stepTimeout, `Tool call '${step.tool}'`);
|
|
288
|
+
if (response.isError) {
|
|
289
|
+
error = this.extractErrorMessage(response);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
catch (e) {
|
|
293
|
+
error = e instanceof Error ? e.message : String(e);
|
|
294
|
+
}
|
|
295
|
+
// Run assertions
|
|
296
|
+
const assertionResults = step.assertions
|
|
297
|
+
? this.runAssertions(step.assertions, response)
|
|
298
|
+
: undefined;
|
|
299
|
+
const assertionsFailed = assertionResults?.some(r => !r.passed) ?? false;
|
|
300
|
+
const success = !error && !assertionsFailed;
|
|
301
|
+
// Generate analysis if requested
|
|
302
|
+
let analysis;
|
|
303
|
+
if (this.options.analyzeSteps) {
|
|
304
|
+
analysis = await this.analyzeStep(step, stepIndex, workflow, response, error);
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
step,
|
|
308
|
+
stepIndex,
|
|
309
|
+
success,
|
|
310
|
+
response,
|
|
311
|
+
error,
|
|
312
|
+
resolvedArgs,
|
|
313
|
+
assertionResults,
|
|
314
|
+
durationMs: Date.now() - startTime,
|
|
315
|
+
analysis,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Resolve arguments for a step, applying mappings from previous step outputs.
|
|
320
|
+
*/
|
|
321
|
+
resolveArguments(step, stepIndex) {
|
|
322
|
+
const args = { ...(step.args ?? {}) };
|
|
323
|
+
if (!step.argMapping) {
|
|
324
|
+
return args;
|
|
325
|
+
}
|
|
326
|
+
for (const [paramName, pathExpr] of Object.entries(step.argMapping)) {
|
|
327
|
+
const value = this.resolvePath(pathExpr, stepIndex);
|
|
328
|
+
if (value !== undefined) {
|
|
329
|
+
args[paramName] = value;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return args;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Resolve a JSONPath-like expression against previous step results.
|
|
336
|
+
* Supports: $steps[n].result.path.to.value
|
|
337
|
+
*/
|
|
338
|
+
resolvePath(pathExpr, currentStepIndex) {
|
|
339
|
+
// Parse the path expression
|
|
340
|
+
const match = pathExpr.match(/^\$steps\[(\d+)\]\.(.+)$/);
|
|
341
|
+
if (!match) {
|
|
342
|
+
throw new Error(`Invalid path expression: ${pathExpr}. Expected format: $steps[n].path.to.value`);
|
|
343
|
+
}
|
|
344
|
+
const stepIndex = parseInt(match[1], 10);
|
|
345
|
+
const propertyPath = match[2];
|
|
346
|
+
if (stepIndex >= currentStepIndex) {
|
|
347
|
+
throw new Error(`Cannot reference step ${stepIndex} from step ${currentStepIndex} (can only reference earlier steps)`);
|
|
348
|
+
}
|
|
349
|
+
const stepResult = this.stepResults[stepIndex];
|
|
350
|
+
if (!stepResult) {
|
|
351
|
+
throw new Error(`Step ${stepIndex} has not been executed yet`);
|
|
352
|
+
}
|
|
353
|
+
if (!stepResult.success || !stepResult.response) {
|
|
354
|
+
throw new Error(`Step ${stepIndex} failed or has no response`);
|
|
355
|
+
}
|
|
356
|
+
// Navigate the property path
|
|
357
|
+
// First check if we're accessing 'result' (the raw content) or 'response' (the full response)
|
|
358
|
+
let target;
|
|
359
|
+
if (propertyPath.startsWith('result.') || propertyPath === 'result') {
|
|
360
|
+
// Extract text content from the response
|
|
361
|
+
const content = stepResult.response.content;
|
|
362
|
+
const textContent = content.find(c => c.type === 'text' && c.text !== undefined);
|
|
363
|
+
if (!textContent || textContent.text === undefined) {
|
|
364
|
+
throw new Error(`Step ${stepIndex} response has no text content`);
|
|
365
|
+
}
|
|
366
|
+
const textValue = textContent.text;
|
|
367
|
+
// Try to parse as JSON
|
|
368
|
+
try {
|
|
369
|
+
target = JSON.parse(textValue);
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
target = textValue;
|
|
373
|
+
}
|
|
374
|
+
// Navigate the remaining path after 'result.'
|
|
375
|
+
const remainingPath = propertyPath.replace(/^result\.?/, '');
|
|
376
|
+
if (remainingPath) {
|
|
377
|
+
target = this.navigatePath(target, remainingPath);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
else if (propertyPath.startsWith('response.')) {
|
|
381
|
+
target = this.navigatePath(stepResult.response, propertyPath.replace(/^response\./, ''));
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
throw new Error(`Path must start with 'result.' or 'response.': ${pathExpr}`);
|
|
385
|
+
}
|
|
386
|
+
return target;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Navigate a dot-separated path in an object.
|
|
390
|
+
*/
|
|
391
|
+
navigatePath(obj, path) {
|
|
392
|
+
const parts = path.split('.');
|
|
393
|
+
let current = obj;
|
|
394
|
+
for (const part of parts) {
|
|
395
|
+
if (current === null || current === undefined) {
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
// Handle array access: field[0]
|
|
399
|
+
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
|
|
400
|
+
if (arrayMatch) {
|
|
401
|
+
const [, fieldName, indexStr] = arrayMatch;
|
|
402
|
+
const index = parseInt(indexStr, 10);
|
|
403
|
+
current = current[fieldName];
|
|
404
|
+
if (Array.isArray(current)) {
|
|
405
|
+
current = current[index];
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
current = current[part];
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return current;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Run assertions against a step response.
|
|
419
|
+
*/
|
|
420
|
+
runAssertions(assertions, response) {
|
|
421
|
+
return assertions.map(assertion => this.runAssertion(assertion, response));
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Run a single assertion.
|
|
425
|
+
*/
|
|
426
|
+
runAssertion(assertion, response) {
|
|
427
|
+
if (!response) {
|
|
428
|
+
return {
|
|
429
|
+
assertion,
|
|
430
|
+
passed: false,
|
|
431
|
+
message: assertion.message ?? 'No response to assert against',
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
// Extract the value at the path
|
|
435
|
+
let actualValue;
|
|
436
|
+
try {
|
|
437
|
+
// Parse the response content as JSON
|
|
438
|
+
const textContent = response.content.find(c => c.type === 'text' && c.text !== undefined);
|
|
439
|
+
if (!textContent || textContent.text === undefined) {
|
|
440
|
+
throw new Error('No text content in response');
|
|
441
|
+
}
|
|
442
|
+
const textValue = textContent.text;
|
|
443
|
+
let parsed;
|
|
444
|
+
try {
|
|
445
|
+
parsed = JSON.parse(textValue);
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
parsed = textValue;
|
|
449
|
+
}
|
|
450
|
+
actualValue = this.navigatePath(parsed, assertion.path);
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
return {
|
|
454
|
+
assertion,
|
|
455
|
+
passed: false,
|
|
456
|
+
message: `Failed to extract path ${assertion.path}: ${error instanceof Error ? error.message : String(error)}`,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
// Check the condition
|
|
460
|
+
let passed = false;
|
|
461
|
+
switch (assertion.condition) {
|
|
462
|
+
case 'exists':
|
|
463
|
+
passed = actualValue !== undefined && actualValue !== null;
|
|
464
|
+
break;
|
|
465
|
+
case 'truthy':
|
|
466
|
+
passed = Boolean(actualValue);
|
|
467
|
+
break;
|
|
468
|
+
case 'equals':
|
|
469
|
+
passed = actualValue === assertion.value;
|
|
470
|
+
break;
|
|
471
|
+
case 'contains':
|
|
472
|
+
if (typeof actualValue === 'string' && typeof assertion.value === 'string') {
|
|
473
|
+
passed = actualValue.includes(assertion.value);
|
|
474
|
+
}
|
|
475
|
+
else if (Array.isArray(actualValue)) {
|
|
476
|
+
passed = actualValue.includes(assertion.value);
|
|
477
|
+
}
|
|
478
|
+
break;
|
|
479
|
+
case 'type':
|
|
480
|
+
passed = typeof actualValue === assertion.value;
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
return {
|
|
484
|
+
assertion,
|
|
485
|
+
passed,
|
|
486
|
+
actualValue,
|
|
487
|
+
message: passed ? undefined : (assertion.message ?? `Assertion failed: ${assertion.condition}`),
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Extract error message from a tool response.
|
|
492
|
+
*/
|
|
493
|
+
extractErrorMessage(response) {
|
|
494
|
+
const textContent = response.content.find(c => c.type === 'text');
|
|
495
|
+
if (textContent && 'text' in textContent) {
|
|
496
|
+
return String(textContent.text);
|
|
497
|
+
}
|
|
498
|
+
return 'Unknown error';
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Get indices of dependency steps that have failed.
|
|
502
|
+
* Dependencies are steps referenced in argMapping.
|
|
503
|
+
*/
|
|
504
|
+
getFailedDependencies(step, stepIndex) {
|
|
505
|
+
if (!step.argMapping) {
|
|
506
|
+
return [];
|
|
507
|
+
}
|
|
508
|
+
const failedDeps = [];
|
|
509
|
+
const seenIndices = new Set();
|
|
510
|
+
for (const pathExpr of Object.values(step.argMapping)) {
|
|
511
|
+
const match = pathExpr.match(/^\$steps\[(\d+)\]\.(.+)$/);
|
|
512
|
+
if (!match)
|
|
513
|
+
continue;
|
|
514
|
+
const depIndex = parseInt(match[1], 10);
|
|
515
|
+
// Skip if we already checked this dependency
|
|
516
|
+
if (seenIndices.has(depIndex))
|
|
517
|
+
continue;
|
|
518
|
+
seenIndices.add(depIndex);
|
|
519
|
+
// Check if the dependency step exists and has failed
|
|
520
|
+
if (depIndex >= 0 && depIndex < stepIndex) {
|
|
521
|
+
const depResult = this.stepResults[depIndex];
|
|
522
|
+
if (depResult && !depResult.success) {
|
|
523
|
+
failedDeps.push(depIndex);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return failedDeps;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Build a data flow graph showing how data moves between steps.
|
|
531
|
+
*/
|
|
532
|
+
buildDataFlowGraph(workflow) {
|
|
533
|
+
const edges = [];
|
|
534
|
+
for (let i = 0; i < workflow.steps.length; i++) {
|
|
535
|
+
const step = workflow.steps[i];
|
|
536
|
+
if (!step.argMapping)
|
|
537
|
+
continue;
|
|
538
|
+
for (const [targetParam, pathExpr] of Object.entries(step.argMapping)) {
|
|
539
|
+
const match = pathExpr.match(/^\$steps\[(\d+)\]\.(.+)$/);
|
|
540
|
+
if (!match)
|
|
541
|
+
continue;
|
|
542
|
+
const fromStep = parseInt(match[1], 10);
|
|
543
|
+
const sourcePath = match[2];
|
|
544
|
+
// Try to get sample value from executed results
|
|
545
|
+
let sampleValue;
|
|
546
|
+
try {
|
|
547
|
+
const stepResult = this.stepResults[fromStep];
|
|
548
|
+
if (stepResult?.response) {
|
|
549
|
+
sampleValue = this.resolvePath(pathExpr, i);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
catch {
|
|
553
|
+
// Ignore resolution errors for graph building
|
|
554
|
+
}
|
|
555
|
+
edges.push({
|
|
556
|
+
fromStep,
|
|
557
|
+
toStep: i,
|
|
558
|
+
sourcePath,
|
|
559
|
+
targetParam,
|
|
560
|
+
sampleValue,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return edges;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Generate LLM analysis for a step.
|
|
568
|
+
* Returns a fallback message if LLM is not available (check mode).
|
|
569
|
+
*/
|
|
570
|
+
async analyzeStep(step, stepIndex, workflow, response, error) {
|
|
571
|
+
// Skip LLM analysis if no LLM is available (check mode)
|
|
572
|
+
if (!this.llm) {
|
|
573
|
+
return error ? `Step failed: ${error}` : 'Step completed.';
|
|
574
|
+
}
|
|
575
|
+
const prompt = buildWorkflowStepAnalysisPrompt({
|
|
576
|
+
workflow,
|
|
577
|
+
step,
|
|
578
|
+
stepIndex,
|
|
579
|
+
response,
|
|
580
|
+
error,
|
|
581
|
+
});
|
|
582
|
+
try {
|
|
583
|
+
return await this.llm.complete(prompt, COMPLETION_OPTIONS.workflowStepAnalysis);
|
|
584
|
+
}
|
|
585
|
+
catch {
|
|
586
|
+
return error ? `Step failed: ${error}` : 'Step completed.';
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Generate a summary of the workflow execution.
|
|
591
|
+
* Returns a fallback message if LLM is not available (check mode).
|
|
592
|
+
*/
|
|
593
|
+
async generateWorkflowSummary(workflow, stepResults, success) {
|
|
594
|
+
// Skip LLM summary if no LLM is available (check mode)
|
|
595
|
+
if (!this.llm) {
|
|
596
|
+
return success
|
|
597
|
+
? `Workflow "${workflow.name}" completed successfully with ${stepResults.length} steps.`
|
|
598
|
+
: `Workflow "${workflow.name}" failed at step ${stepResults.findIndex(r => !r.success) + 1}.`;
|
|
599
|
+
}
|
|
600
|
+
const prompt = buildWorkflowSummaryPrompt({ workflow, stepResults, success });
|
|
601
|
+
try {
|
|
602
|
+
return await this.llm.complete(prompt, COMPLETION_OPTIONS.workflowSummary);
|
|
603
|
+
}
|
|
604
|
+
catch {
|
|
605
|
+
return success
|
|
606
|
+
? `Workflow "${workflow.name}" completed successfully with ${stepResults.length} steps.`
|
|
607
|
+
: `Workflow "${workflow.name}" failed at step ${stepResults.findIndex(r => !r.success) + 1}.`;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow module - chained tool testing.
|
|
3
|
+
*/
|
|
4
|
+
export * from './types.js';
|
|
5
|
+
export * from './executor.js';
|
|
6
|
+
export * from './discovery.js';
|
|
7
|
+
export * from './loader.js';
|
|
8
|
+
export * from './state-tracker.js';
|
|
9
|
+
export * from './auto-generator.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow module - chained tool testing.
|
|
3
|
+
*/
|
|
4
|
+
export * from './types.js';
|
|
5
|
+
export * from './executor.js';
|
|
6
|
+
export * from './discovery.js';
|
|
7
|
+
export * from './loader.js';
|
|
8
|
+
export * from './state-tracker.js';
|
|
9
|
+
export * from './auto-generator.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow loader - loads workflows from YAML files.
|
|
3
|
+
*/
|
|
4
|
+
import type { Workflow } from './types.js';
|
|
5
|
+
/** Default file name for workflow definitions */
|
|
6
|
+
export declare const DEFAULT_WORKFLOWS_FILE: "bellwether-workflows.yaml";
|
|
7
|
+
/**
|
|
8
|
+
* Load workflows from a YAML file.
|
|
9
|
+
* Supports both single-document and multi-document YAML (separated by ---).
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadWorkflowsFromFile(path: string): Workflow[];
|
|
12
|
+
/**
|
|
13
|
+
* Try to load workflows from the default file in a directory.
|
|
14
|
+
* Returns null if file doesn't exist.
|
|
15
|
+
*
|
|
16
|
+
* This enables auto-discovery of workflow files similar to how
|
|
17
|
+
* scenarios are auto-loaded from bellwether-tests.yaml.
|
|
18
|
+
*/
|
|
19
|
+
export declare function tryLoadDefaultWorkflows(directory: string): Workflow[] | null;
|
|
20
|
+
/**
|
|
21
|
+
* Generate a sample workflow YAML template.
|
|
22
|
+
*/
|
|
23
|
+
export declare function generateSampleWorkflowYaml(): string;
|
|
24
|
+
//# sourceMappingURL=loader.d.ts.map
|