@agentprojectcontext/apx 1.81.0 → 1.89.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -8
- package/skills/apc-context/SKILL.md +14 -7
- package/skills/apx/SKILL.md +62 -2
- package/skills/apx-mcp/SKILL.md +42 -15
- package/src/core/agent/a2a/peers.js +161 -0
- package/src/core/agent/a2a/reply.js +379 -27
- package/src/core/agent/abort.js +25 -0
- package/src/core/agent/agent-model.js +58 -0
- package/src/core/agent/agent-tools.js +101 -0
- package/src/core/agent/author-line.js +110 -0
- package/src/core/agent/build-agent-system.js +52 -18
- package/src/core/agent/channels/voice-context.js +17 -2
- package/src/core/agent/closing-floor.js +117 -0
- package/src/core/agent/constants.js +119 -11
- package/src/core/agent/engine-call.js +56 -0
- package/src/core/agent/group/run-group-turn.js +218 -0
- package/src/core/agent/group/turn-resolver.js +165 -0
- package/src/core/agent/judge.js +138 -11
- package/src/core/agent/loop/side-effects.js +106 -3
- package/src/core/agent/memory.js +31 -18
- package/src/core/agent/model-capabilities.js +47 -0
- package/src/core/agent/model-router.js +11 -40
- package/src/core/agent/prompt-builder.js +47 -0
- package/src/core/agent/prompts/channels/a2a.md +12 -0
- package/src/core/agent/prompts/channels/code.md +3 -1
- package/src/core/agent/prompts/channels/telegram.md +2 -0
- package/src/core/agent/prompts/channels/web_code.md +1 -1
- package/src/core/agent/prompts/channels/whatsapp.md +37 -0
- package/src/core/agent/prompts/core/agent-base.md +2 -0
- package/src/core/agent/prompts/discipline/action.md +1 -0
- package/src/core/agent/prompts/discipline/two-segment.md +2 -1
- package/src/core/agent/prompts/modes/mobility.md +36 -0
- package/src/core/agent/retry.js +42 -0
- package/src/core/agent/run-agent.js +322 -25
- package/src/core/agent/run-turn.js +253 -0
- package/src/core/agent/self-memory.js +18 -52
- package/src/core/agent/skills/agent-skills.js +118 -0
- package/src/core/agent/skills/catalog.js +1 -1
- package/src/core/agent/skills/declared.js +13 -0
- package/src/core/agent/skills/index-store.js +8 -1
- package/src/core/agent/skills/inspector.js +20 -3
- package/src/core/agent/skills/loader.js +18 -3
- package/src/core/agent/skills/media.js +121 -0
- package/src/core/agent/skills/origin.js +61 -0
- package/src/core/agent/skills/sections.js +136 -0
- package/src/core/agent/super-agent.js +54 -14
- package/src/core/agent/tools/handlers/_calendar.js +50 -0
- package/src/core/agent/tools/handlers/add-mcp.js +103 -0
- package/src/core/agent/tools/handlers/asana-create-task.js +3 -1
- package/src/core/agent/tools/handlers/attach-media.js +56 -0
- package/src/core/agent/tools/handlers/calendar-create-event.js +38 -0
- package/src/core/agent/tools/handlers/calendar-find-slot.js +39 -0
- package/src/core/agent/tools/handlers/calendar-list-events.js +39 -0
- package/src/core/agent/tools/handlers/calendar-update-event.js +35 -0
- package/src/core/agent/tools/handlers/call-agent.js +14 -6
- package/src/core/agent/tools/handlers/call-runtime.js +27 -49
- package/src/core/agent/tools/handlers/comment-task.js +78 -0
- package/src/core/agent/tools/handlers/complete-task.js +60 -0
- package/src/core/agent/tools/handlers/configure-agent.js +70 -0
- package/src/core/agent/tools/handlers/create-agent.js +68 -0
- package/src/core/agent/tools/handlers/create-task.js +41 -3
- package/src/core/agent/tools/handlers/import-agent.js +5 -5
- package/src/core/agent/tools/handlers/list-mcp-tools.js +83 -0
- package/src/core/agent/tools/handlers/list-routines.js +46 -0
- package/src/core/agent/tools/handlers/list-tasks.js +8 -1
- package/src/core/agent/tools/handlers/mark-commitment.js +57 -0
- package/src/core/agent/tools/handlers/read-skill.js +64 -0
- package/src/core/agent/tools/handlers/remember-routine.js +2 -8
- package/src/core/agent/tools/handlers/remember.js +82 -6
- package/src/core/agent/tools/handlers/remove-agent.js +42 -0
- package/src/core/agent/tools/handlers/run-routine.js +94 -0
- package/src/core/agent/tools/handlers/run-shell.js +44 -2
- package/src/core/agent/tools/handlers/send-telegram.js +41 -19
- package/src/core/agent/tools/handlers/set-agent-prompt.js +44 -0
- package/src/core/agent/tools/handlers/view-media.js +69 -0
- package/src/core/agent/tools/handlers/write-agent-memory.js +52 -0
- package/src/core/agent/tools/helpers.js +36 -4
- package/src/core/agent/tools/names.js +64 -0
- package/src/core/agent/tools/registry-bridge.js +24 -1
- package/src/core/agent/tools/registry.js +79 -0
- package/src/core/agent/tools/tool-call-parser.js +136 -13
- package/src/core/agent/vision-bridge.js +69 -0
- package/src/core/apc/agent-identity.js +74 -0
- package/src/core/apc/agent-rename-refs.js +187 -0
- package/src/core/apc/agent-write.js +312 -0
- package/src/core/apc/agents-vault.js +1 -1
- package/src/core/apc/blob-keys.js +42 -0
- package/src/core/apc/frontmatter.js +166 -10
- package/src/core/apc/parser.js +33 -83
- package/src/core/apc/paths.js +4 -6
- package/src/core/apc/project-memory.js +44 -0
- package/src/core/apc/projects-helpers.js +33 -0
- package/src/core/apc/scaffold.js +36 -16
- package/src/core/channels/telegram/ask-callbacks.js +103 -0
- package/src/core/channels/telegram/dispatch.js +154 -30
- package/src/core/channels/telegram/helpers.js +59 -7
- package/src/core/channels/telegram/inbound/audio.js +26 -30
- package/src/core/channels/telegram/inbound/file.js +22 -32
- package/src/core/channels/telegram/inbound/photo.js +24 -28
- package/src/core/channels/telegram/progress-gate.js +76 -0
- package/src/core/channels/telegram/reply.js +151 -43
- package/src/core/channels/telegram/voice-note.js +150 -0
- package/src/core/config/index.js +53 -54
- package/src/core/config/paths.js +117 -31
- package/src/core/config/redact.js +89 -4
- package/src/core/config/secret-values.js +2 -4
- package/src/core/constants/actors.js +5 -0
- package/src/core/constants/channels.js +3 -1
- package/src/core/constants/task-categories.js +73 -0
- package/src/core/constants/task-fields.js +28 -0
- package/src/core/engines/_globs.js +33 -0
- package/src/core/engines/anthropic.js +19 -1
- package/src/core/engines/catalog.js +20 -0
- package/src/core/engines/gemini.js +84 -16
- package/src/core/engines/index.js +19 -3
- package/src/core/engines/mock.js +145 -1
- package/src/core/engines/openai-compatible.js +150 -15
- package/src/core/engines/presets.js +36 -9
- package/src/core/engines/zen.js +131 -0
- package/src/core/events/bus.js +140 -0
- package/src/core/events/mascot-notify.js +156 -0
- package/src/core/http-tools/browser.js +366 -36
- package/src/core/http-tools/catalog.js +206 -22
- package/src/core/http-tools/grep.js +62 -7
- package/src/core/http-tools/registry.js +3 -1
- package/src/core/i18n/en.js +34 -3
- package/src/core/i18n/es.js +36 -4
- package/src/core/i18n/index.js +5 -5
- package/src/core/i18n/pt.js +32 -3
- package/src/core/identity/self.js +14 -1
- package/src/core/images/engines/a1111.js +219 -0
- package/src/core/images/engines/index.js +187 -0
- package/src/core/images/engines/mock.js +74 -0
- package/src/core/images/engines/openai.js +130 -0
- package/src/core/images/engines/sdcpp.js +204 -0
- package/src/core/images/engines/shared.js +218 -0
- package/src/core/images/generate.js +260 -0
- package/src/core/integrations/catalog.js +8 -3
- package/src/core/integrations/plugins/_google-oauth.js +179 -0
- package/src/core/integrations/plugins/asana.js +7 -3
- package/src/core/integrations/plugins/calendar.js +404 -0
- package/src/core/integrations/store.js +2 -0
- package/src/core/memory/broker.js +16 -1
- package/src/core/memory/compactor.js +19 -3
- package/src/core/memory/consolidate.js +2 -2
- package/src/core/memory/dated-log.js +66 -0
- package/src/core/memory/embed-engines/custom.js +59 -0
- package/src/core/memory/embed-engines/gemini.js +9 -3
- package/src/core/memory/embed-engines/index.js +87 -15
- package/src/core/memory/embeddings.js +52 -24
- package/src/core/memory/index.js +13 -3
- package/src/core/memory/indexer.js +83 -27
- package/src/core/memory/prune.js +182 -0
- package/src/core/memory/store.js +22 -0
- package/src/core/memory/summarizer.js +72 -8
- package/src/core/mobility/answer.js +80 -0
- package/src/core/mobility/geofence.js +667 -0
- package/src/core/mobility/osm-route.js +282 -0
- package/src/core/mobility/preferences.js +91 -0
- package/src/core/mobility/state.js +245 -0
- package/src/core/mobility/trip-event.js +384 -0
- package/src/core/net/tailscale.js +168 -0
- package/src/core/profiles/bundled/secretary/PROFILE.md +32 -42
- package/src/core/profiles/bundled/secretary/config.schema.es.json +68 -0
- package/src/core/profiles/bundled/secretary/config.schema.json +30 -2
- package/src/core/profiles/bundled/secretary/profile.json +3 -1
- package/src/core/profiles/bundled/secretary/routines/a2a-sweep.json +20 -0
- package/src/core/profiles/bundled/secretary/routines/day-close.json +4 -1
- package/src/core/profiles/bundled/secretary/routines/day-open.json +7 -1
- package/src/core/profiles/bundled/secretary/routines/watch.json +13 -2
- package/src/core/profiles/lifecycle.js +243 -19
- package/src/core/profiles/paths.js +12 -0
- package/src/core/profiles/store.js +47 -0
- package/src/core/routines/active-runs.js +213 -0
- package/src/core/routines/delivery.js +612 -0
- package/src/core/routines/header.js +88 -0
- package/src/core/routines/index.js +26 -0
- package/src/core/routines/run-log.js +78 -0
- package/src/core/routines/runner.js +629 -66
- package/src/core/routines/signals.js +75 -0
- package/src/core/runtime-skills/apc-context/SKILL.md +14 -7
- package/src/core/runtime-skills/apx/SKILL.md +93 -1
- package/src/core/runtime-skills/apx-agency-agents/SKILL.md +2 -2
- package/src/core/runtime-skills/apx-agent/SKILL.md +134 -19
- package/src/core/runtime-skills/apx-commitment/SKILL.md +21 -11
- package/src/core/runtime-skills/apx-image/SKILL.md +60 -0
- package/src/core/runtime-skills/apx-integrations/SKILL.md +82 -0
- package/src/core/runtime-skills/apx-mcp/SKILL.md +45 -14
- package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +4 -4
- package/src/core/runtime-skills/apx-profile/SKILL.md +27 -2
- package/src/core/runtime-skills/apx-project/SKILL.md +23 -2
- package/src/core/runtime-skills/apx-routine/SKILL.md +40 -17
- package/src/core/runtime-skills/apx-runtime/SKILL.md +124 -14
- package/src/core/runtime-skills/apx-sessions/SKILL.md +7 -6
- package/src/core/runtime-skills/apx-skill-builder/SKILL.md +15 -13
- package/src/core/runtime-skills/apx-task/SKILL.md +79 -26
- package/src/core/runtime-skills/apx-telegram/SKILL.md +12 -12
- package/src/core/runtime-skills/apx-transcribe/SKILL.md +56 -0
- package/src/core/runtime-skills/apx-voice/SKILL.md +27 -8
- package/src/core/runtime-skills/claude-code/SKILL.md +8 -0
- package/src/core/runtime-skills/openrouter/SKILL.md +8 -2
- package/src/core/runtimes/_spawn.js +9 -1
- package/src/core/runtimes/claude-code.js +11 -2
- package/src/core/runtimes/codex.js +44 -10
- package/src/core/runtimes/index.js +17 -2
- package/src/core/runtimes/opencode.js +88 -9
- package/src/core/runtimes/outcome.js +119 -0
- package/src/core/sessions/index.js +193 -1
- package/src/core/stores/agent-inbox.js +109 -23
- package/src/core/stores/code-sessions.js +21 -0
- package/src/core/stores/commitments.js +27 -3
- package/src/core/stores/conversations.js +220 -20
- package/src/core/stores/deliveries.js +177 -0
- package/src/core/stores/media-archive.js +228 -0
- package/src/core/stores/messages.js +1096 -112
- package/src/core/stores/organization.js +34 -0
- package/src/core/stores/project-memory.js +71 -0
- package/src/core/stores/routine-memory.js +16 -8
- package/src/core/stores/routines.js +27 -49
- package/src/core/stores/sessions.js +4 -8
- package/src/core/stores/tasks.js +212 -18
- package/src/core/stores/turn-record.js +209 -0
- package/src/core/tasks/columns.js +136 -0
- package/src/core/tasks/comment-turn.js +258 -0
- package/src/core/util/time.js +13 -0
- package/src/core/voice/engines/index.js +54 -1
- package/src/core/voice/engines/openai.js +50 -4
- package/src/core/voice/opus.js +67 -0
- package/src/core/voice/pronounceable.js +43 -0
- package/src/core/voice/transcription.js +4 -0
- package/src/core/voice/tts.js +114 -24
- package/src/host/daemon/active-turns.js +188 -0
- package/src/host/daemon/api/admin-config.js +9 -0
- package/src/host/daemon/api/agents.js +99 -90
- package/src/host/daemon/api/artifact-preview.js +7 -6
- package/src/host/daemon/api/artifacts.js +3 -2
- package/src/host/daemon/api/code.js +55 -9
- package/src/host/daemon/api/commitments.js +11 -0
- package/src/host/daemon/api/confirm.js +3 -2
- package/src/host/daemon/api/conversations.js +543 -35
- package/src/host/daemon/api/deck.js +9 -8
- package/src/host/daemon/api/deliveries.js +33 -0
- package/src/host/daemon/api/desktop.js +5 -4
- package/src/host/daemon/api/embeddings.js +15 -6
- package/src/host/daemon/api/engines.js +59 -8
- package/src/host/daemon/api/exec.js +437 -121
- package/src/host/daemon/api/groups.js +215 -0
- package/src/host/daemon/api/images.js +107 -0
- package/src/host/daemon/api/inbox.js +123 -2
- package/src/host/daemon/api/integrations.js +64 -2
- package/src/host/daemon/api/mcps.js +7 -6
- package/src/host/daemon/api/media.js +283 -0
- package/src/host/daemon/api/mobility.js +177 -0
- package/src/host/daemon/api/net.js +182 -0
- package/src/host/daemon/api/pairing.js +38 -5
- package/src/host/daemon/api/profiles.js +30 -2
- package/src/host/daemon/api/routines.js +36 -4
- package/src/host/daemon/api/runtimes.js +74 -39
- package/src/host/daemon/api/sessions-search.js +7 -2
- package/src/host/daemon/api/sessions.js +44 -2
- package/src/host/daemon/api/shared.js +127 -20
- package/src/host/daemon/api/skills.js +11 -4
- package/src/host/daemon/api/super-agent.js +384 -53
- package/src/host/daemon/api/tasks.js +180 -10
- package/src/host/daemon/api/telegram.js +11 -10
- package/src/host/daemon/api/thread-faces.js +159 -0
- package/src/host/daemon/api/top-level.js +3 -3
- package/src/host/daemon/api/transcribe.js +11 -10
- package/src/host/daemon/api/tts.js +97 -4
- package/src/host/daemon/api/turn-abort.js +23 -0
- package/src/host/daemon/api/turns.js +49 -0
- package/src/host/daemon/api/voice.js +5 -4
- package/src/host/daemon/api/web.js +98 -0
- package/src/host/daemon/api.js +39 -0
- package/src/host/daemon/delivery-sweep.js +58 -0
- package/src/host/daemon/desktop-ws.js +5 -23
- package/src/host/daemon/events-ws.js +273 -0
- package/src/host/daemon/index.js +59 -15
- package/src/host/daemon/plugins/desktop/index.js +17 -4
- package/src/host/daemon/plugins/telegram/index.js +78 -40
- package/src/host/daemon/pty-bridge.py +99 -0
- package/src/host/daemon/routines-scheduler.js +1 -0
- package/src/host/daemon/smoke.js +1 -2
- package/src/host/daemon/terminal-ws.js +132 -0
- package/src/host/daemon/tts-keepwarm.js +87 -0
- package/src/host/daemon/wakeup.js +11 -6
- package/src/host/daemon/whisper-server.js +44 -0
- package/src/host/daemon/whisper-server.py +70 -13
- package/src/host/daemon/ws-auth.js +28 -0
- package/src/interfaces/android/app/build.gradle +42 -0
- package/src/interfaces/android/app/proguard-rules.pro +4 -0
- package/src/interfaces/android/app/src/main/AndroidManifest.xml +139 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AlertScreen.java +139 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AndroidAutoDetector.java +106 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxCarAppService.java +57 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxPreferences.java +165 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarAlertStore.java +84 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageActionReceiver.java +47 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageNotification.java +152 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonAddress.java +35 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonClient.java +339 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DeviceLocation.java +38 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ErrandScreen.java +127 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MainActivity.java +872 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationDetector.java +63 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationListenerService.java +453 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsShareIntentParser.java +93 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotBlobCatalog.java +66 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotOverlayService.java +448 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotView.java +249 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MessageFrameParser.java +240 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/NotifyChannels.java +69 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityActionReceiver.java +78 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityNotification.java +161 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/StartupReceiver.java +57 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelEventGate.java +62 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelStatusBanner.java +116 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripLocationService.java +272 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripPlacesSheet.java +203 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripScreen.java +182 -0
- package/src/interfaces/android/app/src/main/res/drawable/app_background.xml +12 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_app.xml +10 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_launcher_foreground.xml +12 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_notification.xml +22 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_trip_car.xml +37 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/apx_logo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_amatista.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_aqua.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_brasa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_campana.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_caracol.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_carbon.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cobalto.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cometa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_coral.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cubi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_eclipse.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_faro.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_gajo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_iris.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_kiwi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_laguna.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_lila.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_menta.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_nimbo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_noche.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_onyx.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_orbita.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_ovni.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_papa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_parche.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_peon.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_perla.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_pino.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_quad.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_rubi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_saturno.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trebol.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trino.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_volcan.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_zafiro.png +0 -0
- package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- package/src/interfaces/android/app/src/main/res/raw/apx_notification.mp3 +0 -0
- package/src/interfaces/android/app/src/main/res/values/colors.xml +4 -0
- package/src/interfaces/android/app/src/main/res/values/strings.xml +25 -0
- package/src/interfaces/android/app/src/main/res/values/styles.xml +10 -0
- package/src/interfaces/android/app/src/main/res/values-v31/styles.xml +14 -0
- package/src/interfaces/android/app/src/main/res/xml/automotive_app_desc.xml +9 -0
- package/src/interfaces/android/app/src/main/res/xml/network_security_config.xml +10 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/AndroidAutoDetectorTest.java +85 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/CarAlertStoreTest.java +104 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/DaemonAddressTest.java +23 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsNavigationDetectorTest.java +69 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsShareIntentParserTest.java +31 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MessageFrameParserTest.java +180 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TravelEventGateTest.java +64 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TripPlacesSheetTest.java +66 -0
- package/src/interfaces/android/build.gradle +3 -0
- package/src/interfaces/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/src/interfaces/android/gradle/wrapper/gradle-wrapper.properties +9 -0
- package/src/interfaces/android/gradle.properties +3 -0
- package/src/interfaces/android/gradlew +248 -0
- package/src/interfaces/android/gradlew.bat +82 -0
- package/src/interfaces/android/settings.gradle +18 -0
- package/src/interfaces/cli/commands/a2a.js +145 -4
- package/src/interfaces/cli/commands/agent.js +247 -22
- package/src/interfaces/cli/commands/code.js +1 -1
- package/src/interfaces/cli/commands/commitment.js +5 -0
- package/src/interfaces/cli/commands/config.js +85 -6
- package/src/interfaces/cli/commands/exec.js +90 -1
- package/src/interfaces/cli/commands/image.js +314 -0
- package/src/interfaces/cli/commands/mcp.js +87 -23
- package/src/interfaces/cli/commands/memory.js +35 -22
- package/src/interfaces/cli/commands/panel.js +94 -0
- package/src/interfaces/cli/commands/profile.js +14 -0
- package/src/interfaces/cli/commands/project.js +29 -0
- package/src/interfaces/cli/commands/routine.js +45 -10
- package/src/interfaces/cli/commands/runtime.js +30 -7
- package/src/interfaces/cli/commands/session.js +90 -38
- package/src/interfaces/cli/commands/sessions.js +35 -2
- package/src/interfaces/cli/commands/skills.js +15 -9
- package/src/interfaces/cli/commands/status.js +2 -3
- package/src/interfaces/cli/commands/task.js +54 -5
- package/src/interfaces/cli/commands/telegram.js +12 -4
- package/src/interfaces/cli/commands/transcribe.js +177 -0
- package/src/interfaces/cli/help/index.js +311 -72
- package/src/interfaces/cli/http.js +61 -13
- package/src/interfaces/cli/index.js +1 -1
- package/src/interfaces/cli/routes/agent.js +5 -4
- package/src/interfaces/cli/routes/commitment.js +3 -2
- package/src/interfaces/cli/routes/config.js +7 -2
- package/src/interfaces/cli/routes/image.js +11 -0
- package/src/interfaces/cli/routes/index.js +2 -0
- package/src/interfaces/cli/routes/log.js +1 -1
- package/src/interfaces/cli/routes/memory.js +3 -2
- package/src/interfaces/cli/routes/panel.js +15 -2
- package/src/interfaces/cli/routes/profile.js +3 -2
- package/src/interfaces/cli/routes/transcribe.js +10 -0
- package/src/interfaces/cli/stdin.js +29 -0
- package/src/interfaces/desktop/assets/blobs/amatista.png +0 -0
- package/src/interfaces/desktop/assets/blobs/aqua.png +0 -0
- package/src/interfaces/desktop/assets/blobs/brasa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/campana.png +0 -0
- package/src/interfaces/desktop/assets/blobs/caracol.png +0 -0
- package/src/interfaces/desktop/assets/blobs/carbon.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cobalto.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cometa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/coral.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cubi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/eclipse.png +0 -0
- package/src/interfaces/desktop/assets/blobs/faro.png +0 -0
- package/src/interfaces/desktop/assets/blobs/gajo.png +0 -0
- package/src/interfaces/desktop/assets/blobs/iris.png +0 -0
- package/src/interfaces/desktop/assets/blobs/kiwi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/laguna.png +0 -0
- package/src/interfaces/desktop/assets/blobs/lila.png +0 -0
- package/src/interfaces/desktop/assets/blobs/menta.png +0 -0
- package/src/interfaces/desktop/assets/blobs/nimbo.png +0 -0
- package/src/interfaces/desktop/assets/blobs/noche.png +0 -0
- package/src/interfaces/desktop/assets/blobs/onyx.png +0 -0
- package/src/interfaces/desktop/assets/blobs/orbita.png +0 -0
- package/src/interfaces/desktop/assets/blobs/ovni.png +0 -0
- package/src/interfaces/desktop/assets/blobs/papa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/parche.png +0 -0
- package/src/interfaces/desktop/assets/blobs/peon.png +0 -0
- package/src/interfaces/desktop/assets/blobs/perla.png +0 -0
- package/src/interfaces/desktop/assets/blobs/pino.png +0 -0
- package/src/interfaces/desktop/assets/blobs/quad.png +0 -0
- package/src/interfaces/desktop/assets/blobs/rubi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/saturno.png +0 -0
- package/src/interfaces/desktop/assets/blobs/trebol.png +0 -0
- package/src/interfaces/desktop/assets/blobs/trino.png +0 -0
- package/src/interfaces/desktop/assets/blobs/volcan.png +0 -0
- package/src/interfaces/desktop/assets/blobs/zafiro.png +0 -0
- package/src/interfaces/desktop/assets/notification.mp3 +0 -0
- package/src/interfaces/desktop/main.js +473 -29
- package/src/interfaces/desktop/mascot-blobs.js +41 -0
- package/src/interfaces/desktop/mascot-preload.js +32 -0
- package/src/interfaces/desktop/mascot.css +186 -0
- package/src/interfaces/desktop/mascot.html +40 -0
- package/src/interfaces/desktop/mascot.js +163 -0
- package/src/interfaces/desktop/preload.js +10 -0
- package/src/interfaces/desktop/renderer.js +308 -48
- package/src/interfaces/desktop/style.css +34 -0
- package/src/interfaces/mcp-server/index.js +87 -0
- package/src/interfaces/tui/_shims/util-locale.ts +0 -2
- package/src/interfaces/tui/app.tsx +0 -6
- package/src/interfaces/tui/attach.ts +0 -1
- package/src/interfaces/tui/context/sdk-apx.tsx +0 -4
- package/src/interfaces/tui/plugin/api.tsx +0 -3
- package/src/interfaces/tui/plugin/runtime.ts +0 -3
- package/src/interfaces/tui/thread.ts +0 -16
- package/src/interfaces/web/README.md +22 -14
- package/src/interfaces/web/dist/assets/claude-XtpLmGtF.webp +0 -0
- package/src/interfaces/web/dist/assets/codex-DExPUgvh.webp +0 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css +32 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.br +0 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.gz +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js +1074 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.br +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.gz +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.br +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.gz +0 -0
- package/src/interfaces/web/dist/favicon/dark/site.webmanifest +12 -6
- package/src/interfaces/web/dist/favicon/white/site.webmanifest +12 -6
- package/src/interfaces/web/dist/index.html +22 -6
- package/src/interfaces/web/dist/index.html.br +0 -0
- package/src/interfaces/web/dist/index.html.gz +0 -0
- package/src/interfaces/web/dist/manifest.webmanifest +25 -0
- package/src/interfaces/web/dist/modules/blobs/amatista.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/aqua.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/brasa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/campana.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/caracol.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/carbon.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cobalto.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cometa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/coral.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cubi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/eclipse.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/faro.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/gajo.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/iris.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/kiwi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/laguna.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/lila.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/menta.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/nimbo.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/noche.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/onyx.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/orbita.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/ovni.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/papa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/parche.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/peon.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/perla.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/pino.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/quad.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/rubi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/saturno.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/trebol.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/trino.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/volcan.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/zafiro.png +0 -0
- package/src/interfaces/web/dist/sw.js +106 -0
- package/src/interfaces/web/dist/sw.js.br +0 -0
- package/src/interfaces/web/dist/sw.js.gz +0 -0
- package/src/interfaces/web/eslint.config.js +83 -0
- package/src/interfaces/web/index.html +20 -4
- package/src/interfaces/web/package-lock.json +1651 -1280
- package/src/interfaces/web/package.json +9 -10
- package/src/interfaces/web/pnpm-lock.yaml +867 -869
- package/src/interfaces/web/public/favicon/dark/site.webmanifest +12 -6
- package/src/interfaces/web/public/favicon/white/site.webmanifest +12 -6
- package/src/interfaces/web/public/manifest.webmanifest +25 -0
- package/src/interfaces/web/public/modules/blobs/amatista.png +0 -0
- package/src/interfaces/web/public/modules/blobs/aqua.png +0 -0
- package/src/interfaces/web/public/modules/blobs/brasa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/campana.png +0 -0
- package/src/interfaces/web/public/modules/blobs/caracol.png +0 -0
- package/src/interfaces/web/public/modules/blobs/carbon.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cobalto.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cometa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/coral.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cubi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/eclipse.png +0 -0
- package/src/interfaces/web/public/modules/blobs/faro.png +0 -0
- package/src/interfaces/web/public/modules/blobs/gajo.png +0 -0
- package/src/interfaces/web/public/modules/blobs/iris.png +0 -0
- package/src/interfaces/web/public/modules/blobs/kiwi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/laguna.png +0 -0
- package/src/interfaces/web/public/modules/blobs/lila.png +0 -0
- package/src/interfaces/web/public/modules/blobs/menta.png +0 -0
- package/src/interfaces/web/public/modules/blobs/nimbo.png +0 -0
- package/src/interfaces/web/public/modules/blobs/noche.png +0 -0
- package/src/interfaces/web/public/modules/blobs/onyx.png +0 -0
- package/src/interfaces/web/public/modules/blobs/orbita.png +0 -0
- package/src/interfaces/web/public/modules/blobs/ovni.png +0 -0
- package/src/interfaces/web/public/modules/blobs/papa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/parche.png +0 -0
- package/src/interfaces/web/public/modules/blobs/peon.png +0 -0
- package/src/interfaces/web/public/modules/blobs/perla.png +0 -0
- package/src/interfaces/web/public/modules/blobs/pino.png +0 -0
- package/src/interfaces/web/public/modules/blobs/quad.png +0 -0
- package/src/interfaces/web/public/modules/blobs/rubi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/saturno.png +0 -0
- package/src/interfaces/web/public/modules/blobs/trebol.png +0 -0
- package/src/interfaces/web/public/modules/blobs/trino.png +0 -0
- package/src/interfaces/web/public/modules/blobs/volcan.png +0 -0
- package/src/interfaces/web/public/modules/blobs/zafiro.png +0 -0
- package/src/interfaces/web/public/sw.js +106 -0
- package/src/interfaces/web/src/App.tsx +106 -10
- package/src/interfaces/web/src/assets/cli/claude.webp +0 -0
- package/src/interfaces/web/src/assets/cli/codex.webp +0 -0
- package/src/interfaces/web/src/assets/cli/cursor.svg +1 -0
- package/src/interfaces/web/src/assets/cli/opencode.png +0 -0
- package/src/interfaces/web/src/components/Combobox.tsx +201 -0
- package/src/interfaces/web/src/components/MobileHint.tsx +95 -0
- package/src/interfaces/web/src/components/MobileLinkDialog.tsx +156 -0
- package/src/interfaces/web/src/components/ModelCombobox.tsx +21 -113
- package/src/interfaces/web/src/components/{routines/ReadOnlyBlock.tsx → ReadOnlyBlock.tsx} +13 -4
- package/src/interfaces/web/src/components/Roby.tsx +5 -3
- package/src/interfaces/web/src/components/RobyBubble.tsx +23 -5
- package/src/interfaces/web/src/components/RowMenu.tsx +46 -0
- package/src/interfaces/web/src/components/TimezoneSelect.tsx +4 -1
- package/src/interfaces/web/src/components/Toast.tsx +50 -14
- package/src/interfaces/web/src/components/UiSelect.tsx +12 -5
- package/src/interfaces/web/src/components/agents/AgentAvatar.tsx +171 -0
- package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +42 -11
- package/src/interfaces/web/src/components/agents/AgentModelBadge.tsx +157 -0
- package/src/interfaces/web/src/components/agents/AgentModelSelect.tsx +57 -0
- package/src/interfaces/web/src/components/agents/AgentSkillsPicker.tsx +115 -0
- package/src/interfaces/web/src/components/agents/BlobAvatar.tsx +50 -0
- package/src/interfaces/web/src/components/agents/blobPresets.ts +50 -0
- package/src/interfaces/web/src/components/agents/modelCatalog.ts +66 -0
- package/src/interfaces/web/src/components/chat/ActionGroup.tsx +162 -0
- package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +4 -3
- package/src/interfaces/web/src/components/chat/AskQuestionsCard.tsx +1 -1
- package/src/interfaces/web/src/components/chat/Attachment.tsx +220 -0
- package/src/interfaces/web/src/components/chat/ChatList.tsx +226 -51
- package/src/interfaces/web/src/components/chat/ChatRowActivity.tsx +45 -0
- package/src/interfaces/web/src/components/chat/Composer.tsx +672 -23
- package/src/interfaces/web/src/components/chat/ComposerCommands.tsx +175 -0
- package/src/interfaces/web/src/components/chat/ComposerSuggest.tsx +215 -0
- package/src/interfaces/web/src/components/chat/ContextBar.tsx +133 -65
- package/src/interfaces/web/src/components/chat/InlineAskPanel.tsx +107 -47
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +460 -119
- package/src/interfaces/web/src/components/chat/MessageList.tsx +165 -18
- package/src/interfaces/web/src/components/chat/ReasoningBlock.tsx +58 -0
- package/src/interfaces/web/src/components/chat/SessionPicker.tsx +182 -0
- package/src/interfaces/web/src/components/chat/SkillTrace.tsx +183 -0
- package/src/interfaces/web/src/components/chat/ToolCall.tsx +11 -11
- package/src/interfaces/web/src/components/code/CodeContextTab.tsx +87 -53
- package/src/interfaces/web/src/components/code/CodeFileTree.tsx +11 -52
- package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +5 -4
- package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +31 -7
- package/src/interfaces/web/src/components/code/CodeSessionList.tsx +32 -11
- package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +33 -3
- package/src/interfaces/web/src/components/code/CodeTerminal.tsx +5 -4
- package/src/interfaces/web/src/components/code/NewCodeSessionDialog.tsx +164 -0
- package/src/interfaces/web/src/components/commitments/CommitmentDetail.tsx +162 -0
- package/src/interfaces/web/src/components/commitments/CommitmentFormDialog.tsx +158 -0
- package/src/interfaces/web/src/components/commitments/CommitmentList.tsx +194 -0
- package/src/interfaces/web/src/components/commitments/commitmentState.tsx +46 -0
- package/src/interfaces/web/src/components/common/BulkActionBar.tsx +60 -0
- package/src/interfaces/web/src/components/common/ConfirmDialog.tsx +4 -1
- package/src/interfaces/web/src/components/common/SelectCheckbox.tsx +40 -0
- package/src/interfaces/web/src/components/common/TabNav.tsx +1 -1
- package/src/interfaces/web/src/components/cron/CronPicker.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileBrowser.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileTree.tsx +6 -4
- package/src/interfaces/web/src/components/files/FileViewer.tsx +9 -5
- package/src/interfaces/web/src/components/files/MarkdownPreview.tsx +45 -9
- package/src/interfaces/web/src/components/images/ImageDefaultsCard.tsx +93 -0
- package/src/interfaces/web/src/components/images/ImageProviderList.tsx +142 -0
- package/src/interfaces/web/src/components/images/ImageProviderModal.tsx +263 -0
- package/src/interfaces/web/src/components/images/ImageTestCard.tsx +142 -0
- package/src/interfaces/web/src/components/inbox/ChannelFilter.tsx +178 -0
- package/src/interfaces/web/src/components/inbox/InboxList.tsx +77 -81
- package/src/interfaces/web/src/components/inbox/InboxRowItem.tsx +140 -0
- package/src/interfaces/web/src/components/integrations/ComingSoonPlugin.tsx +2 -2
- package/src/interfaces/web/src/components/integrations/PluginConnect.tsx +208 -30
- package/src/interfaces/web/src/components/integrations/PluginToolsSection.tsx +1 -1
- package/src/interfaces/web/src/components/layout/ProjectAvatar.tsx +39 -24
- package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +253 -58
- package/src/interfaces/web/src/components/memory/MemoryBrowser.tsx +94 -47
- package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +202 -90
- package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +28 -6
- package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +16 -5
- package/src/interfaces/web/src/components/routines/RoutineList.tsx +49 -9
- package/src/interfaces/web/src/components/routines/VarTextarea.tsx +1 -1
- package/src/interfaces/web/src/components/routines/runChat.ts +121 -0
- package/src/interfaces/web/src/components/sessions/SessionDetail.tsx +148 -0
- package/src/interfaces/web/src/components/sessions/SessionTerminal.tsx +98 -0
- package/src/interfaces/web/src/components/settings/AccessPanel.tsx +205 -0
- package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +246 -101
- package/src/interfaces/web/src/components/settings/DesktopSettingsPanel.tsx +36 -2
- package/src/interfaces/web/src/components/settings/DevicesPanel.tsx +19 -6
- package/src/interfaces/web/src/components/settings/EmbedProviderList.tsx +274 -0
- package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +26 -6
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +118 -119
- package/src/interfaces/web/src/components/settings/NudgePanel.tsx +4 -3
- package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +15 -4
- package/src/interfaces/web/src/components/settings/PanelPrefs.tsx +374 -0
- package/src/interfaces/web/src/components/settings/ProfilePanel.tsx +70 -2
- package/src/interfaces/web/src/components/settings/RoutingPanel.tsx +2 -1
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +102 -43
- package/src/interfaces/web/src/components/settings/SkillsManager.tsx +76 -21
- package/src/interfaces/web/src/components/settings/SkillsSettings.tsx +10 -3
- package/src/interfaces/web/src/components/settings/SuperAgentPanel.tsx +8 -0
- package/src/interfaces/web/src/components/settings/TelegramChannelsPanel.tsx +11 -2
- package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +19 -8
- package/src/interfaces/web/src/components/settings/TelegramRolesPanel.tsx +12 -2
- package/src/interfaces/web/src/components/settings/WebPanel.tsx +22 -31
- package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +15 -3
- package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +97 -66
- package/src/interfaces/web/src/components/settings/providers/ProviderTestDialog.tsx +150 -0
- package/src/interfaces/web/src/components/settings/providers/typeStyles.ts +67 -25
- package/src/interfaces/web/src/components/settings/providers/types.ts +3 -0
- package/src/interfaces/web/src/components/tasks/TaskBoard.tsx +201 -0
- package/src/interfaces/web/src/components/tasks/TaskColumnsDialog.tsx +243 -0
- package/src/interfaces/web/src/components/tasks/TaskComments.tsx +167 -0
- package/src/interfaces/web/src/components/tasks/TaskDetail.tsx +335 -0
- package/src/interfaces/web/src/components/tasks/TaskFormDialog.tsx +406 -0
- package/src/interfaces/web/src/components/tasks/TaskList.tsx +258 -0
- package/src/interfaces/web/src/components/tasks/TaskSubtasks.tsx +126 -0
- package/src/interfaces/web/src/components/tasks/columns.ts +51 -0
- package/src/interfaces/web/src/components/tasks/taskStatus.tsx +159 -34
- package/src/interfaces/web/src/components/tasks/taskViewPrefs.ts +73 -0
- package/src/interfaces/web/src/components/tasks/useTaskColumns.ts +31 -0
- package/src/interfaces/web/src/components/ui/chat-input.tsx +136 -12
- package/src/interfaces/web/src/components/ui/context-menu.tsx +15 -198
- package/src/interfaces/web/src/components/ui/dialog.tsx +3 -2
- package/src/interfaces/web/src/components/ui/filter-chips.tsx +4 -0
- package/src/interfaces/web/src/components/ui/popover.tsx +14 -49
- package/src/interfaces/web/src/components/ui/sheet.tsx +2 -1
- package/src/interfaces/web/src/components/ui/spinner.tsx +2 -1
- package/src/interfaces/web/src/components/ui.tsx +62 -23
- package/src/interfaces/web/src/components/voice/VoiceProviderList.tsx +2 -1
- package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +66 -8
- package/src/interfaces/web/src/components/voice/VoiceQvoxInstallCard.tsx +63 -0
- package/src/interfaces/web/src/components/voice/VoiceQvoxStatusCard.tsx +51 -0
- package/src/interfaces/web/src/components/voice/VoiceSttCard.tsx +4 -3
- package/src/interfaces/web/src/components/voice/VoiceTestCard.tsx +38 -4
- package/src/interfaces/web/src/constants/index.ts +1 -0
- package/src/interfaces/web/src/hooks/useChannelPrefs.ts +39 -0
- package/src/interfaces/web/src/hooks/useChat.ts +1092 -85
- package/src/interfaces/web/src/hooks/useChatActivity.ts +24 -0
- package/src/interfaces/web/src/hooks/useInbox.ts +26 -4
- package/src/interfaces/web/src/hooks/useLiveMessages.ts +16 -0
- package/src/interfaces/web/src/hooks/useOllamaModels.ts +79 -0
- package/src/interfaces/web/src/hooks/useRecorder.ts +198 -0
- package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +23 -6
- package/src/interfaces/web/src/i18n/en.ts +832 -175
- package/src/interfaces/web/src/i18n/es.ts +841 -188
- package/src/interfaces/web/src/lib/api/agents.ts +23 -4
- package/src/interfaces/web/src/lib/api/code.ts +17 -0
- package/src/interfaces/web/src/lib/api/commitments.ts +7 -1
- package/src/interfaces/web/src/lib/api/conversations.ts +38 -11
- package/src/interfaces/web/src/lib/api/embeddings.ts +3 -0
- package/src/interfaces/web/src/lib/api/engines.ts +14 -0
- package/src/interfaces/web/src/lib/api/groups.ts +93 -0
- package/src/interfaces/web/src/lib/api/images.ts +193 -0
- package/src/interfaces/web/src/lib/api/inbox.ts +29 -5
- package/src/interfaces/web/src/lib/api/integrations.ts +9 -0
- package/src/interfaces/web/src/lib/api/media.ts +126 -0
- package/src/interfaces/web/src/lib/api/net.ts +44 -0
- package/src/interfaces/web/src/lib/api/profiles.ts +12 -0
- package/src/interfaces/web/src/lib/api/projects.ts +9 -1
- package/src/interfaces/web/src/lib/api/routines.ts +9 -1
- package/src/interfaces/web/src/lib/api/sessions.ts +18 -0
- package/src/interfaces/web/src/lib/api/skills.ts +8 -0
- package/src/interfaces/web/src/lib/api/super_agent.ts +3 -0
- package/src/interfaces/web/src/lib/api/tasks.ts +46 -6
- package/src/interfaces/web/src/lib/api/tools.ts +2 -0
- package/src/interfaces/web/src/lib/api/transcribe.ts +31 -0
- package/src/interfaces/web/src/lib/api/turns.ts +20 -0
- package/src/interfaces/web/src/lib/api/voice.ts +72 -2
- package/src/interfaces/web/src/lib/api.ts +3 -0
- package/src/interfaces/web/src/lib/channels.ts +214 -0
- package/src/interfaces/web/src/lib/chat-activity.ts +175 -0
- package/src/interfaces/web/src/lib/chat-prefs.ts +48 -0
- package/src/interfaces/web/src/lib/code-context.ts +0 -2
- package/src/interfaces/web/src/lib/http.ts +51 -17
- package/src/interfaces/web/src/lib/inbox-selection.ts +29 -0
- package/src/interfaces/web/src/lib/live.ts +252 -0
- package/src/interfaces/web/src/lib/net.ts +211 -0
- package/src/interfaces/web/src/lib/notify.ts +331 -0
- package/src/interfaces/web/src/lib/projectNav.ts +40 -0
- package/src/interfaces/web/src/lib/pwa.ts +115 -0
- package/src/interfaces/web/src/lib/qvox.ts +24 -0
- package/src/interfaces/web/src/lib/slug.ts +3 -0
- package/src/interfaces/web/src/lib/tone.ts +150 -0
- package/src/interfaces/web/src/main.tsx +15 -4
- package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +33 -11
- package/src/interfaces/web/src/screens/InboxScreen.tsx +126 -71
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -4
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +7 -4
- package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +30 -9
- package/src/interfaces/web/src/screens/base/CommitmentsTab.tsx +150 -168
- package/src/interfaces/web/src/screens/base/LogsTab.tsx +8 -7
- package/src/interfaces/web/src/screens/base/SessionsTab.tsx +99 -37
- package/src/interfaces/web/src/screens/base/WorkspacesTab.tsx +1 -1
- package/src/interfaces/web/src/screens/mobile/MobileChat.tsx +85 -0
- package/src/interfaces/web/src/screens/mobile/MobileChatList.tsx +244 -0
- package/src/interfaces/web/src/screens/mobile/MobileCommitments.tsx +350 -0
- package/src/interfaces/web/src/screens/mobile/MobileScreen.tsx +138 -0
- package/src/interfaces/web/src/screens/mobile/MobileTabBar.tsx +105 -0
- package/src/interfaces/web/src/screens/mobile/MobileTasks.tsx +407 -0
- package/src/interfaces/web/src/screens/mobile/NewChatSheet.tsx +313 -0
- package/src/interfaces/web/src/screens/mobile/mobileList.tsx +194 -0
- package/src/interfaces/web/src/screens/mobile/routes.ts +239 -0
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +135 -64
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +0 -1
- package/src/interfaces/web/src/screens/modules/ImagesScreen.tsx +172 -0
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +36 -4
- package/src/interfaces/web/src/screens/project/AgentBrainGraph.tsx +117 -30
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +537 -92
- package/src/interfaces/web/src/screens/project/AgentsTab.tsx +344 -93
- package/src/interfaces/web/src/screens/project/ArtifactsTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +1160 -94
- package/src/interfaces/web/src/screens/project/IntegrationsTab.tsx +3 -2
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +62 -14
- package/src/interfaces/web/src/screens/project/Overview.tsx +36 -15
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +93 -8
- package/src/interfaces/web/src/screens/project/SkillsTab.tsx +4 -1
- package/src/interfaces/web/src/screens/project/StructureTab.tsx +5 -4
- package/src/interfaces/web/src/screens/project/TasksTab.tsx +351 -129
- package/src/interfaces/web/src/screens/project/VarsTab.tsx +17 -5
- package/src/interfaces/web/src/styles.css +106 -31
- package/src/interfaces/web/src/types/daemon.ts +246 -2
- package/src/interfaces/web/src/vite-env.d.ts +20 -0
- package/src/interfaces/tui/plugin/command-shim.ts +0 -109
- package/src/interfaces/web/components.json +0 -25
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js +0 -849
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js.map +0 -1
- package/src/interfaces/web/dist/assets/index-DzBBXFaO.css +0 -1
- package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +0 -142
- package/src/interfaces/web/src/components/ui/accordion.tsx +0 -72
- package/src/interfaces/web/src/components/ui/alert-dialog.tsx +0 -187
- package/src/interfaces/web/src/components/ui/alert.tsx +0 -76
- package/src/interfaces/web/src/components/ui/aspect-ratio.tsx +0 -22
- package/src/interfaces/web/src/components/ui/avatar.tsx +0 -107
- package/src/interfaces/web/src/components/ui/breadcrumb.tsx +0 -125
- package/src/interfaces/web/src/components/ui/button-group.tsx +0 -87
- package/src/interfaces/web/src/components/ui/calendar.tsx +0 -221
- package/src/interfaces/web/src/components/ui/card.tsx +0 -103
- package/src/interfaces/web/src/components/ui/carousel.tsx +0 -242
- package/src/interfaces/web/src/components/ui/chart.tsx +0 -371
- package/src/interfaces/web/src/components/ui/checkbox.tsx +0 -29
- package/src/interfaces/web/src/components/ui/collapsible.tsx +0 -19
- package/src/interfaces/web/src/components/ui/combobox.tsx +0 -295
- package/src/interfaces/web/src/components/ui/command.tsx +0 -196
- package/src/interfaces/web/src/components/ui/direction.tsx +0 -4
- package/src/interfaces/web/src/components/ui/drawer.tsx +0 -134
- package/src/interfaces/web/src/components/ui/empty.tsx +0 -104
- package/src/interfaces/web/src/components/ui/field.tsx +0 -236
- package/src/interfaces/web/src/components/ui/hover-card.tsx +0 -51
- package/src/interfaces/web/src/components/ui/input-otp.tsx +0 -85
- package/src/interfaces/web/src/components/ui/item.tsx +0 -201
- package/src/interfaces/web/src/components/ui/menubar.tsx +0 -280
- package/src/interfaces/web/src/components/ui/native-select.tsx +0 -61
- package/src/interfaces/web/src/components/ui/navigation-menu.tsx +0 -168
- package/src/interfaces/web/src/components/ui/pagination.tsx +0 -130
- package/src/interfaces/web/src/components/ui/progress.tsx +0 -83
- package/src/interfaces/web/src/components/ui/radio-group.tsx +0 -36
- package/src/interfaces/web/src/components/ui/resizable.tsx +0 -50
- package/src/interfaces/web/src/components/ui/scroll-area.tsx +0 -53
- package/src/interfaces/web/src/components/ui/sidebar.tsx +0 -726
- package/src/interfaces/web/src/components/ui/slider.tsx +0 -52
- package/src/interfaces/web/src/components/ui/sonner.tsx +0 -49
- package/src/interfaces/web/src/components/ui/table.tsx +0 -116
- package/src/interfaces/web/src/components/ui/toggle-group.tsx +0 -87
- package/src/interfaces/web/src/components/ui/toggle.tsx +0 -45
- package/src/interfaces/web/src/hooks/use-mobile.ts +0 -19
- package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +0 -161
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
let pausePreviewed = false; // a preview decode fired for the current pause
|
|
60
60
|
let reuseLiveOnStop = false; // commit should reuse pendingUserText, not re-decode
|
|
61
61
|
let livePromise = null; // in-flight preview decode (awaited on reuse)
|
|
62
|
+
let previewFlushTs = 0; // audio cut-off the pending preview actually saw
|
|
62
63
|
|
|
63
64
|
// Web Audio analyser — drives the live capsule wave from real mic amplitude
|
|
64
65
|
let audioCtx = null;
|
|
@@ -67,7 +68,7 @@
|
|
|
67
68
|
let timeData = null;
|
|
68
69
|
let waveRaf = null;
|
|
69
70
|
|
|
70
|
-
let streamingAgentEntry = null; //
|
|
71
|
+
let streamingAgentEntry = null; // the pending "thinking" bubble; also renders turn errors
|
|
71
72
|
let toolPillsByName = {}; // active tool pills, by tool name, for the live turn
|
|
72
73
|
let ttsAudio = null; // <audio> currently playing
|
|
73
74
|
|
|
@@ -92,6 +93,7 @@
|
|
|
92
93
|
// requestTts / second finalize on the same in-flight bubble.
|
|
93
94
|
let doneHandled = false;
|
|
94
95
|
let ttsTimer = null;
|
|
96
|
+
let prewarmedTurn = false; // this turn already kicked a speak-ahead
|
|
95
97
|
|
|
96
98
|
// ── Inline SVG icons (mirrors the design's I.* set) ──────────────────────
|
|
97
99
|
const SVG = (path, attrs = {}) => {
|
|
@@ -108,6 +110,7 @@
|
|
|
108
110
|
person: () => SVG('<circle cx="12" cy="8" r="3.6"/><path d="M5.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6"/>', { width: 12, height: 12, viewBox: "0 0 24 24" }),
|
|
109
111
|
refresh:() => SVG('<path d="M3 12a9 9 0 0 1 15.5-6.2L21 8M21 3v5h-5M21 12a9 9 0 0 1-15.5 6.2L3 16M3 21v-5h5"/>', { width: 13, height: 13, viewBox: "0 0 24 24", "stroke-width": "1.9" }),
|
|
110
112
|
copy: () => SVG('<rect x="9" y="9" width="11" height="11" rx="2.5"/><path d="M5 15V5a2 2 0 0 1 2-2h8"/>', { width: 13, height: 13, viewBox: "0 0 24 24" }),
|
|
113
|
+
muted: () => SVG('<path d="M11 5 6.5 9H3v6h3.5L11 19V5z"/><path d="M16 9.5l4 5M20 9.5l-4 5"/>', { width: 12, height: 12, viewBox: "0 0 24 24" }),
|
|
111
114
|
check: () => SVG('<path d="M5 12l4.5 4.5L19 7"/>', { width: 13, height: 13, viewBox: "0 0 24 24", "stroke-width": "2" }),
|
|
112
115
|
play: () => `<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5.2v13.6c0 .8.9 1.3 1.6.9l10.5-6.8c.6-.4.6-1.3 0-1.7L9.6 4.3C8.9 3.9 8 4.4 8 5.2z"/></svg>`,
|
|
113
116
|
pause: () => `<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><rect x="6.5" y="5" width="4" height="14" rx="1.3"/><rect x="13.5" y="5" width="4" height="14" rx="1.3"/></svg>`,
|
|
@@ -448,7 +451,11 @@
|
|
|
448
451
|
<button class="chip btn-regen">${ICON.refresh()} Regenerar</button>
|
|
449
452
|
</div>
|
|
450
453
|
`;
|
|
451
|
-
if (m.audio
|
|
454
|
+
if (m.audio) {
|
|
455
|
+
// A missing duration is no reason to withhold the player — the <audio>
|
|
456
|
+
// element reports its own once metadata loads. Requiring m.dur here is
|
|
457
|
+
// what limited playback to the engines that happen to measure their
|
|
458
|
+
// output, which in practice meant the silent mock and nothing else.
|
|
452
459
|
// Insert scrubber before turn-actions
|
|
453
460
|
const scrubberHtml = buildScrubberHtml(m);
|
|
454
461
|
const actions = t.querySelector(".turn-actions");
|
|
@@ -536,6 +543,8 @@
|
|
|
536
543
|
$convScroll?.querySelector("[data-pending='user']")?.remove();
|
|
537
544
|
}
|
|
538
545
|
|
|
546
|
+
// The placeholder bubble shown while the turn is in flight. Segments replace
|
|
547
|
+
// it with real bubbles; a failed turn overwrites it with the error text.
|
|
539
548
|
function ensureStreamingAgentBubble() {
|
|
540
549
|
if (!$convScroll) return;
|
|
541
550
|
if (streamingAgentEntry?.el && document.body.contains(streamingAgentEntry.el)) return;
|
|
@@ -561,16 +570,14 @@
|
|
|
561
570
|
scrollConvToBottom();
|
|
562
571
|
}
|
|
563
572
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
streamingAgentEntry.
|
|
571
|
-
|
|
572
|
-
streamingAgentEntry.msgEl.innerHTML = formatWordsHtml(streamingAgentEntry.text) + `<span class="caret"></span>`;
|
|
573
|
-
scrollConvToBottom();
|
|
573
|
+
// Drop the provisional bubble without recording anything. Streamed deltas are
|
|
574
|
+
// a preview of a segment that is still coming; the `segment` event is what
|
|
575
|
+
// becomes a message, gets spoken, and enters history. Finalizing here instead
|
|
576
|
+
// would file the same reply twice.
|
|
577
|
+
function discardStreamingAgent() {
|
|
578
|
+
if (!streamingAgentEntry) return;
|
|
579
|
+
streamingAgentEntry.el.remove();
|
|
580
|
+
streamingAgentEntry = null;
|
|
574
581
|
}
|
|
575
582
|
|
|
576
583
|
function finalizeStreamingAgent({ audio, dur } = {}) {
|
|
@@ -613,11 +620,52 @@
|
|
|
613
620
|
}
|
|
614
621
|
|
|
615
622
|
// ── Audio scrubber ───────────────────────────────────────────────────────
|
|
623
|
+
// m:ss. The old formatter hardcoded the "0:" minute, so anything past a
|
|
624
|
+
// minute read as 0:73.
|
|
625
|
+
function fmtDur(s) {
|
|
626
|
+
const total = Math.max(0, Math.round(s || 0));
|
|
627
|
+
return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, "0")}`;
|
|
628
|
+
}
|
|
629
|
+
// A bubble's text lands as soon as the turn resolves, but its voice is still
|
|
630
|
+
// being generated — so the reply sat there looking finished and mute, and
|
|
631
|
+
// then a player appeared out of nowhere seconds later. This placeholder fills
|
|
632
|
+
// that gap. Same bar geometry and padding as the real scrubber, so swapping
|
|
633
|
+
// one for the other doesn't move anything on screen.
|
|
634
|
+
function buildPendingAudioHtml() {
|
|
635
|
+
const N = 38;
|
|
636
|
+
const bars = waveShape(N, 13);
|
|
637
|
+
return `
|
|
638
|
+
<div class="audio pending" role="status" aria-label="Generando audio…">
|
|
639
|
+
<span class="play"></span>
|
|
640
|
+
<div class="wavebar">
|
|
641
|
+
${bars.map((h, i) => `<i style="height:${Math.round(h * 24)}px;--i:${i}"></i>`).join("")}
|
|
642
|
+
</div>
|
|
643
|
+
<span class="dur">···</span>
|
|
644
|
+
</div>
|
|
645
|
+
`;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Only ever called for a turn that is live and has asked for speech: a past
|
|
649
|
+
// bubble that was never voiced must not grow a spinner when it is rebuilt.
|
|
650
|
+
function showPendingAudio(turnId) {
|
|
651
|
+
const turnEl = $convScroll?.querySelector(`[data-id="${turnId}"]`);
|
|
652
|
+
if (!turnEl || turnEl.querySelector(".audio")) return;
|
|
653
|
+
turnEl.querySelector(".turn-actions")?.insertAdjacentHTML("beforebegin", buildPendingAudioHtml());
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// The placeholder promises audio is coming, so every path that ends that
|
|
657
|
+
// promise — audio arrived, TTS failed, the watchdog gave up — has to take it
|
|
658
|
+
// down. One left spinning forever is worse than never having shown it.
|
|
659
|
+
function clearPendingAudio(turnId) {
|
|
660
|
+
const turnEl = $convScroll?.querySelector(`[data-id="${turnId}"]`);
|
|
661
|
+
turnEl?.querySelector(".audio.pending")?.remove();
|
|
662
|
+
}
|
|
663
|
+
|
|
616
664
|
function buildScrubberHtml(m) {
|
|
617
665
|
const N = 38;
|
|
618
666
|
const bars = waveShape(N, 13);
|
|
619
667
|
const dur = m.dur || 0;
|
|
620
|
-
const fmt =
|
|
668
|
+
const fmt = fmtDur;
|
|
621
669
|
return `
|
|
622
670
|
<div class="audio" data-bars="${N}">
|
|
623
671
|
<button class="play" aria-label="Reproducir respuesta">${ICON.play()}</button>
|
|
@@ -628,19 +676,37 @@
|
|
|
628
676
|
</div>
|
|
629
677
|
`;
|
|
630
678
|
}
|
|
679
|
+
// One player per bubble, fed by a playlist that is still being written.
|
|
680
|
+
//
|
|
681
|
+
// The reply is synthesized a sentence at a time, so parts arrive while
|
|
682
|
+
// earlier ones are already playing. The element plays them back to back and
|
|
683
|
+
// reports one continuous position across the whole list, which is what the
|
|
684
|
+
// listener perceives — they hear one answer, not three clips.
|
|
631
685
|
function wireScrubber(turnEl, m) {
|
|
632
686
|
const N = 38;
|
|
633
687
|
const audioEl = turnEl.querySelector(".audio");
|
|
634
|
-
|
|
688
|
+
// A bubble rebuilt from state carries only the finished url; treat it as a
|
|
689
|
+
// one-item playlist so replay works the same on both paths.
|
|
690
|
+
if (!m._parts?.length && m.audio) m._parts = [{ url: m.audio, dur: m.dur || 0 }];
|
|
691
|
+
if (!audioEl || !m._parts?.length) return;
|
|
635
692
|
const $play = audioEl.querySelector(".play");
|
|
636
693
|
const $bar = audioEl.querySelector(".wavebar");
|
|
637
694
|
const bars = $bar.querySelectorAll("i");
|
|
638
695
|
const $dur = audioEl.querySelector(".dur");
|
|
639
|
-
const
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
m.
|
|
696
|
+
const fmt = fmtDur;
|
|
697
|
+
const audio = new Audio(m._parts[0].url);
|
|
698
|
+
m._audioEl = audio; // the audio queue drives sequential playback
|
|
699
|
+
m._partIdx = 0;
|
|
643
700
|
let raf = null;
|
|
701
|
+
let waiting = false; // played everything that has arrived so far
|
|
702
|
+
|
|
703
|
+
const partDur = (i) => {
|
|
704
|
+
if (i === m._partIdx && audio.duration > 0 && isFinite(audio.duration)) return audio.duration;
|
|
705
|
+
return m._parts[i]?.dur || 0;
|
|
706
|
+
};
|
|
707
|
+
const total = () => m._parts.reduce((a, _, i) => a + partDur(i), 0);
|
|
708
|
+
const before = () => m._parts.slice(0, m._partIdx).reduce((a, _, i) => a + partDur(i), 0);
|
|
709
|
+
const elapsed = () => before() + (audio.currentTime || 0);
|
|
644
710
|
|
|
645
711
|
const setProgress = (p) => {
|
|
646
712
|
p = Math.max(0, Math.min(1, p));
|
|
@@ -649,15 +715,40 @@
|
|
|
649
715
|
b.classList.toggle("on", i <= cur);
|
|
650
716
|
b.classList.toggle("cur", i === cur && !audio.paused);
|
|
651
717
|
});
|
|
652
|
-
|
|
718
|
+
const t = total();
|
|
719
|
+
$dur.textContent = p > 0 || !audio.paused ? fmt(p * t) : fmt(t);
|
|
653
720
|
};
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
721
|
+
const paint = () => { const t = total(); setProgress(t > 0 ? elapsed() / t : 0); };
|
|
722
|
+
const tick = () => { paint(); raf = requestAnimationFrame(tick); };
|
|
723
|
+
|
|
724
|
+
// Load a part and keep playing. Used both when one ends and when a part
|
|
725
|
+
// the player was waiting for finally shows up.
|
|
726
|
+
const playPart = (i) => {
|
|
727
|
+
m._partIdx = i;
|
|
728
|
+
waiting = false;
|
|
729
|
+
audio.src = m._parts[i].url;
|
|
730
|
+
audio.play().catch(() => onSegmentEnded(m));
|
|
657
731
|
};
|
|
732
|
+
// Called from attachAudioPart when the list grows.
|
|
733
|
+
m._onPartArrived = () => {
|
|
734
|
+
const t = total();
|
|
735
|
+
if (waiting && m._parts[m._partIdx + 1]) playPart(m._partIdx + 1);
|
|
736
|
+
else if (audio.paused && audio.currentTime === 0) $dur.textContent = fmt(t);
|
|
737
|
+
};
|
|
738
|
+
// Called from the tts-end event: nothing more is coming.
|
|
739
|
+
m._onPartsDone = () => { if (waiting) { waiting = false; onSegmentEnded(m); } };
|
|
740
|
+
|
|
741
|
+
audio.addEventListener("loadedmetadata", paint);
|
|
658
742
|
audio.addEventListener("play", () => { $play.innerHTML = ICON.pause(); raf = requestAnimationFrame(tick); if (mode !== "speaking") { mode = "speaking"; render(); } });
|
|
659
743
|
audio.addEventListener("pause", () => { $play.innerHTML = ICON.play(); if (raf) cancelAnimationFrame(raf); });
|
|
660
|
-
audio.addEventListener("ended", () => {
|
|
744
|
+
audio.addEventListener("ended", () => {
|
|
745
|
+
if (m._parts[m._partIdx + 1]) return playPart(m._partIdx + 1);
|
|
746
|
+
if (!m._partsDone) { waiting = true; return; } // the next sentence is still being made
|
|
747
|
+
$play.innerHTML = ICON.play();
|
|
748
|
+
if (raf) cancelAnimationFrame(raf);
|
|
749
|
+
setProgress(1);
|
|
750
|
+
onSegmentEnded(m);
|
|
751
|
+
});
|
|
661
752
|
// 404 / decode error / autoplay block: don't hang — advance the queue.
|
|
662
753
|
audio.addEventListener("error", () => onSegmentEnded(m));
|
|
663
754
|
|
|
@@ -676,19 +767,40 @@
|
|
|
676
767
|
$bar.addEventListener("click", (e) => {
|
|
677
768
|
const r = $bar.getBoundingClientRect();
|
|
678
769
|
const p = Math.max(0, Math.min(1, (e.clientX - r.left) / r.width));
|
|
679
|
-
|
|
770
|
+
// Map one position on the bar onto (part, offset) — the bar spans the
|
|
771
|
+
// whole reply, not the sentence that happens to be playing.
|
|
772
|
+
let target = p * total();
|
|
773
|
+
for (let i = 0; i < m._parts.length; i++) {
|
|
774
|
+
const d = partDur(i);
|
|
775
|
+
if (target <= d || i === m._parts.length - 1) {
|
|
776
|
+
if (i !== m._partIdx) {
|
|
777
|
+
const wasPlaying = !audio.paused;
|
|
778
|
+
m._partIdx = i;
|
|
779
|
+
audio.src = m._parts[i].url;
|
|
780
|
+
if (wasPlaying) audio.play().catch(() => {});
|
|
781
|
+
}
|
|
782
|
+
audio.currentTime = Math.max(0, Math.min(target, Math.max(0, d - 0.05)));
|
|
783
|
+
break;
|
|
784
|
+
}
|
|
785
|
+
target -= d;
|
|
786
|
+
}
|
|
680
787
|
setProgress(p);
|
|
681
788
|
});
|
|
682
789
|
}
|
|
683
790
|
|
|
684
|
-
// Post-finalize hook:
|
|
685
|
-
//
|
|
686
|
-
function
|
|
791
|
+
// Post-finalize hook: a sentence of this turn's speech just arrived. The
|
|
792
|
+
// first one mounts the player; later ones extend the playlist under it.
|
|
793
|
+
function attachAudioPart(turnId, { url, dur }) {
|
|
687
794
|
const m = messages.find((x) => x.id === turnId);
|
|
688
795
|
if (!m) return;
|
|
689
|
-
m.
|
|
690
|
-
m.
|
|
796
|
+
(m._parts = m._parts || []).push({ url, dur: dur || 0 });
|
|
797
|
+
m.audio = m._parts[0].url; // kept for rebuilds
|
|
798
|
+
m.dur = m._parts.reduce((a, p) => a + (p.dur || 0), 0);
|
|
799
|
+
|
|
800
|
+
if (m._parts.length > 1) { m._onPartArrived?.(); return; }
|
|
801
|
+
|
|
691
802
|
const turnEl = $convScroll?.querySelector(`[data-id="${turnId}"]`);
|
|
803
|
+
turnEl?.querySelector(".audio.pending")?.remove();
|
|
692
804
|
if (turnEl && !turnEl.querySelector(".audio")) {
|
|
693
805
|
// Insert the scrubber HTML just before turn-actions (matches appendTurn).
|
|
694
806
|
const actions = turnEl.querySelector(".turn-actions");
|
|
@@ -697,12 +809,34 @@
|
|
|
697
809
|
else turnEl.insertAdjacentHTML("beforeend", html);
|
|
698
810
|
wireScrubber(turnEl, m); // sets m._audioEl
|
|
699
811
|
}
|
|
700
|
-
//
|
|
701
|
-
//
|
|
812
|
+
// The first sentence is enough to start: let the queue play it while the
|
|
813
|
+
// rest of the reply is still being spoken into existence.
|
|
702
814
|
queueMarkReady(m);
|
|
703
815
|
scrollConvToBottom();
|
|
704
816
|
}
|
|
705
817
|
|
|
818
|
+
// No more sentences are coming for this bubble.
|
|
819
|
+
function markAudioComplete(turnId) {
|
|
820
|
+
const m = messages.find((x) => x.id === turnId);
|
|
821
|
+
if (!m) return;
|
|
822
|
+
m._partsDone = true;
|
|
823
|
+
m._onPartsDone?.();
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// The other half of attachAudioPart: this segment produced no audio. Say so
|
|
827
|
+
// on the bubble instead of leaving the reply mutely text-only — "no voice
|
|
828
|
+
// this time" and "the voice is broken" look identical otherwise, and the
|
|
829
|
+
// second one is worth knowing about.
|
|
830
|
+
function markTurnUnvoiced(turnId, reason) {
|
|
831
|
+
const turnEl = $convScroll?.querySelector(`[data-id="${turnId}"]`);
|
|
832
|
+
if (!turnEl || turnEl.querySelector(".unvoiced")) return;
|
|
833
|
+
const el = document.createElement("span");
|
|
834
|
+
el.className = "chip unvoiced";
|
|
835
|
+
el.title = reason ? `Sin voz: ${reason}` : "Sin voz";
|
|
836
|
+
el.innerHTML = `${ICON.muted()} Sin voz`;
|
|
837
|
+
turnEl.querySelector(".turn-actions")?.prepend(el);
|
|
838
|
+
}
|
|
839
|
+
|
|
706
840
|
function waveShape(n, seed = 7) {
|
|
707
841
|
const out = []; let s = seed;
|
|
708
842
|
for (let i = 0; i < n; i++) {
|
|
@@ -723,6 +857,7 @@
|
|
|
723
857
|
currentTurn++;
|
|
724
858
|
resetTurnAudio();
|
|
725
859
|
doneHandled = false;
|
|
860
|
+
prewarmedTurn = false;
|
|
726
861
|
if (ttsTimer) { clearTimeout(ttsTimer); ttsTimer = null; }
|
|
727
862
|
}
|
|
728
863
|
function resetTurnAudio() {
|
|
@@ -777,14 +912,23 @@
|
|
|
777
912
|
// Called from a segment audio's `ended` (or `error`). Advances the queue.
|
|
778
913
|
function onSegmentEnded(m) {
|
|
779
914
|
const e = turnAudios.find((x) => x.m === m);
|
|
780
|
-
|
|
781
|
-
if (
|
|
915
|
+
const counted = !!e?.played; // the queue already moved past this one
|
|
916
|
+
if (e) e.played = true;
|
|
917
|
+
if (!counted && queuePlaying && ttsAudio === m._audioEl) {
|
|
782
918
|
queuePlaying = false;
|
|
783
919
|
audioCursor++;
|
|
784
920
|
pumpAudioQueue();
|
|
785
|
-
|
|
786
|
-
mode = "idle"; render();
|
|
921
|
+
return;
|
|
787
922
|
}
|
|
923
|
+
// Nothing is playing any more, so the capsule must not still say so.
|
|
924
|
+
//
|
|
925
|
+
// This used to hang on "Roby está hablando…" forever. When a segment's TTS
|
|
926
|
+
// outran the turn watchdog, the watchdog wrote the entry off as played;
|
|
927
|
+
// the audio then arrived anyway, the user pressed play by hand, and on
|
|
928
|
+
// `ended` the already-played guard returned early — before the line that
|
|
929
|
+
// puts the capsule back to idle. The guard is about not advancing the
|
|
930
|
+
// queue twice, so that is all it guards now.
|
|
931
|
+
if (!queuePlaying && mode === "speaking") { mode = "idle"; render(); }
|
|
788
932
|
}
|
|
789
933
|
|
|
790
934
|
// ── Recording flow ───────────────────────────────────────────────────────
|
|
@@ -799,10 +943,14 @@
|
|
|
799
943
|
pausePreviewed = false;
|
|
800
944
|
reuseLiveOnStop = false;
|
|
801
945
|
livePromise = null;
|
|
946
|
+
previewFlushTs = 0;
|
|
802
947
|
pendingUserText = "";
|
|
803
|
-
// Warm
|
|
804
|
-
//
|
|
948
|
+
// Warm both models now, while the user is about to speak. Whisper is needed
|
|
949
|
+
// in a few seconds, the voice engine a few seconds after that — and both
|
|
950
|
+
// cost far more when cold than the whole rest of the turn. Overlapping them
|
|
951
|
+
// with the utterance is free time that would otherwise be dead waiting.
|
|
805
952
|
window.apx?.warmupStt?.();
|
|
953
|
+
window.apx?.warmupTts?.();
|
|
806
954
|
mode = "listening";
|
|
807
955
|
render();
|
|
808
956
|
startMic();
|
|
@@ -889,12 +1037,18 @@
|
|
|
889
1037
|
// in-flight preview if it hasn't settled yet.
|
|
890
1038
|
if (reuseLiveOnStop) {
|
|
891
1039
|
if (livePromise) { try { await livePromise; } catch {} }
|
|
892
|
-
|
|
1040
|
+
// Only if the preview's audio actually covers everything said. If the
|
|
1041
|
+
// user resumed speaking after that cut-off (and the new pause couldn't
|
|
1042
|
+
// fire its own preview because one was still in flight), the stashed
|
|
1043
|
+
// text is a truncated utterance — decode again rather than send half
|
|
1044
|
+
// a sentence.
|
|
1045
|
+
if (previewFlushTs && lastVoiceTs <= previewFlushTs) text = (pendingUserText || "").trim();
|
|
893
1046
|
}
|
|
894
1047
|
// Manual send (Enviar / ⌘G release) or no preview yet → one fresh decode.
|
|
895
1048
|
if (!text) text = (await transcribeBuffered()).trim();
|
|
896
1049
|
recordedChunks = [];
|
|
897
1050
|
reuseLiveOnStop = false;
|
|
1051
|
+
previewFlushTs = 0;
|
|
898
1052
|
// Guard with .trim() — whisper occasionally returns a single space or
|
|
899
1053
|
// newline for very short clips, which used to commit an empty bubble.
|
|
900
1054
|
if (!text || isCancelled) {
|
|
@@ -1070,6 +1224,29 @@
|
|
|
1070
1224
|
} catch {}
|
|
1071
1225
|
return "";
|
|
1072
1226
|
}
|
|
1227
|
+
// MediaRecorder only hands over a blob once per timeslice, so at any instant
|
|
1228
|
+
// the last second of speech is still inside the recorder. A preview decode
|
|
1229
|
+
// that skipped this would transcribe an utterance with its tail missing —
|
|
1230
|
+
// which is exactly what made the reuse below unsafe, and why every turn used
|
|
1231
|
+
// to pay a second full decode. requestData() forces the pending audio out now.
|
|
1232
|
+
function flushRecorder() {
|
|
1233
|
+
return new Promise((resolve) => {
|
|
1234
|
+
if (!mediaRecorder || mediaRecorder.state !== "recording") return resolve();
|
|
1235
|
+
let done = false;
|
|
1236
|
+
const finish = () => {
|
|
1237
|
+
if (done) return;
|
|
1238
|
+
done = true;
|
|
1239
|
+
mediaRecorder.removeEventListener("dataavailable", finish);
|
|
1240
|
+
resolve();
|
|
1241
|
+
};
|
|
1242
|
+
mediaRecorder.addEventListener("dataavailable", finish);
|
|
1243
|
+
try { mediaRecorder.requestData(); } catch { finish(); return; }
|
|
1244
|
+
// The event is the normal path; the timer only exists so a recorder that
|
|
1245
|
+
// never answers can't wedge the preview (and with it the auto-send).
|
|
1246
|
+
setTimeout(finish, 250);
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1073
1250
|
// Decode what's been recorded so far (fired once per speech pause). The
|
|
1074
1251
|
// result is stashed in pendingUserText and reused by the auto-send on stop,
|
|
1075
1252
|
// so the same audio is never decoded twice. livePromise lets onstop await an
|
|
@@ -1079,8 +1256,17 @@
|
|
|
1079
1256
|
liveBusy = true;
|
|
1080
1257
|
livePromise = (async () => {
|
|
1081
1258
|
try {
|
|
1259
|
+
await flushRecorder();
|
|
1260
|
+
// Stamp the cut-off BEFORE decoding: onstop reuses this text only if no
|
|
1261
|
+
// further speech arrived after this instant.
|
|
1262
|
+
previewFlushTs = Date.now();
|
|
1082
1263
|
const text = await transcribeBuffered();
|
|
1083
|
-
|
|
1264
|
+
// Deliberately not gated on `mode === "listening"`: the auto-send flips
|
|
1265
|
+
// the mode to "transcribing" at SILENCE_MS, which lands *before* this
|
|
1266
|
+
// decode settles. Gating here threw the result away every single time
|
|
1267
|
+
// and made the reuse below dead code — one wasted decode per turn, plus
|
|
1268
|
+
// a second one on the critical path.
|
|
1269
|
+
if (text && !isCancelled) pendingUserText = text;
|
|
1084
1270
|
} finally { liveBusy = false; }
|
|
1085
1271
|
})();
|
|
1086
1272
|
return livePromise;
|
|
@@ -1110,6 +1296,59 @@
|
|
|
1110
1296
|
// mount the placeholder bubble, and ask main to grow the window now (not
|
|
1111
1297
|
// one ResizeObserver tick later). Shared by commitUserMessage + regen so
|
|
1112
1298
|
// both paths set up the daemon-event pipeline identically.
|
|
1299
|
+
// Emoji and reasoning are stripped daemon-side before a segment is spoken, so
|
|
1300
|
+
// a sentence carrying either would be pre-made under a key the real request
|
|
1301
|
+
// never uses. Cheaper to skip than to synthesize and throw away.
|
|
1302
|
+
const HAS_EMOJI = /\p{Extended_Pictographic}|\p{Regional_Indicator}/u;
|
|
1303
|
+
const HAS_REASONING = /[<[]\s*\/?\s*(think|thinking|reason|reasoning|scratchpad|analysis)/i;
|
|
1304
|
+
// The daemon can only hand the renderer a segment once the whole turn has
|
|
1305
|
+
// resolved, so the voice engine sits idle for the model's entire generation
|
|
1306
|
+
// and only then starts on sentence one. The tokens are already arriving,
|
|
1307
|
+
// though — as soon as they contain a finished sentence, that sentence is
|
|
1308
|
+
// almost certainly the first thing that will be spoken, so start making it
|
|
1309
|
+
// now. main.js keys the result by exact text: if the reply turns out
|
|
1310
|
+
// different, the pre-made audio is simply never claimed.
|
|
1311
|
+
function maybePrewarmTts() {
|
|
1312
|
+
if (prewarmedTurn || !streamingAgentEntry) return;
|
|
1313
|
+
const buf = streamingAgentEntry.text || "";
|
|
1314
|
+
// A long preamble with no sentence end is a model that isn't writing prose
|
|
1315
|
+
// (reasoning, a list, code) — stop watching rather than guess.
|
|
1316
|
+
if (buf.length > 400) { prewarmedTurn = true; return; }
|
|
1317
|
+
if (HAS_REASONING.test(buf)) { prewarmedTurn = true; return; }
|
|
1318
|
+
// Only look at whole sentences: a half-streamed one is not yet the chunk.
|
|
1319
|
+
const complete = buf.match(/^[\s\S]*[.!?…](?=\s)/);
|
|
1320
|
+
if (!complete) return;
|
|
1321
|
+
const first = firstSpeechChunk(complete[0].trim());
|
|
1322
|
+
if (!first) return; // no chunk has closed yet — keep watching
|
|
1323
|
+
prewarmedTurn = true;
|
|
1324
|
+
if (HAS_EMOJI.test(first)) return;
|
|
1325
|
+
window.apx?.prewarmTts?.(first);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Mirror of main.js splitForSpeech, for its first chunk only. It has to agree
|
|
1329
|
+
// exactly: a chunk built here that the real request never asks for is not just
|
|
1330
|
+
// wasted, it holds the voice engine's lock while the chunk that *is* wanted
|
|
1331
|
+
// waits behind it. Returns null while no chunk has closed yet — the splitter
|
|
1332
|
+
// packs short sentences together, so "Hola." on its own is not a chunk.
|
|
1333
|
+
function firstSpeechChunk(text, { min = 12, limit = 80 } = {}) {
|
|
1334
|
+
const pieces = [];
|
|
1335
|
+
for (const sentence of String(text).trim().split(/(?<=[.!?…])\s+/)) {
|
|
1336
|
+
if (sentence.length <= limit) { pieces.push(sentence); continue; }
|
|
1337
|
+
for (const clause of sentence.split(/(?<=[,;:—–])\s+/)) {
|
|
1338
|
+
if (clause.length <= limit) { pieces.push(clause); continue; }
|
|
1339
|
+
for (const word of clause.split(" ")) pieces.push(word);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
let cur = "";
|
|
1343
|
+
for (const piece of pieces) {
|
|
1344
|
+
if (!piece) continue;
|
|
1345
|
+
if (cur && cur.length + 1 + piece.length > limit) return cur;
|
|
1346
|
+
cur = cur ? `${cur} ${piece}` : piece;
|
|
1347
|
+
if (cur.length >= min) return cur;
|
|
1348
|
+
}
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1113
1352
|
function startAgentTurn() {
|
|
1114
1353
|
beginAgentTurn(); // bump currentTurn + reset the audio queue/guards
|
|
1115
1354
|
mode = "thinking";
|
|
@@ -1164,16 +1403,25 @@
|
|
|
1164
1403
|
}
|
|
1165
1404
|
ensureConv();
|
|
1166
1405
|
break;
|
|
1167
|
-
case "token":
|
|
1168
|
-
// Legacy path (backend no longer streams tokens for desktop). Kept so a
|
|
1169
|
-
// mixed-version daemon doesn't break — accumulate into a single bubble.
|
|
1170
|
-
appendStreamingToken(msg.text || "");
|
|
1171
|
-
break;
|
|
1172
1406
|
case "tool_start": addToolPill(msg.name); break;
|
|
1173
1407
|
case "tool_done": updateToolPill(msg.name); break;
|
|
1408
|
+
case "delta": {
|
|
1409
|
+
// Tokens as they land. Purely visual: this bubble is thrown away the
|
|
1410
|
+
// moment the real segment arrives, so nothing here is spoken or kept.
|
|
1411
|
+
if (!msg.text) break;
|
|
1412
|
+
ensureConv();
|
|
1413
|
+
ensureStreamingAgentBubble();
|
|
1414
|
+
streamingAgentEntry.text += msg.text;
|
|
1415
|
+
streamingAgentEntry.msgEl.innerHTML = formatWordsHtml(streamingAgentEntry.text);
|
|
1416
|
+
maybePrewarmTts();
|
|
1417
|
+
requestWindowResize();
|
|
1418
|
+
scrollConvToBottom();
|
|
1419
|
+
break;
|
|
1420
|
+
}
|
|
1174
1421
|
case "segment": {
|
|
1175
1422
|
// Each segment is its own agent message bubble + its own audio.
|
|
1176
1423
|
ensureConv();
|
|
1424
|
+
discardStreamingAgent(); // the streamed preview is now redundant
|
|
1177
1425
|
const text = (msg.text || "").trim();
|
|
1178
1426
|
if (!text) break;
|
|
1179
1427
|
const id = nextId++;
|
|
@@ -1185,6 +1433,7 @@
|
|
|
1185
1433
|
// it for gapless sequential playback. `speak` carries the inline emotion
|
|
1186
1434
|
// tags (the bubble `text` has them stripped) so a tag-aware engine like
|
|
1187
1435
|
// QVox can act on them; falls back to the visible text.
|
|
1436
|
+
showPendingAudio(id);
|
|
1188
1437
|
window.apx?.requestTts?.(msg.speak || text, id);
|
|
1189
1438
|
requestWindowResize();
|
|
1190
1439
|
scrollConvToBottom();
|
|
@@ -1194,6 +1443,7 @@
|
|
|
1194
1443
|
if (doneHandled) break;
|
|
1195
1444
|
doneHandled = true;
|
|
1196
1445
|
turnDone = true;
|
|
1446
|
+
discardStreamingAgent(); // nothing should outlive the turn as a preview
|
|
1197
1447
|
// Record the whole turn as one assistant entry for conversation context.
|
|
1198
1448
|
const full = (msg.text || "").trim();
|
|
1199
1449
|
if (full) history.push({ role: "assistant", content: full });
|
|
@@ -1201,7 +1451,12 @@
|
|
|
1201
1451
|
// the capsule can't get stuck in "Pensando…".
|
|
1202
1452
|
if (turnWatchdog) clearTimeout(turnWatchdog);
|
|
1203
1453
|
turnWatchdog = setTimeout(() => {
|
|
1204
|
-
turnAudios.forEach((e) => {
|
|
1454
|
+
turnAudios.forEach((e) => {
|
|
1455
|
+
if (e.ready) return;
|
|
1456
|
+
e.ready = true; e.failed = true; e.played = true;
|
|
1457
|
+
clearPendingAudio(e.m.id);
|
|
1458
|
+
markTurnUnvoiced(e.m.id, "la voz no respondió");
|
|
1459
|
+
});
|
|
1205
1460
|
pumpAudioQueue();
|
|
1206
1461
|
}, 12000);
|
|
1207
1462
|
// Play whatever audio is already ready; flip to idle if there's nothing
|
|
@@ -1212,13 +1467,18 @@
|
|
|
1212
1467
|
}
|
|
1213
1468
|
break;
|
|
1214
1469
|
}
|
|
1215
|
-
case "tts-
|
|
1216
|
-
|
|
1470
|
+
case "tts-part":
|
|
1471
|
+
// One sentence of this bubble's speech. The first starts playback; the
|
|
1472
|
+
// rest queue up behind it while they are still being generated.
|
|
1473
|
+
if (msg.seg != null) attachAudioPart(msg.seg, { url: msg.url, dur: msg.duration });
|
|
1474
|
+
break;
|
|
1475
|
+
case "tts-end":
|
|
1476
|
+
if (msg.seg != null) markAudioComplete(msg.seg);
|
|
1217
1477
|
break;
|
|
1218
1478
|
case "tts-failed": {
|
|
1219
1479
|
// No audio for this segment — skip it in the queue so playback advances.
|
|
1220
1480
|
const m = (msg.seg != null) ? messages.find((x) => x.id === msg.seg) : null;
|
|
1221
|
-
if (m) queueMarkFailed(m);
|
|
1481
|
+
if (m) { clearPendingAudio(m.id); queueMarkFailed(m); markTurnUnvoiced(m.id, msg.error); }
|
|
1222
1482
|
break;
|
|
1223
1483
|
}
|
|
1224
1484
|
case "error": {
|
|
@@ -358,6 +358,35 @@ button { font-family: inherit; }
|
|
|
358
358
|
.wavebar i.cur { transform: scaleY(1.25); }
|
|
359
359
|
.audio .dur { font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; min-width: 30px; text-align: right; }
|
|
360
360
|
|
|
361
|
+
/* Waiting for the voice. Same box as the real player so the swap is invisible:
|
|
362
|
+
the bars keep their shape and only their opacity moves, in a wave that runs
|
|
363
|
+
left to right — the reply is being spoken into existence, in order. */
|
|
364
|
+
.audio.pending { pointer-events: none; }
|
|
365
|
+
.audio.pending .play {
|
|
366
|
+
background: none; box-shadow: none;
|
|
367
|
+
border: 2px solid color-mix(in oklch, var(--ink-3) 30%, transparent);
|
|
368
|
+
border-top-color: var(--accent);
|
|
369
|
+
animation: audio-spin .7s linear infinite;
|
|
370
|
+
}
|
|
371
|
+
.audio.pending .wavebar { cursor: default; }
|
|
372
|
+
.audio.pending .wavebar i {
|
|
373
|
+
animation: audio-wait 1.15s ease-in-out infinite;
|
|
374
|
+
animation-delay: calc(var(--i) * 28ms);
|
|
375
|
+
}
|
|
376
|
+
.audio.pending .dur { letter-spacing: 1.5px; opacity: .7; }
|
|
377
|
+
@keyframes audio-spin { to { transform: rotate(360deg); } }
|
|
378
|
+
@keyframes audio-wait {
|
|
379
|
+
0%, 100% { opacity: .28; }
|
|
380
|
+
45% { opacity: .9; }
|
|
381
|
+
}
|
|
382
|
+
/* Motion is the whole signal here, so without it say so in the bars instead of
|
|
383
|
+
leaving a placeholder indistinguishable from a finished, silent player. */
|
|
384
|
+
@media (prefers-reduced-motion: reduce) {
|
|
385
|
+
.audio.pending .play,
|
|
386
|
+
.audio.pending .wavebar i { animation: none; }
|
|
387
|
+
.audio.pending .wavebar i { opacity: .4; }
|
|
388
|
+
}
|
|
389
|
+
|
|
361
390
|
/* Continued agent messages (no repeated "Roby" header) hug the previous one. */
|
|
362
391
|
.turn.cont { padding-top: 0; }
|
|
363
392
|
.turn.cont .msg-agent { margin-top: 1px; }
|
|
@@ -390,6 +419,11 @@ button { font-family: inherit; }
|
|
|
390
419
|
}
|
|
391
420
|
.chip:hover { background: var(--glass-hairline); color: var(--ink); border-color: transparent; }
|
|
392
421
|
.chip.done { color: oklch(0.6 0.15 150); }
|
|
422
|
+
/* "Sin voz": a passive marker, not a button — and it stays visible on older
|
|
423
|
+
turns too, which .turn-actions otherwise hides. */
|
|
424
|
+
.chip.unvoiced { cursor: default; opacity: .75; }
|
|
425
|
+
.chip.unvoiced:hover { background: transparent; color: var(--ink-2); border-color: var(--glass-hairline); }
|
|
426
|
+
.turn-actions:has(.unvoiced) { display: flex; opacity: 1; }
|
|
393
427
|
|
|
394
428
|
/* system notice (e.g. no mic permission / dead mic) — not a chat message */
|
|
395
429
|
.sys-notice {
|