@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
|
@@ -20,12 +20,11 @@
|
|
|
20
20
|
// },
|
|
21
21
|
// ...
|
|
22
22
|
// ],
|
|
23
|
-
// //
|
|
24
|
-
// "bot_token": "",
|
|
25
|
-
// "chat_id": "",
|
|
26
|
-
// "route_to_agent": "",
|
|
23
|
+
// "route_to_agent": "", // default for channels that omit it
|
|
27
24
|
// "poll_interval_ms": 1500
|
|
28
25
|
// }
|
|
26
|
+
// With channels[] empty, one implicit "default" channel is polled using
|
|
27
|
+
// BOT_TELEGRAM_TOKEN / TELEGRAM_CHAT_ID from the environment.
|
|
29
28
|
|
|
30
29
|
// This poller is intentionally thin: per-update logic lives in core/channels/
|
|
31
30
|
// telegram/ — dispatch (inbound routing), reply (the super-agent turn),
|
|
@@ -49,10 +48,56 @@ import { handleUpdate } from "#core/channels/telegram/dispatch.js";
|
|
|
49
48
|
import { handleCallbackQuery, startAskFlow, maybeConsumeAskTextAnswer } from "#core/channels/telegram/ask-callbacks.js";
|
|
50
49
|
import { sendMessage, sendChatAction, editMessageReplyMarkup, answerCallbackQuery, getUpdates } from "#core/channels/telegram/api.js";
|
|
51
50
|
import { sendPhoto, sendVoice, sendDocument, sendAudio } from "#core/channels/telegram/media.js";
|
|
51
|
+
import { archiveOutboundMedia, outboundMediaMeta } from "#core/stores/media-archive.js";
|
|
52
52
|
export { sendPhoto, sendVoice, sendDocument, sendAudio };
|
|
53
53
|
|
|
54
54
|
const nowIso = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Record a photo/voice/document/audio the agent just SENT, with the file on it.
|
|
58
|
+
*
|
|
59
|
+
* Two bugs lived in the four copies of this that used to be inline below.
|
|
60
|
+
*
|
|
61
|
+
* `type` was the media kind ("photo", "voice", …), and the ledger's type is a
|
|
62
|
+
* five-value enum (core/stores/messages.js: user | agent | tool | system |
|
|
63
|
+
* compact). `inferMessageType` dropped the unknown value in silence and fell
|
|
64
|
+
* through to "outbound ⇒ agent", so the row was written — just not as anything
|
|
65
|
+
* that said a file was involved. The kind belongs in meta, where
|
|
66
|
+
* `mediaFromMeta` reads it; `type` says who spoke.
|
|
67
|
+
*
|
|
68
|
+
* And the meta named no file at all, so a thread had nothing to render: the
|
|
69
|
+
* caption alone, or the bare placeholder `[photo]` when the send had none. The
|
|
70
|
+
* bytes are archived first (media-archive.js) because a path outside
|
|
71
|
+
* ~/.apx/media is one the media endpoint must refuse — the photo the user
|
|
72
|
+
* already has on Telegram would still read "attachment failed" on the web.
|
|
73
|
+
*/
|
|
74
|
+
function logSentMedia({ poller, chat_id, author, kind, body, source, filename, mime, duration }) {
|
|
75
|
+
const archived = archiveOutboundMedia(source, { filename, mime });
|
|
76
|
+
appendGlobalMessage({
|
|
77
|
+
channel: CHANNELS.TELEGRAM,
|
|
78
|
+
direction: "out",
|
|
79
|
+
type: "agent",
|
|
80
|
+
actor_id: SUPERAGENT_ACTOR_ID,
|
|
81
|
+
actor_kind: "superagent",
|
|
82
|
+
// Same attribution `send()` writes. Without it the row is an agent turn
|
|
83
|
+
// that names no agent, and the thread cannot say who sent the file.
|
|
84
|
+
agent_slug: SUPERAGENT_ACTOR_ID,
|
|
85
|
+
author,
|
|
86
|
+
body,
|
|
87
|
+
meta: {
|
|
88
|
+
chat_id: chat_id || resolveChatId(poller.channel),
|
|
89
|
+
tg_channel: poller.channel.name,
|
|
90
|
+
// A send by public URL has no bytes of ours to keep, so it gets no
|
|
91
|
+
// attachment — but the row should still say what went out. Names only:
|
|
92
|
+
// `mediaFromMeta` needs a path before it offers a card, so this can never
|
|
93
|
+
// put a player on screen with nothing behind it.
|
|
94
|
+
...(filename ? { file_name: filename } : {}),
|
|
95
|
+
...(mime ? { mime_type: mime } : {}),
|
|
96
|
+
...outboundMediaMeta(kind, archived, { duration }),
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
56
101
|
// ---------- per-channel poller ----------------------------------------------
|
|
57
102
|
|
|
58
103
|
class ChannelPoller {
|
|
@@ -64,9 +109,7 @@ class ChannelPoller {
|
|
|
64
109
|
this.plugins = plugins;
|
|
65
110
|
this.registries = registries;
|
|
66
111
|
this.state = loadState();
|
|
67
|
-
this.offset =
|
|
68
|
-
this.state.channels?.[channel.name]?.offset ??
|
|
69
|
-
(channel.name === "default" ? this.state._legacy_offset || 0 : 0);
|
|
112
|
+
this.offset = this.state.channels?.[channel.name]?.offset ?? 0;
|
|
70
113
|
this.polling = false;
|
|
71
114
|
this.lastError = null;
|
|
72
115
|
this.lastUpdateAt = null;
|
|
@@ -116,6 +159,12 @@ class ChannelPoller {
|
|
|
116
159
|
|
|
117
160
|
stop() {
|
|
118
161
|
this.polling = false;
|
|
162
|
+
// Kill in-flight turns so a restart doesn't leave a zombie run that still
|
|
163
|
+
// holds the chat (and so `apx daemon restart` actually interrupts Telegram).
|
|
164
|
+
for (const ctrl of this.activeRequests.values()) {
|
|
165
|
+
try { ctrl.abort(); } catch { /* already aborted */ }
|
|
166
|
+
}
|
|
167
|
+
this.activeRequests.clear();
|
|
119
168
|
}
|
|
120
169
|
|
|
121
170
|
async _loop() {
|
|
@@ -127,6 +176,9 @@ class ChannelPoller {
|
|
|
127
176
|
// A successful poll clears any stale error so status reflects recovery.
|
|
128
177
|
this.lastError = null;
|
|
129
178
|
for (const u of updates) {
|
|
179
|
+
// handleUpdate logs inbound + spawns the model turn; it must NOT
|
|
180
|
+
// await the super-agent. Awaiting the whole run froze getUpdates,
|
|
181
|
+
// so a newer message could never abort the one in flight.
|
|
130
182
|
await this._handleUpdate(u);
|
|
131
183
|
this.offset = u.update_id + 1;
|
|
132
184
|
this._saveOffset();
|
|
@@ -192,7 +244,12 @@ class ChannelPoller {
|
|
|
192
244
|
async _typing(chat_id) {
|
|
193
245
|
const token = resolveBotToken(this.channel);
|
|
194
246
|
if (!token || !chat_id) return;
|
|
195
|
-
try {
|
|
247
|
+
try {
|
|
248
|
+
await sendChatAction(token, chat_id);
|
|
249
|
+
} catch (e) {
|
|
250
|
+
// A silent typing failure looks exactly like a frozen agent to the owner.
|
|
251
|
+
this.log(`telegram[${this.channel.name}] sendChatAction failed: ${e.message}`);
|
|
252
|
+
}
|
|
196
253
|
}
|
|
197
254
|
|
|
198
255
|
// Returns a stop() fn; pings the typing indicator every 4s until called.
|
|
@@ -318,6 +375,7 @@ export default {
|
|
|
318
375
|
async send({ channel: channelName, chat_id, text, reply_markup, author = resolveAgentName(config), meta: extraMeta }) {
|
|
319
376
|
const p = pickPoller(pollers, channelName);
|
|
320
377
|
const result = await p._send({ chat_id, text, reply_markup });
|
|
378
|
+
// attribution-exempt: relay primitive — send() ships text the caller composed; a caller that spent tokens passes model/usage via `meta`.
|
|
321
379
|
appendGlobalMessage({
|
|
322
380
|
channel: CHANNELS.TELEGRAM,
|
|
323
381
|
direction: "out",
|
|
@@ -345,15 +403,10 @@ export default {
|
|
|
345
403
|
async sendPhoto({ channel: channelName, chat_id, photo, caption, parse_mode, author = resolveAgentName(config) }) {
|
|
346
404
|
const p = pickPoller(pollers, channelName);
|
|
347
405
|
const result = await p._sendPhoto({ chat_id, photo, caption, parse_mode });
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
direction: "out",
|
|
351
|
-
type: "photo",
|
|
352
|
-
actor_id: SUPERAGENT_ACTOR_ID,
|
|
353
|
-
actor_kind: "superagent",
|
|
354
|
-
author,
|
|
406
|
+
logSentMedia({
|
|
407
|
+
poller: p, chat_id, author, kind: "photo",
|
|
355
408
|
body: caption || "[photo]",
|
|
356
|
-
|
|
409
|
+
source: photo,
|
|
357
410
|
});
|
|
358
411
|
return result;
|
|
359
412
|
},
|
|
@@ -365,15 +418,10 @@ export default {
|
|
|
365
418
|
async sendVoice({ channel: channelName, chat_id, audio, caption, duration, author = resolveAgentName(config) }) {
|
|
366
419
|
const p = pickPoller(pollers, channelName);
|
|
367
420
|
const result = await p._sendVoice({ chat_id, audio, caption, duration });
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
direction: "out",
|
|
371
|
-
type: "voice",
|
|
372
|
-
actor_id: SUPERAGENT_ACTOR_ID,
|
|
373
|
-
actor_kind: "superagent",
|
|
374
|
-
author,
|
|
421
|
+
logSentMedia({
|
|
422
|
+
poller: p, chat_id, author, kind: "audio",
|
|
375
423
|
body: caption || "[voice]",
|
|
376
|
-
|
|
424
|
+
source: audio, mime: "audio/ogg", duration,
|
|
377
425
|
});
|
|
378
426
|
return result;
|
|
379
427
|
},
|
|
@@ -385,15 +433,10 @@ export default {
|
|
|
385
433
|
async sendDocument({ channel: channelName, chat_id, document, caption, filename, mime_type, author = resolveAgentName(config) }) {
|
|
386
434
|
const p = pickPoller(pollers, channelName);
|
|
387
435
|
const result = await p._sendDocument({ chat_id, document, caption, filename, mime_type });
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
direction: "out",
|
|
391
|
-
type: "document",
|
|
392
|
-
actor_id: SUPERAGENT_ACTOR_ID,
|
|
393
|
-
actor_kind: "superagent",
|
|
394
|
-
author,
|
|
436
|
+
logSentMedia({
|
|
437
|
+
poller: p, chat_id, author, kind: "document",
|
|
395
438
|
body: caption || `[document${filename ? " " + filename : ""}]`,
|
|
396
|
-
|
|
439
|
+
source: document, filename, mime: mime_type,
|
|
397
440
|
});
|
|
398
441
|
return result;
|
|
399
442
|
},
|
|
@@ -405,15 +448,10 @@ export default {
|
|
|
405
448
|
async sendAudio({ channel: channelName, chat_id, audio, caption, title, performer, author = resolveAgentName(config) }) {
|
|
406
449
|
const p = pickPoller(pollers, channelName);
|
|
407
450
|
const result = await p._sendAudio({ chat_id, audio, caption, title, performer });
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
direction: "out",
|
|
411
|
-
type: "audio",
|
|
412
|
-
actor_id: SUPERAGENT_ACTOR_ID,
|
|
413
|
-
actor_kind: "superagent",
|
|
414
|
-
author,
|
|
451
|
+
logSentMedia({
|
|
452
|
+
poller: p, chat_id, author, kind: "audio",
|
|
415
453
|
body: caption || title || "[audio]",
|
|
416
|
-
|
|
454
|
+
source: audio, filename: title ? `${title}.mp3` : undefined, mime: "audio/mpeg",
|
|
417
455
|
});
|
|
418
456
|
return result;
|
|
419
457
|
},
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Run a command on a pseudo-terminal and relay it over stdin/stdout.
|
|
3
|
+
|
|
4
|
+
The coding CLIs APX resumes — claude, codex, opencode — are terminal programs:
|
|
5
|
+
they draw an alt-screen UI, read keys in raw mode, and ask the tty how wide it
|
|
6
|
+
is. A plain pipe gives them none of that, so they either refuse to start or
|
|
7
|
+
render into nothing. Something has to allocate a real pty.
|
|
8
|
+
|
|
9
|
+
The two obvious candidates don't fit. macOS `script(1)` calls tcgetattr on its
|
|
10
|
+
own stdin and exits when that isn't a terminal, which is exactly our case (the
|
|
11
|
+
daemon feeds it a pipe). `node-pty` would work, but it is a native module, and
|
|
12
|
+
APX installs globally through npm onto machines that may have no compiler.
|
|
13
|
+
Python's pty module is already load-bearing for the voice stack, costs nothing
|
|
14
|
+
extra here, and is a few lines.
|
|
15
|
+
|
|
16
|
+
usage: pty-bridge.py <rows> <cols> <command> [args...]
|
|
17
|
+
|
|
18
|
+
Exits with the child's status, or 1 if it was killed by a signal. Closing our
|
|
19
|
+
stdin does not end the session — the child decides when it is done.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import fcntl
|
|
23
|
+
import os
|
|
24
|
+
import pty
|
|
25
|
+
import select
|
|
26
|
+
import struct
|
|
27
|
+
import sys
|
|
28
|
+
import termios
|
|
29
|
+
|
|
30
|
+
BUF = 65536
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def main():
|
|
34
|
+
if len(sys.argv) < 4:
|
|
35
|
+
sys.stderr.write("usage: pty-bridge.py <rows> <cols> <command> [args...]\n")
|
|
36
|
+
return 2
|
|
37
|
+
|
|
38
|
+
rows, cols = int(sys.argv[1]), int(sys.argv[2])
|
|
39
|
+
argv = sys.argv[3:]
|
|
40
|
+
|
|
41
|
+
pid, master = pty.fork()
|
|
42
|
+
if pid == 0:
|
|
43
|
+
# Child: becomes the CLI. execvp only returns on failure, and the
|
|
44
|
+
# message has to reach the pty (our stderr is the pty now) so the user
|
|
45
|
+
# sees "command not found" in the terminal instead of a blank panel.
|
|
46
|
+
try:
|
|
47
|
+
os.execvp(argv[0], argv)
|
|
48
|
+
except OSError as e:
|
|
49
|
+
sys.stderr.write("apx: cannot run %s: %s\r\n" % (argv[0], e))
|
|
50
|
+
sys.stderr.flush()
|
|
51
|
+
os._exit(127)
|
|
52
|
+
|
|
53
|
+
# Tell the child how big its window is before it draws anything.
|
|
54
|
+
try:
|
|
55
|
+
fcntl.ioctl(master, termios.TIOCSWINSZ, struct.pack("HHHH", rows, cols, 0, 0))
|
|
56
|
+
except OSError:
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
stdin_open = True
|
|
60
|
+
try:
|
|
61
|
+
while True:
|
|
62
|
+
watch = [master] + ([sys.stdin.fileno()] if stdin_open else [])
|
|
63
|
+
try:
|
|
64
|
+
ready, _, _ = select.select(watch, [], [])
|
|
65
|
+
except InterruptedError:
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
if master in ready:
|
|
69
|
+
try:
|
|
70
|
+
data = os.read(master, BUF)
|
|
71
|
+
except OSError:
|
|
72
|
+
break # child closed the pty — the session is over
|
|
73
|
+
if not data:
|
|
74
|
+
break
|
|
75
|
+
os.write(sys.stdout.fileno(), data)
|
|
76
|
+
|
|
77
|
+
if stdin_open and sys.stdin.fileno() in ready:
|
|
78
|
+
try:
|
|
79
|
+
data = os.read(sys.stdin.fileno(), BUF)
|
|
80
|
+
except OSError:
|
|
81
|
+
data = b""
|
|
82
|
+
if data:
|
|
83
|
+
os.write(master, data)
|
|
84
|
+
else:
|
|
85
|
+
# Our side hung up. Stop watching stdin, but keep relaying
|
|
86
|
+
# the child's output until it exits on its own.
|
|
87
|
+
stdin_open = False
|
|
88
|
+
finally:
|
|
89
|
+
try:
|
|
90
|
+
os.close(master)
|
|
91
|
+
except OSError:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
_, status = os.waitpid(pid, 0)
|
|
95
|
+
return os.WEXITSTATUS(status) if os.WIFEXITED(status) else 1
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
sys.exit(main())
|
package/src/host/daemon/smoke.js
CHANGED
|
@@ -15,8 +15,7 @@ import { readAgents } from "#core/apc/parser.js";
|
|
|
15
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
16
16
|
const __dirname = path.dirname(__filename);
|
|
17
17
|
|
|
18
|
-
//
|
|
19
|
-
// legacy src/daemon/smoke.js. Adjust the example-project lookup accordingly:
|
|
18
|
+
// Example-project lookup, relative to src/host/daemon/:
|
|
20
19
|
// ../../../examples/my-first-project ← repo-local examples (if any)
|
|
21
20
|
// ../../../../apc/examples/my-first-project ← sibling apc/ repo
|
|
22
21
|
const EXAMPLE_CANDIDATES = [
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// One WebSocket, one terminal, one session.
|
|
2
|
+
//
|
|
3
|
+
// The Sessions list can tell you a conversation exists and hand you the command
|
|
4
|
+
// that reopens it, but pasting that command somewhere else is a context switch
|
|
5
|
+
// away from the thing you were reading. This channel closes the gap: the daemon
|
|
6
|
+
// runs the session's own CLI on a real pty and relays it to a terminal in the
|
|
7
|
+
// web UI.
|
|
8
|
+
//
|
|
9
|
+
// Deliberately NOT a shell. The socket says which session to reopen — engine +
|
|
10
|
+
// id — and the daemon derives the command from the engine that owns it
|
|
11
|
+
// (see resumeArgvFor). A client cannot ask for an arbitrary command, so the
|
|
12
|
+
// channel's blast radius is "the CLIs APX already knows how to launch" rather
|
|
13
|
+
// than "anything on the machine". Whatever the user then types INTO claude or
|
|
14
|
+
// opencode is between them and that tool, exactly as in their own terminal.
|
|
15
|
+
//
|
|
16
|
+
// The wire protocol is the absence of one: every frame is bytes. Client frames
|
|
17
|
+
// are keystrokes for the pty; server frames are output to draw. Status lines
|
|
18
|
+
// from APX itself are written into the same stream, which is why they carry a
|
|
19
|
+
// [apx] prefix — there is no side channel to confuse them with.
|
|
20
|
+
import { spawn } from "node:child_process";
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import os from "node:os";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
25
|
+
import { apiPath } from "./api/prefix.js";
|
|
26
|
+
import { findSessionAcrossEngines, findSessionInEngine, resumeArgvFor } from "#core/sessions/index.js";
|
|
27
|
+
|
|
28
|
+
/** The terminal channel's upgrade path. Lives under /api like every other route. */
|
|
29
|
+
export const TERMINAL_WS_PATH = apiPath("/terminal/ws");
|
|
30
|
+
|
|
31
|
+
const BRIDGE = path.join(path.dirname(fileURLToPath(import.meta.url)), "pty-bridge.py");
|
|
32
|
+
|
|
33
|
+
/** Path-gate: is this upgrade for the terminal WS channel? */
|
|
34
|
+
export function isTerminalUpgradePath(url) {
|
|
35
|
+
let pathname = url || "";
|
|
36
|
+
try { pathname = new URL(url, "http://localhost").pathname; } catch { /* keep raw */ }
|
|
37
|
+
return pathname === TERMINAL_WS_PATH;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Terminal geometry, clamped: a bad number here misdraws the whole session. */
|
|
41
|
+
function readSize(params) {
|
|
42
|
+
const n = (key, dflt, min, max) => {
|
|
43
|
+
const v = Number(params.get(key));
|
|
44
|
+
return Number.isFinite(v) && v >= min && v <= max ? Math.round(v) : dflt;
|
|
45
|
+
};
|
|
46
|
+
return { rows: n("rows", 30, 4, 200), cols: n("cols", 100, 20, 500) };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve which command reopens the session named on the query string, and
|
|
51
|
+
* where to run it. Returns a `problem` instead of throwing — the socket is
|
|
52
|
+
* already open, so every failure has to be something we can print in it.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveTerminalTarget(params, { home = os.homedir() } = {}) {
|
|
55
|
+
const id = String(params.get("id") || "");
|
|
56
|
+
const engineParam = String(params.get("engine") || "");
|
|
57
|
+
if (!id) return { problem: "no session id given" };
|
|
58
|
+
|
|
59
|
+
let meta = null;
|
|
60
|
+
try {
|
|
61
|
+
meta = engineParam ? findSessionInEngine(engineParam, id) : (findSessionAcrossEngines(id)[0] || null);
|
|
62
|
+
} catch { meta = null; }
|
|
63
|
+
|
|
64
|
+
// An engine we were told about is enough to build the command: a session the
|
|
65
|
+
// engine hasn't flushed to disk yet still deserves to open.
|
|
66
|
+
const engine = engineParam || meta?.engine || null;
|
|
67
|
+
const argv = engine ? resumeArgvFor(engine, id) : null;
|
|
68
|
+
if (!argv) {
|
|
69
|
+
return { problem: engine ? `engine "${engine}" cannot reopen a session from the terminal` : "unknown session" };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Run where the conversation happened, so relative paths in it still mean
|
|
73
|
+
// what they meant. Engines that don't record a cwd land in the home dir.
|
|
74
|
+
const cwd = meta?.cwd && fs.existsSync(meta.cwd) ? meta.cwd : home;
|
|
75
|
+
return { argv, cwd, engine, id };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Attach a live terminal to `ws`. Spawns the pty bridge, relays bytes both
|
|
80
|
+
* ways, and makes sure neither side can outlive the other: closing the socket
|
|
81
|
+
* kills the CLI, and the CLI exiting closes the socket.
|
|
82
|
+
*/
|
|
83
|
+
export function startTerminalSession(ws, req, { python = "python3", home = os.homedir() } = {}) {
|
|
84
|
+
const say = (line) => { try { if (ws.readyState === 1) ws.send(Buffer.from(`\r\n[apx] ${line}\r\n`)); } catch {} };
|
|
85
|
+
|
|
86
|
+
let params;
|
|
87
|
+
try { params = new URL(req.url || "", "http://localhost").searchParams; } catch { params = new URLSearchParams(); }
|
|
88
|
+
|
|
89
|
+
const target = resolveTerminalTarget(params, { home });
|
|
90
|
+
if (target.problem) {
|
|
91
|
+
say(target.problem);
|
|
92
|
+
try { ws.close(); } catch {}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const { rows, cols } = readSize(params);
|
|
97
|
+
let child;
|
|
98
|
+
try {
|
|
99
|
+
child = spawn(python, [BRIDGE, String(rows), String(cols), ...target.argv], {
|
|
100
|
+
cwd: target.cwd,
|
|
101
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
102
|
+
});
|
|
103
|
+
} catch (e) {
|
|
104
|
+
say(`could not start a terminal: ${e.message}`);
|
|
105
|
+
try { ws.close(); } catch {}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
say(`${target.argv.join(" ")} (${target.cwd})`);
|
|
110
|
+
|
|
111
|
+
child.on("error", (e) => {
|
|
112
|
+
// python3 missing is the realistic case, and it is worth naming: without it
|
|
113
|
+
// there is no pty, and the panel would otherwise just sit there empty.
|
|
114
|
+
say(`terminal unavailable: ${e.message}`);
|
|
115
|
+
try { ws.close(); } catch {}
|
|
116
|
+
});
|
|
117
|
+
child.stdout.on("data", (chunk) => { try { if (ws.readyState === 1) ws.send(chunk); } catch {} });
|
|
118
|
+
child.stderr.on("data", (chunk) => { try { if (ws.readyState === 1) ws.send(chunk); } catch {} });
|
|
119
|
+
child.on("close", (code) => {
|
|
120
|
+
say(`session ended (exit ${code ?? "?"})`);
|
|
121
|
+
try { ws.close(); } catch {}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
ws.on("message", (raw) => {
|
|
125
|
+
try { child.stdin.write(Buffer.isBuffer(raw) ? raw : Buffer.from(String(raw))); } catch {}
|
|
126
|
+
});
|
|
127
|
+
const stop = () => { try { child.kill("SIGTERM"); } catch {} };
|
|
128
|
+
ws.on("close", stop);
|
|
129
|
+
ws.on("error", stop);
|
|
130
|
+
|
|
131
|
+
return child;
|
|
132
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Keeps a self-hosted voice engine's weights resident, the same way
|
|
2
|
+
// whisper-server.js does for transcription.
|
|
3
|
+
//
|
|
4
|
+
// The problem is not loading — the engine reports `load 0.0s` throughout. On a
|
|
5
|
+
// machine short on RAM macOS compresses the model's pages out from under a
|
|
6
|
+
// process that is merely idle, and the next generation pays to decompress
|
|
7
|
+
// several gigabytes before it can emit a single token. Measured on this M4 Pro
|
|
8
|
+
// with Qwen3-TTS: 1.5s after two minutes idle, 24.5s after nine.
|
|
9
|
+
//
|
|
10
|
+
// The desktop already asks for a warm-up when the microphone opens, which is
|
|
11
|
+
// the right idea and not enough on its own: an utterance lasts three seconds
|
|
12
|
+
// and the decompression takes twenty, so the reply's own synthesis queues
|
|
13
|
+
// behind a warm-up that is still running. Paying it on a timer instead means
|
|
14
|
+
// it is never on the path of a turn at all.
|
|
15
|
+
//
|
|
16
|
+
// Only ever pointed at an engine the user runs themselves — see isSelfHosted.
|
|
17
|
+
// A periodic ping at a metered cloud endpoint would quietly bill for silence.
|
|
18
|
+
import { warmupTts } from "#core/voice/tts.js";
|
|
19
|
+
import { resolveTtsCandidates } from "#core/voice/engines/index.js";
|
|
20
|
+
import { readConfig } from "#core/config/index.js";
|
|
21
|
+
|
|
22
|
+
// Nine minutes was cold and two and a half was fine, so the default sits well
|
|
23
|
+
// inside the window rather than close to its edge — the ping is cheap and a
|
|
24
|
+
// missed one costs twenty seconds.
|
|
25
|
+
export const DEFAULT_KEEP_WARM_MINUTES = 3;
|
|
26
|
+
|
|
27
|
+
let _timer = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whether an engine runs on this machine or the local network, and so costs
|
|
31
|
+
* nothing to poke. Anything reached over the public internet is somebody's
|
|
32
|
+
* metered API, whatever it is nominally called.
|
|
33
|
+
*/
|
|
34
|
+
export function isSelfHosted(baseUrl) {
|
|
35
|
+
let host;
|
|
36
|
+
try { host = new URL(String(baseUrl)).hostname.toLowerCase(); } catch { return false; }
|
|
37
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) return true;
|
|
38
|
+
if (host === "::1" || host === "0.0.0.0") return true;
|
|
39
|
+
if (/^127\./.test(host)) return true;
|
|
40
|
+
if (/^10\./.test(host)) return true;
|
|
41
|
+
if (/^192\.168\./.test(host)) return true;
|
|
42
|
+
if (/^172\.(1[6-9]|2\d|3[01])\./.test(host)) return true; // 172.16/12
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The engine a keep-warm ping would reach, or null when pinging it would be
|
|
48
|
+
* wrong: nothing configured, no warm-up support, or a remote/metered endpoint.
|
|
49
|
+
*/
|
|
50
|
+
export async function keepWarmTarget(globalConfig) {
|
|
51
|
+
const cfg = globalConfig || readConfig() || {};
|
|
52
|
+
const [first] = await resolveTtsCandidates({ globalConfig: cfg });
|
|
53
|
+
if (!first) return null;
|
|
54
|
+
if (typeof first.adapter?.warmup !== "function") return null;
|
|
55
|
+
if (!isSelfHosted(first.engineConfig?.base_url)) return null;
|
|
56
|
+
return first;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function startTtsKeepWarm(log = console.log) {
|
|
60
|
+
stopTtsKeepWarm();
|
|
61
|
+
try {
|
|
62
|
+
const cfg = readConfig() || {};
|
|
63
|
+
const ttsCfg = cfg?.voice?.tts || {};
|
|
64
|
+
if (ttsCfg.keep_warm === false) return;
|
|
65
|
+
const target = await keepWarmTarget(cfg);
|
|
66
|
+
if (!target) return;
|
|
67
|
+
|
|
68
|
+
const minutes = Number(ttsCfg.keep_warm_minutes ?? DEFAULT_KEEP_WARM_MINUTES) || DEFAULT_KEEP_WARM_MINUTES;
|
|
69
|
+
const everyMs = Math.max(60_000, minutes * 60_000);
|
|
70
|
+
const ping = () => {
|
|
71
|
+
warmupTts({ globalConfig: readConfig() || {} })
|
|
72
|
+
.then((r) => { if (!r.ok) log(`tts: keep-warm failed — ${r.error}`); })
|
|
73
|
+
.catch(() => {});
|
|
74
|
+
};
|
|
75
|
+
ping();
|
|
76
|
+
_timer = setInterval(ping, everyMs);
|
|
77
|
+
_timer.unref?.();
|
|
78
|
+
log(`tts: keep-warm every ${Math.round(everyMs / 60_000)} min (${target.provider})`);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
log(`tts: keep-warm not started — ${e?.message || e}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function stopTtsKeepWarm() {
|
|
85
|
+
if (_timer) clearInterval(_timer);
|
|
86
|
+
_timer = null;
|
|
87
|
+
}
|
|
@@ -3,6 +3,7 @@ import fetch from "node-fetch";
|
|
|
3
3
|
import { readIdentity, writeIdentity } from "#core/identity/index.js";
|
|
4
4
|
import { resolveProvider, getAdapter } from "#core/engines/index.js";
|
|
5
5
|
import { canNudge, recordNudge, nudgeFeedbackKeyboard } from "#core/nudge/index.js";
|
|
6
|
+
import { resolveChannels, resolveBotToken, resolveChatId } from "#core/channels/telegram/helpers.js";
|
|
6
7
|
|
|
7
8
|
const WAKEUP_COOLDOWN_MS = 30 * 60 * 1000; // 30 min
|
|
8
9
|
|
|
@@ -13,7 +14,7 @@ const ISO_TO_LANGUAGE = {
|
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
// Exported for unit testing.
|
|
16
|
-
// Priority: config.user.language (ISO 639-1) → identity.language
|
|
17
|
+
// Priority: config.user.language (ISO 639-1) → identity.language → system LANG env.
|
|
17
18
|
export function detectLanguage(identity, config) {
|
|
18
19
|
const cfgLang = config?.user?.language;
|
|
19
20
|
if (cfgLang) return ISO_TO_LANGUAGE[cfgLang.toLowerCase()] || cfgLang;
|
|
@@ -67,8 +68,12 @@ export async function triggerWakeup(config, log) {
|
|
|
67
68
|
const identity = readIdentity();
|
|
68
69
|
if (!identity) return;
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
if (!config?.telegram?.enabled) return;
|
|
72
|
+
const channel = resolveChannels(config)[0];
|
|
73
|
+
if (!channel) return;
|
|
74
|
+
const botToken = resolveBotToken(channel);
|
|
75
|
+
const chatId = resolveChatId(channel);
|
|
76
|
+
if (!botToken || !chatId) return;
|
|
72
77
|
|
|
73
78
|
// Cooldown check
|
|
74
79
|
if (identity.last_wakeup) {
|
|
@@ -91,10 +96,10 @@ export async function triggerWakeup(config, log) {
|
|
|
91
96
|
try {
|
|
92
97
|
const message = await generateMessage(identity, config);
|
|
93
98
|
const text = message || `${identity.agent_name} online. Ready.`;
|
|
94
|
-
await sendTelegram(
|
|
95
|
-
recordNudge(gate, { chat_id:
|
|
99
|
+
await sendTelegram(botToken, chatId, text, nudgeFeedbackKeyboard(gate.nudge_id));
|
|
100
|
+
recordNudge(gate, { chat_id: chatId, preview: text });
|
|
96
101
|
writeIdentity({ last_wakeup: new Date().toISOString() });
|
|
97
|
-
log?.(`wakeup: sent to Telegram chat ${
|
|
102
|
+
log?.(`wakeup: sent to Telegram chat ${chatId}`);
|
|
98
103
|
} catch (e) {
|
|
99
104
|
log?.(`wakeup: failed — ${e.message}`);
|
|
100
105
|
}
|
|
@@ -239,6 +239,50 @@ export async function warmupWhisper() {
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
// ── Keep-warm ───────────────────────────────────────────────────────────────
|
|
243
|
+
//
|
|
244
|
+
// Loading large-v3-turbo costs ~10s, and it is paid by whoever speaks first
|
|
245
|
+
// after the weights fall out of resident memory. That used to be the user:
|
|
246
|
+
// the desktop window warms on open, but `/warmup` holds the model lock while
|
|
247
|
+
// it loads, so an utterance started seconds later queued behind it — which is
|
|
248
|
+
// exactly the ~11s first-transcription stall in the logs, against ~0.9s for
|
|
249
|
+
// every one after it.
|
|
250
|
+
//
|
|
251
|
+
// The window can't own this, because it is closed most of the day and the model
|
|
252
|
+
// goes cold in between. The daemon can: it pings /warmup on a cycle shorter
|
|
253
|
+
// than the server's idle timeout, so the weights stay hot and the timer stays
|
|
254
|
+
// reset for as long as the daemon is up.
|
|
255
|
+
//
|
|
256
|
+
// Turn it off with transcription.local.keep_warm = false, and the idle watchdog
|
|
257
|
+
// takes over: the server exits after idle_minutes and gives the RAM back, at
|
|
258
|
+
// the cost of a cold first utterance.
|
|
259
|
+
let _keepWarmTimer = null;
|
|
260
|
+
|
|
261
|
+
export function startWhisperKeepWarm(log = console.log) {
|
|
262
|
+
stopWhisperKeepWarm();
|
|
263
|
+
return getConfig().then((cfg) => {
|
|
264
|
+
if (cfg.provider === "openai" || cfg.provider === "custom") return;
|
|
265
|
+
if (cfg.local.keep_warm === false) return;
|
|
266
|
+
const idleMin = Number(cfg.local.idle_minutes ?? DEFAULT_LOCAL.idle_minutes) || 10;
|
|
267
|
+
// Comfortably inside the idle window, and never a busy-loop on a tiny one.
|
|
268
|
+
const everyMs = Math.max(60_000, (idleMin - 2) * 60_000);
|
|
269
|
+
const ping = () => {
|
|
270
|
+
warmupWhisper()
|
|
271
|
+
.then((r) => { if (!r.ok) log(`whisper: keep-warm failed — ${r.error}`); })
|
|
272
|
+
.catch(() => {});
|
|
273
|
+
};
|
|
274
|
+
ping();
|
|
275
|
+
_keepWarmTimer = setInterval(ping, everyMs);
|
|
276
|
+
_keepWarmTimer.unref?.();
|
|
277
|
+
log(`whisper: keep-warm every ${Math.round(everyMs / 60_000)} min (idle timeout ${idleMin} min)`);
|
|
278
|
+
}).catch(() => {});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function stopWhisperKeepWarm() {
|
|
282
|
+
if (_keepWarmTimer) clearInterval(_keepWarmTimer);
|
|
283
|
+
_keepWarmTimer = null;
|
|
284
|
+
}
|
|
285
|
+
|
|
242
286
|
export async function shutdownWhisperServer() {
|
|
243
287
|
if (_serverProcess) {
|
|
244
288
|
try { _serverProcess.kill(); } catch {}
|