@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,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for allow_tests default behavior in Vercel AI SDK tools
|
|
3
|
+
*
|
|
4
|
+
* Issue #323: allow_tests parameter has a documented default of true,
|
|
5
|
+
* but this default was not applied when AI tools omit the parameter.
|
|
6
|
+
*
|
|
7
|
+
* @module tests/allow-tests-default
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { jest, describe, test, expect, beforeEach } from '@jest/globals';
|
|
11
|
+
|
|
12
|
+
describe('allow_tests Default Behavior', () => {
|
|
13
|
+
describe('Zod Schema Defaults', () => {
|
|
14
|
+
test('querySchema should have allow_tests default to true', async () => {
|
|
15
|
+
const { querySchema } = await import('../src/tools/common.js');
|
|
16
|
+
|
|
17
|
+
// Parse an empty object - should get default value
|
|
18
|
+
const result = querySchema.parse({ pattern: 'test' });
|
|
19
|
+
|
|
20
|
+
expect(result.allow_tests).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('extractSchema should have allow_tests default to true', async () => {
|
|
24
|
+
const { extractSchema } = await import('../src/tools/common.js');
|
|
25
|
+
|
|
26
|
+
// Parse with only required field
|
|
27
|
+
const result = extractSchema.parse({ targets: 'file.js' });
|
|
28
|
+
|
|
29
|
+
expect(result.allow_tests).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('querySchema should respect explicit false value', async () => {
|
|
33
|
+
const { querySchema } = await import('../src/tools/common.js');
|
|
34
|
+
|
|
35
|
+
const result = querySchema.parse({ pattern: 'test', allow_tests: false });
|
|
36
|
+
|
|
37
|
+
expect(result.allow_tests).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('extractSchema should respect explicit false value', async () => {
|
|
41
|
+
const { extractSchema } = await import('../src/tools/common.js');
|
|
42
|
+
|
|
43
|
+
const result = extractSchema.parse({ targets: 'file.js', allow_tests: false });
|
|
44
|
+
|
|
45
|
+
expect(result.allow_tests).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('Default Application Logic', () => {
|
|
50
|
+
/**
|
|
51
|
+
* Tests the default application logic that should be used in vercel.js tools.
|
|
52
|
+
* The fix uses nullish coalescing: allowTests: allow_tests ?? true
|
|
53
|
+
* This handles both undefined and null as "not specified"
|
|
54
|
+
*/
|
|
55
|
+
function applyAllowTestsDefault(allow_tests) {
|
|
56
|
+
return allow_tests ?? true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
test('should return true when allow_tests is undefined', () => {
|
|
60
|
+
expect(applyAllowTestsDefault(undefined)).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('should return true when allow_tests is explicitly true', () => {
|
|
64
|
+
expect(applyAllowTestsDefault(true)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('should return false when allow_tests is explicitly false', () => {
|
|
68
|
+
expect(applyAllowTestsDefault(false)).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should return true when allow_tests is null (treated as not specified)', () => {
|
|
72
|
+
// null should be treated the same as undefined - use default value
|
|
73
|
+
expect(applyAllowTestsDefault(null)).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('Vercel Tool Implementation Verification', () => {
|
|
78
|
+
/**
|
|
79
|
+
* Verify that the vercel.js file contains the correct default application pattern.
|
|
80
|
+
* This is a code inspection test to catch regressions.
|
|
81
|
+
*/
|
|
82
|
+
test('searchTool should apply default for allowTests', async () => {
|
|
83
|
+
const fs = await import('fs');
|
|
84
|
+
const path = await import('path');
|
|
85
|
+
const { fileURLToPath } = await import('url');
|
|
86
|
+
const __dirname = path.default.dirname(fileURLToPath(import.meta.url));
|
|
87
|
+
const vercelPath = path.default.resolve(__dirname, '../src/tools/vercel.js');
|
|
88
|
+
const vercelSource = fs.default.readFileSync(vercelPath, 'utf-8');
|
|
89
|
+
|
|
90
|
+
// Check that the searchTool uses the nullish coalescing pattern
|
|
91
|
+
expect(vercelSource).toContain('allowTests: allow_tests ?? true');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('queryTool should apply default for allowTests', async () => {
|
|
95
|
+
const fs = await import('fs');
|
|
96
|
+
const path = await import('path');
|
|
97
|
+
const { fileURLToPath } = await import('url');
|
|
98
|
+
const __dirname = path.default.dirname(fileURLToPath(import.meta.url));
|
|
99
|
+
const vercelPath = path.default.resolve(__dirname, '../src/tools/vercel.js');
|
|
100
|
+
const vercelSource = fs.default.readFileSync(vercelPath, 'utf-8');
|
|
101
|
+
|
|
102
|
+
// The queryTool should have the pattern somewhere in its implementation
|
|
103
|
+
// Count occurrences to ensure all tools have the fix
|
|
104
|
+
const matches = vercelSource.match(/allowTests: allow_tests \?\? true/g);
|
|
105
|
+
// Should have at least 4 occurrences (search, query, extract with targets, extract with input_content)
|
|
106
|
+
expect(matches).not.toBeNull();
|
|
107
|
+
expect(matches.length).toBeGreaterThanOrEqual(4);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('extractTool should apply default for allowTests in both branches', async () => {
|
|
111
|
+
const fs = await import('fs');
|
|
112
|
+
const path = await import('path');
|
|
113
|
+
const { fileURLToPath } = await import('url');
|
|
114
|
+
const __dirname = path.default.dirname(fileURLToPath(import.meta.url));
|
|
115
|
+
const vercelPath = path.default.resolve(__dirname, '../src/tools/vercel.js');
|
|
116
|
+
const vercelSource = fs.default.readFileSync(vercelPath, 'utf-8');
|
|
117
|
+
|
|
118
|
+
// Extract tool has two places where allowTests is set (targets and input_content branches)
|
|
119
|
+
// Both should use the nullish coalescing pattern
|
|
120
|
+
const extractSection = vercelSource.slice(
|
|
121
|
+
vercelSource.indexOf('export const extractTool'),
|
|
122
|
+
vercelSource.indexOf('export const delegateTool')
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const matches = extractSection.match(/allowTests: allow_tests \?\? true/g);
|
|
126
|
+
expect(matches).not.toBeNull();
|
|
127
|
+
expect(matches.length).toBe(2); // One for targets branch, one for input_content branch
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('LangChain Tool Implementation Verification', () => {
|
|
132
|
+
/**
|
|
133
|
+
* Verify that the langchain.js file contains the correct default application pattern.
|
|
134
|
+
* This is a code inspection test to catch regressions.
|
|
135
|
+
*/
|
|
136
|
+
test('LangChain tools should apply default for allowTests', async () => {
|
|
137
|
+
const fs = await import('fs');
|
|
138
|
+
const path = await import('path');
|
|
139
|
+
const { fileURLToPath } = await import('url');
|
|
140
|
+
const __dirname = path.default.dirname(fileURLToPath(import.meta.url));
|
|
141
|
+
const langchainPath = path.default.resolve(__dirname, '../src/tools/langchain.js');
|
|
142
|
+
const langchainSource = fs.default.readFileSync(langchainPath, 'utf-8');
|
|
143
|
+
|
|
144
|
+
// Count occurrences to ensure all tools have the fix
|
|
145
|
+
const matches = langchainSource.match(/allowTests: allow_tests \?\? true/g);
|
|
146
|
+
// Should have 3 occurrences (search, query, extract)
|
|
147
|
+
expect(matches).not.toBeNull();
|
|
148
|
+
expect(matches.length).toBe(3);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Context Compactor
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { jest } from '@jest/globals';
|
|
6
|
+
import {
|
|
7
|
+
isContextLimitError,
|
|
8
|
+
identifyMessageSegments,
|
|
9
|
+
compactMessages,
|
|
10
|
+
calculateCompactionStats,
|
|
11
|
+
handleContextLimitError
|
|
12
|
+
} from '../src/agent/contextCompactor.js';
|
|
13
|
+
|
|
14
|
+
describe('Context Compactor', () => {
|
|
15
|
+
describe('isContextLimitError', () => {
|
|
16
|
+
it('should detect Anthropic context length error', () => {
|
|
17
|
+
const error = new Error('prompt is too long: context_length_exceeded');
|
|
18
|
+
expect(isContextLimitError(error)).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should detect OpenAI context window error', () => {
|
|
22
|
+
const error = new Error('This model\'s maximum context length is 8192 tokens. However, your messages resulted in 10000 tokens.');
|
|
23
|
+
expect(isContextLimitError(error)).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should detect Gemini token limit error', () => {
|
|
27
|
+
const error = new Error('The input token count exceeds the maximum limit of 128000 tokens');
|
|
28
|
+
expect(isContextLimitError(error)).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should detect generic "too long" error', () => {
|
|
32
|
+
const error = new Error('The prompt is too long and exceeds the context window');
|
|
33
|
+
expect(isContextLimitError(error)).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should detect "over limit" variations', () => {
|
|
37
|
+
const error = new Error('Total tokens over the limit');
|
|
38
|
+
expect(isContextLimitError(error)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should detect "maximum tokens" error', () => {
|
|
42
|
+
const error = new Error('Request exceeds maximum tokens allowed');
|
|
43
|
+
expect(isContextLimitError(error)).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should work with string error messages', () => {
|
|
47
|
+
const errorString = 'context window exceeded';
|
|
48
|
+
expect(isContextLimitError(errorString)).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should not match unrelated errors', () => {
|
|
52
|
+
const error = new Error('Network connection failed');
|
|
53
|
+
expect(isContextLimitError(error)).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should not match partial matches without overflow cues', () => {
|
|
57
|
+
const error = new Error('Using context from previous message');
|
|
58
|
+
expect(isContextLimitError(error)).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('identifyMessageSegments', () => {
|
|
63
|
+
it('should identify simple user-assistant-result segment', () => {
|
|
64
|
+
const messages = [
|
|
65
|
+
{ role: 'system', content: 'You are an AI assistant' },
|
|
66
|
+
{ role: 'user', content: 'Search for function definitions' },
|
|
67
|
+
{ role: 'assistant', content: '<thinking>Let me search</thinking>\n<search>function</search>' },
|
|
68
|
+
{ role: 'user', content: '<tool_result>Found 10 results</tool_result>' }
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const segments = identifyMessageSegments(messages);
|
|
72
|
+
expect(segments).toHaveLength(1);
|
|
73
|
+
expect(segments[0]).toEqual({
|
|
74
|
+
userIndex: 1,
|
|
75
|
+
monologueIndices: [2],
|
|
76
|
+
finalIndex: 3
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should identify multiple segments', () => {
|
|
81
|
+
const messages = [
|
|
82
|
+
{ role: 'system', content: 'System' },
|
|
83
|
+
{ role: 'user', content: 'First query' },
|
|
84
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
85
|
+
{ role: 'user', content: '<tool_result>Result 1</tool_result>' },
|
|
86
|
+
{ role: 'user', content: 'Second query' },
|
|
87
|
+
{ role: 'assistant', content: '<extract>file.js</extract>' },
|
|
88
|
+
{ role: 'user', content: '<tool_result>Result 2</tool_result>' }
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const segments = identifyMessageSegments(messages);
|
|
92
|
+
expect(segments).toHaveLength(2);
|
|
93
|
+
|
|
94
|
+
expect(segments[0].userIndex).toBe(1);
|
|
95
|
+
expect(segments[0].finalIndex).toBe(3);
|
|
96
|
+
|
|
97
|
+
expect(segments[1].userIndex).toBe(4);
|
|
98
|
+
expect(segments[1].finalIndex).toBe(6);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should handle segment with multiple monologue messages', () => {
|
|
102
|
+
const messages = [
|
|
103
|
+
{ role: 'user', content: 'Query' },
|
|
104
|
+
{ role: 'assistant', content: '<thinking>First thought</thinking>' },
|
|
105
|
+
{ role: 'assistant', content: '<thinking>Second thought</thinking>' },
|
|
106
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
107
|
+
{ role: 'user', content: '<tool_result>Result</tool_result>' }
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const segments = identifyMessageSegments(messages);
|
|
111
|
+
expect(segments).toHaveLength(1);
|
|
112
|
+
expect(segments[0].monologueIndices).toEqual([1, 2, 3]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should handle attempt_completion as segment end', () => {
|
|
116
|
+
const messages = [
|
|
117
|
+
{ role: 'user', content: 'Query' },
|
|
118
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
119
|
+
{ role: 'user', content: '<tool_result>Found results</tool_result>' },
|
|
120
|
+
{ role: 'assistant', content: '<attempt_completion>Here is the answer</attempt_completion>' }
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const segments = identifyMessageSegments(messages);
|
|
124
|
+
expect(segments).toHaveLength(1);
|
|
125
|
+
|
|
126
|
+
// Segment includes all messages with final being attempt_completion
|
|
127
|
+
expect(segments[0].userIndex).toBe(0);
|
|
128
|
+
expect(segments[0].finalIndex).toBe(2); // tool_result is the final
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should handle incomplete segment (no final answer)', () => {
|
|
132
|
+
const messages = [
|
|
133
|
+
{ role: 'user', content: 'Query' },
|
|
134
|
+
{ role: 'assistant', content: '<thinking>In progress...</thinking>' }
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
const segments = identifyMessageSegments(messages);
|
|
138
|
+
expect(segments).toHaveLength(1);
|
|
139
|
+
expect(segments[0].finalIndex).toBe(null);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should skip system messages', () => {
|
|
143
|
+
const messages = [
|
|
144
|
+
{ role: 'system', content: 'System message 1' },
|
|
145
|
+
{ role: 'user', content: 'Query' },
|
|
146
|
+
{ role: 'system', content: 'System message 2' },
|
|
147
|
+
{ role: 'assistant', content: '<search>test</search>' }
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
const segments = identifyMessageSegments(messages);
|
|
151
|
+
expect(segments).toHaveLength(1);
|
|
152
|
+
expect(segments[0].userIndex).toBe(1); // First user message
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('compactMessages', () => {
|
|
157
|
+
it('should remove intermediate monologues from old segments', () => {
|
|
158
|
+
const messages = [
|
|
159
|
+
{ role: 'system', content: 'System' },
|
|
160
|
+
// Segment 1 (old - should be compacted)
|
|
161
|
+
{ role: 'user', content: 'First query' },
|
|
162
|
+
{ role: 'assistant', content: '<thinking>Thought 1</thinking>' },
|
|
163
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
164
|
+
{ role: 'user', content: '<tool_result>Result 1</tool_result>' },
|
|
165
|
+
// Segment 2 (old - should be compacted)
|
|
166
|
+
{ role: 'user', content: 'Second query' },
|
|
167
|
+
{ role: 'assistant', content: '<thinking>Thought 2</thinking>' },
|
|
168
|
+
{ role: 'assistant', content: '<extract>file.js</extract>' },
|
|
169
|
+
{ role: 'user', content: '<tool_result>Result 2</tool_result>' },
|
|
170
|
+
// Segment 3 (active - should be preserved)
|
|
171
|
+
{ role: 'user', content: 'Third query' },
|
|
172
|
+
{ role: 'assistant', content: '<thinking>Active thought</thinking>' }
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
const compacted = compactMessages(messages, {
|
|
176
|
+
keepLastSegment: true,
|
|
177
|
+
minSegmentsToKeep: 1
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Should be fewer messages than original
|
|
181
|
+
expect(compacted.length).toBeLessThan(messages.length);
|
|
182
|
+
|
|
183
|
+
// Check system message preserved
|
|
184
|
+
expect(compacted[0].role).toBe('system');
|
|
185
|
+
|
|
186
|
+
// Check segment 1 and 2 compacted (only user and final)
|
|
187
|
+
const hasFirstQuery = compacted.some(m => m.content === 'First query');
|
|
188
|
+
const hasResult1 = compacted.some(m => m.content === '<tool_result>Result 1</tool_result>');
|
|
189
|
+
const hasThought1 = compacted.some(m => m.content && m.content.includes('Thought 1'));
|
|
190
|
+
|
|
191
|
+
const hasSecondQuery = compacted.some(m => m.content === 'Second query');
|
|
192
|
+
const hasResult2 = compacted.some(m => m.content === '<tool_result>Result 2</tool_result>');
|
|
193
|
+
const hasThought2 = compacted.some(m => m.content && m.content.includes('Thought 2'));
|
|
194
|
+
|
|
195
|
+
expect(hasFirstQuery).toBe(true);
|
|
196
|
+
expect(hasResult1).toBe(true);
|
|
197
|
+
expect(hasThought1).toBe(false); // Thought 1 should be removed
|
|
198
|
+
|
|
199
|
+
expect(hasSecondQuery).toBe(true);
|
|
200
|
+
expect(hasResult2).toBe(true);
|
|
201
|
+
expect(hasThought2).toBe(false); // Thought 2 should be removed
|
|
202
|
+
|
|
203
|
+
// Check segment 3 is fully preserved (active)
|
|
204
|
+
const hasActiveThought = compacted.some(m => m.content && m.content.includes('Active thought'));
|
|
205
|
+
expect(hasActiveThought).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should keep all system messages', () => {
|
|
209
|
+
const messages = [
|
|
210
|
+
{ role: 'system', content: 'System 1' },
|
|
211
|
+
{ role: 'user', content: 'Query' },
|
|
212
|
+
{ role: 'system', content: 'System 2' },
|
|
213
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
214
|
+
{ role: 'user', content: '<tool_result>Result</tool_result>' }
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
const compacted = compactMessages(messages);
|
|
218
|
+
|
|
219
|
+
const systemMessages = compacted.filter(m => m.role === 'system');
|
|
220
|
+
expect(systemMessages).toHaveLength(2);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should handle empty message array', () => {
|
|
224
|
+
const compacted = compactMessages([]);
|
|
225
|
+
expect(compacted).toEqual([]);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should preserve segments when minSegmentsToKeep is high', () => {
|
|
229
|
+
const messages = [
|
|
230
|
+
{ role: 'user', content: 'Query 1' },
|
|
231
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
232
|
+
{ role: 'user', content: '<tool_result>Result 1</tool_result>' },
|
|
233
|
+
{ role: 'user', content: 'Query 2' },
|
|
234
|
+
{ role: 'assistant', content: '<extract>file</extract>' }
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
const compacted = compactMessages(messages, {
|
|
238
|
+
minSegmentsToKeep: 5
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// All segments should be preserved
|
|
242
|
+
expect(compacted).toEqual(messages);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should respect keepLastSegment option', () => {
|
|
246
|
+
const messages = [
|
|
247
|
+
{ role: 'user', content: 'Query 1' },
|
|
248
|
+
{ role: 'assistant', content: '<thinking>Old thought</thinking>' },
|
|
249
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
250
|
+
{ role: 'user', content: '<tool_result>Result</tool_result>' },
|
|
251
|
+
{ role: 'user', content: 'Query 2' },
|
|
252
|
+
{ role: 'assistant', content: '<thinking>New thought</thinking>' }
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
// With keepLastSegment=false and minSegmentsToKeep=1
|
|
256
|
+
const compacted = compactMessages(messages, {
|
|
257
|
+
keepLastSegment: false,
|
|
258
|
+
minSegmentsToKeep: 1
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Should only preserve the second-to-last segment fully
|
|
262
|
+
// Segment 1 should be compacted
|
|
263
|
+
const hasOldThought = compacted.some(m => m.content.includes('Old thought'));
|
|
264
|
+
const hasNewThought = compacted.some(m => m.content.includes('New thought'));
|
|
265
|
+
|
|
266
|
+
expect(hasOldThought).toBe(false);
|
|
267
|
+
expect(hasNewThought).toBe(true);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should handle segments without final answers', () => {
|
|
271
|
+
const messages = [
|
|
272
|
+
{ role: 'user', content: 'Query 1' },
|
|
273
|
+
{ role: 'assistant', content: '<thinking>Thought 1</thinking>' },
|
|
274
|
+
{ role: 'user', content: '<tool_result>Result</tool_result>' },
|
|
275
|
+
{ role: 'user', content: 'Query 2' },
|
|
276
|
+
{ role: 'assistant', content: '<thinking>Thought 2</thinking>' }
|
|
277
|
+
// No final answer for segment 2
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
const compacted = compactMessages(messages, {
|
|
281
|
+
minSegmentsToKeep: 1
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Should preserve the last incomplete segment
|
|
285
|
+
expect(compacted).toContain(messages[4]);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe('calculateCompactionStats', () => {
|
|
290
|
+
it('should calculate correct statistics', () => {
|
|
291
|
+
const original = [
|
|
292
|
+
{ role: 'user', content: 'A'.repeat(100) },
|
|
293
|
+
{ role: 'assistant', content: 'B'.repeat(200) },
|
|
294
|
+
{ role: 'assistant', content: 'C'.repeat(300) },
|
|
295
|
+
{ role: 'user', content: 'D'.repeat(400) }
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
const compacted = [
|
|
299
|
+
{ role: 'user', content: 'A'.repeat(100) },
|
|
300
|
+
{ role: 'user', content: 'D'.repeat(400) }
|
|
301
|
+
];
|
|
302
|
+
|
|
303
|
+
const stats = calculateCompactionStats(original, compacted);
|
|
304
|
+
|
|
305
|
+
expect(stats.originalCount).toBe(4);
|
|
306
|
+
expect(stats.compactedCount).toBe(2);
|
|
307
|
+
expect(stats.removed).toBe(2);
|
|
308
|
+
expect(stats.reductionPercent).toBe(50.0);
|
|
309
|
+
|
|
310
|
+
// Check token estimation
|
|
311
|
+
expect(stats.originalTokens).toBeGreaterThan(0);
|
|
312
|
+
expect(stats.compactedTokens).toBeLessThan(stats.originalTokens);
|
|
313
|
+
expect(stats.tokensSaved).toBe(stats.originalTokens - stats.compactedTokens);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('should handle empty arrays', () => {
|
|
317
|
+
const stats = calculateCompactionStats([], []);
|
|
318
|
+
|
|
319
|
+
expect(stats.originalCount).toBe(0);
|
|
320
|
+
expect(stats.compactedCount).toBe(0);
|
|
321
|
+
expect(stats.removed).toBe(0);
|
|
322
|
+
expect(stats.reductionPercent).toBe(0);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should handle no reduction', () => {
|
|
326
|
+
const messages = [
|
|
327
|
+
{ role: 'user', content: 'Test' }
|
|
328
|
+
];
|
|
329
|
+
|
|
330
|
+
const stats = calculateCompactionStats(messages, messages);
|
|
331
|
+
|
|
332
|
+
expect(stats.removed).toBe(0);
|
|
333
|
+
expect(stats.reductionPercent).toBe(0);
|
|
334
|
+
expect(stats.tokensSaved).toBe(0);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('should estimate tokens correctly', () => {
|
|
338
|
+
const messages = [
|
|
339
|
+
{ role: 'user', content: 'This is a test message with about 10 words in it' }
|
|
340
|
+
];
|
|
341
|
+
|
|
342
|
+
const stats = calculateCompactionStats(messages, []);
|
|
343
|
+
|
|
344
|
+
// Rough estimate: ~50 chars / 4 = ~12-13 tokens
|
|
345
|
+
expect(stats.originalTokens).toBeGreaterThan(10);
|
|
346
|
+
expect(stats.originalTokens).toBeLessThan(20);
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
describe('handleContextLimitError', () => {
|
|
351
|
+
it('should compact messages on context limit error', () => {
|
|
352
|
+
const error = new Error('context length exceeded');
|
|
353
|
+
const messages = [
|
|
354
|
+
{ role: 'user', content: 'Query 1' },
|
|
355
|
+
{ role: 'assistant', content: '<thinking>Thought 1</thinking>' },
|
|
356
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
357
|
+
{ role: 'user', content: '<tool_result>Result 1</tool_result>' },
|
|
358
|
+
{ role: 'user', content: 'Query 2' },
|
|
359
|
+
{ role: 'assistant', content: '<thinking>Thought 2</thinking>' },
|
|
360
|
+
{ role: 'assistant', content: '<extract>file</extract>' }
|
|
361
|
+
];
|
|
362
|
+
|
|
363
|
+
const result = handleContextLimitError(error, messages);
|
|
364
|
+
|
|
365
|
+
expect(result).not.toBe(null);
|
|
366
|
+
expect(result.compacted).toBe(true);
|
|
367
|
+
expect(result.messages.length).toBeLessThanOrEqual(messages.length);
|
|
368
|
+
expect(result.stats).toBeDefined();
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('should return null for non-context errors', () => {
|
|
372
|
+
const error = new Error('Network timeout');
|
|
373
|
+
const messages = [
|
|
374
|
+
{ role: 'user', content: 'Test' }
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
const result = handleContextLimitError(error, messages);
|
|
378
|
+
|
|
379
|
+
expect(result).toBe(null);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('should pass options to compactMessages', () => {
|
|
383
|
+
const error = new Error('tokens exceed maximum');
|
|
384
|
+
const messages = [
|
|
385
|
+
{ role: 'user', content: 'Query 1' },
|
|
386
|
+
{ role: 'assistant', content: '<search>test</search>' },
|
|
387
|
+
{ role: 'user', content: '<tool_result>Result</tool_result>' },
|
|
388
|
+
{ role: 'user', content: 'Query 2' },
|
|
389
|
+
{ role: 'assistant', content: '<extract>file</extract>' }
|
|
390
|
+
];
|
|
391
|
+
|
|
392
|
+
const result = handleContextLimitError(error, messages, {
|
|
393
|
+
keepLastSegment: true,
|
|
394
|
+
minSegmentsToKeep: 3
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
expect(result).not.toBe(null);
|
|
398
|
+
expect(result.messages).toBeDefined();
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should handle string error messages', () => {
|
|
402
|
+
const errorString = 'Input token count exceeds limit';
|
|
403
|
+
const messages = [
|
|
404
|
+
{ role: 'user', content: 'Test' },
|
|
405
|
+
{ role: 'assistant', content: 'Response' }
|
|
406
|
+
];
|
|
407
|
+
|
|
408
|
+
const result = handleContextLimitError(errorString, messages);
|
|
409
|
+
|
|
410
|
+
expect(result).not.toBe(null);
|
|
411
|
+
expect(result.compacted).toBe(true);
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
describe('Real-world scenario', () => {
|
|
416
|
+
it('should handle complex multi-turn conversation', () => {
|
|
417
|
+
const messages = [
|
|
418
|
+
{ role: 'system', content: 'You are a helpful assistant' },
|
|
419
|
+
|
|
420
|
+
// Turn 1 - Complete
|
|
421
|
+
{ role: 'user', content: 'Search for all function definitions' },
|
|
422
|
+
{ role: 'assistant', content: '<thinking>I need to search</thinking>' },
|
|
423
|
+
{ role: 'assistant', content: '<search>function</search>' },
|
|
424
|
+
{ role: 'user', content: '<tool_result>Found 50 functions</tool_result>' },
|
|
425
|
+
|
|
426
|
+
// Turn 2 - Complete
|
|
427
|
+
{ role: 'user', content: 'Extract the first function' },
|
|
428
|
+
{ role: 'assistant', content: '<thinking>Let me extract</thinking>' },
|
|
429
|
+
{ role: 'assistant', content: '<extract>file.js:10</extract>' },
|
|
430
|
+
{ role: 'user', content: '<tool_result>function code here</tool_result>' },
|
|
431
|
+
|
|
432
|
+
// Turn 3 - Complete
|
|
433
|
+
{ role: 'user', content: 'Modify it to add error handling' },
|
|
434
|
+
{ role: 'assistant', content: '<thinking>I will implement</thinking>' },
|
|
435
|
+
{ role: 'assistant', content: '<implement>...</implement>' },
|
|
436
|
+
{ role: 'user', content: '<tool_result>Success</tool_result>' },
|
|
437
|
+
|
|
438
|
+
// Turn 4 - Active
|
|
439
|
+
{ role: 'user', content: 'Now test it' },
|
|
440
|
+
{ role: 'assistant', content: '<thinking>Running tests</thinking>' },
|
|
441
|
+
{ role: 'assistant', content: '<bash>npm test</bash>' }
|
|
442
|
+
];
|
|
443
|
+
|
|
444
|
+
const compacted = compactMessages(messages, {
|
|
445
|
+
keepLastSegment: true,
|
|
446
|
+
minSegmentsToKeep: 1
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Should keep system + Turn 1 (user+final) + Turn 2 (user+final) + Turn 3 (user+final) + Turn 4 (all)
|
|
450
|
+
expect(compacted.length).toBeLessThan(messages.length);
|
|
451
|
+
|
|
452
|
+
// System message should be preserved
|
|
453
|
+
expect(compacted[0].role).toBe('system');
|
|
454
|
+
|
|
455
|
+
// All user messages should be preserved
|
|
456
|
+
const userMessages = compacted.filter(m => m.role === 'user' && !m.content.includes('tool_result'));
|
|
457
|
+
expect(userMessages.length).toBe(4);
|
|
458
|
+
|
|
459
|
+
// Turns 1-3 should have monologues removed
|
|
460
|
+
const hasThinking1 = compacted.some(m => m.content && m.content.includes('I need to search'));
|
|
461
|
+
const hasThinking2 = compacted.some(m => m.content && m.content.includes('Let me extract'));
|
|
462
|
+
const hasThinking3 = compacted.some(m => m.content && m.content.includes('I will implement'));
|
|
463
|
+
|
|
464
|
+
expect(hasThinking1).toBe(false);
|
|
465
|
+
expect(hasThinking2).toBe(false);
|
|
466
|
+
expect(hasThinking3).toBe(false);
|
|
467
|
+
|
|
468
|
+
// Active segment (Turn 4) should be fully preserved
|
|
469
|
+
const hasThinking4 = compacted.some(m => m.content && m.content.includes('Running tests'));
|
|
470
|
+
const hasBash = compacted.some(m => m.content && m.content.includes('bash'));
|
|
471
|
+
|
|
472
|
+
expect(hasThinking4).toBe(true);
|
|
473
|
+
expect(hasBash).toBe(true);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('should provide meaningful statistics', () => {
|
|
477
|
+
const messages = Array.from({ length: 50 }, (_, i) => ({
|
|
478
|
+
role: i % 2 === 0 ? 'user' : 'assistant',
|
|
479
|
+
content: `Message ${i} with some content that takes up space`
|
|
480
|
+
}));
|
|
481
|
+
|
|
482
|
+
const compacted = compactMessages(messages, {
|
|
483
|
+
keepLastSegment: true,
|
|
484
|
+
minSegmentsToKeep: 5
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
const stats = calculateCompactionStats(messages, compacted);
|
|
488
|
+
|
|
489
|
+
expect(stats.originalCount).toBe(50);
|
|
490
|
+
expect(stats.compactedCount).toBeLessThan(50);
|
|
491
|
+
expect(stats.reductionPercent).toBeGreaterThan(0);
|
|
492
|
+
expect(stats.tokensSaved).toBeGreaterThan(0);
|
|
493
|
+
|
|
494
|
+
// Verify it's actually reducing
|
|
495
|
+
expect(stats.compactedCount).toBeLessThan(stats.originalCount);
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
});
|