@crownpeak/dqm-react-component-dev-mcp 1.2.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/README.md +138 -0
- package/data/.env.example +22 -0
- package/data/.gitattributes +47 -0
- package/data/.glfrc.json +7 -0
- package/data/.husky/pre-commit +5 -0
- package/data/.nvmrc +1 -0
- package/data/CHANGELOG.md +75 -0
- package/data/CODE_OF_CONDUCT.md +129 -0
- package/data/CONTRIBUTING.md +203 -0
- package/data/DOCS-STRUCTURE.md +307 -0
- package/data/I18N.md +292 -0
- package/data/LICENSE +22 -0
- package/data/README.md +315 -0
- package/data/SECURITY.md +125 -0
- package/data/WIKI-DEPLOYMENT.md +348 -0
- package/data/docs/AI-FEATURES.md +610 -0
- package/data/docs/API-REFERENCE.md +1022 -0
- package/data/docs/AUTHENTICATION.md +301 -0
- package/data/docs/BACKEND-API.md +468 -0
- package/data/docs/DEVELOPMENT.md +375 -0
- package/data/docs/EXAMPLES.md +622 -0
- package/data/docs/MCP-SERVER.md +307 -0
- package/data/docs/MIGRATION-GUIDE.md +367 -0
- package/data/docs/NPM-PUBLISH.md +193 -0
- package/data/docs/QUICKSTART.md +206 -0
- package/data/docs/REDIS-SETUP.md +162 -0
- package/data/docs/SERVER.md +228 -0
- package/data/docs/TROUBLESHOOTING.md +657 -0
- package/data/docs/WIDGET-GUIDE.md +638 -0
- package/data/docs/WIKI-HOME.md +58 -0
- package/data/docs/WIKI-SIDEBAR.md +39 -0
- package/data/package.json +171 -0
- package/data/playwright.config.ts +64 -0
- package/data/probe/.cargo/config.toml +10 -0
- package/data/probe/.claude/commands/performance-review.md +15 -0
- package/data/probe/.clinerules +288 -0
- package/data/probe/.dockerignore +57 -0
- package/data/probe/.githooks/post-commit +11 -0
- package/data/probe/.githooks/pre-commit +99 -0
- package/data/probe/.githooks/pre-commit-vow +9 -0
- package/data/probe/.prompts/engineer.md +41 -0
- package/data/probe/.roomodes +28 -0
- package/data/probe/.windsurfrules +0 -0
- package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
- package/data/probe/BENCHMARKING.md +256 -0
- package/data/probe/CLAUDE.md +226 -0
- package/data/probe/CODE_OF_CONDUCT.md +128 -0
- package/data/probe/CONTRIBUTING.md +193 -0
- package/data/probe/Cargo.toml +120 -0
- package/data/probe/Cross.toml +10 -0
- package/data/probe/DOCKER-README.md +224 -0
- package/data/probe/Dockerfile +32 -0
- package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
- package/data/probe/LICENSE +201 -0
- package/data/probe/Makefile +210 -0
- package/data/probe/README.md +824 -0
- package/data/probe/SECURITY.md +67 -0
- package/data/probe/WINDOWS-GUIDE.md +294 -0
- package/data/probe/benches/parsing_benchmarks.rs +370 -0
- package/data/probe/benches/search_benchmarks.rs +599 -0
- package/data/probe/benches/simd_benchmarks.rs +372 -0
- package/data/probe/benches/timing_benchmarks.rs +287 -0
- package/data/probe/build-windows.bat +229 -0
- package/data/probe/codex-config/config.toml +6 -0
- package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
- package/data/probe/examples/cache_demo.rs +46 -0
- package/data/probe/examples/chat/.dockerignore +37 -0
- package/data/probe/examples/chat/ChatSessionManager.js +295 -0
- package/data/probe/examples/chat/Dockerfile +98 -0
- package/data/probe/examples/chat/LICENSE +201 -0
- package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
- package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
- package/data/probe/examples/chat/README.md +338 -0
- package/data/probe/examples/chat/TRACING.md +226 -0
- package/data/probe/examples/chat/appTracer.js +968 -0
- package/data/probe/examples/chat/auth.js +76 -0
- package/data/probe/examples/chat/bin/probe-chat.js +13 -0
- package/data/probe/examples/chat/build.js +104 -0
- package/data/probe/examples/chat/cancelRequest.js +84 -0
- package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
- package/data/probe/examples/chat/demo-local-images.js +128 -0
- package/data/probe/examples/chat/fileSpanExporter.js +181 -0
- package/data/probe/examples/chat/implement/README.md +228 -0
- package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
- package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
- package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
- package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
- package/data/probe/examples/chat/implement/backends/registry.js +85 -0
- package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
- package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
- package/data/probe/examples/chat/implement/core/config.js +428 -0
- package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
- package/data/probe/examples/chat/implement/core/utils.js +496 -0
- package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
- package/data/probe/examples/chat/index.js +669 -0
- package/data/probe/examples/chat/mcpServer.js +341 -0
- package/data/probe/examples/chat/npm/LICENSE +15 -0
- package/data/probe/examples/chat/npm/README.md +168 -0
- package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
- package/data/probe/examples/chat/npm/index.js +259 -0
- package/data/probe/examples/chat/npm/package.json +54 -0
- package/data/probe/examples/chat/package.json +102 -0
- package/data/probe/examples/chat/probeChat.js +456 -0
- package/data/probe/examples/chat/probeTool.js +491 -0
- package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
- package/data/probe/examples/chat/telemetry.js +281 -0
- package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
- package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
- package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
- package/data/probe/examples/chat/test/test-backends.js +90 -0
- package/data/probe/examples/chat/test/testUtils.js +530 -0
- package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
- package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
- package/data/probe/examples/chat/test/verify-tests.js +118 -0
- package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
- package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
- package/data/probe/examples/chat/test-chat-tracing.js +38 -0
- package/data/probe/examples/chat/test-direct-function.js +49 -0
- package/data/probe/examples/chat/test-file-size-validation.js +103 -0
- package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
- package/data/probe/examples/chat/test-github-context.txt +12 -0
- package/data/probe/examples/chat/test-hierarchy.js +203 -0
- package/data/probe/examples/chat/test-image-spans.js +37 -0
- package/data/probe/examples/chat/test-local-image-reading.js +176 -0
- package/data/probe/examples/chat/test-mcp-integration.js +136 -0
- package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
- package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
- package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
- package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
- package/data/probe/examples/chat/test-security-validation.js +145 -0
- package/data/probe/examples/chat/test-simple-tracing.js +32 -0
- package/data/probe/examples/chat/test-trace-verification.js +235 -0
- package/data/probe/examples/chat/test-tracing.js +114 -0
- package/data/probe/examples/chat/tokenCounter.js +419 -0
- package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
- package/data/probe/examples/chat/webServer.js +1103 -0
- package/data/probe/examples/reranker/Cargo.toml +33 -0
- package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
- package/data/probe/examples/reranker/MODELS.md +66 -0
- package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
- package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
- package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
- package/data/probe/examples/reranker/README.md +347 -0
- package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
- package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
- package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
- package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
- package/data/probe/examples/reranker/debug_scoring.py +189 -0
- package/data/probe/examples/reranker/debug_tokenization.py +154 -0
- package/data/probe/examples/reranker/download_models.sh +73 -0
- package/data/probe/examples/reranker/requirements.txt +13 -0
- package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
- package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
- package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
- package/data/probe/examples/reranker/simple_test.py +50 -0
- package/data/probe/examples/reranker/test_all_models.sh +63 -0
- package/data/probe/examples/reranker/test_bert_results.sh +44 -0
- package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
- package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
- package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
- package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
- package/data/probe/examples/reranker/test_scores.py +132 -0
- package/data/probe/install.ps1 +508 -0
- package/data/probe/install.sh +460 -0
- package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
- package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
- package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
- package/data/probe/npm/MAID_INTEGRATION.md +313 -0
- package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
- package/data/probe/npm/README.md +824 -0
- package/data/probe/npm/bin/.gitignore +7 -0
- package/data/probe/npm/bin/.gitkeep +0 -0
- package/data/probe/npm/bin/README.md +12 -0
- package/data/probe/npm/bin/probe +167 -0
- package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
- package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
- package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
- package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
- package/data/probe/npm/example-usage.js +335 -0
- package/data/probe/npm/examples/multi-engine-demo.js +117 -0
- package/data/probe/npm/examples/probe-agent-cli.js +113 -0
- package/data/probe/npm/examples/test-agent-edit.js +114 -0
- package/data/probe/npm/examples/test-edit-create.js +120 -0
- package/data/probe/npm/examples/test-edit-direct.js +114 -0
- package/data/probe/npm/index.d.ts +744 -0
- package/data/probe/npm/jest.config.js +52 -0
- package/data/probe/npm/package.json +117 -0
- package/data/probe/npm/scripts/build-agent.cjs +75 -0
- package/data/probe/npm/scripts/build-cjs.js +124 -0
- package/data/probe/npm/scripts/build-mcp.cjs +36 -0
- package/data/probe/npm/scripts/postinstall.js +216 -0
- package/data/probe/npm/test-codex-e2e.js +78 -0
- package/data/probe/npm/test-download-lock.js +109 -0
- package/data/probe/npm/test-grep-security.js +94 -0
- package/data/probe/npm/test-grep-simplified.js +63 -0
- package/data/probe/npm/test-grep.js +51 -0
- package/data/probe/npm/tests/README.md +96 -0
- package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
- package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
- package/data/probe/npm/tests/contextCompactor.test.js +498 -0
- package/data/probe/npm/tests/delegate-config.test.js +353 -0
- package/data/probe/npm/tests/delegate-integration.test.js +348 -0
- package/data/probe/npm/tests/extractor-integration.test.js +162 -0
- package/data/probe/npm/tests/extractor.test.js +317 -0
- package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
- package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
- package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
- package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
- package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
- package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
- package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
- package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
- package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
- package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
- package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
- package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
- package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
- package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
- package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
- package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
- package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
- package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
- package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
- package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
- package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
- package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
- package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
- package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
- package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
- package/data/probe/npm/tests/setup.js +46 -0
- package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
- package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
- package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
- package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
- package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
- package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
- package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
- package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
- package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
- package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
- package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
- package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
- package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
- package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
- package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
- package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
- package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
- package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
- package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
- package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
- package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
- package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
- package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
- package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
- package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
- package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
- package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
- package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
- package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
- package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
- package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
- package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
- package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
- package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
- package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
- package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
- package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
- package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
- package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
- package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
- package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
- package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
- package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
- package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
- package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
- package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
- package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
- package/data/probe/npm/tsconfig.json +21 -0
- package/data/probe/result1.txt +19 -0
- package/data/probe/result2.txt +26 -0
- package/data/probe/scripts/benchmark.sh +270 -0
- package/data/probe/scripts/cache_memory_analysis.rs +844 -0
- package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
- package/data/probe/site/.env.example +10 -0
- package/data/probe/site/DEPLOYMENT.md +86 -0
- package/data/probe/site/README.md +183 -0
- package/data/probe/site/adding-languages.md +135 -0
- package/data/probe/site/ai-chat.md +427 -0
- package/data/probe/site/ai-integration.md +1488 -0
- package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
- package/data/probe/site/blog/index.md +118 -0
- package/data/probe/site/blog/v0.6.0-release.md +426 -0
- package/data/probe/site/blog.md +8 -0
- package/data/probe/site/changelog.md +200 -0
- package/data/probe/site/cli-mode.md +437 -0
- package/data/probe/site/code-extraction.md +436 -0
- package/data/probe/site/contributing/README.md +9 -0
- package/data/probe/site/contributing/documentation-cross-references.md +215 -0
- package/data/probe/site/contributing/documentation-maintenance.md +275 -0
- package/data/probe/site/contributing/documentation-structure.md +75 -0
- package/data/probe/site/documentation-cross-references.md +215 -0
- package/data/probe/site/documentation-guide.md +132 -0
- package/data/probe/site/documentation-maintenance.md +275 -0
- package/data/probe/site/features.md +147 -0
- package/data/probe/site/how-it-works.md +118 -0
- package/data/probe/site/index.md +175 -0
- package/data/probe/site/index.md.bak +133 -0
- package/data/probe/site/installation.md +235 -0
- package/data/probe/site/integrations/docker.md +248 -0
- package/data/probe/site/integrations/github-actions.md +413 -0
- package/data/probe/site/language-support-overview.md +168 -0
- package/data/probe/site/mcp-integration.md +587 -0
- package/data/probe/site/mcp-server.md +304 -0
- package/data/probe/site/navigation-structure.md +76 -0
- package/data/probe/site/nodejs-sdk.md +798 -0
- package/data/probe/site/output-formats.md +625 -0
- package/data/probe/site/package.json +21 -0
- package/data/probe/site/public/_headers +28 -0
- package/data/probe/site/public/_redirects +11 -0
- package/data/probe/site/quick-start.md +289 -0
- package/data/probe/site/search-functionality.md +291 -0
- package/data/probe/site/search-reference.md +291 -0
- package/data/probe/site/supported-languages.md +215 -0
- package/data/probe/site/use-cases/README.md +8 -0
- package/data/probe/site/use-cases/advanced-cli.md +253 -0
- package/data/probe/site/use-cases/ai-code-editors.md +239 -0
- package/data/probe/site/use-cases/building-ai-tools.md +529 -0
- package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
- package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
- package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
- package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
- package/data/probe/site/use-cases/team-chat.md +350 -0
- package/data/probe/site/web-interface.md +434 -0
- package/data/probe/site/wrangler.toml +9 -0
- package/data/probe/test-api-key.sh +1 -0
- package/data/probe/test-probe-implementation/hello.js +7 -0
- package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
- package/data/probe/test_cases/early_termination_issues.rs +533 -0
- package/data/probe/test_data/test_nested_struct.go +26 -0
- package/data/probe/tests/README.md +286 -0
- package/data/probe/tests/README_search_determinism_tests.md +116 -0
- package/data/probe/tests/adjacent_comment_test.rs +152 -0
- package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
- package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
- package/data/probe/tests/block_merging_tests.rs +396 -0
- package/data/probe/tests/c_outline_format_tests.rs +2179 -0
- package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
- package/data/probe/tests/cache_order_tests.rs +147 -0
- package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
- package/data/probe/tests/cli_tests.rs +680 -0
- package/data/probe/tests/comment_context_integration_test.rs +240 -0
- package/data/probe/tests/common.rs +33 -0
- package/data/probe/tests/complex_block_merging_tests.rs +599 -0
- package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
- package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
- package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
- package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
- package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
- package/data/probe/tests/extract_command_tests.rs +1848 -0
- package/data/probe/tests/extract_deduplication_tests.rs +146 -0
- package/data/probe/tests/extract_input_file_tests.rs +84 -0
- package/data/probe/tests/extract_prompt_tests.rs +102 -0
- package/data/probe/tests/filename_search_tests.rs +96 -0
- package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
- package/data/probe/tests/github_extract_tests.rs +234 -0
- package/data/probe/tests/go_comment_test.rs +253 -0
- package/data/probe/tests/go_outline_format_tests.rs +2587 -0
- package/data/probe/tests/go_path_resolver_tests.rs +96 -0
- package/data/probe/tests/html_outline_format_tests.rs +637 -0
- package/data/probe/tests/integration_tests.rs +837 -0
- package/data/probe/tests/ip_whitelist_test.rs +148 -0
- package/data/probe/tests/java_outline_format_tests.rs +1611 -0
- package/data/probe/tests/javascript_extract_tests.rs +315 -0
- package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
- package/data/probe/tests/json_format_tests.rs +436 -0
- package/data/probe/tests/json_schema_validation_tests.rs +450 -0
- package/data/probe/tests/lib_usage.rs +60 -0
- package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
- package/data/probe/tests/line_map_cache_tests.rs +114 -0
- package/data/probe/tests/markdown_integration_tests.rs +190 -0
- package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
- package/data/probe/tests/mocks/test_object.js +27 -0
- package/data/probe/tests/mocks/test_struct.go +50 -0
- package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
- package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
- package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
- package/data/probe/tests/negative_compound_word_tests.rs +246 -0
- package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
- package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
- package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
- package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
- package/data/probe/tests/parallel_extraction_tests.rs +178 -0
- package/data/probe/tests/parallel_search_tests.rs +355 -0
- package/data/probe/tests/path_resolver_tests.rs +698 -0
- package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
- package/data/probe/tests/php_outline_format_tests.rs +768 -0
- package/data/probe/tests/property_tests.proptest-regressions +9 -0
- package/data/probe/tests/property_tests.rs +118 -0
- package/data/probe/tests/python_outline_format_tests.rs +1538 -0
- package/data/probe/tests/query_command_json_tests.rs +438 -0
- package/data/probe/tests/query_command_tests.rs +232 -0
- package/data/probe/tests/query_command_xml_tests.rs +569 -0
- package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
- package/data/probe/tests/required_terms_filename_tests.rs +116 -0
- package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
- package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
- package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
- package/data/probe/tests/rust_outline_format_tests.rs +843 -0
- package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
- package/data/probe/tests/search_determinism_tests.rs +451 -0
- package/data/probe/tests/search_hints_tests.rs +253 -0
- package/data/probe/tests/special_character_escaping_tests.rs +417 -0
- package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
- package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
- package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
- package/data/probe/tests/symbols_tests.rs +166 -0
- package/data/probe/tests/test_file.rs +45 -0
- package/data/probe/tests/test_tokenize.rs +28 -0
- package/data/probe/tests/timeout_tests.rs +82 -0
- package/data/probe/tests/tokenization_tests.rs +195 -0
- package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
- package/data/probe/tests/typescript_extract_tests.rs +214 -0
- package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
- package/data/probe/tests/xml_format_tests.rs +568 -0
- package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
- package/data/scripts/postinstall.mjs +9 -0
- package/data/scripts/set-version.js +0 -0
- package/data/scripts/wiki-build.sh +111 -0
- package/data/scripts/wiki-deploy.sh +73 -0
- package/data/serve.json +12 -0
- package/data/test/demo-dynamic.html +134 -0
- package/data/test/demo-esm.html +105 -0
- package/data/test/demo-iife.html +78 -0
- package/data/tsconfig.json +7 -0
- package/data/vite.server.ts +483 -0
- package/data/vitest.config.ts +40 -0
- package/data/wiki/Home.md +58 -0
- package/data/wiki/_Sidebar.md +39 -0
- package/docs-mcp.config.json +20 -0
- package/package.json +56 -0
- package/src/config.js +111 -0
- package/src/index.js +395 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for Retry + Fallback together
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, test, expect, jest, beforeEach } from '@jest/globals';
|
|
6
|
+
import { RetryManager } from '../../src/agent/RetryManager.js';
|
|
7
|
+
import { FallbackManager } from '../../src/agent/FallbackManager.js';
|
|
8
|
+
|
|
9
|
+
describe('Retry and Fallback Integration', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
jest.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('Combined retry and fallback flow', () => {
|
|
15
|
+
test('should retry on each provider before falling back', async () => {
|
|
16
|
+
const retry = new RetryManager({
|
|
17
|
+
maxRetries: 2,
|
|
18
|
+
initialDelay: 10,
|
|
19
|
+
debug: false
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const fallback = new FallbackManager({
|
|
23
|
+
strategy: 'custom',
|
|
24
|
+
providers: [
|
|
25
|
+
{ provider: 'anthropic', apiKey: 'key1' },
|
|
26
|
+
{ provider: 'openai', apiKey: 'key2' },
|
|
27
|
+
{ provider: 'google', apiKey: 'key3' }
|
|
28
|
+
],
|
|
29
|
+
debug: false
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const callLog = [];
|
|
33
|
+
|
|
34
|
+
// Mock function that tracks which provider is being used
|
|
35
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
36
|
+
callLog.push(config.provider);
|
|
37
|
+
|
|
38
|
+
// First provider (anthropic) fails 3 times (1 initial + 2 retries)
|
|
39
|
+
if (config.provider === 'anthropic') {
|
|
40
|
+
return retry.executeWithRetry(() => {
|
|
41
|
+
throw new Error('Overloaded');
|
|
42
|
+
}, { provider: 'anthropic' });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Second provider (openai) fails 3 times
|
|
46
|
+
if (config.provider === 'openai') {
|
|
47
|
+
return retry.executeWithRetry(() => {
|
|
48
|
+
throw new Error('Overloaded');
|
|
49
|
+
}, { provider: 'openai' });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Third provider (google) succeeds on second retry
|
|
53
|
+
if (config.provider === 'google') {
|
|
54
|
+
let attempts = 0;
|
|
55
|
+
return retry.executeWithRetry(() => {
|
|
56
|
+
attempts++;
|
|
57
|
+
if (attempts < 2) {
|
|
58
|
+
throw new Error('Overloaded');
|
|
59
|
+
}
|
|
60
|
+
return 'success from google';
|
|
61
|
+
}, { provider: 'google' });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const result = await fallback.executeWithFallback(mockFn);
|
|
66
|
+
|
|
67
|
+
expect(result).toBe('success from google');
|
|
68
|
+
expect(callLog).toEqual(['anthropic', 'openai', 'google']);
|
|
69
|
+
|
|
70
|
+
// Verify fallback stats
|
|
71
|
+
const fallbackStats = fallback.getStats();
|
|
72
|
+
expect(fallbackStats.totalAttempts).toBe(3);
|
|
73
|
+
expect(fallbackStats.successfulProvider).toContain('google');
|
|
74
|
+
expect(fallbackStats.failedProviders.length).toBe(2);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('should handle all providers exhausting retries', async () => {
|
|
78
|
+
const retry = new RetryManager({
|
|
79
|
+
maxRetries: 1,
|
|
80
|
+
initialDelay: 5,
|
|
81
|
+
debug: false
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const fallback = new FallbackManager({
|
|
85
|
+
strategy: 'custom',
|
|
86
|
+
providers: [
|
|
87
|
+
{ provider: 'anthropic', apiKey: 'key1' },
|
|
88
|
+
{ provider: 'openai', apiKey: 'key2' }
|
|
89
|
+
],
|
|
90
|
+
debug: false
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
94
|
+
return retry.executeWithRetry(() => {
|
|
95
|
+
throw new Error('Overloaded');
|
|
96
|
+
}, { provider: config.provider });
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await expect(fallback.executeWithFallback(mockFn)).rejects.toThrow();
|
|
100
|
+
|
|
101
|
+
// All providers should have been attempted
|
|
102
|
+
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
103
|
+
|
|
104
|
+
const fallbackStats = fallback.getStats();
|
|
105
|
+
expect(fallbackStats.totalAttempts).toBe(2);
|
|
106
|
+
expect(fallbackStats.successfulProvider).toBeNull();
|
|
107
|
+
expect(fallbackStats.failedProviders.length).toBe(2);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('Real-world scenarios', () => {
|
|
112
|
+
test('should handle Azure Claude -> Bedrock fallback scenario', async () => {
|
|
113
|
+
const retry = new RetryManager({
|
|
114
|
+
maxRetries: 3,
|
|
115
|
+
initialDelay: 10,
|
|
116
|
+
debug: false
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const fallback = new FallbackManager({
|
|
120
|
+
strategy: 'custom',
|
|
121
|
+
providers: [
|
|
122
|
+
{
|
|
123
|
+
provider: 'anthropic',
|
|
124
|
+
apiKey: 'azure-key',
|
|
125
|
+
baseURL: 'https://azure-endpoint.com',
|
|
126
|
+
model: 'claude-3-7-sonnet-20250219'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
provider: 'bedrock',
|
|
130
|
+
region: 'us-west-2',
|
|
131
|
+
apiKey: 'bedrock-key',
|
|
132
|
+
model: 'anthropic.claude-sonnet-4-20250514-v1:0'
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
debug: false
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
let azureAttempts = 0;
|
|
139
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
140
|
+
return retry.executeWithRetry(() => {
|
|
141
|
+
// Azure fails with overloaded
|
|
142
|
+
if (config.baseURL?.includes('azure')) {
|
|
143
|
+
azureAttempts++;
|
|
144
|
+
throw new Error('Overloaded');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Bedrock succeeds
|
|
148
|
+
return `success with ${model}`;
|
|
149
|
+
}, { provider: config.provider, model });
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const result = await fallback.executeWithFallback(mockFn);
|
|
153
|
+
|
|
154
|
+
expect(result).toContain('anthropic.claude-sonnet');
|
|
155
|
+
expect(azureAttempts).toBe(4); // 1 initial + 3 retries
|
|
156
|
+
|
|
157
|
+
const stats = fallback.getStats();
|
|
158
|
+
expect(stats.successfulProvider).toContain('bedrock');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('should handle mixed retryable and non-retryable errors', async () => {
|
|
162
|
+
const retry = new RetryManager({
|
|
163
|
+
maxRetries: 2,
|
|
164
|
+
initialDelay: 10,
|
|
165
|
+
debug: false
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const fallback = new FallbackManager({
|
|
169
|
+
strategy: 'custom',
|
|
170
|
+
providers: [
|
|
171
|
+
{ provider: 'anthropic', apiKey: 'key1' },
|
|
172
|
+
{ provider: 'openai', apiKey: 'key2' }
|
|
173
|
+
],
|
|
174
|
+
debug: false
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
178
|
+
return retry.executeWithRetry(() => {
|
|
179
|
+
// First provider: non-retryable error (invalid API key)
|
|
180
|
+
if (config.provider === 'anthropic') {
|
|
181
|
+
throw new Error('Invalid API key');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Second provider: succeeds
|
|
185
|
+
return 'success';
|
|
186
|
+
}, { provider: config.provider });
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const result = await fallback.executeWithFallback(mockFn);
|
|
190
|
+
|
|
191
|
+
expect(result).toBe('success');
|
|
192
|
+
|
|
193
|
+
// Anthropic should only be attempted once (non-retryable)
|
|
194
|
+
// OpenAI should succeed on first attempt
|
|
195
|
+
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('should respect maxTotalAttempts across providers', async () => {
|
|
199
|
+
const retry = new RetryManager({
|
|
200
|
+
maxRetries: 5,
|
|
201
|
+
initialDelay: 5,
|
|
202
|
+
debug: false
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const fallback = new FallbackManager({
|
|
206
|
+
strategy: 'custom',
|
|
207
|
+
providers: [
|
|
208
|
+
{ provider: 'anthropic', apiKey: 'key1' },
|
|
209
|
+
{ provider: 'openai', apiKey: 'key2' },
|
|
210
|
+
{ provider: 'google', apiKey: 'key3' },
|
|
211
|
+
{ provider: 'bedrock', apiKey: 'key4' }
|
|
212
|
+
],
|
|
213
|
+
maxTotalAttempts: 2, // Only allow 2 provider attempts total
|
|
214
|
+
debug: false
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
218
|
+
return retry.executeWithRetry(() => {
|
|
219
|
+
throw new Error('Overloaded');
|
|
220
|
+
}, { provider: config.provider });
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
await expect(fallback.executeWithFallback(mockFn)).rejects.toThrow();
|
|
224
|
+
|
|
225
|
+
// Should only attempt 2 providers
|
|
226
|
+
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe('Statistics and monitoring', () => {
|
|
231
|
+
test('should track detailed statistics across retry and fallback', async () => {
|
|
232
|
+
const retry = new RetryManager({
|
|
233
|
+
maxRetries: 2,
|
|
234
|
+
initialDelay: 5,
|
|
235
|
+
debug: false
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const fallback = new FallbackManager({
|
|
239
|
+
strategy: 'custom',
|
|
240
|
+
providers: [
|
|
241
|
+
{ provider: 'anthropic', apiKey: 'key1' },
|
|
242
|
+
{ provider: 'openai', apiKey: 'key2' }
|
|
243
|
+
],
|
|
244
|
+
debug: false
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
let anthropicAttempts = 0;
|
|
248
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
249
|
+
if (config.provider === 'anthropic') {
|
|
250
|
+
return retry.executeWithRetry(() => {
|
|
251
|
+
anthropicAttempts++;
|
|
252
|
+
throw new Error('Overloaded');
|
|
253
|
+
}, { provider: 'anthropic' });
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return retry.executeWithRetry(() => 'success', { provider: 'openai' });
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
await fallback.executeWithFallback(mockFn);
|
|
260
|
+
|
|
261
|
+
// Check fallback stats
|
|
262
|
+
const fallbackStats = fallback.getStats();
|
|
263
|
+
expect(fallbackStats.totalAttempts).toBe(2);
|
|
264
|
+
expect(fallbackStats.failedProviders.length).toBe(1);
|
|
265
|
+
expect(fallbackStats.successfulProvider).toContain('openai');
|
|
266
|
+
|
|
267
|
+
// Anthropic should have 3 total attempts (1 + 2 retries)
|
|
268
|
+
expect(anthropicAttempts).toBe(3);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe('Edge cases', () => {
|
|
273
|
+
test('should handle empty provider list gracefully', async () => {
|
|
274
|
+
const fallback = new FallbackManager({
|
|
275
|
+
strategy: 'any',
|
|
276
|
+
providers: []
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
await expect(fallback.executeWithFallback(() => {})).rejects.toThrow('No providers configured');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('should handle provider creation failures', async () => {
|
|
283
|
+
const fallback = new FallbackManager({
|
|
284
|
+
strategy: 'custom',
|
|
285
|
+
providers: [
|
|
286
|
+
{ provider: 'anthropic', apiKey: 'test-key-1' },
|
|
287
|
+
{ provider: 'openai', apiKey: 'valid-key' }
|
|
288
|
+
],
|
|
289
|
+
debug: false
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
293
|
+
// First provider throws error during execution
|
|
294
|
+
if (config.provider === 'anthropic') {
|
|
295
|
+
throw new Error('Provider creation failed');
|
|
296
|
+
}
|
|
297
|
+
// Second provider succeeds
|
|
298
|
+
return 'success';
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Should fallback to second provider
|
|
302
|
+
const result = await fallback.executeWithFallback(mockFn);
|
|
303
|
+
expect(result).toBe('success');
|
|
304
|
+
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test('should handle AbortSignal in retry manager', async () => {
|
|
308
|
+
const retry = new RetryManager({
|
|
309
|
+
maxRetries: 10,
|
|
310
|
+
initialDelay: 100,
|
|
311
|
+
debug: false
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const controller = new AbortController();
|
|
315
|
+
|
|
316
|
+
// Abort after first attempt
|
|
317
|
+
setTimeout(() => controller.abort(), 50);
|
|
318
|
+
|
|
319
|
+
const mockFn = jest.fn().mockImplementation(() => {
|
|
320
|
+
throw new Error('Overloaded');
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
await expect(
|
|
324
|
+
retry.executeWithRetry(mockFn, { signal: controller.signal })
|
|
325
|
+
).rejects.toThrow('Operation aborted');
|
|
326
|
+
|
|
327
|
+
// Should not exhaust all retries
|
|
328
|
+
expect(mockFn.mock.calls.length).toBeLessThan(10);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
describe('Performance', () => {
|
|
333
|
+
test('should complete fallback reasonably quickly with fast retries', async () => {
|
|
334
|
+
const retry = new RetryManager({
|
|
335
|
+
maxRetries: 2,
|
|
336
|
+
initialDelay: 1, // 1ms
|
|
337
|
+
maxDelay: 10,
|
|
338
|
+
debug: false
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const fallback = new FallbackManager({
|
|
342
|
+
strategy: 'custom',
|
|
343
|
+
providers: [
|
|
344
|
+
{ provider: 'anthropic', apiKey: 'key1' },
|
|
345
|
+
{ provider: 'openai', apiKey: 'key2' }
|
|
346
|
+
],
|
|
347
|
+
debug: false
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
const mockFn = jest.fn().mockImplementation((provider, model, config) => {
|
|
351
|
+
if (config.provider === 'anthropic') {
|
|
352
|
+
return retry.executeWithRetry(() => {
|
|
353
|
+
throw new Error('Overloaded');
|
|
354
|
+
}, { provider: 'anthropic' });
|
|
355
|
+
}
|
|
356
|
+
return retry.executeWithRetry(() => 'success', { provider: 'openai' });
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const startTime = Date.now();
|
|
360
|
+
await fallback.executeWithFallback(mockFn);
|
|
361
|
+
const duration = Date.now() - startTime;
|
|
362
|
+
|
|
363
|
+
// Should complete in less than 500ms (with some margin for test execution)
|
|
364
|
+
// 3 retries * ~2ms delay = ~6ms for anthropic, then openai succeeds immediately
|
|
365
|
+
expect(duration).toBeLessThan(500);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
});
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for the JSON schema validation loop bug fix
|
|
3
|
+
*
|
|
4
|
+
* This test validates that schema instructions are added to the INITIAL user message,
|
|
5
|
+
* preventing the validation loop that occurred when the AI responded with plain text
|
|
6
|
+
* and then received correction prompts.
|
|
7
|
+
*
|
|
8
|
+
* Bug: https://github.com/probelabs/probe/issues/XXX
|
|
9
|
+
* Fix: Schema instructions prepended to user message before AI sees it
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, test, expect } from '@jest/globals';
|
|
13
|
+
import { generateExampleFromSchema } from '../../src/agent/schemaUtils.js';
|
|
14
|
+
|
|
15
|
+
describe('Schema in Initial Message - Bug Fix Integration Test', () => {
|
|
16
|
+
|
|
17
|
+
describe('generateExampleFromSchema - Used in Initial Message', () => {
|
|
18
|
+
test('should generate valid JSON example for Visor refine schema', () => {
|
|
19
|
+
// This is the exact schema from the bug report that caused the validation loop
|
|
20
|
+
const visorRefineSchema = {
|
|
21
|
+
type: 'object',
|
|
22
|
+
additionalProperties: false,
|
|
23
|
+
properties: {
|
|
24
|
+
refined: {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
description: 'true if the task description is clear and actionable, false if clarification is needed'
|
|
27
|
+
},
|
|
28
|
+
text: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'If refined=true, confirmation message. If refined=false, specific questions to ask.'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
required: ['refined', 'text']
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const example = generateExampleFromSchema(visorRefineSchema);
|
|
37
|
+
|
|
38
|
+
// Should generate a valid example
|
|
39
|
+
expect(example).toBeDefined();
|
|
40
|
+
expect(example).not.toBeNull();
|
|
41
|
+
|
|
42
|
+
// Should have the correct structure
|
|
43
|
+
expect(example).toHaveProperty('refined');
|
|
44
|
+
expect(example).toHaveProperty('text');
|
|
45
|
+
|
|
46
|
+
// Should use correct types
|
|
47
|
+
expect(typeof example.refined).toBe('boolean');
|
|
48
|
+
expect(typeof example.text).toBe('string');
|
|
49
|
+
|
|
50
|
+
// Should be valid JSON when stringified
|
|
51
|
+
const jsonString = JSON.stringify(example);
|
|
52
|
+
expect(() => JSON.parse(jsonString)).not.toThrow();
|
|
53
|
+
|
|
54
|
+
// The example should match what the AI is expected to generate
|
|
55
|
+
expect(example).toEqual({
|
|
56
|
+
refined: false,
|
|
57
|
+
text: 'If refined=true, confirmation message. If refined=false, specific questions to ask.'
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('should create a complete schema instruction message', () => {
|
|
62
|
+
const schema = {
|
|
63
|
+
type: 'object',
|
|
64
|
+
properties: {
|
|
65
|
+
status: { type: 'string', description: 'Operation status' },
|
|
66
|
+
count: { type: 'number' }
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const example = generateExampleFromSchema(schema);
|
|
71
|
+
|
|
72
|
+
// Simulate how the message would be constructed in ProbeAgent
|
|
73
|
+
const userMessage = 'Please analyze this code';
|
|
74
|
+
const schemaInstructions = `\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n${JSON.stringify(schema, null, 2)}\n\nExample:\n<attempt_completion>\n${JSON.stringify(example, null, 2)}\n</attempt_completion>\n\nYour response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.`;
|
|
75
|
+
|
|
76
|
+
const fullMessage = userMessage + schemaInstructions;
|
|
77
|
+
|
|
78
|
+
// Should contain the original message
|
|
79
|
+
expect(fullMessage).toContain('Please analyze this code');
|
|
80
|
+
|
|
81
|
+
// Should contain clear JSON requirement
|
|
82
|
+
expect(fullMessage).toContain('IMPORTANT');
|
|
83
|
+
expect(fullMessage).toContain('you MUST format it as valid JSON');
|
|
84
|
+
|
|
85
|
+
// Should contain the schema
|
|
86
|
+
expect(fullMessage).toContain('"type": "object"');
|
|
87
|
+
expect(fullMessage).toContain('"status"');
|
|
88
|
+
expect(fullMessage).toContain('"count"');
|
|
89
|
+
|
|
90
|
+
// Should contain a concrete example
|
|
91
|
+
expect(fullMessage).toContain('Example:');
|
|
92
|
+
expect(fullMessage).toContain('<attempt_completion>');
|
|
93
|
+
expect(fullMessage).toContain('"status": "Operation status"');
|
|
94
|
+
expect(fullMessage).toContain('"count": 0');
|
|
95
|
+
|
|
96
|
+
// Should contain explicit restrictions
|
|
97
|
+
expect(fullMessage).toContain('ONLY valid JSON');
|
|
98
|
+
expect(fullMessage).toContain('no plain text');
|
|
99
|
+
expect(fullMessage).toContain('no explanations');
|
|
100
|
+
expect(fullMessage).toContain('no markdown');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('should handle schema as JSON string (common in Visor)', () => {
|
|
104
|
+
const schemaString = JSON.stringify({
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
result: { type: 'string' }
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const example = generateExampleFromSchema(schemaString);
|
|
112
|
+
|
|
113
|
+
expect(example).toBeDefined();
|
|
114
|
+
expect(example).toHaveProperty('result');
|
|
115
|
+
expect(typeof example.result).toBe('string');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should gracefully handle invalid schema without crashing', () => {
|
|
119
|
+
const invalidSchema = 'not valid json {';
|
|
120
|
+
|
|
121
|
+
const example = generateExampleFromSchema(invalidSchema);
|
|
122
|
+
|
|
123
|
+
// Should return null for invalid schema
|
|
124
|
+
expect(example).toBeNull();
|
|
125
|
+
|
|
126
|
+
// This ensures the user message construction doesn't crash
|
|
127
|
+
// even if schema parsing fails
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('Bug Prevention - Validation Loop Scenario', () => {
|
|
132
|
+
test('should document the bug scenario that is now prevented', () => {
|
|
133
|
+
// BEFORE THE FIX:
|
|
134
|
+
// 1. User message: "Hi! Just checking"
|
|
135
|
+
// 2. Schema: {refined: boolean, text: string}
|
|
136
|
+
// 3. AI receives ONLY: "Hi! Just checking" (no schema info)
|
|
137
|
+
// 4. AI responds: "Hello! I'm ready to help..." (plain text)
|
|
138
|
+
// 5. System tries to parse as JSON -> FAILS
|
|
139
|
+
// 6. System sends correction: "CRITICAL JSON ERROR..."
|
|
140
|
+
// 7. AI still responds with plain text -> LOOP continues for 3 attempts
|
|
141
|
+
// 8. Total time: 100+ seconds, 30+ API calls
|
|
142
|
+
|
|
143
|
+
// AFTER THE FIX:
|
|
144
|
+
// 1. User message: "Hi! Just checking"
|
|
145
|
+
// 2. Schema: {refined: boolean, text: string}
|
|
146
|
+
const schema = {
|
|
147
|
+
type: 'object',
|
|
148
|
+
properties: {
|
|
149
|
+
refined: { type: 'boolean' },
|
|
150
|
+
text: { type: 'string' }
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// 3. System generates example
|
|
155
|
+
const example = generateExampleFromSchema(schema);
|
|
156
|
+
|
|
157
|
+
// 4. AI receives enriched message with schema instructions
|
|
158
|
+
const userMessage = 'Hi! Just checking';
|
|
159
|
+
const enrichedMessage = userMessage + `\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n${JSON.stringify(schema, null, 2)}\n\nExample:\n<attempt_completion>\n${JSON.stringify(example, null, 2)}\n</attempt_completion>\n\nYour response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.`;
|
|
160
|
+
|
|
161
|
+
// 5. AI now knows to respond with JSON from the start
|
|
162
|
+
// 6. AI responds: <attempt_completion>{"refined": false, "text": "..."}</attempt_completion>
|
|
163
|
+
// 7. System parses JSON -> SUCCESS on first try
|
|
164
|
+
// 8. Total time: 4 seconds, 1 API call
|
|
165
|
+
|
|
166
|
+
// Verify the fix is in place
|
|
167
|
+
expect(enrichedMessage).toContain('you MUST format it as valid JSON');
|
|
168
|
+
expect(enrichedMessage).toContain(JSON.stringify(example, null, 2));
|
|
169
|
+
expect(enrichedMessage).not.toContain('CRITICAL JSON ERROR'); // No correction needed!
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('should prevent the specific Gemini 2.5 Pro issue', () => {
|
|
173
|
+
// The bug was specifically observed with Google Gemini 2.5 Pro
|
|
174
|
+
// which would respond with plain text or <task> XML tags
|
|
175
|
+
|
|
176
|
+
const visorSchema = {
|
|
177
|
+
type: 'object',
|
|
178
|
+
additionalProperties: false,
|
|
179
|
+
properties: {
|
|
180
|
+
refined: { type: 'boolean' },
|
|
181
|
+
text: { type: 'string' }
|
|
182
|
+
},
|
|
183
|
+
required: ['refined', 'text']
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const example = generateExampleFromSchema(visorSchema);
|
|
187
|
+
|
|
188
|
+
// The example should be immediately usable by the AI
|
|
189
|
+
expect(JSON.stringify(example)).toBe(
|
|
190
|
+
'{"refined":false,"text":"your answer here"}'
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// This is what the AI should see upfront, preventing confusion
|
|
194
|
+
const instructions = `IMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:
|
|
195
|
+
|
|
196
|
+
${JSON.stringify(visorSchema, null, 2)}
|
|
197
|
+
|
|
198
|
+
Example:
|
|
199
|
+
<attempt_completion>
|
|
200
|
+
${JSON.stringify(example, null, 2)}
|
|
201
|
+
</attempt_completion>
|
|
202
|
+
|
|
203
|
+
Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.`;
|
|
204
|
+
|
|
205
|
+
// Should be crystal clear to the AI
|
|
206
|
+
expect(instructions).toContain('MUST format it as valid JSON');
|
|
207
|
+
expect(instructions).toContain('Example:');
|
|
208
|
+
expect(instructions).toContain('ONLY valid JSON');
|
|
209
|
+
expect(instructions).toContain('no plain text');
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('Edge Cases', () => {
|
|
214
|
+
test('should handle schema with deeply nested objects', () => {
|
|
215
|
+
const nestedSchema = {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {
|
|
218
|
+
user: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {
|
|
221
|
+
profile: {
|
|
222
|
+
type: 'object',
|
|
223
|
+
properties: {
|
|
224
|
+
name: { type: 'string' }
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const example = generateExampleFromSchema(nestedSchema);
|
|
233
|
+
|
|
234
|
+
// Should handle nesting
|
|
235
|
+
expect(example).toHaveProperty('user');
|
|
236
|
+
expect(typeof example.user).toBe('object');
|
|
237
|
+
|
|
238
|
+
// Inner objects default to empty
|
|
239
|
+
expect(example.user).toEqual({});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test('should handle schema with all primitive types', () => {
|
|
243
|
+
const allTypesSchema = {
|
|
244
|
+
type: 'object',
|
|
245
|
+
properties: {
|
|
246
|
+
str: { type: 'string', description: 'A string' },
|
|
247
|
+
num: { type: 'number' },
|
|
248
|
+
bool: { type: 'boolean' },
|
|
249
|
+
arr: { type: 'array' },
|
|
250
|
+
obj: { type: 'object' }
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const example = generateExampleFromSchema(allTypesSchema);
|
|
255
|
+
|
|
256
|
+
expect(example).toEqual({
|
|
257
|
+
str: 'A string',
|
|
258
|
+
num: 0,
|
|
259
|
+
bool: false,
|
|
260
|
+
arr: [],
|
|
261
|
+
obj: {}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Should be valid JSON
|
|
265
|
+
expect(() => JSON.parse(JSON.stringify(example))).not.toThrow();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test('should use description as example value for strings', () => {
|
|
269
|
+
const schema = {
|
|
270
|
+
type: 'object',
|
|
271
|
+
properties: {
|
|
272
|
+
greeting: { type: 'string', description: 'Hello, World!' },
|
|
273
|
+
noDesc: { type: 'string' }
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const example = generateExampleFromSchema(schema);
|
|
278
|
+
|
|
279
|
+
// Description should be used as the example value
|
|
280
|
+
expect(example.greeting).toBe('Hello, World!');
|
|
281
|
+
|
|
282
|
+
// Without description, default placeholder
|
|
283
|
+
expect(example.noDesc).toBe('your answer here');
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('Performance - Bug Fix Impact', () => {
|
|
288
|
+
test('should prevent wasted iterations (regression test)', () => {
|
|
289
|
+
// Before fix: 30+ iterations (tool loop + 3 correction attempts each)
|
|
290
|
+
// After fix: 1 iteration (AI gets it right on first try)
|
|
291
|
+
|
|
292
|
+
const schema = {
|
|
293
|
+
type: 'object',
|
|
294
|
+
properties: {
|
|
295
|
+
refined: { type: 'boolean' },
|
|
296
|
+
text: { type: 'string' }
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const startTime = Date.now();
|
|
301
|
+
|
|
302
|
+
// Generate example (happens once per request)
|
|
303
|
+
const example = generateExampleFromSchema(schema);
|
|
304
|
+
|
|
305
|
+
const endTime = Date.now();
|
|
306
|
+
const generationTime = endTime - startTime;
|
|
307
|
+
|
|
308
|
+
// Should be very fast (< 10ms)
|
|
309
|
+
expect(generationTime).toBeLessThan(10);
|
|
310
|
+
|
|
311
|
+
// Should produce valid output
|
|
312
|
+
expect(example).toBeDefined();
|
|
313
|
+
expect(() => JSON.parse(JSON.stringify(example))).not.toThrow();
|
|
314
|
+
|
|
315
|
+
// This small cost (< 10ms) saves 100+ seconds of validation loops
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|