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,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRestSessionBridge = createRestSessionBridge;
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Defaults
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null;
|
|
9
|
+
}
|
|
10
|
+
function pickString(row, ...keys) {
|
|
11
|
+
for (const key of keys) {
|
|
12
|
+
const v = row[key];
|
|
13
|
+
if (typeof v === 'string')
|
|
14
|
+
return v;
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
function pickDate(row, ...keys) {
|
|
19
|
+
for (const key of keys) {
|
|
20
|
+
const v = row[key];
|
|
21
|
+
if (typeof v === 'string' || typeof v === 'number')
|
|
22
|
+
return v;
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
function pickNumber(row, ...keys) {
|
|
27
|
+
for (const key of keys) {
|
|
28
|
+
const v = row[key];
|
|
29
|
+
if (typeof v === 'number')
|
|
30
|
+
return v;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
function defaultMapSession(row) {
|
|
35
|
+
if (!isRecord(row)) {
|
|
36
|
+
return { id: '', title: 'Untitled' };
|
|
37
|
+
}
|
|
38
|
+
const id = pickString(row, 'id', 'sessionId', 'session_id') ?? '';
|
|
39
|
+
const title = pickString(row, 'title', 'name') ?? 'New chat';
|
|
40
|
+
const createdAt = pickDate(row, 'createdAt', 'created_at');
|
|
41
|
+
const updatedAt = pickDate(row, 'updatedAt', 'updated_at');
|
|
42
|
+
const messageCount = pickNumber(row, 'messageCount', 'message_count');
|
|
43
|
+
const status = pickString(row, 'status');
|
|
44
|
+
return {
|
|
45
|
+
id,
|
|
46
|
+
title,
|
|
47
|
+
createdAt,
|
|
48
|
+
updatedAt,
|
|
49
|
+
messageCount,
|
|
50
|
+
status: status === 'active' || status === 'archived' ? status : status,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function defaultMapMessage(row) {
|
|
54
|
+
if (!isRecord(row))
|
|
55
|
+
return null;
|
|
56
|
+
const id = pickString(row, 'id') ?? '';
|
|
57
|
+
const role = (pickString(row, 'role') ?? 'user');
|
|
58
|
+
const content = pickString(row, 'content', 'text') ?? null;
|
|
59
|
+
const createdAtRaw = row.createdAt ?? row.created_at;
|
|
60
|
+
return {
|
|
61
|
+
id,
|
|
62
|
+
role,
|
|
63
|
+
content,
|
|
64
|
+
createdAt: typeof createdAtRaw === 'string' ||
|
|
65
|
+
typeof createdAtRaw === 'number' ||
|
|
66
|
+
createdAtRaw instanceof Date
|
|
67
|
+
? createdAtRaw
|
|
68
|
+
: undefined,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function resolveHeaders(headers) {
|
|
72
|
+
if (!headers)
|
|
73
|
+
return {};
|
|
74
|
+
if (typeof headers === 'function')
|
|
75
|
+
return await headers();
|
|
76
|
+
return headers;
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Factory
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
/**
|
|
82
|
+
* Build a `SessionConfig` from a standard REST chat backend.
|
|
83
|
+
*
|
|
84
|
+
* The factory wires the five session hooks (`list`, `load`, `create`,
|
|
85
|
+
* `remove`, `rename`) to a conventional REST layout:
|
|
86
|
+
*
|
|
87
|
+
* | Hook | Request |
|
|
88
|
+
* |----------|--------------------------------------------|
|
|
89
|
+
* | `list` | `GET {baseUrl}` |
|
|
90
|
+
* | `load` | `GET {baseUrl}/{id}{messagesPath}` |
|
|
91
|
+
* | `create` | `POST {baseUrl}` with `createBody(opts)` |
|
|
92
|
+
* | `remove` | `DELETE {baseUrl}/{id}` (or PATCH via `removeRequest`) |
|
|
93
|
+
* | `rename` | `PATCH {baseUrl}/{id}` with `{ title }` |
|
|
94
|
+
*
|
|
95
|
+
* All field-name mapping is done through `mapSession` / `mapMessage`,
|
|
96
|
+
* which have defaults that tolerate both `snake_case` and `camelCase`.
|
|
97
|
+
* For anything exotic (different status codes, non-JSON bodies, etc.),
|
|
98
|
+
* pass `request` and take over the transport entirely.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* // Chaingrow — uses archive-instead-of-delete and a non-standard create body
|
|
103
|
+
* export const chainGrowSessions = createRestSessionBridge({
|
|
104
|
+
* baseUrl: `${API_URL}/chat/sessions`,
|
|
105
|
+
* headers: () => ({ Authorization: `Bearer ${authStore.getState().token}` }),
|
|
106
|
+
* createBody: () => ({ execution_types: ['chat'] }),
|
|
107
|
+
* removeRequest: () => ({ method: 'PATCH', body: { status: 'archived' } }),
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
function createRestSessionBridge(options) {
|
|
112
|
+
const { baseUrl, headers, credentials = 'same-origin', fetchFn, request: customRequest, createBody = ({ title }) => (title ? { title } : {}), removeRequest = () => ({
|
|
113
|
+
method: 'DELETE',
|
|
114
|
+
body: undefined,
|
|
115
|
+
}), messagesPath = '/messages', mapSession = defaultMapSession, mapMessage = defaultMapMessage, listQuery, } = options;
|
|
116
|
+
const doFetch = fetchFn ??
|
|
117
|
+
(typeof globalThis !== 'undefined' && globalThis.fetch);
|
|
118
|
+
const request = customRequest
|
|
119
|
+
? customRequest
|
|
120
|
+
: async ({ method, url, body, }) => {
|
|
121
|
+
if (!doFetch) {
|
|
122
|
+
throw new Error('[createRestSessionBridge] No `fetch` available. Pass `fetchFn` or `request`.');
|
|
123
|
+
}
|
|
124
|
+
const mergedHeaders = {
|
|
125
|
+
Accept: 'application/json',
|
|
126
|
+
...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
|
|
127
|
+
...(await resolveHeaders(headers)),
|
|
128
|
+
};
|
|
129
|
+
const res = await doFetch(url, {
|
|
130
|
+
method,
|
|
131
|
+
credentials,
|
|
132
|
+
headers: mergedHeaders,
|
|
133
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
134
|
+
});
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
throw new Error(`[createRestSessionBridge] ${method} ${url} → HTTP ${res.status}`);
|
|
137
|
+
}
|
|
138
|
+
if (res.status === 204)
|
|
139
|
+
return undefined;
|
|
140
|
+
const text = await res.text();
|
|
141
|
+
if (!text)
|
|
142
|
+
return undefined;
|
|
143
|
+
try {
|
|
144
|
+
return JSON.parse(text);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return text;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const buildListUrl = () => {
|
|
151
|
+
if (!listQuery)
|
|
152
|
+
return baseUrl;
|
|
153
|
+
const params = listQuery();
|
|
154
|
+
const entries = Object.entries(params).filter(([, v]) => v !== undefined);
|
|
155
|
+
if (entries.length === 0)
|
|
156
|
+
return baseUrl;
|
|
157
|
+
const qs = entries
|
|
158
|
+
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
|
|
159
|
+
.join('&');
|
|
160
|
+
const sep = baseUrl.includes('?') ? '&' : '?';
|
|
161
|
+
return `${baseUrl}${sep}${qs}`;
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
list: async () => {
|
|
165
|
+
const rows = await request({ method: 'GET', url: buildListUrl() });
|
|
166
|
+
if (!Array.isArray(rows))
|
|
167
|
+
return [];
|
|
168
|
+
return rows.map(mapSession);
|
|
169
|
+
},
|
|
170
|
+
load: async (id) => {
|
|
171
|
+
const rows = await request({
|
|
172
|
+
method: 'GET',
|
|
173
|
+
url: `${baseUrl}/${encodeURIComponent(id)}${messagesPath}`,
|
|
174
|
+
});
|
|
175
|
+
// Some APIs wrap messages in `{ messages: [...] }`; unwrap if needed.
|
|
176
|
+
const list = Array.isArray(rows)
|
|
177
|
+
? rows
|
|
178
|
+
: isRecord(rows) && Array.isArray(rows.messages)
|
|
179
|
+
? rows.messages
|
|
180
|
+
: [];
|
|
181
|
+
return list
|
|
182
|
+
.map(mapMessage)
|
|
183
|
+
.filter((m) => m !== null);
|
|
184
|
+
},
|
|
185
|
+
create: async (opts = {}) => {
|
|
186
|
+
const created = await request({
|
|
187
|
+
method: 'POST',
|
|
188
|
+
url: baseUrl,
|
|
189
|
+
body: createBody(opts),
|
|
190
|
+
});
|
|
191
|
+
return mapSession(created);
|
|
192
|
+
},
|
|
193
|
+
remove: async (id) => {
|
|
194
|
+
const { method, body } = removeRequest(id);
|
|
195
|
+
await request({
|
|
196
|
+
method,
|
|
197
|
+
url: `${baseUrl}/${encodeURIComponent(id)}`,
|
|
198
|
+
body,
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
rename: async (id, title) => {
|
|
202
|
+
await request({
|
|
203
|
+
method: 'PATCH',
|
|
204
|
+
url: `${baseUrl}/${encodeURIComponent(id)}`,
|
|
205
|
+
body: { title },
|
|
206
|
+
});
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import '../styles.css';
|
|
2
|
+
import type { AiChatPanelProps } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Batteries-included chat panel.
|
|
5
|
+
*
|
|
6
|
+
* Composes MessageList, ChatInput/MentionInput, SuggestionBar,
|
|
7
|
+
* approval cards, truncation banner, and typing indicator
|
|
8
|
+
* into a complete chat UI.
|
|
9
|
+
*
|
|
10
|
+
* Uses configuration from the parent `<AiChatProvider>`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function AiChatPanel({ className, welcomeMessage }: AiChatPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AiChatPanel = AiChatPanel;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
require("../styles.css");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
8
|
+
const message_list_js_1 = require("./message-list.js");
|
|
9
|
+
const chat_input_js_1 = require("./chat-input.js");
|
|
10
|
+
const mention_input_js_1 = require("./mention-input.js");
|
|
11
|
+
const suggestion_bar_js_1 = require("./suggestion-bar.js");
|
|
12
|
+
const approval_card_js_1 = require("./approval-card.js");
|
|
13
|
+
const bulk_approval_card_js_1 = require("./bulk-approval-card.js");
|
|
14
|
+
const pipeline_timeline_js_1 = require("./pipeline-timeline.js");
|
|
15
|
+
/**
|
|
16
|
+
* Batteries-included chat panel.
|
|
17
|
+
*
|
|
18
|
+
* Composes MessageList, ChatInput/MentionInput, SuggestionBar,
|
|
19
|
+
* approval cards, truncation banner, and typing indicator
|
|
20
|
+
* into a complete chat UI.
|
|
21
|
+
*
|
|
22
|
+
* Uses configuration from the parent `<AiChatProvider>`.
|
|
23
|
+
*/
|
|
24
|
+
function AiChatPanel({ className, welcomeMessage }) {
|
|
25
|
+
const { classNames, hasMentions, locale, isLoading, stop, error, messages, pipelineSteps, pipelineState, pendingApprovals, approve, reject, isProcessingApproval, truncation, continueTruncation, dismissTruncation, components, themeVars, themeEffect, } = (0, chat_context_js_1.useChatContext)();
|
|
26
|
+
const ApprovalCardComponent = components.ApprovalCard ?? approval_card_js_1.ApprovalCard;
|
|
27
|
+
const BulkApprovalCardComponent = components.BulkApprovalCard ?? bulk_approval_card_js_1.BulkApprovalCard;
|
|
28
|
+
const PipelineTimelineComponent = components.PipelineTimeline ?? pipeline_timeline_js_1.PipelineTimeline;
|
|
29
|
+
const InputComponent = components.ChatInput ?? (hasMentions ? mention_input_js_1.MentionInput : chat_input_js_1.ChatInput);
|
|
30
|
+
// Group approvals by tool name for bulk operations
|
|
31
|
+
const { singleApprovals, bulkGroups } = (0, react_1.useMemo)(() => {
|
|
32
|
+
const groups = new Map();
|
|
33
|
+
for (const approval of pendingApprovals) {
|
|
34
|
+
const existing = groups.get(approval.toolName) ?? [];
|
|
35
|
+
existing.push(approval);
|
|
36
|
+
groups.set(approval.toolName, existing);
|
|
37
|
+
}
|
|
38
|
+
const singles = [];
|
|
39
|
+
const bulks = [];
|
|
40
|
+
for (const [, approvals] of groups) {
|
|
41
|
+
if (approvals.length === 1) {
|
|
42
|
+
singles.push(approvals[0]);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
bulks.push(approvals);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { singleApprovals: singles, bulkGroups: bulks };
|
|
49
|
+
}, [pendingApprovals]);
|
|
50
|
+
// Check if last assistant message has visible text (for typing indicator)
|
|
51
|
+
const showTypingIndicator = (0, react_1.useMemo)(() => {
|
|
52
|
+
if (!isLoading)
|
|
53
|
+
return false;
|
|
54
|
+
const lastAssistant = [...messages].reverse().find(m => m.role === 'assistant');
|
|
55
|
+
if (!lastAssistant)
|
|
56
|
+
return true;
|
|
57
|
+
const hasText = lastAssistant.parts.some(p => 'text' in p && typeof p.text === 'string' && p.text.trim().length > 0);
|
|
58
|
+
return !hasText;
|
|
59
|
+
}, [isLoading, messages]);
|
|
60
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: className ?? classNames.panel, "data-component": "ai-chat-panel", "data-state": isLoading ? 'loading' : 'idle', "data-theme-effect": themeEffect, style: themeVars, children: [error && ((0, jsx_runtime_1.jsx)("div", { "data-component": "error-banner", role: "alert", children: locale.errorMessage })), (0, jsx_runtime_1.jsx)(PipelineTimelineComponent, { steps: pipelineSteps, pipelineState: pipelineState, isLoading: isLoading, onStop: stop }), messages.length > 0 ? ((0, jsx_runtime_1.jsx)(message_list_js_1.MessageList, {})) : welcomeMessage ? ((0, jsx_runtime_1.jsx)("div", { "data-component": "message-list", children: (0, jsx_runtime_1.jsx)("div", { "data-component": "message-bubble", "data-role": "assistant", children: (0, jsx_runtime_1.jsx)("div", { "data-element": "content", children: welcomeMessage }) }) })) : ((0, jsx_runtime_1.jsx)("div", { "data-component": "empty-state", children: locale.emptyState })), singleApprovals.map((approval) => ((0, jsx_runtime_1.jsx)(ApprovalCardComponent, { approval: approval, onApprove: approve, onReject: reject, isProcessing: isProcessingApproval }, approval.id))), bulkGroups.map((group) => ((0, jsx_runtime_1.jsx)(BulkApprovalCardComponent, { toolName: group[0].toolName, approvals: group, onApproveAll: () => {
|
|
61
|
+
for (const a of group)
|
|
62
|
+
approve(a.id);
|
|
63
|
+
}, onRejectAll: () => {
|
|
64
|
+
for (const a of group)
|
|
65
|
+
reject(a.id);
|
|
66
|
+
}, isProcessing: isProcessingApproval }, `bulk-${group[0].toolName}`))), showTypingIndicator && ((0, jsx_runtime_1.jsxs)("div", { "data-component": "typing-indicator", children: [(0, jsx_runtime_1.jsx)("span", { "data-element": "dot" }), (0, jsx_runtime_1.jsx)("span", { "data-element": "dot" }), (0, jsx_runtime_1.jsx)("span", { "data-element": "dot" })] })), truncation && !isLoading && ((0, jsx_runtime_1.jsxs)("div", { "data-component": "truncation-banner", children: [(0, jsx_runtime_1.jsx)("p", { "data-element": "message", children: truncation.message }), (0, jsx_runtime_1.jsxs)("div", { "data-element": "actions", children: [(0, jsx_runtime_1.jsx)("button", { onClick: continueTruncation, "data-action": "continue", children: locale.continueButton }), (0, jsx_runtime_1.jsx)("button", { onClick: dismissTruncation, "data-action": "dismiss", children: locale.dismissButton })] })] })), !isLoading && !showTypingIndicator && (0, jsx_runtime_1.jsx)(suggestion_bar_js_1.SuggestionBar, {}), (0, jsx_runtime_1.jsx)(InputComponent, {})] }));
|
|
67
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { AiTriggerButtonProps } from '../types.js';
|
|
2
|
+
export declare function AiTriggerButton({ onClickChat, onClickMic, isRecording, isConnecting, onStopRecording, onCancelRecording, portal, className, buttonClassName, renderWrapper, draggable, persistPosition, ariaLabel, micAriaLabel, stopAriaLabel, cancelAriaLabel, showMic, icon, }: AiTriggerButtonProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AiTriggerButton = AiTriggerButton;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const react_dom_1 = require("react-dom");
|
|
7
|
+
const recording_controls_js_1 = require("./recording-controls.js");
|
|
8
|
+
const use_draggable_position_js_1 = require("../hooks/use-draggable-position.js");
|
|
9
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
10
|
+
const wavesurfer_loader_js_1 = require("./wavesurfer-loader.js");
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Inline SVG icons (no lucide-react dependency)
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
function SparklesIcon() {
|
|
15
|
+
return ((0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("path", { d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" }), (0, jsx_runtime_1.jsx)("path", { d: "M20 3v4" }), (0, jsx_runtime_1.jsx)("path", { d: "M22 5h-4" })] }));
|
|
16
|
+
}
|
|
17
|
+
function MicIcon() {
|
|
18
|
+
return ((0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }), (0, jsx_runtime_1.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", x2: "12", y1: "19", y2: "22" })] }));
|
|
19
|
+
}
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Inline styles — SDK must not depend on consumer's Tailwind config
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const WRAPPER_STYLE = {
|
|
24
|
+
position: 'fixed',
|
|
25
|
+
bottom: '1rem',
|
|
26
|
+
left: '50%',
|
|
27
|
+
transform: 'translateX(-50%)',
|
|
28
|
+
zIndex: 9999,
|
|
29
|
+
pointerEvents: 'none',
|
|
30
|
+
};
|
|
31
|
+
const WRAPPER_POSITIONED_STYLE = {
|
|
32
|
+
position: 'fixed',
|
|
33
|
+
zIndex: 9999,
|
|
34
|
+
pointerEvents: 'none',
|
|
35
|
+
};
|
|
36
|
+
const PILL_BASE_STYLE = {
|
|
37
|
+
pointerEvents: 'auto',
|
|
38
|
+
display: 'flex',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
gap: '0.5rem',
|
|
41
|
+
borderRadius: '9999px',
|
|
42
|
+
paddingLeft: '0.75rem',
|
|
43
|
+
paddingRight: '0.5rem',
|
|
44
|
+
paddingTop: '0.375rem',
|
|
45
|
+
paddingBottom: '0.375rem',
|
|
46
|
+
};
|
|
47
|
+
const RECORDING_PILL_STYLE = {
|
|
48
|
+
...PILL_BASE_STYLE,
|
|
49
|
+
paddingLeft: '0.5rem',
|
|
50
|
+
minWidth: '12rem',
|
|
51
|
+
};
|
|
52
|
+
const SPARKLE_STYLE = {
|
|
53
|
+
position: 'relative',
|
|
54
|
+
zIndex: 10,
|
|
55
|
+
display: 'flex',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
flexShrink: 0,
|
|
58
|
+
padding: '0.25rem',
|
|
59
|
+
};
|
|
60
|
+
const MIC_BUTTON_STYLE = {
|
|
61
|
+
position: 'relative',
|
|
62
|
+
zIndex: 10,
|
|
63
|
+
height: '1.75rem',
|
|
64
|
+
width: '1.75rem',
|
|
65
|
+
borderRadius: '9999px',
|
|
66
|
+
display: 'flex',
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
justifyContent: 'center',
|
|
69
|
+
flexShrink: 0,
|
|
70
|
+
backgroundColor: 'rgba(255,255,255,0.2)',
|
|
71
|
+
border: 'none',
|
|
72
|
+
color: 'inherit',
|
|
73
|
+
cursor: 'pointer',
|
|
74
|
+
padding: 0,
|
|
75
|
+
};
|
|
76
|
+
const WAVEFORM_CONTAINER_STYLE = {
|
|
77
|
+
flex: 1,
|
|
78
|
+
display: 'flex',
|
|
79
|
+
alignItems: 'center',
|
|
80
|
+
justifyContent: 'center',
|
|
81
|
+
minWidth: 0,
|
|
82
|
+
};
|
|
83
|
+
const DOT_STYLE = {
|
|
84
|
+
height: '0.375rem',
|
|
85
|
+
width: '0.375rem',
|
|
86
|
+
borderRadius: '9999px',
|
|
87
|
+
backgroundColor: 'currentColor',
|
|
88
|
+
opacity: 0.6,
|
|
89
|
+
};
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// CSS keyframes injected once for bounce animation
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
let stylesInjected = false;
|
|
94
|
+
function injectStyles() {
|
|
95
|
+
if (stylesInjected || typeof document === 'undefined')
|
|
96
|
+
return;
|
|
97
|
+
stylesInjected = true;
|
|
98
|
+
const style = document.createElement('style');
|
|
99
|
+
style.textContent = `
|
|
100
|
+
@keyframes ai-trigger-bounce {
|
|
101
|
+
0%, 100% { transform: translateY(0); }
|
|
102
|
+
50% { transform: translateY(-25%); }
|
|
103
|
+
}
|
|
104
|
+
[data-component="ai-trigger-button"] [data-dot] {
|
|
105
|
+
animation: ai-trigger-bounce 1.4s ease-in-out infinite;
|
|
106
|
+
}
|
|
107
|
+
[data-component="ai-trigger-button"] [data-dot="2"] {
|
|
108
|
+
animation-delay: 0.15s;
|
|
109
|
+
}
|
|
110
|
+
[data-component="ai-trigger-button"] [data-dot="3"] {
|
|
111
|
+
animation-delay: 0.3s;
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
114
|
+
document.head.appendChild(style);
|
|
115
|
+
}
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// ConnectingDots — shown while connecting or as wavesurfer fallback
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
function ConnectingDots() {
|
|
120
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: WAVEFORM_CONTAINER_STYLE, "data-element": "connecting-indicator", children: [(0, jsx_runtime_1.jsx)("span", { "data-dot": "1", style: DOT_STYLE }), (0, jsx_runtime_1.jsx)("span", { "data-dot": "2", style: { ...DOT_STYLE, marginLeft: '0.375rem' } }), (0, jsx_runtime_1.jsx)("span", { "data-dot": "3", style: { ...DOT_STYLE, marginLeft: '0.375rem' } })] }));
|
|
121
|
+
}
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// TriggerLiveWave — real-time mic waveform via WaveSurfer.js
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
function TriggerLiveWave() {
|
|
126
|
+
const containerRef = (0, react_1.useRef)(null);
|
|
127
|
+
const [loadFailed, setLoadFailed] = (0, react_1.useState)(false);
|
|
128
|
+
(0, react_1.useEffect)(() => {
|
|
129
|
+
const el = containerRef.current;
|
|
130
|
+
if (!el)
|
|
131
|
+
return;
|
|
132
|
+
let disposed = false;
|
|
133
|
+
const cleanupRef = { current: () => { } };
|
|
134
|
+
// Lazy-load the optional wavesurfer.js peer dep at runtime — see wavesurfer-loader.ts.
|
|
135
|
+
(0, wavesurfer_loader_js_1.loadWaveSurfer)()
|
|
136
|
+
.then(({ WaveSurfer, RecordPlugin }) => {
|
|
137
|
+
if (disposed)
|
|
138
|
+
return;
|
|
139
|
+
const ws = WaveSurfer.create({
|
|
140
|
+
container: el,
|
|
141
|
+
waveColor: '#000000',
|
|
142
|
+
height: 24,
|
|
143
|
+
barWidth: 2,
|
|
144
|
+
barGap: 1,
|
|
145
|
+
barRadius: 2,
|
|
146
|
+
cursorWidth: 0,
|
|
147
|
+
interact: false,
|
|
148
|
+
normalize: true,
|
|
149
|
+
});
|
|
150
|
+
const record = ws.registerPlugin(RecordPlugin.create({
|
|
151
|
+
scrollingWaveform: true,
|
|
152
|
+
scrollingWaveformWindow: 5,
|
|
153
|
+
renderRecordedAudio: false,
|
|
154
|
+
}));
|
|
155
|
+
record.startMic().catch((err) => {
|
|
156
|
+
console.warn('[AiTriggerButton] Failed to start waveform mic:', err);
|
|
157
|
+
});
|
|
158
|
+
cleanupRef.current = () => {
|
|
159
|
+
record.stopMic();
|
|
160
|
+
record.destroy();
|
|
161
|
+
ws.destroy();
|
|
162
|
+
};
|
|
163
|
+
})
|
|
164
|
+
.catch((err) => {
|
|
165
|
+
console.warn('[AiTriggerButton] wavesurfer.js is not installed — waveform visualization disabled. Install it with: npm install wavesurfer.js', err);
|
|
166
|
+
if (!disposed)
|
|
167
|
+
setLoadFailed(true);
|
|
168
|
+
});
|
|
169
|
+
return () => {
|
|
170
|
+
disposed = true;
|
|
171
|
+
cleanupRef.current();
|
|
172
|
+
};
|
|
173
|
+
}, []);
|
|
174
|
+
if (loadFailed) {
|
|
175
|
+
return (0, jsx_runtime_1.jsx)(ConnectingDots, {});
|
|
176
|
+
}
|
|
177
|
+
return (0, jsx_runtime_1.jsx)("div", { ref: containerRef, "data-element": "waveform", style: { flex: 1, minWidth: 0 } });
|
|
178
|
+
}
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// AiTriggerButton
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
function AiTriggerButton({ onClickChat, onClickMic, isRecording, isConnecting, onStopRecording, onCancelRecording, portal = true, className, buttonClassName, renderWrapper, draggable = true, persistPosition = 'ai-trigger-btn', ariaLabel = 'AI Assistant', micAriaLabel = 'Start recording', stopAriaLabel = 'Stop recording', cancelAriaLabel = 'Cancel recording', showMic = true, icon, }) {
|
|
183
|
+
const [isMounted, setIsMounted] = (0, react_1.useState)(false);
|
|
184
|
+
// Theme vars from the provider (standalone use is allowed — fall back).
|
|
185
|
+
const themeVars = (0, react_1.useContext)(chat_context_js_1.ChatContext)?.themeVars ?? {};
|
|
186
|
+
const { position, isDragging, onMouseDown, wasDragged, resetPosition } = (0, use_draggable_position_js_1.useDraggablePosition)({
|
|
187
|
+
enabled: draggable,
|
|
188
|
+
persistKey: persistPosition || false,
|
|
189
|
+
});
|
|
190
|
+
(0, react_1.useEffect)(() => {
|
|
191
|
+
injectStyles();
|
|
192
|
+
setIsMounted(true);
|
|
193
|
+
}, []);
|
|
194
|
+
if (!isMounted)
|
|
195
|
+
return null;
|
|
196
|
+
const state = isRecording ? 'recording' : isConnecting ? 'connecting' : 'idle';
|
|
197
|
+
// Wrapper: use className if provided (consumer controls styling), otherwise inline styles.
|
|
198
|
+
// Theme CSS variables are always spread so the pill inherits the active palette.
|
|
199
|
+
const wrapperStyle = className
|
|
200
|
+
? { ...themeVars }
|
|
201
|
+
: {
|
|
202
|
+
...themeVars,
|
|
203
|
+
...(position
|
|
204
|
+
? { ...WRAPPER_POSITIONED_STYLE, left: position.x, top: position.y }
|
|
205
|
+
: WRAPPER_STYLE),
|
|
206
|
+
};
|
|
207
|
+
const wrapperClassName = className ?? undefined;
|
|
208
|
+
// ---- Recording / connecting state ----
|
|
209
|
+
if (isRecording || isConnecting) {
|
|
210
|
+
const content = ((0, jsx_runtime_1.jsx)("div", { className: wrapperClassName, style: wrapperStyle, "data-component": "ai-trigger-button", "data-state": state, children: (0, jsx_runtime_1.jsxs)("div", { className: buttonClassName ?? undefined, style: RECORDING_PILL_STYLE, "aria-label": stopAriaLabel, children: [(0, jsx_runtime_1.jsx)(recording_controls_js_1.CancelButton, { onClick: onCancelRecording, ariaLabel: cancelAriaLabel }), (0, jsx_runtime_1.jsx)("div", { style: WAVEFORM_CONTAINER_STYLE, "data-element": "waveform-container", children: isConnecting ? (0, jsx_runtime_1.jsx)(ConnectingDots, {}) : (0, jsx_runtime_1.jsx)(TriggerLiveWave, {}) }), (0, jsx_runtime_1.jsx)(recording_controls_js_1.StopButton, { onClick: onStopRecording, ariaLabel: stopAriaLabel })] }) }));
|
|
211
|
+
return portal ? (0, react_dom_1.createPortal)(content, document.body) : content;
|
|
212
|
+
}
|
|
213
|
+
// ---- Default (idle) state ----
|
|
214
|
+
const button = ((0, jsx_runtime_1.jsxs)("div", { role: "button", tabIndex: 0, onMouseDown: onMouseDown, onClick: () => {
|
|
215
|
+
if (!wasDragged)
|
|
216
|
+
onClickChat();
|
|
217
|
+
}, onDoubleClick: () => {
|
|
218
|
+
if (position)
|
|
219
|
+
resetPosition();
|
|
220
|
+
}, onKeyDown: (e) => {
|
|
221
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
onClickChat();
|
|
224
|
+
}
|
|
225
|
+
}, className: buttonClassName ?? undefined, style: {
|
|
226
|
+
...PILL_BASE_STYLE,
|
|
227
|
+
cursor: isDragging ? 'grabbing' : 'pointer',
|
|
228
|
+
// When the mic is hidden, balance the padding so the single
|
|
229
|
+
// icon sits centered instead of off-to-the-left.
|
|
230
|
+
...(showMic ? {} : { paddingRight: '0.75rem' }),
|
|
231
|
+
}, "data-element": "button-pill", "aria-label": ariaLabel, children: [(0, jsx_runtime_1.jsx)("span", { style: SPARKLE_STYLE, "data-element": "chat-trigger", "aria-hidden": "true", children: icon ?? (0, jsx_runtime_1.jsx)(SparklesIcon, {}) }), showMic && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: (e) => {
|
|
232
|
+
e.stopPropagation();
|
|
233
|
+
if (!wasDragged)
|
|
234
|
+
onClickMic();
|
|
235
|
+
}, style: MIC_BUTTON_STYLE, "data-element": "mic-trigger", "aria-label": micAriaLabel, children: (0, jsx_runtime_1.jsx)(MicIcon, {}) }))] }));
|
|
236
|
+
const wrapped = renderWrapper ? renderWrapper(button) : button;
|
|
237
|
+
const content = ((0, jsx_runtime_1.jsx)("div", { className: wrapperClassName, style: wrapperStyle, "data-component": "ai-trigger-button", "data-state": "idle", "data-dragging": isDragging || undefined, children: wrapped }));
|
|
238
|
+
return portal ? (0, react_dom_1.createPortal)(content, document.body) : content;
|
|
239
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ApprovalCardProps } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Single tool approval card with rich detail display.
|
|
4
|
+
*
|
|
5
|
+
* Structure: header → details (label/value pairs) → actions (cancel/confirm).
|
|
6
|
+
* Uses `data-state` attribute for styling pending/processing states.
|
|
7
|
+
* Detail lines containing a colon are split into label + value.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ApprovalCard({ approval, onApprove, onReject, className, isProcessing, }: ApprovalCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApprovalCard = ApprovalCard;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
6
|
+
/**
|
|
7
|
+
* Single tool approval card with rich detail display.
|
|
8
|
+
*
|
|
9
|
+
* Structure: header → details (label/value pairs) → actions (cancel/confirm).
|
|
10
|
+
* Uses `data-state` attribute for styling pending/processing states.
|
|
11
|
+
* Detail lines containing a colon are split into label + value.
|
|
12
|
+
*/
|
|
13
|
+
function ApprovalCard({ approval, onApprove, onReject, className, isProcessing, }) {
|
|
14
|
+
const { classNames, locale } = (0, chat_context_js_1.useChatContext)();
|
|
15
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: className ?? classNames.approvalCard, "data-component": "approval-card", "data-tool": approval.toolName, "data-state": isProcessing ? 'processing' : 'pending', children: [(0, jsx_runtime_1.jsx)("div", { "data-element": "header", children: (0, jsx_runtime_1.jsx)("span", { "data-element": "description", children: approval.description ?? approval.toolName }) }), approval.details && approval.details.length > 0 && ((0, jsx_runtime_1.jsx)("div", { "data-element": "details", children: approval.details.map((detail, i) => {
|
|
16
|
+
const colonIndex = detail.indexOf(':');
|
|
17
|
+
if (colonIndex === -1) {
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)("div", { "data-element": "detail-line", children: detail }, i));
|
|
19
|
+
}
|
|
20
|
+
const label = detail.substring(0, colonIndex);
|
|
21
|
+
const value = detail.substring(colonIndex + 1).trim();
|
|
22
|
+
return ((0, jsx_runtime_1.jsxs)("div", { "data-element": "detail-line", children: [(0, jsx_runtime_1.jsx)("span", { "data-element": "detail-label", children: label }), (0, jsx_runtime_1.jsx)("span", { "data-element": "detail-value", children: value })] }, i));
|
|
23
|
+
}) })), (0, jsx_runtime_1.jsxs)("div", { "data-element": "actions", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: () => onReject(approval.id), disabled: isProcessing, "data-action": "reject", children: ['\u2715', " ", locale.cancelButton] }), (0, jsx_runtime_1.jsxs)("button", { onClick: () => onApprove(approval.id), disabled: isProcessing, "data-action": "approve", children: ['\u2713', " ", approval.confirmText ?? locale.confirmButton] })] })] }));
|
|
24
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BulkApprovalCardProps } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Grouped approval card for 2+ tool calls of the same type.
|
|
4
|
+
*
|
|
5
|
+
* Shows one primary detail (first value) per approval for a compact overview.
|
|
6
|
+
* Remaining approvals are hidden behind an expandable "+N more" toggle.
|
|
7
|
+
* Uses `toolLabels` from context for human-readable tool action names.
|
|
8
|
+
*/
|
|
9
|
+
export declare function BulkApprovalCard({ toolName, approvals, onApproveAll, onRejectAll, className, isProcessing, }: BulkApprovalCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BulkApprovalCard = BulkApprovalCard;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
7
|
+
/**
|
|
8
|
+
* Grouped approval card for 2+ tool calls of the same type.
|
|
9
|
+
*
|
|
10
|
+
* Shows one primary detail (first value) per approval for a compact overview.
|
|
11
|
+
* Remaining approvals are hidden behind an expandable "+N more" toggle.
|
|
12
|
+
* Uses `toolLabels` from context for human-readable tool action names.
|
|
13
|
+
*/
|
|
14
|
+
function BulkApprovalCard({ toolName, approvals, onApproveAll, onRejectAll, className, isProcessing, }) {
|
|
15
|
+
const { classNames, locale, toolLabels } = (0, chat_context_js_1.useChatContext)();
|
|
16
|
+
const [expanded, setExpanded] = (0, react_1.useState)(false);
|
|
17
|
+
const count = approvals.length;
|
|
18
|
+
const labels = toolLabels.labels?.[toolName] ?? { singular: toolName, plural: toolName };
|
|
19
|
+
const actionLabel = count === 1 ? labels.singular : labels.plural;
|
|
20
|
+
// Extract one primary detail per approval (first detail value = typically the title)
|
|
21
|
+
const primaryDetails = [];
|
|
22
|
+
for (const approval of approvals) {
|
|
23
|
+
if (approval.details && approval.details.length > 0) {
|
|
24
|
+
const first = approval.details[0];
|
|
25
|
+
const colonIndex = first.indexOf(':');
|
|
26
|
+
const value = colonIndex > -1 ? first.substring(colonIndex + 1).trim() : first;
|
|
27
|
+
if (value)
|
|
28
|
+
primaryDetails.push(value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const maxVisible = 3;
|
|
32
|
+
const visibleDetails = expanded ? primaryDetails : primaryDetails.slice(0, maxVisible);
|
|
33
|
+
const remainingCount = primaryDetails.length - maxVisible;
|
|
34
|
+
const allCountText = (locale.allCountLabel ?? 'All {count}').replace('{count}', String(count));
|
|
35
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: className ?? classNames.bulkApprovalCard, "data-component": "bulk-approval-card", "data-tool": toolName, "data-count": count, "data-state": isProcessing ? 'processing' : 'pending', children: [(0, jsx_runtime_1.jsxs)("div", { "data-element": "header", children: [(0, jsx_runtime_1.jsx)("span", { "data-element": "tool-icon" }), (0, jsx_runtime_1.jsxs)("span", { "data-element": "description", children: [count, " ", actionLabel, "?"] })] }), visibleDetails.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { "data-element": "details", children: [visibleDetails.map((detail, i) => ((0, jsx_runtime_1.jsxs)("div", { "data-element": "detail-line", children: [(0, jsx_runtime_1.jsx)("span", { "data-element": "detail-bullet" }), (0, jsx_runtime_1.jsx)("span", { "data-element": "detail-value", children: detail })] }, i))), remainingCount > 0 && !expanded && ((0, jsx_runtime_1.jsxs)("button", { type: "button", "data-element": "detail-overflow", onClick: () => setExpanded(true), children: ["+", remainingCount, " ", locale.moreItemsLabel] }))] })), (0, jsx_runtime_1.jsxs)("div", { "data-element": "actions", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: onRejectAll, disabled: isProcessing, "data-action": "reject", children: ['\u2715', " ", locale.cancelButton] }), (0, jsx_runtime_1.jsxs)("button", { onClick: onApproveAll, disabled: isProcessing, "data-action": "approve", children: ['\u2713', " ", count === 1 ? (locale.confirmButton) : allCountText] })] })] }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ChatInputProps } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Plain chat input field with submit handling.
|
|
4
|
+
*
|
|
5
|
+
* Submits on Enter (without Shift). Renders the InputExtra component
|
|
6
|
+
* from provider config if available (e.g., voice input button).
|
|
7
|
+
*
|
|
8
|
+
* Toggles between send and stop button based on loading state.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ChatInput({ className, onSubmit }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
|