@yasserkhanorg/impact-gate 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +168 -0
- package/README.md +520 -0
- package/dist/adapters/cypress.d.ts +10 -0
- package/dist/adapters/cypress.d.ts.map +1 -0
- package/dist/adapters/cypress.js +86 -0
- package/dist/adapters/framework_adapter.d.ts +41 -0
- package/dist/adapters/framework_adapter.d.ts.map +1 -0
- package/dist/adapters/framework_adapter.js +152 -0
- package/dist/adapters/playwright.d.ts +10 -0
- package/dist/adapters/playwright.d.ts.map +1 -0
- package/dist/adapters/playwright.js +86 -0
- package/dist/adapters/pytest.d.ts +10 -0
- package/dist/adapters/pytest.d.ts.map +1 -0
- package/dist/adapters/pytest.js +96 -0
- package/dist/adapters/supertest.d.ts +12 -0
- package/dist/adapters/supertest.d.ts.map +1 -0
- package/dist/adapters/supertest.js +85 -0
- package/dist/agent/api_catalog.d.ts +11 -0
- package/dist/agent/api_catalog.d.ts.map +1 -0
- package/dist/agent/api_catalog.js +210 -0
- package/dist/agent/config.d.ts +193 -0
- package/dist/agent/config.d.ts.map +1 -0
- package/dist/agent/config.js +875 -0
- package/dist/agent/feedback.d.ts +91 -0
- package/dist/agent/feedback.d.ts.map +1 -0
- package/dist/agent/feedback.js +323 -0
- package/dist/agent/git.d.ts +19 -0
- package/dist/agent/git.d.ts.map +1 -0
- package/dist/agent/git.js +257 -0
- package/dist/agent/handoff.d.ts +22 -0
- package/dist/agent/handoff.d.ts.map +1 -0
- package/dist/agent/handoff.js +180 -0
- package/dist/agent/llm_agents_flow.d.ts +15 -0
- package/dist/agent/llm_agents_flow.d.ts.map +1 -0
- package/dist/agent/llm_agents_flow.js +434 -0
- package/dist/agent/native_flow.d.ts +6 -0
- package/dist/agent/native_flow.d.ts.map +1 -0
- package/dist/agent/native_flow.js +179 -0
- package/dist/agent/pipeline.d.ts +7 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +260 -0
- package/dist/agent/pipeline_types.d.ts +54 -0
- package/dist/agent/pipeline_types.d.ts.map +1 -0
- package/dist/agent/pipeline_types.js +4 -0
- package/dist/agent/pipeline_utils.d.ts +12 -0
- package/dist/agent/pipeline_utils.d.ts.map +1 -0
- package/dist/agent/pipeline_utils.js +156 -0
- package/dist/agent/plan.d.ts +170 -0
- package/dist/agent/plan.d.ts.map +1 -0
- package/dist/agent/plan.js +86 -0
- package/dist/agent/playwright_report.d.ts +8 -0
- package/dist/agent/playwright_report.d.ts.map +1 -0
- package/dist/agent/playwright_report.js +126 -0
- package/dist/agent/process_runner.d.ts +10 -0
- package/dist/agent/process_runner.d.ts.map +1 -0
- package/dist/agent/process_runner.js +92 -0
- package/dist/agent/spec_generator.d.ts +5 -0
- package/dist/agent/spec_generator.d.ts.map +1 -0
- package/dist/agent/spec_generator.js +253 -0
- package/dist/agent/test_path.d.ts +2 -0
- package/dist/agent/test_path.d.ts.map +1 -0
- package/dist/agent/test_path.js +23 -0
- package/dist/agent/traceability_capture.d.ts +18 -0
- package/dist/agent/traceability_capture.d.ts.map +1 -0
- package/dist/agent/traceability_capture.js +313 -0
- package/dist/agent/traceability_ingest.d.ts +21 -0
- package/dist/agent/traceability_ingest.d.ts.map +1 -0
- package/dist/agent/traceability_ingest.js +237 -0
- package/dist/agent/types.d.ts +42 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +4 -0
- package/dist/agent/utils.d.ts +13 -0
- package/dist/agent/utils.d.ts.map +1 -0
- package/dist/agent/utils.js +152 -0
- package/dist/agent/validation_runner.d.ts +5 -0
- package/dist/agent/validation_runner.d.ts.map +1 -0
- package/dist/agent/validation_runner.js +77 -0
- package/dist/agentic/fix_loop.d.ts +26 -0
- package/dist/agentic/fix_loop.d.ts.map +1 -0
- package/dist/agentic/fix_loop.js +96 -0
- package/dist/agentic/playwright_runner.d.ts +43 -0
- package/dist/agentic/playwright_runner.d.ts.map +1 -0
- package/dist/agentic/playwright_runner.js +165 -0
- package/dist/agentic/runner.d.ts +27 -0
- package/dist/agentic/runner.d.ts.map +1 -0
- package/dist/agentic/runner.js +210 -0
- package/dist/agentic/types.d.ts +62 -0
- package/dist/agentic/types.d.ts.map +1 -0
- package/dist/agentic/types.js +4 -0
- package/dist/agents/coverage-evaluator.d.ts +8 -0
- package/dist/agents/coverage-evaluator.d.ts.map +1 -0
- package/dist/agents/coverage-evaluator.js +41 -0
- package/dist/agents/cross-impact.d.ts +13 -0
- package/dist/agents/cross-impact.d.ts.map +1 -0
- package/dist/agents/cross-impact.js +140 -0
- package/dist/agents/executor.d.ts +8 -0
- package/dist/agents/executor.d.ts.map +1 -0
- package/dist/agents/executor.js +75 -0
- package/dist/agents/explorer.d.ts +12 -0
- package/dist/agents/explorer.d.ts.map +1 -0
- package/dist/agents/explorer.js +43 -0
- package/dist/agents/generator.d.ts +8 -0
- package/dist/agents/generator.d.ts.map +1 -0
- package/dist/agents/generator.js +77 -0
- package/dist/agents/healer.d.ts +8 -0
- package/dist/agents/healer.d.ts.map +1 -0
- package/dist/agents/healer.js +31 -0
- package/dist/agents/impact-analyst.d.ts +8 -0
- package/dist/agents/impact-analyst.d.ts.map +1 -0
- package/dist/agents/impact-analyst.js +38 -0
- package/dist/agents/regression-advisor.d.ts +8 -0
- package/dist/agents/regression-advisor.d.ts.map +1 -0
- package/dist/agents/regression-advisor.js +116 -0
- package/dist/agents/strategist.d.ts +9 -0
- package/dist/agents/strategist.d.ts.map +1 -0
- package/dist/agents/strategist.js +92 -0
- package/dist/agents/test-designer.d.ts +8 -0
- package/dist/agents/test-designer.d.ts.map +1 -0
- package/dist/agents/test-designer.js +111 -0
- package/dist/anthropic_provider.d.ts +65 -0
- package/dist/anthropic_provider.d.ts.map +1 -0
- package/dist/anthropic_provider.js +334 -0
- package/dist/api.d.ts +48 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +151 -0
- package/dist/base_provider.d.ts +109 -0
- package/dist/base_provider.d.ts.map +1 -0
- package/dist/base_provider.js +203 -0
- package/dist/budget_ledger.d.ts +28 -0
- package/dist/budget_ledger.d.ts.map +1 -0
- package/dist/budget_ledger.js +62 -0
- package/dist/cache/cached_provider.d.ts +49 -0
- package/dist/cache/cached_provider.d.ts.map +1 -0
- package/dist/cache/cached_provider.js +91 -0
- package/dist/cache/response_cache.d.ts +79 -0
- package/dist/cache/response_cache.d.ts.map +1 -0
- package/dist/cache/response_cache.js +177 -0
- package/dist/cli/commands/analyze.d.ts +3 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +77 -0
- package/dist/cli/commands/bootstrap.d.ts +3 -0
- package/dist/cli/commands/bootstrap.d.ts.map +1 -0
- package/dist/cli/commands/bootstrap.js +109 -0
- package/dist/cli/commands/cost_report.d.ts +3 -0
- package/dist/cli/commands/cost_report.d.ts.map +1 -0
- package/dist/cli/commands/cost_report.js +115 -0
- package/dist/cli/commands/crew.d.ts +3 -0
- package/dist/cli/commands/crew.d.ts.map +1 -0
- package/dist/cli/commands/crew.js +255 -0
- package/dist/cli/commands/feedback.d.ts +3 -0
- package/dist/cli/commands/feedback.d.ts.map +1 -0
- package/dist/cli/commands/feedback.js +39 -0
- package/dist/cli/commands/finalize.d.ts +3 -0
- package/dist/cli/commands/finalize.d.ts.map +1 -0
- package/dist/cli/commands/finalize.js +41 -0
- package/dist/cli/commands/gate.d.ts +3 -0
- package/dist/cli/commands/gate.d.ts.map +1 -0
- package/dist/cli/commands/gate.js +89 -0
- package/dist/cli/commands/generate.d.ts +4 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +108 -0
- package/dist/cli/commands/heal.d.ts +3 -0
- package/dist/cli/commands/heal.d.ts.map +1 -0
- package/dist/cli/commands/heal.js +60 -0
- package/dist/cli/commands/impact.d.ts +4 -0
- package/dist/cli/commands/impact.d.ts.map +1 -0
- package/dist/cli/commands/impact.js +33 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +169 -0
- package/dist/cli/commands/llm_health.d.ts +2 -0
- package/dist/cli/commands/llm_health.d.ts.map +1 -0
- package/dist/cli/commands/llm_health.js +22 -0
- package/dist/cli/commands/plan.d.ts +4 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +120 -0
- package/dist/cli/commands/plan_crew.d.ts +17 -0
- package/dist/cli/commands/plan_crew.d.ts.map +1 -0
- package/dist/cli/commands/plan_crew.js +316 -0
- package/dist/cli/commands/traceability.d.ts +4 -0
- package/dist/cli/commands/traceability.d.ts.map +1 -0
- package/dist/cli/commands/traceability.js +77 -0
- package/dist/cli/commands/train.d.ts +3 -0
- package/dist/cli/commands/train.d.ts.map +1 -0
- package/dist/cli/commands/train.js +391 -0
- package/dist/cli/defaults.d.ts +35 -0
- package/dist/cli/defaults.d.ts.map +1 -0
- package/dist/cli/defaults.js +172 -0
- package/dist/cli/errors.d.ts +27 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +57 -0
- package/dist/cli/parse_args.d.ts +6 -0
- package/dist/cli/parse_args.d.ts.map +1 -0
- package/dist/cli/parse_args.js +257 -0
- package/dist/cli/types.d.ts +87 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +4 -0
- package/dist/cli/usage.d.ts +2 -0
- package/dist/cli/usage.d.ts.map +1 -0
- package/dist/cli/usage.js +109 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +194 -0
- package/dist/crew/context.d.ts +55 -0
- package/dist/crew/context.d.ts.map +1 -0
- package/dist/crew/context.js +36 -0
- package/dist/crew/orchestrator.d.ts +50 -0
- package/dist/crew/orchestrator.d.ts.map +1 -0
- package/dist/crew/orchestrator.js +329 -0
- package/dist/crew/protocol.d.ts +46 -0
- package/dist/crew/protocol.d.ts.map +1 -0
- package/dist/crew/protocol.js +4 -0
- package/dist/crew/provider.d.ts +17 -0
- package/dist/crew/provider.d.ts.map +1 -0
- package/dist/crew/provider.js +36 -0
- package/dist/crew/sanitize.d.ts +3 -0
- package/dist/crew/sanitize.d.ts.map +1 -0
- package/dist/crew/sanitize.js +31 -0
- package/dist/crew/types.d.ts +52 -0
- package/dist/crew/types.d.ts.map +1 -0
- package/dist/crew/types.js +4 -0
- package/dist/crew/workflows.d.ts +52 -0
- package/dist/crew/workflows.d.ts.map +1 -0
- package/dist/crew/workflows.js +36 -0
- package/dist/custom_provider.d.ts +20 -0
- package/dist/custom_provider.d.ts.map +1 -0
- package/dist/custom_provider.js +277 -0
- package/dist/engine/ai_enrichment.d.ts +44 -0
- package/dist/engine/ai_enrichment.d.ts.map +1 -0
- package/dist/engine/ai_enrichment.js +267 -0
- package/dist/engine/diff_loader.d.ts +11 -0
- package/dist/engine/diff_loader.d.ts.map +1 -0
- package/dist/engine/diff_loader.js +63 -0
- package/dist/engine/impact_engine.d.ts +72 -0
- package/dist/engine/impact_engine.d.ts.map +1 -0
- package/dist/engine/impact_engine.js +298 -0
- package/dist/engine/plan_builder.d.ts +11 -0
- package/dist/engine/plan_builder.d.ts.map +1 -0
- package/dist/engine/plan_builder.js +599 -0
- package/dist/esm/adapters/cypress.js +49 -0
- package/dist/esm/adapters/framework_adapter.js +114 -0
- package/dist/esm/adapters/playwright.js +49 -0
- package/dist/esm/adapters/pytest.js +59 -0
- package/dist/esm/adapters/supertest.js +48 -0
- package/dist/esm/agent/api_catalog.js +199 -0
- package/dist/esm/agent/config.js +872 -0
- package/dist/esm/agent/feedback.js +317 -0
- package/dist/esm/agent/git.js +252 -0
- package/dist/esm/agent/handoff.js +177 -0
- package/dist/esm/agent/llm_agents_flow.js +421 -0
- package/dist/esm/agent/native_flow.js +175 -0
- package/dist/esm/agent/pipeline.js +256 -0
- package/dist/esm/agent/pipeline_types.js +3 -0
- package/dist/esm/agent/pipeline_utils.js +146 -0
- package/dist/esm/agent/plan.js +83 -0
- package/dist/esm/agent/playwright_report.js +123 -0
- package/dist/esm/agent/process_runner.js +83 -0
- package/dist/esm/agent/spec_generator.js +249 -0
- package/dist/esm/agent/test_path.js +20 -0
- package/dist/esm/agent/traceability_capture.js +310 -0
- package/dist/esm/agent/traceability_ingest.js +234 -0
- package/dist/esm/agent/types.js +3 -0
- package/dist/esm/agent/utils.js +138 -0
- package/dist/esm/agent/validation_runner.js +73 -0
- package/dist/esm/agentic/fix_loop.js +91 -0
- package/dist/esm/agentic/playwright_runner.js +161 -0
- package/dist/esm/agentic/runner.js +207 -0
- package/dist/esm/agentic/types.js +3 -0
- package/dist/esm/agents/coverage-evaluator.js +37 -0
- package/dist/esm/agents/cross-impact.js +136 -0
- package/dist/esm/agents/executor.js +71 -0
- package/dist/esm/agents/explorer.js +39 -0
- package/dist/esm/agents/generator.js +73 -0
- package/dist/esm/agents/healer.js +27 -0
- package/dist/esm/agents/impact-analyst.js +34 -0
- package/dist/esm/agents/regression-advisor.js +112 -0
- package/dist/esm/agents/strategist.js +88 -0
- package/dist/esm/agents/test-designer.js +107 -0
- package/dist/esm/anthropic_provider.js +326 -0
- package/dist/esm/api.js +143 -0
- package/dist/esm/base_provider.js +198 -0
- package/dist/esm/budget_ledger.js +58 -0
- package/dist/esm/cache/cached_provider.js +85 -0
- package/dist/esm/cache/response_cache.js +140 -0
- package/dist/esm/cli/commands/analyze.js +74 -0
- package/dist/esm/cli/commands/bootstrap.js +106 -0
- package/dist/esm/cli/commands/cost_report.js +112 -0
- package/dist/esm/cli/commands/crew.js +252 -0
- package/dist/esm/cli/commands/feedback.js +36 -0
- package/dist/esm/cli/commands/finalize.js +38 -0
- package/dist/esm/cli/commands/gate.js +86 -0
- package/dist/esm/cli/commands/generate.js +105 -0
- package/dist/esm/cli/commands/heal.js +57 -0
- package/dist/esm/cli/commands/impact.js +30 -0
- package/dist/esm/cli/commands/init.js +133 -0
- package/dist/esm/cli/commands/llm_health.js +19 -0
- package/dist/esm/cli/commands/plan.js +117 -0
- package/dist/esm/cli/commands/plan_crew.js +309 -0
- package/dist/esm/cli/commands/traceability.js +73 -0
- package/dist/esm/cli/commands/train.js +355 -0
- package/dist/esm/cli/defaults.js +165 -0
- package/dist/esm/cli/errors.js +52 -0
- package/dist/esm/cli/parse_args.js +251 -0
- package/dist/esm/cli/types.js +3 -0
- package/dist/esm/cli/usage.js +106 -0
- package/dist/esm/cli.js +192 -0
- package/dist/esm/crew/context.js +32 -0
- package/dist/esm/crew/orchestrator.js +325 -0
- package/dist/esm/crew/protocol.js +3 -0
- package/dist/esm/crew/provider.js +33 -0
- package/dist/esm/crew/sanitize.js +27 -0
- package/dist/esm/crew/types.js +3 -0
- package/dist/esm/crew/workflows.js +33 -0
- package/dist/esm/custom_provider.js +273 -0
- package/dist/esm/engine/ai_enrichment.js +264 -0
- package/dist/esm/engine/diff_loader.js +59 -0
- package/dist/esm/engine/impact_engine.js +291 -0
- package/dist/esm/engine/plan_builder.js +593 -0
- package/dist/esm/index.js +72 -0
- package/dist/esm/knowledge/api_surface.js +408 -0
- package/dist/esm/knowledge/cluster_utils.js +60 -0
- package/dist/esm/knowledge/context_loader.js +85 -0
- package/dist/esm/knowledge/failure_history.js +121 -0
- package/dist/esm/knowledge/kg_bridge.js +381 -0
- package/dist/esm/knowledge/kg_types.js +3 -0
- package/dist/esm/knowledge/route_families.js +393 -0
- package/dist/esm/knowledge/spec_index.js +122 -0
- package/dist/esm/logger.js +115 -0
- package/dist/esm/mcp-server.js +621 -0
- package/dist/esm/metrics/prometheus.js +149 -0
- package/dist/esm/model_router.js +59 -0
- package/dist/esm/ollama_provider.js +301 -0
- package/dist/esm/openai_provider.js +243 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/pipeline/orchestrator.js +228 -0
- package/dist/esm/pipeline/spec_verifier.js +75 -0
- package/dist/esm/pipeline/stage0_preprocess.js +102 -0
- package/dist/esm/pipeline/stage1_impact.js +140 -0
- package/dist/esm/pipeline/stage2_coverage.js +153 -0
- package/dist/esm/pipeline/stage3_generation.js +284 -0
- package/dist/esm/pipeline/stage4_heal.js +288 -0
- package/dist/esm/progress.js +112 -0
- package/dist/esm/prompts/coverage.js +57 -0
- package/dist/esm/prompts/cross-impact.js +53 -0
- package/dist/esm/prompts/generation.js +297 -0
- package/dist/esm/prompts/generation_profile.js +147 -0
- package/dist/esm/prompts/heal.js +91 -0
- package/dist/esm/prompts/impact.js +63 -0
- package/dist/esm/prompts/json_extract.js +36 -0
- package/dist/esm/prompts/strategist.js +61 -0
- package/dist/esm/prompts/test-designer.js +92 -0
- package/dist/esm/provider_factory.js +366 -0
- package/dist/esm/provider_interface.js +23 -0
- package/dist/esm/provider_utils.js +96 -0
- package/dist/esm/qa-agent/cli.js +205 -0
- package/dist/esm/qa-agent/orchestrator.js +120 -0
- package/dist/esm/qa-agent/phase1/runner.js +139 -0
- package/dist/esm/qa-agent/phase1/scope.js +126 -0
- package/dist/esm/qa-agent/phase2/agent_browser.js +95 -0
- package/dist/esm/qa-agent/phase2/agent_loop.js +351 -0
- package/dist/esm/qa-agent/phase2/exploration_state.js +97 -0
- package/dist/esm/qa-agent/phase2/tools.js +386 -0
- package/dist/esm/qa-agent/phase2/vision.js +75 -0
- package/dist/esm/qa-agent/phase3/feedback.js +34 -0
- package/dist/esm/qa-agent/phase3/reporter.js +145 -0
- package/dist/esm/qa-agent/phase3/spec_generator.js +62 -0
- package/dist/esm/qa-agent/phase3/verdict.js +66 -0
- package/dist/esm/qa-agent/safe_env.js +23 -0
- package/dist/esm/qa-agent/types.js +3 -0
- package/dist/esm/reporters/junit.js +86 -0
- package/dist/esm/reporters/reporter.js +3 -0
- package/dist/esm/reporters/sarif.js +132 -0
- package/dist/esm/resilience/circuit_breaker.js +78 -0
- package/dist/esm/resilience/retry.js +56 -0
- package/dist/esm/sanitize.js +66 -0
- package/dist/esm/training/enricher.js +345 -0
- package/dist/esm/training/kg_scanner.js +115 -0
- package/dist/esm/training/merger.js +204 -0
- package/dist/esm/training/scanner.js +923 -0
- package/dist/esm/training/types.js +6 -0
- package/dist/esm/training/validator.js +254 -0
- package/dist/esm/validation/guardrails.js +101 -0
- package/dist/esm/validation/output_schema.js +80 -0
- package/dist/esm/version.js +33 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +169 -0
- package/dist/knowledge/api_surface.d.ts +37 -0
- package/dist/knowledge/api_surface.d.ts.map +1 -0
- package/dist/knowledge/api_surface.js +418 -0
- package/dist/knowledge/cluster_utils.d.ts +28 -0
- package/dist/knowledge/cluster_utils.d.ts.map +1 -0
- package/dist/knowledge/cluster_utils.js +67 -0
- package/dist/knowledge/context_loader.d.ts +13 -0
- package/dist/knowledge/context_loader.d.ts.map +1 -0
- package/dist/knowledge/context_loader.js +90 -0
- package/dist/knowledge/failure_history.d.ts +39 -0
- package/dist/knowledge/failure_history.d.ts.map +1 -0
- package/dist/knowledge/failure_history.js +128 -0
- package/dist/knowledge/kg_bridge.d.ts +31 -0
- package/dist/knowledge/kg_bridge.d.ts.map +1 -0
- package/dist/knowledge/kg_bridge.js +388 -0
- package/dist/knowledge/kg_types.d.ts +75 -0
- package/dist/knowledge/kg_types.d.ts.map +1 -0
- package/dist/knowledge/kg_types.js +4 -0
- package/dist/knowledge/route_families.d.ts +98 -0
- package/dist/knowledge/route_families.d.ts.map +1 -0
- package/dist/knowledge/route_families.js +410 -0
- package/dist/knowledge/spec_index.d.ts +18 -0
- package/dist/knowledge/spec_index.d.ts.map +1 -0
- package/dist/knowledge/spec_index.js +128 -0
- package/dist/logger.d.ts +31 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +119 -0
- package/dist/mcp-server.d.ts +68 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +629 -0
- package/dist/metrics/prometheus.d.ts +37 -0
- package/dist/metrics/prometheus.d.ts.map +1 -0
- package/dist/metrics/prometheus.js +153 -0
- package/dist/model_router.d.ts +28 -0
- package/dist/model_router.d.ts.map +1 -0
- package/dist/model_router.js +63 -0
- package/dist/ollama_provider.d.ts +65 -0
- package/dist/ollama_provider.d.ts.map +1 -0
- package/dist/ollama_provider.js +309 -0
- package/dist/openai_provider.d.ts +23 -0
- package/dist/openai_provider.d.ts.map +1 -0
- package/dist/openai_provider.js +251 -0
- package/dist/pipeline/orchestrator.d.ts +33 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -0
- package/dist/pipeline/orchestrator.js +231 -0
- package/dist/pipeline/spec_verifier.d.ts +20 -0
- package/dist/pipeline/spec_verifier.d.ts.map +1 -0
- package/dist/pipeline/spec_verifier.js +79 -0
- package/dist/pipeline/stage0_preprocess.d.ts +31 -0
- package/dist/pipeline/stage0_preprocess.d.ts.map +1 -0
- package/dist/pipeline/stage0_preprocess.js +105 -0
- package/dist/pipeline/stage1_impact.d.ts +19 -0
- package/dist/pipeline/stage1_impact.d.ts.map +1 -0
- package/dist/pipeline/stage1_impact.js +143 -0
- package/dist/pipeline/stage2_coverage.d.ts +19 -0
- package/dist/pipeline/stage2_coverage.d.ts.map +1 -0
- package/dist/pipeline/stage2_coverage.js +156 -0
- package/dist/pipeline/stage3_generation.d.ts +43 -0
- package/dist/pipeline/stage3_generation.d.ts.map +1 -0
- package/dist/pipeline/stage3_generation.js +287 -0
- package/dist/pipeline/stage4_heal.d.ts +62 -0
- package/dist/pipeline/stage4_heal.d.ts.map +1 -0
- package/dist/pipeline/stage4_heal.js +294 -0
- package/dist/progress.d.ts +22 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +116 -0
- package/dist/prompts/coverage.d.ts +39 -0
- package/dist/prompts/coverage.d.ts.map +1 -0
- package/dist/prompts/coverage.js +61 -0
- package/dist/prompts/cross-impact.d.ts +23 -0
- package/dist/prompts/cross-impact.d.ts.map +1 -0
- package/dist/prompts/cross-impact.js +57 -0
- package/dist/prompts/generation.d.ts +25 -0
- package/dist/prompts/generation.d.ts.map +1 -0
- package/dist/prompts/generation.js +302 -0
- package/dist/prompts/generation_profile.d.ts +29 -0
- package/dist/prompts/generation_profile.d.ts.map +1 -0
- package/dist/prompts/generation_profile.js +151 -0
- package/dist/prompts/heal.d.ts +23 -0
- package/dist/prompts/heal.d.ts.map +1 -0
- package/dist/prompts/heal.js +95 -0
- package/dist/prompts/impact.d.ts +31 -0
- package/dist/prompts/impact.d.ts.map +1 -0
- package/dist/prompts/impact.js +67 -0
- package/dist/prompts/json_extract.d.ts +14 -0
- package/dist/prompts/json_extract.d.ts.map +1 -0
- package/dist/prompts/json_extract.js +39 -0
- package/dist/prompts/strategist.d.ts +25 -0
- package/dist/prompts/strategist.d.ts.map +1 -0
- package/dist/prompts/strategist.js +65 -0
- package/dist/prompts/test-designer.d.ts +35 -0
- package/dist/prompts/test-designer.d.ts.map +1 -0
- package/dist/prompts/test-designer.js +96 -0
- package/dist/provider_factory.d.ts +104 -0
- package/dist/provider_factory.d.ts.map +1 -0
- package/dist/provider_factory.js +371 -0
- package/dist/provider_interface.d.ts +365 -0
- package/dist/provider_interface.d.ts.map +1 -0
- package/dist/provider_interface.js +28 -0
- package/dist/provider_utils.d.ts +39 -0
- package/dist/provider_utils.d.ts.map +1 -0
- package/dist/provider_utils.js +103 -0
- package/dist/qa-agent/cli.d.ts +3 -0
- package/dist/qa-agent/cli.d.ts.map +1 -0
- package/dist/qa-agent/cli.js +207 -0
- package/dist/qa-agent/orchestrator.d.ts +3 -0
- package/dist/qa-agent/orchestrator.d.ts.map +1 -0
- package/dist/qa-agent/orchestrator.js +123 -0
- package/dist/qa-agent/phase1/runner.d.ts +3 -0
- package/dist/qa-agent/phase1/runner.d.ts.map +1 -0
- package/dist/qa-agent/phase1/runner.js +142 -0
- package/dist/qa-agent/phase1/scope.d.ts +6 -0
- package/dist/qa-agent/phase1/scope.d.ts.map +1 -0
- package/dist/qa-agent/phase1/scope.js +129 -0
- package/dist/qa-agent/phase2/agent_browser.d.ts +35 -0
- package/dist/qa-agent/phase2/agent_browser.d.ts.map +1 -0
- package/dist/qa-agent/phase2/agent_browser.js +99 -0
- package/dist/qa-agent/phase2/agent_loop.d.ts +3 -0
- package/dist/qa-agent/phase2/agent_loop.d.ts.map +1 -0
- package/dist/qa-agent/phase2/agent_loop.js +357 -0
- package/dist/qa-agent/phase2/exploration_state.d.ts +12 -0
- package/dist/qa-agent/phase2/exploration_state.d.ts.map +1 -0
- package/dist/qa-agent/phase2/exploration_state.js +109 -0
- package/dist/qa-agent/phase2/tools.d.ts +28 -0
- package/dist/qa-agent/phase2/tools.d.ts.map +1 -0
- package/dist/qa-agent/phase2/tools.js +390 -0
- package/dist/qa-agent/phase2/vision.d.ts +3 -0
- package/dist/qa-agent/phase2/vision.d.ts.map +1 -0
- package/dist/qa-agent/phase2/vision.js +78 -0
- package/dist/qa-agent/phase3/feedback.d.ts +3 -0
- package/dist/qa-agent/phase3/feedback.d.ts.map +1 -0
- package/dist/qa-agent/phase3/feedback.js +37 -0
- package/dist/qa-agent/phase3/reporter.d.ts +3 -0
- package/dist/qa-agent/phase3/reporter.d.ts.map +1 -0
- package/dist/qa-agent/phase3/reporter.js +148 -0
- package/dist/qa-agent/phase3/spec_generator.d.ts +3 -0
- package/dist/qa-agent/phase3/spec_generator.d.ts.map +1 -0
- package/dist/qa-agent/phase3/spec_generator.js +65 -0
- package/dist/qa-agent/phase3/verdict.d.ts +3 -0
- package/dist/qa-agent/phase3/verdict.d.ts.map +1 -0
- package/dist/qa-agent/phase3/verdict.js +69 -0
- package/dist/qa-agent/safe_env.d.ts +3 -0
- package/dist/qa-agent/safe_env.d.ts.map +1 -0
- package/dist/qa-agent/safe_env.js +26 -0
- package/dist/qa-agent/types.d.ts +130 -0
- package/dist/qa-agent/types.d.ts.map +1 -0
- package/dist/qa-agent/types.js +4 -0
- package/dist/reporters/junit.d.ts +6 -0
- package/dist/reporters/junit.d.ts.map +1 -0
- package/dist/reporters/junit.js +89 -0
- package/dist/reporters/reporter.d.ts +42 -0
- package/dist/reporters/reporter.d.ts.map +1 -0
- package/dist/reporters/reporter.js +4 -0
- package/dist/reporters/sarif.d.ts +7 -0
- package/dist/reporters/sarif.d.ts.map +1 -0
- package/dist/reporters/sarif.js +135 -0
- package/dist/resilience/circuit_breaker.d.ts +36 -0
- package/dist/resilience/circuit_breaker.d.ts.map +1 -0
- package/dist/resilience/circuit_breaker.js +82 -0
- package/dist/resilience/retry.d.ts +11 -0
- package/dist/resilience/retry.d.ts.map +1 -0
- package/dist/resilience/retry.js +59 -0
- package/dist/sanitize.d.ts +15 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +71 -0
- package/dist/training/enricher.d.ts +17 -0
- package/dist/training/enricher.d.ts.map +1 -0
- package/dist/training/enricher.js +350 -0
- package/dist/training/kg_scanner.d.ts +13 -0
- package/dist/training/kg_scanner.d.ts.map +1 -0
- package/dist/training/kg_scanner.js +118 -0
- package/dist/training/merger.d.ts +15 -0
- package/dist/training/merger.d.ts.map +1 -0
- package/dist/training/merger.js +208 -0
- package/dist/training/scanner.d.ts +36 -0
- package/dist/training/scanner.d.ts.map +1 -0
- package/dist/training/scanner.js +932 -0
- package/dist/training/types.d.ts +117 -0
- package/dist/training/types.d.ts.map +1 -0
- package/dist/training/types.js +9 -0
- package/dist/training/validator.d.ts +21 -0
- package/dist/training/validator.d.ts.map +1 -0
- package/dist/training/validator.js +262 -0
- package/dist/validation/guardrails.d.ts +31 -0
- package/dist/validation/guardrails.d.ts.map +1 -0
- package/dist/validation/guardrails.js +112 -0
- package/dist/validation/output_schema.d.ts +67 -0
- package/dist/validation/output_schema.d.ts.map +1 -0
- package/dist/validation/output_schema.js +84 -0
- package/dist/version.d.ts +6 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +36 -0
- package/package.json +126 -0
- package/schemas/flow-decision.schema.json +83 -0
- package/schemas/gap.schema.json +18 -0
- package/schemas/impact.schema.json +455 -0
- package/schemas/plan.schema.json +491 -0
- package/schemas/route-families.schema.json +137 -0
- package/schemas/subsystem-risk-map.schema.json +62 -0
- package/schemas/traceability-input.schema.json +122 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
const DURATION_BUCKETS = [0.1, 0.5, 1, 2, 5, 10, 30, 60, 120, 300];
|
|
4
|
+
export class PrometheusMetrics {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.counters = [];
|
|
7
|
+
this.gauges = [];
|
|
8
|
+
this.histograms = [];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Record an LLM request.
|
|
12
|
+
*/
|
|
13
|
+
recordLLMRequest(provider, agent, durationMs, costUSD, tokens) {
|
|
14
|
+
this.incrementCounter('e2e_agents_llm_requests_total', 'Total LLM requests', { provider, agent });
|
|
15
|
+
this.incrementCounter('e2e_agents_llm_tokens_total', 'Total tokens consumed', { provider, agent }, tokens);
|
|
16
|
+
this.incrementCounter('e2e_agents_llm_cost_usd_total', 'Total LLM cost in USD', { provider, agent }, costUSD);
|
|
17
|
+
this.observeHistogram('e2e_agents_llm_request_duration_seconds', 'LLM request duration', { provider, agent }, durationMs / 1000);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Record a crew workflow run.
|
|
21
|
+
*/
|
|
22
|
+
recordCrewRun(workflow, families, durationMs, costUSD) {
|
|
23
|
+
this.incrementCounter('e2e_agents_crew_runs_total', 'Total crew workflow runs', { workflow });
|
|
24
|
+
this.incrementCounter('e2e_agents_crew_families_processed_total', 'Total families processed', { workflow }, families);
|
|
25
|
+
this.incrementCounter('e2e_agents_crew_cost_usd_total', 'Total crew cost in USD', { workflow }, costUSD);
|
|
26
|
+
this.observeHistogram('e2e_agents_crew_duration_seconds', 'Crew workflow duration', { workflow }, durationMs / 1000);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Record a budget check event.
|
|
30
|
+
*/
|
|
31
|
+
recordBudgetCheck(exceeded, currentUSD, limitUSD) {
|
|
32
|
+
this.incrementCounter('e2e_agents_budget_checks_total', 'Total budget checks', { exceeded: String(exceeded) });
|
|
33
|
+
this.setGauge('e2e_agents_budget_used_usd', 'Current budget usage in USD', {}, currentUSD);
|
|
34
|
+
this.setGauge('e2e_agents_budget_limit_usd', 'Budget limit in USD', {}, limitUSD);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Record a circuit breaker state change.
|
|
38
|
+
*/
|
|
39
|
+
recordCircuitBreakerState(state) {
|
|
40
|
+
this.setGauge('e2e_agents_circuit_breaker_state', 'Circuit breaker state (0=closed, 1=open, 2=half-open)', {}, state === 'closed' ? 0 : state === 'open' ? 1 : 2);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Record a cache hit or miss.
|
|
44
|
+
*/
|
|
45
|
+
recordCacheResult(hit, agent) {
|
|
46
|
+
this.incrementCounter('e2e_agents_cache_lookups_total', 'Total cache lookups', { result: hit ? 'hit' : 'miss', agent });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Export all metrics in Prometheus text exposition format.
|
|
50
|
+
*/
|
|
51
|
+
export() {
|
|
52
|
+
const lines = [];
|
|
53
|
+
const seenHelp = new Set();
|
|
54
|
+
// Export counters
|
|
55
|
+
for (const counter of this.counters) {
|
|
56
|
+
if (!seenHelp.has(counter.name)) {
|
|
57
|
+
lines.push(`# HELP ${counter.name} ${counter.help}`);
|
|
58
|
+
lines.push(`# TYPE ${counter.name} counter`);
|
|
59
|
+
seenHelp.add(counter.name);
|
|
60
|
+
}
|
|
61
|
+
const labelStr = formatLabels(counter.labels);
|
|
62
|
+
lines.push(`${counter.name}${labelStr} ${counter.value}`);
|
|
63
|
+
}
|
|
64
|
+
// Export gauges
|
|
65
|
+
for (const gauge of this.gauges) {
|
|
66
|
+
if (!seenHelp.has(gauge.name)) {
|
|
67
|
+
lines.push(`# HELP ${gauge.name} ${gauge.help}`);
|
|
68
|
+
lines.push(`# TYPE ${gauge.name} gauge`);
|
|
69
|
+
seenHelp.add(gauge.name);
|
|
70
|
+
}
|
|
71
|
+
const labelStr = formatLabels(gauge.labels);
|
|
72
|
+
lines.push(`${gauge.name}${labelStr} ${gauge.value}`);
|
|
73
|
+
}
|
|
74
|
+
// Export histograms
|
|
75
|
+
for (const hist of this.histograms) {
|
|
76
|
+
if (!seenHelp.has(hist.name)) {
|
|
77
|
+
lines.push(`# HELP ${hist.name} ${hist.help}`);
|
|
78
|
+
lines.push(`# TYPE ${hist.name} histogram`);
|
|
79
|
+
seenHelp.add(hist.name);
|
|
80
|
+
}
|
|
81
|
+
const labelStr = formatLabels(hist.labels);
|
|
82
|
+
let cumulative = 0;
|
|
83
|
+
for (const bucket of DURATION_BUCKETS) {
|
|
84
|
+
cumulative += hist.buckets.get(bucket) || 0;
|
|
85
|
+
lines.push(`${hist.name}_bucket${formatLabels({ ...hist.labels, le: String(bucket) })} ${cumulative}`);
|
|
86
|
+
}
|
|
87
|
+
lines.push(`${hist.name}_bucket${formatLabels({ ...hist.labels, le: '+Inf' })} ${hist.count}`);
|
|
88
|
+
lines.push(`${hist.name}_sum${labelStr} ${hist.sum}`);
|
|
89
|
+
lines.push(`${hist.name}_count${labelStr} ${hist.count}`);
|
|
90
|
+
}
|
|
91
|
+
return lines.join('\n') + '\n';
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Reset all metrics to zero.
|
|
95
|
+
*/
|
|
96
|
+
reset() {
|
|
97
|
+
this.counters = [];
|
|
98
|
+
this.gauges = [];
|
|
99
|
+
this.histograms = [];
|
|
100
|
+
}
|
|
101
|
+
incrementCounter(name, help, labels, value = 1) {
|
|
102
|
+
const existing = this.counters.find((c) => c.name === name && labelsMatch(c.labels, labels));
|
|
103
|
+
if (existing) {
|
|
104
|
+
existing.value += value;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
this.counters.push({ name, help, labels, value });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
setGauge(name, help, labels, value) {
|
|
111
|
+
const existing = this.gauges.find((c) => c.name === name && labelsMatch(c.labels, labels));
|
|
112
|
+
if (existing) {
|
|
113
|
+
existing.value = value;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.gauges.push({ name, help, labels, value });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
observeHistogram(name, help, labels, value) {
|
|
120
|
+
let existing = this.histograms.find((h) => h.name === name && labelsMatch(h.labels, labels));
|
|
121
|
+
if (!existing) {
|
|
122
|
+
existing = { name, help, labels, sum: 0, count: 0, buckets: new Map() };
|
|
123
|
+
this.histograms.push(existing);
|
|
124
|
+
}
|
|
125
|
+
existing.sum += value;
|
|
126
|
+
existing.count++;
|
|
127
|
+
for (const bucket of DURATION_BUCKETS) {
|
|
128
|
+
if (value <= bucket) {
|
|
129
|
+
existing.buckets.set(bucket, (existing.buckets.get(bucket) || 0) + 1);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function escapeLabel(v) {
|
|
135
|
+
return v.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
|
|
136
|
+
}
|
|
137
|
+
function formatLabels(labels) {
|
|
138
|
+
const entries = Object.entries(labels);
|
|
139
|
+
if (entries.length === 0)
|
|
140
|
+
return '';
|
|
141
|
+
return `{${entries.map(([k, v]) => `${k}="${escapeLabel(v)}"`).join(',')}}`;
|
|
142
|
+
}
|
|
143
|
+
function labelsMatch(a, b) {
|
|
144
|
+
const keysA = Object.keys(a);
|
|
145
|
+
const keysB = Object.keys(b);
|
|
146
|
+
if (keysA.length !== keysB.length)
|
|
147
|
+
return false;
|
|
148
|
+
return keysA.every((k) => a[k] === b[k]);
|
|
149
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
const AGENT_COMPLEXITY = {
|
|
4
|
+
'impact-analyst': 'classification',
|
|
5
|
+
'coverage-evaluator': 'classification',
|
|
6
|
+
'cross-impact': 'extraction',
|
|
7
|
+
'regression-advisor': 'extraction',
|
|
8
|
+
'strategist': 'classification',
|
|
9
|
+
'test-designer': 'generation',
|
|
10
|
+
'generator': 'generation',
|
|
11
|
+
'executor': 'generation',
|
|
12
|
+
'healer': 'reasoning',
|
|
13
|
+
'explorer': 'reasoning',
|
|
14
|
+
};
|
|
15
|
+
const DEFAULT_MODELS = {
|
|
16
|
+
anthropic: {
|
|
17
|
+
classification: 'claude-haiku-4-5-20251001',
|
|
18
|
+
extraction: 'claude-haiku-4-5-20251001',
|
|
19
|
+
generation: 'claude-sonnet-4-5-20250514',
|
|
20
|
+
reasoning: 'claude-sonnet-4-5-20250514',
|
|
21
|
+
},
|
|
22
|
+
openai: {
|
|
23
|
+
classification: 'gpt-4o-mini',
|
|
24
|
+
extraction: 'gpt-4o-mini',
|
|
25
|
+
generation: 'gpt-4o',
|
|
26
|
+
reasoning: 'gpt-4o',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
export class ModelRouter {
|
|
30
|
+
constructor(providerType, overrides) {
|
|
31
|
+
this.providerType = providerType;
|
|
32
|
+
this.overrides = overrides || {};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the recommended model for a given agent role.
|
|
36
|
+
* Returns undefined if no routing recommendation (use provider default).
|
|
37
|
+
*/
|
|
38
|
+
getModel(role) {
|
|
39
|
+
const complexity = AGENT_COMPLEXITY[role];
|
|
40
|
+
if (!complexity)
|
|
41
|
+
return undefined;
|
|
42
|
+
// Check user overrides first
|
|
43
|
+
const override = this.overrides[complexity];
|
|
44
|
+
if (override)
|
|
45
|
+
return override;
|
|
46
|
+
// Check provider defaults
|
|
47
|
+
const defaults = DEFAULT_MODELS[this.providerType];
|
|
48
|
+
if (defaults)
|
|
49
|
+
return defaults[complexity];
|
|
50
|
+
// No recommendation — use provider's default model
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the task complexity for an agent role.
|
|
55
|
+
*/
|
|
56
|
+
getComplexity(role) {
|
|
57
|
+
return AGENT_COMPLEXITY[role] || 'generation';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import OpenAI from 'openai';
|
|
4
|
+
import { LLMProviderError, UnsupportedCapabilityError } from './provider_interface.js';
|
|
5
|
+
import { sanitizeErrorMessage, withTimeout } from './provider_utils.js';
|
|
6
|
+
import { BaseProvider } from './base_provider.js';
|
|
7
|
+
import { logger } from './logger.js';
|
|
8
|
+
/**
|
|
9
|
+
* SECURITY: Validate Ollama base URL and enforce HTTPS for remote connections
|
|
10
|
+
*/
|
|
11
|
+
function normalizeOllamaBaseUrl(baseUrl) {
|
|
12
|
+
const raw = baseUrl || 'http://localhost:11434';
|
|
13
|
+
try {
|
|
14
|
+
const parsed = new URL(raw);
|
|
15
|
+
if (!parsed.pathname || parsed.pathname === '/') {
|
|
16
|
+
parsed.pathname = '/v1';
|
|
17
|
+
}
|
|
18
|
+
return parsed.toString().replace(/\/$/, '');
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return 'http://localhost:11434/v1';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function validateOllamaUrl(baseUrl) {
|
|
25
|
+
const url = normalizeOllamaBaseUrl(baseUrl);
|
|
26
|
+
try {
|
|
27
|
+
const parsed = new URL(url);
|
|
28
|
+
// For non-localhost URLs, warn about HTTP risks
|
|
29
|
+
const isLocalhost = parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1' || parsed.hostname === '::1';
|
|
30
|
+
if (!isLocalhost && parsed.protocol === 'http:') {
|
|
31
|
+
logger.warn('Ollama connection over plaintext HTTP to remote server. ' +
|
|
32
|
+
'Prompts and responses will be transmitted unencrypted. Consider using HTTPS proxy or local Ollama.');
|
|
33
|
+
}
|
|
34
|
+
return { valid: true, url };
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return {
|
|
38
|
+
valid: false,
|
|
39
|
+
url: 'http://localhost:11434/v1',
|
|
40
|
+
warning: `Invalid Ollama URL: ${baseUrl}. Using default: http://localhost:11434/v1`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* SECURITY: Validate model name to prevent injection issues
|
|
46
|
+
*/
|
|
47
|
+
function validateModelName(model) {
|
|
48
|
+
// Allow alphanumeric, dash, colon, underscore
|
|
49
|
+
// Typical format: deepseek-r1:7b, llama4:13b, etc.
|
|
50
|
+
return /^[a-z0-9_:.\-]+$/i.test(model) && model.length < 256;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* SECURITY: Validate timeout value
|
|
54
|
+
*/
|
|
55
|
+
function validateTimeout(timeout) {
|
|
56
|
+
if (!timeout)
|
|
57
|
+
return 60000;
|
|
58
|
+
if (timeout < 1000 || timeout > 600000) {
|
|
59
|
+
logger.warn('Timeout out of valid range (1s-10m). Using 60 second default.');
|
|
60
|
+
return 60000;
|
|
61
|
+
}
|
|
62
|
+
return timeout;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Ollama Provider - Free, local LLM execution
|
|
66
|
+
*
|
|
67
|
+
* Features:
|
|
68
|
+
* - Zero cost (runs locally)
|
|
69
|
+
* - Full privacy (no data leaves your machine)
|
|
70
|
+
* - OpenAI-compatible API
|
|
71
|
+
* - Supports DeepSeek-R1, Llama 4, and other open models
|
|
72
|
+
*
|
|
73
|
+
* Limitations:
|
|
74
|
+
* - No vision support (most models)
|
|
75
|
+
* - Slower inference than cloud APIs (~2-5 sec vs <1 sec)
|
|
76
|
+
* - Requires local installation and model downloads
|
|
77
|
+
*
|
|
78
|
+
* Recommended models:
|
|
79
|
+
* - deepseek-r1:7b - Fast, good quality, low memory (4GB)
|
|
80
|
+
* - deepseek-r1:14b - Better quality, medium memory (8GB)
|
|
81
|
+
* - llama4:13b - High quality, medium memory (8GB)
|
|
82
|
+
* - deepseek-r1:7b-q4 - Quantized for speed, lower quality
|
|
83
|
+
*
|
|
84
|
+
* Setup:
|
|
85
|
+
* 1. Install Ollama: curl -fsSL https://ollama.com/install.sh | sh
|
|
86
|
+
* 2. Pull model: ollama pull deepseek-r1:7b
|
|
87
|
+
* 3. Start: ollama serve (runs on localhost:11434)
|
|
88
|
+
*/
|
|
89
|
+
export class OllamaProvider extends BaseProvider {
|
|
90
|
+
constructor(config) {
|
|
91
|
+
super();
|
|
92
|
+
this.name = 'ollama';
|
|
93
|
+
this.capabilities = {
|
|
94
|
+
vision: false, // Most Ollama models don't support vision
|
|
95
|
+
streaming: true,
|
|
96
|
+
maxTokens: 8000, // Varies by model
|
|
97
|
+
costPer1MInputTokens: 0, // Free!
|
|
98
|
+
costPer1MOutputTokens: 0, // Free!
|
|
99
|
+
supportsTools: true, // DeepSeek, Llama 4 support function calling
|
|
100
|
+
supportsPromptCaching: false,
|
|
101
|
+
typicalResponseTimeMs: 3000, // ~2-5 seconds on decent hardware
|
|
102
|
+
};
|
|
103
|
+
// SECURITY: Validate and sanitize URL
|
|
104
|
+
const urlValidation = validateOllamaUrl(config.baseUrl);
|
|
105
|
+
if (!urlValidation.valid && urlValidation.warning) {
|
|
106
|
+
logger.warn(urlValidation.warning);
|
|
107
|
+
}
|
|
108
|
+
// SECURITY: Validate timeout
|
|
109
|
+
const timeout = validateTimeout(config.timeout);
|
|
110
|
+
// Ollama uses OpenAI-compatible API
|
|
111
|
+
this.client = new OpenAI({
|
|
112
|
+
baseURL: urlValidation.url,
|
|
113
|
+
apiKey: 'ollama', // Ollama doesn't require real API key
|
|
114
|
+
timeout,
|
|
115
|
+
maxRetries: 0, // Don't retry to avoid hanging on connection issues
|
|
116
|
+
});
|
|
117
|
+
const model = config.model || 'deepseek-r1:7b';
|
|
118
|
+
// SECURITY: Validate model name format
|
|
119
|
+
if (!validateModelName(model)) {
|
|
120
|
+
throw new Error('Invalid model name format');
|
|
121
|
+
}
|
|
122
|
+
this.model = model;
|
|
123
|
+
}
|
|
124
|
+
async generateText(prompt, options) {
|
|
125
|
+
this.checkBudget();
|
|
126
|
+
const startTime = Date.now();
|
|
127
|
+
try {
|
|
128
|
+
// SECURITY: Validate prompt length
|
|
129
|
+
if (prompt.length > 10 * 1024 * 1024) {
|
|
130
|
+
throw new Error('Prompt exceeds maximum size (10MB)');
|
|
131
|
+
}
|
|
132
|
+
const messages = [];
|
|
133
|
+
// Add system message if provided
|
|
134
|
+
if (options?.systemPrompt) {
|
|
135
|
+
messages.push({
|
|
136
|
+
role: 'system',
|
|
137
|
+
content: options.systemPrompt,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// Add user prompt
|
|
141
|
+
messages.push({
|
|
142
|
+
role: 'user',
|
|
143
|
+
content: prompt,
|
|
144
|
+
});
|
|
145
|
+
const response = await withTimeout(this.client.chat.completions.create({
|
|
146
|
+
model: this.model,
|
|
147
|
+
messages,
|
|
148
|
+
max_tokens: options?.maxTokens,
|
|
149
|
+
temperature: options?.temperature,
|
|
150
|
+
top_p: options?.topP,
|
|
151
|
+
stop: options?.stopSequences,
|
|
152
|
+
}), options?.timeout, 'generateText');
|
|
153
|
+
const responseTime = Date.now() - startTime;
|
|
154
|
+
const text = response.choices[0]?.message?.content || '';
|
|
155
|
+
const usage = {
|
|
156
|
+
inputTokens: response.usage?.prompt_tokens || 0,
|
|
157
|
+
outputTokens: response.usage?.completion_tokens || 0,
|
|
158
|
+
totalTokens: response.usage?.total_tokens || 0,
|
|
159
|
+
};
|
|
160
|
+
// Update stats
|
|
161
|
+
this.updateStats(usage, responseTime, 0); // Cost is always 0 for Ollama
|
|
162
|
+
return {
|
|
163
|
+
text,
|
|
164
|
+
usage,
|
|
165
|
+
cost: 0, // Free!
|
|
166
|
+
metadata: {
|
|
167
|
+
model: this.model,
|
|
168
|
+
responseTimeMs: responseTime,
|
|
169
|
+
finishReason: response.choices[0]?.finish_reason,
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
this.stats.failedRequests++;
|
|
175
|
+
throw new LLMProviderError(sanitizeErrorMessage(error, 'generateText'), this.name, undefined, error);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Ollama does not support vision by default
|
|
180
|
+
* This method throws an error to help users understand the limitation
|
|
181
|
+
*/
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
183
|
+
async analyzeImage(images, prompt, options) {
|
|
184
|
+
throw new UnsupportedCapabilityError(this.name, 'vision');
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Stream text generation for real-time feedback
|
|
188
|
+
*/
|
|
189
|
+
async *streamText(prompt, options) {
|
|
190
|
+
try {
|
|
191
|
+
// SECURITY: Validate prompt length
|
|
192
|
+
if (prompt.length > 10 * 1024 * 1024) {
|
|
193
|
+
throw new Error('Prompt exceeds maximum size (10MB)');
|
|
194
|
+
}
|
|
195
|
+
const messages = [];
|
|
196
|
+
if (options?.systemPrompt) {
|
|
197
|
+
messages.push({
|
|
198
|
+
role: 'system',
|
|
199
|
+
content: options.systemPrompt,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
messages.push({
|
|
203
|
+
role: 'user',
|
|
204
|
+
content: prompt,
|
|
205
|
+
});
|
|
206
|
+
const stream = await withTimeout(this.client.chat.completions.create({
|
|
207
|
+
model: this.model,
|
|
208
|
+
messages,
|
|
209
|
+
max_tokens: options?.maxTokens,
|
|
210
|
+
temperature: options?.temperature,
|
|
211
|
+
top_p: options?.topP,
|
|
212
|
+
stop: options?.stopSequences,
|
|
213
|
+
stream: true,
|
|
214
|
+
}), options?.timeout, 'streamText');
|
|
215
|
+
for await (const chunk of stream) {
|
|
216
|
+
const content = chunk.choices[0]?.delta?.content;
|
|
217
|
+
if (content) {
|
|
218
|
+
yield content;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Note: Streaming doesn't provide detailed usage stats
|
|
222
|
+
// We increment request count but can't track exact tokens
|
|
223
|
+
this.stats.requestCount++;
|
|
224
|
+
this.stats.lastUpdated = new Date();
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
this.stats.failedRequests++;
|
|
228
|
+
throw new LLMProviderError(sanitizeErrorMessage(error, 'streamText'), this.name, undefined, error);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Check if Ollama is running and accessible
|
|
233
|
+
*/
|
|
234
|
+
async checkHealth() {
|
|
235
|
+
try {
|
|
236
|
+
// Try a simple request
|
|
237
|
+
await withTimeout(this.client.models.list(), 5000, 'health check');
|
|
238
|
+
return {
|
|
239
|
+
healthy: true,
|
|
240
|
+
message: `Ollama is running with model: ${this.model}`,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
return {
|
|
245
|
+
healthy: false,
|
|
246
|
+
message: `Ollama not accessible: ${sanitizeErrorMessage(error, 'health check')}`,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* List available models in Ollama
|
|
252
|
+
*/
|
|
253
|
+
async listModels() {
|
|
254
|
+
try {
|
|
255
|
+
const response = await withTimeout(this.client.models.list(), 5000, 'listModels');
|
|
256
|
+
return response.data.map((model) => model.id);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
throw new LLMProviderError(sanitizeErrorMessage(error, 'listModels'), this.name, undefined, error);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Helper function to check if Ollama is installed and suggest setup
|
|
265
|
+
*/
|
|
266
|
+
export async function checkOllamaSetup() {
|
|
267
|
+
const provider = new OllamaProvider({});
|
|
268
|
+
try {
|
|
269
|
+
const health = await provider.checkHealth();
|
|
270
|
+
const models = await provider.listModels();
|
|
271
|
+
return {
|
|
272
|
+
installed: true,
|
|
273
|
+
running: health.healthy,
|
|
274
|
+
modelAvailable: models.length > 0,
|
|
275
|
+
setupInstructions: health.healthy ? 'Ollama is ready to use!' : 'Run: ollama serve',
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
return {
|
|
280
|
+
installed: false,
|
|
281
|
+
running: false,
|
|
282
|
+
modelAvailable: false,
|
|
283
|
+
setupInstructions: `
|
|
284
|
+
Ollama is not installed. To set up:
|
|
285
|
+
|
|
286
|
+
1. Install Ollama:
|
|
287
|
+
curl -fsSL https://ollama.com/install.sh | sh
|
|
288
|
+
|
|
289
|
+
2. Pull a model (choose one):
|
|
290
|
+
ollama pull deepseek-r1:7b # Recommended: Fast, 4GB RAM
|
|
291
|
+
ollama pull deepseek-r1:14b # Better quality, 8GB RAM
|
|
292
|
+
ollama pull llama4:13b # Alternative, 8GB RAM
|
|
293
|
+
|
|
294
|
+
3. Start Ollama:
|
|
295
|
+
ollama serve
|
|
296
|
+
|
|
297
|
+
For more info: https://ollama.com
|
|
298
|
+
`.trim(),
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|