@mcp-abap-adt/llm-agent-server 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/bin/llm-agent +2 -0
- package/bin/llm-agent-check +2 -0
- package/dist/agent.d.ts +49 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +97 -0
- package/dist/agent.js.map +1 -0
- package/dist/agents/anthropic-agent.d.ts +33 -0
- package/dist/agents/anthropic-agent.d.ts.map +1 -0
- package/dist/agents/anthropic-agent.js +138 -0
- package/dist/agents/anthropic-agent.js.map +1 -0
- package/dist/agents/base.d.ts +90 -0
- package/dist/agents/base.d.ts.map +1 -0
- package/dist/agents/base.js +107 -0
- package/dist/agents/base.js.map +1 -0
- package/dist/agents/deepseek-agent.d.ts +31 -0
- package/dist/agents/deepseek-agent.d.ts.map +1 -0
- package/dist/agents/deepseek-agent.js +121 -0
- package/dist/agents/deepseek-agent.js.map +1 -0
- package/dist/agents/index.d.ts +10 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +10 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/openai-agent.d.ts +32 -0
- package/dist/agents/openai-agent.d.ts.map +1 -0
- package/dist/agents/openai-agent.js +122 -0
- package/dist/agents/openai-agent.js.map +1 -0
- package/dist/agents/prompt-based-agent.d.ts +29 -0
- package/dist/agents/prompt-based-agent.d.ts.map +1 -0
- package/dist/agents/prompt-based-agent.js +67 -0
- package/dist/agents/prompt-based-agent.js.map +1 -0
- package/dist/agents/sap-core-ai-agent.d.ts +41 -0
- package/dist/agents/sap-core-ai-agent.d.ts.map +1 -0
- package/dist/agents/sap-core-ai-agent.js +151 -0
- package/dist/agents/sap-core-ai-agent.js.map +1 -0
- package/dist/cli.d.ts +53 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +338 -0
- package/dist/cli.js.map +1 -0
- package/dist/generated/version.d.ts +2 -0
- package/dist/generated/version.d.ts.map +1 -0
- package/dist/generated/version.js +3 -0
- package/dist/generated/version.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-providers/anthropic.d.ts +25 -0
- package/dist/llm-providers/anthropic.d.ts.map +1 -0
- package/dist/llm-providers/anthropic.js +202 -0
- package/dist/llm-providers/anthropic.js.map +1 -0
- package/dist/llm-providers/base.d.ts +33 -0
- package/dist/llm-providers/base.d.ts.map +1 -0
- package/dist/llm-providers/base.js +18 -0
- package/dist/llm-providers/base.js.map +1 -0
- package/dist/llm-providers/deepseek.d.ts +24 -0
- package/dist/llm-providers/deepseek.d.ts.map +1 -0
- package/dist/llm-providers/deepseek.js +60 -0
- package/dist/llm-providers/deepseek.js.map +1 -0
- package/dist/llm-providers/index.d.ts +13 -0
- package/dist/llm-providers/index.d.ts.map +1 -0
- package/dist/llm-providers/index.js +15 -0
- package/dist/llm-providers/index.js.map +1 -0
- package/dist/llm-providers/openai.d.ts +34 -0
- package/dist/llm-providers/openai.d.ts.map +1 -0
- package/dist/llm-providers/openai.js +193 -0
- package/dist/llm-providers/openai.js.map +1 -0
- package/dist/llm-providers/sap-core-ai.d.ts +90 -0
- package/dist/llm-providers/sap-core-ai.d.ts.map +1 -0
- package/dist/llm-providers/sap-core-ai.js +394 -0
- package/dist/llm-providers/sap-core-ai.js.map +1 -0
- package/dist/mcp/client.d.ts +133 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +314 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/smart-agent/adapters/cline-client-adapter.d.ts +18 -0
- package/dist/smart-agent/adapters/cline-client-adapter.d.ts.map +1 -0
- package/dist/smart-agent/adapters/cline-client-adapter.js +21 -0
- package/dist/smart-agent/adapters/cline-client-adapter.js.map +1 -0
- package/dist/smart-agent/adapters/index.d.ts +3 -0
- package/dist/smart-agent/adapters/index.d.ts.map +1 -0
- package/dist/smart-agent/adapters/index.js +3 -0
- package/dist/smart-agent/adapters/index.js.map +1 -0
- package/dist/smart-agent/adapters/llm-adapter.d.ts +24 -0
- package/dist/smart-agent/adapters/llm-adapter.d.ts.map +1 -0
- package/dist/smart-agent/adapters/llm-adapter.js +345 -0
- package/dist/smart-agent/adapters/llm-adapter.js.map +1 -0
- package/dist/smart-agent/adapters/mcp-client-adapter.d.ts +16 -0
- package/dist/smart-agent/adapters/mcp-client-adapter.d.ts.map +1 -0
- package/dist/smart-agent/adapters/mcp-client-adapter.js +95 -0
- package/dist/smart-agent/adapters/mcp-client-adapter.js.map +1 -0
- package/dist/smart-agent/adapters/non-streaming-llm.d.ts +18 -0
- package/dist/smart-agent/adapters/non-streaming-llm.d.ts.map +1 -0
- package/dist/smart-agent/adapters/non-streaming-llm.js +44 -0
- package/dist/smart-agent/adapters/non-streaming-llm.js.map +1 -0
- package/dist/smart-agent/agent.d.ts +229 -0
- package/dist/smart-agent/agent.d.ts.map +1 -0
- package/dist/smart-agent/agent.js +1538 -0
- package/dist/smart-agent/agent.js.map +1 -0
- package/dist/smart-agent/api-adapters/anthropic-adapter.d.ts +10 -0
- package/dist/smart-agent/api-adapters/anthropic-adapter.d.ts.map +1 -0
- package/dist/smart-agent/api-adapters/anthropic-adapter.js +356 -0
- package/dist/smart-agent/api-adapters/anthropic-adapter.js.map +1 -0
- package/dist/smart-agent/api-adapters/index.d.ts +3 -0
- package/dist/smart-agent/api-adapters/index.d.ts.map +1 -0
- package/dist/smart-agent/api-adapters/index.js +3 -0
- package/dist/smart-agent/api-adapters/index.js.map +1 -0
- package/dist/smart-agent/api-adapters/openai-adapter.d.ts +10 -0
- package/dist/smart-agent/api-adapters/openai-adapter.d.ts.map +1 -0
- package/dist/smart-agent/api-adapters/openai-adapter.js +277 -0
- package/dist/smart-agent/api-adapters/openai-adapter.js.map +1 -0
- package/dist/smart-agent/builder.d.ts +281 -0
- package/dist/smart-agent/builder.d.ts.map +1 -0
- package/dist/smart-agent/builder.js +942 -0
- package/dist/smart-agent/builder.js.map +1 -0
- package/dist/smart-agent/cache/index.d.ts +4 -0
- package/dist/smart-agent/cache/index.d.ts.map +1 -0
- package/dist/smart-agent/cache/index.js +3 -0
- package/dist/smart-agent/cache/index.js.map +1 -0
- package/dist/smart-agent/cache/noop-tool-cache.d.ts +7 -0
- package/dist/smart-agent/cache/noop-tool-cache.d.ts.map +1 -0
- package/dist/smart-agent/cache/noop-tool-cache.js +8 -0
- package/dist/smart-agent/cache/noop-tool-cache.js.map +1 -0
- package/dist/smart-agent/cache/tool-cache.d.ts +14 -0
- package/dist/smart-agent/cache/tool-cache.d.ts.map +1 -0
- package/dist/smart-agent/cache/tool-cache.js +32 -0
- package/dist/smart-agent/cache/tool-cache.js.map +1 -0
- package/dist/smart-agent/cache/types.d.ts +7 -0
- package/dist/smart-agent/cache/types.d.ts.map +1 -0
- package/dist/smart-agent/cache/types.js +2 -0
- package/dist/smart-agent/cache/types.js.map +1 -0
- package/dist/smart-agent/check-models-cli.d.ts +14 -0
- package/dist/smart-agent/check-models-cli.d.ts.map +1 -0
- package/dist/smart-agent/check-models-cli.js +237 -0
- package/dist/smart-agent/check-models-cli.js.map +1 -0
- package/dist/smart-agent/classifier/index.d.ts +3 -0
- package/dist/smart-agent/classifier/index.d.ts.map +1 -0
- package/dist/smart-agent/classifier/index.js +2 -0
- package/dist/smart-agent/classifier/index.js.map +1 -0
- package/dist/smart-agent/classifier/llm-classifier.d.ts +20 -0
- package/dist/smart-agent/classifier/llm-classifier.d.ts.map +1 -0
- package/dist/smart-agent/classifier/llm-classifier.js +128 -0
- package/dist/smart-agent/classifier/llm-classifier.js.map +1 -0
- package/dist/smart-agent/cli.d.ts +65 -0
- package/dist/smart-agent/cli.d.ts.map +1 -0
- package/dist/smart-agent/cli.js +199 -0
- package/dist/smart-agent/cli.js.map +1 -0
- package/dist/smart-agent/config/config-watcher.d.ts +54 -0
- package/dist/smart-agent/config/config-watcher.d.ts.map +1 -0
- package/dist/smart-agent/config/config-watcher.js +107 -0
- package/dist/smart-agent/config/config-watcher.js.map +1 -0
- package/dist/smart-agent/config/index.d.ts +2 -0
- package/dist/smart-agent/config/index.d.ts.map +1 -0
- package/dist/smart-agent/config/index.js +2 -0
- package/dist/smart-agent/config/index.js.map +1 -0
- package/dist/smart-agent/config.d.ts +35 -0
- package/dist/smart-agent/config.d.ts.map +1 -0
- package/dist/smart-agent/config.js +360 -0
- package/dist/smart-agent/config.js.map +1 -0
- package/dist/smart-agent/context/context-assembler.d.ts +49 -0
- package/dist/smart-agent/context/context-assembler.d.ts.map +1 -0
- package/dist/smart-agent/context/context-assembler.js +184 -0
- package/dist/smart-agent/context/context-assembler.js.map +1 -0
- package/dist/smart-agent/context/index.d.ts +3 -0
- package/dist/smart-agent/context/index.d.ts.map +1 -0
- package/dist/smart-agent/context/index.js +2 -0
- package/dist/smart-agent/context/index.js.map +1 -0
- package/dist/smart-agent/health/health-checker.d.ts +21 -0
- package/dist/smart-agent/health/health-checker.d.ts.map +1 -0
- package/dist/smart-agent/health/health-checker.js +52 -0
- package/dist/smart-agent/health/health-checker.js.map +1 -0
- package/dist/smart-agent/health/index.d.ts +3 -0
- package/dist/smart-agent/health/index.d.ts.map +1 -0
- package/dist/smart-agent/health/index.js +2 -0
- package/dist/smart-agent/health/index.js.map +1 -0
- package/dist/smart-agent/health/types.d.ts +25 -0
- package/dist/smart-agent/health/types.d.ts.map +1 -0
- package/dist/smart-agent/health/types.js +2 -0
- package/dist/smart-agent/health/types.js.map +1 -0
- package/dist/smart-agent/history/history-memory.d.ts +12 -0
- package/dist/smart-agent/history/history-memory.d.ts.map +1 -0
- package/dist/smart-agent/history/history-memory.js +26 -0
- package/dist/smart-agent/history/history-memory.js.map +1 -0
- package/dist/smart-agent/history/history-summarizer.d.ts +10 -0
- package/dist/smart-agent/history/history-summarizer.d.ts.map +1 -0
- package/dist/smart-agent/history/history-summarizer.js +27 -0
- package/dist/smart-agent/history/history-summarizer.js.map +1 -0
- package/dist/smart-agent/history/index.d.ts +3 -0
- package/dist/smart-agent/history/index.d.ts.map +1 -0
- package/dist/smart-agent/history/index.js +3 -0
- package/dist/smart-agent/history/index.js.map +1 -0
- package/dist/smart-agent/interfaces/api-adapter.d.ts +36 -0
- package/dist/smart-agent/interfaces/api-adapter.d.ts.map +1 -0
- package/dist/smart-agent/interfaces/api-adapter.js +9 -0
- package/dist/smart-agent/interfaces/api-adapter.js.map +1 -0
- package/dist/smart-agent/interfaces/client-adapter.d.ts +23 -0
- package/dist/smart-agent/interfaces/client-adapter.d.ts.map +1 -0
- package/dist/smart-agent/interfaces/client-adapter.js +10 -0
- package/dist/smart-agent/interfaces/client-adapter.js.map +1 -0
- package/dist/smart-agent/interfaces/mcp-connection-strategy.d.ts +27 -0
- package/dist/smart-agent/interfaces/mcp-connection-strategy.d.ts.map +1 -0
- package/dist/smart-agent/interfaces/mcp-connection-strategy.js +2 -0
- package/dist/smart-agent/interfaces/mcp-connection-strategy.js.map +1 -0
- package/dist/smart-agent/interfaces/model-resolver.d.ts +9 -0
- package/dist/smart-agent/interfaces/model-resolver.d.ts.map +1 -0
- package/dist/smart-agent/interfaces/model-resolver.js +2 -0
- package/dist/smart-agent/interfaces/model-resolver.js.map +1 -0
- package/dist/smart-agent/interfaces/pipeline.d.ts +125 -0
- package/dist/smart-agent/interfaces/pipeline.d.ts.map +1 -0
- package/dist/smart-agent/interfaces/pipeline.js +13 -0
- package/dist/smart-agent/interfaces/pipeline.js.map +1 -0
- package/dist/smart-agent/logger/console-logger.d.ts +7 -0
- package/dist/smart-agent/logger/console-logger.d.ts.map +1 -0
- package/dist/smart-agent/logger/console-logger.js +12 -0
- package/dist/smart-agent/logger/console-logger.js.map +1 -0
- package/dist/smart-agent/logger/default-request-logger.d.ts +17 -0
- package/dist/smart-agent/logger/default-request-logger.d.ts.map +1 -0
- package/dist/smart-agent/logger/default-request-logger.js +86 -0
- package/dist/smart-agent/logger/default-request-logger.js.map +1 -0
- package/dist/smart-agent/logger/index.d.ts +3 -0
- package/dist/smart-agent/logger/index.d.ts.map +1 -0
- package/dist/smart-agent/logger/index.js +2 -0
- package/dist/smart-agent/logger/index.js.map +1 -0
- package/dist/smart-agent/logger/noop-request-logger.d.ts +11 -0
- package/dist/smart-agent/logger/noop-request-logger.d.ts.map +1 -0
- package/dist/smart-agent/logger/noop-request-logger.js +20 -0
- package/dist/smart-agent/logger/noop-request-logger.js.map +1 -0
- package/dist/smart-agent/logger/session-logger.d.ts +10 -0
- package/dist/smart-agent/logger/session-logger.d.ts.map +1 -0
- package/dist/smart-agent/logger/session-logger.js +40 -0
- package/dist/smart-agent/logger/session-logger.js.map +1 -0
- package/dist/smart-agent/logger/types.d.ts +63 -0
- package/dist/smart-agent/logger/types.d.ts.map +1 -0
- package/dist/smart-agent/logger/types.js +2 -0
- package/dist/smart-agent/logger/types.js.map +1 -0
- package/dist/smart-agent/mcp-client-factory.d.ts +3 -0
- package/dist/smart-agent/mcp-client-factory.d.ts.map +1 -0
- package/dist/smart-agent/mcp-client-factory.js +21 -0
- package/dist/smart-agent/mcp-client-factory.js.map +1 -0
- package/dist/smart-agent/metrics/in-memory-metrics.d.ts +58 -0
- package/dist/smart-agent/metrics/in-memory-metrics.d.ts.map +1 -0
- package/dist/smart-agent/metrics/in-memory-metrics.js +78 -0
- package/dist/smart-agent/metrics/in-memory-metrics.js.map +1 -0
- package/dist/smart-agent/metrics/index.d.ts +4 -0
- package/dist/smart-agent/metrics/index.d.ts.map +1 -0
- package/dist/smart-agent/metrics/index.js +3 -0
- package/dist/smart-agent/metrics/index.js.map +1 -0
- package/dist/smart-agent/metrics/noop-metrics.d.ts +17 -0
- package/dist/smart-agent/metrics/noop-metrics.d.ts.map +1 -0
- package/dist/smart-agent/metrics/noop-metrics.js +22 -0
- package/dist/smart-agent/metrics/noop-metrics.js.map +1 -0
- package/dist/smart-agent/metrics/types.d.ts +36 -0
- package/dist/smart-agent/metrics/types.d.ts.map +1 -0
- package/dist/smart-agent/metrics/types.js +9 -0
- package/dist/smart-agent/metrics/types.js.map +1 -0
- package/dist/smart-agent/otel/index.d.ts +2 -0
- package/dist/smart-agent/otel/index.d.ts.map +1 -0
- package/dist/smart-agent/otel/index.js +2 -0
- package/dist/smart-agent/otel/index.js.map +1 -0
- package/dist/smart-agent/otel/otel-tracer-adapter.d.ts +15 -0
- package/dist/smart-agent/otel/otel-tracer-adapter.d.ts.map +1 -0
- package/dist/smart-agent/otel/otel-tracer-adapter.js +62 -0
- package/dist/smart-agent/otel/otel-tracer-adapter.js.map +1 -0
- package/dist/smart-agent/pipeline/condition-evaluator.d.ts +35 -0
- package/dist/smart-agent/pipeline/condition-evaluator.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/condition-evaluator.js +143 -0
- package/dist/smart-agent/pipeline/condition-evaluator.js.map +1 -0
- package/dist/smart-agent/pipeline/context.d.ts +121 -0
- package/dist/smart-agent/pipeline/context.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/context.js +19 -0
- package/dist/smart-agent/pipeline/context.js.map +1 -0
- package/dist/smart-agent/pipeline/default-pipeline.d.ts +69 -0
- package/dist/smart-agent/pipeline/default-pipeline.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/default-pipeline.js +278 -0
- package/dist/smart-agent/pipeline/default-pipeline.js.map +1 -0
- package/dist/smart-agent/pipeline/executor.d.ts +54 -0
- package/dist/smart-agent/pipeline/executor.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/executor.js +133 -0
- package/dist/smart-agent/pipeline/executor.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/assemble.d.ts +16 -0
- package/dist/smart-agent/pipeline/handlers/assemble.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/assemble.js +72 -0
- package/dist/smart-agent/pipeline/handlers/assemble.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/build-tool-query.d.ts +30 -0
- package/dist/smart-agent/pipeline/handlers/build-tool-query.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/build-tool-query.js +80 -0
- package/dist/smart-agent/pipeline/handlers/build-tool-query.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/classify.d.ts +21 -0
- package/dist/smart-agent/pipeline/handlers/classify.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/classify.js +60 -0
- package/dist/smart-agent/pipeline/handlers/classify.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/expand.d.ts +16 -0
- package/dist/smart-agent/pipeline/handlers/expand.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/expand.js +24 -0
- package/dist/smart-agent/pipeline/handlers/expand.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/history-upsert.d.ts +29 -0
- package/dist/smart-agent/pipeline/handlers/history-upsert.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/history-upsert.js +75 -0
- package/dist/smart-agent/pipeline/handlers/history-upsert.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/index.d.ts +31 -0
- package/dist/smart-agent/pipeline/handlers/index.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/index.js +44 -0
- package/dist/smart-agent/pipeline/handlers/index.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/rag-query.d.ts +27 -0
- package/dist/smart-agent/pipeline/handlers/rag-query.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/rag-query.js +117 -0
- package/dist/smart-agent/pipeline/handlers/rag-query.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/rerank.d.ts +16 -0
- package/dist/smart-agent/pipeline/handlers/rerank.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/rerank.js +27 -0
- package/dist/smart-agent/pipeline/handlers/rerank.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/skill-select.d.ts +18 -0
- package/dist/smart-agent/pipeline/handlers/skill-select.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/skill-select.js +88 -0
- package/dist/smart-agent/pipeline/handlers/skill-select.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/summarize.d.ts +17 -0
- package/dist/smart-agent/pipeline/handlers/summarize.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/summarize.js +56 -0
- package/dist/smart-agent/pipeline/handlers/summarize.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/tool-loop.d.ts +32 -0
- package/dist/smart-agent/pipeline/handlers/tool-loop.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/tool-loop.js +734 -0
- package/dist/smart-agent/pipeline/handlers/tool-loop.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/tool-select.d.ts +21 -0
- package/dist/smart-agent/pipeline/handlers/tool-select.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/tool-select.js +109 -0
- package/dist/smart-agent/pipeline/handlers/tool-select.js.map +1 -0
- package/dist/smart-agent/pipeline/handlers/translate.d.ts +17 -0
- package/dist/smart-agent/pipeline/handlers/translate.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/handlers/translate.js +42 -0
- package/dist/smart-agent/pipeline/handlers/translate.js.map +1 -0
- package/dist/smart-agent/pipeline/index.d.ts +14 -0
- package/dist/smart-agent/pipeline/index.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/index.js +16 -0
- package/dist/smart-agent/pipeline/index.js.map +1 -0
- package/dist/smart-agent/pipeline/stage-handler.d.ts +36 -0
- package/dist/smart-agent/pipeline/stage-handler.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/stage-handler.js +24 -0
- package/dist/smart-agent/pipeline/stage-handler.js.map +1 -0
- package/dist/smart-agent/pipeline/types.d.ts +116 -0
- package/dist/smart-agent/pipeline/types.d.ts.map +1 -0
- package/dist/smart-agent/pipeline/types.js +54 -0
- package/dist/smart-agent/pipeline/types.js.map +1 -0
- package/dist/smart-agent/pipeline.d.ts +82 -0
- package/dist/smart-agent/pipeline.d.ts.map +1 -0
- package/dist/smart-agent/pipeline.js +8 -0
- package/dist/smart-agent/pipeline.js.map +1 -0
- package/dist/smart-agent/plugins/index.d.ts +4 -0
- package/dist/smart-agent/plugins/index.d.ts.map +1 -0
- package/dist/smart-agent/plugins/index.js +3 -0
- package/dist/smart-agent/plugins/index.js.map +1 -0
- package/dist/smart-agent/plugins/loader.d.ts +67 -0
- package/dist/smart-agent/plugins/loader.d.ts.map +1 -0
- package/dist/smart-agent/plugins/loader.js +114 -0
- package/dist/smart-agent/plugins/loader.js.map +1 -0
- package/dist/smart-agent/plugins/types.d.ts +164 -0
- package/dist/smart-agent/plugins/types.d.ts.map +1 -0
- package/dist/smart-agent/plugins/types.js +136 -0
- package/dist/smart-agent/plugins/types.js.map +1 -0
- package/dist/smart-agent/policy/fallback-llm-call-strategy.d.ts +16 -0
- package/dist/smart-agent/policy/fallback-llm-call-strategy.d.ts.map +1 -0
- package/dist/smart-agent/policy/fallback-llm-call-strategy.js +66 -0
- package/dist/smart-agent/policy/fallback-llm-call-strategy.js.map +1 -0
- package/dist/smart-agent/policy/heuristic-injection-detector.d.ts +5 -0
- package/dist/smart-agent/policy/heuristic-injection-detector.d.ts.map +1 -0
- package/dist/smart-agent/policy/heuristic-injection-detector.js +36 -0
- package/dist/smart-agent/policy/heuristic-injection-detector.js.map +1 -0
- package/dist/smart-agent/policy/index.d.ts +6 -0
- package/dist/smart-agent/policy/index.d.ts.map +1 -0
- package/dist/smart-agent/policy/index.js +5 -0
- package/dist/smart-agent/policy/index.js.map +1 -0
- package/dist/smart-agent/policy/mixed-tool-call-handler.d.ts +16 -0
- package/dist/smart-agent/policy/mixed-tool-call-handler.d.ts.map +1 -0
- package/dist/smart-agent/policy/mixed-tool-call-handler.js +49 -0
- package/dist/smart-agent/policy/mixed-tool-call-handler.js.map +1 -0
- package/dist/smart-agent/policy/non-streaming-llm-call-strategy.d.ts +6 -0
- package/dist/smart-agent/policy/non-streaming-llm-call-strategy.d.ts.map +1 -0
- package/dist/smart-agent/policy/non-streaming-llm-call-strategy.js +21 -0
- package/dist/smart-agent/policy/non-streaming-llm-call-strategy.js.map +1 -0
- package/dist/smart-agent/policy/pending-tool-results-registry.d.ts +25 -0
- package/dist/smart-agent/policy/pending-tool-results-registry.d.ts.map +1 -0
- package/dist/smart-agent/policy/pending-tool-results-registry.js +50 -0
- package/dist/smart-agent/policy/pending-tool-results-registry.js.map +1 -0
- package/dist/smart-agent/policy/streaming-llm-call-strategy.d.ts +6 -0
- package/dist/smart-agent/policy/streaming-llm-call-strategy.d.ts.map +1 -0
- package/dist/smart-agent/policy/streaming-llm-call-strategy.js +7 -0
- package/dist/smart-agent/policy/streaming-llm-call-strategy.js.map +1 -0
- package/dist/smart-agent/policy/tool-availability-registry.d.ts +21 -0
- package/dist/smart-agent/policy/tool-availability-registry.d.ts.map +1 -0
- package/dist/smart-agent/policy/tool-availability-registry.js +77 -0
- package/dist/smart-agent/policy/tool-availability-registry.js.map +1 -0
- package/dist/smart-agent/policy/tool-policy-guard.d.ts +8 -0
- package/dist/smart-agent/policy/tool-policy-guard.d.ts.map +1 -0
- package/dist/smart-agent/policy/tool-policy-guard.js +40 -0
- package/dist/smart-agent/policy/tool-policy-guard.js.map +1 -0
- package/dist/smart-agent/policy/types.d.ts +51 -0
- package/dist/smart-agent/policy/types.d.ts.map +1 -0
- package/dist/smart-agent/policy/types.js +17 -0
- package/dist/smart-agent/policy/types.js.map +1 -0
- package/dist/smart-agent/providers.d.ts +98 -0
- package/dist/smart-agent/providers.d.ts.map +1 -0
- package/dist/smart-agent/providers.js +245 -0
- package/dist/smart-agent/providers.js.map +1 -0
- package/dist/smart-agent/reranker/index.d.ts +4 -0
- package/dist/smart-agent/reranker/index.d.ts.map +1 -0
- package/dist/smart-agent/reranker/index.js +3 -0
- package/dist/smart-agent/reranker/index.js.map +1 -0
- package/dist/smart-agent/reranker/llm-reranker.d.ts +10 -0
- package/dist/smart-agent/reranker/llm-reranker.d.ts.map +1 -0
- package/dist/smart-agent/reranker/llm-reranker.js +55 -0
- package/dist/smart-agent/reranker/llm-reranker.js.map +1 -0
- package/dist/smart-agent/reranker/noop-reranker.d.ts +6 -0
- package/dist/smart-agent/reranker/noop-reranker.d.ts.map +1 -0
- package/dist/smart-agent/reranker/noop-reranker.js +6 -0
- package/dist/smart-agent/reranker/noop-reranker.js.map +1 -0
- package/dist/smart-agent/reranker/types.d.ts +5 -0
- package/dist/smart-agent/reranker/types.d.ts.map +1 -0
- package/dist/smart-agent/reranker/types.js +2 -0
- package/dist/smart-agent/reranker/types.js.map +1 -0
- package/dist/smart-agent/resilience/circuit-breaker-embedder.d.ts +16 -0
- package/dist/smart-agent/resilience/circuit-breaker-embedder.d.ts.map +1 -0
- package/dist/smart-agent/resilience/circuit-breaker-embedder.js +47 -0
- package/dist/smart-agent/resilience/circuit-breaker-embedder.js.map +1 -0
- package/dist/smart-agent/resilience/circuit-breaker-llm.d.ts +19 -0
- package/dist/smart-agent/resilience/circuit-breaker-llm.d.ts.map +1 -0
- package/dist/smart-agent/resilience/circuit-breaker-llm.js +72 -0
- package/dist/smart-agent/resilience/circuit-breaker-llm.js.map +1 -0
- package/dist/smart-agent/resilience/circuit-breaker.d.ts +36 -0
- package/dist/smart-agent/resilience/circuit-breaker.d.ts.map +1 -0
- package/dist/smart-agent/resilience/circuit-breaker.js +60 -0
- package/dist/smart-agent/resilience/circuit-breaker.js.map +1 -0
- package/dist/smart-agent/resilience/fallback-rag.d.ts +21 -0
- package/dist/smart-agent/resilience/fallback-rag.d.ts.map +1 -0
- package/dist/smart-agent/resilience/fallback-rag.js +80 -0
- package/dist/smart-agent/resilience/fallback-rag.js.map +1 -0
- package/dist/smart-agent/resilience/index.d.ts +5 -0
- package/dist/smart-agent/resilience/index.d.ts.map +1 -0
- package/dist/smart-agent/resilience/index.js +5 -0
- package/dist/smart-agent/resilience/index.js.map +1 -0
- package/dist/smart-agent/resilience/rate-limiter-llm.d.ts +17 -0
- package/dist/smart-agent/resilience/rate-limiter-llm.d.ts.map +1 -0
- package/dist/smart-agent/resilience/rate-limiter-llm.js +30 -0
- package/dist/smart-agent/resilience/rate-limiter-llm.js.map +1 -0
- package/dist/smart-agent/resilience/retry-llm.d.ts +32 -0
- package/dist/smart-agent/resilience/retry-llm.d.ts.map +1 -0
- package/dist/smart-agent/resilience/retry-llm.js +103 -0
- package/dist/smart-agent/resilience/retry-llm.js.map +1 -0
- package/dist/smart-agent/resilience/token-bucket-rate-limiter.d.ts +21 -0
- package/dist/smart-agent/resilience/token-bucket-rate-limiter.d.ts.map +1 -0
- package/dist/smart-agent/resilience/token-bucket-rate-limiter.js +32 -0
- package/dist/smart-agent/resilience/token-bucket-rate-limiter.js.map +1 -0
- package/dist/smart-agent/server.d.ts +19 -0
- package/dist/smart-agent/server.d.ts.map +1 -0
- package/dist/smart-agent/server.js +349 -0
- package/dist/smart-agent/server.js.map +1 -0
- package/dist/smart-agent/session/index.d.ts +4 -0
- package/dist/smart-agent/session/index.d.ts.map +1 -0
- package/dist/smart-agent/session/index.js +3 -0
- package/dist/smart-agent/session/index.js.map +1 -0
- package/dist/smart-agent/session/noop-session-manager.d.ts +8 -0
- package/dist/smart-agent/session/noop-session-manager.d.ts.map +1 -0
- package/dist/smart-agent/session/noop-session-manager.js +11 -0
- package/dist/smart-agent/session/noop-session-manager.js.map +1 -0
- package/dist/smart-agent/session/session-manager.d.ts +13 -0
- package/dist/smart-agent/session/session-manager.d.ts.map +1 -0
- package/dist/smart-agent/session/session-manager.js +20 -0
- package/dist/smart-agent/session/session-manager.js.map +1 -0
- package/dist/smart-agent/session/types.d.ts +7 -0
- package/dist/smart-agent/session/types.d.ts.map +1 -0
- package/dist/smart-agent/session/types.js +2 -0
- package/dist/smart-agent/session/types.js.map +1 -0
- package/dist/smart-agent/skills/claude-skill-manager.d.ts +24 -0
- package/dist/smart-agent/skills/claude-skill-manager.d.ts.map +1 -0
- package/dist/smart-agent/skills/claude-skill-manager.js +81 -0
- package/dist/smart-agent/skills/claude-skill-manager.js.map +1 -0
- package/dist/smart-agent/skills/codex-skill-manager.d.ts +20 -0
- package/dist/smart-agent/skills/codex-skill-manager.d.ts.map +1 -0
- package/dist/smart-agent/skills/codex-skill-manager.js +75 -0
- package/dist/smart-agent/skills/codex-skill-manager.js.map +1 -0
- package/dist/smart-agent/skills/filesystem-skill-manager.d.ts +17 -0
- package/dist/smart-agent/skills/filesystem-skill-manager.d.ts.map +1 -0
- package/dist/smart-agent/skills/filesystem-skill-manager.js +48 -0
- package/dist/smart-agent/skills/filesystem-skill-manager.js.map +1 -0
- package/dist/smart-agent/skills/filesystem-skill.d.ts +25 -0
- package/dist/smart-agent/skills/filesystem-skill.d.ts.map +1 -0
- package/dist/smart-agent/skills/filesystem-skill.js +110 -0
- package/dist/smart-agent/skills/filesystem-skill.js.map +1 -0
- package/dist/smart-agent/skills/index.d.ts +9 -0
- package/dist/smart-agent/skills/index.d.ts.map +1 -0
- package/dist/smart-agent/skills/index.js +9 -0
- package/dist/smart-agent/skills/index.js.map +1 -0
- package/dist/smart-agent/skills/skill-utils.d.ts +15 -0
- package/dist/smart-agent/skills/skill-utils.d.ts.map +1 -0
- package/dist/smart-agent/skills/skill-utils.js +46 -0
- package/dist/smart-agent/skills/skill-utils.js.map +1 -0
- package/dist/smart-agent/smart-server.d.ts +150 -0
- package/dist/smart-agent/smart-server.d.ts.map +1 -0
- package/dist/smart-agent/smart-server.js +903 -0
- package/dist/smart-agent/smart-server.js.map +1 -0
- package/dist/smart-agent/strategies/index.d.ts +4 -0
- package/dist/smart-agent/strategies/index.d.ts.map +1 -0
- package/dist/smart-agent/strategies/index.js +4 -0
- package/dist/smart-agent/strategies/index.js.map +1 -0
- package/dist/smart-agent/strategies/lazy-connection-strategy.d.ts +15 -0
- package/dist/smart-agent/strategies/lazy-connection-strategy.d.ts.map +1 -0
- package/dist/smart-agent/strategies/lazy-connection-strategy.js +82 -0
- package/dist/smart-agent/strategies/lazy-connection-strategy.js.map +1 -0
- package/dist/smart-agent/strategies/noop-connection-strategy.d.ts +6 -0
- package/dist/smart-agent/strategies/noop-connection-strategy.d.ts.map +1 -0
- package/dist/smart-agent/strategies/noop-connection-strategy.js +6 -0
- package/dist/smart-agent/strategies/noop-connection-strategy.js.map +1 -0
- package/dist/smart-agent/strategies/periodic-connection-strategy.d.ts +13 -0
- package/dist/smart-agent/strategies/periodic-connection-strategy.d.ts.map +1 -0
- package/dist/smart-agent/strategies/periodic-connection-strategy.js +40 -0
- package/dist/smart-agent/strategies/periodic-connection-strategy.js.map +1 -0
- package/dist/smart-agent/testing/index.d.ts +121 -0
- package/dist/smart-agent/testing/index.d.ts.map +1 -0
- package/dist/smart-agent/testing/index.js +354 -0
- package/dist/smart-agent/testing/index.js.map +1 -0
- package/dist/smart-agent/tracer/index.d.ts +3 -0
- package/dist/smart-agent/tracer/index.d.ts.map +1 -0
- package/dist/smart-agent/tracer/index.js +2 -0
- package/dist/smart-agent/tracer/index.js.map +1 -0
- package/dist/smart-agent/tracer/noop-tracer.d.ts +5 -0
- package/dist/smart-agent/tracer/noop-tracer.d.ts.map +1 -0
- package/dist/smart-agent/tracer/noop-tracer.js +16 -0
- package/dist/smart-agent/tracer/noop-tracer.js.map +1 -0
- package/dist/smart-agent/tracer/types.d.ts +17 -0
- package/dist/smart-agent/tracer/types.d.ts.map +1 -0
- package/dist/smart-agent/tracer/types.js +2 -0
- package/dist/smart-agent/tracer/types.js.map +1 -0
- package/dist/smart-agent/utils/external-tools-normalizer.d.ts +15 -0
- package/dist/smart-agent/utils/external-tools-normalizer.d.ts.map +1 -0
- package/dist/smart-agent/utils/external-tools-normalizer.js +146 -0
- package/dist/smart-agent/utils/external-tools-normalizer.js.map +1 -0
- package/dist/smart-agent/utils/lazy.d.ts +51 -0
- package/dist/smart-agent/utils/lazy.d.ts.map +1 -0
- package/dist/smart-agent/utils/lazy.js +127 -0
- package/dist/smart-agent/utils/lazy.js.map +1 -0
- package/dist/smart-agent/utils/parse-frontmatter.d.ts +15 -0
- package/dist/smart-agent/utils/parse-frontmatter.d.ts.map +1 -0
- package/dist/smart-agent/utils/parse-frontmatter.js +22 -0
- package/dist/smart-agent/utils/parse-frontmatter.js.map +1 -0
- package/dist/smart-agent/utils/tool-call-deltas.d.ts +4 -0
- package/dist/smart-agent/utils/tool-call-deltas.d.ts.map +1 -0
- package/dist/smart-agent/utils/tool-call-deltas.js +25 -0
- package/dist/smart-agent/utils/tool-call-deltas.js.map +1 -0
- package/dist/smart-agent/validator/index.d.ts +3 -0
- package/dist/smart-agent/validator/index.d.ts.map +1 -0
- package/dist/smart-agent/validator/index.js +2 -0
- package/dist/smart-agent/validator/index.js.map +1 -0
- package/dist/smart-agent/validator/noop-validator.d.ts +6 -0
- package/dist/smart-agent/validator/noop-validator.d.ts.map +1 -0
- package/dist/smart-agent/validator/noop-validator.js +6 -0
- package/dist/smart-agent/validator/noop-validator.js.map +1 -0
- package/dist/smart-agent/validator/types.d.ts +17 -0
- package/dist/smart-agent/validator/types.d.ts.map +1 -0
- package/dist/smart-agent/validator/types.js +8 -0
- package/dist/smart-agent/validator/types.js.map +1 -0
- package/dist/smoke-adapters.d.ts +17 -0
- package/dist/smoke-adapters.d.ts.map +1 -0
- package/dist/smoke-adapters.js +178 -0
- package/dist/smoke-adapters.js.map +1 -0
- package/package.json +89 -0
- package/tools/claude-via-agent.ps1 +83 -0
- package/tools/claude-via-agent.sh +96 -0
|
@@ -0,0 +1,1538 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { NoopToolCache } from './cache/noop-tool-cache.js';
|
|
3
|
+
import { LlmClassifier } from './classifier/llm-classifier.js';
|
|
4
|
+
import { StreamingLlmCallStrategy } from './policy/streaming-llm-call-strategy.js';
|
|
5
|
+
export { OrchestratorError, } from '@mcp-abap-adt/llm-agent';
|
|
6
|
+
import { NoopQueryExpander, OrchestratorError, QueryEmbedding, TextOnlyEmbedding, } from '@mcp-abap-adt/llm-agent';
|
|
7
|
+
import { NoopRequestLogger } from './logger/noop-request-logger.js';
|
|
8
|
+
import { NoopMetrics } from './metrics/noop-metrics.js';
|
|
9
|
+
import { fireInternalToolsAsync } from './policy/mixed-tool-call-handler.js';
|
|
10
|
+
import { PendingToolResultsRegistry } from './policy/pending-tool-results-registry.js';
|
|
11
|
+
import { isToolContextUnavailableError, ToolAvailabilityRegistry, } from './policy/tool-availability-registry.js';
|
|
12
|
+
import { NoopReranker } from './reranker/noop-reranker.js';
|
|
13
|
+
import { NoopSessionManager } from './session/noop-session-manager.js';
|
|
14
|
+
import { NoopTracer } from './tracer/noop-tracer.js';
|
|
15
|
+
import { normalizeExternalTools } from './utils/external-tools-normalizer.js';
|
|
16
|
+
import { getStreamToolCallName, toToolCallDelta, } from './utils/tool-call-deltas.js';
|
|
17
|
+
import { NoopValidator } from './validator/noop-validator.js';
|
|
18
|
+
function mergeSignals(...signals) {
|
|
19
|
+
const ctrl = new AbortController();
|
|
20
|
+
for (const s of signals) {
|
|
21
|
+
if (!s)
|
|
22
|
+
continue;
|
|
23
|
+
if (s.aborted) {
|
|
24
|
+
ctrl.abort(s.reason);
|
|
25
|
+
return ctrl;
|
|
26
|
+
}
|
|
27
|
+
s.addEventListener('abort', () => ctrl.abort(s.reason), { once: true });
|
|
28
|
+
}
|
|
29
|
+
return ctrl;
|
|
30
|
+
}
|
|
31
|
+
function createTimeoutSignal(ms) {
|
|
32
|
+
const ctrl = new AbortController();
|
|
33
|
+
const id = setTimeout(() => ctrl.abort(new Error('Timeout')), ms);
|
|
34
|
+
return { signal: ctrl.signal, clear: () => clearTimeout(id) };
|
|
35
|
+
}
|
|
36
|
+
export class SmartAgent {
|
|
37
|
+
deps;
|
|
38
|
+
config;
|
|
39
|
+
toolAvailabilityRegistry;
|
|
40
|
+
tracer;
|
|
41
|
+
metrics;
|
|
42
|
+
reranker;
|
|
43
|
+
queryExpander;
|
|
44
|
+
toolCache;
|
|
45
|
+
outputValidator;
|
|
46
|
+
sessionManager;
|
|
47
|
+
pendingToolResults;
|
|
48
|
+
requestLogger;
|
|
49
|
+
defaultLlmCallStrategy;
|
|
50
|
+
_activeClients;
|
|
51
|
+
_mainLlm;
|
|
52
|
+
_classifierLlm;
|
|
53
|
+
_helperLlm;
|
|
54
|
+
_classifier;
|
|
55
|
+
constructor(deps, config) {
|
|
56
|
+
this.deps = deps;
|
|
57
|
+
this.config = config;
|
|
58
|
+
this.toolAvailabilityRegistry = new ToolAvailabilityRegistry(this.config.toolUnavailableTtlMs);
|
|
59
|
+
this.tracer = deps.tracer ?? new NoopTracer();
|
|
60
|
+
this.metrics = deps.metrics ?? new NoopMetrics();
|
|
61
|
+
this.reranker = deps.reranker ?? new NoopReranker();
|
|
62
|
+
this.queryExpander = deps.queryExpander ?? new NoopQueryExpander();
|
|
63
|
+
this.toolCache = deps.toolCache ?? new NoopToolCache();
|
|
64
|
+
this.outputValidator = deps.outputValidator ?? new NoopValidator();
|
|
65
|
+
this.sessionManager = deps.sessionManager ?? new NoopSessionManager();
|
|
66
|
+
this.pendingToolResults = new PendingToolResultsRegistry();
|
|
67
|
+
this.requestLogger = deps.requestLogger ?? new NoopRequestLogger();
|
|
68
|
+
this.defaultLlmCallStrategy =
|
|
69
|
+
deps.llmCallStrategy ?? new StreamingLlmCallStrategy();
|
|
70
|
+
this._activeClients = [...deps.mcpClients];
|
|
71
|
+
this._mainLlm = deps.mainLlm;
|
|
72
|
+
this._helperLlm = deps.helperLlm;
|
|
73
|
+
this._classifier = deps.classifier;
|
|
74
|
+
this._classifierLlm = deps.classifierLlm;
|
|
75
|
+
}
|
|
76
|
+
/** Current main LLM instance. Use this for direct LLM calls that should respect hot-swap. */
|
|
77
|
+
get currentMainLlm() {
|
|
78
|
+
return this._mainLlm;
|
|
79
|
+
}
|
|
80
|
+
async _resolveActiveClients(opts) {
|
|
81
|
+
if (!this.deps.connectionStrategy)
|
|
82
|
+
return;
|
|
83
|
+
const result = await this.deps.connectionStrategy.resolve(this._activeClients, opts);
|
|
84
|
+
this._activeClients = result.clients;
|
|
85
|
+
if (result.toolsChanged) {
|
|
86
|
+
await this._revectorizeTools(result.clients, opts);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async _revectorizeTools(clients, opts) {
|
|
90
|
+
const toolsRag = this.deps.ragStores.tools ?? Object.values(this.deps.ragStores)[0];
|
|
91
|
+
if (!toolsRag)
|
|
92
|
+
return;
|
|
93
|
+
for (const client of clients) {
|
|
94
|
+
const result = await client.listTools(opts);
|
|
95
|
+
if (!result.ok)
|
|
96
|
+
continue;
|
|
97
|
+
for (const tool of result.value) {
|
|
98
|
+
const text = `Tool: ${tool.name} — ${tool.description}`;
|
|
99
|
+
await toolsRag.writer?.()?.upsertRaw(`tool:${tool.name}`, text, {});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Apply a partial config update at runtime (hot-reload). */
|
|
104
|
+
applyConfigUpdate(update) {
|
|
105
|
+
this.config = { ...this.config, ...update };
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Replace active LLM instances at runtime.
|
|
109
|
+
* Changes apply to new requests only — in-flight requests continue
|
|
110
|
+
* using the dependency snapshot captured at request start.
|
|
111
|
+
* Reconfigured LLMs do not inherit builder-time wrappers (retry, circuit breaker, rate limiter).
|
|
112
|
+
*
|
|
113
|
+
* **Important:** This is the only supported way to hot-swap LLMs.
|
|
114
|
+
* Direct mutation of `deps` fields has no effect — SmartAgent copies
|
|
115
|
+
* deps into private fields at construction time.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const newLlm = makeLlm({ provider: 'openai', model: 'gpt-5.4-pro', ... });
|
|
120
|
+
* handle.agent.reconfigure({ mainLlm: newLlm });
|
|
121
|
+
* // handle.chat() and handle.streamChat() now use the new LLM
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
reconfigure(update) {
|
|
125
|
+
if (update.mainLlm) {
|
|
126
|
+
this._mainLlm = update.mainLlm;
|
|
127
|
+
}
|
|
128
|
+
if (update.helperLlm) {
|
|
129
|
+
this._helperLlm = update.helperLlm;
|
|
130
|
+
}
|
|
131
|
+
if (update.classifierLlm) {
|
|
132
|
+
this._classifierLlm = update.classifierLlm;
|
|
133
|
+
this._classifier = new LlmClassifier(update.classifierLlm, this.deps.classifierConfig, this.requestLogger);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Add a custom RAG store at runtime. Takes effect on the next request.
|
|
138
|
+
* Built-in store names ('tools', 'history') cannot be overwritten.
|
|
139
|
+
*
|
|
140
|
+
* @param options.translateQuery — when true, the pipeline translates the
|
|
141
|
+
* query to English before searching this store (useful for stores with
|
|
142
|
+
* English-only content like MCP tool descriptions).
|
|
143
|
+
*/
|
|
144
|
+
addRagStore(name, store, options) {
|
|
145
|
+
if (name === 'tools' || name === 'history') {
|
|
146
|
+
throw new Error(`Cannot overwrite built-in RAG store "${name}" via addRagStore()`);
|
|
147
|
+
}
|
|
148
|
+
if (this.deps.ragRegistry) {
|
|
149
|
+
// Route through registry so the ragStores projection (and any listeners)
|
|
150
|
+
// see the change.
|
|
151
|
+
if (this.deps.ragRegistry.get(name)) {
|
|
152
|
+
this.deps.ragRegistry.unregister(name);
|
|
153
|
+
}
|
|
154
|
+
this.deps.ragRegistry.register(name, store, undefined, {
|
|
155
|
+
displayName: name,
|
|
156
|
+
scope: 'global',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Fallback for consumers that built SmartAgentDeps without a registry.
|
|
161
|
+
this.deps.ragStores[name] = store;
|
|
162
|
+
}
|
|
163
|
+
if (options?.translateQuery) {
|
|
164
|
+
if (!this.deps.translateQueryStores) {
|
|
165
|
+
this.deps.translateQueryStores = new Set();
|
|
166
|
+
}
|
|
167
|
+
this.deps.translateQueryStores.add(name);
|
|
168
|
+
}
|
|
169
|
+
this.deps.pipeline?.rebuildStages?.();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Remove a custom RAG store at runtime. Takes effect on the next request.
|
|
173
|
+
* Built-in store names ('tools', 'history') cannot be removed.
|
|
174
|
+
*/
|
|
175
|
+
removeRagStore(name) {
|
|
176
|
+
if (name === 'tools' || name === 'history') {
|
|
177
|
+
throw new Error(`Cannot remove built-in RAG store "${name}" via removeRagStore()`);
|
|
178
|
+
}
|
|
179
|
+
if (this.deps.ragRegistry) {
|
|
180
|
+
this.deps.ragRegistry.unregister(name);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
delete this.deps.ragStores[name];
|
|
184
|
+
}
|
|
185
|
+
this.deps.translateQueryStores?.delete(name);
|
|
186
|
+
this.deps.pipeline?.rebuildStages?.();
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Close a session: remove session-scoped RAG collections for the given
|
|
190
|
+
* sessionId and flush session-scoped history memory.
|
|
191
|
+
* Errors from registry cleanup are logged but not thrown — best-effort.
|
|
192
|
+
*/
|
|
193
|
+
async closeSession(sessionId) {
|
|
194
|
+
if (this.deps.ragRegistry) {
|
|
195
|
+
const res = await this.deps.ragRegistry.closeSession(sessionId);
|
|
196
|
+
if (!res.ok) {
|
|
197
|
+
this.deps.logger?.log({
|
|
198
|
+
type: 'warning',
|
|
199
|
+
traceId: 'close_session',
|
|
200
|
+
message: `closeSession(${sessionId}) failed: ${res.error.message}`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
this.deps.historyMemory?.clear(sessionId);
|
|
205
|
+
}
|
|
206
|
+
/** Returns the model identifiers of the currently active LLM instances. */
|
|
207
|
+
getActiveConfig() {
|
|
208
|
+
return {
|
|
209
|
+
mainModel: this._mainLlm.model,
|
|
210
|
+
classifierModel: this._classifierLlm?.model,
|
|
211
|
+
helperModel: this._helperLlm?.model,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/** Returns whitelisted runtime-safe agent config fields (for HTTP DTO). */
|
|
215
|
+
getAgentConfig() {
|
|
216
|
+
return {
|
|
217
|
+
maxIterations: this.config.maxIterations,
|
|
218
|
+
maxToolCalls: this.config.maxToolCalls,
|
|
219
|
+
ragQueryK: this.config.ragQueryK,
|
|
220
|
+
toolUnavailableTtlMs: this.config.toolUnavailableTtlMs,
|
|
221
|
+
showReasoning: this.config.showReasoning,
|
|
222
|
+
historyAutoSummarizeLimit: this.config.historyAutoSummarizeLimit,
|
|
223
|
+
classificationEnabled: this.config.classificationEnabled,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
async healthCheck(options) {
|
|
227
|
+
const HEALTH_TIMEOUT_MS = this.config.healthTimeoutMs ?? 5_000;
|
|
228
|
+
const { signal: timeoutSignal, clear: clearTimeout_ } = createTimeoutSignal(HEALTH_TIMEOUT_MS);
|
|
229
|
+
const merged = mergeSignals(timeoutSignal, options?.signal);
|
|
230
|
+
const healthOptions = {
|
|
231
|
+
...options,
|
|
232
|
+
signal: merged.signal,
|
|
233
|
+
maxTokens: 1,
|
|
234
|
+
};
|
|
235
|
+
const results = {
|
|
236
|
+
llm: false,
|
|
237
|
+
rag: false,
|
|
238
|
+
mcp: [],
|
|
239
|
+
};
|
|
240
|
+
try {
|
|
241
|
+
if (this._mainLlm.healthCheck) {
|
|
242
|
+
const hc = await this._mainLlm.healthCheck(healthOptions);
|
|
243
|
+
results.llm = hc.ok && hc.value;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
// Fallback for ILlm implementations without healthCheck
|
|
247
|
+
const llmRes = await this._mainLlm.chat([{ role: 'user', content: 'ping' }], [], healthOptions);
|
|
248
|
+
results.llm = llmRes.ok;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
results.llm = false;
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const firstStore = Object.values(this.deps.ragStores)[0];
|
|
256
|
+
const ragRes = firstStore
|
|
257
|
+
? await firstStore.healthCheck(healthOptions)
|
|
258
|
+
: { ok: true, value: undefined };
|
|
259
|
+
results.rag = ragRes.ok;
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
results.rag = false;
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
const mcpChecks = await Promise.all(this._activeClients.map(async (client) => {
|
|
266
|
+
try {
|
|
267
|
+
if (client.healthCheck) {
|
|
268
|
+
const hc = await client.healthCheck(healthOptions);
|
|
269
|
+
return {
|
|
270
|
+
name: 'mcp-client',
|
|
271
|
+
ok: hc.ok,
|
|
272
|
+
error: hc.ok || !hc.error
|
|
273
|
+
? undefined
|
|
274
|
+
: hc.error instanceof Error
|
|
275
|
+
? hc.error.message
|
|
276
|
+
: String(hc.error),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// Fallback for IMcpClient implementations without healthCheck
|
|
280
|
+
const tools = await client.listTools(healthOptions);
|
|
281
|
+
return {
|
|
282
|
+
name: 'mcp-client',
|
|
283
|
+
ok: tools.ok,
|
|
284
|
+
error: tools.ok || !tools.error
|
|
285
|
+
? undefined
|
|
286
|
+
: tools.error instanceof Error
|
|
287
|
+
? tools.error.message
|
|
288
|
+
: String(tools.error),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
return {
|
|
293
|
+
name: 'mcp-client',
|
|
294
|
+
ok: false,
|
|
295
|
+
error: err instanceof Error ? err.message : String(err),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}));
|
|
299
|
+
results.mcp = mcpChecks;
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
// AbortSignal timeout — leave mcp as empty
|
|
303
|
+
}
|
|
304
|
+
clearTimeout_();
|
|
305
|
+
return { ok: true, value: results };
|
|
306
|
+
}
|
|
307
|
+
async process(textOrMessages, options) {
|
|
308
|
+
let content = '';
|
|
309
|
+
const totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
310
|
+
let stopReason = 'stop';
|
|
311
|
+
const collectedToolCalls = [];
|
|
312
|
+
// Map streaming index → position in collectedToolCalls for delta correlation
|
|
313
|
+
const indexToPosition = new Map();
|
|
314
|
+
for await (const chunk of this.streamProcess(textOrMessages, options)) {
|
|
315
|
+
if (!chunk.ok)
|
|
316
|
+
return chunk;
|
|
317
|
+
if (chunk.value.content)
|
|
318
|
+
content += chunk.value.content;
|
|
319
|
+
if (chunk.value.toolCalls) {
|
|
320
|
+
for (const tc of chunk.value.toolCalls) {
|
|
321
|
+
const delta = toToolCallDelta(tc, collectedToolCalls.length);
|
|
322
|
+
// Try to find existing entry by index first (streaming deltas),
|
|
323
|
+
// then by id (non-streaming / first delta with id).
|
|
324
|
+
const posByIndex = indexToPosition.get(delta.index);
|
|
325
|
+
const existing = posByIndex !== undefined
|
|
326
|
+
? collectedToolCalls[posByIndex]
|
|
327
|
+
: delta.id
|
|
328
|
+
? collectedToolCalls.find((c) => c.id === delta.id)
|
|
329
|
+
: undefined;
|
|
330
|
+
if (existing) {
|
|
331
|
+
if (delta.arguments)
|
|
332
|
+
existing.function.arguments += delta.arguments;
|
|
333
|
+
}
|
|
334
|
+
else if (delta.name) {
|
|
335
|
+
const pos = collectedToolCalls.length;
|
|
336
|
+
collectedToolCalls.push({
|
|
337
|
+
id: delta.id || '',
|
|
338
|
+
type: 'function',
|
|
339
|
+
function: {
|
|
340
|
+
name: delta.name,
|
|
341
|
+
arguments: delta.arguments || '',
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
indexToPosition.set(delta.index, pos);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (chunk.value.finishReason === 'tool_calls') {
|
|
349
|
+
stopReason = 'tool_calls';
|
|
350
|
+
}
|
|
351
|
+
if (chunk.value.usage) {
|
|
352
|
+
totalUsage.promptTokens += chunk.value.usage.promptTokens;
|
|
353
|
+
totalUsage.completionTokens += chunk.value.usage.completionTokens;
|
|
354
|
+
totalUsage.totalTokens += chunk.value.usage.totalTokens;
|
|
355
|
+
if (chunk.value.usage.models) {
|
|
356
|
+
totalUsage.models = chunk.value.usage.models;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
ok: true,
|
|
362
|
+
value: {
|
|
363
|
+
content,
|
|
364
|
+
iterations: 1,
|
|
365
|
+
toolCallCount: collectedToolCalls.length,
|
|
366
|
+
stopReason,
|
|
367
|
+
...(collectedToolCalls.length > 0
|
|
368
|
+
? { toolCalls: collectedToolCalls }
|
|
369
|
+
: {}),
|
|
370
|
+
usage: totalUsage,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
async *streamProcess(textOrMessages, options) {
|
|
375
|
+
if (this.config.smartAgentEnabled === false) {
|
|
376
|
+
yield {
|
|
377
|
+
ok: false,
|
|
378
|
+
error: new OrchestratorError('SmartAgent is disabled', 'DISABLED'),
|
|
379
|
+
};
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
this.metrics.requestCount.add();
|
|
383
|
+
const requestStart = Date.now();
|
|
384
|
+
const traceId = options?.trace?.traceId ?? randomUUID();
|
|
385
|
+
const rootSpan = this.tracer.startSpan('smart_agent.process', {
|
|
386
|
+
traceId,
|
|
387
|
+
attributes: { 'smart_agent.mode': this.config.mode || 'smart' },
|
|
388
|
+
});
|
|
389
|
+
let timeoutCleanup;
|
|
390
|
+
let opts = options;
|
|
391
|
+
if (this.config.timeoutMs) {
|
|
392
|
+
const { signal, clear } = createTimeoutSignal(this.config.timeoutMs);
|
|
393
|
+
timeoutCleanup = clear;
|
|
394
|
+
const merged = mergeSignals(options?.signal, signal);
|
|
395
|
+
opts = { ...options, signal: merged.signal };
|
|
396
|
+
}
|
|
397
|
+
const mode = this.config.mode || 'smart';
|
|
398
|
+
// Per-request client adapter detection from system prompt
|
|
399
|
+
let detectedAdapter;
|
|
400
|
+
const messages = typeof textOrMessages === 'string' ? undefined : textOrMessages;
|
|
401
|
+
if (messages && this.deps.clientAdapters?.length) {
|
|
402
|
+
const systemMsg = messages.find((m) => m.role === 'system');
|
|
403
|
+
if (systemMsg?.content) {
|
|
404
|
+
detectedAdapter = this.deps.clientAdapters.find((a) => a.detect(typeof systemMsg.content === 'string' ? systemMsg.content : ''));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
const sessionId = options?.sessionId ?? 'default';
|
|
408
|
+
const externalTools = normalizeExternalTools(options?.externalTools);
|
|
409
|
+
opts?.sessionLogger?.logStep('external_tools_normalized', {
|
|
410
|
+
rawCount: options?.externalTools?.length ?? 0,
|
|
411
|
+
normalizedCount: externalTools.length,
|
|
412
|
+
normalizedNames: externalTools.map((t) => t.name),
|
|
413
|
+
});
|
|
414
|
+
opts?.sessionLogger?.logStep('pipeline_start', { mode, textOrMessages });
|
|
415
|
+
this.requestLogger.startRequest();
|
|
416
|
+
try {
|
|
417
|
+
if (mode === 'pass') {
|
|
418
|
+
const messages = typeof textOrMessages === 'string'
|
|
419
|
+
? [{ role: 'user', content: textOrMessages }]
|
|
420
|
+
: textOrMessages;
|
|
421
|
+
opts?.sessionLogger?.logStep('client_request', { textOrMessages });
|
|
422
|
+
const stream = this._mainLlm.streamChat(messages, externalTools, opts);
|
|
423
|
+
let passContent = '';
|
|
424
|
+
const passToolCalls = [];
|
|
425
|
+
for await (const chunk of stream) {
|
|
426
|
+
if (chunk.ok) {
|
|
427
|
+
if (chunk.value.reset) {
|
|
428
|
+
passContent = '';
|
|
429
|
+
passToolCalls.length = 0;
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
if (chunk.value.content)
|
|
433
|
+
passContent += chunk.value.content;
|
|
434
|
+
if (chunk.value.toolCalls)
|
|
435
|
+
passToolCalls.push(...chunk.value.toolCalls);
|
|
436
|
+
}
|
|
437
|
+
yield chunk;
|
|
438
|
+
}
|
|
439
|
+
opts?.sessionLogger?.logStep('llm_response_pass', {
|
|
440
|
+
content: passContent,
|
|
441
|
+
toolCalls: passToolCalls.length > 0 ? passToolCalls : undefined,
|
|
442
|
+
});
|
|
443
|
+
rootSpan.setStatus('ok');
|
|
444
|
+
rootSpan.end();
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
// Pipeline path (when configured via Builder)
|
|
448
|
+
if (this.deps.pipeline) {
|
|
449
|
+
const stream = this._runStructuredPipeline(textOrMessages, externalTools, opts, rootSpan, sessionId);
|
|
450
|
+
for await (const chunk of stream)
|
|
451
|
+
yield chunk;
|
|
452
|
+
rootSpan.setStatus('ok');
|
|
453
|
+
rootSpan.end();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
// 1. Unified Preparation (default hardcoded flow)
|
|
457
|
+
const initResult = await this._preparePipeline(textOrMessages, opts, rootSpan);
|
|
458
|
+
if (!initResult.ok) {
|
|
459
|
+
rootSpan.setStatus('error', initResult.error.message);
|
|
460
|
+
rootSpan.end();
|
|
461
|
+
yield initResult;
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
let { processedHistory } = initResult.value;
|
|
465
|
+
const { subprompts, toolClientMap } = initResult.value;
|
|
466
|
+
// Token budget check — summarize if over budget
|
|
467
|
+
if (this.sessionManager.isOverBudget()) {
|
|
468
|
+
const sumResult = await this._summarizeHistory(processedHistory, opts);
|
|
469
|
+
if (sumResult.ok)
|
|
470
|
+
processedHistory = sumResult.value;
|
|
471
|
+
this.sessionManager.reset();
|
|
472
|
+
}
|
|
473
|
+
// 2. Decide context and tools for the WHOLE request
|
|
474
|
+
await this._resolveActiveClients(opts);
|
|
475
|
+
const actions = subprompts.filter((sp) => sp.type === 'action');
|
|
476
|
+
const hasActions = actions.length > 0;
|
|
477
|
+
const hasMcpClients = this._activeClients.length > 0;
|
|
478
|
+
const hasRagStores = Object.keys(this.deps.ragStores).length > 0;
|
|
479
|
+
const shouldRetrieve = mode === 'hard' || (hasActions && (hasMcpClients || hasRagStores));
|
|
480
|
+
let finalTools = [];
|
|
481
|
+
let retrieved = {
|
|
482
|
+
ragResults: {},
|
|
483
|
+
tools: [],
|
|
484
|
+
};
|
|
485
|
+
let skillContent = '';
|
|
486
|
+
if (shouldRetrieve) {
|
|
487
|
+
// Collect all action texts for RAG
|
|
488
|
+
const combinedActionText = actions.map((a) => a.text).join(' ');
|
|
489
|
+
// Translate + expand once (only used for stores in translateQueryStores)
|
|
490
|
+
const translateStores = this.deps.translateQueryStores;
|
|
491
|
+
let translatedText;
|
|
492
|
+
if (translateStores && translateStores.size > 0) {
|
|
493
|
+
translatedText = await this._toEnglishForRag(combinedActionText, opts);
|
|
494
|
+
if (this.config.queryExpansionEnabled) {
|
|
495
|
+
const expandResult = await this.queryExpander.expand(translatedText, opts);
|
|
496
|
+
if (expandResult.ok)
|
|
497
|
+
translatedText = expandResult.value;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
const k = this.config.ragQueryK ?? 10;
|
|
501
|
+
const ragSpan = this.tracer.startSpan('smart_agent.rag_query', {
|
|
502
|
+
parent: rootSpan,
|
|
503
|
+
attributes: { 'rag.k': k },
|
|
504
|
+
});
|
|
505
|
+
const storeEntries = Object.entries(this.deps.ragStores);
|
|
506
|
+
// Build per-store embedding: translated for translateQuery stores, original for others
|
|
507
|
+
const mkEmbed = (text) => this.deps.embedder
|
|
508
|
+
? new QueryEmbedding(text, this.deps.embedder, opts)
|
|
509
|
+
: new TextOnlyEmbedding(text);
|
|
510
|
+
// Cache embeddings to avoid duplicate embed calls
|
|
511
|
+
const originalEmbedding = mkEmbed(combinedActionText);
|
|
512
|
+
const translatedEmbedding = translatedText && translatedText !== combinedActionText
|
|
513
|
+
? mkEmbed(translatedText)
|
|
514
|
+
: originalEmbedding;
|
|
515
|
+
const ragQueryResults = await Promise.all(storeEntries.map(([name, store]) => {
|
|
516
|
+
const emb = translateStores?.has(name) && translatedText
|
|
517
|
+
? translatedEmbedding
|
|
518
|
+
: originalEmbedding;
|
|
519
|
+
return store.query(emb, k, opts).then((r) => ({ name, result: r }));
|
|
520
|
+
}));
|
|
521
|
+
ragSpan.end();
|
|
522
|
+
const ragResultsMap = {};
|
|
523
|
+
for (const { name, result: r } of ragQueryResults) {
|
|
524
|
+
ragResultsMap[name] = r.ok ? r.value : [];
|
|
525
|
+
this.metrics.ragQueryCount.add(1, {
|
|
526
|
+
store: name,
|
|
527
|
+
hit: String(r.ok && r.value.length > 0),
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
// Rerank results
|
|
531
|
+
// Rerank all stores in parallel, using matching query text per store
|
|
532
|
+
const rerankedEntries = await Promise.all(Object.entries(ragResultsMap).map(async ([name, results]) => {
|
|
533
|
+
if (results.length > 0) {
|
|
534
|
+
const rerankText = translateStores?.has(name) && translatedText
|
|
535
|
+
? translatedText
|
|
536
|
+
: combinedActionText;
|
|
537
|
+
const rr = await this.reranker.rerank(rerankText, results, opts);
|
|
538
|
+
return { name, results: rr.ok ? rr.value : results };
|
|
539
|
+
}
|
|
540
|
+
return { name, results };
|
|
541
|
+
}));
|
|
542
|
+
const rerankedMap = {};
|
|
543
|
+
for (const { name, results } of rerankedEntries) {
|
|
544
|
+
rerankedMap[name] = results;
|
|
545
|
+
}
|
|
546
|
+
const { tools: mcpTools } = await this._listAllTools(opts);
|
|
547
|
+
// Collect all RAG results for tool discovery
|
|
548
|
+
const allRagResults = Object.values(rerankedMap).flat();
|
|
549
|
+
// Log RAG results with scores for diagnostics
|
|
550
|
+
for (const [storeName, results] of Object.entries(rerankedMap)) {
|
|
551
|
+
const logQuery = translateStores?.has(storeName) && translatedText
|
|
552
|
+
? translatedText
|
|
553
|
+
: combinedActionText;
|
|
554
|
+
opts?.sessionLogger?.logStep(`rag_query_${storeName}`, {
|
|
555
|
+
query: logQuery.slice(0, 200),
|
|
556
|
+
k,
|
|
557
|
+
resultCount: results.length,
|
|
558
|
+
results: results.map((r) => ({
|
|
559
|
+
id: r.metadata.id,
|
|
560
|
+
score: r.score,
|
|
561
|
+
text: r.text.slice(0, 120),
|
|
562
|
+
})),
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
const ragToolNames = new Set(allRagResults
|
|
566
|
+
.map((r) => r.metadata.id)
|
|
567
|
+
.filter((id) => id?.startsWith('tool:'))
|
|
568
|
+
.map((id) => id.slice(5).replace(/:.*$/, '')));
|
|
569
|
+
const selectedMcpTools = ragToolNames.size > 0
|
|
570
|
+
? mcpTools.filter((t) => ragToolNames.has(t.name))
|
|
571
|
+
: mode === 'hard'
|
|
572
|
+
? mcpTools
|
|
573
|
+
: [];
|
|
574
|
+
// Log tool selection diagnostics
|
|
575
|
+
opts?.sessionLogger?.logStep('tools_selected', {
|
|
576
|
+
totalMcp: mcpTools.length,
|
|
577
|
+
ragMatchedTools: [...ragToolNames],
|
|
578
|
+
selectedCount: selectedMcpTools.length + externalTools.length,
|
|
579
|
+
selectedNames: [
|
|
580
|
+
...selectedMcpTools.map((t) => t.name),
|
|
581
|
+
...externalTools.map((t) => t.name),
|
|
582
|
+
],
|
|
583
|
+
});
|
|
584
|
+
retrieved = {
|
|
585
|
+
ragResults: rerankedMap,
|
|
586
|
+
tools: selectedMcpTools,
|
|
587
|
+
};
|
|
588
|
+
finalTools =
|
|
589
|
+
mode === 'hard'
|
|
590
|
+
? selectedMcpTools
|
|
591
|
+
: [...selectedMcpTools, ...externalTools];
|
|
592
|
+
opts?.sessionLogger?.logStep('external_tools_merge', {
|
|
593
|
+
mode,
|
|
594
|
+
mcpCount: selectedMcpTools.length,
|
|
595
|
+
externalCount: externalTools.length,
|
|
596
|
+
externalNames: externalTools.map((t) => t.name),
|
|
597
|
+
finalCount: finalTools.length,
|
|
598
|
+
});
|
|
599
|
+
// Skill injection (when enabled and skillManager configured)
|
|
600
|
+
if (this.config.skillInjectionEnabled !== false &&
|
|
601
|
+
this.deps.skillManager) {
|
|
602
|
+
const ragSkillNames = new Set(allRagResults
|
|
603
|
+
.map((r) => r.metadata.id)
|
|
604
|
+
.filter((id) => id?.startsWith('skill:'))
|
|
605
|
+
.map((id) => id.slice(6)));
|
|
606
|
+
// Fallback: dedicated RAG query when no skill:* in existing results
|
|
607
|
+
if (ragSkillNames.size === 0) {
|
|
608
|
+
const k = this.config.ragQueryK ?? 15;
|
|
609
|
+
const storeEntries = Object.entries(this.deps.ragStores);
|
|
610
|
+
const fallbackResults = await Promise.all(storeEntries.map(([name, store]) => {
|
|
611
|
+
const text = translateStores?.has(name) && translatedText
|
|
612
|
+
? translatedText
|
|
613
|
+
: combinedActionText;
|
|
614
|
+
const emb = this.deps.embedder
|
|
615
|
+
? new QueryEmbedding(text, this.deps.embedder, opts)
|
|
616
|
+
: new TextOnlyEmbedding(text);
|
|
617
|
+
return store.query(emb, k, opts);
|
|
618
|
+
}));
|
|
619
|
+
for (const result of fallbackResults) {
|
|
620
|
+
if (result.ok) {
|
|
621
|
+
for (const r of result.value) {
|
|
622
|
+
const id = r.metadata.id;
|
|
623
|
+
if (id?.startsWith('skill:')) {
|
|
624
|
+
ragSkillNames.add(id.slice(6));
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
if (ragSkillNames.size > 0) {
|
|
630
|
+
opts?.sessionLogger?.logStep('skill_select_rag_fallback', {
|
|
631
|
+
query: combinedActionText.slice(0, 200),
|
|
632
|
+
k,
|
|
633
|
+
matchedSkills: [...ragSkillNames],
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
const allSkillsResult = await this.deps.skillManager.listSkills(opts);
|
|
638
|
+
if (allSkillsResult.ok) {
|
|
639
|
+
const allSkills = allSkillsResult.value;
|
|
640
|
+
const matched = ragSkillNames.size > 0
|
|
641
|
+
? allSkills.filter((s) => ragSkillNames.has(s.name))
|
|
642
|
+
: mode === 'hard'
|
|
643
|
+
? allSkills
|
|
644
|
+
: [];
|
|
645
|
+
const contentParts = [];
|
|
646
|
+
for (const skill of matched) {
|
|
647
|
+
const contentResult = await skill.getContent(undefined, opts);
|
|
648
|
+
if (contentResult.ok && contentResult.value) {
|
|
649
|
+
contentParts.push(`### Skill: ${skill.name}\n${contentResult.value}`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
skillContent = contentParts.join('\n\n');
|
|
653
|
+
opts?.sessionLogger?.logStep('skills_selected', {
|
|
654
|
+
totalSkills: allSkills.length,
|
|
655
|
+
ragMatchedSkills: [...ragSkillNames],
|
|
656
|
+
selectedCount: matched.length,
|
|
657
|
+
selectedNames: matched.map((s) => s.name),
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
// If we're here, mode is definitely 'smart' (not 'hard' or 'pass')
|
|
664
|
+
finalTools = externalTools;
|
|
665
|
+
}
|
|
666
|
+
const filteredTools = this.toolAvailabilityRegistry.filterTools(sessionId, finalTools);
|
|
667
|
+
finalTools = filteredTools.allowed;
|
|
668
|
+
if (filteredTools.blocked.length > 0) {
|
|
669
|
+
opts?.sessionLogger?.logStep('active_tools_filtered_by_registry', {
|
|
670
|
+
blocked: filteredTools.blocked,
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
// 3. Assemble Context once
|
|
674
|
+
const mainAction = actions.length > 1
|
|
675
|
+
? {
|
|
676
|
+
type: 'action',
|
|
677
|
+
text: actions.map((a) => a.text).join('\n'),
|
|
678
|
+
context: actions.find((a) => a.context)?.context,
|
|
679
|
+
dependency: 'independent',
|
|
680
|
+
}
|
|
681
|
+
: actions.length === 1
|
|
682
|
+
? actions[0]
|
|
683
|
+
: subprompts.find((sp) => sp.type === 'chat') || subprompts[0];
|
|
684
|
+
if (actions.length > 1) {
|
|
685
|
+
opts?.sessionLogger?.logStep('actions_merged', {
|
|
686
|
+
count: actions.length,
|
|
687
|
+
actions: actions.map((a) => ({
|
|
688
|
+
text: a.text,
|
|
689
|
+
dependency: a.dependency,
|
|
690
|
+
})),
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
const assembleSpan = this.tracer.startSpan('smart_agent.assemble', {
|
|
694
|
+
parent: rootSpan,
|
|
695
|
+
});
|
|
696
|
+
const assembleResult = await this.deps.assembler.assemble(mainAction, retrieved, processedHistory, opts);
|
|
697
|
+
if (!assembleResult.ok) {
|
|
698
|
+
assembleSpan.setStatus('error', assembleResult.error.message);
|
|
699
|
+
assembleSpan.end();
|
|
700
|
+
rootSpan.setStatus('error', assembleResult.error.message);
|
|
701
|
+
rootSpan.end();
|
|
702
|
+
yield {
|
|
703
|
+
ok: false,
|
|
704
|
+
error: new OrchestratorError(assembleResult.error.message, 'ASSEMBLER_ERROR'),
|
|
705
|
+
};
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
assembleSpan.setStatus('ok');
|
|
709
|
+
assembleSpan.end();
|
|
710
|
+
// Inject skill content into system message (post-assembly)
|
|
711
|
+
if (skillContent) {
|
|
712
|
+
const sysMsg = assembleResult.value.find((m) => m.role === 'system');
|
|
713
|
+
if (sysMsg) {
|
|
714
|
+
sysMsg.content += `\n\n## Active Skills\n${skillContent}`;
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
assembleResult.value.unshift({
|
|
718
|
+
role: 'system',
|
|
719
|
+
content: `## Active Skills\n${skillContent}`,
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
opts?.sessionLogger?.logStep(`final_context_assembled`, {
|
|
724
|
+
messages: assembleResult.value,
|
|
725
|
+
tools: finalTools.map((t) => t.name),
|
|
726
|
+
});
|
|
727
|
+
// 4. Single Streaming Loop
|
|
728
|
+
const stream = this._runStreamingToolLoop(mainAction, retrieved, assembleResult.value, toolClientMap, opts, rootSpan, sessionId, mode === 'hard' ? [] : externalTools, finalTools, detectedAdapter);
|
|
729
|
+
for await (const chunk of stream)
|
|
730
|
+
yield chunk;
|
|
731
|
+
rootSpan.setStatus('ok');
|
|
732
|
+
}
|
|
733
|
+
finally {
|
|
734
|
+
this.requestLogger.endRequest();
|
|
735
|
+
rootSpan.end();
|
|
736
|
+
timeoutCleanup?.();
|
|
737
|
+
this.metrics.requestLatency.record(Date.now() - requestStart);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
async _preparePipeline(textOrMessages, opts, parentSpan) {
|
|
741
|
+
opts?.sessionLogger?.logStep('client_request', { textOrMessages });
|
|
742
|
+
const text = typeof textOrMessages === 'string'
|
|
743
|
+
? textOrMessages
|
|
744
|
+
: (textOrMessages.filter((m) => m.role === 'user').slice(-1)[0]
|
|
745
|
+
?.content ?? '');
|
|
746
|
+
const history = typeof textOrMessages === 'string' ? [] : textOrMessages;
|
|
747
|
+
let processedHistory = history;
|
|
748
|
+
const summarizeLimit = this.config.historyAutoSummarizeLimit ?? 10;
|
|
749
|
+
if (this._helperLlm && history.length > summarizeLimit) {
|
|
750
|
+
const res = await this._summarizeHistory(history, opts);
|
|
751
|
+
if (res.ok)
|
|
752
|
+
processedHistory = res.value;
|
|
753
|
+
}
|
|
754
|
+
let subprompts;
|
|
755
|
+
if (this.config.classificationEnabled === false) {
|
|
756
|
+
// Skip classification — treat entire input as a single action
|
|
757
|
+
subprompts = [
|
|
758
|
+
{ type: 'action', text, dependency: 'independent' },
|
|
759
|
+
];
|
|
760
|
+
opts?.sessionLogger?.logStep('classification_skipped', { text });
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
const classifySpan = this.tracer.startSpan('smart_agent.classify', {
|
|
764
|
+
parent: parentSpan,
|
|
765
|
+
});
|
|
766
|
+
const classifyResult = await this._classifier.classify(text, opts);
|
|
767
|
+
if (!classifyResult.ok) {
|
|
768
|
+
classifySpan.setStatus('error', classifyResult.error.message);
|
|
769
|
+
classifySpan.end();
|
|
770
|
+
return {
|
|
771
|
+
ok: false,
|
|
772
|
+
error: new OrchestratorError(classifyResult.error.message, 'CLASSIFIER_ERROR'),
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
classifySpan.setStatus('ok');
|
|
776
|
+
classifySpan.end();
|
|
777
|
+
opts?.sessionLogger?.logStep('classifier_response', {
|
|
778
|
+
subprompts: classifyResult.value,
|
|
779
|
+
});
|
|
780
|
+
subprompts = classifyResult.value;
|
|
781
|
+
}
|
|
782
|
+
for (const sp of subprompts) {
|
|
783
|
+
this.metrics.classifierIntentCount.add(1, { intent: sp.type });
|
|
784
|
+
}
|
|
785
|
+
const { toolClientMap } = await this._listAllTools(opts);
|
|
786
|
+
return { ok: true, value: { subprompts, processedHistory, toolClientMap } };
|
|
787
|
+
}
|
|
788
|
+
async *_runStreamingToolLoop(_action, _retrieved, initialMessages, toolClientMap, opts, parentSpan, sessionId, externalTools, activeTools, clientAdapter) {
|
|
789
|
+
const toolLoopSpan = this.tracer.startSpan('smart_agent.tool_loop', {
|
|
790
|
+
parent: parentSpan,
|
|
791
|
+
});
|
|
792
|
+
let toolCallCount = 0;
|
|
793
|
+
let messages = initialMessages;
|
|
794
|
+
const usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
795
|
+
const externalToolNames = new Set(externalTools.map((t) => t.name));
|
|
796
|
+
const timingLog = [];
|
|
797
|
+
const loopStart = Date.now();
|
|
798
|
+
let currentTools = activeTools;
|
|
799
|
+
// Inject tool priority instruction when external tools are present
|
|
800
|
+
if (externalTools.length > 0) {
|
|
801
|
+
const systemIdx = messages.findIndex((m) => m.role === 'system');
|
|
802
|
+
if (systemIdx >= 0) {
|
|
803
|
+
const sys = messages[systemIdx];
|
|
804
|
+
messages = [...messages];
|
|
805
|
+
messages[systemIdx] = {
|
|
806
|
+
...sys,
|
|
807
|
+
content: `${sys.content}\n\nIMPORTANT: You have internal tools and client-provided tools (marked [client-provided] in their description). Always prefer internal tools when they can accomplish the task. Use client-provided tools only when no internal tool can do the job.`,
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
// Inject pending internal tool results from previous mixed-call request
|
|
812
|
+
if (this.pendingToolResults.has(sessionId)) {
|
|
813
|
+
const pending = await this.pendingToolResults.consume(sessionId);
|
|
814
|
+
if (pending) {
|
|
815
|
+
messages = [
|
|
816
|
+
...messages,
|
|
817
|
+
pending.assistantMessage,
|
|
818
|
+
...pending.results.map((r) => ({
|
|
819
|
+
role: 'tool',
|
|
820
|
+
content: r.text,
|
|
821
|
+
tool_call_id: r.toolCallId,
|
|
822
|
+
})),
|
|
823
|
+
];
|
|
824
|
+
opts?.sessionLogger?.logStep('pending_tool_results_injected', {
|
|
825
|
+
toolNames: pending.results.map((r) => r.toolName),
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
for (let iteration = 0;; iteration++) {
|
|
830
|
+
let iterationBuffer = '';
|
|
831
|
+
if (opts?.signal?.aborted) {
|
|
832
|
+
toolLoopSpan.setStatus('error', 'Aborted');
|
|
833
|
+
toolLoopSpan.end();
|
|
834
|
+
yield { ok: false, error: new OrchestratorError('Aborted', 'ABORTED') };
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
if (iteration >= this.config.maxIterations) {
|
|
838
|
+
timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
|
|
839
|
+
toolLoopSpan.addEvent('iteration_limit_reached');
|
|
840
|
+
toolLoopSpan.end();
|
|
841
|
+
yield {
|
|
842
|
+
ok: true,
|
|
843
|
+
value: {
|
|
844
|
+
content: '',
|
|
845
|
+
finishReason: 'length',
|
|
846
|
+
usage: {
|
|
847
|
+
...usage,
|
|
848
|
+
models: this.requestLogger.getSummary().byModel,
|
|
849
|
+
},
|
|
850
|
+
timing: timingLog,
|
|
851
|
+
},
|
|
852
|
+
};
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
// Refresh MCP tools on each iteration (when enabled)
|
|
856
|
+
if (iteration > 0 && this.config.refreshToolsPerIteration !== false) {
|
|
857
|
+
const refreshSpan = this.tracer.startSpan('smart_agent.refresh_tools', {
|
|
858
|
+
parent: toolLoopSpan,
|
|
859
|
+
attributes: { 'llm.iteration': iteration + 1 },
|
|
860
|
+
});
|
|
861
|
+
const refreshed = await this._listAllTools(opts);
|
|
862
|
+
const prevNames = [...toolClientMap.keys()];
|
|
863
|
+
toolClientMap.clear();
|
|
864
|
+
for (const [name, client] of refreshed.toolClientMap) {
|
|
865
|
+
toolClientMap.set(name, client);
|
|
866
|
+
}
|
|
867
|
+
currentTools = [...refreshed.tools, ...externalTools];
|
|
868
|
+
opts?.sessionLogger?.logStep('tools_refreshed', {
|
|
869
|
+
iteration: iteration + 1,
|
|
870
|
+
previous: prevNames,
|
|
871
|
+
current: currentTools.map((t) => t.name),
|
|
872
|
+
});
|
|
873
|
+
refreshSpan.end();
|
|
874
|
+
}
|
|
875
|
+
// Per-iteration RAG tool re-selection (when enabled)
|
|
876
|
+
if (iteration > 0 &&
|
|
877
|
+
this.config.toolReselectPerIteration &&
|
|
878
|
+
this.deps.ragStores?.tools) {
|
|
879
|
+
const reselectSpan = this.tracer.startSpan('smart_agent.tool_reselect', {
|
|
880
|
+
parent: toolLoopSpan,
|
|
881
|
+
attributes: { 'llm.iteration': iteration + 1 },
|
|
882
|
+
});
|
|
883
|
+
try {
|
|
884
|
+
// Extract last tool calls
|
|
885
|
+
const lastAssistant = [...messages]
|
|
886
|
+
.reverse()
|
|
887
|
+
.find((m) => m.role === 'assistant');
|
|
888
|
+
const toolCallNames = [];
|
|
889
|
+
if (lastAssistant && 'tool_calls' in lastAssistant) {
|
|
890
|
+
const tcs = lastAssistant.tool_calls;
|
|
891
|
+
if (Array.isArray(tcs)) {
|
|
892
|
+
for (const tc of tcs) {
|
|
893
|
+
const name = tc?.function?.name || '';
|
|
894
|
+
if (name)
|
|
895
|
+
toolCallNames.push(name);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
// Skip for read-only tools — they rarely need different tools on retry
|
|
900
|
+
const readOnlyPrefixes = [
|
|
901
|
+
'Search',
|
|
902
|
+
'Read',
|
|
903
|
+
'Get',
|
|
904
|
+
'List',
|
|
905
|
+
'Describe',
|
|
906
|
+
];
|
|
907
|
+
const allReadOnly = toolCallNames.length > 0 &&
|
|
908
|
+
toolCallNames.every((n) => readOnlyPrefixes.some((p) => n.startsWith(p)));
|
|
909
|
+
if (!allReadOnly) {
|
|
910
|
+
// Build context-aware query from error/result context
|
|
911
|
+
const lastToolMsg = [...messages]
|
|
912
|
+
.reverse()
|
|
913
|
+
.find((m) => m.role === 'tool');
|
|
914
|
+
const toolResult = typeof lastToolMsg?.content === 'string'
|
|
915
|
+
? lastToolMsg.content.slice(0, 200)
|
|
916
|
+
: '';
|
|
917
|
+
const isError = toolResult.toLowerCase().includes('error') ||
|
|
918
|
+
toolResult.toLowerCase().includes('already exist') ||
|
|
919
|
+
toolResult.toLowerCase().includes('failed');
|
|
920
|
+
const inputText = _action.text;
|
|
921
|
+
let reSelectQuery;
|
|
922
|
+
if (toolCallNames.length > 0 && isError) {
|
|
923
|
+
const updateHints = toolCallNames
|
|
924
|
+
.filter((n) => n.startsWith('Create'))
|
|
925
|
+
.map((n) => n.replace(/^Create/, 'Update'))
|
|
926
|
+
.join(', ');
|
|
927
|
+
const hints = updateHints ? ` Need ${updateHints}.` : '';
|
|
928
|
+
reSelectQuery = `${toolCallNames.join(', ')} failed: ${toolResult.slice(0, 150)}.${hints} ${inputText.slice(0, 200)}`;
|
|
929
|
+
}
|
|
930
|
+
else if (toolCallNames.length > 0) {
|
|
931
|
+
reSelectQuery = `After ${toolCallNames.join(', ')}: ${toolResult}\n${inputText.slice(0, 200)}`;
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
reSelectQuery = inputText;
|
|
935
|
+
}
|
|
936
|
+
// Query tools RAG
|
|
937
|
+
const embedding = this.deps.embedder
|
|
938
|
+
? new QueryEmbedding(reSelectQuery, this.deps.embedder, opts)
|
|
939
|
+
: new TextOnlyEmbedding(reSelectQuery);
|
|
940
|
+
const ragK = this.config.ragQueryK ?? 20;
|
|
941
|
+
const ragResult = await this.deps.ragStores.tools.query(embedding, ragK, opts);
|
|
942
|
+
if (ragResult.ok && ragResult.value.length > 0) {
|
|
943
|
+
const newToolNames = new Set(ragResult.value
|
|
944
|
+
.map((r) => r.metadata?.id || '')
|
|
945
|
+
.filter((id) => id.startsWith('tool:'))
|
|
946
|
+
.map((id) => id.slice(5).replace(/:.*$/, '')));
|
|
947
|
+
if (newToolNames.size > 0) {
|
|
948
|
+
const refreshed = await this._listAllTools(opts);
|
|
949
|
+
const newMcpTools = refreshed.tools.filter((t) => newToolNames.has(t.name));
|
|
950
|
+
currentTools = [
|
|
951
|
+
...newMcpTools,
|
|
952
|
+
...externalTools,
|
|
953
|
+
];
|
|
954
|
+
opts?.sessionLogger?.logStep('tools_reselected', {
|
|
955
|
+
iteration: iteration + 1,
|
|
956
|
+
query: reSelectQuery.slice(0, 100),
|
|
957
|
+
previousTools: toolCallNames,
|
|
958
|
+
newTools: [...newToolNames],
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
opts?.sessionLogger?.logStep('tools_reselect_skipped', {
|
|
965
|
+
iteration: iteration + 1,
|
|
966
|
+
reason: 'read-only tools only',
|
|
967
|
+
tools: toolCallNames,
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
finally {
|
|
972
|
+
reselectSpan.end();
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
const filteredForIteration = this.toolAvailabilityRegistry.filterTools(sessionId, currentTools);
|
|
976
|
+
currentTools = filteredForIteration.allowed;
|
|
977
|
+
if (filteredForIteration.blocked.length > 0) {
|
|
978
|
+
opts?.sessionLogger?.logStep('active_tools_filtered_in_iteration', {
|
|
979
|
+
iteration: iteration + 1,
|
|
980
|
+
blocked: filteredForIteration.blocked,
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
opts?.sessionLogger?.logStep(`llm_request_iter_${iteration + 1}`, {
|
|
984
|
+
messages,
|
|
985
|
+
tools: currentTools,
|
|
986
|
+
});
|
|
987
|
+
const llmSpan = this.tracer.startSpan('smart_agent.llm_call', {
|
|
988
|
+
parent: toolLoopSpan,
|
|
989
|
+
attributes: { 'llm.iteration': iteration + 1 },
|
|
990
|
+
});
|
|
991
|
+
this.metrics.llmCallCount.add();
|
|
992
|
+
const llmCallStart = Date.now();
|
|
993
|
+
const stream = this.defaultLlmCallStrategy.call(this._mainLlm, messages, currentTools, opts);
|
|
994
|
+
let content = '';
|
|
995
|
+
let finishReason;
|
|
996
|
+
const toolCallsMap = new Map();
|
|
997
|
+
// Track which streaming indices belong to external tools so that
|
|
998
|
+
// argument-only continuation deltas (no name field) are forwarded too.
|
|
999
|
+
const externalToolIndices = new Set();
|
|
1000
|
+
for await (const chunkResult of stream) {
|
|
1001
|
+
if (!chunkResult.ok) {
|
|
1002
|
+
llmSpan.setStatus('error', chunkResult.error.message);
|
|
1003
|
+
llmSpan.end();
|
|
1004
|
+
toolLoopSpan.setStatus('error', chunkResult.error.message);
|
|
1005
|
+
toolLoopSpan.end();
|
|
1006
|
+
yield {
|
|
1007
|
+
ok: false,
|
|
1008
|
+
error: new OrchestratorError(chunkResult.error.message, 'LLM_ERROR'),
|
|
1009
|
+
};
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
const chunk = chunkResult.value;
|
|
1013
|
+
// Mid-stream retry: discard accumulated state and restart accumulation
|
|
1014
|
+
if (chunk.reset) {
|
|
1015
|
+
content = '';
|
|
1016
|
+
iterationBuffer = '';
|
|
1017
|
+
toolCallsMap.clear();
|
|
1018
|
+
externalToolIndices.clear();
|
|
1019
|
+
finishReason = undefined;
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1022
|
+
if (chunk.content) {
|
|
1023
|
+
content += chunk.content;
|
|
1024
|
+
// When a client adapter is detected, buffer content — it will be wrapped after the stream completes
|
|
1025
|
+
if (!clientAdapter) {
|
|
1026
|
+
if (this.config.streamMode === 'final') {
|
|
1027
|
+
iterationBuffer += chunk.content;
|
|
1028
|
+
}
|
|
1029
|
+
else {
|
|
1030
|
+
yield { ok: true, value: { content: chunk.content } };
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
if (chunk.toolCalls) {
|
|
1035
|
+
// Register newly seen external tool indices
|
|
1036
|
+
for (const tc of chunk.toolCalls) {
|
|
1037
|
+
const name = getStreamToolCallName(tc);
|
|
1038
|
+
if (name && externalToolNames.has(name)) {
|
|
1039
|
+
const delta = toToolCallDelta(tc, 0);
|
|
1040
|
+
externalToolIndices.add(delta.index);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
const externalDeltas = chunk.toolCalls.filter((tc) => {
|
|
1044
|
+
const delta = toToolCallDelta(tc, 0);
|
|
1045
|
+
return externalToolIndices.has(delta.index);
|
|
1046
|
+
});
|
|
1047
|
+
if (externalDeltas.length > 0) {
|
|
1048
|
+
yield {
|
|
1049
|
+
ok: true,
|
|
1050
|
+
value: { content: '', toolCalls: externalDeltas },
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
for (const [fallbackIndex, rawToolCall,] of chunk.toolCalls.entries()) {
|
|
1054
|
+
const tc = toToolCallDelta(rawToolCall, fallbackIndex);
|
|
1055
|
+
if (!toolCallsMap.has(tc.index)) {
|
|
1056
|
+
toolCallsMap.set(tc.index, {
|
|
1057
|
+
id: tc.id || '',
|
|
1058
|
+
name: tc.name || '',
|
|
1059
|
+
arguments: tc.arguments || '',
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
const ex = toolCallsMap.get(tc.index);
|
|
1064
|
+
if (ex) {
|
|
1065
|
+
if (tc.id)
|
|
1066
|
+
ex.id = tc.id;
|
|
1067
|
+
if (tc.name)
|
|
1068
|
+
ex.name = tc.name;
|
|
1069
|
+
if (tc.arguments)
|
|
1070
|
+
ex.arguments += tc.arguments;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
if (chunk.finishReason)
|
|
1076
|
+
finishReason = chunk.finishReason;
|
|
1077
|
+
if (chunk.usage) {
|
|
1078
|
+
usage.promptTokens += chunk.usage.promptTokens;
|
|
1079
|
+
usage.completionTokens += chunk.usage.completionTokens;
|
|
1080
|
+
usage.totalTokens += chunk.usage.totalTokens;
|
|
1081
|
+
this.sessionManager.addTokens(chunk.usage.totalTokens);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
llmSpan.setStatus('ok');
|
|
1085
|
+
llmSpan.end();
|
|
1086
|
+
const llmCallDuration = Date.now() - llmCallStart;
|
|
1087
|
+
this.metrics.llmCallLatency.record(llmCallDuration);
|
|
1088
|
+
timingLog.push({
|
|
1089
|
+
phase: `llm_call_${iteration + 1}`,
|
|
1090
|
+
duration: llmCallDuration,
|
|
1091
|
+
});
|
|
1092
|
+
// In 'final' mode: yield buffered content only if this is the last iteration
|
|
1093
|
+
if (this.config.streamMode === 'final' && iterationBuffer) {
|
|
1094
|
+
if (finishReason !== 'tool_calls') {
|
|
1095
|
+
// Final iteration — stream the buffered content
|
|
1096
|
+
yield { ok: true, value: { content: iterationBuffer } };
|
|
1097
|
+
}
|
|
1098
|
+
iterationBuffer = '';
|
|
1099
|
+
}
|
|
1100
|
+
const toolCalls = Array.from(toolCallsMap.values()).map((tc) => {
|
|
1101
|
+
let args = {};
|
|
1102
|
+
try {
|
|
1103
|
+
args = JSON.parse(tc.arguments);
|
|
1104
|
+
}
|
|
1105
|
+
catch {
|
|
1106
|
+
args = {};
|
|
1107
|
+
}
|
|
1108
|
+
return { id: tc.id, name: tc.name, arguments: args };
|
|
1109
|
+
});
|
|
1110
|
+
opts?.sessionLogger?.logStep(`llm_response_iter_${iteration + 1}`, {
|
|
1111
|
+
content,
|
|
1112
|
+
toolCalls,
|
|
1113
|
+
finishReason,
|
|
1114
|
+
});
|
|
1115
|
+
if (finishReason !== 'tool_calls' || toolCalls.length === 0) {
|
|
1116
|
+
// Output validation
|
|
1117
|
+
const valResult = await this.outputValidator.validate(content, { messages, tools: currentTools }, opts);
|
|
1118
|
+
if (valResult.ok && !valResult.value.valid) {
|
|
1119
|
+
const correction = valResult.value.correctedContent ?? valResult.value.reason;
|
|
1120
|
+
messages = [
|
|
1121
|
+
...messages,
|
|
1122
|
+
{ role: 'assistant', content },
|
|
1123
|
+
{
|
|
1124
|
+
role: 'user',
|
|
1125
|
+
content: `Your previous response was rejected by validation: ${correction}. Please try again.`,
|
|
1126
|
+
},
|
|
1127
|
+
];
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
opts?.sessionLogger?.logStep('final_response', { content, usage });
|
|
1131
|
+
// onBeforeStream hook — consumer transforms content before streaming
|
|
1132
|
+
if (this.config.onBeforeStream) {
|
|
1133
|
+
const hookCtx = { messages };
|
|
1134
|
+
for await (const chunk of this.config.onBeforeStream(content, hookCtx)) {
|
|
1135
|
+
if (clientAdapter) {
|
|
1136
|
+
yield {
|
|
1137
|
+
ok: true,
|
|
1138
|
+
value: { content: clientAdapter.wrapResponse(chunk) },
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
else {
|
|
1142
|
+
yield { ok: true, value: { content: chunk } };
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
else if (clientAdapter && content) {
|
|
1147
|
+
yield {
|
|
1148
|
+
ok: true,
|
|
1149
|
+
value: { content: clientAdapter.wrapResponse(content) },
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
|
|
1153
|
+
toolLoopSpan.setStatus('ok');
|
|
1154
|
+
toolLoopSpan.end();
|
|
1155
|
+
const summary = this.requestLogger.getSummary();
|
|
1156
|
+
yield {
|
|
1157
|
+
ok: true,
|
|
1158
|
+
value: {
|
|
1159
|
+
content: '',
|
|
1160
|
+
finishReason: finishReason || 'stop',
|
|
1161
|
+
usage: {
|
|
1162
|
+
...usage,
|
|
1163
|
+
models: summary.byModel,
|
|
1164
|
+
},
|
|
1165
|
+
timing: timingLog,
|
|
1166
|
+
},
|
|
1167
|
+
};
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const internalCalls = toolCalls.filter((tc) => toolClientMap.has(tc.name));
|
|
1171
|
+
const validExternalCalls = toolCalls.filter((tc) => externalToolNames.has(tc.name));
|
|
1172
|
+
const blockedToolNames = this.toolAvailabilityRegistry.getBlockedToolNames(sessionId);
|
|
1173
|
+
const blockedCalls = toolCalls.filter((tc) => blockedToolNames.has(tc.name));
|
|
1174
|
+
const hallucinations = toolCalls.filter((tc) => !blockedToolNames.has(tc.name) &&
|
|
1175
|
+
!toolClientMap.has(tc.name) &&
|
|
1176
|
+
!externalToolNames.has(tc.name));
|
|
1177
|
+
if (blockedCalls.length > 0) {
|
|
1178
|
+
messages = [
|
|
1179
|
+
...messages,
|
|
1180
|
+
{
|
|
1181
|
+
role: 'assistant',
|
|
1182
|
+
content: content || null,
|
|
1183
|
+
tool_calls: blockedCalls.map((tc) => ({
|
|
1184
|
+
id: tc.id,
|
|
1185
|
+
type: 'function',
|
|
1186
|
+
function: {
|
|
1187
|
+
name: tc.name,
|
|
1188
|
+
arguments: JSON.stringify(tc.arguments),
|
|
1189
|
+
},
|
|
1190
|
+
})),
|
|
1191
|
+
},
|
|
1192
|
+
];
|
|
1193
|
+
for (const blocked of blockedCalls) {
|
|
1194
|
+
messages = [
|
|
1195
|
+
...messages,
|
|
1196
|
+
{
|
|
1197
|
+
role: 'tool',
|
|
1198
|
+
content: `Error: Tool "${blocked.name}" is temporarily unavailable in this session.`,
|
|
1199
|
+
tool_call_id: blocked.id,
|
|
1200
|
+
},
|
|
1201
|
+
];
|
|
1202
|
+
}
|
|
1203
|
+
opts?.sessionLogger?.logStep('blocked_tool_calls_intercepted', {
|
|
1204
|
+
toolNames: blockedCalls.map((tc) => tc.name),
|
|
1205
|
+
});
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
if (hallucinations.length > 0) {
|
|
1209
|
+
messages = [
|
|
1210
|
+
...messages,
|
|
1211
|
+
{
|
|
1212
|
+
role: 'assistant',
|
|
1213
|
+
content: content || null,
|
|
1214
|
+
tool_calls: toolCalls.map((tc) => ({
|
|
1215
|
+
id: tc.id,
|
|
1216
|
+
type: 'function',
|
|
1217
|
+
function: {
|
|
1218
|
+
name: tc.name,
|
|
1219
|
+
arguments: JSON.stringify(tc.arguments),
|
|
1220
|
+
},
|
|
1221
|
+
})),
|
|
1222
|
+
},
|
|
1223
|
+
];
|
|
1224
|
+
for (const h of hallucinations) {
|
|
1225
|
+
messages = [
|
|
1226
|
+
...messages,
|
|
1227
|
+
{
|
|
1228
|
+
role: 'tool',
|
|
1229
|
+
content: `Error: Tool "${h.name}" not found.`,
|
|
1230
|
+
tool_call_id: h.id,
|
|
1231
|
+
},
|
|
1232
|
+
];
|
|
1233
|
+
}
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (validExternalCalls.length > 0) {
|
|
1237
|
+
// Mixed calls: fire internal tools async, store pending results
|
|
1238
|
+
if (internalCalls.length > 0) {
|
|
1239
|
+
fireInternalToolsAsync(content, internalCalls, this.pendingToolResults, sessionId, {
|
|
1240
|
+
toolClientMap,
|
|
1241
|
+
toolCache: this.toolCache,
|
|
1242
|
+
metrics: this.metrics,
|
|
1243
|
+
options: opts,
|
|
1244
|
+
});
|
|
1245
|
+
opts?.sessionLogger?.logStep('mixed_tool_calls', {
|
|
1246
|
+
internal: internalCalls.map((tc) => tc.name),
|
|
1247
|
+
external: validExternalCalls.map((tc) => tc.name),
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
|
|
1251
|
+
toolLoopSpan.setStatus('ok');
|
|
1252
|
+
toolLoopSpan.end();
|
|
1253
|
+
yield {
|
|
1254
|
+
ok: true,
|
|
1255
|
+
value: {
|
|
1256
|
+
content: '',
|
|
1257
|
+
finishReason: 'tool_calls',
|
|
1258
|
+
usage: {
|
|
1259
|
+
...usage,
|
|
1260
|
+
models: this.requestLogger.getSummary().byModel,
|
|
1261
|
+
},
|
|
1262
|
+
timing: timingLog,
|
|
1263
|
+
},
|
|
1264
|
+
};
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
if (content || internalCalls.length > 0)
|
|
1268
|
+
messages = [
|
|
1269
|
+
...messages,
|
|
1270
|
+
{
|
|
1271
|
+
role: 'assistant',
|
|
1272
|
+
content: content || null,
|
|
1273
|
+
tool_calls: internalCalls.map((tc) => ({
|
|
1274
|
+
id: tc.id,
|
|
1275
|
+
type: 'function',
|
|
1276
|
+
function: {
|
|
1277
|
+
name: tc.name,
|
|
1278
|
+
arguments: JSON.stringify(tc.arguments),
|
|
1279
|
+
},
|
|
1280
|
+
})),
|
|
1281
|
+
},
|
|
1282
|
+
];
|
|
1283
|
+
// Truncate batch to remaining budget
|
|
1284
|
+
const remaining = this.config.maxToolCalls !== undefined
|
|
1285
|
+
? this.config.maxToolCalls - toolCallCount
|
|
1286
|
+
: internalCalls.length;
|
|
1287
|
+
if (remaining <= 0) {
|
|
1288
|
+
timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
|
|
1289
|
+
toolLoopSpan.addEvent('tool_call_limit_reached');
|
|
1290
|
+
toolLoopSpan.end();
|
|
1291
|
+
yield {
|
|
1292
|
+
ok: true,
|
|
1293
|
+
value: {
|
|
1294
|
+
content: '',
|
|
1295
|
+
finishReason: 'length',
|
|
1296
|
+
usage: {
|
|
1297
|
+
...usage,
|
|
1298
|
+
models: this.requestLogger.getSummary().byModel,
|
|
1299
|
+
},
|
|
1300
|
+
timing: timingLog,
|
|
1301
|
+
},
|
|
1302
|
+
};
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
const batch = internalCalls.slice(0, remaining);
|
|
1306
|
+
const heartbeatMs = this.config.heartbeatIntervalMs ?? 5000;
|
|
1307
|
+
// Yield all progress messages before execution
|
|
1308
|
+
for (const tc of batch) {
|
|
1309
|
+
yield {
|
|
1310
|
+
ok: true,
|
|
1311
|
+
value: { content: `\n\n[SmartAgent: Executing ${tc.name}...]\n` },
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
const toolExecPromises = batch.map(async (tc) => {
|
|
1315
|
+
const toolStart = Date.now();
|
|
1316
|
+
opts?.sessionLogger?.logStep(`mcp_call_${tc.name}`, {
|
|
1317
|
+
arguments: tc.arguments,
|
|
1318
|
+
});
|
|
1319
|
+
const client = toolClientMap.get(tc.name);
|
|
1320
|
+
if (!client)
|
|
1321
|
+
return { tc, text: '', res: null, duration: 0 };
|
|
1322
|
+
const toolSpan = this.tracer.startSpan('smart_agent.tool_call', {
|
|
1323
|
+
parent: toolLoopSpan,
|
|
1324
|
+
attributes: { 'tool.name': tc.name },
|
|
1325
|
+
});
|
|
1326
|
+
const cached = this.toolCache.get(tc.name, tc.arguments);
|
|
1327
|
+
const res = cached
|
|
1328
|
+
? (() => {
|
|
1329
|
+
this.metrics.toolCacheHitCount.add();
|
|
1330
|
+
toolSpan.setAttribute('cache', 'hit');
|
|
1331
|
+
return { ok: true, value: cached };
|
|
1332
|
+
})()
|
|
1333
|
+
: await (async () => {
|
|
1334
|
+
const r = await client.callTool(tc.name, tc.arguments, opts);
|
|
1335
|
+
if (r.ok)
|
|
1336
|
+
this.toolCache.set(tc.name, tc.arguments, r.value);
|
|
1337
|
+
return r;
|
|
1338
|
+
})();
|
|
1339
|
+
const text = !res.ok
|
|
1340
|
+
? res.error.message
|
|
1341
|
+
: typeof res.value.content === 'string'
|
|
1342
|
+
? res.value.content
|
|
1343
|
+
: JSON.stringify(res.value.content);
|
|
1344
|
+
toolSpan.setStatus(res.ok ? 'ok' : 'error', res.ok ? undefined : text);
|
|
1345
|
+
toolSpan.end();
|
|
1346
|
+
return { tc, text, res, duration: Date.now() - toolStart };
|
|
1347
|
+
});
|
|
1348
|
+
// Race: tool execution vs periodic heartbeat
|
|
1349
|
+
const allDone = Promise.all(toolExecPromises);
|
|
1350
|
+
const pendingTools = new Set(batch.map((tc) => tc.name));
|
|
1351
|
+
const toolStartTime = Date.now();
|
|
1352
|
+
let results = [];
|
|
1353
|
+
let settled = false;
|
|
1354
|
+
// Mark individual tools as done when they resolve
|
|
1355
|
+
for (const [i, p] of toolExecPromises.entries()) {
|
|
1356
|
+
p.then(() => pendingTools.delete(batch[i].name));
|
|
1357
|
+
}
|
|
1358
|
+
while (!settled) {
|
|
1359
|
+
const winner = await Promise.race([
|
|
1360
|
+
allDone.then((r) => ({ tag: 'done', results: r })),
|
|
1361
|
+
new Promise((resolve) => setTimeout(() => resolve({ tag: 'tick' }), heartbeatMs)),
|
|
1362
|
+
]);
|
|
1363
|
+
if (winner.tag === 'done') {
|
|
1364
|
+
results = winner.results;
|
|
1365
|
+
settled = true;
|
|
1366
|
+
}
|
|
1367
|
+
else {
|
|
1368
|
+
// Yield heartbeat for each still-pending tool
|
|
1369
|
+
for (const tool of pendingTools) {
|
|
1370
|
+
yield {
|
|
1371
|
+
ok: true,
|
|
1372
|
+
value: {
|
|
1373
|
+
content: '',
|
|
1374
|
+
heartbeat: {
|
|
1375
|
+
tool,
|
|
1376
|
+
elapsed: Date.now() - toolStartTime,
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
// Collect per-tool timing into the shared timing log
|
|
1384
|
+
for (const r of results) {
|
|
1385
|
+
timingLog.push({
|
|
1386
|
+
phase: `tool_${r.tc.name}`,
|
|
1387
|
+
duration: r.duration,
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
// Process results: update availability, metrics, messages
|
|
1391
|
+
const toolMessages = [];
|
|
1392
|
+
for (const { tc, text, res } of results) {
|
|
1393
|
+
if (!res)
|
|
1394
|
+
continue;
|
|
1395
|
+
if (!res.ok &&
|
|
1396
|
+
isToolContextUnavailableError(text) &&
|
|
1397
|
+
!externalToolNames.has(tc.name)) {
|
|
1398
|
+
const entry = this.toolAvailabilityRegistry.block(sessionId, tc.name, text);
|
|
1399
|
+
currentTools = currentTools.filter((t) => t.name !== tc.name);
|
|
1400
|
+
opts?.sessionLogger?.logStep(`tool_blacklisted_${tc.name}`, {
|
|
1401
|
+
reason: text,
|
|
1402
|
+
blockedUntil: entry.blockedUntil,
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
opts?.sessionLogger?.logStep(`mcp_result_${tc.name}`, {
|
|
1406
|
+
result: text,
|
|
1407
|
+
});
|
|
1408
|
+
toolCallCount++;
|
|
1409
|
+
this.metrics.toolCallCount.add();
|
|
1410
|
+
toolMessages.push({
|
|
1411
|
+
role: 'tool',
|
|
1412
|
+
content: text,
|
|
1413
|
+
tool_call_id: tc.id,
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
messages = [...messages, ...toolMessages];
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
async _listAllTools(opts) {
|
|
1420
|
+
await this._resolveActiveClients(opts);
|
|
1421
|
+
const tools = [];
|
|
1422
|
+
const toolClientMap = new Map();
|
|
1423
|
+
const settled = await Promise.allSettled(this._activeClients.map(async (client) => ({
|
|
1424
|
+
client,
|
|
1425
|
+
result: await client.listTools(opts),
|
|
1426
|
+
})));
|
|
1427
|
+
for (const e of settled) {
|
|
1428
|
+
if (e.status === 'fulfilled' && e.value.result.ok) {
|
|
1429
|
+
for (const t of e.value.result.value) {
|
|
1430
|
+
if (!toolClientMap.has(t.name)) {
|
|
1431
|
+
tools.push(t);
|
|
1432
|
+
toolClientMap.set(t.name, e.value.client);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
return { tools, toolClientMap };
|
|
1438
|
+
}
|
|
1439
|
+
async _toEnglishForRag(text, opts) {
|
|
1440
|
+
if (/^[\p{ASCII}]+$/u.test(text) || text.length < 15)
|
|
1441
|
+
return text;
|
|
1442
|
+
const dp = 'Translate the user request to English for search purposes. Preserve technical terms if present. Reply with only the expanded English terms, no explanation.';
|
|
1443
|
+
const llm = this._helperLlm || this._mainLlm;
|
|
1444
|
+
const res = await llm.chat([
|
|
1445
|
+
{
|
|
1446
|
+
role: 'system',
|
|
1447
|
+
content: this.config.ragTranslatePrompt || dp,
|
|
1448
|
+
},
|
|
1449
|
+
{ role: 'user', content: text },
|
|
1450
|
+
], [], opts);
|
|
1451
|
+
return res.ok && res.value.content.trim() ? res.value.content.trim() : text;
|
|
1452
|
+
}
|
|
1453
|
+
async _summarizeHistory(h, opts) {
|
|
1454
|
+
if (!this._helperLlm)
|
|
1455
|
+
return { ok: true, value: h };
|
|
1456
|
+
const toS = h.slice(0, -5);
|
|
1457
|
+
const rec = h.slice(-5);
|
|
1458
|
+
if (toS.length === 0)
|
|
1459
|
+
return { ok: true, value: h };
|
|
1460
|
+
const dp = 'Summarize the conversation so far in 2-3 sentences. Focus on the user goals and the current status of the task. Keep technical SAP terms as is.';
|
|
1461
|
+
const summarizeStart = Date.now();
|
|
1462
|
+
const res = await this._helperLlm.chat([
|
|
1463
|
+
...toS,
|
|
1464
|
+
{
|
|
1465
|
+
role: 'system',
|
|
1466
|
+
content: this.config.historySummaryPrompt || dp,
|
|
1467
|
+
},
|
|
1468
|
+
], [], opts);
|
|
1469
|
+
this.requestLogger.logLlmCall({
|
|
1470
|
+
component: 'helper',
|
|
1471
|
+
model: this._helperLlm.model ?? 'unknown',
|
|
1472
|
+
promptTokens: res.ok ? (res.value.usage?.promptTokens ?? 0) : 0,
|
|
1473
|
+
completionTokens: res.ok ? (res.value.usage?.completionTokens ?? 0) : 0,
|
|
1474
|
+
totalTokens: res.ok ? (res.value.usage?.totalTokens ?? 0) : 0,
|
|
1475
|
+
durationMs: Date.now() - summarizeStart,
|
|
1476
|
+
});
|
|
1477
|
+
if (!res.ok)
|
|
1478
|
+
return { ok: true, value: h };
|
|
1479
|
+
return {
|
|
1480
|
+
ok: true,
|
|
1481
|
+
value: [
|
|
1482
|
+
{
|
|
1483
|
+
role: 'system',
|
|
1484
|
+
content: `Summary of previous conversation: ${res.value.content}`,
|
|
1485
|
+
},
|
|
1486
|
+
...rec,
|
|
1487
|
+
],
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
async *_runStructuredPipeline(textOrMessages, externalTools, opts, _parentSpan, _sessionId) {
|
|
1491
|
+
if (!this.deps.pipeline)
|
|
1492
|
+
return;
|
|
1493
|
+
const history = typeof textOrMessages === 'string' ? [] : textOrMessages;
|
|
1494
|
+
const chunkQueue = [];
|
|
1495
|
+
let resolveWait = null;
|
|
1496
|
+
let done = false;
|
|
1497
|
+
const executorPromise = this.deps.pipeline
|
|
1498
|
+
.execute(textOrMessages, history, opts, (chunk) => {
|
|
1499
|
+
chunkQueue.push(chunk);
|
|
1500
|
+
if (resolveWait) {
|
|
1501
|
+
resolveWait();
|
|
1502
|
+
resolveWait = null;
|
|
1503
|
+
}
|
|
1504
|
+
}, externalTools)
|
|
1505
|
+
.then(() => {
|
|
1506
|
+
done = true;
|
|
1507
|
+
if (resolveWait) {
|
|
1508
|
+
resolveWait();
|
|
1509
|
+
resolveWait = null;
|
|
1510
|
+
}
|
|
1511
|
+
})
|
|
1512
|
+
.catch((err) => {
|
|
1513
|
+
chunkQueue.push({
|
|
1514
|
+
ok: false,
|
|
1515
|
+
error: new OrchestratorError(String(err), 'PIPELINE_ERROR'),
|
|
1516
|
+
});
|
|
1517
|
+
done = true;
|
|
1518
|
+
if (resolveWait) {
|
|
1519
|
+
resolveWait();
|
|
1520
|
+
resolveWait = null;
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
while (!done || chunkQueue.length > 0) {
|
|
1524
|
+
if (chunkQueue.length > 0) {
|
|
1525
|
+
const chunk = chunkQueue.shift();
|
|
1526
|
+
if (chunk !== undefined)
|
|
1527
|
+
yield chunk;
|
|
1528
|
+
}
|
|
1529
|
+
else if (!done) {
|
|
1530
|
+
await new Promise((r) => {
|
|
1531
|
+
resolveWait = r;
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
await executorPromise;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
//# sourceMappingURL=agent.js.map
|