@xopcai/xopc 0.0.93 → 0.0.94
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/agents-OqhbJkMf.js +222 -0
- package/dist/gateway/static/root/assets/apps-page-OHXW9XP8.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-4N2R-jof.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-CsGkK9h9.js → channels-status-swr-Bv6f9kDq.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-CyAm0xJT.js → cron-api-BtaQaHJq.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-Dah32HJK.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DHwVV8XK.js → dist-BJfD9Qvs.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BK8kcc4F.js → extension-debug-page-DnYuMzmH.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Cf8X_QUc.js → extension-page-CJfc-6XV.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-C5-YLMmy.js → extension-settings-page-BxdfYQMG.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-BAPnkYbC.js → fetch-B0aeeY0q.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-8p7ucXa1.js → field-primitives-DOLHwowi.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CpgW2sGp.js → heartbeat-config-api-Bj2INAf5.js} +1 -1
- package/dist/gateway/static/root/assets/index-Bj_l8QDp.css +1 -0
- package/dist/gateway/static/root/assets/{index-Do52EfZK.js → index-DuQ1XPoA.js} +99 -98
- package/dist/gateway/static/root/assets/logs-page-AsOgLNJE.js +2 -0
- package/dist/gateway/static/root/assets/{note-detail-page-WLM6FUIi.js → note-detail-page-24J4mVP-.js} +3 -3
- package/dist/gateway/static/root/assets/{note-time-EFyIVhec.js → note-time-JBszYV3s.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-BYPVYcYn.js → notes-page-BApAirFB.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DX9huWsA.js +1 -0
- package/dist/gateway/static/root/assets/{settings-advanced-gate-CEs8pGh6.js → settings-advanced-gate-DWvhsTuz.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-C6cGTVwK.js → settings-form-section-CxMjaMiy.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-4VmUTzQs.js +3 -0
- package/dist/gateway/static/root/assets/{share-preview-page-tnIfJ4K6.js → share-preview-page-IX0TJvRd.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page-CGKGKfwe.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-D6EsNTPr.js → theme-store-Cg_SuBw0.js} +1 -1
- package/dist/gateway/static/root/assets/{url-CTjpm0Uz.js → url-BHHmdJYc.js} +2 -2
- package/dist/gateway/static/root/assets/{utils-C86AVfY-.js → utils-BmlcxR2j.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DaGm2N4J.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-page.utils-DsEriMFW.js → workflow-page.utils-D0vsIGHD.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-BFCrD3nw.js +27 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +3 -0
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.js +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -2
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +18 -5
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +11 -4
- package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +2 -2
- package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/build-direct-message-content.js +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
- package/dist/src/agent/service/process-direct-streaming.js +15 -12
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +4 -2
- package/dist/src/agent/service.js +24 -8
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +3 -1
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/search/registry.js +1 -1
- package/dist/src/agent/tools/search/registry.js.map +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/session-search-tool.js +1 -1
- package/dist/src/agent/tools/session-search-tool.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +2 -2
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workflow/progress-broker.js +1 -1
- package/dist/src/agent/workflow/progress-broker.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +1 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/channels/pipeline.js +3 -2
- package/dist/src/channels/pipeline.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/cli-log-level-preset.d.ts +1 -1
- package/dist/src/cli/cli-log-level-preset.js +2 -2
- package/dist/src/cli/cli-log-level-preset.js.map +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +2 -2
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +4 -4
- package/dist/src/cli/commands/logs.js +3 -3
- package/dist/src/cli/commands/logs.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +5 -5
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/executor.js +9 -6
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +3 -3
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/app.js +4 -1
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/route-logger.d.ts +6 -0
- package/dist/src/gateway/hono/lib/route-logger.js +31 -0
- package/dist/src/gateway/hono/lib/route-logger.js.map +1 -0
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/middleware/auth.js +16 -3
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/middleware/logger.js +1 -1
- package/dist/src/gateway/hono/middleware/logger.js.map +1 -1
- package/dist/src/gateway/hono/middleware/route-errors.d.ts +5 -0
- package/dist/src/gateway/hono/middleware/route-errors.js +27 -0
- package/dist/src/gateway/hono/middleware/route-errors.js.map +1 -0
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agent-stream.js +6 -0
- package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/browser-install.js +2 -4
- package/dist/src/gateway/hono/routes/browser-install.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/config.js +25 -11
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/cron.js +5 -0
- package/dist/src/gateway/hono/routes/cron.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +4 -6
- package/dist/src/gateway/hono/routes/host-fs.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +14 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-fallback.js +3 -0
- package/dist/src/gateway/hono/routes/lazy-fallback.js.map +1 -1
- package/dist/src/gateway/hono/routes/logs.js +39 -7
- package/dist/src/gateway/hono/routes/logs.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.d.ts +3 -0
- package/dist/src/gateway/hono/routes/mcp.js +107 -0
- package/dist/src/gateway/hono/routes/mcp.js.map +1 -0
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +6 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/update.js +2 -4
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/routes/voice.js +2 -4
- package/dist/src/gateway/hono/routes/voice.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +4 -6
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.js +9 -2
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +3 -3
- package/dist/src/gateway/service/agent-runner.js.map +1 -1
- package/dist/src/gateway/service/config-coordinator.js +14 -6
- package/dist/src/gateway/service/config-coordinator.js.map +1 -1
- package/dist/src/gateway/service/marketplace-service.js +3 -3
- package/dist/src/gateway/service/marketplace-service.js.map +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +22 -5
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sse-hub.js +1 -1
- package/dist/src/gateway/service/sse-hub.js.map +1 -1
- package/dist/src/gateway/service.js +13 -6
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/mcp/channel-bridge.js +26 -2
- package/dist/src/mcp/channel-bridge.js.map +1 -1
- package/dist/src/mcp/gateway-http-client.js +24 -2
- package/dist/src/mcp/gateway-http-client.js.map +1 -1
- package/dist/src/notes/store.js +2 -2
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.js +12 -6
- package/dist/src/session/config-store.js.map +1 -1
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/index.js +2 -2
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/manager.js +8 -1
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
- package/dist/src/session/parity/sessions-json-file.js +1 -1
- package/dist/src/session/parity/transcript-file-lock.js +2 -2
- package/dist/src/session/parity/transcript-paths.js +1 -1
- package/dist/src/session/resolve-session.js +4 -4
- package/dist/src/session/search-index-cache.js +1 -1
- package/dist/src/session/search-index.js +1 -1
- package/dist/src/session/session-title.d.ts +19 -3
- package/dist/src/session/session-title.js +84 -9
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/store.js +6 -6
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui.js +3 -3
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/index.js +4 -4
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/config.js +2 -6
- package/dist/src/utils/logger/config.js.map +1 -1
- package/dist/src/utils/logger/context.d.ts +3 -22
- package/dist/src/utils/logger/context.js +4 -32
- package/dist/src/utils/logger/context.js.map +1 -1
- package/dist/src/utils/logger/index.d.ts +4 -7
- package/dist/src/utils/logger/index.js +9 -28
- package/dist/src/utils/logger/index.js.map +1 -1
- package/dist/src/utils/logger/log-store.d.ts +14 -32
- package/dist/src/utils/logger/log-store.js +68 -119
- package/dist/src/utils/logger/log-store.js.map +1 -1
- package/dist/src/utils/logger/log-stream.d.ts +5 -70
- package/dist/src/utils/logger/log-stream.js +67 -178
- package/dist/src/utils/logger/log-stream.js.map +1 -1
- package/dist/src/utils/logger/pino-record.d.ts +8 -0
- package/dist/src/utils/logger/pino-record.js +83 -0
- package/dist/src/utils/logger/pino-record.js.map +1 -0
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/utils/logger/stats.d.ts +1 -1
- package/dist/src/utils/logger/stats.js +2 -2
- package/dist/src/utils/logger/stats.js.map +1 -1
- package/dist/src/utils/logger/streams.js +18 -0
- package/dist/src/utils/logger/streams.js.map +1 -1
- package/dist/src/utils/logger/types.d.ts +0 -9
- package/dist/src/utils/logger/types.js.map +1 -1
- package/dist/src/utils/logger.js +4 -4
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +2 -1
- package/dist/gateway/static/root/assets/agents-C7tTJLP9.js +0 -222
- package/dist/gateway/static/root/assets/apps-page-BbzdMyrg.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-B49vG2hE.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-Bjx7IOdR.js +0 -1
- package/dist/gateway/static/root/assets/index-CwDdudZM.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-BxukQ-J-.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BFD2_-Cl.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-BiP5iH46.js +0 -2
- package/dist/gateway/static/root/assets/skills-page-CNDctFIn.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-CalxUkxm.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-D2fRxXJG.js +0 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { buildSessionKey, parseSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { messagesToClientHistory } from '../../../session/client-history.js';\nimport { computeUserRoundDeleteRange } from '../../../session/user-round-delete.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\nimport type { StartupUnavailableGatewayMethod } from '../../startup-readiness.js';\n\ntype SessionsStartupMethod = StartupUnavailableGatewayMethod;\n\nfunction ensureGatewayReadyForSessions(\n c: Parameters<typeof respondStartupUnavailable>[0],\n service: AuthenticatedRouteDeps['service'],\n method: SessionsStartupMethod,\n): Response | null {\n if (service.isGatewayReady()) {\n return null;\n }\n return respondStartupUnavailable(c, method);\n}\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n // POST /api/sessions - Create new session (reuses empty sessions)\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n // If a specific chat_id is provided, use it (for advanced use cases)\n // Otherwise, try to find and reuse an existing empty session\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, []);\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n\n // Look for existing empty sessions to reuse\n const existingSessions = await service.sessions.listSessions({\n channel,\n limit: 50,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n \n // Reuse an empty session only when it matches the requested agent (session key embeds agent id).\n const emptySession = existingSessions.items.find((s) => {\n if (s.messageCount !== 0) return false;\n const parsed = parseSessionKey(s.key);\n return parsed?.agentId === agentId;\n });\n \n if (emptySession) {\n // Return existing empty session instead of creating a new one\n const session = await service.sessions.getSession(emptySession.key);\n return c.json({ session, reused: true }, 200);\n }\n \n // No empty session found, create a new one\n const chatId = `chat_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, []);\n\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n const query = c.req.query();\n const result = await service.sessions.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.sessions.stats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.sessions.chatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/:key/run — read-only active webchat agent run (for UI resume)\n authenticated.get('/api/sessions/:key/run', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.run');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: service.sessions.getActiveRun(key) });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.sessions.getAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.patchAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/messages — flattened transcript for TUI / clients\n authenticated.get('/api/sessions/:key/messages', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.messages');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const limitRaw = c.req.query('limit');\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;\n const limit =\n parsedLimit !== undefined && Number.isFinite(parsedLimit)\n ? Math.min(500, Math.max(1, parsedLimit))\n : undefined;\n\n const before = c.req.query('before')?.trim();\n const offsetRaw = c.req.query('offset');\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n\n const result = await service.sessions.getMessagePage(key, {\n limit,\n offset,\n ...(before ? { before } : {}),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n\n const messages = messagesToClientHistory(result.session.messages, { limit });\n return c.json({\n ok: true,\n payload: { messages },\n pagination: result.pagination,\n });\n });\n\n // GET /api/sessions/:key/history — UI chat history page from the newest tail.\n authenticated.get('/api/sessions/:key/history', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const before = c.req.query('before')?.trim();\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n ...(before ? { before } : {}),\n });\n\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n return c.json(result);\n });\n\n // POST /api/sessions/:key/transcript/context — append persisted-only `kind: 'context'` row (not in LLM context)\n authenticated.post('/api/sessions/:key/transcript/context', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const id = typeof body.id === 'string' && body.id.trim() ? body.id.trim() : undefined;\n const text = typeof body.text === 'string' ? body.text : undefined;\n const data =\n body.data !== undefined && typeof body.data === 'object' && body.data !== null && !Array.isArray(body.data)\n ? (body.data as Record<string, unknown>)\n : undefined;\n await service.sessionIndexInstance.appendTranscriptContextEntry(key, { id, text, data });\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/compaction/checkpoints — list pre-compaction snapshots (OpenClaw-style)\n authenticated.get('/api/sessions/:key/compaction/checkpoints', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const checkpoints = await service.sessions.listCompactionCheckpoints(key);\n return c.json({ ok: true, payload: { checkpoints } });\n });\n\n authenticated.get('/api/sessions/:key/compaction/checkpoints/:checkpointId', async (c) => {\n const key = c.req.param('key');\n const checkpointId = c.req.param('checkpointId');\n const checkpoint = await service.sessions.getCompactionCheckpoint(key, checkpointId);\n if (!checkpoint) {\n return c.json({ ok: false, error: 'Checkpoint not found' }, 404);\n }\n return c.json({ ok: true, payload: { checkpoint } });\n });\n\n authenticated.post('/api/sessions/:key/compaction/restore', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const checkpointId = typeof body.checkpointId === 'string' ? body.checkpointId.trim() : '';\n if (!checkpointId) {\n return c.json({ ok: false, error: 'checkpointId required' }, 400);\n }\n try {\n await service.sessions.restoreCompactionCheckpoint(key, checkpointId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found') || msg.includes('Invalid')) {\n return c.json({ ok: false, error: msg }, 404);\n }\n return c.json({ ok: false, error: msg }, 500);\n }\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, session });\n });\n\n authenticated.post('/api/sessions/:key/compaction/run', async (c) => {\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const instructions = typeof body.instructions === 'string' ? body.instructions : undefined;\n const force = typeof body.force === 'boolean' ? body.force : true;\n const result = await service.sessions.runCompaction(key, { instructions, force });\n return c.json({ ok: true, payload: { result } });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const includeTranscript = includeSet.has('transcript');\n const includeTranscriptRows = includeSet.has('transcriptRows');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const hasPagingQuery = offsetRaw !== undefined || limitRaw !== undefined;\n\n if (hasPagingQuery) {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json(result);\n }\n\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // PATCH /api/sessions/:key - Partial metadata (name, tags, customData); OpenClaw-style patch subset\n authenticated.patch('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const patch: {\n name?: string;\n tags?: string[];\n replaceTags?: boolean;\n customData?: Record<string, unknown>;\n } = {};\n if (typeof body.name === 'string') {\n patch.name = body.name;\n }\n if (Array.isArray(body.tags)) {\n patch.tags = body.tags;\n }\n if (typeof body.replaceTags === 'boolean') {\n patch.replaceTags = body.replaceTags;\n }\n if (body.customData !== undefined && typeof body.customData === 'object' && body.customData !== null) {\n patch.customData = body.customData as Record<string, unknown>;\n }\n const result = await service.sessions.patch(key, patch);\n if (result.ok === false) {\n return c.json({ ok: false, error: result.error }, 404);\n }\n\n const session = await service.sessions.getSession(key);\n return c.json({ ok: true, session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.sessions.export(key, format);\n return c.json(result);\n });\n\n // DELETE /api/sessions/:key/messages — delete LLM rows by range or by user turn.\n // `userRoundIndex` (0-based among user messages) removes the user row and every following\n // assistant / tool / toolResult row until the next user. Prefer this from the web console so\n // tool loops are not left orphaned after retry/delete.\n authenticated.delete('/api/sessions/:key/messages', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const loaded = await service.sessionIndexInstance.loadMessages(key);\n if (!loaded) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n let startIndex = typeof body.startIndex === 'number' ? body.startIndex : -1;\n let count = typeof body.count === 'number' ? body.count : 0;\n const userRoundIndex =\n typeof body.userRoundIndex === 'number' ? body.userRoundIndex : undefined;\n\n if (userRoundIndex !== undefined) {\n const range = computeUserRoundDeleteRange(loaded, userRoundIndex);\n if (!range) {\n return c.json({ error: 'User round index out of range' }, 400);\n }\n startIndex = range.startIndex;\n count = range.count;\n }\n\n if (startIndex < 0 || count <= 0) {\n return c.json({ error: 'Invalid startIndex or count' }, 400);\n }\n if (startIndex >= loaded.length) {\n return c.json({ error: 'Index out of range' }, 400);\n }\n const deleteCount = Math.min(count, loaded.length - startIndex);\n const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));\n await service.sessionIndexInstance.saveMessages(key, next);\n return c.json({ ok: true, deleted: deleteCount });\n });\n\n // POST /api/sessions/:key/reset - Reset session (archive transcript, new session id; keep key + overrides)\n authenticated.post('/api/sessions/:key/reset', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.reset');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const result = await service.sessions.reset(key);\n if (result.ok === false) {\n const status = result.error === 'Session not found' ? 404 : 400;\n return c.json({ ok: false, error: result.error }, status);\n }\n const session = await service.sessions.getSession(key);\n return c.json({\n ok: true,\n reset: true,\n sessionId: result.sessionId,\n previousSessionId: result.previousSessionId,\n session,\n });\n });\n\n // DELETE /api/sessions/:key - Delete session (removes key from index)\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.delete(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.archive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unarchive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.pin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unpin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.sessions.rename(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.sessions.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeSet.has('transcript'),\n includeTranscriptRows: includeSet.has('transcriptRows'),\n });\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { buildSessionKey, parseSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { createGatewayRouteLogger, logRouteError } from '../lib/route-logger.js';\nimport { messagesToClientHistory } from '../../../session/client-history.js';\nimport { computeUserRoundDeleteRange } from '../../../session/user-round-delete.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\nimport type { StartupUnavailableGatewayMethod } from '../../startup-readiness.js';\n\nconst log = createGatewayRouteLogger('Sessions');\n\ntype SessionsStartupMethod = StartupUnavailableGatewayMethod;\n\nfunction ensureGatewayReadyForSessions(\n c: Parameters<typeof respondStartupUnavailable>[0],\n service: AuthenticatedRouteDeps['service'],\n method: SessionsStartupMethod,\n): Response | null {\n if (service.isGatewayReady()) {\n return null;\n }\n return respondStartupUnavailable(c, method);\n}\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n // POST /api/sessions - Create new session (reuses empty sessions)\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n // If a specific chat_id is provided, use it (for advanced use cases)\n // Otherwise, try to find and reuse an existing empty session\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, []);\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n\n // Look for existing empty sessions to reuse\n const existingSessions = await service.sessions.listSessions({\n channel,\n limit: 50,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n \n // Reuse an empty session only when it matches the requested agent (session key embeds agent id).\n const emptySession = existingSessions.items.find((s) => {\n if (s.messageCount !== 0) return false;\n const parsed = parseSessionKey(s.key);\n return parsed?.agentId === agentId;\n });\n \n if (emptySession) {\n // Return existing empty session instead of creating a new one\n const session = await service.sessions.getSession(emptySession.key);\n return c.json({ session, reused: true }, 200);\n }\n \n // No empty session found, create a new one\n const chatId = `chat_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, []);\n\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n const query = c.req.query();\n const result = await service.sessions.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.sessions.stats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.sessions.chatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/:key/run — read-only active webchat agent run (for UI resume)\n authenticated.get('/api/sessions/:key/run', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.run');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: service.sessions.getActiveRun(key) });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.sessions.getAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.patchAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/messages — flattened transcript for TUI / clients\n authenticated.get('/api/sessions/:key/messages', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.messages');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const limitRaw = c.req.query('limit');\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;\n const limit =\n parsedLimit !== undefined && Number.isFinite(parsedLimit)\n ? Math.min(500, Math.max(1, parsedLimit))\n : undefined;\n\n const before = c.req.query('before')?.trim();\n const offsetRaw = c.req.query('offset');\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n\n const result = await service.sessions.getMessagePage(key, {\n limit,\n offset,\n ...(before ? { before } : {}),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n\n const messages = messagesToClientHistory(result.session.messages, { limit });\n return c.json({\n ok: true,\n payload: { messages },\n pagination: result.pagination,\n });\n });\n\n // GET /api/sessions/:key/history — UI chat history page from the newest tail.\n authenticated.get('/api/sessions/:key/history', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const before = c.req.query('before')?.trim();\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n ...(before ? { before } : {}),\n });\n\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n return c.json(result);\n });\n\n // POST /api/sessions/:key/transcript/context — append persisted-only `kind: 'context'` row (not in LLM context)\n authenticated.post('/api/sessions/:key/transcript/context', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const id = typeof body.id === 'string' && body.id.trim() ? body.id.trim() : undefined;\n const text = typeof body.text === 'string' ? body.text : undefined;\n const data =\n body.data !== undefined && typeof body.data === 'object' && body.data !== null && !Array.isArray(body.data)\n ? (body.data as Record<string, unknown>)\n : undefined;\n await service.sessionIndexInstance.appendTranscriptContextEntry(key, { id, text, data });\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/compaction/checkpoints — list pre-compaction snapshots (OpenClaw-style)\n authenticated.get('/api/sessions/:key/compaction/checkpoints', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const checkpoints = await service.sessions.listCompactionCheckpoints(key);\n return c.json({ ok: true, payload: { checkpoints } });\n });\n\n authenticated.get('/api/sessions/:key/compaction/checkpoints/:checkpointId', async (c) => {\n const key = c.req.param('key');\n const checkpointId = c.req.param('checkpointId');\n const checkpoint = await service.sessions.getCompactionCheckpoint(key, checkpointId);\n if (!checkpoint) {\n return c.json({ ok: false, error: 'Checkpoint not found' }, 404);\n }\n return c.json({ ok: true, payload: { checkpoint } });\n });\n\n authenticated.post('/api/sessions/:key/compaction/restore', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const checkpointId = typeof body.checkpointId === 'string' ? body.checkpointId.trim() : '';\n if (!checkpointId) {\n return c.json({ ok: false, error: 'checkpointId required' }, 400);\n }\n try {\n await service.sessions.restoreCompactionCheckpoint(key, checkpointId);\n } catch (err) {\n logRouteError(log, c, err, 'gateway.route.sessions', { operation: 'restoreCheckpoint', sessionKey: key });\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found') || msg.includes('Invalid')) {\n return c.json({ ok: false, error: msg }, 404);\n }\n return c.json({ ok: false, error: msg }, 500);\n }\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, session });\n });\n\n authenticated.post('/api/sessions/:key/compaction/run', async (c) => {\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const instructions = typeof body.instructions === 'string' ? body.instructions : undefined;\n const force = typeof body.force === 'boolean' ? body.force : true;\n const result = await service.sessions.runCompaction(key, { instructions, force });\n return c.json({ ok: true, payload: { result } });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const includeTranscript = includeSet.has('transcript');\n const includeTranscriptRows = includeSet.has('transcriptRows');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const hasPagingQuery = offsetRaw !== undefined || limitRaw !== undefined;\n\n if (hasPagingQuery) {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json(result);\n }\n\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // PATCH /api/sessions/:key - Partial metadata (name, tags, customData); OpenClaw-style patch subset\n authenticated.patch('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const patch: {\n name?: string;\n tags?: string[];\n replaceTags?: boolean;\n customData?: Record<string, unknown>;\n } = {};\n if (typeof body.name === 'string') {\n patch.name = body.name;\n }\n if (Array.isArray(body.tags)) {\n patch.tags = body.tags;\n }\n if (typeof body.replaceTags === 'boolean') {\n patch.replaceTags = body.replaceTags;\n }\n if (body.customData !== undefined && typeof body.customData === 'object' && body.customData !== null) {\n patch.customData = body.customData as Record<string, unknown>;\n }\n const result = await service.sessions.patch(key, patch);\n if (result.ok === false) {\n return c.json({ ok: false, error: result.error }, 404);\n }\n\n const session = await service.sessions.getSession(key);\n return c.json({ ok: true, session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.sessions.export(key, format);\n return c.json(result);\n });\n\n // DELETE /api/sessions/:key/messages — delete LLM rows by range or by user turn.\n // `userRoundIndex` (0-based among user messages) removes the user row and every following\n // assistant / tool / toolResult row until the next user. Prefer this from the web console so\n // tool loops are not left orphaned after retry/delete.\n authenticated.delete('/api/sessions/:key/messages', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const loaded = await service.sessionIndexInstance.loadMessages(key);\n if (!loaded) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n let startIndex = typeof body.startIndex === 'number' ? body.startIndex : -1;\n let count = typeof body.count === 'number' ? body.count : 0;\n const userRoundIndex =\n typeof body.userRoundIndex === 'number' ? body.userRoundIndex : undefined;\n\n if (userRoundIndex !== undefined) {\n const range = computeUserRoundDeleteRange(loaded, userRoundIndex);\n if (!range) {\n return c.json({ error: 'User round index out of range' }, 400);\n }\n startIndex = range.startIndex;\n count = range.count;\n }\n\n if (startIndex < 0 || count <= 0) {\n return c.json({ error: 'Invalid startIndex or count' }, 400);\n }\n if (startIndex >= loaded.length) {\n return c.json({ error: 'Index out of range' }, 400);\n }\n const deleteCount = Math.min(count, loaded.length - startIndex);\n const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));\n await service.sessionIndexInstance.saveMessages(key, next);\n return c.json({ ok: true, deleted: deleteCount });\n });\n\n // POST /api/sessions/:key/reset - Reset session (archive transcript, new session id; keep key + overrides)\n authenticated.post('/api/sessions/:key/reset', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.reset');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const result = await service.sessions.reset(key);\n if (result.ok === false) {\n const status = result.error === 'Session not found' ? 404 : 400;\n return c.json({ ok: false, error: result.error }, status);\n }\n const session = await service.sessions.getSession(key);\n return c.json({\n ok: true,\n reset: true,\n sessionId: result.sessionId,\n previousSessionId: result.previousSessionId,\n session,\n });\n });\n\n // DELETE /api/sessions/:key - Delete session (removes key from index)\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.delete(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.archive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unarchive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.pin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unpin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.sessions.rename(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.sessions.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeSet.has('transcript'),\n includeTranscriptRows: includeSet.has('transcriptRows'),\n });\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
|
|
@@ -13,8 +13,8 @@ import { getClientIpFromHeaders } from "../../security/loopback.js";
|
|
|
13
13
|
import { renderFolderLandingPage, renderShareExpiredPage, renderShareLandingPage } from "../../../share/share-landing.js";
|
|
14
14
|
import { consumeSharePublicLimit } from "../../../share/share-rate-limit.js";
|
|
15
15
|
import { createZipStream, planDirectoryFiles } from "../../../share/share-zip.js";
|
|
16
|
-
import { createHash } from "node:crypto";
|
|
17
16
|
import { createReadStream } from "node:fs";
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
18
|
import { stat } from "node:fs/promises";
|
|
19
19
|
import { Readable } from "node:stream";
|
|
20
20
|
//#region src/gateway/hono/routes/shares.ts
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { PACKAGE_VERSION, init_package_version } from "../../../package-version.js";
|
|
2
|
-
import { createLogger } from "../../../utils/logger/index.js";
|
|
3
|
-
import { init_logger } from "../../../utils/logger.js";
|
|
4
2
|
import { loadConfig } from "../../../config/loader.js";
|
|
5
3
|
import "../../../config/index.js";
|
|
6
4
|
import { acquireUpdateLock } from "../../../infra/update-lock.js";
|
|
7
5
|
import { normalizeUpdateChannel } from "../../../infra/update-channels.js";
|
|
8
6
|
import { getUpdateAvailable, runGatewayUpdateCheck } from "../../../infra/update-startup.js";
|
|
7
|
+
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
9
8
|
import { formatUpdateApiResult, runGatewayUpdateWithPostSteps } from "../../../infra/update-runner.js";
|
|
10
9
|
import { streamSSE } from "hono/streaming";
|
|
11
10
|
//#region src/gateway/hono/routes/update.ts
|
|
12
11
|
init_package_version();
|
|
13
|
-
|
|
14
|
-
const log = createLogger("GatewayUpdate");
|
|
12
|
+
const log = createGatewayRouteLogger("Update");
|
|
15
13
|
function mapUpdateFailure(result, channel) {
|
|
16
14
|
const apiResult = formatUpdateApiResult(result, channel);
|
|
17
15
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","names":[],"sources":["../../../../../src/gateway/hono/routes/update.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { acquireUpdateLock } from '../../../infra/update-lock.js';\nimport {\n DEFAULT_PACKAGE_CHANNEL,\n normalizeUpdateChannel,\n type UpdateChannel,\n} from '../../../infra/update-channels.js';\nimport {\n formatUpdateApiResult,\n runGatewayUpdateWithPostSteps,\n type UpdateRunResult,\n} from '../../../infra/update-runner.js';\nimport { getUpdateAvailable, runGatewayUpdateCheck } from '../../../infra/update-startup.js';\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport {
|
|
1
|
+
{"version":3,"file":"update.js","names":[],"sources":["../../../../../src/gateway/hono/routes/update.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { acquireUpdateLock } from '../../../infra/update-lock.js';\nimport {\n DEFAULT_PACKAGE_CHANNEL,\n normalizeUpdateChannel,\n type UpdateChannel,\n} from '../../../infra/update-channels.js';\nimport {\n formatUpdateApiResult,\n runGatewayUpdateWithPostSteps,\n type UpdateRunResult,\n} from '../../../infra/update-runner.js';\nimport { getUpdateAvailable, runGatewayUpdateCheck } from '../../../infra/update-startup.js';\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createGatewayRouteLogger('Update');\n\nfunction mapUpdateFailure(result: UpdateRunResult, channel: UpdateChannel) {\n const apiResult = formatUpdateApiResult(result, channel);\n const message =\n typeof apiResult.message === 'string'\n ? apiResult.message\n : result.reason ?? 'Update failed';\n return { apiResult, message };\n}\n\nexport function registerUpdateRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { strictRateLimitMiddleware, service } = deps;\n\n authenticated.get('/api/update/status', (c) => {\n const update = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: update !== null,\n latestVersion: update?.latestVersion ?? null,\n channel: update?.channel ?? null,\n },\n });\n });\n\n authenticated.post('/api/update/check', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n await runGatewayUpdateCheck({\n config,\n force: true,\n onUpdateAvailableChange: (update) => {\n service.emit('update.available', update);\n },\n });\n const result = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: result !== null,\n latestVersion: result?.latestVersion ?? null,\n channel: result?.channel ?? null,\n },\n });\n });\n\n authenticated.post('/api/update/run', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n const channel = normalizeUpdateChannel(config.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;\n\n const lock = await acquireUpdateLock('gateway');\n if (!lock) {\n return c.json(\n { ok: false, error: 'busy', message: 'Another update is already in progress.' },\n 409,\n );\n }\n\n try {\n log.info({ channel }, 'Gateway: starting in-process update');\n const result = await runGatewayUpdateWithPostSteps({\n channel,\n cwd: process.cwd(),\n argv1: process.argv[1],\n triggerInProcessRestart: () => service.triggerGatewayProcessRestart(),\n });\n const apiResult = formatUpdateApiResult(result, channel);\n if (result.status === 'error') {\n const { message } = mapUpdateFailure(result, channel);\n log.warn({ channel, reason: result.reason }, 'Gateway: update failed');\n return c.json({\n ok: false,\n error: 'update-failed',\n message,\n result: apiResult,\n });\n }\n log.info({ channel, mode: result.mode }, 'Gateway: update finished');\n return c.json({ ok: true, result: apiResult });\n } catch (err) {\n log.error({ err, channel }, 'Gateway: update threw');\n return c.json(\n {\n ok: false,\n error: 'internal',\n message: err instanceof Error ? err.message : String(err),\n },\n 500,\n );\n } finally {\n await lock.release();\n }\n });\n\n authenticated.post('/api/update/run/stream', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n const channel = normalizeUpdateChannel(config.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;\n\n return streamSSE(c, async (stream) => {\n const lock = await acquireUpdateLock('gateway');\n if (!lock) {\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'busy',\n message: 'Another update is already in progress.',\n }),\n });\n return;\n }\n\n try {\n log.info({ channel }, 'Gateway: starting streamed in-process update');\n const result = await runGatewayUpdateWithPostSteps({\n channel,\n cwd: process.cwd(),\n argv1: process.argv[1],\n triggerInProcessRestart: () => service.triggerGatewayProcessRestart(),\n progress: {\n onStepStart: async (step) => {\n await stream.writeSSE({\n event: 'progress',\n data: JSON.stringify({\n line: `[${step.index + 1}/${step.total}] ${step.name}: ${step.command}`,\n source: 'stdout',\n }),\n });\n },\n onStepComplete: async (step) => {\n if (step.stderrTail) {\n await stream.writeSSE({\n event: 'progress',\n data: JSON.stringify({ line: step.stderrTail, source: 'stderr' }),\n });\n }\n },\n },\n });\n\n const apiResult = formatUpdateApiResult(result, channel);\n if (result.status === 'error') {\n const { message } = mapUpdateFailure(result, channel);\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'update-failed',\n message,\n result: apiResult,\n reason: result.reason,\n }),\n });\n return;\n }\n\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({ ok: true, result: apiResult }),\n });\n } catch (err) {\n log.error({ err, channel }, 'Gateway: streamed update threw');\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'internal',\n message: err instanceof Error ? err.message : String(err),\n }),\n });\n } finally {\n await lock.release();\n }\n });\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createLogger } from "../../../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../../../utils/logger.js";
|
|
3
1
|
import { getDefaultModelSync, init_providers, resolveModel } from "../../../providers/index.js";
|
|
4
2
|
import { resolveTtsProviderConfigSlice } from "../../../voice/tts/config-slice.js";
|
|
5
3
|
import { isTTSAvailable } from "../../../voice/tts/factory.js";
|
|
@@ -12,12 +10,12 @@ import "../../../voice/stt/index.js";
|
|
|
12
10
|
import { mergeSttConfigFromAppConfig } from "../../../channels/attachments/voice-stt-webchat.js";
|
|
13
11
|
import { listSttProvidersForApi } from "../../../voice/stt/list-providers.js";
|
|
14
12
|
import "../../../voice/tts/index.js";
|
|
13
|
+
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
15
14
|
import { listTtsProvidersForApi } from "../../../voice/tts/list-providers.js";
|
|
16
15
|
import { complete } from "@earendil-works/pi-ai";
|
|
17
16
|
//#region src/gateway/hono/routes/voice.ts
|
|
18
17
|
init_providers();
|
|
19
|
-
|
|
20
|
-
const log = createLogger("Gateway:Voice");
|
|
18
|
+
const log = createGatewayRouteLogger("Voice");
|
|
21
19
|
function readVoiceApiKeyFromConfigFileOnly(cfg, kind, providerId) {
|
|
22
20
|
const id = providerId.trim();
|
|
23
21
|
if (!id) return void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice.js","names":[],"sources":["../../../../../src/gateway/hono/routes/voice.ts"],"sourcesContent":["/**\n * Voice routes — POST /api/voice/transcribe\n *\n * Single endpoint that:\n * 1. Runs STT (Whisper preferred for low latency, Alibaba fallback)\n * 2. Optionally runs LLM refine on the raw transcript\n * 3. Returns { raw, refined?, language }\n *\n * LLM refine is auto-applied when a model is resolvable; gracefully degrades\n * to raw-only when no LLM is configured.\n */\n\nimport type { Hono } from 'hono';\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../../providers/index.js';\nimport { isSTTAvailable, transcribe } from '../../../voice/stt/index.js';\nimport { isTTSAvailable, mergeTtsConfigFromAppConfig, speak } from '../../../voice/tts/index.js';\nimport { listTtsProvidersForApi } from '../../../voice/tts/list-providers.js';\nimport { listSttProvidersForApi } from '../../../voice/stt/list-providers.js';\nimport { mergeSttConfigFromAppConfig } from '../../../channels/attachments/voice-stt-webchat.js';\nimport { resolveSttProviderConfigSlice } from '../../../voice/stt/config-slice.js';\nimport { resolveTtsProviderConfigSlice } from '../../../voice/tts/config-slice.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createLogger('Gateway:Voice');\n\nfunction readVoiceApiKeyFromConfigFileOnly(\n cfg: Config,\n kind: 'stt' | 'tts',\n providerId: string,\n): string | undefined {\n const id = providerId.trim();\n if (!id) return undefined;\n const slice =\n kind === 'stt'\n ? resolveSttProviderConfigSlice(id, cfg.tools?.media?.audio)\n : resolveTtsProviderConfigSlice(id, cfg.messages?.tts);\n const key = slice.apiKey;\n return typeof key === 'string' && key.trim() ? key.trim() : undefined;\n}\n\nconst REFINE_TIMEOUT_MS = 15_000;\nconst MAX_AUDIO_BYTES = 25 * 1024 * 1024; // 25 MB\n\nconst REFINE_SYSTEM_PROMPT = `你是语音转文字后处理助手。将语音转写原文整理为高质量文本输入。\n\n规则:\n1. 修正明显的语音识别错误\n2. 添加正确的标点符号\n3. 去除口语赘词(嗯、啊、那个、就是说、然后就是)\n4. 保持原意不变,不要扩写或改变语义\n5. 如果原文已经很好,原样输出\n6. 只输出整理后的文字,不要解释`;\n\nfunction resolveRefineModel(config: Config | undefined): ReturnType<typeof resolveModel> | null {\n const envRef = process.env.XOPC_VOICE_REFINE_MODEL?.trim();\n if (envRef) {\n try {\n return resolveModel(envRef);\n } catch { /* fall through */ }\n }\n for (const candidate of ['openai/gpt-4o-mini', 'google/gemini-2.0-flash']) {\n try {\n return resolveModel(candidate);\n } catch { /* next */ }\n }\n try {\n return resolveModel(getDefaultModelSync(config));\n } catch {\n return null;\n }\n}\n\nasync function refineTranscript(\n raw: string,\n config: Config | undefined,\n signal?: AbortSignal,\n): Promise<string | undefined> {\n if (!raw.trim()) return undefined;\n\n const model = resolveRefineModel(config);\n if (!model) {\n log.debug('No LLM model available for voice refine; returning raw only');\n return undefined;\n }\n\n try {\n const userMsg: UserMessage = {\n role: 'user',\n content: `${REFINE_SYSTEM_PROMPT}\\n\\n原文:${raw}`,\n timestamp: Date.now(),\n };\n\n const timeoutSignal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(REFINE_TIMEOUT_MS)\n : undefined;\n const mergedSignal =\n signal && timeoutSignal && typeof AbortSignal.any === 'function'\n ? AbortSignal.any([signal, timeoutSignal])\n : signal ?? timeoutSignal;\n\n const result = await complete(\n model,\n { messages: [userMsg] },\n {\n maxTokens: Math.min(raw.length * 3, 4096),\n temperature: 0.2,\n signal: mergedSignal as AbortSignal,\n },\n );\n\n let out = '';\n if (Array.isArray(result.content)) {\n for (const c of result.content) {\n if (c && typeof c === 'object' && (c as { type?: string }).type === 'text') {\n out += String((c as { text?: string }).text || '');\n }\n }\n }\n\n const refined = out.trim();\n if (!refined || refined === raw.trim()) return undefined;\n return refined;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log.warn({ errorMessage: msg }, 'Voice refine failed; returning raw only');\n return undefined;\n }\n}\n\nexport function registerVoiceRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n /**\n * GET /api/voice/providers\n *\n * Lists registered SpeechProviderPlugin ids with configured state for the\n * current gateway config (OpenClaw `tts.providers` equivalent).\n */\n authenticated.get('/api/voice/providers', (c) => {\n const config = service.currentConfig as Config;\n const payload = listTtsProvidersForApi(config);\n return c.json({ ok: true, payload });\n });\n\n /**\n * GET /api/voice/stt-providers\n *\n * Lists registered MediaUnderstandingProvider ids with configured state for\n * the current gateway config (OpenClaw `tools.media.audio.providers` equivalent).\n */\n authenticated.get('/api/voice/stt-providers', (c) => {\n const config = service.currentConfig as Config;\n const payload = listSttProvidersForApi(config);\n return c.json({ ok: true, payload });\n });\n\n /**\n * POST /api/voice/reveal-api-key — return plaintext voice provider apiKey from config file only.\n * Body: `{ kind: 'stt' | 'tts', provider: string }`\n */\n authenticated.post('/api/voice/reveal-api-key', strictRateLimitMiddleware, async (c) => {\n let body: { kind?: unknown; provider?: unknown } = {};\n try {\n body = (await c.req.json()) as typeof body;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON body' } }, 400);\n }\n const kind = body.kind === 'stt' || body.kind === 'tts' ? body.kind : null;\n const provider = typeof body.provider === 'string' ? body.provider.trim() : '';\n if (!kind) {\n return c.json({ ok: false, error: { message: 'kind must be \"stt\" or \"tts\"' } }, 400);\n }\n if (!provider) {\n return c.json({ ok: false, error: { message: 'provider is required' } }, 400);\n }\n\n const cfg = service.currentConfig as Config;\n const apiKey = readVoiceApiKeyFromConfigFileOnly(cfg, kind, provider);\n return c.json({\n ok: true,\n payload: {\n kind,\n provider,\n apiKey: apiKey ?? null,\n source: apiKey ? ('config' as const) : ('none' as const),\n },\n });\n });\n\n /**\n * POST /api/voice/tts-test\n *\n * Body: { text: string, provider?: string, model?: string, voice?: string }\n * Response: { ok: true, payload: { audio: string, format: string, provider: string } }\n */\n authenticated.post('/api/voice/tts-test', strictRateLimitMiddleware, async (c) => {\n let body: { text?: unknown; provider?: unknown; model?: unknown; voice?: unknown } = {};\n try {\n body = (await c.req.json()) as typeof body;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON body' } }, 400);\n }\n\n const text = typeof body.text === 'string' ? body.text.trim() : '';\n if (!text) {\n return c.json({ ok: false, error: { message: 'text is required' } }, 400);\n }\n if (text.length > 1000) {\n return c.json({ ok: false, error: { message: 'text exceeds 1000 characters' } }, 400);\n }\n\n const config = service.currentConfig as Config;\n const baseTtsConfig = mergeTtsConfigFromAppConfig(config.messages?.tts);\n const provider = typeof body.provider === 'string' && body.provider.trim() ? body.provider.trim() : baseTtsConfig.provider;\n const ttsConfig = {\n ...baseTtsConfig,\n enabled: true,\n provider,\n fallback: { enabled: false, order: [provider] },\n };\n\n if (!isTTSAvailable(ttsConfig)) {\n return c.json({\n ok: false,\n error: { message: `TTS provider \"${provider}\" is not configured.` },\n }, 503);\n }\n\n try {\n const result = await speak(text, ttsConfig, {\n appConfig: config,\n parseDirectives: false,\n tts: {\n ...(typeof body.model === 'string' && body.model.trim() ? { model: body.model.trim() } : {}),\n ...(typeof body.voice === 'string' && body.voice.trim() ? { voice: body.voice.trim() } : {}),\n },\n });\n return c.json({\n ok: true,\n payload: {\n audio: result.audio.toString('base64'),\n format: result.format,\n provider: result.provider,\n ...(result.duration !== undefined ? { duration: result.duration } : {}),\n },\n });\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log.error({ errorMessage: msg, provider }, 'Voice TTS test failed');\n return c.json({ ok: false, error: { message: `TTS test failed: ${msg}` } }, 502);\n }\n });\n\n /**\n * POST /api/voice/transcribe\n *\n * Body: { audio: string (base64), mimeType: string, language?: string }\n * Response: { ok: true, payload: { raw: string, refined?: string, language?: string } }\n */\n authenticated.post('/api/voice/transcribe', async (c) => {\n let body: { audio?: string; mimeType?: string; language?: string } = {};\n try {\n body = (await c.req.json()) as typeof body;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON body' } }, 400);\n }\n\n const { audio, mimeType, language } = body;\n if (!audio || typeof audio !== 'string') {\n return c.json({ ok: false, error: { message: 'Missing required field: audio (base64)' } }, 400);\n }\n if (!mimeType || typeof mimeType !== 'string') {\n return c.json({ ok: false, error: { message: 'Missing required field: mimeType' } }, 400);\n }\n\n // Decode base64 audio\n let audioBuffer: Buffer;\n try {\n audioBuffer = Buffer.from(audio, 'base64');\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid base64 audio data' } }, 400);\n }\n\n if (audioBuffer.length === 0) {\n return c.json({ ok: false, error: { message: 'Empty audio data' } }, 400);\n }\n if (audioBuffer.length > MAX_AUDIO_BYTES) {\n return c.json({ ok: false, error: { message: 'Audio data exceeds 25 MB limit' } }, 400);\n }\n\n // Resolve STT config from app config\n const config = service.currentConfig as Config;\n const sttConfigRaw = config.tools?.media?.audio;\n const sttConfig = mergeSttConfigFromAppConfig(sttConfigRaw, config.tools?.media);\n\n if (!isSTTAvailable(sttConfig)) {\n return c.json({\n ok: false,\n error: { message: 'STT is not configured. Enable STT in gateway config (tools.media.audio).' },\n }, 503);\n }\n\n // Run STT\n let raw: string;\n let detectedLanguage: string | undefined;\n try {\n const result = await transcribe(audioBuffer, sttConfig, {\n language: language || (sttConfig.provider === 'alibaba' ? 'zh' : undefined),\n });\n raw = result.text;\n detectedLanguage = result.language ?? language;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log.error({ errorMessage: msg }, 'Voice transcription failed');\n return c.json({ ok: false, error: { message: `Transcription failed: ${msg}` } }, 502);\n }\n\n if (!raw.trim()) {\n return c.json({\n ok: true,\n payload: { raw: '', language: detectedLanguage },\n });\n }\n\n // Run LLM refine (auto, best-effort)\n const refined = await refineTranscript(raw, config);\n\n return c.json({\n ok: true,\n payload: {\n raw,\n ...(refined ? { refined } : {}),\n ...(detectedLanguage ? { language: detectedLanguage } : {}),\n },\n });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"voice.js","names":[],"sources":["../../../../../src/gateway/hono/routes/voice.ts"],"sourcesContent":["/**\n * Voice routes — POST /api/voice/transcribe\n *\n * Single endpoint that:\n * 1. Runs STT (Whisper preferred for low latency, Alibaba fallback)\n * 2. Optionally runs LLM refine on the raw transcript\n * 3. Returns { raw, refined?, language }\n *\n * LLM refine is auto-applied when a model is resolvable; gracefully degrades\n * to raw-only when no LLM is configured.\n */\n\nimport type { Hono } from 'hono';\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../../providers/index.js';\nimport { isSTTAvailable, transcribe } from '../../../voice/stt/index.js';\nimport { isTTSAvailable, mergeTtsConfigFromAppConfig, speak } from '../../../voice/tts/index.js';\nimport { listTtsProvidersForApi } from '../../../voice/tts/list-providers.js';\nimport { listSttProvidersForApi } from '../../../voice/stt/list-providers.js';\nimport { mergeSttConfigFromAppConfig } from '../../../channels/attachments/voice-stt-webchat.js';\nimport { resolveSttProviderConfigSlice } from '../../../voice/stt/config-slice.js';\nimport { resolveTtsProviderConfigSlice } from '../../../voice/tts/config-slice.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createGatewayRouteLogger('Voice');\n\nfunction readVoiceApiKeyFromConfigFileOnly(\n cfg: Config,\n kind: 'stt' | 'tts',\n providerId: string,\n): string | undefined {\n const id = providerId.trim();\n if (!id) return undefined;\n const slice =\n kind === 'stt'\n ? resolveSttProviderConfigSlice(id, cfg.tools?.media?.audio)\n : resolveTtsProviderConfigSlice(id, cfg.messages?.tts);\n const key = slice.apiKey;\n return typeof key === 'string' && key.trim() ? key.trim() : undefined;\n}\n\nconst REFINE_TIMEOUT_MS = 15_000;\nconst MAX_AUDIO_BYTES = 25 * 1024 * 1024; // 25 MB\n\nconst REFINE_SYSTEM_PROMPT = `你是语音转文字后处理助手。将语音转写原文整理为高质量文本输入。\n\n规则:\n1. 修正明显的语音识别错误\n2. 添加正确的标点符号\n3. 去除口语赘词(嗯、啊、那个、就是说、然后就是)\n4. 保持原意不变,不要扩写或改变语义\n5. 如果原文已经很好,原样输出\n6. 只输出整理后的文字,不要解释`;\n\nfunction resolveRefineModel(config: Config | undefined): ReturnType<typeof resolveModel> | null {\n const envRef = process.env.XOPC_VOICE_REFINE_MODEL?.trim();\n if (envRef) {\n try {\n return resolveModel(envRef);\n } catch { /* fall through */ }\n }\n for (const candidate of ['openai/gpt-4o-mini', 'google/gemini-2.0-flash']) {\n try {\n return resolveModel(candidate);\n } catch { /* next */ }\n }\n try {\n return resolveModel(getDefaultModelSync(config));\n } catch {\n return null;\n }\n}\n\nasync function refineTranscript(\n raw: string,\n config: Config | undefined,\n signal?: AbortSignal,\n): Promise<string | undefined> {\n if (!raw.trim()) return undefined;\n\n const model = resolveRefineModel(config);\n if (!model) {\n log.debug('No LLM model available for voice refine; returning raw only');\n return undefined;\n }\n\n try {\n const userMsg: UserMessage = {\n role: 'user',\n content: `${REFINE_SYSTEM_PROMPT}\\n\\n原文:${raw}`,\n timestamp: Date.now(),\n };\n\n const timeoutSignal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(REFINE_TIMEOUT_MS)\n : undefined;\n const mergedSignal =\n signal && timeoutSignal && typeof AbortSignal.any === 'function'\n ? AbortSignal.any([signal, timeoutSignal])\n : signal ?? timeoutSignal;\n\n const result = await complete(\n model,\n { messages: [userMsg] },\n {\n maxTokens: Math.min(raw.length * 3, 4096),\n temperature: 0.2,\n signal: mergedSignal as AbortSignal,\n },\n );\n\n let out = '';\n if (Array.isArray(result.content)) {\n for (const c of result.content) {\n if (c && typeof c === 'object' && (c as { type?: string }).type === 'text') {\n out += String((c as { text?: string }).text || '');\n }\n }\n }\n\n const refined = out.trim();\n if (!refined || refined === raw.trim()) return undefined;\n return refined;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log.warn({ errorMessage: msg }, 'Voice refine failed; returning raw only');\n return undefined;\n }\n}\n\nexport function registerVoiceRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n /**\n * GET /api/voice/providers\n *\n * Lists registered SpeechProviderPlugin ids with configured state for the\n * current gateway config (OpenClaw `tts.providers` equivalent).\n */\n authenticated.get('/api/voice/providers', (c) => {\n const config = service.currentConfig as Config;\n const payload = listTtsProvidersForApi(config);\n return c.json({ ok: true, payload });\n });\n\n /**\n * GET /api/voice/stt-providers\n *\n * Lists registered MediaUnderstandingProvider ids with configured state for\n * the current gateway config (OpenClaw `tools.media.audio.providers` equivalent).\n */\n authenticated.get('/api/voice/stt-providers', (c) => {\n const config = service.currentConfig as Config;\n const payload = listSttProvidersForApi(config);\n return c.json({ ok: true, payload });\n });\n\n /**\n * POST /api/voice/reveal-api-key — return plaintext voice provider apiKey from config file only.\n * Body: `{ kind: 'stt' | 'tts', provider: string }`\n */\n authenticated.post('/api/voice/reveal-api-key', strictRateLimitMiddleware, async (c) => {\n let body: { kind?: unknown; provider?: unknown } = {};\n try {\n body = (await c.req.json()) as typeof body;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON body' } }, 400);\n }\n const kind = body.kind === 'stt' || body.kind === 'tts' ? body.kind : null;\n const provider = typeof body.provider === 'string' ? body.provider.trim() : '';\n if (!kind) {\n return c.json({ ok: false, error: { message: 'kind must be \"stt\" or \"tts\"' } }, 400);\n }\n if (!provider) {\n return c.json({ ok: false, error: { message: 'provider is required' } }, 400);\n }\n\n const cfg = service.currentConfig as Config;\n const apiKey = readVoiceApiKeyFromConfigFileOnly(cfg, kind, provider);\n return c.json({\n ok: true,\n payload: {\n kind,\n provider,\n apiKey: apiKey ?? null,\n source: apiKey ? ('config' as const) : ('none' as const),\n },\n });\n });\n\n /**\n * POST /api/voice/tts-test\n *\n * Body: { text: string, provider?: string, model?: string, voice?: string }\n * Response: { ok: true, payload: { audio: string, format: string, provider: string } }\n */\n authenticated.post('/api/voice/tts-test', strictRateLimitMiddleware, async (c) => {\n let body: { text?: unknown; provider?: unknown; model?: unknown; voice?: unknown } = {};\n try {\n body = (await c.req.json()) as typeof body;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON body' } }, 400);\n }\n\n const text = typeof body.text === 'string' ? body.text.trim() : '';\n if (!text) {\n return c.json({ ok: false, error: { message: 'text is required' } }, 400);\n }\n if (text.length > 1000) {\n return c.json({ ok: false, error: { message: 'text exceeds 1000 characters' } }, 400);\n }\n\n const config = service.currentConfig as Config;\n const baseTtsConfig = mergeTtsConfigFromAppConfig(config.messages?.tts);\n const provider = typeof body.provider === 'string' && body.provider.trim() ? body.provider.trim() : baseTtsConfig.provider;\n const ttsConfig = {\n ...baseTtsConfig,\n enabled: true,\n provider,\n fallback: { enabled: false, order: [provider] },\n };\n\n if (!isTTSAvailable(ttsConfig)) {\n return c.json({\n ok: false,\n error: { message: `TTS provider \"${provider}\" is not configured.` },\n }, 503);\n }\n\n try {\n const result = await speak(text, ttsConfig, {\n appConfig: config,\n parseDirectives: false,\n tts: {\n ...(typeof body.model === 'string' && body.model.trim() ? { model: body.model.trim() } : {}),\n ...(typeof body.voice === 'string' && body.voice.trim() ? { voice: body.voice.trim() } : {}),\n },\n });\n return c.json({\n ok: true,\n payload: {\n audio: result.audio.toString('base64'),\n format: result.format,\n provider: result.provider,\n ...(result.duration !== undefined ? { duration: result.duration } : {}),\n },\n });\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log.error({ errorMessage: msg, provider }, 'Voice TTS test failed');\n return c.json({ ok: false, error: { message: `TTS test failed: ${msg}` } }, 502);\n }\n });\n\n /**\n * POST /api/voice/transcribe\n *\n * Body: { audio: string (base64), mimeType: string, language?: string }\n * Response: { ok: true, payload: { raw: string, refined?: string, language?: string } }\n */\n authenticated.post('/api/voice/transcribe', async (c) => {\n let body: { audio?: string; mimeType?: string; language?: string } = {};\n try {\n body = (await c.req.json()) as typeof body;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON body' } }, 400);\n }\n\n const { audio, mimeType, language } = body;\n if (!audio || typeof audio !== 'string') {\n return c.json({ ok: false, error: { message: 'Missing required field: audio (base64)' } }, 400);\n }\n if (!mimeType || typeof mimeType !== 'string') {\n return c.json({ ok: false, error: { message: 'Missing required field: mimeType' } }, 400);\n }\n\n // Decode base64 audio\n let audioBuffer: Buffer;\n try {\n audioBuffer = Buffer.from(audio, 'base64');\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid base64 audio data' } }, 400);\n }\n\n if (audioBuffer.length === 0) {\n return c.json({ ok: false, error: { message: 'Empty audio data' } }, 400);\n }\n if (audioBuffer.length > MAX_AUDIO_BYTES) {\n return c.json({ ok: false, error: { message: 'Audio data exceeds 25 MB limit' } }, 400);\n }\n\n // Resolve STT config from app config\n const config = service.currentConfig as Config;\n const sttConfigRaw = config.tools?.media?.audio;\n const sttConfig = mergeSttConfigFromAppConfig(sttConfigRaw, config.tools?.media);\n\n if (!isSTTAvailable(sttConfig)) {\n return c.json({\n ok: false,\n error: { message: 'STT is not configured. Enable STT in gateway config (tools.media.audio).' },\n }, 503);\n }\n\n // Run STT\n let raw: string;\n let detectedLanguage: string | undefined;\n try {\n const result = await transcribe(audioBuffer, sttConfig, {\n language: language || (sttConfig.provider === 'alibaba' ? 'zh' : undefined),\n });\n raw = result.text;\n detectedLanguage = result.language ?? language;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log.error({ errorMessage: msg }, 'Voice transcription failed');\n return c.json({ ok: false, error: { message: `Transcription failed: ${msg}` } }, 502);\n }\n\n if (!raw.trim()) {\n return c.json({\n ok: true,\n payload: { raw: '', language: detectedLanguage },\n });\n }\n\n // Run LLM refine (auto, best-effort)\n const refined = await refineTranscript(raw, config);\n\n return c.json({\n ok: true,\n payload: {\n raw,\n ...(refined ? { refined } : {}),\n ...(detectedLanguage ? { language: detectedLanguage } : {}),\n },\n });\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createLogger } from "../../../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../../../utils/logger.js";
|
|
3
1
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentHomeDir, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
|
|
4
2
|
import { extractProfileAgentId } from "../../../config/agent-profile.js";
|
|
5
3
|
import { validateWritePath } from "../../../agent/sandbox/path-policy.js";
|
|
@@ -10,16 +8,16 @@ import { resolveSafeTtsFilePath } from "../../../channels/attachments/outbound-t
|
|
|
10
8
|
import { buildFilePathClassifierContext, classifyFileLocation, displayNameForPath, fileRefSessionKeysMatch, resolveFileReferenceCandidate } from "../../file-path-classifier.js";
|
|
11
9
|
import { fileReferenceRegistry } from "../../file-reference-registry.js";
|
|
12
10
|
import { resolveHeartbeatMdPath } from "../../workspace-heartbeat-path.js";
|
|
11
|
+
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
13
12
|
import { listWorkspaceRelativeFilesFsFallback } from "../../workspace-fs-file-list.js";
|
|
14
13
|
import { runRipgrepInDirectory, runRipgrepListFiles } from "../../workspace-ripgrep.js";
|
|
15
|
-
import {
|
|
14
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
16
15
|
import { constants } from "node:fs";
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
17
17
|
import { copyFile, link, mkdir, readFile, readdir, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
18
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
19
18
|
//#region src/gateway/hono/routes/workspace.ts
|
|
20
19
|
init_agent_scope();
|
|
21
|
-
|
|
22
|
-
const log = createLogger("HonoApp");
|
|
20
|
+
const log = createGatewayRouteLogger("Workspace");
|
|
23
21
|
/** Agent home for persisted `inbound/` and `tts/` attachments (matches `persistOutboundTtsAudio` / `prepareInboundAttachments`). */
|
|
24
22
|
function resolvePersistedAttachmentAgentHome(cfg, sessionKeyRaw) {
|
|
25
23
|
const sk = typeof sessionKeyRaw === "string" ? sessionKeyRaw.trim() : "";
|