@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
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
// Routine output delivery — where a run's final text actually GOES.
|
|
2
|
+
//
|
|
3
|
+
// Until this file existed, a routine's answer was written to the ledger and
|
|
4
|
+
// nowhere else. Reaching a human was left to two workarounds, and both fail
|
|
5
|
+
// quietly:
|
|
6
|
+
//
|
|
7
|
+
// 1. a `apx telegram send "$APX_LLM_OUTPUT"` post_command — shell quoting,
|
|
8
|
+
// a 32k env truncation, and a sink that only exists if you remember it;
|
|
9
|
+
// 2. a paragraph in the prompt asking the model to call send_telegram. The
|
|
10
|
+
// bundled secretary profile still spells this out in full ("if you do not
|
|
11
|
+
// call the tool, you receive nothing at all") because there was no other
|
|
12
|
+
// way — and the one morning the model skips it, the symptom is silence.
|
|
13
|
+
//
|
|
14
|
+
// `deliver_to` makes delivery a property of the ROUTINE instead of a thing the
|
|
15
|
+
// prompt has to beg for: the runner takes the final text and hands it to one
|
|
16
|
+
// adapter per configured channel. Adding a channel is one entry in
|
|
17
|
+
// DELIVERY_ADAPTERS and nothing else — the resolution, the double-send guard
|
|
18
|
+
// and the run record are shared.
|
|
19
|
+
//
|
|
20
|
+
// A channel only belongs here when something actually READS what the adapter
|
|
21
|
+
// writes. `deck` is deliberately absent for that reason: writing to a surface
|
|
22
|
+
// nobody reads is a delivery that reports success and reaches no one.
|
|
23
|
+
import fs from "node:fs";
|
|
24
|
+
import { appendGlobalMessage } from "#core/stores/messages.js";
|
|
25
|
+
import { CHANNELS } from "#core/constants/channels.js";
|
|
26
|
+
import { SUPERAGENT_ACTOR_ID, resolveAgentName, resolveOwnerName } from "#core/identity/index.js";
|
|
27
|
+
import { TOOLS } from "#core/agent/tools/names.js";
|
|
28
|
+
import { canNudge, recordNudge } from "#core/nudge/index.js";
|
|
29
|
+
import { conversationPath, startConversation, appendTurn } from "#core/stores/conversations.js";
|
|
30
|
+
import { callEngine } from "#core/engines/index.js";
|
|
31
|
+
import { attachmentsMeta } from "#core/stores/media-archive.js";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A project agent's ONE persistent web chat with the owner. A routine run by a
|
|
35
|
+
* non-Roby agent posts its message here (a fixed thread reused across runs)
|
|
36
|
+
* instead of into the super-agent's dated web channel — so golf-coach keeps a
|
|
37
|
+
* single ongoing conversation you can reply to, the way Manu asked for. See
|
|
38
|
+
* `deliverToAgentWebChat`.
|
|
39
|
+
*/
|
|
40
|
+
export const AGENT_WEB_CHAT_ID = "web-main";
|
|
41
|
+
|
|
42
|
+
/** `deliver_to: ["profile"]` — take the channels from the active agent profile. */
|
|
43
|
+
export const PROFILE_DELIVERY = "profile";
|
|
44
|
+
|
|
45
|
+
/** `deliver_to: ["none"]` — say out loud that this routine delivers nowhere. */
|
|
46
|
+
export const NO_DELIVERY = "none";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The token a routine writes INSTEAD of a message when it decides it has
|
|
50
|
+
* nothing worth interrupting for.
|
|
51
|
+
*
|
|
52
|
+
* The watch and a2a-sweep prompts have promised this since they were written —
|
|
53
|
+
* "if you decide to stay quiet, say so in your reply and it goes nowhere" — and
|
|
54
|
+
* nothing in the code ever kept the promise. `routineOutputText` returns any
|
|
55
|
+
* non-empty reply, so the sentence the model wrote to explain ITSELF was
|
|
56
|
+
* delivered as if it were the news: "Me mantengo en silencio. La señal de
|
|
57
|
+
* inactividad de 8 días en flit es de severidad baja…" arrived on Manu's phone
|
|
58
|
+
* twice on 2026-08-27, and each one was charged against the interruption budget
|
|
59
|
+
* — two of that day's three unscheduled slots spent by a routine saying it had
|
|
60
|
+
* nothing to say. The budget that exists to protect real messages was being
|
|
61
|
+
* drained by abstentions.
|
|
62
|
+
*
|
|
63
|
+
* A decision is not a message, so it gets a token rather than a sentence. The
|
|
64
|
+
* reasoning after the marker still matters — it just belongs in the run log and
|
|
65
|
+
* the routine's memory, which is where the prompt already asks for it.
|
|
66
|
+
*/
|
|
67
|
+
export const ABSTAIN_MARKER = "NO_MESSAGE";
|
|
68
|
+
|
|
69
|
+
const ABSTAIN_RE = new RegExp(`^${ABSTAIN_MARKER}\\b[\\s:.,\u2013\u2014-]*(.*)$`, "i");
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Read a routine's reply as an abstention, or null if it is a real message.
|
|
73
|
+
*
|
|
74
|
+
* Deliberately marker-only: no prose detection. A regex hunting for "silencio"
|
|
75
|
+
* or "staying quiet" across two languages would both miss abstentions the model
|
|
76
|
+
* phrased differently AND swallow a genuine message that happens to mention
|
|
77
|
+
* keeping quiet — and a delivery that eats real news is worse than the bug it
|
|
78
|
+
* would be fixing. The marker has to be the first thing on the first line;
|
|
79
|
+
* anything after it is kept as the reason.
|
|
80
|
+
*
|
|
81
|
+
* @returns {{reason: string}|null}
|
|
82
|
+
*/
|
|
83
|
+
export function readAbstention(text) {
|
|
84
|
+
const raw = typeof text === "string" ? text.trim() : "";
|
|
85
|
+
if (!raw) return null;
|
|
86
|
+
const lines = raw.split(/\r?\n/);
|
|
87
|
+
// A model that emphasises or fences the marker still means the marker. NOT
|
|
88
|
+
// `_` — it is markdown emphasis everywhere except inside NO_MESSAGE itself.
|
|
89
|
+
const first = lines[0].replace(/[`*#>]/g, "").trim();
|
|
90
|
+
const m = ABSTAIN_RE.exec(first);
|
|
91
|
+
if (!m) return null;
|
|
92
|
+
return { reason: [m[1], ...lines.slice(1)].join("\n").trim() };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Write the text into a global channel ledger. That is the whole of "delivery"
|
|
97
|
+
* for a surface APX owns: appendGlobalMessage announces the row on the message
|
|
98
|
+
* bus, so a panel with the thread open sees it arrive, and one that is closed
|
|
99
|
+
* finds it in the thread list afterwards.
|
|
100
|
+
*
|
|
101
|
+
* `project_id` is what files the row under the right project (rowBelongsTo in
|
|
102
|
+
* core/stores/messages.js) — an unstamped row lands in the default workspace,
|
|
103
|
+
* which is not where the routine ran.
|
|
104
|
+
*/
|
|
105
|
+
/** The `media` a delivered row carries, shaped for the thread viewer.
|
|
106
|
+
*
|
|
107
|
+
* This used to name the skill's own file — `~/.apx/skills/<slug>/grip.png` —
|
|
108
|
+
* and the media endpoint serves nothing from outside ~/.apx/media, so every
|
|
109
|
+
* delivered image rendered as "attachment failed" no matter how correct the
|
|
110
|
+
* row was. `attachmentsMeta` archives the bytes first and records the copy. */
|
|
111
|
+
function mediaMeta(attachments) {
|
|
112
|
+
return attachmentsMeta(attachments);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Post a non-Roby agent's routine output into that agent's OWN persistent web
|
|
117
|
+
* chat — a single reused thread (`AGENT_WEB_CHAT_ID`) attributed to the agent,
|
|
118
|
+
* NOT the super-agent's dated web channel. This is the rule Manu set: "a routine
|
|
119
|
+
* run by an agent that is not Roby creates its own chat with me on the web
|
|
120
|
+
* channel" — golf-coach's tip lands in golf-coach's thread, and stays there to
|
|
121
|
+
* be answered, run after run.
|
|
122
|
+
*/
|
|
123
|
+
function deliverToAgentWebChat(ctx, { routine, text, attachments, agent, abstained }) {
|
|
124
|
+
const storagePath = ctx?.project?.storagePath;
|
|
125
|
+
if (!storagePath) throw new Error("no project storagePath for the agent web chat");
|
|
126
|
+
const author = agent.name || agent.slug;
|
|
127
|
+
const file = conversationPath(storagePath, agent.slug, AGENT_WEB_CHAT_ID);
|
|
128
|
+
if (!fs.existsSync(file)) {
|
|
129
|
+
startConversation({
|
|
130
|
+
storagePath,
|
|
131
|
+
agentSlug: agent.slug,
|
|
132
|
+
engine: agent.model || "",
|
|
133
|
+
channel: CHANNELS.WEB,
|
|
134
|
+
title: author,
|
|
135
|
+
id: AGENT_WEB_CHAT_ID,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// The thread the panel reopens. Left OPEN on purpose — this is a live chat the
|
|
139
|
+
// owner replies in, not a closed run record. appendTurn announces it on the
|
|
140
|
+
// message bus, so an open panel sees the tip arrive without a reload.
|
|
141
|
+
appendTurn({
|
|
142
|
+
filePath: file,
|
|
143
|
+
role: "assistant",
|
|
144
|
+
content: text,
|
|
145
|
+
// Carry model AND usage, the same attribution turn-record.js writes — a
|
|
146
|
+
// conversation reopened from the file renders "0 tok"/no model without it.
|
|
147
|
+
meta: {
|
|
148
|
+
agent: agent.slug,
|
|
149
|
+
agent_name: author,
|
|
150
|
+
...(agent.model ? { model: agent.model } : {}),
|
|
151
|
+
...(agent.usage ? { usage: agent.usage } : {}),
|
|
152
|
+
via: "routine_delivery",
|
|
153
|
+
routine: routine.name,
|
|
154
|
+
// The image belongs on the THREAD too, not only on the ledger row. This
|
|
155
|
+
// file is what the panel reopens; without it the tip came back as text
|
|
156
|
+
// and the picture it was built around was only in the inbox copy.
|
|
157
|
+
...mediaMeta(attachments),
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
// The cross-channel ledger row, under the AGENT (search, RAG, the inbox) —
|
|
161
|
+
// stamped web + agent, never the global super-agent web channel.
|
|
162
|
+
ctx?.project?.logMessage?.({
|
|
163
|
+
agent_slug: agent.slug,
|
|
164
|
+
channel: CHANNELS.WEB,
|
|
165
|
+
direction: "out",
|
|
166
|
+
type: "agent",
|
|
167
|
+
actor_id: agent.slug,
|
|
168
|
+
actor_kind: "agent",
|
|
169
|
+
author,
|
|
170
|
+
body: text,
|
|
171
|
+
meta: {
|
|
172
|
+
routine: routine.name,
|
|
173
|
+
routine_id: routine.id || "",
|
|
174
|
+
via: "routine_delivery",
|
|
175
|
+
conversation: AGENT_WEB_CHAT_ID,
|
|
176
|
+
...(abstained ? { abstained: true } : {}),
|
|
177
|
+
// The one-line headline the event feed hands the desktop mascot.
|
|
178
|
+
...(agent.notify ? { notify: agent.notify } : {}),
|
|
179
|
+
...(agent.model ? { model: agent.model } : {}),
|
|
180
|
+
...(agent.usage ? { usage: agent.usage } : {}),
|
|
181
|
+
...mediaMeta(attachments),
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
const n = (attachments || []).filter((a) => a && a.path).length;
|
|
185
|
+
return { note: `posted to ${agent.slug}'s own web chat${n ? ` (+${n} image${n > 1 ? "s" : ""})` : ""}` };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Who a delivered ledger row is FROM.
|
|
190
|
+
*
|
|
191
|
+
* On `web` this never came up — a non-Roby agent is routed to its own chat
|
|
192
|
+
* before it gets here — but `log` takes every agent's abstentions into one
|
|
193
|
+
* shared thread, and stamping them all as the super-agent would read as Roby
|
|
194
|
+
* having said things golf-coach said.
|
|
195
|
+
*/
|
|
196
|
+
function ledgerActor(ctx, agent) {
|
|
197
|
+
const slug = agent?.slug;
|
|
198
|
+
if (slug && slug !== SUPERAGENT_ACTOR_ID) {
|
|
199
|
+
return {
|
|
200
|
+
actor_id: slug,
|
|
201
|
+
actor_kind: "agent",
|
|
202
|
+
agent_slug: slug,
|
|
203
|
+
author: agent.name || slug,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
actor_id: SUPERAGENT_ACTOR_ID,
|
|
208
|
+
actor_kind: "superagent",
|
|
209
|
+
agent_slug: SUPERAGENT_ACTOR_ID,
|
|
210
|
+
author: resolveAgentName(ctx?.globalConfig || {}),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function ledgerAdapter(channel) {
|
|
215
|
+
return {
|
|
216
|
+
id: channel,
|
|
217
|
+
async deliver(ctx, { routine, text, attachments, agent, abstained }) {
|
|
218
|
+
// A non-Roby agent's routine goes to ITS own chat, not the super-agent's
|
|
219
|
+
// channel (the rule above). Only the super-agent's own routines — or a
|
|
220
|
+
// channel with no agent identity — write the global channel thread.
|
|
221
|
+
if (channel === CHANNELS.WEB && agent?.slug && agent.slug !== SUPERAGENT_ACTOR_ID) {
|
|
222
|
+
return deliverToAgentWebChat(ctx, { routine, text, attachments, agent, abstained });
|
|
223
|
+
}
|
|
224
|
+
appendGlobalMessage({
|
|
225
|
+
channel,
|
|
226
|
+
direction: "out",
|
|
227
|
+
type: "agent",
|
|
228
|
+
...ledgerActor(ctx, agent),
|
|
229
|
+
body: text,
|
|
230
|
+
meta: {
|
|
231
|
+
project_id: ctx?.project?.id ?? null,
|
|
232
|
+
routine: routine.name,
|
|
233
|
+
routine_id: routine.id || "",
|
|
234
|
+
via: "routine_delivery",
|
|
235
|
+
// A decision, not a message — so a reader (and any future UI) can
|
|
236
|
+
// fold it away instead of showing it as something Roby said.
|
|
237
|
+
...(abstained ? { abstained: true } : {}),
|
|
238
|
+
// Attribution when the caller carried it (the super-agent's own run —
|
|
239
|
+
// see runner.js). Without it the delivered row renders "0 tok"/no model.
|
|
240
|
+
...(agent?.model ? { model: agent.model } : {}),
|
|
241
|
+
...(agent?.usage ? { usage: agent.usage } : {}),
|
|
242
|
+
...mediaMeta(attachments),
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
const n = (attachments || []).filter((a) => a && a.path).length;
|
|
246
|
+
if (abstained) return { note: `noted in the ${channel} thread (stayed quiet)` };
|
|
247
|
+
return { note: `written to the ${channel} thread${n ? ` (+${n} image${n > 1 ? "s" : ""})` : ""}` };
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Roby tells Manu he has something waiting, on Telegram, in Roby's own words —
|
|
254
|
+
* the second half of Manu's rule ("leave a delivery so Roby notifies me"), done
|
|
255
|
+
* without the a2a-chat hack that used to clutter the inbox and leak the
|
|
256
|
+
* `super_agent` slug into the UI.
|
|
257
|
+
*
|
|
258
|
+
* The gate is checked FIRST, so a delivery the interruption budget would hold
|
|
259
|
+
* never spends a model turn composing a line nobody receives:
|
|
260
|
+
* • a priority/anchor delivery crosses the budget → Roby composes and sends now
|
|
261
|
+
* (this is what makes a priority tip arrive "de toque", not in 20 minutes);
|
|
262
|
+
* • an ordinary one is held when the budget says so — reported as `held` so the
|
|
263
|
+
* delivery queue shows it withheld rather than lost.
|
|
264
|
+
*
|
|
265
|
+
* Roby WRITES the line (never a canned string, per the model-authored rule); a
|
|
266
|
+
* model that is down falls back to a thin template so the owner is still told.
|
|
267
|
+
*
|
|
268
|
+
* @returns {{sent?:boolean, held?:boolean, skipped?:boolean, line?:string, reason?:string}}
|
|
269
|
+
*/
|
|
270
|
+
export async function notifyOwnerViaRoby(ctx, { routine, agent, text, notify, gate = null, severity = null }) {
|
|
271
|
+
const tg = ctx?.plugins?.get?.("telegram");
|
|
272
|
+
if (!tg?.send) return { skipped: true, reason: "telegram plugin not loaded" };
|
|
273
|
+
const globalConfig = ctx?.globalConfig || {};
|
|
274
|
+
|
|
275
|
+
// Gate first — no compose, no send, no tokens when the budget holds it.
|
|
276
|
+
if (gate) {
|
|
277
|
+
const decision = canNudge(
|
|
278
|
+
{
|
|
279
|
+
kind: `delivery:${agent.slug}`,
|
|
280
|
+
project_id: gate.project_id ?? null,
|
|
281
|
+
severity: gate.severity || "normal",
|
|
282
|
+
unsolicited: gate.unsolicited !== false,
|
|
283
|
+
scheduled: gate.scheduled === true,
|
|
284
|
+
channel: CHANNELS.TELEGRAM,
|
|
285
|
+
},
|
|
286
|
+
globalConfig,
|
|
287
|
+
);
|
|
288
|
+
if (!decision.allowed) return { held: true, reason: decision.reason };
|
|
289
|
+
const line = await composeRobyNotice({ agent, text, notify, globalConfig, severity });
|
|
290
|
+
await tg.send({ text: line, meta: { via: "delivery_notify", routine: routine.name, routine_id: routine.id || "", agent: agent.slug } });
|
|
291
|
+
recordNudge(decision, { preview: line });
|
|
292
|
+
return { sent: true, line, reason: decision.reason };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const line = await composeRobyNotice({ agent, text, notify, globalConfig, severity });
|
|
296
|
+
await tg.send({ text: line, meta: { via: "delivery_notify", routine: routine.name, routine_id: routine.id || "", agent: agent.slug } });
|
|
297
|
+
return { sent: true, line };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** The one Telegram line, written as Roby. Model-authored; a thin template only
|
|
301
|
+
* when the model is unavailable, so the owner is never left un-told. */
|
|
302
|
+
async function composeRobyNotice({ agent, text, notify, globalConfig, severity = null }) {
|
|
303
|
+
const robyName = resolveAgentName(globalConfig) || "Roby";
|
|
304
|
+
// The owner's name comes from identity.json, never from this file: a name
|
|
305
|
+
// written in here is the author's own, shipped into every other install.
|
|
306
|
+
const owner = resolveOwnerName();
|
|
307
|
+
const who = agent.name || agent.slug;
|
|
308
|
+
const model = globalConfig?.super_agent?.model;
|
|
309
|
+
// A `critical` relay is an alert, not a "you have a reply waiting" nudge — the
|
|
310
|
+
// line has to read as urgent so the owner acts on it now.
|
|
311
|
+
const urgent = severity === "critical";
|
|
312
|
+
if (model) {
|
|
313
|
+
try {
|
|
314
|
+
const r = await callEngine({
|
|
315
|
+
modelId: model,
|
|
316
|
+
system: urgent
|
|
317
|
+
? `You are ${robyName}, ${owner}'s personal assistant. The agent "${who}" just flagged something ` +
|
|
318
|
+
`CRITICAL that needs ${owner} now. Write ONE short line (max ~160 characters) to send ${owner} on ` +
|
|
319
|
+
`Telegram, in THEIR language, making clear it is urgent and from ${who}, and hinting what the ` +
|
|
320
|
+
`problem is. No preamble, no quotes — just the line.`
|
|
321
|
+
: `You are ${robyName}, ${owner}'s personal assistant. The agent "${who}" just left ${owner} a ` +
|
|
322
|
+
`message in its own chat and it is waiting for a reply. Write ONE short line (max ~160 characters) ` +
|
|
323
|
+
`to send ${owner} on Telegram, in THEIR language, telling them they have something to answer from ` +
|
|
324
|
+
`${who} and hinting what it is about. Warm and brief. No preamble, no quotes — just the line.`,
|
|
325
|
+
messages: [{ role: "user", content: `What ${who} left:\n\n${notify || text || ""}` }],
|
|
326
|
+
config: globalConfig,
|
|
327
|
+
});
|
|
328
|
+
const line = String(r.text || "").replace(/\s+/g, " ").trim();
|
|
329
|
+
if (line) return line;
|
|
330
|
+
} catch { /* fall through to the template floor */ }
|
|
331
|
+
}
|
|
332
|
+
if (urgent) return `⚠️ ${who} marcó algo crítico${notify ? `: ${notify}` : ""} — revisalo ahora en su chat.`;
|
|
333
|
+
return `${who} te dejó un mensaje${notify ? `: ${notify}` : ""} — respondé en su chat.`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export const DELIVERY_ADAPTERS = Object.freeze({
|
|
337
|
+
[CHANNELS.TELEGRAM]: {
|
|
338
|
+
id: CHANNELS.TELEGRAM,
|
|
339
|
+
// A channel that reaches a PHONE. What makes it valuable — it arrives
|
|
340
|
+
// whether or not you went looking — is also what makes it the wrong place
|
|
341
|
+
// for a routine's reasoning, so `abstentionChannels` routes around it.
|
|
342
|
+
push: true,
|
|
343
|
+
// The tool that would produce the same message from inside the loop. The
|
|
344
|
+
// runner suppresses it for the run, the way it already suppresses the tool
|
|
345
|
+
// an equivalent post_command would duplicate.
|
|
346
|
+
overlapTools: [TOOLS.SEND_TELEGRAM],
|
|
347
|
+
async deliver(ctx, { routine, text, gate, attachments }) {
|
|
348
|
+
const tg = ctx?.plugins?.get?.("telegram");
|
|
349
|
+
if (!tg?.send) throw new Error("telegram plugin not loaded");
|
|
350
|
+
|
|
351
|
+
// Send the queued images AFTER the text lands, each as its own photo. The
|
|
352
|
+
// text is the message that must always arrive, so a photo that fails to
|
|
353
|
+
// upload never costs the words. Skipped when the plugin can't send photos.
|
|
354
|
+
const sendPhotos = async () => {
|
|
355
|
+
const shots = (attachments || []).filter((a) => a && a.path);
|
|
356
|
+
if (!shots.length || typeof tg.sendPhoto !== "function") return 0;
|
|
357
|
+
let sent = 0;
|
|
358
|
+
for (const a of shots) {
|
|
359
|
+
try {
|
|
360
|
+
await tg.sendPhoto({ photo: a.path, caption: a.caption || "", author: "apx" });
|
|
361
|
+
sent++;
|
|
362
|
+
} catch { /* one bad image must not sink the rest */ }
|
|
363
|
+
}
|
|
364
|
+
return sent;
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// The interruption budget. Suppressing send_telegram for a delivering
|
|
368
|
+
// routine moved this push off the tool that used to gate it, so the gate
|
|
369
|
+
// has to live here or a watch would push every 20 minutes regardless of
|
|
370
|
+
// budget or quiet-hours. An anchor passes as `scheduled`; a blocker
|
|
371
|
+
// passes as `critical`; a solicited reply passes as `unsolicited: false`;
|
|
372
|
+
// an ordinary status/fyi is held when the budget says so. `gate: null`
|
|
373
|
+
// (a caller that hasn't opted in) delivers unconditionally, as before.
|
|
374
|
+
if (gate) {
|
|
375
|
+
const decision = canNudge(
|
|
376
|
+
{
|
|
377
|
+
kind: `routine:${routine.name}`,
|
|
378
|
+
project_id: gate.project_id ?? null,
|
|
379
|
+
severity: gate.severity || "normal",
|
|
380
|
+
unsolicited: gate.unsolicited !== false,
|
|
381
|
+
scheduled: gate.scheduled === true,
|
|
382
|
+
channel: CHANNELS.TELEGRAM,
|
|
383
|
+
},
|
|
384
|
+
ctx?.globalConfig || {},
|
|
385
|
+
);
|
|
386
|
+
if (!decision.allowed) return { held: true, reason: decision.reason };
|
|
387
|
+
await tg.send({
|
|
388
|
+
text,
|
|
389
|
+
meta: { routine: routine.name, routine_id: routine.id || "", via: "routine_delivery" },
|
|
390
|
+
});
|
|
391
|
+
const sent = await sendPhotos();
|
|
392
|
+
recordNudge(decision, { preview: text });
|
|
393
|
+
return { note: `sent to telegram (${decision.reason})${sent ? ` +${sent} photo${sent > 1 ? "s" : ""}` : ""}` };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
await tg.send({
|
|
397
|
+
text,
|
|
398
|
+
meta: { routine: routine.name, routine_id: routine.id || "", via: "routine_delivery" },
|
|
399
|
+
});
|
|
400
|
+
const sent = await sendPhotos();
|
|
401
|
+
return { note: `sent to telegram${sent ? ` +${sent} photo${sent > 1 ? "s" : ""}` : ""}` };
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
[CHANNELS.WEB]: ledgerAdapter(CHANNELS.WEB),
|
|
405
|
+
// Deliberately identical to `web` in mechanism and opposite in intent: the
|
|
406
|
+
// same ledger thread machinery pointed at a channel nobody is sitting in. A
|
|
407
|
+
// routine can name it in `deliver_to` to say "record this, do not deliver
|
|
408
|
+
// it"; abstentions go here whether they name it or not.
|
|
409
|
+
[CHANNELS.LOG]: ledgerAdapter(CHANNELS.LOG),
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
/** The channel ids `deliver_to` accepts, for help text and validation. */
|
|
413
|
+
export function deliveryChannelIds() {
|
|
414
|
+
return Object.keys(DELIVERY_ADAPTERS);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Where an ABSTENTION goes: `log`, always, whatever the routine delivers to.
|
|
419
|
+
*
|
|
420
|
+
* Never a push channel — the whole point is that the routine decided not to
|
|
421
|
+
* interrupt, and pushing "I decided not to interrupt you" is the interruption
|
|
422
|
+
* it just declined to make. And not nowhere either: Manu's rule when he found
|
|
423
|
+
* these on his phone was to leave them somewhere he can go and look at them.
|
|
424
|
+
*
|
|
425
|
+
* The first version of that rule read "somewhere quiet" as "the routine's own
|
|
426
|
+
* non-push channels, or `web`", and on a real install every one of them is
|
|
427
|
+
* `web` — so a watch running every two hours wrote twelve notes a day into the
|
|
428
|
+
* SAME dated thread as the conversation. Manu, 2026-08-31: "está bien la señal
|
|
429
|
+
* pero se ve muy seguido… ¿por qué no creamos canal log y que mande todo ahí?"
|
|
430
|
+
*
|
|
431
|
+
* Ignoring the routine's configured channels is the point, not a shortcut. A
|
|
432
|
+
* quiet channel that is also a chat is still the chat; the destination has to
|
|
433
|
+
* be decided by what the text IS (a decision, not a message), which is the same
|
|
434
|
+
* thing everywhere. Rows stay stamped `abstained`, so a reader can still tell a
|
|
435
|
+
* decision from something Roby said.
|
|
436
|
+
*/
|
|
437
|
+
export function abstentionChannels(_channels) {
|
|
438
|
+
return [CHANNELS.LOG];
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* A `deliver_to` value as a clean list, or null for "the routine said nothing".
|
|
443
|
+
*
|
|
444
|
+
* null and [] are DIFFERENT on purpose, and the difference is the one this repo
|
|
445
|
+
* has already been bitten by once (see allowed_tools in stores/routines.js):
|
|
446
|
+
* null means "no opinion, fall through to the default", [] means "deliver
|
|
447
|
+
* nowhere" and stops the fallthrough. So the store must persist an absent
|
|
448
|
+
* deliver_to as null and never as [].
|
|
449
|
+
*/
|
|
450
|
+
export function normalizeDeliverTo(value) {
|
|
451
|
+
if (typeof value === "string") {
|
|
452
|
+
const parts = value.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
453
|
+
return parts.length ? [...new Set(parts)] : [];
|
|
454
|
+
}
|
|
455
|
+
if (!Array.isArray(value)) return null;
|
|
456
|
+
return [...new Set(
|
|
457
|
+
value.filter((v) => typeof v === "string").map((s) => s.trim().toLowerCase()).filter(Boolean),
|
|
458
|
+
)];
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** The channels an agent profile wants routine output on, if it says. */
|
|
462
|
+
function profileChannels(profileConfig) {
|
|
463
|
+
const explicit = normalizeDeliverTo(profileConfig?.routine_delivery);
|
|
464
|
+
if (explicit && explicit.length) return explicit;
|
|
465
|
+
// Falling back to primary_channel is deliberate but NOT automatic: it only
|
|
466
|
+
// applies to a routine that asked for "profile". primary_channel answers
|
|
467
|
+
// "where do unrequested messages go", which is the same question for a
|
|
468
|
+
// routine that has opted into being delivered, and a different one for a
|
|
469
|
+
// routine that has not opted in at all.
|
|
470
|
+
const primary = normalizeDeliverTo(profileConfig?.primary_channel);
|
|
471
|
+
return primary && primary.length ? primary : [];
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Where this run's output goes.
|
|
476
|
+
*
|
|
477
|
+
* Order: the routine's own `deliver_to`, then the deployment default
|
|
478
|
+
* (`config.routines.deliver_to`), then nowhere. "Nowhere" is the default on
|
|
479
|
+
* purpose — every routine that existed before this feature keeps behaving
|
|
480
|
+
* exactly as it did, and delivery is something you turn on.
|
|
481
|
+
*
|
|
482
|
+
* @returns {{channels: string[], unknown: string[], source: string}}
|
|
483
|
+
* `unknown` carries names that match no adapter so the caller can SAY so
|
|
484
|
+
* rather than silently delivering to fewer places than asked.
|
|
485
|
+
*/
|
|
486
|
+
export function resolveDeliveryChannels(routine, { profileConfig, globalConfig } = {}) {
|
|
487
|
+
let source = "routine";
|
|
488
|
+
let want = normalizeDeliverTo(routine?.deliver_to);
|
|
489
|
+
if (want === null) {
|
|
490
|
+
source = "config";
|
|
491
|
+
want = normalizeDeliverTo(globalConfig?.routines?.deliver_to);
|
|
492
|
+
}
|
|
493
|
+
if (want === null) return { channels: [], unknown: [], source: "none" };
|
|
494
|
+
if (want.includes(NO_DELIVERY)) return { channels: [], unknown: [], source: "off" };
|
|
495
|
+
|
|
496
|
+
const expanded = [];
|
|
497
|
+
for (const id of want) {
|
|
498
|
+
if (id === PROFILE_DELIVERY) {
|
|
499
|
+
source = "profile";
|
|
500
|
+
expanded.push(...profileChannels(profileConfig));
|
|
501
|
+
} else {
|
|
502
|
+
expanded.push(id);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const seen = new Set();
|
|
506
|
+
const channels = [];
|
|
507
|
+
const unknown = [];
|
|
508
|
+
for (const id of expanded) {
|
|
509
|
+
if (seen.has(id)) continue;
|
|
510
|
+
seen.add(id);
|
|
511
|
+
if (DELIVERY_ADAPTERS[id]) channels.push(id);
|
|
512
|
+
else if (id !== NO_DELIVERY) unknown.push(id);
|
|
513
|
+
}
|
|
514
|
+
return { channels, unknown, source: channels.length || unknown.length ? source : "none" };
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Tools that would duplicate a configured delivery, to be suppressed for the
|
|
519
|
+
* run. Same contract as computeSuppressedTools for post_commands: the sink owns
|
|
520
|
+
* the message, so the loop must not send it too.
|
|
521
|
+
*/
|
|
522
|
+
export function deliverySuppressedTools(channels) {
|
|
523
|
+
const out = new Set();
|
|
524
|
+
for (const id of channels || []) {
|
|
525
|
+
for (const t of DELIVERY_ADAPTERS[id]?.overlapTools || []) out.add(t);
|
|
526
|
+
}
|
|
527
|
+
return [...out];
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* What this run PRODUCED, in the order the handlers put it: an agent's final
|
|
532
|
+
* text, a telegram routine's body, a shell routine's stdout.
|
|
533
|
+
*
|
|
534
|
+
* Delivery needs one answer to "what would a person read", and every handler
|
|
535
|
+
* spells it differently — reading `reply` only meant a `kind: shell` routine
|
|
536
|
+
* had output, a configured channel, and nothing to deliver.
|
|
537
|
+
*/
|
|
538
|
+
export function routineOutputText(result) {
|
|
539
|
+
for (const key of ["reply", "text", "stdout"]) {
|
|
540
|
+
const v = result?.[key];
|
|
541
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
542
|
+
}
|
|
543
|
+
return "";
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Channels whose message is ALREADY on its way, so delivering would send it
|
|
548
|
+
* twice. Three ways that happens, and all three are real:
|
|
549
|
+
*
|
|
550
|
+
* • `handler` — the run IS the send. A `kind: telegram` routine posts
|
|
551
|
+
* spec.text itself; delivering the same text after it is
|
|
552
|
+
* the same message twice.
|
|
553
|
+
* • `post_commands` — an `apx telegram send "$APX_LLM_OUTPUT"` sink. The user
|
|
554
|
+
* wired the pipe by hand; the pipe wins.
|
|
555
|
+
* • `agent` — the loop called the tool anyway. Suppression should
|
|
556
|
+
* have removed it, so this is the backstop, not the plan:
|
|
557
|
+
* a rename or an override that slips past suppression
|
|
558
|
+
* must not turn into a duplicate message.
|
|
559
|
+
*
|
|
560
|
+
* @returns {Array<{channel: string, reason: string}>}
|
|
561
|
+
*/
|
|
562
|
+
export function alreadyServedChannels({ routine, channels, postSinks, trace }) {
|
|
563
|
+
const calledOk = new Set(
|
|
564
|
+
(Array.isArray(trace) ? trace : [])
|
|
565
|
+
.filter((t) => t?.tool && !t?.result?.error)
|
|
566
|
+
.map((t) => t.tool),
|
|
567
|
+
);
|
|
568
|
+
const served = [];
|
|
569
|
+
for (const id of channels || []) {
|
|
570
|
+
const tools = DELIVERY_ADAPTERS[id]?.overlapTools || [];
|
|
571
|
+
if (id === CHANNELS.TELEGRAM && routine?.kind === CHANNELS.TELEGRAM) {
|
|
572
|
+
served.push({ channel: id, reason: "handler" });
|
|
573
|
+
} else if (tools.some((t) => (postSinks || []).includes(t))) {
|
|
574
|
+
served.push({ channel: id, reason: "post_commands" });
|
|
575
|
+
} else if (tools.some((t) => calledOk.has(t))) {
|
|
576
|
+
served.push({ channel: id, reason: "agent" });
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return served;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Deliver `text` to each channel. Never throws: one channel being down must not
|
|
584
|
+
* lose the other channels' delivery, and it must not turn a run that did its
|
|
585
|
+
* work into a run that reports as a crash. What it does instead is RECORD the
|
|
586
|
+
* failure per channel, so the caller can name it — the whole point of this
|
|
587
|
+
* feature is that a message nobody received stops looking like success.
|
|
588
|
+
*
|
|
589
|
+
* @returns {Array<{channel, status, note?, error?}>}
|
|
590
|
+
*/
|
|
591
|
+
export async function deliverRoutineOutput(ctx, { routine, channels, text, gate = null, attachments = [], agent = null, abstained = false }) {
|
|
592
|
+
const out = [];
|
|
593
|
+
for (const id of channels || []) {
|
|
594
|
+
const adapter = DELIVERY_ADAPTERS[id];
|
|
595
|
+
if (!adapter) {
|
|
596
|
+
out.push({ channel: id, status: "error", error: `unknown delivery channel: ${id}` });
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
try {
|
|
600
|
+
const r = await adapter.deliver(ctx, { routine, text, gate, attachments, agent, abstained });
|
|
601
|
+
// "held" is not "ok" and not "error": the interruption budget did its job.
|
|
602
|
+
// The caller must not treat it as a failed delivery — the message was
|
|
603
|
+
// deliberately withheld, and the message the model wrote survives in the
|
|
604
|
+
// run log / routine memory to fold into the next brief.
|
|
605
|
+
if (r?.held) out.push({ channel: id, status: "held", reason: r.reason });
|
|
606
|
+
else out.push({ channel: id, status: "ok", ...(r?.note ? { note: r.note } : {}) });
|
|
607
|
+
} catch (e) {
|
|
608
|
+
out.push({ channel: id, status: "error", error: e?.message || String(e) });
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return out;
|
|
612
|
+
}
|