@agentprojectcontext/apx 1.80.2 → 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 +134 -0
- 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
|
@@ -1,28 +1,121 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Bot, Clock, CornerDownRight, Copy, Info, Pencil, RefreshCw, X } from "lucide-react";
|
|
2
3
|
import { cn } from "../../lib/cn";
|
|
4
|
+
import { AgentAvatar, type AgentFace } from "../agents/AgentAvatar";
|
|
3
5
|
import { ToolCall } from "./ToolCall";
|
|
6
|
+
import { ActionGroup, segmentTurnParts, countTurnTools, type TurnSegment } from "./ActionGroup";
|
|
7
|
+
import { SkillTrace } from "./SkillTrace";
|
|
8
|
+
import { ReasoningBlock } from "./ReasoningBlock";
|
|
4
9
|
import { AskQuestionsCard } from "./AskQuestionsCard";
|
|
5
10
|
import { AskAnswersCard, parseAskAnswerText } from "./AskAnswersCard";
|
|
6
|
-
import {
|
|
11
|
+
import { AttachmentGroup, stripMediaMarker } from "./Attachment";
|
|
12
|
+
import { MarkdownPreview, renderMentions } from "../files/MarkdownPreview";
|
|
13
|
+
import { textOf, type ChatMsg, type ChatPart } from "../../hooks/useChat";
|
|
7
14
|
import { Tip } from "../ui/tip";
|
|
8
15
|
import { t } from "../../i18n";
|
|
9
16
|
|
|
10
17
|
interface Props {
|
|
11
18
|
msg: ChatMsg;
|
|
12
|
-
/** True when
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
19
|
+
/** True when THIS turn's ask_questions call is the one still waiting for an
|
|
20
|
+
* answer. Decided by the list, which can see whether a user message came
|
|
21
|
+
* after it; a turn cannot tell on its own. */
|
|
22
|
+
askPending?: boolean;
|
|
16
23
|
/** True when this user message is the reply to a preceding `ask_questions`
|
|
17
24
|
* call. Renders as a full-width centered card instead of the user bubble. */
|
|
18
25
|
isAskAnswer?: boolean;
|
|
19
26
|
onCopy?: (text: string) => void;
|
|
27
|
+
/** Who said it. Absent → the neutral glyph (surfaces that don't know the
|
|
28
|
+
* cast). The user side draws no avatar at all: you know who you are, and a
|
|
29
|
+
* generic silhouette on every second bubble is pure noise. */
|
|
30
|
+
face?: AgentFace;
|
|
31
|
+
/** Phone shaping: drop the avatar column and let the bubble have the width.
|
|
32
|
+
* On a 390px screen the face costs 36px on EVERY assistant turn to repeat
|
|
33
|
+
* the name already standing in the header, three inches above. */
|
|
34
|
+
compact?: boolean;
|
|
35
|
+
/** Written while the previous turn was still running: it is in the thread but
|
|
36
|
+
* has not left yet. Drawn at half strength, and it says so. */
|
|
37
|
+
queued?: boolean;
|
|
38
|
+
/** Take it back before it goes. Only meaningful alongside `queued`. */
|
|
39
|
+
onUnqueue?: () => void;
|
|
40
|
+
/** Re-run this assistant turn (drop it and everything after, ask again).
|
|
41
|
+
* Absent → no button (super-agent threads / previews don't offer it). */
|
|
42
|
+
onRegenerate?: () => void;
|
|
43
|
+
/** Edit this user turn and re-send, dropping everything after it. Absent → no
|
|
44
|
+
* edit affordance. */
|
|
45
|
+
onEdit?: (text: string) => void;
|
|
46
|
+
/** Group style: name each speaker in a header ABOVE the bubble (with a "traído
|
|
47
|
+
* por X" tag when a mention pulled them in), the way a group chat reads. Off
|
|
48
|
+
* in a 1:1, where the single agent is already named in the header. */
|
|
49
|
+
showSpeaker?: boolean;
|
|
50
|
+
/** Resolve an agent slug to its display name, for the "traído por X" tag. */
|
|
51
|
+
nameOf?: (slug: string) => string;
|
|
52
|
+
/** Full view: tool calls collapse into an ActionGroup. Simple ("pelado") view:
|
|
53
|
+
* tools hide and the narration lines that lived inside the group render as
|
|
54
|
+
* normal bubbles in order — same parts list, different layout. Default on. */
|
|
55
|
+
showTools?: boolean;
|
|
20
56
|
}
|
|
21
57
|
|
|
22
|
-
export function MessageBubble({ msg,
|
|
58
|
+
export function MessageBubble({ msg, askPending, isAskAnswer, onCopy, face, compact, queued, onUnqueue, onRegenerate, onEdit, showSpeaker, nameOf, showTools = true }: Props) {
|
|
59
|
+
// Hooks before any early return. The group-notice branch below returns without
|
|
60
|
+
// rendering a bubble, and these two used to sit after it — so a notice arriving
|
|
61
|
+
// mid-thread ("X joined the chat") changed the hook count for that row and React
|
|
62
|
+
// threw "rendered more hooks than during the previous render". Group chat is
|
|
63
|
+
// exactly where notices appear, so the crash was on the feature's own path.
|
|
64
|
+
const [editing, setEditing] = useState(false);
|
|
65
|
+
const [draft, setDraft] = useState("");
|
|
66
|
+
|
|
67
|
+
// A group system notice ("… se sumó / salió del chat") is a centred line, not
|
|
68
|
+
// a bubble, so it reads as something the room did rather than someone saying it.
|
|
69
|
+
if (msg.event) {
|
|
70
|
+
const who = (nameOf ? nameOf(msg.who || "") : msg.who) || msg.who || "";
|
|
71
|
+
return (
|
|
72
|
+
<div className="flex justify-center py-1">
|
|
73
|
+
<span className="rounded-full bg-muted/50 px-3 py-0.5 text-[11px] text-muted-fg">
|
|
74
|
+
{msg.event === "left" ? t("project.groups.left_chat", { name: who }) : t("project.groups.joined_chat", { name: who })}
|
|
75
|
+
</span>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
23
79
|
const mine = msg.role === "user";
|
|
24
|
-
|
|
80
|
+
// A turn that carried a file shows the file; its text is the marker the agent
|
|
81
|
+
// was handed, so only what the user actually wrote (caption, or the voice
|
|
82
|
+
// transcript) stays as text — copy included.
|
|
83
|
+
//
|
|
84
|
+
// Both directions. This was `mine ? msg.media : undefined`, which threw away
|
|
85
|
+
// every attachment the AGENT sent: the photo it pushed to Telegram, the image
|
|
86
|
+
// a routine delivered, a skill diagram it attached. The row on disk had the
|
|
87
|
+
// file and the bubble dropped it on the floor — so "the agent shared a photo"
|
|
88
|
+
// rendered as a bare caption, or as the placeholder text where a caption was
|
|
89
|
+
// never written.
|
|
90
|
+
const media = msg.media;
|
|
91
|
+
const copyText = media?.length ? stripMediaMarker(textOf(msg), media.length) : textOf(msg);
|
|
25
92
|
const hasTools = msg.parts.some((p) => p.kind === "tool");
|
|
93
|
+
// A user turn is never grouped — it has no tools, and the segmenter would
|
|
94
|
+
// return one plain part per message anyway; blocks only shape the agent side.
|
|
95
|
+
//
|
|
96
|
+
// The turn keeps ITS OWN count across however many blocks it happened in:
|
|
97
|
+
// three tools, a sentence, three more tools is one turn of six actions, not
|
|
98
|
+
// two turns of three.
|
|
99
|
+
const segments = mine ? [] : segmentTurnParts(msg.parts);
|
|
100
|
+
const toolTotal = mine ? 0 : countTurnTools(msg.parts);
|
|
101
|
+
const blockCount = segments.filter((seg) => seg.kind === "work").length;
|
|
102
|
+
// The last block is the one still working; the earlier ones already finished.
|
|
103
|
+
const lastWorkAt = segments.map((seg) => seg.kind).lastIndexOf("work");
|
|
104
|
+
// Simple view: same parts, no ActionGroup. Narration that lived inside the
|
|
105
|
+
// work block comes out as regular bubbles; tools stay hidden (ask_questions
|
|
106
|
+
// still shows — it is a control the reader must reach).
|
|
107
|
+
const simpleParts = !mine && !showTools
|
|
108
|
+
? msg.parts.filter((p) =>
|
|
109
|
+
p.kind === "text" ||
|
|
110
|
+
p.kind === "reasoning" ||
|
|
111
|
+
(p.kind === "tool" && p.tool === "ask_questions"),
|
|
112
|
+
)
|
|
113
|
+
: null;
|
|
114
|
+
// What actually gets drawn, in order. Only the agent's full view has blocks;
|
|
115
|
+
// the user's own turn and the simple view are flat lists of parts.
|
|
116
|
+
const renderList: TurnSegment[] = showTools && !mine
|
|
117
|
+
? segments
|
|
118
|
+
: (simpleParts || msg.parts).map((part) => ({ kind: "part", part }) as const);
|
|
26
119
|
|
|
27
120
|
if (mine && isAskAnswer) {
|
|
28
121
|
const text = textOf(msg);
|
|
@@ -31,148 +124,396 @@ export function MessageBubble({ msg, isLast, isAskAnswer, onCopy }: Props) {
|
|
|
31
124
|
}
|
|
32
125
|
}
|
|
33
126
|
|
|
127
|
+
const startEdit = () => { setDraft(copyText); setEditing(true); };
|
|
128
|
+
const submitEdit = () => {
|
|
129
|
+
const v = draft.trim();
|
|
130
|
+
setEditing(false);
|
|
131
|
+
if (!onEdit) return;
|
|
132
|
+
// Caption may be empty when the turn still has a file — editing only the
|
|
133
|
+
// text of a photo message must not refuse the save.
|
|
134
|
+
if (v || media?.length) onEdit(v);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// One part of the turn, outside any block: the agent's own words, its
|
|
138
|
+
// thinking, or a card that must stay in the open.
|
|
139
|
+
const renderPart = (part: ChatPart, i: number) =>
|
|
140
|
+
part.kind === "reasoning" ? (
|
|
141
|
+
<ReasoningBlock key={i} text={part.text} streaming={part.streaming} />
|
|
142
|
+
) : part.kind === "tool" ? (
|
|
143
|
+
part.tool === "ask_questions" && !mine ? (
|
|
144
|
+
<AskQuestionsCard key={`${part.id}-${i}`} part={part} pending={!!askPending} />
|
|
145
|
+
) : (
|
|
146
|
+
<ToolCall key={`${part.id}-${i}`} part={part} />
|
|
147
|
+
)
|
|
148
|
+
) : textOfPart(part.text, media) ? (
|
|
149
|
+
<div
|
|
150
|
+
key={i}
|
|
151
|
+
className={cn(
|
|
152
|
+
// max-w-full AND overflow-wrap:anywhere. The column caps at 85%, but
|
|
153
|
+
// a flex child is free to exceed its parent unless it is told not to,
|
|
154
|
+
// so one unbroken string still pushed the bubble past both edges of a
|
|
155
|
+
// phone with the text cut off on the left. `anywhere` rather than
|
|
156
|
+
// Tailwind's `break-words` (overflow-wrap: break-word) because only
|
|
157
|
+
// `anywhere` also shrinks the element's MIN-CONTENT width:
|
|
158
|
+
// break-word wraps the glyphs but still reports the whole URL as the
|
|
159
|
+
// narrowest the box can be, so any ancestor that sizes to content — a
|
|
160
|
+
// flex item, a grid cell — is laid out around the unbroken string and
|
|
161
|
+
// the overflow comes back.
|
|
162
|
+
"max-w-full [overflow-wrap:anywhere] rounded-2xl px-3 py-2 text-sm leading-relaxed",
|
|
163
|
+
mine
|
|
164
|
+
? "whitespace-pre-wrap rounded-br-sm bg-bubble-mine text-foreground"
|
|
165
|
+
// Agent bubble — the softer muted fill the group v1 used, now
|
|
166
|
+
// shared by every chat bubble so 1:1 and group read the same.
|
|
167
|
+
: "w-full rounded-bl-sm bg-muted/50 text-foreground",
|
|
168
|
+
)}
|
|
169
|
+
>
|
|
170
|
+
{/* The agent writes markdown — **bold**, lists, `code`, links — so its
|
|
171
|
+
turns render through the (dependency-free, no
|
|
172
|
+
dangerouslySetInnerHTML) markdown component. The user's own bubble
|
|
173
|
+
stays literal: they typed it, and reflowing their text as markdown
|
|
174
|
+
would eat their asterisks and line breaks. The first/last child
|
|
175
|
+
margins are zeroed so the block spacing does not double up with the
|
|
176
|
+
bubble's own py-2. */}
|
|
177
|
+
{mine ? (
|
|
178
|
+
renderMentions(textOfPart(part.text, media))
|
|
179
|
+
) : (
|
|
180
|
+
<MarkdownPreview
|
|
181
|
+
content={textOfPart(part.text, media)}
|
|
182
|
+
mentions
|
|
183
|
+
className="text-sm text-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0"
|
|
184
|
+
/>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
) : null;
|
|
188
|
+
|
|
34
189
|
return (
|
|
35
|
-
<div
|
|
36
|
-
{
|
|
190
|
+
<div
|
|
191
|
+
className={cn(
|
|
192
|
+
"group flex items-start gap-2",
|
|
193
|
+
mine ? "justify-end" : "justify-start",
|
|
194
|
+
// Not sent yet, and it should not read as if it were: the same bubble
|
|
195
|
+
// at half strength, the way a message in flight looks everywhere else.
|
|
196
|
+
queued && "opacity-55",
|
|
197
|
+
)}
|
|
198
|
+
>
|
|
199
|
+
{!mine && !compact && (face ? (
|
|
200
|
+
<AgentAvatar {...face} size={28} className="mt-0.5" />
|
|
201
|
+
) : (
|
|
37
202
|
<span className="mt-0.5 grid size-7 shrink-0 place-items-center rounded-full bg-muted text-muted-foreground">
|
|
38
203
|
<Bot size={14} />
|
|
39
204
|
</span>
|
|
40
|
-
)}
|
|
41
|
-
|
|
205
|
+
))}
|
|
206
|
+
{/* Both sides are capped. The user's own column used to have no max-width
|
|
207
|
+
at all, so one unbroken string — a Google Docs URL pasted into a
|
|
208
|
+
message — stretched the bubble past the viewport and the text ran off
|
|
209
|
+
the left edge. Invisible on a wide screen, unreadable on a phone. */}
|
|
210
|
+
<div
|
|
211
|
+
className={cn(
|
|
212
|
+
"flex min-w-0 flex-col gap-1.5",
|
|
213
|
+
compact ? "max-w-[92%]" : "max-w-[85%]",
|
|
214
|
+
mine ? "items-end" : "w-full",
|
|
215
|
+
)}
|
|
216
|
+
>
|
|
217
|
+
{/* Group style: name the speaker ABOVE the bubble, with a "traído por X"
|
|
218
|
+
tag when a mention pulled them in — the way a group chat reads. */}
|
|
219
|
+
{showSpeaker && !mine && (msg.agent || msg.agentId) && (
|
|
220
|
+
<div className="flex items-center gap-1.5 text-[11px] leading-none">
|
|
221
|
+
<span className="font-semibold text-foreground/90">{msg.agent}</span>
|
|
222
|
+
{msg.reason && (
|
|
223
|
+
<span className="inline-flex items-center gap-0.5 text-muted-fg/70">
|
|
224
|
+
<CornerDownRight size={11} /> {t("project.groups.pulled_by", { name: nameOf ? nameOf(msg.reason) : msg.reason })}
|
|
225
|
+
</span>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
229
|
+
|
|
230
|
+
{/* What was actually sent: the voice note plays, the photo is the photo,
|
|
231
|
+
the document opens. */}
|
|
232
|
+
{media?.length ? <AttachmentGroup media={media} /> : null}
|
|
233
|
+
|
|
42
234
|
{/* Operational notes (engine fallbacks, retries, suppressed tools). */}
|
|
43
235
|
{!mine && msg.notes && msg.notes.length > 0 && (
|
|
44
236
|
<div className="flex flex-col gap-0.5">
|
|
45
237
|
{msg.notes.map((n, i) => (
|
|
46
|
-
<span key={i} className="flex items-center gap-1 text-[10px] text-amber-400/80">
|
|
238
|
+
<span key={i} className="flex items-center gap-1 text-[10px] text-amber-600 dark:text-amber-400/80">
|
|
47
239
|
<Info size={10} /> {n}
|
|
48
240
|
</span>
|
|
49
241
|
))}
|
|
50
242
|
</div>
|
|
51
243
|
)}
|
|
52
244
|
|
|
53
|
-
{/* Skill Inspector: which skills the per-turn RAG injected for this turn.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<div
|
|
57
|
-
className="flex flex-wrap items-center gap-1 text-[10px] text-sky-400/90"
|
|
58
|
-
>
|
|
59
|
-
<Sparkles size={10} />
|
|
60
|
-
{msg.inspector.loaded?.map((s) => (
|
|
61
|
-
<span key={`l-${s}`} className="rounded bg-sky-500/15 px-1 py-0.5 font-mono">
|
|
62
|
-
{s}
|
|
63
|
-
</span>
|
|
64
|
-
))}
|
|
65
|
-
{msg.inspector.hinted?.map((s) => (
|
|
66
|
-
<span key={`h-${s}`} className="rounded border border-sky-500/30 px-1 py-0.5 font-mono opacity-70">
|
|
67
|
-
{s}?
|
|
68
|
-
</span>
|
|
69
|
-
))}
|
|
70
|
-
</div>
|
|
71
|
-
</Tip>
|
|
72
|
-
) : null}
|
|
73
|
-
|
|
74
|
-
{/* Ordered parts: interleaved assistant text + tool calls. */}
|
|
75
|
-
{msg.parts.map((part, i) =>
|
|
76
|
-
part.kind === "tool" ? (
|
|
77
|
-
part.tool === "ask_questions" && !mine ? (
|
|
78
|
-
<AskQuestionsCard
|
|
79
|
-
key={`${part.id}-${i}`}
|
|
80
|
-
part={part}
|
|
81
|
-
pending={!!isLast}
|
|
82
|
-
/>
|
|
83
|
-
) : (
|
|
84
|
-
<ToolCall key={`${part.id}-${i}`} part={part} />
|
|
85
|
-
)
|
|
86
|
-
) : part.text ? (
|
|
87
|
-
<div
|
|
88
|
-
key={i}
|
|
89
|
-
className={cn(
|
|
90
|
-
"whitespace-pre-wrap rounded-2xl px-3 py-2 text-sm leading-relaxed shadow-sm",
|
|
91
|
-
mine
|
|
92
|
-
? "rounded-br-sm border border-emerald-500/30 bg-emerald-500/10 text-foreground dark:bg-emerald-500/15"
|
|
93
|
-
: "w-full rounded-bl-sm border border-border bg-card text-foreground",
|
|
94
|
-
)}
|
|
95
|
-
>
|
|
96
|
-
{part.text}
|
|
97
|
-
</div>
|
|
98
|
-
) : null,
|
|
99
|
-
)}
|
|
245
|
+
{/* Skill Inspector: which skills the per-turn RAG injected for this turn.
|
|
246
|
+
Each badge opens the skill it names. */}
|
|
247
|
+
{!mine && msg.inspector && <SkillTrace inspector={msg.inspector} />}
|
|
100
248
|
|
|
101
|
-
{/*
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
249
|
+
{/* Editing your own turn in place: on save it re-sends and everything
|
|
250
|
+
below is dropped and re-answered. Enter saves, Esc/Cancel backs out. */}
|
|
251
|
+
{mine && editing && (
|
|
252
|
+
<div className={cn("flex w-full flex-col gap-1.5", compact ? "max-w-[92%]" : "max-w-[85%]")}>
|
|
253
|
+
<textarea
|
|
254
|
+
autoFocus
|
|
255
|
+
value={draft}
|
|
256
|
+
onChange={(e) => setDraft(e.target.value)}
|
|
257
|
+
onKeyDown={(e) => {
|
|
258
|
+
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); submitEdit(); }
|
|
259
|
+
if (e.key === "Escape") setEditing(false);
|
|
260
|
+
}}
|
|
261
|
+
rows={Math.min(8, Math.max(2, draft.split("\n").length))}
|
|
262
|
+
className="w-full resize-y rounded-2xl rounded-br-sm border border-primary/40 bg-bubble-mine px-3 py-2 text-sm leading-relaxed text-foreground outline-none focus:border-primary"
|
|
263
|
+
/>
|
|
264
|
+
<div className="flex items-center justify-end gap-2 text-xs">
|
|
265
|
+
<button type="button" onClick={() => setEditing(false)} className="rounded px-2 py-1 text-muted-foreground hover:text-foreground">
|
|
266
|
+
{t("common.cancel")}
|
|
267
|
+
</button>
|
|
268
|
+
<button type="button" onClick={submitEdit} disabled={!draft.trim()} className="rounded bg-primary px-2 py-1 font-medium text-primary-foreground disabled:opacity-50">
|
|
269
|
+
{t("chat_ui.edit_resend")}
|
|
270
|
+
</button>
|
|
271
|
+
</div>
|
|
105
272
|
</div>
|
|
106
273
|
)}
|
|
274
|
+
{/* The turn in the order it happened: a run of tool calls collapses into
|
|
275
|
+
one block, and what the agent SAID between the runs stands outside
|
|
276
|
+
them, as the message it is. A 24-step turn is still a log rather
|
|
277
|
+
than a screenful of cards — but the reader can now see WHERE in the
|
|
278
|
+
turn each thing was said, instead of only the closing line with
|
|
279
|
+
everything before it inside one box.
|
|
107
280
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
{!mine &&
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
281
|
+
Simple view has no blocks at all: every text/reasoning part in
|
|
282
|
+
original order, tools hidden (ask_questions still shows — it is a
|
|
283
|
+
control the reader must reach). */}
|
|
284
|
+
{!(mine && editing) && renderList.map((seg, si) =>
|
|
285
|
+
seg.kind === "work" ? (
|
|
286
|
+
<ActionGroup
|
|
287
|
+
key={`work-${si}`}
|
|
288
|
+
parts={seg.parts}
|
|
289
|
+
// Only the LAST block is still working; the ones above it have
|
|
290
|
+
// already finished, and a spinner on each would say otherwise.
|
|
291
|
+
running={!!msg.pending && si === lastWorkAt}
|
|
292
|
+
// Numbered against the TURN, not the block: a second block
|
|
293
|
+
// starting over at "1 action" would read as a second turn. A turn
|
|
294
|
+
// with one block just says how many — "1–4 of 4" is noise.
|
|
295
|
+
range={blockCount > 1 ? { from: seg.from, to: seg.to, total: toolTotal } : undefined}
|
|
296
|
+
/>
|
|
297
|
+
) : (
|
|
298
|
+
renderPart(seg.part, si)
|
|
299
|
+
),
|
|
300
|
+
)}
|
|
301
|
+
{/* Still going. Not just before the first part arrives: a turn that has
|
|
302
|
+
been running shell commands for two minutes shows a list of finished
|
|
303
|
+
steps and nothing that says more is coming, so it reads as an answer
|
|
304
|
+
that stopped mid-thought. The pill stays for the whole turn and goes
|
|
305
|
+
when the turn does. */}
|
|
306
|
+
{!mine && msg.pending && (
|
|
307
|
+
<Typing label={
|
|
308
|
+
(() => {
|
|
309
|
+
const name = face?.name || msg.agent || "";
|
|
310
|
+
const key = msg.parts.length === 0 ? "chat_ui.typing" : "chat_ui.working";
|
|
311
|
+
// In a group the speaker header already names them right above, so
|
|
312
|
+
// the pill drops the name ("está escribiendo…"). In a 1:1 the pill
|
|
313
|
+
// is the only place it's named, so keep it ("Candela está escribiendo…").
|
|
314
|
+
return showSpeaker || !name
|
|
315
|
+
? t(`${key}_generic` as "chat_ui.typing_generic")
|
|
316
|
+
: t(key, { name });
|
|
317
|
+
})()
|
|
318
|
+
} />
|
|
124
319
|
)}
|
|
125
320
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
321
|
+
{/* One line under the bubble: who answered on the left, when it did and
|
|
322
|
+
what it cost on the right. They used to be two stacked rows with the
|
|
323
|
+
second one hover-only, which on a phone means it does not exist.
|
|
324
|
+
Nothing at all while the turn is still running: a lone timestamp
|
|
325
|
+
under "escribiendo…" is a receipt for a message that has not
|
|
326
|
+
arrived yet. It appears with the answer. */}
|
|
327
|
+
{!(!mine && msg.pending) && <div
|
|
328
|
+
className={cn(
|
|
329
|
+
"flex w-full items-center gap-x-2 gap-y-1 text-[10px]",
|
|
330
|
+
// On a phone the row may not wrap: the whole point is that the meta
|
|
331
|
+
// stands BESIDE the attribution, and "zen:deepseek-v4-flash-free"
|
|
332
|
+
// alone fills 390px, so letting it wrap puts the data back under the
|
|
333
|
+
// bubble where it started. The model gives up the room instead — it
|
|
334
|
+
// is the one field here also spelled out in the context panel.
|
|
335
|
+
compact ? "flex-nowrap" : "flex-wrap",
|
|
336
|
+
mine && "justify-end",
|
|
337
|
+
)}
|
|
338
|
+
>
|
|
339
|
+
{/* In a group the speaker is named ABOVE the bubble, so the footer drops
|
|
340
|
+
the green name chip and keeps only model/time/cost. */}
|
|
341
|
+
{!mine && msg.agent && !showSpeaker && (
|
|
342
|
+
<span className="shrink-0 rounded bg-emerald-500/15 px-1 py-0.5 font-medium text-emerald-700 dark:text-emerald-300">
|
|
343
|
+
{msg.agent}
|
|
131
344
|
</span>
|
|
132
|
-
) : null}
|
|
133
|
-
{!mine && hasTools && (
|
|
134
|
-
<span>· {t("shared_ui.tools_count", { n: msg.parts.filter((p) => p.kind === "tool").length })}</span>
|
|
135
345
|
)}
|
|
136
|
-
{/*
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
· {t("shared_ui.tools_count", { n: msg.toolSummary.total })}
|
|
144
|
-
{msg.toolSummary.failed
|
|
145
|
-
? ` (${t("shared_ui.tools_failed", { n: msg.toolSummary.failed })})`
|
|
146
|
-
: ""}
|
|
346
|
+
{/* Half-strength surface: the attribution sits under the bubble and
|
|
347
|
+
should read as quieter than it, never as a second chip competing
|
|
348
|
+
with the agent's name. The token flips per theme, so one value
|
|
349
|
+
covers light and dark. */}
|
|
350
|
+
{!mine && msg.model && (
|
|
351
|
+
<span className="min-w-0 truncate rounded bg-surface-soft/50 px-1 py-0.5 font-mono text-muted-foreground">
|
|
352
|
+
{msg.model}
|
|
147
353
|
</span>
|
|
148
|
-
) : null}
|
|
149
|
-
{onCopy && copyText && (
|
|
150
|
-
<Tip content={t("chat_ui.copy")}>
|
|
151
|
-
<button
|
|
152
|
-
type="button"
|
|
153
|
-
onClick={() => onCopy(copyText)}
|
|
154
|
-
className="inline-flex items-center gap-1 hover:text-foreground"
|
|
155
|
-
aria-label={t("chat_ui.copy")}
|
|
156
|
-
>
|
|
157
|
-
<Copy size={10} /> {t("chat_ui.copy")}
|
|
158
|
-
</button>
|
|
159
|
-
</Tip>
|
|
160
354
|
)}
|
|
161
|
-
|
|
355
|
+
<div
|
|
356
|
+
className={cn(
|
|
357
|
+
"ml-auto flex shrink-0 items-center gap-2 text-muted-foreground",
|
|
358
|
+
// The phone has no hover, so there it is simply always on. So is
|
|
359
|
+
// the queue line — "waiting its turn, here is how to take it
|
|
360
|
+
// back" is not something to hide behind a hover.
|
|
361
|
+
!compact && !queued && "opacity-0 transition-opacity group-hover:opacity-100",
|
|
362
|
+
)}
|
|
363
|
+
>
|
|
364
|
+
{/* A timestamp on a turn that has not gone out yet is a receipt for
|
|
365
|
+
something that did not happen. What it is waiting for takes the
|
|
366
|
+
slot instead, until it leaves and gets a real one. */}
|
|
367
|
+
{queued ? (
|
|
368
|
+
<span className="inline-flex items-center gap-1">
|
|
369
|
+
<Clock size={10} /> {t("chat_ui.queued")}
|
|
370
|
+
</span>
|
|
371
|
+
) : (
|
|
372
|
+
<span>{formatTs(msg.ts, compact)}</span>
|
|
373
|
+
)}
|
|
374
|
+
{queued && onUnqueue && (
|
|
375
|
+
<Tip content={t("chat_ui.queued_cancel")}>
|
|
376
|
+
<button
|
|
377
|
+
type="button"
|
|
378
|
+
onClick={onUnqueue}
|
|
379
|
+
className="inline-flex items-center hover:text-foreground"
|
|
380
|
+
aria-label={t("chat_ui.queued_cancel")}
|
|
381
|
+
>
|
|
382
|
+
<X size={11} />
|
|
383
|
+
</button>
|
|
384
|
+
</Tip>
|
|
385
|
+
)}
|
|
386
|
+
{!mine && msg.usage && (msg.usage.input_tokens || msg.usage.output_tokens) ? (
|
|
387
|
+
<span className="font-mono">
|
|
388
|
+
· {fmtTok((msg.usage.input_tokens || 0) + (msg.usage.output_tokens || 0))} tok
|
|
389
|
+
</span>
|
|
390
|
+
) : null}
|
|
391
|
+
{showTools && !mine && hasTools && (
|
|
392
|
+
<span>· {t("shared_ui.tools_count", { n: msg.parts.filter((p) => p.kind === "tool").length })}</span>
|
|
393
|
+
)}
|
|
394
|
+
{/* Replayed turns have no tool parts — the live events are gone —
|
|
395
|
+
but they do carry the summary recorded at the time. Show that
|
|
396
|
+
instead, so history does not look like the agent just answered
|
|
397
|
+
from nothing. Failures are named: "it tried and could not" is
|
|
398
|
+
the half worth surfacing. Hidden in simple view with the rest. */}
|
|
399
|
+
{showTools && !mine && !hasTools && msg.toolSummary?.tools?.length ? (
|
|
400
|
+
<span title={msg.toolSummary.tools.map((x) => `${x.name}×${x.count}`).join(", ")}>
|
|
401
|
+
· {t("shared_ui.tools_count", { n: msg.toolSummary.total })}
|
|
402
|
+
{msg.toolSummary.failed
|
|
403
|
+
? ` (${t("shared_ui.tools_failed", { n: msg.toolSummary.failed })})`
|
|
404
|
+
: ""}
|
|
405
|
+
</span>
|
|
406
|
+
) : null}
|
|
407
|
+
{onCopy && copyText && (
|
|
408
|
+
<Tip content={t("chat_ui.copy")}>
|
|
409
|
+
<button
|
|
410
|
+
type="button"
|
|
411
|
+
onClick={() => onCopy(copyText)}
|
|
412
|
+
className="inline-flex items-center gap-1 hover:text-foreground"
|
|
413
|
+
aria-label={t("chat_ui.copy")}
|
|
414
|
+
>
|
|
415
|
+
<Copy size={10} /> {!compact && t("chat_ui.copy")}
|
|
416
|
+
</button>
|
|
417
|
+
</Tip>
|
|
418
|
+
)}
|
|
419
|
+
{/* Edit your turn and re-ask (drops everything below). */}
|
|
420
|
+
{mine && onEdit && !queued && !editing && (
|
|
421
|
+
<Tip content={t("chat_ui.edit")}>
|
|
422
|
+
<button
|
|
423
|
+
type="button"
|
|
424
|
+
onClick={startEdit}
|
|
425
|
+
className="inline-flex items-center gap-1 hover:text-foreground"
|
|
426
|
+
aria-label={t("chat_ui.edit")}
|
|
427
|
+
>
|
|
428
|
+
<Pencil size={10} /> {!compact && t("chat_ui.edit")}
|
|
429
|
+
</button>
|
|
430
|
+
</Tip>
|
|
431
|
+
)}
|
|
432
|
+
{/* Re-run this answer (drops it and everything below). */}
|
|
433
|
+
{!mine && onRegenerate && !queued && (
|
|
434
|
+
<Tip content={t("chat_ui.regenerate")}>
|
|
435
|
+
<button
|
|
436
|
+
type="button"
|
|
437
|
+
onClick={onRegenerate}
|
|
438
|
+
className="inline-flex items-center gap-1 hover:text-foreground"
|
|
439
|
+
aria-label={t("chat_ui.regenerate")}
|
|
440
|
+
>
|
|
441
|
+
<RefreshCw size={10} /> {!compact && t("chat_ui.regenerate")}
|
|
442
|
+
</button>
|
|
443
|
+
</Tip>
|
|
444
|
+
)}
|
|
445
|
+
</div>
|
|
446
|
+
</div>}
|
|
162
447
|
</div>
|
|
163
|
-
{mine && (
|
|
164
|
-
<span className="mt-0.5 grid size-7 shrink-0 place-items-center rounded-full bg-muted text-muted-foreground">
|
|
165
|
-
<User size={14} />
|
|
166
|
-
</span>
|
|
167
|
-
)}
|
|
168
448
|
</div>
|
|
169
449
|
);
|
|
170
450
|
}
|
|
171
451
|
|
|
172
|
-
|
|
452
|
+
/** "escribiendo…" / "trabajando…" — the word in the reader's language, with the
|
|
453
|
+
* dots doing the waiting. Three spans on staggered delays rather than a CSS
|
|
454
|
+
* animation of the text itself, so a screen reader gets one stable label
|
|
455
|
+
* instead of a glyph that changes three times a second. */
|
|
456
|
+
function Typing({ label }: { label: string }) {
|
|
457
|
+
return (
|
|
458
|
+
// w-fit, not the stretched full-width bubble every other assistant turn
|
|
459
|
+
// gets: a two-word status painted across the whole column reads as a
|
|
460
|
+
// message that arrived empty.
|
|
461
|
+
<div className="flex w-fit items-center gap-1.5 self-start rounded-2xl rounded-bl-sm bg-surface-soft px-3 py-2 text-sm text-muted-foreground">
|
|
462
|
+
<span>{label}</span>
|
|
463
|
+
<span aria-hidden className="flex items-center gap-[3px]">
|
|
464
|
+
{[0, 1, 2].map((i) => (
|
|
465
|
+
<span
|
|
466
|
+
key={i}
|
|
467
|
+
className="size-1 animate-bounce rounded-full bg-current"
|
|
468
|
+
style={{ animationDelay: `${i * 140}ms`, animationDuration: "1s" }}
|
|
469
|
+
/>
|
|
470
|
+
))}
|
|
471
|
+
</span>
|
|
472
|
+
</div>
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** The visible text of a part: with attachments, the machine-facing markers
|
|
477
|
+
* are dropped and what is left (a caption, or the voice transcript) is shown. */
|
|
478
|
+
function textOfPart(text: string | undefined, media: unknown[] | undefined): string {
|
|
479
|
+
if (!text) return "";
|
|
480
|
+
return media?.length ? stripMediaMarker(text, media.length) : text;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/** 1219686 → "1.2M". The raw count fit while the row was hover-only and had the
|
|
484
|
+
* bubble's whole width; now it shares a line with the agent and the model on a
|
|
485
|
+
* 390px screen, where seven digits are what pushes the row onto two. */
|
|
486
|
+
function fmtTok(n: number): string {
|
|
487
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
488
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
|
|
489
|
+
return String(n);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function formatTs(iso: string, compact?: boolean): string {
|
|
173
493
|
try {
|
|
174
494
|
const d = new Date(iso);
|
|
175
|
-
|
|
495
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
496
|
+
// Seconds are for reading a live stream on a desktop; on the phone they are
|
|
497
|
+
// three more characters competing with the model's name for the same line.
|
|
498
|
+
const time = d.toLocaleTimeString([], {
|
|
499
|
+
hour: "2-digit",
|
|
500
|
+
minute: "2-digit",
|
|
501
|
+
...(compact ? {} : { second: "2-digit" }),
|
|
502
|
+
});
|
|
503
|
+
// Today → time only. Older (or future) days keep the date so a scrolled
|
|
504
|
+
// thread is readable without opening a calendar.
|
|
505
|
+
const now = new Date();
|
|
506
|
+
const sameDay =
|
|
507
|
+
d.getFullYear() === now.getFullYear() &&
|
|
508
|
+
d.getMonth() === now.getMonth() &&
|
|
509
|
+
d.getDate() === now.getDate();
|
|
510
|
+
if (sameDay) return time;
|
|
511
|
+
const date = d.toLocaleDateString([], {
|
|
512
|
+
day: "2-digit",
|
|
513
|
+
month: "2-digit",
|
|
514
|
+
...(d.getFullYear() !== now.getFullYear() ? { year: "2-digit" } : {}),
|
|
515
|
+
});
|
|
516
|
+
return `${date} ${time}`;
|
|
176
517
|
} catch {
|
|
177
518
|
return iso;
|
|
178
519
|
}
|