@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
|
@@ -15,17 +15,45 @@ import os from "node:os";
|
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { callEngine } from "#core/engines/index.js";
|
|
17
17
|
import { runSuperAgent } from "#core/agent/super-agent.js";
|
|
18
|
-
import { computeSuppressedTools } from "#core/agent/index.js";
|
|
19
|
-
import {
|
|
18
|
+
import { runAgent, computeSuppressedTools } from "#core/agent/index.js";
|
|
19
|
+
import { TELEGRAM_TOOL_ITERS, ROUTINE_UNCAPPED_TOOL_ITERS } from "#core/agent/constants.js";
|
|
20
|
+
import { createToolSession, makeToolHandlers } from "#core/agent/tools/registry.js";
|
|
20
21
|
import { readAgents } from "#core/apc/parser.js";
|
|
22
|
+
import { scopeProjects } from "#core/apc/projects-helpers.js";
|
|
21
23
|
import { buildAgentSystem } from "#core/agent/build-agent-system.js";
|
|
24
|
+
import { resolveAgentModel } from "#core/agent/agent-model.js";
|
|
25
|
+
import { resolveAgentAllowedTools } from "#core/agent/agent-tools.js";
|
|
22
26
|
import { resolveAgentName, SUPERAGENT_ACTOR_ID } from "#core/identity/index.js";
|
|
27
|
+
import { recordAgentTurn } from "#core/stores/turn-record.js";
|
|
23
28
|
import { resolveArtifactRef, ARTIFACTS_SKIP_SIGNAL } from "#core/stores/artifacts.js";
|
|
24
29
|
import {
|
|
25
30
|
ensureRoutineMemory,
|
|
26
31
|
readRoutineMemoryForPrompt,
|
|
27
32
|
routineMemoryPath,
|
|
28
33
|
} from "#core/stores/routine-memory.js";
|
|
34
|
+
import { buildRoutineHeader, prependRoutineHeader } from "#core/routines/header.js";
|
|
35
|
+
import {
|
|
36
|
+
startRoutineRun,
|
|
37
|
+
setRoutineRunPhase,
|
|
38
|
+
startRoutineRunTool,
|
|
39
|
+
finishRoutineRunTool,
|
|
40
|
+
addRoutineRunText,
|
|
41
|
+
setRoutineRunConversation,
|
|
42
|
+
endRoutineRun,
|
|
43
|
+
} from "#core/routines/active-runs.js";
|
|
44
|
+
import {
|
|
45
|
+
resolveDeliveryChannels,
|
|
46
|
+
deliverySuppressedTools,
|
|
47
|
+
deliverRoutineOutput,
|
|
48
|
+
alreadyServedChannels,
|
|
49
|
+
routineOutputText,
|
|
50
|
+
notifyOwnerViaRoby,
|
|
51
|
+
readAbstention,
|
|
52
|
+
abstentionChannels,
|
|
53
|
+
ABSTAIN_MARKER,
|
|
54
|
+
AGENT_WEB_CHAT_ID,
|
|
55
|
+
} from "#core/routines/delivery.js";
|
|
56
|
+
import { recordDelivery, markDelivery, DELIVERY_STATUS } from "#core/stores/deliveries.js";
|
|
29
57
|
import { CHANNELS } from "#core/constants/channels.js";
|
|
30
58
|
import { detectSignals, formatSignals, peakSeverity, thresholdsFromConfig } from "#core/routines/signals.js";
|
|
31
59
|
import { readActiveProfile, effectiveProfileConfig } from "#core/profiles/store.js";
|
|
@@ -35,6 +63,7 @@ import {
|
|
|
35
63
|
computeNextRun,
|
|
36
64
|
} from "#core/stores/routines.js";
|
|
37
65
|
import { nowIso } from "#core/util/time.js";
|
|
66
|
+
import { loadAgentSkills, collectAgentSkillMedia } from "#core/agent/skills/agent-skills.js";
|
|
38
67
|
|
|
39
68
|
// --------------------- handlers ---------------------------------------------
|
|
40
69
|
|
|
@@ -51,43 +80,282 @@ async function handleHeartbeat(ctx, routine) {
|
|
|
51
80
|
body: message,
|
|
52
81
|
meta: { routine: routine.name },
|
|
53
82
|
});
|
|
54
|
-
|
|
83
|
+
// `text` is the run's output (routineOutputText): a heartbeat's product IS
|
|
84
|
+
// this line, and without naming it here a heartbeat with a delivery channel
|
|
85
|
+
// had something to say and delivered an empty string.
|
|
86
|
+
return { status: "ok", text: message, note: `logged to messages on channel '${channel}'` };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Is this routine "telegram-bound" — i.e. is its PRODUCT a Telegram message? The
|
|
90
|
+
// reliable signal is a `apx telegram …` post_command, which pipes the model's
|
|
91
|
+
// final text straight into Telegram and shows up here as a suppressed
|
|
92
|
+
// send_telegram (see tools-overlap.js). There the final turn literally becomes
|
|
93
|
+
// the message, so its dedicated Telegram ceiling is the right shape.
|
|
94
|
+
//
|
|
95
|
+
// Merely HAVING the send_telegram tool available does NOT count: it's a
|
|
96
|
+
// near-universal default (an empty allowed_tools falls back to the broad set),
|
|
97
|
+
// so keying on it would mark almost every routine telegram-bound and cap the
|
|
98
|
+
// exact background work this distinction exists to free. Magui filling a backlog
|
|
99
|
+
// might send a summary at the end, but her job is the backlog, not the message —
|
|
100
|
+
// she must finish first. So only the post_command sink marks telegram-bound.
|
|
101
|
+
export function routineReportsToTelegram({ autoSuppress, deliverTo }) {
|
|
102
|
+
// `deliver_to: ["telegram"]` is the same shape of sink, declared on the
|
|
103
|
+
// routine instead of in a shell string: the runner hands the final text to
|
|
104
|
+
// Telegram, so the final turn IS the message here too. No routine that
|
|
105
|
+
// predates deliver_to has one, so this widens the rule without moving any
|
|
106
|
+
// existing routine from one budget to the other.
|
|
107
|
+
if ((deliverTo || []).includes(CHANNELS.TELEGRAM)) return true;
|
|
108
|
+
return (autoSuppress || []).includes("send_telegram");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Tool-loop budget for a routine: the dedicated Telegram or non-Telegram
|
|
112
|
+
// runaway ceiling. Both honor a per-deployment config override.
|
|
113
|
+
export function routineToolIters(config, { telegramBound }) {
|
|
114
|
+
const sa = config?.super_agent || {};
|
|
115
|
+
const pick = (raw, fallback) => {
|
|
116
|
+
const n = Number(raw);
|
|
117
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
118
|
+
};
|
|
119
|
+
return telegramBound
|
|
120
|
+
? pick(sa.telegram_max_iters, TELEGRAM_TOOL_ITERS)
|
|
121
|
+
: pick(sa.routine_max_iters, ROUTINE_UNCAPPED_TOOL_ITERS);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Bridge the agent loop's progress events onto the open run record, so a panel
|
|
126
|
+
* can watch a run TAKE its steps. Until this existed the only trace of a run
|
|
127
|
+
* was written at the end, which meant a four-minute routine was four minutes of
|
|
128
|
+
* nothing followed by a wall of text.
|
|
129
|
+
*
|
|
130
|
+
* Returns null when no run is open (a direct handler call in a test), and the
|
|
131
|
+
* loop then pays one `if` per event instead of building a record nobody reads.
|
|
132
|
+
*/
|
|
133
|
+
function runProgressEvents(runId) {
|
|
134
|
+
if (!runId) return null;
|
|
135
|
+
return (ev) => {
|
|
136
|
+
if (ev?.type === "tool_start") {
|
|
137
|
+
startRoutineRunTool(runId, { traceId: ev.trace?.id, tool: ev.trace?.tool, args: ev.trace?.args });
|
|
138
|
+
} else if (ev?.type === "tool_result") {
|
|
139
|
+
finishRoutineRunTool(runId, { traceId: ev.trace?.id, tool: ev.trace?.tool, result: ev.trace?.result });
|
|
140
|
+
} else if (ev?.type === "assistant_text") {
|
|
141
|
+
addRoutineRunText(runId, ev.text);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
55
144
|
}
|
|
56
145
|
|
|
57
146
|
async function handleExecAgent(ctx, routine) {
|
|
58
|
-
const { project, globalConfig } = ctx;
|
|
147
|
+
const { project, globalConfig, projects, plugins, registries } = ctx;
|
|
59
148
|
const { agent: slug, prompt } = routine.spec;
|
|
60
149
|
if (!slug || !prompt) throw new Error("exec_agent: spec needs { agent, prompt }");
|
|
61
150
|
|
|
62
151
|
const agents = readAgents(project.path);
|
|
63
152
|
const agent = agents.find((a) => a.slug === slug);
|
|
64
153
|
if (!agent) throw new Error(`agent ${slug} not found`);
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
154
|
+
const agentName = agent.fields?.Name || agent.name || slug;
|
|
155
|
+
const config = project.config || globalConfig;
|
|
156
|
+
const model = await resolveAgentModel({ agent, config });
|
|
157
|
+
if (!model) throw new Error(`no model for agent ${slug} (no override, no router default)`);
|
|
158
|
+
|
|
159
|
+
// Explicit opt-out ONLY. `spec.no_tools: true` keeps the old one-shot text
|
|
160
|
+
// path (weather-style "write a sentence, post_commands send it").
|
|
161
|
+
//
|
|
162
|
+
// An empty `allowed_tools` used to count as that opt-out, and it is also what
|
|
163
|
+
// the store writes when nobody specified any — `apx routine add` without
|
|
164
|
+
// `--allowed-tools` produced `[]`. So every routine created the obvious way
|
|
165
|
+
// silently ran with NO tools: the agent could not read a file, reach Asana or
|
|
166
|
+
// write its ledger, and the "answer" was a model narrating work it never did.
|
|
167
|
+
// The two states are now distinct: `[]` means "no override, use the agent's
|
|
168
|
+
// declared tools", and refusing tools altogether is something you have to say.
|
|
169
|
+
// A non-Roby agent that delivers to web gets its OWN persistent web chat
|
|
170
|
+
// (web-main), written by the delivery adapter. Recording a fresh per-run
|
|
171
|
+
// routine conversation here too would give it a second, noisier thread — so
|
|
172
|
+
// for that case keep only the ledger audit and let the web chat be the thread.
|
|
173
|
+
const isProjectAgent = slug !== SUPERAGENT_ACTOR_ID;
|
|
174
|
+
const deliversToWeb = (ctx.deliverTo || []).includes(CHANNELS.WEB);
|
|
175
|
+
const ledgerOnly = isProjectAgent && deliversToWeb;
|
|
176
|
+
|
|
177
|
+
const noTools = routine.spec?.no_tools === true;
|
|
178
|
+
// Only a NON-EMPTY list overrides the agent's own declared tools.
|
|
179
|
+
const toolOverride =
|
|
180
|
+
Array.isArray(routine.allowed_tools) && routine.allowed_tools.length > 0
|
|
181
|
+
? routine.allowed_tools
|
|
182
|
+
: undefined;
|
|
183
|
+
|
|
184
|
+
const system = buildAgentSystem(project, agent, {
|
|
185
|
+
invocation: "routine",
|
|
186
|
+
routine: routine.name,
|
|
187
|
+
channel: CHANNELS.ROUTINE,
|
|
188
|
+
globalConfig: config,
|
|
77
189
|
});
|
|
78
190
|
|
|
79
|
-
|
|
191
|
+
// Images the agent's skills declare: the pool attach_media / view_media
|
|
192
|
+
// validate against, and the sink a queued attachment lands in for delivery.
|
|
193
|
+
// Same skills the system prompt above rendered, so the manifest the model
|
|
194
|
+
// sees and the ids it can attach never drift.
|
|
195
|
+
const attachableMedia = collectAgentSkillMedia(loadAgentSkills(project, agent));
|
|
196
|
+
const mediaSink = [];
|
|
197
|
+
|
|
198
|
+
let text = "";
|
|
199
|
+
let trace = [];
|
|
200
|
+
let usage = null;
|
|
201
|
+
let allowedTools = [];
|
|
202
|
+
// What ANSWERED, which is not always what was resolved: the router can fall
|
|
203
|
+
// back mid-run, and the record should name the model that produced the reply.
|
|
204
|
+
let answeredOn = model;
|
|
205
|
+
|
|
206
|
+
if (noTools) {
|
|
207
|
+
const result = await callEngine({
|
|
208
|
+
modelId: model,
|
|
209
|
+
system,
|
|
210
|
+
messages: [{ role: "user", content: prompt }],
|
|
211
|
+
config,
|
|
212
|
+
});
|
|
213
|
+
text = result.text || "";
|
|
214
|
+
usage = result.usage;
|
|
215
|
+
answeredOn = result.model || model;
|
|
216
|
+
} else {
|
|
217
|
+
const cfg = structuredClone(config || {});
|
|
218
|
+
cfg.super_agent = {
|
|
219
|
+
...(config?.super_agent || {}),
|
|
220
|
+
// A scheduled run has no human to click Confirm. Default to total so
|
|
221
|
+
// a Magui-style cron can edit its ledger; pin permission_mode on the
|
|
222
|
+
// routine itself to lock it down.
|
|
223
|
+
permission_mode: routine.permission_mode || "total",
|
|
224
|
+
...(toolOverride ? { allowed_tools: toolOverride } : {}),
|
|
225
|
+
};
|
|
226
|
+
const autoSuppress = computeSuppressedTools(routine.post_commands);
|
|
227
|
+
const explicitSuppress = Array.isArray(routine.spec?.suppress_tools)
|
|
228
|
+
? routine.spec.suppress_tools.filter((s) => typeof s === "string")
|
|
229
|
+
: [];
|
|
230
|
+
// A configured delivery owns the message the same way a post_command sink
|
|
231
|
+
// does — leaving send_telegram in the loop next to `deliver_to: telegram`
|
|
232
|
+
// is the two-messages bug of spec/done/01 with a different sink.
|
|
233
|
+
const deliverSuppress = deliverySuppressedTools(ctx.deliverTo);
|
|
234
|
+
const suppressTools = [...new Set([...autoSuppress, ...explicitSuppress, ...deliverSuppress])];
|
|
235
|
+
allowedTools = resolveAgentAllowedTools(agent, { override: toolOverride });
|
|
236
|
+
const toolSession = createToolSession(CHANNELS.ROUTINE, { allowedTools });
|
|
237
|
+
// A routine that reports to Telegram keeps the bounded chat budget; one that
|
|
238
|
+
// does background work nobody watches runs to completion (Magui's backlog
|
|
239
|
+
// refill was being cut off at ~23 steps by the Telegram budget).
|
|
240
|
+
const telegramBound = routineReportsToTelegram({ autoSuppress, deliverTo: ctx.deliverTo });
|
|
241
|
+
const maxIters = routineToolIters(cfg, { telegramBound });
|
|
242
|
+
|
|
243
|
+
const result = await runAgent({
|
|
244
|
+
globalConfig: cfg,
|
|
245
|
+
system,
|
|
246
|
+
prompt,
|
|
247
|
+
overrideModel: model,
|
|
248
|
+
toolSchemas: toolSession.initialSchemas,
|
|
249
|
+
makeToolHandlers,
|
|
250
|
+
toolHandlerCtx: {
|
|
251
|
+
// Scoped to the routine's OWN project, so an unqualified path is read
|
|
252
|
+
// against it instead of against the default project. See scopeProjects.
|
|
253
|
+
projects: scopeProjects(projects, project.id),
|
|
254
|
+
plugins,
|
|
255
|
+
registries,
|
|
256
|
+
globalConfig: cfg,
|
|
257
|
+
channel: CHANNELS.ROUTINE,
|
|
258
|
+
channelMeta: {
|
|
259
|
+
routineName: routine.name,
|
|
260
|
+
routineId: routine.id || "",
|
|
261
|
+
projectPath: project.path,
|
|
262
|
+
// Who is speaking, for any tool that signs what it writes
|
|
263
|
+
// (comment_task). run-turn.js sets the same key.
|
|
264
|
+
agentSlug: slug,
|
|
265
|
+
},
|
|
266
|
+
toolSession,
|
|
267
|
+
// Skill media plumbing for attach_media / view_media (see above).
|
|
268
|
+
attachableMedia,
|
|
269
|
+
mediaSink,
|
|
270
|
+
requestConfirmation: null,
|
|
271
|
+
},
|
|
272
|
+
agentName: slug,
|
|
273
|
+
onEvent: runProgressEvents(ctx.runId),
|
|
274
|
+
suppressTools: suppressTools.length > 0 ? suppressTools : null,
|
|
275
|
+
maxIters,
|
|
276
|
+
// A routine has to both act and report, and 2048 was tight enough that a
|
|
277
|
+
// run which wrote its output before filing it hit the cap mid-item. The
|
|
278
|
+
// loop now recovers from that (see wasTruncated), but the headroom keeps
|
|
279
|
+
// it from being the normal case.
|
|
280
|
+
maxTokens: 4096,
|
|
281
|
+
});
|
|
282
|
+
text = result.text || "";
|
|
283
|
+
trace = Array.isArray(result.trace) ? result.trace : [];
|
|
284
|
+
usage = result.usage;
|
|
285
|
+
answeredOn = result.model || model;
|
|
286
|
+
|
|
287
|
+
const blocked = blockedForPermission(trace);
|
|
288
|
+
if (blocked.length) {
|
|
289
|
+
const { conversationId } = recordRoutineTurn(project, routine, {
|
|
290
|
+
slug, model: answeredOn, prompt, reply: text, trace, usage, conversation: !ledgerOnly,
|
|
291
|
+
});
|
|
292
|
+
return {
|
|
293
|
+
status: "error",
|
|
294
|
+
error:
|
|
295
|
+
`blocked waiting for a confirmation nobody can give: ${blocked.join(", ")}. ` +
|
|
296
|
+
`A scheduled run has no one to approve a dangerous tool — either allow it on ` +
|
|
297
|
+
`this routine (allowed_tools) or use a tool that does not need approval.`,
|
|
298
|
+
blocked_tools: blocked,
|
|
299
|
+
reply: text,
|
|
300
|
+
trace,
|
|
301
|
+
agent_slug: slug,
|
|
302
|
+
agent_name: agentName,
|
|
303
|
+
model: answeredOn,
|
|
304
|
+
conversation_id: conversationId || (ledgerOnly ? AGENT_WEB_CHAT_ID : null),
|
|
305
|
+
allowed_tools: allowedTools,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const { conversationId } = recordRoutineTurn(project, routine, {
|
|
311
|
+
slug, model: answeredOn, prompt, reply: text, trace, usage, conversation: !ledgerOnly,
|
|
312
|
+
});
|
|
313
|
+
setRoutineRunConversation(ctx.runId, { conversationId, agentSlug: slug });
|
|
314
|
+
return {
|
|
315
|
+
status: "ok",
|
|
316
|
+
reply: text,
|
|
317
|
+
trace,
|
|
80
318
|
agent_slug: slug,
|
|
319
|
+
agent_name: agentName,
|
|
320
|
+
model: answeredOn,
|
|
321
|
+
conversation_id: conversationId || (ledgerOnly ? AGENT_WEB_CHAT_ID : null),
|
|
322
|
+
allowed_tools: allowedTools,
|
|
323
|
+
usage,
|
|
324
|
+
// Images the agent queued with attach_media, for the delivery adapters.
|
|
325
|
+
...(mediaSink.length ? { attachments: mediaSink } : {}),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* File this run the way a message to you is filed: one conversation to reopen,
|
|
331
|
+
* one set of ledger rows to search — written by the SAME recorder every other
|
|
332
|
+
* channel uses, so a run records which agent answered, on which model, and what
|
|
333
|
+
* it cost. It used to have its own pair of writers here, and the file half of
|
|
334
|
+
* that pair wrote text and nothing else: the thread opened as "0 tok", no
|
|
335
|
+
* model, no actor. A scheduled run is the case where the stored record is the
|
|
336
|
+
* only record there will ever be — nobody watched it stream.
|
|
337
|
+
*/
|
|
338
|
+
function recordRoutineTurn(project, routine, { slug, model, prompt, reply, trace, usage, conversation = true }) {
|
|
339
|
+
return recordAgentTurn({
|
|
340
|
+
project,
|
|
341
|
+
agentSlug: slug,
|
|
81
342
|
channel: CHANNELS.ROUTINE,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
343
|
+
title: routine.name,
|
|
344
|
+
model,
|
|
345
|
+
prompt,
|
|
346
|
+
// False for a delivering project agent: its user-facing thread is its own
|
|
347
|
+
// persistent web chat, not a per-run routine conversation. The ledger audit
|
|
348
|
+
// (usage/model/trace) is still written either way.
|
|
349
|
+
conversation,
|
|
350
|
+
// The thread says whose clock woke it; the ledger row keeps the bare prompt
|
|
351
|
+
// (it already carries `meta.routine`, and search should match the words the
|
|
352
|
+
// routine actually asked).
|
|
353
|
+
filedPrompt: `[routine: ${routine.name}]\n\n${prompt}`,
|
|
354
|
+
reply,
|
|
355
|
+
trace,
|
|
356
|
+
usage,
|
|
357
|
+
scope: { routine: routine.name },
|
|
89
358
|
});
|
|
90
|
-
return { status: "ok", reply: result.text };
|
|
91
359
|
}
|
|
92
360
|
|
|
93
361
|
async function handleSuperAgent(ctx, routine, extraChannelMeta = {}) {
|
|
@@ -99,7 +367,9 @@ async function handleSuperAgent(ctx, routine, extraChannelMeta = {}) {
|
|
|
99
367
|
cfg.super_agent = {
|
|
100
368
|
...(globalConfig?.super_agent || {}),
|
|
101
369
|
...(routine.permission_mode ? { permission_mode: routine.permission_mode } : {}),
|
|
102
|
-
|
|
370
|
+
// Same rule as exec_agent: an empty list is the store's default, not a
|
|
371
|
+
// deliberate "no tools".
|
|
372
|
+
...(routine.allowed_tools?.length ? { allowed_tools: routine.allowed_tools } : {}),
|
|
103
373
|
};
|
|
104
374
|
|
|
105
375
|
// Auto-suppress tools whose output would duplicate post_commands.
|
|
@@ -110,7 +380,18 @@ async function handleSuperAgent(ctx, routine, extraChannelMeta = {}) {
|
|
|
110
380
|
const explicitSuppress = Array.isArray(routine.spec?.suppress_tools)
|
|
111
381
|
? routine.spec.suppress_tools.filter((s) => typeof s === "string")
|
|
112
382
|
: [];
|
|
113
|
-
|
|
383
|
+
// Same rule as exec_agent: a channel the runner is going to deliver to loses
|
|
384
|
+
// its in-loop twin, so the run produces one message and not two.
|
|
385
|
+
const deliverSuppress = deliverySuppressedTools(ctx.deliverTo);
|
|
386
|
+
const suppressTools = [...new Set([...autoSuppress, ...explicitSuppress, ...deliverSuppress])];
|
|
387
|
+
|
|
388
|
+
// Same rule as exec_agent: only a `apx telegram …` post_command makes the run
|
|
389
|
+
// telegram-bound (bounded chat budget). A super_agent report that sends via the
|
|
390
|
+
// send_telegram tool — like the secretary open/close — is work that should run
|
|
391
|
+
// to completion, which also lifts it off runSuperAgent's low chit-chat default
|
|
392
|
+
// of MAX_TOOL_ITERS.
|
|
393
|
+
const telegramBound = routineReportsToTelegram({ autoSuppress, deliverTo: ctx.deliverTo });
|
|
394
|
+
const maxIters = routineToolIters(cfg, { telegramBound });
|
|
114
395
|
|
|
115
396
|
const result = await runSuperAgent({
|
|
116
397
|
globalConfig: cfg,
|
|
@@ -143,6 +424,8 @@ async function handleSuperAgent(ctx, routine, extraChannelMeta = {}) {
|
|
|
143
424
|
...extraChannelMeta,
|
|
144
425
|
},
|
|
145
426
|
suppressTools: suppressTools.length > 0 ? suppressTools : null,
|
|
427
|
+
maxIters,
|
|
428
|
+
onEvent: runProgressEvents(ctx.runId),
|
|
146
429
|
});
|
|
147
430
|
|
|
148
431
|
// A tool that needed a human in a run with no human is a DEAD END, not a
|
|
@@ -151,21 +434,23 @@ async function handleSuperAgent(ctx, routine, extraChannelMeta = {}) {
|
|
|
151
434
|
// and it took twenty-one shell commands to work out why. Name it.
|
|
152
435
|
const blocked = blockedForPermission(result.trace);
|
|
153
436
|
|
|
154
|
-
|
|
437
|
+
// Same recorder as exec_agent and as a message typed by hand — the prompt, the
|
|
438
|
+
// steps, and a reply stamped with model and usage. The super-agent's chats
|
|
439
|
+
// live in the ledger rather than in per-agent conversation files, so only that
|
|
440
|
+
// half is written; what goes into it is the same shape either way.
|
|
441
|
+
recordAgentTurn({
|
|
442
|
+
project,
|
|
443
|
+
agentSlug: SUPERAGENT_ACTOR_ID,
|
|
444
|
+
agentName: result.name || resolveAgentName(globalConfig),
|
|
445
|
+
actorKind: "superagent",
|
|
446
|
+
conversation: false,
|
|
155
447
|
channel: CHANNELS.ROUTINE,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
meta: {
|
|
163
|
-
routine: routine.name,
|
|
164
|
-
tool_trace: result.trace,
|
|
165
|
-
// Compact form too: the viewer renders this without parsing the trace.
|
|
166
|
-
...(summarizeToolTrace(result.trace) ? { tool_summary: summarizeToolTrace(result.trace) } : {}),
|
|
167
|
-
usage: result.usage,
|
|
168
|
-
},
|
|
448
|
+
model: result.model,
|
|
449
|
+
prompt,
|
|
450
|
+
reply: result.text || "",
|
|
451
|
+
trace: result.trace,
|
|
452
|
+
usage: result.usage,
|
|
453
|
+
scope: { routine: routine.name },
|
|
169
454
|
});
|
|
170
455
|
if (blocked.length) {
|
|
171
456
|
return {
|
|
@@ -198,6 +483,21 @@ export function blockedForPermission(trace) {
|
|
|
198
483
|
return [...names];
|
|
199
484
|
}
|
|
200
485
|
|
|
486
|
+
/**
|
|
487
|
+
* The active agent profile's settings, or `{}`. Read by the watcher (for its
|
|
488
|
+
* thresholds) and by delivery (for `deliver_to: ["profile"]`), and swallowing
|
|
489
|
+
* the error is the point: a profile that fails to load must not take down a
|
|
490
|
+
* run that has nothing to do with it.
|
|
491
|
+
*/
|
|
492
|
+
function activeProfileConfig(globalConfig) {
|
|
493
|
+
try {
|
|
494
|
+
const active = readActiveProfile(globalConfig);
|
|
495
|
+
return active ? (effectiveProfileConfig(active, globalConfig) || {}) : {};
|
|
496
|
+
} catch {
|
|
497
|
+
return {};
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
201
501
|
async function handleTelegram(ctx, routine) {
|
|
202
502
|
const { plugins } = ctx;
|
|
203
503
|
const tg = plugins?.get("telegram");
|
|
@@ -211,9 +511,10 @@ async function handleTelegram(ctx, routine) {
|
|
|
211
511
|
|
|
212
512
|
function handleShell(ctx, routine) {
|
|
213
513
|
return new Promise((resolve, reject) => {
|
|
214
|
-
const { command, timeout_ms = 30_000 } = routine.spec;
|
|
215
|
-
|
|
216
|
-
|
|
514
|
+
const { command, cmd, timeout_ms = 30_000 } = routine.spec || {};
|
|
515
|
+
const finalCmd = command || cmd;
|
|
516
|
+
if (!finalCmd) return reject(new Error("shell routine needs spec.command (or spec.cmd)"));
|
|
517
|
+
const child = spawn("sh", ["-c", finalCmd], {
|
|
217
518
|
cwd: ctx.project.path,
|
|
218
519
|
stdio: ["ignore", "pipe", "pipe"],
|
|
219
520
|
});
|
|
@@ -253,11 +554,7 @@ async function handleWatch(ctx, routine) {
|
|
|
253
554
|
// Thresholds come from the active profile — "stale after 7 days" is a
|
|
254
555
|
// judgement about how someone works, not a constant — with the routine able
|
|
255
556
|
// to override for its own narrower purpose.
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
const active = readActiveProfile(globalConfig);
|
|
259
|
-
if (active) profileConfig = effectiveProfileConfig(active, globalConfig) || {};
|
|
260
|
-
} catch { /* a broken profile must not take the watcher down */ }
|
|
557
|
+
const profileConfig = activeProfileConfig(globalConfig);
|
|
261
558
|
|
|
262
559
|
const entries = [];
|
|
263
560
|
for (const entry of projects?.list?.() || []) {
|
|
@@ -275,6 +572,9 @@ async function handleWatch(ctx, routine) {
|
|
|
275
572
|
...thresholdsFromConfig(profileConfig),
|
|
276
573
|
...(thresholds && typeof thresholds === "object" ? thresholds : {}),
|
|
277
574
|
types: Array.isArray(types) ? types : [],
|
|
575
|
+
// So the a2a detector surfaces each message once — everything that arrived
|
|
576
|
+
// since this watch last ran, and nothing it already considered.
|
|
577
|
+
a2a_since: routine.last_run_at || routine.last_run || "",
|
|
278
578
|
});
|
|
279
579
|
|
|
280
580
|
if (!signals.length) {
|
|
@@ -297,7 +597,8 @@ async function handleWatch(ctx, routine) {
|
|
|
297
597
|
`${formatSignals(signals)}\n\n` +
|
|
298
598
|
"These were found deterministically — they are facts, not guesses. Your job is " +
|
|
299
599
|
"judgement: decide whether any of it is worth interrupting for right now, and if " +
|
|
300
|
-
"so say the one thing that matters. Staying quiet is a valid outcome
|
|
600
|
+
"so say the one thing that matters. Staying quiet is a valid outcome — reply with " +
|
|
601
|
+
`${ABSTAIN_MARKER} on the first line when you choose it, and your reasoning after.`,
|
|
301
602
|
},
|
|
302
603
|
};
|
|
303
604
|
|
|
@@ -314,6 +615,10 @@ async function handleWatch(ctx, routine) {
|
|
|
314
615
|
signals: signals.length,
|
|
315
616
|
peak_severity: peakSeverity(signals),
|
|
316
617
|
signal_types: [...new Set(signals.map((s) => s.type))],
|
|
618
|
+
// Solicited when the owner explicitly asked to be told about one of these
|
|
619
|
+
// (an a2a message tagged solicited). It crosses the interruption budget the
|
|
620
|
+
// same way a reply does — see the gate in core/routines/delivery.js.
|
|
621
|
+
solicited: signals.some((s) => s.payload?.solicited === true),
|
|
317
622
|
...(skipped.length ? { skipped } : {}),
|
|
318
623
|
};
|
|
319
624
|
}
|
|
@@ -352,6 +657,46 @@ function injectPreOutput(prompt, preOutput) {
|
|
|
352
657
|
return prompt.replace(/\{\{pre_output\}\}/g, preOutput || "");
|
|
353
658
|
}
|
|
354
659
|
|
|
660
|
+
// The one-line notification a delivery hands the mascot / push feed: short
|
|
661
|
+
// enough for a bubble, in the message's own language. Two tiers, so tokens are
|
|
662
|
+
// only spent when they buy something:
|
|
663
|
+
// • a short message IS its own headline — take its first meaningful line, free;
|
|
664
|
+
// • a long one gets a real ≤100-char summary from the model ("you have a golf
|
|
665
|
+
// trivia to answer" rather than the first 100 chars of a wall of text).
|
|
666
|
+
const NOTIFY_MAX_CHARS = 100;
|
|
667
|
+
const NOTIFY_SUMMARY_OVER = 280;
|
|
668
|
+
|
|
669
|
+
function firstLineNotify(text) {
|
|
670
|
+
const line = String(text || "")
|
|
671
|
+
.split("\n").map((s) => s.trim()).find(Boolean) || "";
|
|
672
|
+
// Strip the loudest markdown so the bubble reads as prose, keep emoji.
|
|
673
|
+
return line.replace(/[*_`#>]+/g, "").replace(/\s+/g, " ").trim().slice(0, NOTIFY_MAX_CHARS);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
export async function buildDeliveryNotify({ text, model, config }) {
|
|
677
|
+
const clean = String(text || "").trim();
|
|
678
|
+
if (!clean) return "";
|
|
679
|
+
if (clean.length <= NOTIFY_SUMMARY_OVER) return firstLineNotify(clean);
|
|
680
|
+
// Long → a dedicated tiny summary. Kept model-authored (never a canned string)
|
|
681
|
+
// and in the message's own language; a model that is down falls back to the
|
|
682
|
+
// truncated headline rather than going silent.
|
|
683
|
+
try {
|
|
684
|
+
const r = await callEngine({
|
|
685
|
+
modelId: model,
|
|
686
|
+
system:
|
|
687
|
+
"You write ONE ultra-short notification line (max 100 characters) that tells the user " +
|
|
688
|
+
"what a message is about, so they know whether to open it. Write in the SAME language as " +
|
|
689
|
+
"the message. No quotes, no preamble, no trailing period — just the line.",
|
|
690
|
+
messages: [{ role: "user", content: `Message:\n\n${clean}\n\nNotification line (≤100 chars):` }],
|
|
691
|
+
config,
|
|
692
|
+
});
|
|
693
|
+
const line = String(r.text || "").replace(/\s+/g, " ").trim().slice(0, NOTIFY_MAX_CHARS);
|
|
694
|
+
return line || firstLineNotify(clean);
|
|
695
|
+
} catch {
|
|
696
|
+
return firstLineNotify(clean);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
355
700
|
/** Decide whether to skip the LLM call based on skip_prompt_on + pre results. */
|
|
356
701
|
function shouldSkipPrompt(routine, preExitCode, preStdout) {
|
|
357
702
|
const mode = routine.skip_prompt_on || "signal";
|
|
@@ -379,12 +724,49 @@ function shouldSkipPrompt(routine, preExitCode, preStdout) {
|
|
|
379
724
|
* @returns {object} { status, last_run_at, next_run_at, ...handler-result }
|
|
380
725
|
*/
|
|
381
726
|
export async function runRoutineNow(ctx, routine) {
|
|
727
|
+
// The run record is opened HERE, around everything, so a routine is visible
|
|
728
|
+
// as running from its first millisecond — including while a pre_command is
|
|
729
|
+
// still shelling out, which is where the old panel showed nothing at all.
|
|
730
|
+
const run = startRoutineRun({
|
|
731
|
+
projectRoot: ctx.project?.storagePath || os.homedir(),
|
|
732
|
+
routine,
|
|
733
|
+
trigger: ctx.trigger || "manual",
|
|
734
|
+
});
|
|
735
|
+
let out = null;
|
|
736
|
+
let failure = null;
|
|
737
|
+
try {
|
|
738
|
+
out = await runRoutinePipeline({ ...ctx, runId: run.id }, routine);
|
|
739
|
+
return out;
|
|
740
|
+
} catch (e) {
|
|
741
|
+
failure = e;
|
|
742
|
+
throw e;
|
|
743
|
+
} finally {
|
|
744
|
+
endRoutineRun(run.id, {
|
|
745
|
+
status: failure || out?.status === "error" ? "error" : "ok",
|
|
746
|
+
error: failure?.message || out?.error || null,
|
|
747
|
+
conversationId: out?.conversation_id || null,
|
|
748
|
+
agentSlug: out?.agent_slug || null,
|
|
749
|
+
text: out?.reply || out?.text || null,
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
async function runRoutinePipeline(ctx, routine) {
|
|
382
755
|
const cwd = ctx.project?.path || os.homedir();
|
|
383
756
|
const storagePath = ctx.project?.storagePath || os.homedir();
|
|
384
757
|
|
|
385
758
|
const hasPreCmds = Array.isArray(routine.pre_commands) && routine.pre_commands.length > 0;
|
|
386
759
|
const hasPostCmds = Array.isArray(routine.post_commands) && routine.post_commands.length > 0;
|
|
387
760
|
|
|
761
|
+
// Where this run's output goes, resolved ONCE and before the handler runs —
|
|
762
|
+
// the handlers need it too, because a channel the runner is going to deliver
|
|
763
|
+
// to has its in-loop twin (send_telegram) suppressed for the run.
|
|
764
|
+
const delivery = resolveDeliveryChannels(routine, {
|
|
765
|
+
profileConfig: activeProfileConfig(ctx.globalConfig),
|
|
766
|
+
globalConfig: ctx.project?.config || ctx.globalConfig,
|
|
767
|
+
});
|
|
768
|
+
const runCtx = delivery.channels.length ? { ...ctx, deliverTo: delivery.channels } : ctx;
|
|
769
|
+
|
|
388
770
|
let preStdout = "";
|
|
389
771
|
let preExitCode = 0;
|
|
390
772
|
let preOutputFile = null;
|
|
@@ -419,23 +801,44 @@ export async function runRoutineNow(ctx, routine) {
|
|
|
419
801
|
|
|
420
802
|
// ── Phase 2: LLM / handler ────────────────────────────────────────────────
|
|
421
803
|
const skip = hasPreCmds && shouldSkipPrompt(routine, preExitCode, preStdout);
|
|
804
|
+
setRoutineRunPhase(ctx.runId, "agent");
|
|
422
805
|
|
|
423
806
|
let result = { status: "ok" };
|
|
424
807
|
let status = "ok";
|
|
425
808
|
let errMsg = null;
|
|
426
809
|
|
|
427
810
|
if (!skip) {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
:
|
|
811
|
+
// The automation header: name / id / memory path / last run / this run,
|
|
812
|
+
// built once so a single run stamps one instant. Prepended to the LLM
|
|
813
|
+
// prompt so the model always opens on its identity and the current time
|
|
814
|
+
// natively — the routine no longer needs an `echo …date…` pre_command
|
|
815
|
+
// feeding {{pre_output}} just to know what day it is. It rides on
|
|
816
|
+
// `spec.prompt` ONLY: a telegram routine's `spec.text` is the message body
|
|
817
|
+
// sent verbatim to the chat (handleTelegram), so a header there would leak
|
|
818
|
+
// into the delivered message, not brief a model.
|
|
819
|
+
const header = buildRoutineHeader(routine, {
|
|
820
|
+
storagePath,
|
|
821
|
+
config: ctx.project?.config || ctx.globalConfig,
|
|
822
|
+
nowMs: Date.now(),
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
// Injected unconditionally, including when there is no pre output at all.
|
|
826
|
+
// A routine that asks for {{pre_output}} and gets nothing must see an empty
|
|
827
|
+
// slot, not the literal braces: a placeholder that survives into the prompt
|
|
828
|
+
// reaches the model as text and it will dutifully try to make sense of it.
|
|
829
|
+
// The replace is a no-op for the routines that never mention it.
|
|
830
|
+
const enrichedRoutine = {
|
|
831
|
+
...routine,
|
|
832
|
+
spec: {
|
|
833
|
+
...routine.spec,
|
|
834
|
+
// {{pre_output}} works in both the LLM prompt and the telegram text;
|
|
835
|
+
// the header rides on the prompt only (see above). Keys the spec does
|
|
836
|
+
// not have stay absent — a `prompt: undefined` on a shell routine would
|
|
837
|
+
// be a new shape for every reader downstream.
|
|
838
|
+
...(typeof routine.spec?.prompt === "string" ? { prompt: prependRoutineHeader(injectPreOutput(routine.spec.prompt, preStdout), header) } : {}),
|
|
839
|
+
...(typeof routine.spec?.text === "string" ? { text: injectPreOutput(routine.spec.text, preStdout) } : {}),
|
|
840
|
+
},
|
|
841
|
+
};
|
|
439
842
|
|
|
440
843
|
const handler = HANDLERS[enrichedRoutine.kind];
|
|
441
844
|
if (!handler) {
|
|
@@ -443,7 +846,7 @@ export async function runRoutineNow(ctx, routine) {
|
|
|
443
846
|
errMsg = `unknown routine kind: ${enrichedRoutine.kind}`;
|
|
444
847
|
} else {
|
|
445
848
|
try {
|
|
446
|
-
result = await handler(
|
|
849
|
+
result = await handler(runCtx, enrichedRoutine);
|
|
447
850
|
if (result?.status === "error") {
|
|
448
851
|
status = "error";
|
|
449
852
|
errMsg = result.error || result.stderr || `routine ${routine.name} returned error status`;
|
|
@@ -458,15 +861,164 @@ export async function runRoutineNow(ctx, routine) {
|
|
|
458
861
|
result = { status: "ok", skipped: true, note: "pre_commands signalled skip" };
|
|
459
862
|
}
|
|
460
863
|
|
|
864
|
+
// ── Phase 2.5: delivery ───────────────────────────────────────────────────
|
|
865
|
+
// The run's own answer, handed to every channel the routine is configured
|
|
866
|
+
// for. Before this phase existed the answer went to the ledger and stopped
|
|
867
|
+
// there: reaching a person meant a shell post_command or a paragraph in the
|
|
868
|
+
// prompt asking the model to call send_telegram, and the failure mode of both
|
|
869
|
+
// is silence. See core/routines/delivery.js.
|
|
870
|
+
setRoutineRunPhase(ctx.runId, "delivery");
|
|
871
|
+
const llmOutput = result?.reply || result?.text || "";
|
|
872
|
+
const deliveryText = routineOutputText(result);
|
|
873
|
+
// A run that judged it had nothing worth interrupting for. Not an empty run
|
|
874
|
+
// and not a failed one — a decision, and the watch prompts have always told
|
|
875
|
+
// the model that making it is free. Until this branch existed it was not:
|
|
876
|
+
// "Me mantengo en silencio…" was delivered as the news and charged to the
|
|
877
|
+
// interruption budget like any other push. See readAbstention in delivery.js.
|
|
878
|
+
const abstention = readAbstention(deliveryText);
|
|
879
|
+
const wanted = delivery.channels.length + delivery.unknown.length;
|
|
880
|
+
let deliveries = [];
|
|
881
|
+
let deliverySkipped = [];
|
|
882
|
+
if (wanted > 0 && status === "ok" && abstention) {
|
|
883
|
+
result = { ...result, abstained: true, abstain_reason: abstention.reason || null };
|
|
884
|
+
// No gate, so no nudge is spent and no cooldown consumed; no push channel,
|
|
885
|
+
// so nothing reaches the phone. A bare marker with no reasoning is written
|
|
886
|
+
// nowhere at all — the run log already records that it ran and stayed quiet.
|
|
887
|
+
if (abstention.reason) {
|
|
888
|
+
deliveries = await deliverRoutineOutput(runCtx, {
|
|
889
|
+
routine,
|
|
890
|
+
channels: abstentionChannels(delivery.channels),
|
|
891
|
+
text: abstention.reason,
|
|
892
|
+
gate: null,
|
|
893
|
+
abstained: true,
|
|
894
|
+
agent:
|
|
895
|
+
result?.agent_slug && result.agent_slug !== SUPERAGENT_ACTOR_ID
|
|
896
|
+
? { slug: result.agent_slug, name: result.agent_name || result.agent_slug, model: result.model, usage: result.usage }
|
|
897
|
+
: { slug: SUPERAGENT_ACTOR_ID, model: result?.model, usage: result?.usage },
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
} else if (wanted > 0 && status === "ok" && deliveryText) {
|
|
901
|
+
deliverySkipped = alreadyServedChannels({
|
|
902
|
+
routine,
|
|
903
|
+
channels: delivery.channels,
|
|
904
|
+
postSinks: computeSuppressedTools(routine.post_commands),
|
|
905
|
+
trace: result?.trace,
|
|
906
|
+
});
|
|
907
|
+
const skipIds = new Set(deliverySkipped.map((d) => d.channel));
|
|
908
|
+
// The interruption budget, applied to the push channels delivery owns now
|
|
909
|
+
// that send_telegram is suppressed for a delivering routine. An anchor is
|
|
910
|
+
// `scheduled` and exempt; a watch/a2a run carries its detector's peak
|
|
911
|
+
// severity (a blocker is critical and crosses quiet-hours); a run the owner
|
|
912
|
+
// solicited crosses the budget like a reply. See core/routines/delivery.js.
|
|
913
|
+
const gate = {
|
|
914
|
+
severity: result?.peak_severity || "normal",
|
|
915
|
+
scheduled: routine.spec?.anchor === true,
|
|
916
|
+
unsolicited: !(result?.solicited === true),
|
|
917
|
+
project_id: ctx.project?.id ?? null,
|
|
918
|
+
};
|
|
919
|
+
const attachments = Array.isArray(result?.attachments) ? result.attachments : [];
|
|
920
|
+
const channels = delivery.channels.filter((c) => !skipIds.has(c));
|
|
921
|
+
|
|
922
|
+
// Manu's rule: a routine run by an agent that is NOT Roby must post to its
|
|
923
|
+
// OWN web chat and, instead of pinging the phone itself, leave a delivery
|
|
924
|
+
// for Roby to notify. So for a project agent we split the configured
|
|
925
|
+
// channels — the chat channels go to the agent's own thread, and any push
|
|
926
|
+
// channel (telegram) becomes an a2a emit to Roby, who decides the notify.
|
|
927
|
+
const runByAgent =
|
|
928
|
+
result?.agent_slug && result.agent_slug !== SUPERAGENT_ACTOR_ID
|
|
929
|
+
? { slug: result.agent_slug, name: result.agent_name || result.agent_slug, model: result.model, usage: result.usage }
|
|
930
|
+
: null;
|
|
931
|
+
|
|
932
|
+
if (runByAgent) {
|
|
933
|
+
// The short notification line the mascot / push feed shows (see
|
|
934
|
+
// buildDeliveryNotify): a headline for a short tip, a model summary for a
|
|
935
|
+
// long one. Rides on the delivery so the web ledger row carries it and the
|
|
936
|
+
// event feed can hand it to the pet.
|
|
937
|
+
runByAgent.notify = await buildDeliveryNotify({
|
|
938
|
+
text: deliveryText,
|
|
939
|
+
model: runByAgent.model,
|
|
940
|
+
config: ctx.project?.config || ctx.globalConfig,
|
|
941
|
+
});
|
|
942
|
+
const pushChannels = channels.filter((c) => c === CHANNELS.TELEGRAM);
|
|
943
|
+
const chatChannels = channels.filter((c) => c !== CHANNELS.TELEGRAM);
|
|
944
|
+
deliveries = await deliverRoutineOutput(runCtx, {
|
|
945
|
+
routine, channels: chatChannels, text: deliveryText, gate, attachments, agent: runByAgent,
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
// The delivery queue — one record per thing left waiting for Manu, visible
|
|
949
|
+
// as it piles up and gets crossed off (see core/stores/deliveries.js).
|
|
950
|
+
const priority = routine.spec?.anchor === true;
|
|
951
|
+
const delId = recordDelivery(storagePath, {
|
|
952
|
+
agent: runByAgent.slug,
|
|
953
|
+
agentName: runByAgent.name,
|
|
954
|
+
routine: routine.name,
|
|
955
|
+
routineId: routine.id || "",
|
|
956
|
+
notify: runByAgent.notify,
|
|
957
|
+
priority,
|
|
958
|
+
project_id: ctx.project?.id ?? null,
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
// How Roby tells Manu, by priority:
|
|
962
|
+
// • an anchor (urgent) delivery notifies NOW, crossing the budget;
|
|
963
|
+
// • an ordinary one is LEFT PENDING — the daemon's grace sweep notifies it
|
|
964
|
+
// ~a minute later, unless Manu opens the chat and replies first, which
|
|
965
|
+
// marks it answered and cancels the notify (answerDeliveries).
|
|
966
|
+
if (pushChannels.length) {
|
|
967
|
+
if (priority) {
|
|
968
|
+
const r = await notifyOwnerViaRoby(runCtx, {
|
|
969
|
+
routine, agent: runByAgent, text: deliveryText, notify: runByAgent.notify, gate,
|
|
970
|
+
});
|
|
971
|
+
if (r.sent) {
|
|
972
|
+
markDelivery(storagePath, delId, DELIVERY_STATUS.NOTIFIED, { channel: "telegram" });
|
|
973
|
+
deliveries.push({ channel: "telegram(roby)", status: "ok", note: r.reason || "roby notified" });
|
|
974
|
+
} else if (r.held) {
|
|
975
|
+
markDelivery(storagePath, delId, DELIVERY_STATUS.HELD, { reason: r.reason });
|
|
976
|
+
deliveries.push({ channel: "telegram(roby)", status: "held", reason: r.reason });
|
|
977
|
+
} else {
|
|
978
|
+
deliveries.push({ channel: "telegram(roby)", status: "error", error: r.reason || "not sent" });
|
|
979
|
+
}
|
|
980
|
+
} else {
|
|
981
|
+
deliveries.push({ channel: "telegram(roby)", status: "deferred", note: "grace window — Roby notifies unless answered first" });
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
} else {
|
|
985
|
+
// The super-agent's own routine. Carry its model/usage so the delivered
|
|
986
|
+
// web-thread row is attributed like every other agent turn (the ledger
|
|
987
|
+
// adapter reads agent.model/agent.usage), not filed as "0 tok"/no model.
|
|
988
|
+
deliveries = await deliverRoutineOutput(runCtx, {
|
|
989
|
+
routine, channels, text: deliveryText, gate, attachments,
|
|
990
|
+
agent: { slug: SUPERAGENT_ACTOR_ID, model: result?.model, usage: result?.usage },
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
for (const id of delivery.unknown) {
|
|
994
|
+
deliveries.push({ channel: id, status: "error", error: `unknown delivery channel: ${id}` });
|
|
995
|
+
}
|
|
996
|
+
// Asked to deliver, delivered nowhere, and nothing else was going to carry
|
|
997
|
+
// it — that is the exact shape of failure this feature exists to end, so it
|
|
998
|
+
// is reported as an error rather than as a run that "went fine". A `held`
|
|
999
|
+
// delivery is NOT that failure: the budget withheld it on purpose, and the
|
|
1000
|
+
// message survives in the run log to fold into the next brief.
|
|
1001
|
+
const anyOk =
|
|
1002
|
+
deliveries.some((d) => d.status === "ok" || d.status === "held" || d.status === "deferred") ||
|
|
1003
|
+
deliverySkipped.length > 0;
|
|
1004
|
+
if (!anyOk) {
|
|
1005
|
+
status = "error";
|
|
1006
|
+
errMsg =
|
|
1007
|
+
`nothing delivered: ${deliveries.map((d) => `${d.channel} (${d.error})`).join("; ")}. ` +
|
|
1008
|
+
`The run produced an answer and no one received it.`;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
461
1012
|
// ── Phase 3: post_commands ────────────────────────────────────────────────
|
|
462
1013
|
const postRuns = [];
|
|
463
1014
|
if (hasPostCmds) {
|
|
464
|
-
|
|
1015
|
+
setRoutineRunPhase(ctx.runId, "post");
|
|
465
1016
|
const postEnv = {
|
|
466
1017
|
...pipelineEnv,
|
|
467
1018
|
APX_LLM_OUTPUT: llmOutput.slice(0, 32_000),
|
|
468
1019
|
APX_STATUS: status,
|
|
469
1020
|
APX_SKIPPED: skip ? "1" : "0",
|
|
1021
|
+
APX_DELIVERED: deliveries.filter((d) => d.status === "ok").map((d) => d.channel).join(","),
|
|
470
1022
|
};
|
|
471
1023
|
for (const rawCmd of routine.post_commands) {
|
|
472
1024
|
const cmd = resolveArtifactRef(rawCmd, storagePath);
|
|
@@ -494,16 +1046,27 @@ export async function runRoutineNow(ctx, routine) {
|
|
|
494
1046
|
actor_id: "apx:routine",
|
|
495
1047
|
author: "apx",
|
|
496
1048
|
body: status === "ok"
|
|
497
|
-
? `routine ${routine.name} ok${skip ? " (skipped LLM)" : ""}`
|
|
1049
|
+
? `routine ${routine.name} ok${skip ? " (skipped LLM)" : result?.abstained ? " (stayed quiet)" : ""}`
|
|
498
1050
|
: `routine ${routine.name} error: ${errMsg}`,
|
|
499
1051
|
meta: {
|
|
500
1052
|
routine: routine.name, status, skipped: skip, result,
|
|
501
|
-
// Persisted run flow so the UI can replay pre → action → post.
|
|
1053
|
+
// Persisted run flow so the UI can replay pre → action → delivery → post.
|
|
502
1054
|
flow: {
|
|
503
1055
|
pre: hasPreCmds ? { output: preStdout.slice(0, 8000), exit: preExitCode } : null,
|
|
1056
|
+
delivery: wanted ? { channels: delivery.channels, source: delivery.source, results: deliveries, skipped: deliverySkipped } : null,
|
|
504
1057
|
post: postRuns.length ? postRuns : null,
|
|
505
1058
|
},
|
|
506
1059
|
},
|
|
507
1060
|
});
|
|
508
|
-
return {
|
|
1061
|
+
return {
|
|
1062
|
+
...result,
|
|
1063
|
+
// A caller that ran the routine by hand (CLI, API, the web panel) should be
|
|
1064
|
+
// able to see where the answer went without going to read the ledger.
|
|
1065
|
+
...(wanted
|
|
1066
|
+
? { delivery: { channels: delivery.channels, source: delivery.source, results: deliveries, skipped: deliverySkipped } }
|
|
1067
|
+
: {}),
|
|
1068
|
+
...(status === "error" && result?.status !== "error" ? { status, error: errMsg } : {}),
|
|
1069
|
+
last_run_at: lastRun,
|
|
1070
|
+
next_run_at: next,
|
|
1071
|
+
};
|
|
509
1072
|
}
|