glirastes 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -0
- package/CODE_OF_CONDUCT.md +85 -0
- package/CONTRIBUTING.md +87 -0
- package/README.md +268 -23
- package/SECURITY.md +46 -0
- package/codegen/package.json +5 -0
- package/dist/cjs/codegen/asset-sync.d.ts +20 -0
- package/dist/cjs/codegen/asset-sync.js +28 -0
- package/dist/cjs/codegen/coverage.d.ts +66 -0
- package/dist/cjs/codegen/coverage.js +408 -0
- package/dist/cjs/codegen/endpoint-scanner.d.ts +16 -0
- package/dist/cjs/codegen/endpoint-scanner.js +197 -0
- package/dist/cjs/codegen/format.d.ts +17 -0
- package/dist/cjs/codegen/format.js +34 -0
- package/dist/cjs/codegen/fs-utils.d.ts +45 -0
- package/dist/cjs/codegen/fs-utils.js +165 -0
- package/dist/cjs/codegen/index.d.ts +13 -0
- package/dist/cjs/codegen/index.js +33 -0
- package/dist/cjs/codegen/mcp-generator.d.ts +50 -0
- package/dist/cjs/codegen/mcp-generator.js +803 -0
- package/dist/cjs/codegen/module-generator.d.ts +11 -0
- package/dist/cjs/codegen/module-generator.js +353 -0
- package/dist/cjs/codegen/nestjs-scanner.d.ts +43 -0
- package/dist/cjs/codegen/nestjs-scanner.js +241 -0
- package/dist/cjs/codegen/output-recommender.d.ts +23 -0
- package/dist/cjs/codegen/output-recommender.js +33 -0
- package/dist/cjs/codegen/scaffolder.d.ts +36 -0
- package/dist/cjs/codegen/scaffolder.js +262 -0
- package/dist/cjs/codegen/skill-generator.d.ts +49 -0
- package/dist/cjs/codegen/skill-generator.js +967 -0
- package/dist/cjs/codegen/types.d.ts +52 -0
- package/dist/cjs/codegen/types.js +16 -0
- package/dist/cjs/codegen/ui-scanner.d.ts +24 -0
- package/dist/cjs/codegen/ui-scanner.js +202 -0
- package/dist/cjs/codegen/validator.d.ts +35 -0
- package/dist/cjs/codegen/validator.js +292 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/openapi/index.d.ts +78 -0
- package/dist/cjs/openapi/index.js +347 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/react/audio-worklet-processor.d.ts +16 -0
- package/dist/cjs/react/audio-worklet-processor.js +27 -0
- package/dist/cjs/react/bridges/rest-session-bridge.d.ts +113 -0
- package/dist/cjs/react/bridges/rest-session-bridge.js +209 -0
- package/dist/cjs/react/components/ai-chat-panel.d.ts +12 -0
- package/dist/cjs/react/components/ai-chat-panel.js +67 -0
- package/dist/cjs/react/components/ai-trigger-button.d.ts +2 -0
- package/dist/cjs/react/components/ai-trigger-button.js +239 -0
- package/dist/cjs/react/components/approval-card.d.ts +9 -0
- package/dist/cjs/react/components/approval-card.js +24 -0
- package/dist/cjs/react/components/bulk-approval-card.d.ts +9 -0
- package/dist/cjs/react/components/bulk-approval-card.js +36 -0
- package/dist/cjs/react/components/chat-input.d.ts +10 -0
- package/dist/cjs/react/components/chat-input.js +60 -0
- package/dist/cjs/react/components/chat-window.d.ts +2 -0
- package/dist/cjs/react/components/chat-window.js +134 -0
- package/dist/cjs/react/components/confirm-dialog.d.ts +32 -0
- package/dist/cjs/react/components/confirm-dialog.js +48 -0
- package/dist/cjs/react/components/floating-chat-ui.d.ts +90 -0
- package/dist/cjs/react/components/floating-chat-ui.js +163 -0
- package/dist/cjs/react/components/mention-chip.d.ts +16 -0
- package/dist/cjs/react/components/mention-chip.js +42 -0
- package/dist/cjs/react/components/mention-input.d.ts +8 -0
- package/dist/cjs/react/components/mention-input.js +117 -0
- package/dist/cjs/react/components/message-bubble.d.ts +11 -0
- package/dist/cjs/react/components/message-bubble.js +171 -0
- package/dist/cjs/react/components/message-list.d.ts +8 -0
- package/dist/cjs/react/components/message-list.js +52 -0
- package/dist/cjs/react/components/pipeline-timeline.d.ts +7 -0
- package/dist/cjs/react/components/pipeline-timeline.js +72 -0
- package/dist/cjs/react/components/recording-bar.d.ts +2 -0
- package/dist/cjs/react/components/recording-bar.js +81 -0
- package/dist/cjs/react/components/recording-controls.d.ts +18 -0
- package/dist/cjs/react/components/recording-controls.js +38 -0
- package/dist/cjs/react/components/rich-mention-input.d.ts +2 -0
- package/dist/cjs/react/components/rich-mention-input.js +571 -0
- package/dist/cjs/react/components/session-switcher.d.ts +14 -0
- package/dist/cjs/react/components/session-switcher.js +133 -0
- package/dist/cjs/react/components/suggestion-bar.d.ts +9 -0
- package/dist/cjs/react/components/suggestion-bar.js +47 -0
- package/dist/cjs/react/components/suggestion-chip.d.ts +9 -0
- package/dist/cjs/react/components/suggestion-chip.js +14 -0
- package/dist/cjs/react/components/voice-input-addon.d.ts +13 -0
- package/dist/cjs/react/components/voice-input-addon.js +31 -0
- package/dist/cjs/react/components/voice-input-button.d.ts +2 -0
- package/dist/cjs/react/components/voice-input-button.js +55 -0
- package/dist/cjs/react/components/wavesurfer-loader.d.ts +5 -0
- package/dist/cjs/react/components/wavesurfer-loader.js +36 -0
- package/dist/cjs/react/hooks/use-ai-chat.d.ts +22 -0
- package/dist/cjs/react/hooks/use-ai-chat.js +51 -0
- package/dist/cjs/react/hooks/use-approvals.d.ts +23 -0
- package/dist/cjs/react/hooks/use-approvals.js +63 -0
- package/dist/cjs/react/hooks/use-deepgram-transcription.d.ts +2 -0
- package/dist/cjs/react/hooks/use-deepgram-transcription.js +329 -0
- package/dist/cjs/react/hooks/use-drag-resize-panel.d.ts +48 -0
- package/dist/cjs/react/hooks/use-drag-resize-panel.js +308 -0
- package/dist/cjs/react/hooks/use-draggable-position.d.ts +25 -0
- package/dist/cjs/react/hooks/use-draggable-position.js +134 -0
- package/dist/cjs/react/hooks/use-keyboard-shortcut.d.ts +20 -0
- package/dist/cjs/react/hooks/use-keyboard-shortcut.js +93 -0
- package/dist/cjs/react/hooks/use-mentions.d.ts +23 -0
- package/dist/cjs/react/hooks/use-mentions.js +42 -0
- package/dist/cjs/react/hooks/use-suggestions.d.ts +22 -0
- package/dist/cjs/react/hooks/use-suggestions.js +39 -0
- package/dist/cjs/react/index.d.ts +43 -0
- package/dist/cjs/react/index.js +111 -0
- package/dist/cjs/react/provider/ai-chat-provider.d.ts +45 -0
- package/dist/cjs/react/provider/ai-chat-provider.js +1024 -0
- package/dist/cjs/react/provider/chat-context.d.ts +84 -0
- package/dist/cjs/react/provider/chat-context.js +13 -0
- package/dist/cjs/react/template.d.ts +84 -0
- package/dist/cjs/react/template.js +90 -0
- package/dist/cjs/react/themes.d.ts +24 -0
- package/dist/cjs/react/themes.js +273 -0
- package/dist/cjs/react/transports/langgraph/index.d.ts +2 -0
- package/dist/cjs/react/transports/langgraph/index.js +8 -0
- package/dist/cjs/react/transports/langgraph/langgraph-ai-chat.d.ts +62 -0
- package/dist/cjs/react/transports/langgraph/langgraph-ai-chat.js +94 -0
- package/dist/cjs/react/transports/langgraph.d.ts +71 -0
- package/dist/cjs/react/transports/langgraph.js +369 -0
- package/dist/cjs/react/transports/vercel/index.d.ts +2 -0
- package/dist/cjs/react/transports/vercel/index.js +8 -0
- package/dist/cjs/react/transports/vercel/vercel-ai-chat.d.ts +49 -0
- package/dist/cjs/react/transports/vercel/vercel-ai-chat.js +81 -0
- package/dist/cjs/react/transports/vercel.d.ts +30 -0
- package/dist/cjs/react/transports/vercel.js +69 -0
- package/dist/cjs/react/types.d.ts +760 -0
- package/dist/cjs/react/types.js +2 -0
- package/dist/cjs/react/ui.d.ts +73 -0
- package/dist/cjs/react/ui.js +183 -0
- package/dist/cjs/react/utils/create-approval-description.d.ts +53 -0
- package/dist/cjs/react/utils/create-approval-description.js +122 -0
- package/dist/cjs/react/utils/create-tool-result-handler.d.ts +90 -0
- package/dist/cjs/react/utils/create-tool-result-handler.js +168 -0
- package/dist/cjs/react/utils/mention-markup.d.ts +13 -0
- package/dist/cjs/react/utils/mention-markup.js +117 -0
- package/dist/cjs/react/utils/merge-pipeline-steps.d.ts +19 -0
- package/dist/cjs/react/utils/merge-pipeline-steps.js +81 -0
- package/dist/cjs/react/utils/sanitize-stored-messages.d.ts +23 -0
- package/dist/cjs/react/utils/sanitize-stored-messages.js +52 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-auth.guard.d.ts +10 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-auth.guard.js +42 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-module-options.interface.d.ts +32 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-module-options.interface.js +4 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.controller.d.ts +11 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.controller.js +80 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.module.d.ts +9 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.module.js +119 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.service.d.ts +13 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.service.js +131 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/ai-chat-request.dto.d.ts +7 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/ai-chat-request.dto.js +52 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message-part.dto.d.ts +19 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message-part.dto.js +108 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message.dto.d.ts +8 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message.dto.js +59 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/index.d.ts +3 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/index.js +9 -0
- package/dist/cjs/server/adapters/nestjs/chat/index.d.ts +3 -0
- package/dist/cjs/server/adapters/nestjs/chat/index.js +9 -0
- package/dist/cjs/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +4 -0
- package/dist/cjs/server/adapters/nestjs/chat/speech-stream.gateway.js +73 -0
- package/dist/cjs/server/adapters/nestjs/chat/ws-loader.d.ts +5 -0
- package/dist/cjs/server/adapters/nestjs/chat/ws-loader.js +72 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-module.decorator.d.ts +6 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-module.decorator.js +13 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-param.decorator.d.ts +5 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-param.decorator.js +15 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-tool.decorator.d.ts +6 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-tool.decorator.js +22 -0
- package/dist/cjs/server/adapters/nestjs/decorators/constants.d.ts +4 -0
- package/dist/cjs/server/adapters/nestjs/decorators/constants.js +7 -0
- package/dist/cjs/server/adapters/nestjs/index.d.ts +14 -0
- package/dist/cjs/server/adapters/nestjs/index.js +42 -0
- package/dist/cjs/server/adapters/nestjs/metadata.d.ts +39 -0
- package/dist/cjs/server/adapters/nestjs/metadata.js +36 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools-explorer.service.d.ts +36 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools-explorer.service.js +159 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.module.d.ts +37 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.module.js +44 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.service.d.ts +28 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.service.js +41 -0
- package/dist/cjs/server/adapters/nestjs/scanner/nestjs-scanner.d.ts +16 -0
- package/dist/cjs/server/adapters/nestjs/scanner/nestjs-scanner.js +117 -0
- package/dist/cjs/server/adapters/nestjs/scanner/schema-builder.d.ts +26 -0
- package/dist/cjs/server/adapters/nestjs/scanner/schema-builder.js +259 -0
- package/dist/cjs/server/adapters/nestjs/swagger.d.ts +7 -0
- package/dist/cjs/server/adapters/nestjs/swagger.js +39 -0
- package/dist/cjs/server/adapters/nextjs/context-helpers.d.ts +22 -0
- package/dist/cjs/server/adapters/nextjs/context-helpers.js +60 -0
- package/dist/cjs/server/adapters/nextjs/create-ai-chat-handler.d.ts +94 -0
- package/dist/cjs/server/adapters/nextjs/create-ai-chat-handler.js +965 -0
- package/dist/cjs/server/adapters/nextjs/filter-fallback-error.d.ts +11 -0
- package/dist/cjs/server/adapters/nextjs/filter-fallback-error.js +41 -0
- package/dist/cjs/server/adapters/nextjs/index.d.ts +8 -0
- package/dist/cjs/server/adapters/nextjs/index.js +22 -0
- package/dist/cjs/server/adapters/nextjs/prepare-model-messages.d.ts +58 -0
- package/dist/cjs/server/adapters/nextjs/prepare-model-messages.js +114 -0
- package/dist/cjs/server/adapters/nextjs/sanitize-model-messages.d.ts +64 -0
- package/dist/cjs/server/adapters/nextjs/sanitize-model-messages.js +489 -0
- package/dist/cjs/server/adapters/nextjs/server-action-helper.d.ts +7 -0
- package/dist/cjs/server/adapters/nextjs/server-action-helper.js +40 -0
- package/dist/cjs/server/adapters/nextjs/types.d.ts +246 -0
- package/dist/cjs/server/adapters/nextjs/types.js +2 -0
- package/dist/cjs/server/adapters/nextjs/with-ai-tool.d.ts +9 -0
- package/dist/cjs/server/adapters/nextjs/with-ai-tool.js +12 -0
- package/dist/cjs/server/core/followup-tool.d.ts +9 -0
- package/dist/cjs/server/core/followup-tool.js +82 -0
- package/dist/cjs/server/core/index.d.ts +139 -0
- package/dist/cjs/server/core/index.js +818 -0
- package/dist/cjs/server/core/intent-classifier.d.ts +94 -0
- package/dist/cjs/server/core/intent-classifier.js +324 -0
- package/dist/cjs/server/core/model-selector.d.ts +12 -0
- package/dist/cjs/server/core/model-selector.js +48 -0
- package/dist/cjs/server/core/module-router.d.ts +14 -0
- package/dist/cjs/server/core/module-router.js +110 -0
- package/dist/cjs/server/core/zod-compact.d.ts +18 -0
- package/dist/cjs/server/core/zod-compact.js +129 -0
- package/dist/cjs/server/index.d.ts +6 -0
- package/dist/cjs/server/index.js +28 -0
- package/dist/cjs/server/lancer/cache.d.ts +9 -0
- package/dist/cjs/server/lancer/cache.js +33 -0
- package/dist/cjs/server/lancer/client.d.ts +2 -0
- package/dist/cjs/server/lancer/client.js +279 -0
- package/dist/cjs/server/lancer/errors.d.ts +13 -0
- package/dist/cjs/server/lancer/errors.js +21 -0
- package/dist/cjs/server/lancer/index.d.ts +3 -0
- package/dist/cjs/server/lancer/index.js +7 -0
- package/dist/cjs/server/lancer/telemetry-buffer.d.ts +15 -0
- package/dist/cjs/server/lancer/telemetry-buffer.js +64 -0
- package/dist/cjs/server/lancer/types.d.ts +201 -0
- package/dist/cjs/server/lancer/types.js +5 -0
- package/dist/cjs/server/pii-shield/aegis-detector.d.ts +26 -0
- package/dist/cjs/server/pii-shield/aegis-detector.js +26 -0
- package/dist/cjs/server/pii-shield/create-pii-shield.d.ts +2 -0
- package/dist/cjs/server/pii-shield/create-pii-shield.js +191 -0
- package/dist/cjs/server/pii-shield/deep-walk.d.ts +1 -0
- package/dist/cjs/server/pii-shield/deep-walk.js +19 -0
- package/dist/cjs/server/pii-shield/fake-data.d.ts +5 -0
- package/dist/cjs/server/pii-shield/fake-data.js +170 -0
- package/dist/cjs/server/pii-shield/index.d.ts +4 -0
- package/dist/cjs/server/pii-shield/index.js +9 -0
- package/dist/cjs/server/pii-shield/leakage.d.ts +1 -0
- package/dist/cjs/server/pii-shield/leakage.js +15 -0
- package/dist/cjs/server/pii-shield/session-mapping.d.ts +12 -0
- package/dist/cjs/server/pii-shield/session-mapping.js +70 -0
- package/dist/cjs/server/pipeline.d.ts +26 -0
- package/dist/cjs/server/pipeline.js +127 -0
- package/dist/cjs/server/testing/approvals.d.ts +11 -0
- package/dist/cjs/server/testing/approvals.js +41 -0
- package/dist/cjs/server/testing/combination.d.ts +3 -0
- package/dist/cjs/server/testing/combination.js +83 -0
- package/dist/cjs/server/testing/create-test-suite.d.ts +29 -0
- package/dist/cjs/server/testing/create-test-suite.js +81 -0
- package/dist/cjs/server/testing/edge-cases.d.ts +8 -0
- package/dist/cjs/server/testing/edge-cases.js +277 -0
- package/dist/cjs/server/testing/guardrails.d.ts +14 -0
- package/dist/cjs/server/testing/guardrails.js +152 -0
- package/dist/cjs/server/testing/helpers.d.ts +14 -0
- package/dist/cjs/server/testing/helpers.js +119 -0
- package/dist/cjs/server/testing/index.d.ts +12 -0
- package/dist/cjs/server/testing/index.js +37 -0
- package/dist/cjs/server/testing/mock-executor.d.ts +8 -0
- package/dist/cjs/server/testing/mock-executor.js +40 -0
- package/dist/cjs/server/testing/regression.d.ts +7 -0
- package/dist/cjs/server/testing/regression.js +27 -0
- package/dist/cjs/server/testing/routing.d.ts +12 -0
- package/dist/cjs/server/testing/routing.js +63 -0
- package/dist/cjs/server/testing/schema-consistency.d.ts +6 -0
- package/dist/cjs/server/testing/schema-consistency.js +56 -0
- package/dist/cjs/server/testing/smoke.d.ts +11 -0
- package/dist/cjs/server/testing/smoke.js +64 -0
- package/dist/cjs/server/testing/types.d.ts +156 -0
- package/dist/cjs/server/testing/types.js +2 -0
- package/dist/cjs/types.d.ts +696 -0
- package/dist/cjs/types.js +91 -0
- package/dist/cli/commands/install-skills.d.ts +17 -0
- package/dist/cli/commands/install-skills.js +185 -0
- package/dist/cli/commands/install-skills.js.map +1 -0
- package/dist/cli/index.js +25 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/react/components/ai-trigger-button.js +4 -6
- package/dist/react/components/ai-trigger-button.js.map +1 -1
- package/dist/react/components/recording-bar.js +4 -6
- package/dist/react/components/recording-bar.js.map +1 -1
- package/dist/react/components/wavesurfer-loader.d.ts +5 -0
- package/dist/react/components/wavesurfer-loader.js +34 -0
- package/dist/react/components/wavesurfer-loader.js.map +1 -0
- package/dist/server/adapters/nestjs/chat/ai-chat.module.d.ts +1 -1
- package/dist/server/adapters/nestjs/chat/ai-chat.module.js +3 -2
- package/dist/server/adapters/nestjs/chat/ai-chat.module.js.map +1 -1
- package/dist/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +1 -1
- package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js +10 -8
- package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js.map +1 -1
- package/dist/server/adapters/nestjs/chat/ws-loader.d.ts +5 -0
- package/dist/server/adapters/nestjs/chat/ws-loader.js +37 -0
- package/dist/server/adapters/nestjs/chat/ws-loader.js.map +1 -0
- package/dist/server/adapters/nextjs/create-ai-chat-handler.d.ts +16 -0
- package/dist/server/adapters/nextjs/create-ai-chat-handler.js +14 -3
- package/dist/server/adapters/nextjs/create-ai-chat-handler.js.map +1 -1
- package/dist/server/adapters/nextjs/filter-fallback-error.d.ts +11 -0
- package/dist/server/adapters/nextjs/filter-fallback-error.js +38 -0
- package/dist/server/adapters/nextjs/filter-fallback-error.js.map +1 -0
- package/openapi/package.json +5 -0
- package/package.json +66 -21
- package/react/langgraph/package.json +5 -0
- package/react/package.json +5 -0
- package/react/vercel/package.json +5 -0
- package/server/nestjs/package.json +5 -0
- package/server/nextjs/package.json +5 -0
- package/server/package.json +5 -0
- package/server/testing/package.json +5 -0
- package/skills/README.md +107 -0
- package/skills/building-glirastes-chat-ui/SKILL.md +378 -0
- package/skills/integrating-glirastes-nestjs/SKILL.md +346 -0
- package/skills/integrating-glirastes-nextjs/SKILL.md +306 -0
- package/skills/integrating-glirastes-nextjs-with-nestjs-backend/SKILL.md +359 -0
- package/skills/maintaining-glirastes-tools/SKILL.md +463 -0
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseJsonResponse = exports.buildClassificationPrompt = exports.classifyWithHeuristics = exports.jaccardSimilarity = exports.tokenize = exports.createIntentClassifier = exports.createModelSelectorFromMap = exports.createModelSelector = exports.createAiRouter = exports.defineModule = exports.createFollowupTool = exports.zodToCompactDescription = void 0;
|
|
4
|
+
exports.truncateToolResult = truncateToolResult;
|
|
5
|
+
exports.buildPath = buildPath;
|
|
6
|
+
exports.stripPathParams = stripPathParams;
|
|
7
|
+
exports.buildQueryString = buildQueryString;
|
|
8
|
+
exports.applyTemplateValue = applyTemplateValue;
|
|
9
|
+
exports.buildUiActionFromPattern = buildUiActionFromPattern;
|
|
10
|
+
exports.normalizeResultUiAction = normalizeResultUiAction;
|
|
11
|
+
exports.endpointToolToTool = endpointToolToTool;
|
|
12
|
+
exports.endpointToolsToRegistry = endpointToolsToRegistry;
|
|
13
|
+
exports.uiToolToTool = uiToolToTool;
|
|
14
|
+
exports.uiToolsToRegistry = uiToolsToRegistry;
|
|
15
|
+
exports.toolToAiTool = toolToAiTool;
|
|
16
|
+
exports.toolsToAiTools = toolsToAiTools;
|
|
17
|
+
exports.normalizeNodeHeaders = normalizeNodeHeaders;
|
|
18
|
+
exports.createFetchInternalApiCaller = createFetchInternalApiCaller;
|
|
19
|
+
exports.createNextInternalApiCaller = createNextInternalApiCaller;
|
|
20
|
+
exports.createExpressInternalApiCaller = createExpressInternalApiCaller;
|
|
21
|
+
const types_js_1 = require("../../types.js");
|
|
22
|
+
const zod_compact_js_1 = require("./zod-compact.js");
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Helpers (internal)
|
|
25
|
+
// ============================================================================
|
|
26
|
+
function isRecord(value) {
|
|
27
|
+
return typeof value === 'object' && value !== null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default max characters for a serialized tool result (~4000 tokens).
|
|
31
|
+
* Arrays exceeding this are truncated with a `_truncated` marker.
|
|
32
|
+
*/
|
|
33
|
+
const DEFAULT_MAX_RESULT_CHARS = 16_000;
|
|
34
|
+
/**
|
|
35
|
+
* Truncate large tool results to prevent LLM context overflow.
|
|
36
|
+
*
|
|
37
|
+
* Strategy: find the largest array in the top-level result and
|
|
38
|
+
* progressively remove items from the end until the serialized
|
|
39
|
+
* size is under the limit. A `_truncated` object is appended so the
|
|
40
|
+
* LLM knows the data was cut.
|
|
41
|
+
*/
|
|
42
|
+
function truncateToolResult(result, maxChars = DEFAULT_MAX_RESULT_CHARS) {
|
|
43
|
+
if (!isRecord(result))
|
|
44
|
+
return result;
|
|
45
|
+
const serialized = JSON.stringify(result);
|
|
46
|
+
if (serialized.length <= maxChars)
|
|
47
|
+
return result;
|
|
48
|
+
// Find the largest array at the top level
|
|
49
|
+
let largestKey = null;
|
|
50
|
+
let largestLen = 0;
|
|
51
|
+
const rec = result;
|
|
52
|
+
for (const [key, value] of Object.entries(rec)) {
|
|
53
|
+
if (Array.isArray(value) && value.length > largestLen) {
|
|
54
|
+
largestKey = key;
|
|
55
|
+
largestLen = value.length;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!largestKey || largestLen === 0)
|
|
59
|
+
return result;
|
|
60
|
+
// Binary-search for the right array length
|
|
61
|
+
const arr = rec[largestKey];
|
|
62
|
+
let lo = 1;
|
|
63
|
+
let hi = arr.length;
|
|
64
|
+
while (lo < hi) {
|
|
65
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
66
|
+
const candidate = {
|
|
67
|
+
...rec,
|
|
68
|
+
[largestKey]: arr.slice(0, mid),
|
|
69
|
+
_truncated: { field: largestKey, showing: mid, total: arr.length },
|
|
70
|
+
};
|
|
71
|
+
if (JSON.stringify(candidate).length <= maxChars) {
|
|
72
|
+
lo = mid + 1;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
hi = mid;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const finalCount = Math.max(lo - 1, 1);
|
|
79
|
+
return {
|
|
80
|
+
...rec,
|
|
81
|
+
[largestKey]: arr.slice(0, finalCount),
|
|
82
|
+
_truncated: { field: largestKey, showing: finalCount, total: arr.length },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function buildPath(pathTemplate, payload) {
|
|
86
|
+
return pathTemplate.replace(/:([A-Za-z0-9_]+)/g, (_full, paramName) => {
|
|
87
|
+
const value = payload[paramName];
|
|
88
|
+
if (value === undefined || value === null || value === '') {
|
|
89
|
+
throw new Error(`Missing required path parameter: "${paramName}" for ${pathTemplate}`);
|
|
90
|
+
}
|
|
91
|
+
delete payload[paramName];
|
|
92
|
+
return encodeURIComponent(String(value));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function stripPathParams(pathTemplate, payload) {
|
|
96
|
+
const pathParamNames = new Set();
|
|
97
|
+
for (const match of pathTemplate.matchAll(/:([A-Za-z0-9_]+)/g)) {
|
|
98
|
+
pathParamNames.add(match[1]);
|
|
99
|
+
}
|
|
100
|
+
const remaining = {};
|
|
101
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
102
|
+
if (!pathParamNames.has(key)) {
|
|
103
|
+
remaining[key] = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return remaining;
|
|
107
|
+
}
|
|
108
|
+
function buildQueryString(payload) {
|
|
109
|
+
const params = new URLSearchParams();
|
|
110
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
111
|
+
if (value === undefined || value === null || value === '')
|
|
112
|
+
continue;
|
|
113
|
+
if (Array.isArray(value)) {
|
|
114
|
+
for (const item of value) {
|
|
115
|
+
if (item === undefined || item === null || item === '')
|
|
116
|
+
continue;
|
|
117
|
+
params.append(key, String(item));
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
params.append(key, String(value));
|
|
122
|
+
}
|
|
123
|
+
const query = params.toString();
|
|
124
|
+
return query ? `?${query}` : '';
|
|
125
|
+
}
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Template Interpolation
|
|
128
|
+
// ============================================================================
|
|
129
|
+
function applyTemplateValue(value, input, responseData) {
|
|
130
|
+
if (typeof value === 'string' && value.startsWith('$')) {
|
|
131
|
+
const key = value.slice(1);
|
|
132
|
+
if (key in responseData)
|
|
133
|
+
return responseData[key];
|
|
134
|
+
if (key in input)
|
|
135
|
+
return input[key];
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
if (Array.isArray(value)) {
|
|
139
|
+
return value.map((item) => applyTemplateValue(item, input, responseData));
|
|
140
|
+
}
|
|
141
|
+
if (isRecord(value)) {
|
|
142
|
+
const output = {};
|
|
143
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
144
|
+
output[key] = applyTemplateValue(nested, input, responseData);
|
|
145
|
+
}
|
|
146
|
+
return output;
|
|
147
|
+
}
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
function buildSuccessUiAction(template, input, responseData) {
|
|
151
|
+
if (!template)
|
|
152
|
+
return undefined;
|
|
153
|
+
return applyTemplateValue(template, input, responseData);
|
|
154
|
+
}
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// UI Pattern Builders
|
|
157
|
+
// ============================================================================
|
|
158
|
+
function getNestedValue(obj, path) {
|
|
159
|
+
const parts = path.split('.');
|
|
160
|
+
let current = obj;
|
|
161
|
+
for (const part of parts) {
|
|
162
|
+
if (current === null || current === undefined)
|
|
163
|
+
return undefined;
|
|
164
|
+
if (typeof current !== 'object')
|
|
165
|
+
return undefined;
|
|
166
|
+
current = current[part];
|
|
167
|
+
}
|
|
168
|
+
return current;
|
|
169
|
+
}
|
|
170
|
+
function buildFilterAndNavigateAction(pattern, input, response) {
|
|
171
|
+
if (pattern.condition) {
|
|
172
|
+
const conditionValue = getNestedValue(response, pattern.condition) ??
|
|
173
|
+
getNestedValue(input, pattern.condition);
|
|
174
|
+
if (!conditionValue)
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
const filters = {};
|
|
178
|
+
const mapping = pattern.filterMapping ?? {};
|
|
179
|
+
const arrayFields = new Set(pattern.arrayFields ?? ['status', 'priority', 'assignee']);
|
|
180
|
+
for (const [filterKey, responseField] of Object.entries(mapping)) {
|
|
181
|
+
const value = getNestedValue(response, responseField) ??
|
|
182
|
+
getNestedValue(input, responseField);
|
|
183
|
+
if (value === undefined || value === null)
|
|
184
|
+
continue;
|
|
185
|
+
if (arrayFields.has(filterKey)) {
|
|
186
|
+
filters[filterKey] = Array.isArray(value) ? value : [value];
|
|
187
|
+
}
|
|
188
|
+
else if (typeof value === 'string') {
|
|
189
|
+
filters[filterKey] = value;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const hasFilters = Object.keys(filters).length > 0;
|
|
193
|
+
if (!hasFilters && !pattern.condition) {
|
|
194
|
+
return { type: 'navigate-and-filter', destination: pattern.target };
|
|
195
|
+
}
|
|
196
|
+
if (!hasFilters)
|
|
197
|
+
return undefined;
|
|
198
|
+
return {
|
|
199
|
+
type: 'navigate-and-filter',
|
|
200
|
+
destination: pattern.target,
|
|
201
|
+
filters,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function buildOpenDetailAction(pattern, response) {
|
|
205
|
+
const id = getNestedValue(response, pattern.idField);
|
|
206
|
+
if (!id || typeof id !== 'string')
|
|
207
|
+
return undefined;
|
|
208
|
+
return {
|
|
209
|
+
type: 'run-client-action',
|
|
210
|
+
actionId: `${pattern.entity}-details.open`,
|
|
211
|
+
payload: { [`${pattern.entity}Id`]: id },
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function buildOpenDialogAction(pattern, response) {
|
|
215
|
+
const payload = {};
|
|
216
|
+
if (pattern.idField) {
|
|
217
|
+
const id = getNestedValue(response, pattern.idField);
|
|
218
|
+
if (id && typeof id === 'string') {
|
|
219
|
+
payload.entityId = id;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
type: 'run-client-action',
|
|
224
|
+
actionId: `${pattern.dialog}-dialog.open`,
|
|
225
|
+
payload: Object.keys(payload).length > 0 ? payload : undefined,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function buildRefreshAction(pattern) {
|
|
229
|
+
return {
|
|
230
|
+
type: 'run-client-action',
|
|
231
|
+
actionId: `${pattern.target}.refresh`,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function buildToastAction(pattern, response) {
|
|
235
|
+
let message = pattern.message;
|
|
236
|
+
if (message.startsWith('$')) {
|
|
237
|
+
const fieldValue = getNestedValue(response, message.slice(1));
|
|
238
|
+
message = typeof fieldValue === 'string' ? fieldValue : pattern.message;
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
type: 'run-client-action',
|
|
242
|
+
actionId: 'toast.show',
|
|
243
|
+
payload: { message, variant: pattern.variant ?? 'default' },
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Build a uiAction from a UiPattern definition + runtime data.
|
|
248
|
+
*/
|
|
249
|
+
function buildUiActionFromPattern(pattern, input, response) {
|
|
250
|
+
switch (pattern.type) {
|
|
251
|
+
case 'filter-and-navigate':
|
|
252
|
+
return buildFilterAndNavigateAction(pattern, input, response);
|
|
253
|
+
case 'open-detail':
|
|
254
|
+
return buildOpenDetailAction(pattern, response);
|
|
255
|
+
case 'open-dialog':
|
|
256
|
+
return buildOpenDialogAction(pattern, response);
|
|
257
|
+
case 'refresh':
|
|
258
|
+
return buildRefreshAction(pattern);
|
|
259
|
+
case 'toast':
|
|
260
|
+
return buildToastAction(pattern, response);
|
|
261
|
+
default:
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Build uiActions from an array of UiPattern definitions.
|
|
267
|
+
* Filters out undefined results (patterns whose conditions were not met).
|
|
268
|
+
*/
|
|
269
|
+
function buildUiActionsFromPatterns(patterns, input, response) {
|
|
270
|
+
const results = [];
|
|
271
|
+
for (const pattern of patterns) {
|
|
272
|
+
const action = buildUiActionFromPattern(pattern, input, response);
|
|
273
|
+
if (action !== undefined) {
|
|
274
|
+
results.push(action);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return results;
|
|
278
|
+
}
|
|
279
|
+
// ============================================================================
|
|
280
|
+
// UI Action Validation
|
|
281
|
+
// ============================================================================
|
|
282
|
+
/**
|
|
283
|
+
* Validates and normalizes optional uiAction inside tool results.
|
|
284
|
+
* Invalid actions are dropped so frontend event handling stays deterministic.
|
|
285
|
+
*
|
|
286
|
+
* @param result - Tool execution result (may contain uiAction)
|
|
287
|
+
* @param uiActionSchema - Zod schema to validate against (from createUiActionSchema)
|
|
288
|
+
*/
|
|
289
|
+
function normalizeResultUiAction(result, uiActionSchema) {
|
|
290
|
+
if (!isRecord(result) || !('uiAction' in result))
|
|
291
|
+
return result;
|
|
292
|
+
if (!uiActionSchema)
|
|
293
|
+
return result; // No schema provided, pass through
|
|
294
|
+
const candidate = result.uiAction;
|
|
295
|
+
// Array of uiActions: validate each element, keep valid ones
|
|
296
|
+
if (Array.isArray(candidate)) {
|
|
297
|
+
const validActions = [];
|
|
298
|
+
for (const item of candidate) {
|
|
299
|
+
const parsed = uiActionSchema.safeParse(item);
|
|
300
|
+
if (parsed.success) {
|
|
301
|
+
validActions.push(parsed.data);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (validActions.length > 0) {
|
|
305
|
+
return { ...result, uiAction: validActions };
|
|
306
|
+
}
|
|
307
|
+
const { uiAction: _invalid, ...rest } = result;
|
|
308
|
+
return { ...rest, warning: 'All UI actions in array were invalid and dropped.' };
|
|
309
|
+
}
|
|
310
|
+
// Single uiAction: existing logic
|
|
311
|
+
const parsed = uiActionSchema.safeParse(candidate);
|
|
312
|
+
if (parsed.success) {
|
|
313
|
+
return { ...result, uiAction: parsed.data };
|
|
314
|
+
}
|
|
315
|
+
const { uiAction: _invalid, ...rest } = result;
|
|
316
|
+
return { ...rest, warning: 'Invalid UI action dropped.' };
|
|
317
|
+
}
|
|
318
|
+
// ============================================================================
|
|
319
|
+
// Endpoint Tool Definition → Tool Conversion
|
|
320
|
+
// ============================================================================
|
|
321
|
+
/**
|
|
322
|
+
* Convert an endpoint tool definition into a Tool.
|
|
323
|
+
* Uses callEndpoint from the ToolContext to execute HTTP requests.
|
|
324
|
+
*/
|
|
325
|
+
function endpointToolToTool(endpointTool) {
|
|
326
|
+
let description = endpointTool.description;
|
|
327
|
+
if (endpointTool.outputSchema) {
|
|
328
|
+
description += `\n\nReturns: ${(0, zod_compact_js_1.zodToCompactDescription)(endpointTool.outputSchema)}`;
|
|
329
|
+
}
|
|
330
|
+
return (0, types_js_1.defineTool)({
|
|
331
|
+
id: endpointTool.id,
|
|
332
|
+
description,
|
|
333
|
+
inputSchema: endpointTool.inputSchema,
|
|
334
|
+
outputSchema: endpointTool.outputSchema,
|
|
335
|
+
method: endpointTool.method,
|
|
336
|
+
needsApproval: endpointTool.needsApproval ??
|
|
337
|
+
(endpointTool.method === 'GET' ? false : true),
|
|
338
|
+
execute: async (rawInput, context) => {
|
|
339
|
+
const endpointContext = context;
|
|
340
|
+
if (!endpointContext.callEndpoint) {
|
|
341
|
+
throw new Error('EndpointToolContext with callEndpoint is required for endpoint tools.');
|
|
342
|
+
}
|
|
343
|
+
const inputPayload = isRecord(rawInput) ? { ...rawInput } : {};
|
|
344
|
+
const endpointPath = buildPath(endpointTool.path, inputPayload);
|
|
345
|
+
const requestPayload = stripPathParams(endpointTool.path, inputPayload);
|
|
346
|
+
const requestPath = endpointTool.method === 'GET' || endpointTool.method === 'DELETE'
|
|
347
|
+
? `${endpointPath}${buildQueryString(requestPayload)}`
|
|
348
|
+
: endpointPath;
|
|
349
|
+
const requestBody = endpointTool.method === 'GET' || endpointTool.method === 'DELETE'
|
|
350
|
+
? undefined
|
|
351
|
+
: Object.keys(requestPayload).length > 0
|
|
352
|
+
? requestPayload
|
|
353
|
+
: undefined;
|
|
354
|
+
const response = await endpointContext.callEndpoint({
|
|
355
|
+
method: endpointTool.method,
|
|
356
|
+
path: requestPath,
|
|
357
|
+
body: requestBody,
|
|
358
|
+
});
|
|
359
|
+
if (!response.ok) {
|
|
360
|
+
return {
|
|
361
|
+
success: false,
|
|
362
|
+
error: response.error ?? `Endpoint failed (${response.status})`,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
const responseData = isRecord(response.data)
|
|
366
|
+
? response.data
|
|
367
|
+
: { data: response.data };
|
|
368
|
+
// Priority: 1) Response uiAction, 2) uiPattern, 3) uiActionOnSuccess template
|
|
369
|
+
let uiAction;
|
|
370
|
+
if ('uiAction' in responseData && responseData.uiAction !== undefined) {
|
|
371
|
+
// Response-provided uiAction: pass through as-is (single or array)
|
|
372
|
+
if (Array.isArray(responseData.uiAction)) {
|
|
373
|
+
const filtered = responseData.uiAction.filter(isRecord);
|
|
374
|
+
uiAction = filtered.length > 0 ? filtered : undefined;
|
|
375
|
+
}
|
|
376
|
+
else if (isRecord(responseData.uiAction)) {
|
|
377
|
+
uiAction = responseData.uiAction;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
else if (endpointTool.uiPattern) {
|
|
381
|
+
if (Array.isArray(endpointTool.uiPattern)) {
|
|
382
|
+
const actions = buildUiActionsFromPatterns(endpointTool.uiPattern, inputPayload, responseData);
|
|
383
|
+
uiAction = actions.length > 0 ? actions : undefined;
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
uiAction = buildUiActionFromPattern(endpointTool.uiPattern, inputPayload, responseData);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else if (endpointTool.uiActionOnSuccess) {
|
|
390
|
+
if (Array.isArray(endpointTool.uiActionOnSuccess)) {
|
|
391
|
+
const actions = [];
|
|
392
|
+
for (const template of endpointTool.uiActionOnSuccess) {
|
|
393
|
+
const action = buildSuccessUiAction(template, inputPayload, responseData);
|
|
394
|
+
if (action)
|
|
395
|
+
actions.push(action);
|
|
396
|
+
}
|
|
397
|
+
uiAction = actions.length > 0 ? actions : undefined;
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
uiAction = buildSuccessUiAction(endpointTool.uiActionOnSuccess, inputPayload, responseData);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
success: true,
|
|
405
|
+
...responseData,
|
|
406
|
+
...(uiAction ? { uiAction } : {}),
|
|
407
|
+
};
|
|
408
|
+
},
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Convert an array of endpoint tools into a ToolRegistry.
|
|
413
|
+
*/
|
|
414
|
+
function endpointToolsToRegistry(endpointTools) {
|
|
415
|
+
const registry = {};
|
|
416
|
+
for (const endpointTool of endpointTools) {
|
|
417
|
+
if (registry[endpointTool.toolName]) {
|
|
418
|
+
throw new Error(`Duplicate endpoint toolName: ${endpointTool.toolName}`);
|
|
419
|
+
}
|
|
420
|
+
registry[endpointTool.toolName] = endpointToolToTool(endpointTool);
|
|
421
|
+
}
|
|
422
|
+
return registry;
|
|
423
|
+
}
|
|
424
|
+
// ============================================================================
|
|
425
|
+
// UI Tool Definition → Tool Conversion
|
|
426
|
+
// ============================================================================
|
|
427
|
+
function applyUiTemplateValue(value, input) {
|
|
428
|
+
if (typeof value === 'string' && value.startsWith('$')) {
|
|
429
|
+
const key = value.slice(1);
|
|
430
|
+
return key in input ? input[key] : null;
|
|
431
|
+
}
|
|
432
|
+
if (Array.isArray(value)) {
|
|
433
|
+
return value.map((item) => applyUiTemplateValue(item, input));
|
|
434
|
+
}
|
|
435
|
+
if (isRecord(value)) {
|
|
436
|
+
const output = {};
|
|
437
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
438
|
+
output[key] = applyUiTemplateValue(nested, input);
|
|
439
|
+
}
|
|
440
|
+
return output;
|
|
441
|
+
}
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Convert a UI tool definition into a Tool.
|
|
446
|
+
* UI tools never call external services — they only produce uiActions.
|
|
447
|
+
*/
|
|
448
|
+
function uiToolToTool(uiTool) {
|
|
449
|
+
let description = uiTool.description;
|
|
450
|
+
if (uiTool.outputSchema) {
|
|
451
|
+
description += `\n\nReturns: ${(0, zod_compact_js_1.zodToCompactDescription)(uiTool.outputSchema)}`;
|
|
452
|
+
}
|
|
453
|
+
return (0, types_js_1.defineTool)({
|
|
454
|
+
id: uiTool.id,
|
|
455
|
+
description,
|
|
456
|
+
inputSchema: uiTool.inputSchema,
|
|
457
|
+
outputSchema: uiTool.outputSchema,
|
|
458
|
+
needsApproval: uiTool.needsApproval ?? false,
|
|
459
|
+
execute: async (rawInput) => {
|
|
460
|
+
const inputPayload = isRecord(rawInput) ? { ...rawInput } : {};
|
|
461
|
+
// Priority: 1) uiPattern (dynamic), 2) uiAction (static template)
|
|
462
|
+
let uiAction;
|
|
463
|
+
if (uiTool.uiPattern) {
|
|
464
|
+
if (Array.isArray(uiTool.uiPattern)) {
|
|
465
|
+
const actions = buildUiActionsFromPatterns(uiTool.uiPattern, inputPayload, {});
|
|
466
|
+
uiAction = actions.length > 0 ? actions : undefined;
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
uiAction = buildUiActionFromPattern(uiTool.uiPattern, inputPayload, {});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
else if (uiTool.uiAction) {
|
|
473
|
+
if (Array.isArray(uiTool.uiAction)) {
|
|
474
|
+
const actions = [];
|
|
475
|
+
for (const template of uiTool.uiAction) {
|
|
476
|
+
const resolved = applyUiTemplateValue(template, inputPayload);
|
|
477
|
+
if (resolved)
|
|
478
|
+
actions.push(resolved);
|
|
479
|
+
}
|
|
480
|
+
uiAction = actions.length > 0 ? actions : undefined;
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
uiAction = applyUiTemplateValue(uiTool.uiAction, inputPayload);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
const message = uiTool.successMessage
|
|
487
|
+
? applyUiTemplateValue(uiTool.successMessage, inputPayload) || 'Action executed.'
|
|
488
|
+
: 'Action executed.';
|
|
489
|
+
return {
|
|
490
|
+
success: true,
|
|
491
|
+
message,
|
|
492
|
+
...(uiAction ? { uiAction } : {}),
|
|
493
|
+
};
|
|
494
|
+
},
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Convert an array of UI tools into a ToolRegistry.
|
|
499
|
+
*/
|
|
500
|
+
function uiToolsToRegistry(uiTools) {
|
|
501
|
+
const registry = {};
|
|
502
|
+
for (const uiTool of uiTools) {
|
|
503
|
+
if (registry[uiTool.toolName]) {
|
|
504
|
+
throw new Error(`Duplicate UI toolName: ${uiTool.toolName}`);
|
|
505
|
+
}
|
|
506
|
+
registry[uiTool.toolName] = uiToolToTool(uiTool);
|
|
507
|
+
}
|
|
508
|
+
return registry;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Convert a Tool to an AI SDK-compatible tool object.
|
|
512
|
+
*
|
|
513
|
+
* Returns a plain object with `description`, `parameters`, `execute` that
|
|
514
|
+
* can be passed to any AI SDK that follows the Vercel AI SDK convention.
|
|
515
|
+
*
|
|
516
|
+
* @param tool - The tool to convert
|
|
517
|
+
* @param context - Runtime context (currentDate, locale, runtime)
|
|
518
|
+
* @param toolName - Override tool name (defaults to tool.id)
|
|
519
|
+
* @param options - Additional options
|
|
520
|
+
*/
|
|
521
|
+
function toolToAiTool(tool, context, toolName, options) {
|
|
522
|
+
const name = toolName ?? tool.id;
|
|
523
|
+
const needsApproval = tool.needsApproval;
|
|
524
|
+
const requiresApproval = !!needsApproval;
|
|
525
|
+
return {
|
|
526
|
+
_toolId: tool.id,
|
|
527
|
+
description: tool.description,
|
|
528
|
+
parameters: tool.inputSchema,
|
|
529
|
+
needsApproval: requiresApproval
|
|
530
|
+
? async (input) => {
|
|
531
|
+
const needed = typeof needsApproval === 'boolean'
|
|
532
|
+
? needsApproval
|
|
533
|
+
: await needsApproval(input, context);
|
|
534
|
+
if (needed) {
|
|
535
|
+
options?.onAudit?.({
|
|
536
|
+
type: 'approval.requested',
|
|
537
|
+
timestamp: new Date().toISOString(),
|
|
538
|
+
sessionId: options.sessionId ?? '',
|
|
539
|
+
source: 'server-core',
|
|
540
|
+
details: {
|
|
541
|
+
toolId: tool.id,
|
|
542
|
+
toolName: name,
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
return needed;
|
|
547
|
+
}
|
|
548
|
+
: undefined,
|
|
549
|
+
execute: async (input) => {
|
|
550
|
+
const startTime = Date.now();
|
|
551
|
+
try {
|
|
552
|
+
const result = await tool.execute(input, context);
|
|
553
|
+
// Audit: tool executed successfully
|
|
554
|
+
options?.onAudit?.({
|
|
555
|
+
type: 'tool.executed',
|
|
556
|
+
timestamp: new Date().toISOString(),
|
|
557
|
+
sessionId: options.sessionId ?? '',
|
|
558
|
+
source: 'server-core',
|
|
559
|
+
details: {
|
|
560
|
+
toolId: tool.id,
|
|
561
|
+
toolName: name,
|
|
562
|
+
method: tool.method,
|
|
563
|
+
latencyMs: Date.now() - startTime,
|
|
564
|
+
success: true,
|
|
565
|
+
approvalRequired: !!requiresApproval,
|
|
566
|
+
},
|
|
567
|
+
});
|
|
568
|
+
// Output schema: parse to strip extra fields, re-attach uiAction for client
|
|
569
|
+
let cleanResult = result;
|
|
570
|
+
if (tool.outputSchema &&
|
|
571
|
+
isRecord(result) &&
|
|
572
|
+
result.success !== false) {
|
|
573
|
+
const parsed = tool.outputSchema.safeParse(result);
|
|
574
|
+
if (parsed.success) {
|
|
575
|
+
// Use parsed data (extra fields stripped by Zod)
|
|
576
|
+
const rec = result;
|
|
577
|
+
cleanResult = {
|
|
578
|
+
...parsed.data,
|
|
579
|
+
// Preserve success flag
|
|
580
|
+
...(rec.success !== undefined ? { success: rec.success } : {}),
|
|
581
|
+
// Re-attach uiAction for client stream (stripped by schema parse)
|
|
582
|
+
...(rec.uiAction ? { uiAction: rec.uiAction } : {}),
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
// Schema mismatch — warn but pass through unmodified
|
|
587
|
+
console.warn(`[glirastes] Output schema mismatch for tool "${name}":`, parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`));
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
// Truncate large arrays to prevent context overflow
|
|
591
|
+
cleanResult = truncateToolResult(cleanResult);
|
|
592
|
+
return options?.uiActionSchema
|
|
593
|
+
? normalizeResultUiAction(cleanResult, options.uiActionSchema)
|
|
594
|
+
: cleanResult;
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
// Audit: tool execution failed
|
|
598
|
+
options?.onAudit?.({
|
|
599
|
+
type: 'tool.failed',
|
|
600
|
+
timestamp: new Date().toISOString(),
|
|
601
|
+
sessionId: options.sessionId ?? '',
|
|
602
|
+
source: 'server-core',
|
|
603
|
+
details: {
|
|
604
|
+
toolId: tool.id,
|
|
605
|
+
toolName: name,
|
|
606
|
+
error: error instanceof Error ? error.message : String(error),
|
|
607
|
+
latencyMs: Date.now() - startTime,
|
|
608
|
+
},
|
|
609
|
+
});
|
|
610
|
+
options?.onError?.(tool.id, error);
|
|
611
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
612
|
+
return normalizeResultUiAction({
|
|
613
|
+
error: `Error in ${tool.id}: ${errorMessage}`,
|
|
614
|
+
hint: 'Check the parameters and try again.',
|
|
615
|
+
}, options?.uiActionSchema);
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Forward an audit event to the remote telemetry sink (fire-and-forget).
|
|
622
|
+
*/
|
|
623
|
+
function forwardToTelemetry(telemetry, event, traceId) {
|
|
624
|
+
try {
|
|
625
|
+
telemetry.emit({
|
|
626
|
+
eventType: event.type,
|
|
627
|
+
traceId: traceId ?? event.sessionId,
|
|
628
|
+
toolId: (event.details?.toolId ?? event.details?.toolName),
|
|
629
|
+
latencyMs: event.details?.latencyMs,
|
|
630
|
+
timestamp: event.timestamp,
|
|
631
|
+
payload: event.details,
|
|
632
|
+
actor: { sessionId: event.sessionId },
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
catch {
|
|
636
|
+
// Telemetry is fire-and-forget, never block tool execution
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Wrap options to auto-forward audit events to remote telemetry.
|
|
641
|
+
* Returns options with an augmented `onAudit` that calls both
|
|
642
|
+
* the original callback and the telemetry sink.
|
|
643
|
+
*/
|
|
644
|
+
function withTelemetryForwarding(options) {
|
|
645
|
+
if (!options?.telemetry)
|
|
646
|
+
return options;
|
|
647
|
+
const { telemetry, onAudit: originalOnAudit } = options;
|
|
648
|
+
return {
|
|
649
|
+
...options,
|
|
650
|
+
onAudit: (event) => {
|
|
651
|
+
originalOnAudit?.(event);
|
|
652
|
+
forwardToTelemetry(telemetry, event, options.traceId);
|
|
653
|
+
},
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Convert a registry of tools to AI SDK tools.
|
|
658
|
+
* The SDK does not perform authorization — the backend API that each tool
|
|
659
|
+
* calls is responsible for permission enforcement.
|
|
660
|
+
*/
|
|
661
|
+
function toolsToAiTools(registry, context, options) {
|
|
662
|
+
const resolvedOptions = withTelemetryForwarding(options);
|
|
663
|
+
const tools = {};
|
|
664
|
+
for (const [name, tool] of Object.entries(registry)) {
|
|
665
|
+
tools[name] = toolToAiTool(tool, context, name, resolvedOptions);
|
|
666
|
+
}
|
|
667
|
+
return tools;
|
|
668
|
+
}
|
|
669
|
+
// ============================================================================
|
|
670
|
+
// Transport Adapters
|
|
671
|
+
// ============================================================================
|
|
672
|
+
function toErrorMessage(data, fallback) {
|
|
673
|
+
if (typeof data === 'string' && data.trim())
|
|
674
|
+
return data;
|
|
675
|
+
if (isRecord(data)) {
|
|
676
|
+
// NestJS ValidationPipe returns: { statusCode, message: string[], error: "Bad Request" }
|
|
677
|
+
// Prefer the detailed message(s) over the generic error string.
|
|
678
|
+
const message = data.message;
|
|
679
|
+
if (Array.isArray(message) && message.length > 0) {
|
|
680
|
+
const details = message
|
|
681
|
+
.filter((m) => typeof m === 'string' && m.trim().length > 0)
|
|
682
|
+
.join('; ');
|
|
683
|
+
if (details) {
|
|
684
|
+
const prefix = typeof data.error === 'string' && data.error.trim()
|
|
685
|
+
? `${data.error}: `
|
|
686
|
+
: '';
|
|
687
|
+
return `${prefix}${details}`;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (typeof message === 'string' && message.trim())
|
|
691
|
+
return message;
|
|
692
|
+
if (typeof data.error === 'string' && data.error.trim())
|
|
693
|
+
return data.error;
|
|
694
|
+
}
|
|
695
|
+
return fallback;
|
|
696
|
+
}
|
|
697
|
+
async function parseResponseBody(response) {
|
|
698
|
+
const contentType = response.headers.get('content-type') || '';
|
|
699
|
+
if (contentType.includes('application/json')) {
|
|
700
|
+
try {
|
|
701
|
+
return await response.json();
|
|
702
|
+
}
|
|
703
|
+
catch {
|
|
704
|
+
return undefined;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
const text = await response.text();
|
|
708
|
+
return text.length > 0 ? text : undefined;
|
|
709
|
+
}
|
|
710
|
+
function normalizeNodeHeaders(headers, allowedHeaderNames) {
|
|
711
|
+
const allowlist = allowedHeaderNames
|
|
712
|
+
? new Set(allowedHeaderNames.map((n) => n.toLowerCase()))
|
|
713
|
+
: undefined;
|
|
714
|
+
const normalized = {};
|
|
715
|
+
for (const [rawName, rawValue] of Object.entries(headers)) {
|
|
716
|
+
const name = rawName.toLowerCase();
|
|
717
|
+
if (allowlist && !allowlist.has(name))
|
|
718
|
+
continue;
|
|
719
|
+
if (rawValue === undefined)
|
|
720
|
+
continue;
|
|
721
|
+
if (Array.isArray(rawValue)) {
|
|
722
|
+
normalized[name] = rawValue.join(name === 'cookie' ? '; ' : ', ');
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
normalized[name] = rawValue;
|
|
726
|
+
}
|
|
727
|
+
return normalized;
|
|
728
|
+
}
|
|
729
|
+
function createFetchInternalApiCaller(options) {
|
|
730
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
731
|
+
return async (request) => {
|
|
732
|
+
const url = new URL(request.path, options.baseUrl).toString();
|
|
733
|
+
const methodAllowsBody = request.method !== 'GET' && request.method !== 'DELETE';
|
|
734
|
+
const headers = {
|
|
735
|
+
...(options.defaultHeaders ?? {}),
|
|
736
|
+
};
|
|
737
|
+
const init = { method: request.method, headers };
|
|
738
|
+
if (methodAllowsBody && request.body !== undefined) {
|
|
739
|
+
if (!headers['content-type']) {
|
|
740
|
+
headers['content-type'] = 'application/json';
|
|
741
|
+
}
|
|
742
|
+
init.body = JSON.stringify(request.body);
|
|
743
|
+
}
|
|
744
|
+
const response = await fetchImpl(url, init);
|
|
745
|
+
const data = await parseResponseBody(response);
|
|
746
|
+
if (!response.ok) {
|
|
747
|
+
return {
|
|
748
|
+
ok: false,
|
|
749
|
+
status: response.status,
|
|
750
|
+
data,
|
|
751
|
+
error: toErrorMessage(data, `Endpoint failed (${response.status})`),
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
return { ok: true, status: response.status, data };
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function createNextInternalApiCaller(options) {
|
|
758
|
+
const headers = {
|
|
759
|
+
...(options.defaultHeaders ?? {}),
|
|
760
|
+
};
|
|
761
|
+
if (options.cookieHeader)
|
|
762
|
+
headers.cookie = options.cookieHeader;
|
|
763
|
+
return createFetchInternalApiCaller({
|
|
764
|
+
baseUrl: options.origin,
|
|
765
|
+
fetchImpl: options.fetchImpl,
|
|
766
|
+
defaultHeaders: headers,
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
function createExpressInternalApiCaller(options) {
|
|
770
|
+
const forwardHeaderNames = options.forwardHeaderNames ?? [
|
|
771
|
+
'cookie',
|
|
772
|
+
'authorization',
|
|
773
|
+
'x-request-id',
|
|
774
|
+
];
|
|
775
|
+
const forwardedHeaders = options.reqHeaders
|
|
776
|
+
? normalizeNodeHeaders(options.reqHeaders, forwardHeaderNames)
|
|
777
|
+
: {};
|
|
778
|
+
return createFetchInternalApiCaller({
|
|
779
|
+
baseUrl: options.baseUrl,
|
|
780
|
+
fetchImpl: options.fetchImpl,
|
|
781
|
+
defaultHeaders: {
|
|
782
|
+
...forwardedHeaders,
|
|
783
|
+
...(options.defaultHeaders ?? {}),
|
|
784
|
+
},
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
// ============================================================================
|
|
788
|
+
// Re-exports
|
|
789
|
+
// ============================================================================
|
|
790
|
+
var zod_compact_js_2 = require("./zod-compact.js");
|
|
791
|
+
Object.defineProperty(exports, "zodToCompactDescription", { enumerable: true, get: function () { return zod_compact_js_2.zodToCompactDescription; } });
|
|
792
|
+
// ============================================================================
|
|
793
|
+
// Followup Tool
|
|
794
|
+
// ============================================================================
|
|
795
|
+
var followup_tool_js_1 = require("./followup-tool.js");
|
|
796
|
+
Object.defineProperty(exports, "createFollowupTool", { enumerable: true, get: function () { return followup_tool_js_1.createFollowupTool; } });
|
|
797
|
+
// ============================================================================
|
|
798
|
+
// Module Routing
|
|
799
|
+
// ============================================================================
|
|
800
|
+
var module_router_js_1 = require("./module-router.js");
|
|
801
|
+
Object.defineProperty(exports, "defineModule", { enumerable: true, get: function () { return module_router_js_1.defineModule; } });
|
|
802
|
+
Object.defineProperty(exports, "createAiRouter", { enumerable: true, get: function () { return module_router_js_1.createAiRouter; } });
|
|
803
|
+
// ============================================================================
|
|
804
|
+
// Model Selection
|
|
805
|
+
// ============================================================================
|
|
806
|
+
var model_selector_js_1 = require("./model-selector.js");
|
|
807
|
+
Object.defineProperty(exports, "createModelSelector", { enumerable: true, get: function () { return model_selector_js_1.createModelSelector; } });
|
|
808
|
+
Object.defineProperty(exports, "createModelSelectorFromMap", { enumerable: true, get: function () { return model_selector_js_1.createModelSelectorFromMap; } });
|
|
809
|
+
// ============================================================================
|
|
810
|
+
// Intent Classification
|
|
811
|
+
// ============================================================================
|
|
812
|
+
var intent_classifier_js_1 = require("./intent-classifier.js");
|
|
813
|
+
Object.defineProperty(exports, "createIntentClassifier", { enumerable: true, get: function () { return intent_classifier_js_1.createIntentClassifier; } });
|
|
814
|
+
Object.defineProperty(exports, "tokenize", { enumerable: true, get: function () { return intent_classifier_js_1.tokenize; } });
|
|
815
|
+
Object.defineProperty(exports, "jaccardSimilarity", { enumerable: true, get: function () { return intent_classifier_js_1.jaccardSimilarity; } });
|
|
816
|
+
Object.defineProperty(exports, "classifyWithHeuristics", { enumerable: true, get: function () { return intent_classifier_js_1.classifyWithHeuristics; } });
|
|
817
|
+
Object.defineProperty(exports, "buildClassificationPrompt", { enumerable: true, get: function () { return intent_classifier_js_1.buildClassificationPrompt; } });
|
|
818
|
+
Object.defineProperty(exports, "parseJsonResponse", { enumerable: true, get: function () { return intent_classifier_js_1.parseJsonResponse; } });
|