@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,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State tracker - tracks state changes during workflow execution.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functionality to:
|
|
5
|
+
* - Classify tools by their state role (reader, writer, both)
|
|
6
|
+
* - Identify probe tools that can capture state
|
|
7
|
+
* - Take state snapshots before/after workflow steps
|
|
8
|
+
* - Detect state changes between snapshots
|
|
9
|
+
* - Infer dependencies between workflow steps
|
|
10
|
+
*
|
|
11
|
+
* RELIABILITY: All probe tool calls have timeouts to prevent indefinite hangs.
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from 'crypto';
|
|
14
|
+
import { getLogger } from '../logging/logger.js';
|
|
15
|
+
import { withTimeout, DEFAULT_TIMEOUTS, TimeoutError } from '../utils/timeout.js';
|
|
16
|
+
import { MATH_FACTORS, DISPLAY_LIMITS } from '../constants.js';
|
|
17
|
+
/**
|
|
18
|
+
* Patterns that indicate a tool reads state.
|
|
19
|
+
*/
|
|
20
|
+
const READER_PATTERNS = [
|
|
21
|
+
/^(get|read|list|fetch|query|search|find|show|view|check|describe|inspect)/i,
|
|
22
|
+
/(reader|getter|viewer|inspector|checker)$/i,
|
|
23
|
+
/\b(retrieve|lookup|select|scan)\b/i,
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Patterns that indicate a tool writes state.
|
|
27
|
+
*/
|
|
28
|
+
const WRITER_PATTERNS = [
|
|
29
|
+
/^(create|add|insert|write|set|update|modify|delete|remove|drop|clear|reset)/i,
|
|
30
|
+
/^(post|put|patch)/i,
|
|
31
|
+
/(writer|setter|creator|mutator|modifier)$/i,
|
|
32
|
+
/\b(save|store|persist|commit|push)\b/i,
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Patterns that indicate a tool is suitable as a state probe.
|
|
36
|
+
* These are tools that can provide a comprehensive view of state.
|
|
37
|
+
*/
|
|
38
|
+
const PROBE_PATTERNS = [
|
|
39
|
+
/^(list|get_all|fetch_all|query_all|show_all)/i,
|
|
40
|
+
/\b(all|everything|dump|export|snapshot)\b/i,
|
|
41
|
+
/_list$/i,
|
|
42
|
+
/^list_/i,
|
|
43
|
+
];
|
|
44
|
+
/**
|
|
45
|
+
* State tracker for workflow execution.
|
|
46
|
+
*/
|
|
47
|
+
export class StateTracker {
|
|
48
|
+
client;
|
|
49
|
+
tools;
|
|
50
|
+
options;
|
|
51
|
+
logger = getLogger('state-tracker');
|
|
52
|
+
toolClassifications = new Map();
|
|
53
|
+
probeTools = [];
|
|
54
|
+
snapshotTimeout;
|
|
55
|
+
probeTimeout;
|
|
56
|
+
constructor(client, tools, _llm, options = {}, timeoutConfig) {
|
|
57
|
+
this.client = client;
|
|
58
|
+
this.tools = tools;
|
|
59
|
+
this.options = options;
|
|
60
|
+
this.snapshotTimeout = timeoutConfig?.snapshotTimeout ?? DEFAULT_TIMEOUTS.stateSnapshot;
|
|
61
|
+
this.probeTimeout = timeoutConfig?.probeTimeout ?? DEFAULT_TIMEOUTS.probeTool;
|
|
62
|
+
this.classifyTools();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Classify all tools by their state role.
|
|
66
|
+
*/
|
|
67
|
+
classifyTools() {
|
|
68
|
+
for (const tool of this.tools) {
|
|
69
|
+
const info = this.classifyTool(tool);
|
|
70
|
+
this.toolClassifications.set(tool.name, info);
|
|
71
|
+
if (info.isProbe) {
|
|
72
|
+
this.probeTools.push(tool.name);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Use specified probe tools if provided
|
|
76
|
+
if (this.options.probeTools?.length) {
|
|
77
|
+
this.probeTools = this.options.probeTools.filter(name => this.tools.some(t => t.name === name));
|
|
78
|
+
}
|
|
79
|
+
this.logger.debug({
|
|
80
|
+
toolCount: this.tools.length,
|
|
81
|
+
probeCount: this.probeTools.length,
|
|
82
|
+
probes: this.probeTools,
|
|
83
|
+
}, 'Tools classified');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Classify a single tool by analyzing its name and description.
|
|
87
|
+
*/
|
|
88
|
+
classifyTool(tool) {
|
|
89
|
+
const name = tool.name;
|
|
90
|
+
const description = tool.description ?? '';
|
|
91
|
+
const combined = `${name} ${description}`;
|
|
92
|
+
const isReader = READER_PATTERNS.some(p => p.test(combined));
|
|
93
|
+
const isWriter = WRITER_PATTERNS.some(p => p.test(combined));
|
|
94
|
+
const isProbe = PROBE_PATTERNS.some(p => p.test(combined));
|
|
95
|
+
let role;
|
|
96
|
+
let confidence;
|
|
97
|
+
if (isReader && isWriter) {
|
|
98
|
+
role = 'both';
|
|
99
|
+
confidence = 0.7;
|
|
100
|
+
}
|
|
101
|
+
else if (isReader) {
|
|
102
|
+
role = 'reader';
|
|
103
|
+
confidence = 0.8;
|
|
104
|
+
}
|
|
105
|
+
else if (isWriter) {
|
|
106
|
+
role = 'writer';
|
|
107
|
+
confidence = 0.8;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
role = 'unknown';
|
|
111
|
+
confidence = 0.3;
|
|
112
|
+
}
|
|
113
|
+
// Infer state types from description
|
|
114
|
+
const stateTypes = this.inferStateTypes(combined);
|
|
115
|
+
return {
|
|
116
|
+
tool: name,
|
|
117
|
+
role,
|
|
118
|
+
stateTypes: stateTypes.length > 0 ? stateTypes : undefined,
|
|
119
|
+
isProbe: isProbe && isReader,
|
|
120
|
+
confidence,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Infer state types from tool description.
|
|
125
|
+
*/
|
|
126
|
+
inferStateTypes(text) {
|
|
127
|
+
const types = [];
|
|
128
|
+
const lowerText = text.toLowerCase();
|
|
129
|
+
const stateTypePatterns = [
|
|
130
|
+
[/\b(file|files|directory|folder|path)\b/, 'files'],
|
|
131
|
+
[/\b(database|db|table|row|record|sql)\b/, 'database'],
|
|
132
|
+
[/\b(user|account|profile|auth)\b/, 'users'],
|
|
133
|
+
[/\b(session|token|cookie)\b/, 'sessions'],
|
|
134
|
+
[/\b(cache|cached|caching)\b/, 'cache'],
|
|
135
|
+
[/\b(queue|message|event)\b/, 'queue'],
|
|
136
|
+
[/\b(config|setting|preference)\b/, 'config'],
|
|
137
|
+
[/\b(resource|entity|object|item)\b/, 'resources'],
|
|
138
|
+
];
|
|
139
|
+
for (const [pattern, type] of stateTypePatterns) {
|
|
140
|
+
if (pattern.test(lowerText)) {
|
|
141
|
+
types.push(type);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return [...new Set(types)];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get the classification for a specific tool.
|
|
148
|
+
*/
|
|
149
|
+
getToolInfo(toolName) {
|
|
150
|
+
return this.toolClassifications.get(toolName);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get all tool classifications.
|
|
154
|
+
*/
|
|
155
|
+
getAllToolInfo() {
|
|
156
|
+
return Array.from(this.toolClassifications.values());
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get available probe tools.
|
|
160
|
+
*/
|
|
161
|
+
getProbeTools() {
|
|
162
|
+
return [...this.probeTools];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Take a state snapshot using available probe tools.
|
|
166
|
+
*
|
|
167
|
+
* RELIABILITY: Each probe tool call has an individual timeout to prevent hangs.
|
|
168
|
+
* The entire snapshot operation also has a total timeout.
|
|
169
|
+
*
|
|
170
|
+
* @param afterStepIndex - The step index this snapshot was taken after
|
|
171
|
+
* @param snapshotTimeoutMs - Optional total timeout for the snapshot operation (overrides configured timeout)
|
|
172
|
+
*/
|
|
173
|
+
async takeSnapshot(afterStepIndex, snapshotTimeoutMs) {
|
|
174
|
+
const effectiveSnapshotTimeout = snapshotTimeoutMs ?? this.snapshotTimeout;
|
|
175
|
+
const snapshotStart = Date.now();
|
|
176
|
+
const timestamp = new Date();
|
|
177
|
+
const stateData = {};
|
|
178
|
+
let successCount = 0;
|
|
179
|
+
let failureCount = 0;
|
|
180
|
+
// Track consecutive failures for circuit breaker
|
|
181
|
+
let consecutiveFailures = 0;
|
|
182
|
+
const maxConsecutiveFailures = Math.ceil(this.probeTools.length * MATH_FACTORS.PROBE_FAILURE_THRESHOLD);
|
|
183
|
+
// Call each probe tool to gather state with individual timeouts
|
|
184
|
+
for (const probeName of this.probeTools) {
|
|
185
|
+
// Check if we've exceeded the total snapshot timeout
|
|
186
|
+
const elapsed = Date.now() - snapshotStart;
|
|
187
|
+
if (elapsed >= effectiveSnapshotTimeout) {
|
|
188
|
+
this.logger.warn({ afterStepIndex, elapsed, timeout: effectiveSnapshotTimeout }, 'Snapshot operation exceeded total timeout, stopping probe calls');
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
// Circuit breaker: stop if too many consecutive failures
|
|
192
|
+
if (consecutiveFailures >= maxConsecutiveFailures) {
|
|
193
|
+
this.logger.warn({ consecutiveFailures, maxConsecutiveFailures }, 'Too many consecutive probe failures, aborting snapshot');
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
// Apply timeout to individual probe tool call
|
|
198
|
+
const result = await withTimeout(this.client.callTool(probeName, {}), this.probeTimeout, `Probe tool '${probeName}'`);
|
|
199
|
+
const content = this.extractContent(result);
|
|
200
|
+
stateData[probeName] = content;
|
|
201
|
+
successCount++;
|
|
202
|
+
consecutiveFailures = 0; // Reset on success
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
failureCount++;
|
|
206
|
+
consecutiveFailures++;
|
|
207
|
+
const isTimeout = error instanceof TimeoutError;
|
|
208
|
+
this.logger.warn({
|
|
209
|
+
probe: probeName,
|
|
210
|
+
error: error instanceof Error ? error.message : String(error),
|
|
211
|
+
isTimeout,
|
|
212
|
+
consecutiveFailures,
|
|
213
|
+
}, 'Probe tool failed');
|
|
214
|
+
stateData[probeName] = {
|
|
215
|
+
error: isTimeout ? 'probe_timeout' : 'probe_failed',
|
|
216
|
+
message: error instanceof Error ? error.message : String(error),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Log snapshot summary
|
|
221
|
+
this.logger.debug({
|
|
222
|
+
afterStepIndex,
|
|
223
|
+
probeCount: this.probeTools.length,
|
|
224
|
+
successCount,
|
|
225
|
+
failureCount,
|
|
226
|
+
durationMs: Date.now() - snapshotStart,
|
|
227
|
+
}, 'Snapshot completed');
|
|
228
|
+
// If no probes available or all failed, create empty snapshot
|
|
229
|
+
const data = successCount > 0 ? stateData : null;
|
|
230
|
+
const hash = this.hashState(data);
|
|
231
|
+
return {
|
|
232
|
+
timestamp,
|
|
233
|
+
afterStepIndex,
|
|
234
|
+
probeTool: this.probeTools.length > 0 ? this.probeTools.join(',') : undefined,
|
|
235
|
+
data,
|
|
236
|
+
hash,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Extract content from a tool call result.
|
|
241
|
+
*/
|
|
242
|
+
extractContent(result) {
|
|
243
|
+
const textContent = result.content.find(c => c.type === 'text' && c.text !== undefined);
|
|
244
|
+
if (!textContent || textContent.text === undefined) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
return JSON.parse(textContent.text);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return textContent.text;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Generate a hash for state data.
|
|
256
|
+
*/
|
|
257
|
+
hashState(data) {
|
|
258
|
+
const json = JSON.stringify(data, null, 0);
|
|
259
|
+
return createHash('sha256').update(json).digest('hex').slice(0, DISPLAY_LIMITS.HASH_DISPLAY_LENGTH);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Compare two snapshots and identify changes.
|
|
263
|
+
*/
|
|
264
|
+
compareSnapshots(before, after, causedByStep) {
|
|
265
|
+
const changes = [];
|
|
266
|
+
if (before.hash === after.hash) {
|
|
267
|
+
return changes;
|
|
268
|
+
}
|
|
269
|
+
// Deep compare the state data
|
|
270
|
+
const beforeData = before.data;
|
|
271
|
+
const afterData = after.data;
|
|
272
|
+
if (!beforeData || !afterData) {
|
|
273
|
+
if (beforeData && !afterData) {
|
|
274
|
+
changes.push({
|
|
275
|
+
type: 'deleted',
|
|
276
|
+
path: '$',
|
|
277
|
+
before: beforeData,
|
|
278
|
+
after: undefined,
|
|
279
|
+
causedByStep,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
else if (!beforeData && afterData) {
|
|
283
|
+
changes.push({
|
|
284
|
+
type: 'created',
|
|
285
|
+
path: '$',
|
|
286
|
+
before: undefined,
|
|
287
|
+
after: afterData,
|
|
288
|
+
causedByStep,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
return changes;
|
|
292
|
+
}
|
|
293
|
+
// Compare probe results
|
|
294
|
+
const allKeys = new Set([...Object.keys(beforeData), ...Object.keys(afterData)]);
|
|
295
|
+
for (const key of allKeys) {
|
|
296
|
+
const beforeValue = beforeData[key];
|
|
297
|
+
const afterValue = afterData[key];
|
|
298
|
+
if (beforeValue === undefined && afterValue !== undefined) {
|
|
299
|
+
changes.push({
|
|
300
|
+
type: 'created',
|
|
301
|
+
path: `$.${key}`,
|
|
302
|
+
before: undefined,
|
|
303
|
+
after: afterValue,
|
|
304
|
+
causedByStep,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
else if (beforeValue !== undefined && afterValue === undefined) {
|
|
308
|
+
changes.push({
|
|
309
|
+
type: 'deleted',
|
|
310
|
+
path: `$.${key}`,
|
|
311
|
+
before: beforeValue,
|
|
312
|
+
after: undefined,
|
|
313
|
+
causedByStep,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
else if (JSON.stringify(beforeValue) !== JSON.stringify(afterValue)) {
|
|
317
|
+
changes.push({
|
|
318
|
+
type: 'modified',
|
|
319
|
+
path: `$.${key}`,
|
|
320
|
+
before: beforeValue,
|
|
321
|
+
after: afterValue,
|
|
322
|
+
causedByStep,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return changes;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Infer dependencies between workflow steps based on state changes and tool roles.
|
|
330
|
+
*/
|
|
331
|
+
inferDependencies(stepResults) {
|
|
332
|
+
const dependencies = [];
|
|
333
|
+
const writerSteps = new Map(); // stateType -> step indices
|
|
334
|
+
for (let i = 0; i < stepResults.length; i++) {
|
|
335
|
+
const result = stepResults[i];
|
|
336
|
+
const toolInfo = this.toolClassifications.get(result.step.tool);
|
|
337
|
+
if (!toolInfo)
|
|
338
|
+
continue;
|
|
339
|
+
// Track writers
|
|
340
|
+
if (toolInfo.role === 'writer' || toolInfo.role === 'both') {
|
|
341
|
+
const stateTypes = toolInfo.stateTypes ?? ['unknown'];
|
|
342
|
+
for (const stateType of stateTypes) {
|
|
343
|
+
const writers = writerSteps.get(stateType) ?? [];
|
|
344
|
+
writers.push(i);
|
|
345
|
+
writerSteps.set(stateType, writers);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Track readers and create dependencies
|
|
349
|
+
if (toolInfo.role === 'reader' || toolInfo.role === 'both') {
|
|
350
|
+
const stateTypes = toolInfo.stateTypes ?? ['unknown'];
|
|
351
|
+
for (const stateType of stateTypes) {
|
|
352
|
+
const writers = writerSteps.get(stateType) ?? [];
|
|
353
|
+
// Find most recent writer for this state type
|
|
354
|
+
const recentWriters = writers.filter(w => w < i);
|
|
355
|
+
if (recentWriters.length > 0) {
|
|
356
|
+
const producerStep = recentWriters[recentWriters.length - 1];
|
|
357
|
+
const producerTool = stepResults[producerStep].step.tool;
|
|
358
|
+
dependencies.push({
|
|
359
|
+
producerStep,
|
|
360
|
+
consumerStep: i,
|
|
361
|
+
stateType,
|
|
362
|
+
description: `Step ${i} (${result.step.tool}) reads ${stateType} state potentially modified by step ${producerStep} (${producerTool})`,
|
|
363
|
+
verified: false,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return dependencies;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Verify dependencies using state snapshots.
|
|
373
|
+
*/
|
|
374
|
+
verifyDependencies(dependencies, _snapshots, changes) {
|
|
375
|
+
return dependencies.map(dep => {
|
|
376
|
+
// Check if the producer step caused any changes
|
|
377
|
+
const producerChanges = changes.filter(c => c.causedByStep === dep.producerStep);
|
|
378
|
+
const verified = producerChanges.length > 0;
|
|
379
|
+
return {
|
|
380
|
+
...dep,
|
|
381
|
+
verified,
|
|
382
|
+
};
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Generate a summary of state tracking results.
|
|
387
|
+
*/
|
|
388
|
+
async generateSummary(tracking) {
|
|
389
|
+
const parts = [];
|
|
390
|
+
// Summarize tool roles
|
|
391
|
+
const writers = tracking.toolRoles.filter(t => t.role === 'writer' || t.role === 'both');
|
|
392
|
+
const readers = tracking.toolRoles.filter(t => t.role === 'reader' || t.role === 'both');
|
|
393
|
+
if (writers.length > 0) {
|
|
394
|
+
parts.push(`State writers: ${writers.map(t => t.tool).join(', ')}`);
|
|
395
|
+
}
|
|
396
|
+
if (readers.length > 0) {
|
|
397
|
+
parts.push(`State readers: ${readers.map(t => t.tool).join(', ')}`);
|
|
398
|
+
}
|
|
399
|
+
// Summarize changes
|
|
400
|
+
if (tracking.changes.length > 0) {
|
|
401
|
+
const created = tracking.changes.filter(c => c.type === 'created').length;
|
|
402
|
+
const modified = tracking.changes.filter(c => c.type === 'modified').length;
|
|
403
|
+
const deleted = tracking.changes.filter(c => c.type === 'deleted').length;
|
|
404
|
+
const changeParts = [];
|
|
405
|
+
if (created > 0)
|
|
406
|
+
changeParts.push(`${created} created`);
|
|
407
|
+
if (modified > 0)
|
|
408
|
+
changeParts.push(`${modified} modified`);
|
|
409
|
+
if (deleted > 0)
|
|
410
|
+
changeParts.push(`${deleted} deleted`);
|
|
411
|
+
parts.push(`State changes: ${changeParts.join(', ')}`);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
parts.push('No state changes detected');
|
|
415
|
+
}
|
|
416
|
+
// Summarize dependencies
|
|
417
|
+
if (tracking.dependencies.length > 0) {
|
|
418
|
+
const verified = tracking.dependencies.filter(d => d.verified).length;
|
|
419
|
+
parts.push(`Dependencies: ${tracking.dependencies.length} inferred (${verified} verified)`);
|
|
420
|
+
}
|
|
421
|
+
return parts.join('. ') + '.';
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=state-tracker.js.map
|