@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Shared OpenAI-compatible chat adapter (OpenAI, Groq, OpenRouter, …).
|
|
2
2
|
import { pingUrl } from "./_health.js";
|
|
3
|
+
import { streamSseDataEvents } from "./_streaming.js";
|
|
3
4
|
|
|
4
5
|
// Adapters stash provider-private metadata on tool_calls under an underscore
|
|
5
6
|
// prefix (e.g. gemini's `_thoughtSignature`). Strict OpenAI-shaped APIs reject
|
|
@@ -14,14 +15,38 @@ function stripPrivateFields(tc) {
|
|
|
14
15
|
return out;
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
/** OpenAI multimodal content: text plus any `images` riding on the turn.
|
|
19
|
+
* Without this, run-agent's turnImages were silently dropped and a vision
|
|
20
|
+
* model (or a text model behind a vision bridge) never saw the photo. */
|
|
21
|
+
function contentForOpenAi(m) {
|
|
22
|
+
const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content ?? "");
|
|
23
|
+
const imgs = Array.isArray(m.images)
|
|
24
|
+
? m.images.filter((im) => im && im.data && im.mime)
|
|
25
|
+
: [];
|
|
26
|
+
if (!imgs.length) return text;
|
|
27
|
+
return [
|
|
28
|
+
...(text ? [{ type: "text", text }] : []),
|
|
29
|
+
...imgs.map((im) => ({
|
|
30
|
+
type: "image_url",
|
|
31
|
+
image_url: { url: `data:${im.mime};base64,${im.data}` },
|
|
32
|
+
})),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
|
|
17
36
|
export function createOpenAiCompatibleEngine({
|
|
18
37
|
id,
|
|
19
38
|
defaultBaseUrl,
|
|
20
39
|
apiKeyEnv,
|
|
21
40
|
defaultFallbackModel = null,
|
|
41
|
+
extraHeaders = {},
|
|
42
|
+
decorateMessage = null,
|
|
43
|
+
// Zen free-tier accepts the literal key "public" with the opencode UA.
|
|
44
|
+
// Without a key the adapter would refuse the call even though the gateway
|
|
45
|
+
// is happy — so an engine can opt into a built-in default.
|
|
46
|
+
defaultApiKey = "",
|
|
22
47
|
}) {
|
|
23
48
|
function getKey(config) {
|
|
24
|
-
return config?.api_key || process.env[apiKeyEnv] || "";
|
|
49
|
+
return config?.api_key || process.env[apiKeyEnv] || defaultApiKey || "";
|
|
25
50
|
}
|
|
26
51
|
|
|
27
52
|
function getBaseUrl(config) {
|
|
@@ -29,12 +54,29 @@ export function createOpenAiCompatibleEngine({
|
|
|
29
54
|
return String(raw).replace(/\/$/, "");
|
|
30
55
|
}
|
|
31
56
|
|
|
57
|
+
// Headers beyond the ones every call needs. Some gateways gate on something
|
|
58
|
+
// other than the key — OpenCode Zen serves its free tier only to a caller
|
|
59
|
+
// that identifies itself as the opencode client — and a self-hosted proxy in
|
|
60
|
+
// front of a model may want its own. The adapter carries a default per
|
|
61
|
+
// engine; `engines.<id>.headers` in config adds to or overrides it. The
|
|
62
|
+
// per-call ones (auth, content-type) always win, so config can't blank out
|
|
63
|
+
// the key by accident.
|
|
64
|
+
function buildHeaders(config, perCall = {}) {
|
|
65
|
+
const merged = { ...extraHeaders, ...(config?.headers || {}), ...perCall };
|
|
66
|
+
const out = {};
|
|
67
|
+
for (const [k, v] of Object.entries(merged)) {
|
|
68
|
+
if (v != null && v !== "") out[String(k).toLowerCase()] = String(v);
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
32
73
|
return {
|
|
33
74
|
id,
|
|
34
75
|
needsApiKey: true,
|
|
35
76
|
apiKeyEnv,
|
|
36
77
|
defaultBaseUrl,
|
|
37
78
|
defaultFallbackModel,
|
|
79
|
+
buildHeaders,
|
|
38
80
|
|
|
39
81
|
/**
|
|
40
82
|
* Health: confirm we have a key and the `/models` catalog answers.
|
|
@@ -48,7 +90,7 @@ export function createOpenAiCompatibleEngine({
|
|
|
48
90
|
const base = getBaseUrl(config);
|
|
49
91
|
const res = await pingUrl(`${base}/models`, {
|
|
50
92
|
timeoutMs: Math.max(timeoutMs, 1200),
|
|
51
|
-
headers: { authorization: `Bearer ${getKey(config)}` },
|
|
93
|
+
headers: buildHeaders(config, { authorization: `Bearer ${getKey(config)}` }),
|
|
52
94
|
});
|
|
53
95
|
if (res.ok) return { ok: true, provider: id, detail: base };
|
|
54
96
|
// Key present but catalog ping failed — keep going, the chat call will
|
|
@@ -72,6 +114,8 @@ export function createOpenAiCompatibleEngine({
|
|
|
72
114
|
tools,
|
|
73
115
|
toolChoice,
|
|
74
116
|
signal,
|
|
117
|
+
onToken,
|
|
118
|
+
onReasoningToken,
|
|
75
119
|
}) {
|
|
76
120
|
const key = getKey(config);
|
|
77
121
|
if (!key) {
|
|
@@ -86,16 +130,24 @@ export function createOpenAiCompatibleEngine({
|
|
|
86
130
|
// - tool_call_id (tool result turns — Groq / OpenAI strict require
|
|
87
131
|
// this to match the assistant's tool_call id)
|
|
88
132
|
// - name (some providers prefer it on tool messages)
|
|
133
|
+
// - images (user/tool turns carrying vision bytes — rendered as
|
|
134
|
+
// multimodal content parts; text-only models ignore or
|
|
135
|
+
// 400, which the vision bridge in run-agent covers)
|
|
89
136
|
//
|
|
90
137
|
// Dropping any of these is the cause of the
|
|
91
138
|
// "messages.N.tool_call_id: property 'tool_call_id' is missing"
|
|
92
139
|
// 400 we saw on Groq when llama-3.3 emitted a pseudo-tool call.
|
|
140
|
+
//
|
|
141
|
+
// Rebuilding the entry from scratch (rather than spreading `m`) is what
|
|
142
|
+
// keeps engine-private fields off the wire — strict OpenAI-shaped APIs
|
|
143
|
+
// reject unknown properties. An engine that needs one of them replayed
|
|
144
|
+
// for a specific model opts in through `decorateMessage`; see zen.js.
|
|
93
145
|
const fullMessages = [];
|
|
94
146
|
if (system) fullMessages.push({ role: "system", content: system });
|
|
95
147
|
for (const m of messages) {
|
|
96
148
|
const entry = {
|
|
97
149
|
role: m.role,
|
|
98
|
-
content:
|
|
150
|
+
content: contentForOpenAi(m),
|
|
99
151
|
};
|
|
100
152
|
if (m.tool_calls) entry.tool_calls = m.tool_calls.map(stripPrivateFields);
|
|
101
153
|
if (m.tool_call_id) entry.tool_call_id = m.tool_call_id;
|
|
@@ -104,6 +156,7 @@ export function createOpenAiCompatibleEngine({
|
|
|
104
156
|
if (m.role === "tool" && (m.tool_name || m.name)) {
|
|
105
157
|
entry.name = m.name || m.tool_name;
|
|
106
158
|
}
|
|
159
|
+
if (decorateMessage) decorateMessage(entry, m, { model, config });
|
|
107
160
|
fullMessages.push(entry);
|
|
108
161
|
}
|
|
109
162
|
|
|
@@ -114,6 +167,15 @@ export function createOpenAiCompatibleEngine({
|
|
|
114
167
|
max_tokens: maxTokens,
|
|
115
168
|
};
|
|
116
169
|
|
|
170
|
+
// Thinking, off at the source. A reasoning model spends the token budget
|
|
171
|
+
// planning before it writes a word, so a small max_tokens comes back with
|
|
172
|
+
// a full chain of thought and an EMPTY answer — and the operator pays for
|
|
173
|
+
// both. `thinking: false` on the provider stops it being generated;
|
|
174
|
+
// `reasoning_effort: "none"` is the knob the OpenAI-shaped gateways read
|
|
175
|
+
// (verified against Zen: reasoning_tokens drops to 0). Only sent when the
|
|
176
|
+
// operator asked for it — a provider that never heard of the field 400s.
|
|
177
|
+
if (config?.thinking === false) body.reasoning_effort = "none";
|
|
178
|
+
|
|
117
179
|
if (tools && tools.length > 0) {
|
|
118
180
|
body.tools = tools;
|
|
119
181
|
if (toolChoice === "required" || toolChoice === "any") {
|
|
@@ -123,34 +185,49 @@ export function createOpenAiCompatibleEngine({
|
|
|
123
185
|
}
|
|
124
186
|
}
|
|
125
187
|
|
|
188
|
+
// Stream when the caller wants tokens as they land. A tool-forced turn is
|
|
189
|
+
// excluded: it has no prose to stream, only a call to assemble.
|
|
190
|
+
const wantsStream =
|
|
191
|
+
typeof onToken === "function" && toolChoice !== "required" && toolChoice !== "any";
|
|
192
|
+
if (wantsStream) {
|
|
193
|
+
body.stream = true;
|
|
194
|
+
// Streamed responses omit usage unless asked. Gateways that don't know
|
|
195
|
+
// the field ignore it; Zen sends the totals in a final choice-less row.
|
|
196
|
+
body.stream_options = { include_usage: true };
|
|
197
|
+
}
|
|
198
|
+
|
|
126
199
|
const res = await fetch(`${getBaseUrl(config)}/chat/completions`, {
|
|
127
200
|
method: "POST",
|
|
128
|
-
headers: {
|
|
201
|
+
headers: buildHeaders(config, {
|
|
129
202
|
"content-type": "application/json",
|
|
130
203
|
authorization: `Bearer ${key}`,
|
|
131
|
-
},
|
|
204
|
+
}),
|
|
132
205
|
body: JSON.stringify(body),
|
|
133
206
|
signal,
|
|
134
207
|
});
|
|
135
|
-
|
|
208
|
+
|
|
136
209
|
if (!res.ok) {
|
|
210
|
+
// An error answers as JSON even when the request asked for a stream.
|
|
211
|
+
const err = await res.json().catch(() => null);
|
|
137
212
|
throw new Error(
|
|
138
|
-
`${id} ${res.status}: ${
|
|
213
|
+
`${id} ${res.status}: ${err?.error?.message || JSON.stringify(err)}`
|
|
139
214
|
);
|
|
140
215
|
}
|
|
141
216
|
|
|
217
|
+
if (wantsStream) return readStream(res, onToken, onReasoningToken);
|
|
218
|
+
|
|
219
|
+
const json = await res.json();
|
|
142
220
|
const choice = json.choices?.[0];
|
|
143
|
-
// Reasoning models on OpenRouter/Groq return their chain of thought in a
|
|
144
|
-
// SEPARATE field (`reasoning`, or `reasoning_content` on some routers).
|
|
145
|
-
// It is not an answer and must never reach a channel — fold it into the
|
|
146
|
-
// <think> form APX already knows how to strip per channel.
|
|
147
|
-
const reasoning = choice?.message?.reasoning || choice?.message?.reasoning_content || "";
|
|
148
|
-
const answer = choice?.message?.content || "";
|
|
149
|
-
const text = reasoning ? `<think>${reasoning}</think>${answer}` : answer;
|
|
150
221
|
const toolCalls = choice?.message?.tool_calls;
|
|
151
222
|
|
|
152
223
|
return {
|
|
153
|
-
|
|
224
|
+
// Reasoning travels in its own field, never folded into the answer.
|
|
225
|
+
// It used to be wrapped in <think>…</think> and left inside `text` for
|
|
226
|
+
// each surface to strip; the surfaces that forgot (web, CLI) showed the
|
|
227
|
+
// model's notes to the user. Keeping the two apart at the boundary
|
|
228
|
+
// means no surface can leak what it never received.
|
|
229
|
+
text: choice?.message?.content || "",
|
|
230
|
+
reasoning: choice?.message?.reasoning || choice?.message?.reasoning_content || "",
|
|
154
231
|
tool_calls: toolCalls?.length > 0 ? toolCalls : undefined,
|
|
155
232
|
finish_reason: choice?.finish_reason,
|
|
156
233
|
usage: {
|
|
@@ -162,3 +239,61 @@ export function createOpenAiCompatibleEngine({
|
|
|
162
239
|
},
|
|
163
240
|
};
|
|
164
241
|
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Read an OpenAI-shaped SSE stream into the same result object the blocking
|
|
245
|
+
* path returns. The two channels stay apart the whole way down: `content`
|
|
246
|
+
* deltas reach `onToken`, reasoning reaches `onReasoningToken`, and a caller
|
|
247
|
+
* that only passes the first never sees a word of the thinking. tool_calls are
|
|
248
|
+
* reassembled by index (a call arrives split across rows: the name in one, the
|
|
249
|
+
* arguments a character at a time after it).
|
|
250
|
+
*/
|
|
251
|
+
async function readStream(res, onToken, onReasoningToken) {
|
|
252
|
+
let text = "";
|
|
253
|
+
let reasoning = "";
|
|
254
|
+
let finishReason;
|
|
255
|
+
let usage = null;
|
|
256
|
+
const calls = [];
|
|
257
|
+
|
|
258
|
+
for await (const evt of streamSseDataEvents(res)) {
|
|
259
|
+
if (evt.usage) usage = evt.usage;
|
|
260
|
+
const choice = evt.choices?.[0];
|
|
261
|
+
if (!choice) continue;
|
|
262
|
+
const delta = choice.delta || {};
|
|
263
|
+
|
|
264
|
+
if (delta.content) {
|
|
265
|
+
text += delta.content;
|
|
266
|
+
onToken(delta.content);
|
|
267
|
+
}
|
|
268
|
+
const think = delta.reasoning_content || delta.reasoning;
|
|
269
|
+
if (think) {
|
|
270
|
+
reasoning += think;
|
|
271
|
+
if (typeof onReasoningToken === "function") onReasoningToken(think);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (const tc of delta.tool_calls || []) {
|
|
275
|
+
const i = Number.isFinite(tc.index) ? tc.index : calls.length;
|
|
276
|
+
if (!calls[i]) calls[i] = { id: "", type: "function", function: { name: "", arguments: "" } };
|
|
277
|
+
const slot = calls[i];
|
|
278
|
+
if (tc.id) slot.id = tc.id;
|
|
279
|
+
if (tc.type) slot.type = tc.type;
|
|
280
|
+
if (tc.function?.name) slot.function.name += tc.function.name;
|
|
281
|
+
if (tc.function?.arguments) slot.function.arguments += tc.function.arguments;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (choice.finish_reason) finishReason = choice.finish_reason;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const toolCalls = calls.filter((c) => c?.function?.name);
|
|
288
|
+
return {
|
|
289
|
+
text,
|
|
290
|
+
reasoning,
|
|
291
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
292
|
+
finish_reason: finishReason,
|
|
293
|
+
usage: {
|
|
294
|
+
input_tokens: usage?.prompt_tokens || 0,
|
|
295
|
+
output_tokens: usage?.completion_tokens || 0,
|
|
296
|
+
},
|
|
297
|
+
raw: null,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
@@ -24,34 +24,40 @@ export const ENGINE_PRESETS = {
|
|
|
24
24
|
default_model: "claude-sonnet-5",
|
|
25
25
|
api_key_env: "ANTHROPIC_API_KEY",
|
|
26
26
|
known_models: [
|
|
27
|
-
"claude-
|
|
27
|
+
"claude-fable-5",
|
|
28
|
+
"claude-opus-5",
|
|
28
29
|
"claude-sonnet-5",
|
|
29
30
|
"claude-haiku-4-5",
|
|
30
|
-
"claude-
|
|
31
|
+
"claude-opus-4-8",
|
|
32
|
+
"claude-sonnet-4-6",
|
|
31
33
|
],
|
|
32
34
|
},
|
|
33
35
|
openai: {
|
|
34
36
|
base_url: "https://api.openai.com/v1",
|
|
35
|
-
default_model: "gpt-5.
|
|
37
|
+
default_model: "gpt-5.6-luna",
|
|
36
38
|
api_key_env: "OPENAI_API_KEY",
|
|
37
39
|
known_models: [
|
|
40
|
+
"gpt-5.6-sol",
|
|
41
|
+
"gpt-5.6-terra",
|
|
42
|
+
"gpt-5.6-luna",
|
|
38
43
|
"gpt-5.5",
|
|
39
44
|
"gpt-5.4-mini",
|
|
40
45
|
"gpt-5.4-nano",
|
|
41
|
-
"gpt-5.1",
|
|
42
|
-
"gpt-4.1-mini",
|
|
43
46
|
],
|
|
44
47
|
},
|
|
45
48
|
gemini: {
|
|
46
49
|
base_url: "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
47
|
-
default_model: "gemini-
|
|
50
|
+
default_model: "gemini-3.7-flash",
|
|
48
51
|
api_key_env: "GEMINI_API_KEY",
|
|
49
52
|
known_models: [
|
|
53
|
+
"gemini-3.7-flash",
|
|
54
|
+
"gemini-3.6-flash",
|
|
50
55
|
"gemini-3.5-flash",
|
|
56
|
+
"gemini-3.5-flash-lite",
|
|
51
57
|
"gemini-3.1-pro-preview",
|
|
58
|
+
"gemini-3.1-flash-lite",
|
|
52
59
|
"gemini-2.5-pro",
|
|
53
60
|
"gemini-2.5-flash",
|
|
54
|
-
"gemini-2.5-flash-lite",
|
|
55
61
|
],
|
|
56
62
|
},
|
|
57
63
|
groq: {
|
|
@@ -75,9 +81,12 @@ export const ENGINE_PRESETS = {
|
|
|
75
81
|
known_models: [
|
|
76
82
|
"openrouter/auto",
|
|
77
83
|
"openrouter/free",
|
|
84
|
+
"anthropic/claude-opus-5",
|
|
78
85
|
"anthropic/claude-sonnet-5",
|
|
79
|
-
"openai/gpt-5.
|
|
80
|
-
"
|
|
86
|
+
"openai/gpt-5.6-sol",
|
|
87
|
+
"openai/gpt-5.6-terra",
|
|
88
|
+
"google/gemini-3.7-flash",
|
|
89
|
+
"qwen/qwen3.8-27b",
|
|
81
90
|
],
|
|
82
91
|
},
|
|
83
92
|
azure: {
|
|
@@ -92,6 +101,24 @@ export const ENGINE_PRESETS = {
|
|
|
92
101
|
api_key_env: "",
|
|
93
102
|
known_models: [], // dynamic — fetched live from the local Ollama daemon
|
|
94
103
|
},
|
|
104
|
+
// OpenCode Zen. The free-tier ids are listed first: they bill at zero.
|
|
105
|
+
// Free models need the opencode User-Agent (see zen.js ZEN_HEADERS) and
|
|
106
|
+
// accept api_key "public" when no personal key is set. Paid Claude/GPT/
|
|
107
|
+
// Gemini models on the same base URL need a real Zen key.
|
|
108
|
+
zen: {
|
|
109
|
+
base_url: "https://opencode.ai/zen/v1",
|
|
110
|
+
default_model: "big-pickle",
|
|
111
|
+
api_key_env: "OPENCODE_ZEN_API_KEY",
|
|
112
|
+
known_models: [
|
|
113
|
+
"big-pickle",
|
|
114
|
+
"nemotron-3-ultra-free",
|
|
115
|
+
"nemotron-3.5-lightning-free",
|
|
116
|
+
"deepseek-v4-flash-free",
|
|
117
|
+
"laguna-s-2.1-free",
|
|
118
|
+
"mimo-v2.5-free",
|
|
119
|
+
"hy3-free",
|
|
120
|
+
],
|
|
121
|
+
},
|
|
95
122
|
mock: { base_url: "", default_model: "mock", api_key_env: "", known_models: ["mock"] },
|
|
96
123
|
custom: { base_url: "", default_model: "", api_key_env: "", known_models: [] },
|
|
97
124
|
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// OpenCode Zen — an OpenAI-compatible gateway in front of many vendors'
|
|
2
|
+
// models, including a handful the provider serves at no cost.
|
|
3
|
+
//
|
|
4
|
+
// The free models are the reason this engine exists: with a Zen key they bill
|
|
5
|
+
// at zero, which makes them a real option for an agent that runs all day. The
|
|
6
|
+
// key is not optional, though. Zen also fronts paid Claude/GPT/Gemini models on
|
|
7
|
+
// the same base URL, and the same key is what tells the two apart — so it is
|
|
8
|
+
// required here like any other provider's.
|
|
9
|
+
import { createOpenAiCompatibleEngine } from "./openai-compatible.js";
|
|
10
|
+
import { matchesModelGlob, modelListFromConfig } from "./_globs.js";
|
|
11
|
+
|
|
12
|
+
// The free tier is gated on the caller naming itself as the opencode client,
|
|
13
|
+
// not only on the key: byte-for-byte the same request answers 429
|
|
14
|
+
// FreeUsageLimitError without this User-Agent and 200 with it. So it travels
|
|
15
|
+
// with every Zen call — chat, health and the model catalog. It is a pinned
|
|
16
|
+
// version string, and pins go stale; `engines.zen.headers` overrides it from
|
|
17
|
+
// config when Zen starts asking for a newer one.
|
|
18
|
+
//
|
|
19
|
+
// Pair with api_key "public" (or any Zen key). Missing UA → 429. Missing key
|
|
20
|
+
// with UA still works for free models when the adapter falls back to "public".
|
|
21
|
+
export const ZEN_HEADERS = { "user-agent": "opencode/1.18.18" };
|
|
22
|
+
|
|
23
|
+
// Which models demand their own thinking back on every subsequent request.
|
|
24
|
+
//
|
|
25
|
+
// DeepSeek's thinking mode treats `reasoning_content` as part of the assistant
|
|
26
|
+
// turn, not as a by-product of it: replay the turn without it and the upstream
|
|
27
|
+
// answers
|
|
28
|
+
// 400 [invalid_request_error] The `reasoning_content` in the thinking mode
|
|
29
|
+
// must be passed back to the API.
|
|
30
|
+
// The first turn always works, so this only bites once the loop has an
|
|
31
|
+
// assistant turn in history — i.e. the long, tool-heavy turns.
|
|
32
|
+
//
|
|
33
|
+
// Same mechanism as Gemini's thought signatures, and scoped the same way: a
|
|
34
|
+
// glob list, one entry per family. Scoped to v4+ ON PURPOSE — the older
|
|
35
|
+
// reasoners (deepseek-r1, deepseek-v3) do the exact opposite and 400 when
|
|
36
|
+
// `reasoning_content` appears in the context, so widening this to `deepseek-*`
|
|
37
|
+
// would trade one failure for another. v5 is a forward default: the
|
|
38
|
+
// requirement is a family trait, not a per-version quirk.
|
|
39
|
+
export const REASONING_REPLAY_MODELS = ["deepseek-v4*", "deepseek-v5*"];
|
|
40
|
+
|
|
41
|
+
// Per-install override, no code change required:
|
|
42
|
+
// engines.zen.reasoning_replay_models: ["deepseek-v4*", "some-new-reasoner*"]
|
|
43
|
+
export function modelReplaysReasoning(model, config = {}) {
|
|
44
|
+
return matchesModelGlob(
|
|
45
|
+
model,
|
|
46
|
+
modelListFromConfig(config?.reasoning_replay_models, REASONING_REPLAY_MODELS)
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Put `reasoning_content` back on assistant turns for the models that require
|
|
52
|
+
* it. `run-agent.js` stores it as `_reasoning` on the turn it came from; the
|
|
53
|
+
* underscore keeps it off the wire for every other model, since the shared
|
|
54
|
+
* serialiser copies only the fields it knows.
|
|
55
|
+
*
|
|
56
|
+
* When the field is missing there is nothing to do and nothing to invent — a
|
|
57
|
+
* turn inherited from another engine after a fallback rotation never had one.
|
|
58
|
+
* That case is caught by the retry classifier, which rotates off the model
|
|
59
|
+
* instead of failing the run.
|
|
60
|
+
*/
|
|
61
|
+
function replayReasoningContent(entry, source, { model, config }) {
|
|
62
|
+
if (entry.role !== "assistant") return;
|
|
63
|
+
if (!modelReplaysReasoning(model, config)) return;
|
|
64
|
+
const reasoning = source?._reasoning || source?.reasoning_content;
|
|
65
|
+
if (typeof reasoning === "string" && reasoning) entry.reasoning_content = reasoning;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Free-tier key. With ZEN_HEADERS the gateway answers 200 for big-pickle and
|
|
69
|
+
// the other *-free models; without the UA it answers 429 FreeUsageLimitError
|
|
70
|
+
// even when the key is valid. Prefer a real OPENCODE_ZEN_API_KEY / engines.zen
|
|
71
|
+
// api_key when present (paid models need one); fall back to "public" so agents
|
|
72
|
+
// are never left keyless on the free tier.
|
|
73
|
+
export const ZEN_PUBLIC_API_KEY = "public";
|
|
74
|
+
|
|
75
|
+
const base = createOpenAiCompatibleEngine({
|
|
76
|
+
id: "zen",
|
|
77
|
+
defaultBaseUrl: "https://opencode.ai/zen/v1",
|
|
78
|
+
apiKeyEnv: "OPENCODE_ZEN_API_KEY",
|
|
79
|
+
defaultFallbackModel: "zen:big-pickle",
|
|
80
|
+
extraHeaders: ZEN_HEADERS,
|
|
81
|
+
decorateMessage: replayReasoningContent,
|
|
82
|
+
defaultApiKey: ZEN_PUBLIC_API_KEY,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
/** The cheapest model that still proves a key works: free, one token. */
|
|
86
|
+
const PROBE_MODEL = "big-pickle";
|
|
87
|
+
|
|
88
|
+
// Zen serves its catalog to anyone — `GET /models` answers 200 with no key at
|
|
89
|
+
// all, and 200 again with a made-up one. The shared health check reads that as
|
|
90
|
+
// "connected", so a typo in the key would show a healthy provider that fails on
|
|
91
|
+
// the first real turn. Here the probe has to be a completion: one token against
|
|
92
|
+
// a free model, which costs nothing and is the only answer the gateway gives
|
|
93
|
+
// that actually depends on the key. Empty config still probes with "public".
|
|
94
|
+
export default {
|
|
95
|
+
...base,
|
|
96
|
+
|
|
97
|
+
async health(config = {}, { timeoutMs = 800 } = {}) {
|
|
98
|
+
const key = config?.api_key || process.env.OPENCODE_ZEN_API_KEY || ZEN_PUBLIC_API_KEY;
|
|
99
|
+
if (!key) return { ok: false, provider: "zen", reason: "no api_key" };
|
|
100
|
+
|
|
101
|
+
const url = `${String(config?.base_url || base.defaultBaseUrl).replace(/\/$/, "")}/chat/completions`;
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
const timer = setTimeout(() => controller.abort(), Math.max(timeoutMs, 4000));
|
|
104
|
+
try {
|
|
105
|
+
const res = await fetch(url, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: base.buildHeaders(config, {
|
|
108
|
+
"content-type": "application/json",
|
|
109
|
+
authorization: `Bearer ${key}`,
|
|
110
|
+
}),
|
|
111
|
+
body: JSON.stringify({
|
|
112
|
+
model: config?.model || PROBE_MODEL,
|
|
113
|
+
messages: [{ role: "user", content: "ping" }],
|
|
114
|
+
max_tokens: 1,
|
|
115
|
+
}),
|
|
116
|
+
signal: controller.signal,
|
|
117
|
+
});
|
|
118
|
+
if (res.ok) return { ok: true, provider: "zen", detail: url };
|
|
119
|
+
if (res.status === 401 || res.status === 403) {
|
|
120
|
+
return { ok: false, provider: "zen", reason: "api_key rechazada por Zen" };
|
|
121
|
+
}
|
|
122
|
+
// Anything else (a rate limit, a model that went away) says nothing about
|
|
123
|
+
// the key, so the chain is allowed to try — flagged, not blocked.
|
|
124
|
+
return { ok: true, provider: "zen", detail: url, soft: true, reason: `HTTP ${res.status}` };
|
|
125
|
+
} catch (e) {
|
|
126
|
+
return { ok: true, provider: "zen", detail: url, soft: true, reason: e.message };
|
|
127
|
+
} finally {
|
|
128
|
+
clearTimeout(timer);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// The in-process event bus: "this just happened", for anyone in the SAME
|
|
2
|
+
// process who cares.
|
|
3
|
+
//
|
|
4
|
+
// Why it exists: every channel writes its turns through one of two funnels in
|
|
5
|
+
// stores/messages.js. Until now nothing announced those writes, so a surface
|
|
6
|
+
// that wanted to show a conversation as it happens had no choice but to poll —
|
|
7
|
+
// the web inbox re-fetched every 15s and an open thread never re-fetched at
|
|
8
|
+
// all. A message that arrived on Telegram was invisible to a browser sitting
|
|
9
|
+
// on the same conversation until someone reloaded the page.
|
|
10
|
+
//
|
|
11
|
+
// Layering (rule 8): core EMITS and never listens. It knows nothing about
|
|
12
|
+
// WebSockets, clients or the daemon — the emitted event carries only facts core
|
|
13
|
+
// already has (which channel, which day file, which project root). The daemon
|
|
14
|
+
// subscribes in host/daemon/events-ws.js, enriches what it alone knows (a
|
|
15
|
+
// project root is an id there, not here) and fans it out. Moving the emit
|
|
16
|
+
// upward into the adapter was the alternative and it does not work: the writes
|
|
17
|
+
// happen deep inside the Telegram dispatch and the agent loop, not at a route.
|
|
18
|
+
//
|
|
19
|
+
// SCOPE, and its one real limit: an EventEmitter is per PROCESS. Every write
|
|
20
|
+
// that matters happens inside the daemon — it owns the HTTP API, the Telegram
|
|
21
|
+
// poller and the agent loop, and the CLI reaches it over HTTP — so the daemon's
|
|
22
|
+
// subscriber sees them all. A second process writing straight to the JSONL
|
|
23
|
+
// (a script, a test) is NOT announced. That is by design: the bus reports what
|
|
24
|
+
// this process did, it is not a filesystem watcher.
|
|
25
|
+
import { EventEmitter } from "node:events";
|
|
26
|
+
|
|
27
|
+
const bus = new EventEmitter();
|
|
28
|
+
// One listener per subscriber, but a daemon may hold several (the WS hub today,
|
|
29
|
+
// more later) and Node warns at 10. Raise it rather than leak a real warning.
|
|
30
|
+
bus.setMaxListeners(50);
|
|
31
|
+
|
|
32
|
+
export const MESSAGE_EVENT = "message";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A message was appended to the ledger.
|
|
36
|
+
*
|
|
37
|
+
* @param {object} event
|
|
38
|
+
* - scope "global" (cross-project channel) | "project"
|
|
39
|
+
* - channel telegram | web | desktop | …
|
|
40
|
+
* - thread the day file's id (YYYY-MM-DD) — what a thread is addressed by
|
|
41
|
+
* - project_id for a global write, whatever the record's meta claimed (may be null)
|
|
42
|
+
* - project_root for a project write, the storage path — the daemon maps it to an id
|
|
43
|
+
* - agent_slug the agent the turn belongs to, when the write named one
|
|
44
|
+
* - direction in | out
|
|
45
|
+
* - type user | agent | tool | system | compact
|
|
46
|
+
* - author display name of who wrote the row, when the writer had one
|
|
47
|
+
* - final true when this row is the closing message of a turn
|
|
48
|
+
* - streamed true when this row is a mid-turn Telegram chunk
|
|
49
|
+
* - ts the record's timestamp
|
|
50
|
+
*
|
|
51
|
+
* Never throws into the caller: an announcement failing must not fail the write
|
|
52
|
+
* that produced it. The ledger is the source of truth; this is a notification.
|
|
53
|
+
*/
|
|
54
|
+
export function emitMessageEvent(event) {
|
|
55
|
+
try {
|
|
56
|
+
bus.emit(MESSAGE_EVENT, event);
|
|
57
|
+
} catch {
|
|
58
|
+
/* a broken listener is the listener's problem, not the writer's */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Subscribe to message events. Returns the unsubscribe function. */
|
|
63
|
+
export function onMessageEvent(fn) {
|
|
64
|
+
bus.on(MESSAGE_EVENT, fn);
|
|
65
|
+
return () => bus.off(MESSAGE_EVENT, fn);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const ROUTINE_EVENT = "routine";
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A routine run started, moved a step, or ended.
|
|
72
|
+
*
|
|
73
|
+
* Same layering as the message event above: core emits the facts it already
|
|
74
|
+
* has (which project root, which routine, the run record) and never listens.
|
|
75
|
+
* The daemon subscribes in host/daemon/events-ws.js, maps the root to a project
|
|
76
|
+
* id and fans it out.
|
|
77
|
+
*
|
|
78
|
+
* Unlike a message event this one CARRIES the step, on purpose. A run's steps
|
|
79
|
+
* are not in the ledger while it runs — they are written once, at the end — so
|
|
80
|
+
* "re-fetch through the API you already use" has nothing to fetch. The live
|
|
81
|
+
* record IS the data, exactly like the turn frames in events-ws.js.
|
|
82
|
+
*
|
|
83
|
+
* @param {object} event
|
|
84
|
+
* - phase start | progress | end
|
|
85
|
+
* - project_root the project's storage path — the daemon maps it to an id
|
|
86
|
+
* - routine the routine's name
|
|
87
|
+
* - run the public run record (core/routines/active-runs.js)
|
|
88
|
+
*/
|
|
89
|
+
export function emitRoutineEvent(event) {
|
|
90
|
+
try {
|
|
91
|
+
bus.emit(ROUTINE_EVENT, event);
|
|
92
|
+
} catch {
|
|
93
|
+
/* a broken listener is the listener's problem, not the runner's */
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Subscribe to routine-run events. Returns the unsubscribe function. */
|
|
98
|
+
export function onRoutineEvent(fn) {
|
|
99
|
+
bus.on(ROUTINE_EVENT, fn);
|
|
100
|
+
return () => bus.off(ROUTINE_EVENT, fn);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Drop every listener. For tests, and for a clean daemon shutdown. */
|
|
104
|
+
export function resetEventBus() {
|
|
105
|
+
bus.removeAllListeners();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const MOBILITY_ALERT_EVENT = "mobility_alert";
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A proximity alert is going out, as the CARD rather than as a rendered line.
|
|
112
|
+
*
|
|
113
|
+
* This is the one event that carries its whole payload. The message events
|
|
114
|
+
* above are signals — "thread X moved, go re-fetch" — because a browser can
|
|
115
|
+
* ask. The phone cannot: it is on a mobile connection, possibly on a head unit,
|
|
116
|
+
* and the alert has to become a notification with four buttons within a second
|
|
117
|
+
* of the car passing the place. A round trip to fetch what the frame could have
|
|
118
|
+
* carried is a round trip that fails in a tunnel.
|
|
119
|
+
*
|
|
120
|
+
* It exists so the alert does NOT depend on Telegram. Proximity delivery used
|
|
121
|
+
* to be a Telegram send whose ledger row Android turned into a card, so a
|
|
122
|
+
* daemon with no Telegram plugin loaded — or a phone whose owner never wired
|
|
123
|
+
* one up — got no alert at all, on the surface where it matters most.
|
|
124
|
+
*
|
|
125
|
+
* @param {object} card core/mobility/geofence.js proximityCard() — emoji-free,
|
|
126
|
+
* four labelled actions, two Maps URIs.
|
|
127
|
+
*/
|
|
128
|
+
export function emitMobilityAlert(card) {
|
|
129
|
+
try {
|
|
130
|
+
bus.emit(MOBILITY_ALERT_EVENT, card);
|
|
131
|
+
} catch {
|
|
132
|
+
/* a broken listener must not fail the alert that produced it */
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Subscribe to proximity-alert cards. Returns the unsubscribe function. */
|
|
137
|
+
export function onMobilityAlert(fn) {
|
|
138
|
+
bus.on(MOBILITY_ALERT_EVENT, fn);
|
|
139
|
+
return () => bus.off(MOBILITY_ALERT_EVENT, fn);
|
|
140
|
+
}
|