@agentprojectcontext/apx 1.77.3 → 1.79.0
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/README.md +23 -9
- package/package.json +12 -12
- package/src/core/agent/build-agent-system.js +3 -2
- package/src/core/agent/constants.js +3 -2
- package/src/core/agent/loop/greeting-guard.js +55 -0
- package/src/core/agent/loop/side-effects.js +52 -0
- package/src/core/agent/prompt-builder.js +49 -8
- package/src/core/agent/run-agent.js +43 -53
- package/src/core/agent/security.js +1 -1
- package/src/core/agent/self-memory.js +4 -2
- package/src/core/agent/skills/index-store.js +2 -2
- package/src/core/agent/skills/loader.js +3 -22
- package/src/core/agent/super-agent.js +0 -2
- package/src/core/agent/tool-summary.js +65 -0
- package/src/core/agent/tools/handlers/call-runtime.js +4 -4
- package/src/core/agent/tools/handlers/list-commitments.js +80 -0
- package/src/core/agent/tools/handlers/list-tasks.js +66 -27
- package/src/core/agent/tools/handlers/record-commitment.js +68 -0
- package/src/core/agent/tools/handlers/search-sessions.js +1 -1
- package/src/core/agent/tools/handlers/send-telegram.js +68 -2
- package/src/core/agent/tools/handlers/set-permission-mode.js +11 -4
- package/src/core/agent/tools/names.js +64 -0
- package/src/core/agent/tools/registry.js +9 -0
- package/src/core/agent/tools/tool-call-parser.js +70 -1
- package/src/core/apc/context-copy.js +1 -1
- package/src/core/apc/frontmatter.js +85 -0
- package/src/core/apc/parser.js +9 -21
- package/src/core/apc/paths.js +8 -8
- package/src/core/apc/scaffold.js +5 -4
- package/src/core/channels/telegram/ask-callbacks.js +35 -0
- package/src/core/channels/telegram/config.js +201 -0
- package/src/core/channels/telegram/dispatch.js +3 -0
- package/src/core/channels/telegram/reply.js +30 -5
- package/src/core/config/index.js +25 -183
- package/src/core/config/paths.js +57 -1
- package/src/core/config/redact.js +22 -0
- package/src/core/confirmation/adapters/web.js +1 -1
- package/src/core/daemon/service.js +238 -0
- package/src/core/deck/manifest.js +12 -12
- package/src/core/desktop/autostart.js +3 -2
- package/src/core/desktop/process.js +4 -4
- package/src/core/engines/gemini.js +322 -60
- package/src/core/engines/openai-compatible.js +21 -2
- package/src/core/engines/presets.js +2 -2
- package/src/core/http-tools/browser.js +1 -1
- package/src/core/http-tools/catalog.js +551 -0
- package/src/core/http-tools/fetch.js +1 -1
- package/src/core/http-tools/glob.js +3 -3
- package/src/core/http-tools/grep.js +2 -9
- package/src/core/http-tools/inline-handlers.js +59 -0
- package/src/core/http-tools/registry.js +31 -615
- package/src/core/http-tools/search.js +2 -2
- package/src/core/identity/self.js +6 -7
- package/src/core/identity/telegram.js +3 -3
- package/src/core/logging.js +6 -5
- package/src/core/mcp/sources.js +12 -16
- package/src/core/memory/consolidate.js +225 -0
- package/src/core/memory/indexer.js +2 -5
- package/src/core/nudge/index.js +192 -0
- package/src/core/nudge/policy.js +143 -0
- package/src/core/nudge/store.js +141 -0
- package/src/core/profiles/bundled/secretary/PROFILE.md +8 -9
- package/src/core/profiles/bundled/secretary/config.schema.json +33 -3
- package/src/core/profiles/bundled/secretary/routines/day-close.json +7 -3
- package/src/core/profiles/bundled/secretary/routines/day-open.json +7 -3
- package/src/core/profiles/bundled/secretary/routines/watch.json +13 -0
- package/src/core/profiles/lifecycle.js +0 -2
- package/src/core/profiles/store.js +2 -7
- package/src/core/routines/runner.js +103 -4
- package/src/core/routines/signals.js +270 -0
- package/src/core/runtime-skills/apx-agency-agents/SKILL.md +2 -2
- package/src/core/runtime-skills/apx-profile/SKILL.md +3 -3
- package/src/core/runtime-skills/apx-project/SKILL.md +1 -1
- package/src/core/runtime-skills/apx-task/SKILL.md +8 -8
- package/src/core/runtime-skills/apx-telegram/SKILL.md +4 -4
- package/src/core/runtime-skills/apx-voice/SKILL.md +4 -4
- package/src/core/runtimes/detect.js +2 -2
- package/src/core/sessions/index.js +800 -0
- package/src/core/stores/code-sessions.js +3 -14
- package/src/core/stores/commitments.js +331 -0
- package/src/core/stores/engine-sessions.js +0 -4
- package/src/core/stores/messages.js +4 -5
- package/src/core/stores/organization.js +9 -11
- package/src/core/stores/routines.js +23 -14
- package/src/core/stores/runtime-callbacks.js +2 -1
- package/src/core/util/json-file.js +128 -0
- package/src/core/util/thinking.js +51 -0
- package/src/core/vars/sources.js +14 -21
- package/src/core/voice/stt-models.js +1 -1
- package/src/core/voice/tts.js +5 -4
- package/src/host/daemon/api/admin-config.js +5 -5
- package/src/host/daemon/api/admin.js +8 -7
- package/src/host/daemon/api/agents.js +16 -16
- package/src/host/daemon/api/artifact-preview.js +8 -8
- package/src/host/daemon/api/artifacts.js +7 -7
- package/src/host/daemon/api/code.js +8 -8
- package/src/host/daemon/api/commitments.js +135 -0
- package/src/host/daemon/api/config.js +6 -6
- package/src/host/daemon/api/confirm.js +2 -2
- package/src/host/daemon/api/connections.js +2 -2
- package/src/host/daemon/api/conversations.js +12 -12
- package/src/host/daemon/api/deck.js +6 -6
- package/src/host/daemon/api/desktop.js +8 -8
- package/src/host/daemon/api/embeddings.js +4 -4
- package/src/host/daemon/api/engines.js +8 -7
- package/src/host/daemon/api/exec.js +5 -4
- package/src/host/daemon/api/files-project.js +6 -6
- package/src/host/daemon/api/health.js +2 -2
- package/src/host/daemon/api/identity.js +3 -3
- package/src/host/daemon/api/inbox.js +2 -2
- package/src/host/daemon/api/integrations.js +23 -19
- package/src/host/daemon/api/mcps.js +16 -12
- package/src/host/daemon/api/messages.js +5 -5
- package/src/host/daemon/api/nudges.js +112 -0
- package/src/host/daemon/api/organization.js +8 -8
- package/src/host/daemon/api/pairing.js +6 -6
- package/src/host/daemon/api/plugins.js +3 -3
- package/src/host/daemon/api/prefix.js +20 -0
- package/src/host/daemon/api/profiles.js +9 -9
- package/src/host/daemon/api/projects.js +5 -5
- package/src/host/daemon/api/routines.js +32 -8
- package/src/host/daemon/api/run.js +2 -2
- package/src/host/daemon/api/runtimes.js +6 -6
- package/src/host/daemon/api/self-memory.js +50 -0
- package/src/host/daemon/api/sessions-search.js +18 -11
- package/src/host/daemon/api/sessions.js +6 -6
- package/src/host/daemon/api/shared.js +59 -13
- package/src/host/daemon/api/skills.js +12 -12
- package/src/host/daemon/api/super-agent.js +4 -4
- package/src/host/daemon/api/tasks.js +11 -11
- package/src/host/daemon/api/telegram.js +61 -24
- package/src/host/daemon/api/tools.js +7 -7
- package/src/host/daemon/api/top-level.js +7 -7
- package/src/host/daemon/api/transcribe.js +6 -6
- package/src/host/daemon/api/tts.js +3 -3
- package/src/host/daemon/api/vars.js +11 -8
- package/src/host/daemon/api/voice.js +9 -7
- package/src/host/daemon/api/web.js +28 -32
- package/src/host/daemon/api.js +83 -48
- package/src/host/daemon/callback-reconciler.js +16 -0
- package/src/host/daemon/db.js +1 -1
- package/src/host/daemon/desktop-ws.js +7 -3
- package/src/host/daemon/index.js +11 -5
- package/src/host/daemon/plugins/desktop/index.js +8 -2
- package/src/host/daemon/plugins/telegram/index.js +7 -2
- package/src/host/daemon/stt-venv.js +20 -81
- package/src/host/daemon/wakeup.js +18 -4
- package/src/interfaces/acp/index.js +3 -3
- package/src/interfaces/acp/session.js +2 -2
- package/src/interfaces/cli/commands/a2a.js +2 -2
- package/src/interfaces/cli/commands/agent.js +3 -3
- package/src/interfaces/cli/commands/artifact.js +13 -13
- package/src/interfaces/cli/commands/chat.js +3 -3
- package/src/interfaces/cli/commands/command.js +2 -2
- package/src/interfaces/cli/commands/commitment.js +154 -0
- package/src/interfaces/cli/commands/config.js +4 -4
- package/src/interfaces/cli/commands/daemon.js +74 -18
- package/src/interfaces/cli/commands/desktop.js +7 -14
- package/src/interfaces/cli/commands/exec.js +2 -2
- package/src/interfaces/cli/commands/log.js +3 -4
- package/src/interfaces/cli/commands/mcp.js +9 -9
- package/src/interfaces/cli/commands/memory.js +75 -2
- package/src/interfaces/cli/commands/messages.js +5 -5
- package/src/interfaces/cli/commands/model.js +0 -18
- package/src/interfaces/cli/commands/nudge.js +130 -0
- package/src/interfaces/cli/commands/obsidian.js +5 -5
- package/src/interfaces/cli/commands/org.js +5 -5
- package/src/interfaces/cli/commands/pair.js +6 -6
- package/src/interfaces/cli/commands/plugins.js +2 -2
- package/src/interfaces/cli/commands/profile.js +10 -10
- package/src/interfaces/cli/commands/project-config.js +6 -6
- package/src/interfaces/cli/commands/project.js +10 -10
- package/src/interfaces/cli/commands/routine.js +8 -9
- package/src/interfaces/cli/commands/runtime.js +2 -2
- package/src/interfaces/cli/commands/search.js +0 -1
- package/src/interfaces/cli/commands/session.js +12 -40
- package/src/interfaces/cli/commands/sessions.js +21 -798
- package/src/interfaces/cli/commands/setup.js +16 -6
- package/src/interfaces/cli/commands/skills.js +1 -2
- package/src/interfaces/cli/commands/status.js +3 -3
- package/src/interfaces/cli/commands/task.js +8 -8
- package/src/interfaces/cli/commands/telegram.js +21 -21
- package/src/interfaces/cli/commands/voice.js +6 -6
- package/src/interfaces/cli/help/index.js +2245 -0
- package/src/interfaces/cli/http.js +9 -4
- package/src/interfaces/cli/index.js +14 -2857
- package/src/interfaces/cli/routes/acp.js +13 -0
- package/src/interfaces/cli/routes/agent.js +27 -0
- package/src/interfaces/cli/routes/artifact.js +28 -0
- package/src/interfaces/cli/routes/chat.js +11 -0
- package/src/interfaces/cli/routes/code.js +11 -0
- package/src/interfaces/cli/routes/command.js +21 -0
- package/src/interfaces/cli/routes/commitment.js +19 -0
- package/src/interfaces/cli/routes/config.js +16 -0
- package/src/interfaces/cli/routes/connections.js +11 -0
- package/src/interfaces/cli/routes/conversations.js +21 -0
- package/src/interfaces/cli/routes/daemon.js +25 -0
- package/src/interfaces/cli/routes/desktop.js +20 -0
- package/src/interfaces/cli/routes/env.js +13 -0
- package/src/interfaces/cli/routes/exec.js +11 -0
- package/src/interfaces/cli/routes/identity.js +11 -0
- package/src/interfaces/cli/routes/index.js +75 -0
- package/src/interfaces/cli/routes/init.js +11 -0
- package/src/interfaces/cli/routes/log.js +20 -0
- package/src/interfaces/cli/routes/mcp.js +22 -0
- package/src/interfaces/cli/routes/memory.js +19 -0
- package/src/interfaces/cli/routes/messages.js +16 -0
- package/src/interfaces/cli/routes/model.js +11 -0
- package/src/interfaces/cli/routes/nudge.js +17 -0
- package/src/interfaces/cli/routes/obsidian.js +17 -0
- package/src/interfaces/cli/routes/org.js +34 -0
- package/src/interfaces/cli/routes/overlay.js +10 -0
- package/src/interfaces/cli/routes/pair.js +17 -0
- package/src/interfaces/cli/routes/panel.js +16 -0
- package/src/interfaces/cli/routes/permission.js +11 -0
- package/src/interfaces/cli/routes/plugins.js +21 -0
- package/src/interfaces/cli/routes/profile.js +27 -0
- package/src/interfaces/cli/routes/project.js +41 -0
- package/src/interfaces/cli/routes/restart.js +15 -0
- package/src/interfaces/cli/routes/routine.js +28 -0
- package/src/interfaces/cli/routes/run.js +11 -0
- package/src/interfaces/cli/routes/search.js +11 -0
- package/src/interfaces/cli/routes/send.js +11 -0
- package/src/interfaces/cli/routes/session.js +26 -0
- package/src/interfaces/cli/routes/sessions.js +15 -0
- package/src/interfaces/cli/routes/setup.js +18 -0
- package/src/interfaces/cli/routes/skills.js +20 -0
- package/src/interfaces/cli/routes/status.js +12 -0
- package/src/interfaces/cli/routes/task.js +26 -0
- package/src/interfaces/cli/routes/telegram.js +39 -0
- package/src/interfaces/cli/routes/update.js +24 -0
- package/src/interfaces/cli/routes/voice.js +17 -0
- package/src/interfaces/desktop/main.js +6 -7
- package/src/interfaces/desktop/renderer.js +0 -5
- package/src/interfaces/mcp-server/index.js +15 -14
- package/src/interfaces/tui/_shims/globals.d.ts +8 -0
- package/src/interfaces/tui/tsconfig.json +4 -1
- package/src/interfaces/web/README.md +6 -6
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js +849 -0
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-DzBBXFaO.css +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/package-lock.json +11 -10
- package/src/interfaces/web/src/components/AddProjectDialog.tsx +1 -1
- package/src/interfaces/web/src/components/Section.tsx +18 -3
- package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +1 -1
- package/src/interfaces/web/src/components/chat/ChatList.tsx +2 -2
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +13 -0
- package/src/interfaces/web/src/components/chat/SkillPicker.tsx +1 -1
- package/src/interfaces/web/src/components/code/CodeFileTree.tsx +1 -1
- package/src/interfaces/web/src/components/code/CodeTerminal.tsx +1 -1
- package/src/interfaces/web/src/components/cron/CronPicker.tsx +196 -0
- package/src/interfaces/web/src/components/desktop/DesktopStatusCard.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileBrowser.tsx +2 -2
- package/src/interfaces/web/src/components/inbox/InboxList.tsx +145 -0
- package/src/interfaces/web/src/components/memory/MemoryBrowser.tsx +36 -6
- package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +1 -1
- package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +16 -4
- package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +14 -4
- package/src/interfaces/web/src/components/routines/shared.ts +14 -5
- package/src/interfaces/web/src/components/settings/DesktopSettingsPanel.tsx +1 -1
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +1 -1
- package/src/interfaces/web/src/components/settings/NudgePanel.tsx +183 -0
- package/src/interfaces/web/src/components/settings/ProfilePanel.tsx +36 -12
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +1 -1
- package/src/interfaces/web/src/components/settings/SkillsManager.tsx +2 -2
- package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +1 -1
- package/src/interfaces/web/src/components/ui/filter-chips.tsx +47 -0
- package/src/interfaces/web/src/components/ui.tsx +1 -0
- package/src/interfaces/web/src/constants/index.ts +1 -0
- package/src/interfaces/web/src/hooks/useChat.ts +5 -1
- package/src/interfaces/web/src/hooks/useDaemonStatus.ts +1 -1
- package/src/interfaces/web/src/hooks/useDevices.ts +1 -1
- package/src/interfaces/web/src/hooks/useEngines.ts +1 -1
- package/src/interfaces/web/src/hooks/useGlobalConfig.ts +2 -2
- package/src/interfaces/web/src/hooks/useIdentity.ts +1 -1
- package/src/interfaces/web/src/hooks/useInbox.ts +1 -1
- package/src/interfaces/web/src/hooks/useNudges.ts +38 -0
- package/src/interfaces/web/src/hooks/useProfiles.ts +3 -3
- package/src/interfaces/web/src/hooks/useProjects.ts +1 -1
- package/src/interfaces/web/src/hooks/useTelegram.ts +3 -3
- package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +3 -3
- package/src/interfaces/web/src/i18n/en.ts +127 -0
- package/src/interfaces/web/src/i18n/es.ts +127 -0
- package/src/interfaces/web/src/lib/api/admin.ts +11 -11
- package/src/interfaces/web/src/lib/api/agents.ts +14 -14
- package/src/interfaces/web/src/lib/api/artifacts.ts +11 -11
- package/src/interfaces/web/src/lib/api/code.ts +1 -1
- package/src/interfaces/web/src/lib/api/commitments.ts +57 -0
- package/src/interfaces/web/src/lib/api/conversations.ts +8 -8
- package/src/interfaces/web/src/lib/api/deck.ts +3 -3
- package/src/interfaces/web/src/lib/api/desktop.ts +8 -8
- package/src/interfaces/web/src/lib/api/embeddings.ts +3 -3
- package/src/interfaces/web/src/lib/api/engines.ts +3 -3
- package/src/interfaces/web/src/lib/api/filesystem.ts +2 -2
- package/src/interfaces/web/src/lib/api/health.ts +1 -1
- package/src/interfaces/web/src/lib/api/identity.ts +2 -2
- package/src/interfaces/web/src/lib/api/inbox.ts +1 -1
- package/src/interfaces/web/src/lib/api/integrations.ts +8 -8
- package/src/interfaces/web/src/lib/api/mcps.ts +6 -6
- package/src/interfaces/web/src/lib/api/messages.ts +3 -3
- package/src/interfaces/web/src/lib/api/notebook.ts +23 -0
- package/src/interfaces/web/src/lib/api/nudges.ts +53 -0
- package/src/interfaces/web/src/lib/api/organization.ts +7 -7
- package/src/interfaces/web/src/lib/api/profiles.ts +8 -8
- package/src/interfaces/web/src/lib/api/projectFiles.ts +5 -5
- package/src/interfaces/web/src/lib/api/projects.ts +12 -12
- package/src/interfaces/web/src/lib/api/routines.ts +7 -7
- package/src/interfaces/web/src/lib/api/sessions.ts +2 -2
- package/src/interfaces/web/src/lib/api/skills.ts +11 -11
- package/src/interfaces/web/src/lib/api/super_agent.ts +3 -3
- package/src/interfaces/web/src/lib/api/tasks.ts +12 -12
- package/src/interfaces/web/src/lib/api/telegram.ts +14 -14
- package/src/interfaces/web/src/lib/api/tools.ts +1 -1
- package/src/interfaces/web/src/lib/api/vars.ts +4 -4
- package/src/interfaces/web/src/lib/api/voice.ts +6 -6
- package/src/interfaces/web/src/lib/cron.ts +196 -0
- package/src/interfaces/web/src/lib/when.ts +32 -0
- package/src/interfaces/web/src/screens/InboxScreen.tsx +107 -77
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +5 -2
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +17 -3
- package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +1 -1
- package/src/interfaces/web/src/screens/base/CommitmentsTab.tsx +239 -0
- package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +103 -20
- package/src/interfaces/web/src/screens/base/LogsTab.tsx +18 -3
- package/src/interfaces/web/src/screens/base/SessionsTab.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +8 -8
- package/src/interfaces/web/src/screens/project/AgentsTab.tsx +2 -2
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +24 -6
- package/src/interfaces/web/src/screens/project/ConfigTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +3 -3
- package/src/interfaces/web/src/screens/project/Overview.tsx +6 -6
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +15 -13
- package/src/interfaces/web/src/screens/project/StructureTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/TasksTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/VarsTab.tsx +1 -1
- package/src/interfaces/web/src/types/daemon.ts +10 -1
- package/src/interfaces/web/vite.config.ts +13 -18
- package/src/interfaces/web/dist/assets/index-BptlbKjU.js +0 -824
- package/src/interfaces/web/dist/assets/index-BptlbKjU.js.map +0 -1
- package/src/interfaces/web/dist/assets/index-D_EJEA1n.css +0 -1
- package/src/skills/apc-context/SKILL.md +0 -159
- /package/src/{host/daemon → core}/runtimes/_spawn.js +0 -0
- /package/src/{host/daemon → core}/runtimes/aider.js +0 -0
- /package/src/{host/daemon → core}/runtimes/antigravity.js +0 -0
- /package/src/{host/daemon → core}/runtimes/claude-code.js +0 -0
- /package/src/{host/daemon → core}/runtimes/codex.js +0 -0
- /package/src/{host/daemon → core}/runtimes/cursor-agent.js +0 -0
- /package/src/{host/daemon → core}/runtimes/gemini-cli.js +0 -0
- /package/src/{host/daemon → core}/runtimes/index.js +0 -0
- /package/src/{host/daemon → core}/runtimes/opencode.js +0 -0
- /package/src/{host/daemon → core}/runtimes/qwen-code.js +0 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// Signals — deterministic detection of things worth noticing.
|
|
2
|
+
//
|
|
3
|
+
// THE SPLIT THIS FILE EXISTS FOR: detection is cheap and mechanical; judgement
|
|
4
|
+
// is expensive and contextual. Mixing them means paying a language model every
|
|
5
|
+
// five minutes to conclude that nothing is happening. Everything here is a
|
|
6
|
+
// pure function over stored state — no model, no network, no clock beyond the
|
|
7
|
+
// `now` you pass in — so a watch routine that finds nothing costs nothing, and
|
|
8
|
+
// every rule below is testable with synthetic state.
|
|
9
|
+
//
|
|
10
|
+
// Thresholds are PARAMETERS, never constants. "Stale after 7 days" is a
|
|
11
|
+
// judgement about how someone works, and judgements belong to the profile.
|
|
12
|
+
//
|
|
13
|
+
// A signal is:
|
|
14
|
+
// { type, project_id, project_name, severity, subject, detected_at, payload }
|
|
15
|
+
//
|
|
16
|
+
// `subject` is a one-line human phrasing — the detector already knows exactly
|
|
17
|
+
// what it found, and making the model re-derive it from payload fields is how
|
|
18
|
+
// summaries drift from the data they claim to describe.
|
|
19
|
+
import { listTasks } from "#core/stores/tasks.js";
|
|
20
|
+
import { listCommitments } from "#core/stores/commitments.js";
|
|
21
|
+
import { nowIso } from "#core/util/time.js";
|
|
22
|
+
|
|
23
|
+
/** Every detector, keyed by the type it emits. */
|
|
24
|
+
export const SIGNAL_TYPES = Object.freeze([
|
|
25
|
+
"overdue_task",
|
|
26
|
+
"blocked_task",
|
|
27
|
+
"stale_project",
|
|
28
|
+
"commitment_due",
|
|
29
|
+
"overdue_commitment",
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
/** Defaults chosen to be quiet. A watcher that cries on day one gets turned off. */
|
|
33
|
+
export const DEFAULT_THRESHOLDS = Object.freeze({
|
|
34
|
+
blocked_hours: 48,
|
|
35
|
+
stale_project_days: 7,
|
|
36
|
+
commitment_lead_hours: 48,
|
|
37
|
+
/** Detectors to run. Empty = all of them. */
|
|
38
|
+
types: [],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// detectors — each takes (project, opts) and returns Signal[]
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
/** A task whose due date has passed and which nobody closed. */
|
|
46
|
+
function detectOverdueTasks(project, { now }) {
|
|
47
|
+
const today = now.slice(0, 10);
|
|
48
|
+
return listTasks(project.storagePath, { state: "open" })
|
|
49
|
+
.filter((t) => t.due && t.due < today)
|
|
50
|
+
.map((t) =>
|
|
51
|
+
signal(project, {
|
|
52
|
+
type: "overdue_task",
|
|
53
|
+
// A task one day late and one three weeks late are not the same event.
|
|
54
|
+
severity: daysBetween(t.due, today) >= 7 ? "high" : "normal",
|
|
55
|
+
subject: `"${t.title}" was due ${t.due}`,
|
|
56
|
+
payload: { task_id: t.id, title: t.title, due: t.due, days_late: daysBetween(t.due, today) },
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A task sitting in `blocked` long enough that nobody is coming back to it.
|
|
63
|
+
*
|
|
64
|
+
* Uses updated_at, not created_at: a task blocked this morning is a normal
|
|
65
|
+
* working state, and flagging it would train the user to ignore the watcher.
|
|
66
|
+
*/
|
|
67
|
+
function detectBlockedTasks(project, { now, blocked_hours }) {
|
|
68
|
+
const cutoff = new Date(Date.parse(now) - blocked_hours * 3_600_000).toISOString();
|
|
69
|
+
return listTasks(project.storagePath, { state: "open", status: "blocked" })
|
|
70
|
+
.filter((t) => (t.updated_at || t.created_at || "") < cutoff)
|
|
71
|
+
.map((t) =>
|
|
72
|
+
signal(project, {
|
|
73
|
+
type: "blocked_task",
|
|
74
|
+
severity: "normal",
|
|
75
|
+
subject: `"${t.title}" has been blocked since ${(t.updated_at || t.created_at || "").slice(0, 10)}`,
|
|
76
|
+
payload: { task_id: t.id, title: t.title, since: t.updated_at || t.created_at },
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* A project nobody has touched.
|
|
83
|
+
*
|
|
84
|
+
* WHAT "ACTIVITY" MEANS HERE: the newest task or commitment event in the
|
|
85
|
+
* project's store. APX has no single per-project activity timestamp, and
|
|
86
|
+
* folding every conversation on a five-minute tick would defeat the point of a
|
|
87
|
+
* cheap detector. So this measures what it can actually see, and the phrasing
|
|
88
|
+
* says so — "no task or commitment activity", not "nothing happened". A caller
|
|
89
|
+
* with a better timestamp can pass `last_activity_at` and it wins.
|
|
90
|
+
*
|
|
91
|
+
* Claiming more than the data supports is the failure mode that kills trust in
|
|
92
|
+
* a watcher: one confident "you have abandoned this" about a project the user
|
|
93
|
+
* worked on all week, and they stop believing the rest.
|
|
94
|
+
*
|
|
95
|
+
* Deliberately ONE signal per project rather than per silent item — the point
|
|
96
|
+
* is "you have forgotten about this", and saying it once is the whole message.
|
|
97
|
+
*
|
|
98
|
+
* A project with nothing recorded at all is skipped: a freshly registered
|
|
99
|
+
* project is not neglected, and greeting someone with "this is stale" the day
|
|
100
|
+
* they add it is exactly what gets a watcher muted.
|
|
101
|
+
*/
|
|
102
|
+
function detectStaleProject(project, { now, stale_project_days }) {
|
|
103
|
+
const last = project.last_activity_at || lastRecordedActivity(project.storagePath);
|
|
104
|
+
if (!last) return [];
|
|
105
|
+
const days = daysBetween(last.slice(0, 10), now.slice(0, 10));
|
|
106
|
+
if (days < stale_project_days) return [];
|
|
107
|
+
const measured = project.last_activity_at ? "activity" : "task or commitment activity";
|
|
108
|
+
return [
|
|
109
|
+
signal(project, {
|
|
110
|
+
type: "stale_project",
|
|
111
|
+
severity: days >= stale_project_days * 3 ? "normal" : "low",
|
|
112
|
+
subject: `no ${measured} on ${project.name || project.path || "this project"} for ${days} days`,
|
|
113
|
+
payload: { days, last_activity_at: last, measured },
|
|
114
|
+
}),
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Newest task or commitment timestamp in a project store, or "" when empty. */
|
|
119
|
+
function lastRecordedActivity(storagePath) {
|
|
120
|
+
let newest = "";
|
|
121
|
+
const bump = (v) => { if (v && v > newest) newest = v; };
|
|
122
|
+
try {
|
|
123
|
+
for (const t of listTasks(storagePath, { state: "all" })) bump(t.updated_at || t.created_at);
|
|
124
|
+
} catch { /* unreadable → treated as no evidence, not as staleness */ }
|
|
125
|
+
try {
|
|
126
|
+
for (const c of listCommitments(storagePath, { state: "all" })) bump(c.updated_at || c.created_at);
|
|
127
|
+
} catch { /* same */ }
|
|
128
|
+
return newest;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** A promise coming due inside the lead window — still time to keep it. */
|
|
132
|
+
function detectCommitmentsDue(project, { now, commitment_lead_hours }) {
|
|
133
|
+
const horizon = new Date(Date.parse(now) + commitment_lead_hours * 3_600_000).toISOString();
|
|
134
|
+
return listCommitments(project.storagePath, { state: "open" })
|
|
135
|
+
.filter((c) => c.due && c.due >= now && c.due <= horizon)
|
|
136
|
+
.map((c) =>
|
|
137
|
+
signal(project, {
|
|
138
|
+
type: "commitment_due",
|
|
139
|
+
// Higher than an equivalent task on purpose: someone is waiting, and a
|
|
140
|
+
// warning that arrives in time is worth more than one that arrives after.
|
|
141
|
+
severity: "high",
|
|
142
|
+
subject: `you promised ${c.counterparty}: ${c.body} — due ${c.due.slice(0, 10)}`,
|
|
143
|
+
payload: { commitment_id: c.id, counterparty: c.counterparty, due: c.due, body: c.body },
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** A promise already past its date and still open. The costliest thing here. */
|
|
149
|
+
function detectOverdueCommitments(project, { now }) {
|
|
150
|
+
return listCommitments(project.storagePath, { state: "open", overdue: true, now })
|
|
151
|
+
.map((c) =>
|
|
152
|
+
signal(project, {
|
|
153
|
+
type: "overdue_commitment",
|
|
154
|
+
severity: "critical",
|
|
155
|
+
subject: `you owe ${c.counterparty}: ${c.body} — was due ${c.due.slice(0, 10)}`,
|
|
156
|
+
payload: {
|
|
157
|
+
commitment_id: c.id, counterparty: c.counterparty, due: c.due, body: c.body,
|
|
158
|
+
days_late: daysBetween(c.due.slice(0, 10), now.slice(0, 10)),
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const DETECTORS = {
|
|
165
|
+
overdue_task: detectOverdueTasks,
|
|
166
|
+
blocked_task: detectBlockedTasks,
|
|
167
|
+
stale_project: detectStaleProject,
|
|
168
|
+
commitment_due: detectCommitmentsDue,
|
|
169
|
+
overdue_commitment: detectOverdueCommitments,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// public API
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Run the configured detectors over the given projects.
|
|
178
|
+
*
|
|
179
|
+
* @param {{id, name?, path?, storagePath, last_activity_at?}[]} projects
|
|
180
|
+
* @param {object} opts thresholds + `types` + `now` (ISO, injectable for tests)
|
|
181
|
+
* @returns {{ signals: object[], skipped: {id, error}[] }}
|
|
182
|
+
*/
|
|
183
|
+
export function detectSignals(projects, opts = {}) {
|
|
184
|
+
const cfg = { ...DEFAULT_THRESHOLDS, ...opts, now: opts.now || nowIso() };
|
|
185
|
+
const wanted = Array.isArray(cfg.types) && cfg.types.length
|
|
186
|
+
? cfg.types.filter((t) => t in DETECTORS)
|
|
187
|
+
: SIGNAL_TYPES;
|
|
188
|
+
|
|
189
|
+
const signals = [];
|
|
190
|
+
const skipped = [];
|
|
191
|
+
|
|
192
|
+
for (const project of projects || []) {
|
|
193
|
+
if (!project?.storagePath) continue;
|
|
194
|
+
for (const type of wanted) {
|
|
195
|
+
try {
|
|
196
|
+
signals.push(...DETECTORS[type](project, cfg));
|
|
197
|
+
} catch (e) {
|
|
198
|
+
// One unreadable log must not blank the whole sweep — and must not be
|
|
199
|
+
// silent either, or the watcher reports "all clear" when it is blind.
|
|
200
|
+
skipped.push({ id: project.id, type, error: e?.message || String(e) });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
signals.sort(bySeverityThenDate);
|
|
206
|
+
return { signals, skipped };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const SEVERITY_RANK = { critical: 0, high: 1, normal: 2, low: 3 };
|
|
210
|
+
|
|
211
|
+
function bySeverityThenDate(a, b) {
|
|
212
|
+
const s = (SEVERITY_RANK[a.severity] ?? 9) - (SEVERITY_RANK[b.severity] ?? 9);
|
|
213
|
+
if (s !== 0) return s;
|
|
214
|
+
return String(a.subject).localeCompare(String(b.subject));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Render signals as the block a routine hands the model.
|
|
219
|
+
*
|
|
220
|
+
* Pre-rendered rather than passed as JSON because the model's job here is
|
|
221
|
+
* judgement — "is any of this worth interrupting for?" — not parsing.
|
|
222
|
+
*/
|
|
223
|
+
export function formatSignals(signals) {
|
|
224
|
+
if (!signals?.length) return "";
|
|
225
|
+
const lines = signals.map(
|
|
226
|
+
(s) => `- [${s.severity}] ${s.project_name ? `${s.project_name}: ` : ""}${s.subject}`,
|
|
227
|
+
);
|
|
228
|
+
return lines.join("\n");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** The highest severity present, for the interruption budget. */
|
|
232
|
+
export function peakSeverity(signals) {
|
|
233
|
+
let best = "low";
|
|
234
|
+
for (const s of signals || []) {
|
|
235
|
+
if ((SEVERITY_RANK[s.severity] ?? 9) < (SEVERITY_RANK[best] ?? 9)) best = s.severity;
|
|
236
|
+
}
|
|
237
|
+
return signals?.length ? best : "low";
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Thresholds from a profile's config, falling back to the defaults. */
|
|
241
|
+
export function thresholdsFromConfig(profileConfig = {}) {
|
|
242
|
+
const pick = (key, fallback) => {
|
|
243
|
+
const v = Number.parseInt(profileConfig[key], 10);
|
|
244
|
+
return Number.isFinite(v) && v > 0 ? v : fallback;
|
|
245
|
+
};
|
|
246
|
+
return {
|
|
247
|
+
blocked_hours: pick("blocked_task_hours", DEFAULT_THRESHOLDS.blocked_hours),
|
|
248
|
+
stale_project_days: pick("stale_project_days", DEFAULT_THRESHOLDS.stale_project_days),
|
|
249
|
+
commitment_lead_hours: pick("commitment_lead_hours", DEFAULT_THRESHOLDS.commitment_lead_hours),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
function signal(project, fields) {
|
|
256
|
+
return {
|
|
257
|
+
project_id: project.id ?? null,
|
|
258
|
+
project_name: project.name || project.path || "",
|
|
259
|
+
detected_at: nowIso(),
|
|
260
|
+
...fields,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Whole days between two YYYY-MM-DD strings. Negative when `to` precedes `from`. */
|
|
265
|
+
function daysBetween(from, to) {
|
|
266
|
+
const a = Date.parse(`${String(from).slice(0, 10)}T00:00:00Z`);
|
|
267
|
+
const b = Date.parse(`${String(to).slice(0, 10)}T00:00:00Z`);
|
|
268
|
+
if (!Number.isFinite(a) || !Number.isFinite(b)) return 0;
|
|
269
|
+
return Math.round((b - a) / 86_400_000);
|
|
270
|
+
}
|
|
@@ -68,7 +68,7 @@ import_agent({ slug: "cody-developer", project: "<name-or-path>" })
|
|
|
68
68
|
|
|
69
69
|
## Web equivalents
|
|
70
70
|
|
|
71
|
-
Agent defaults tab (`/p/0/agent-defaults`): same CRUD — "New" (POST `/agents/vault`), per-card "Edit" (PATCH `/agents/vault/:slug`, copy-on-write for bundled), "Delete"/"Hide" (DELETE), "Show removed" toggle with "Restore" button.
|
|
71
|
+
Agent defaults tab (`/p/0/agent-defaults`): same CRUD — "New" (POST `/api/agents/vault`), per-card "Edit" (PATCH `/api/agents/vault/:slug`, copy-on-write for bundled), "Delete"/"Hide" (DELETE), "Show removed" toggle with "Restore" button.
|
|
72
72
|
|
|
73
73
|
## Which agent to use
|
|
74
74
|
|
|
@@ -107,7 +107,7 @@ is_master: false
|
|
|
107
107
|
|---|---|
|
|
108
108
|
| `role` | Shown in CLI/web; appears as "Role: …" in prompt. |
|
|
109
109
|
| `model` | Default model for engine routing. |
|
|
110
|
-
| `description` | Shown in `/agents/vault` and AgentDefaultsTab cards. |
|
|
110
|
+
| `description` | Shown in `/api/agents/vault` and AgentDefaultsTab cards. |
|
|
111
111
|
| `language` | Adds "Default language: <code>" to system prompt. |
|
|
112
112
|
| `skills` | Per-agent skill names; bodies loaded by skill resolution. |
|
|
113
113
|
| `tools` | Tool hints; actual callable tools depend on invocation surface. |
|
|
@@ -113,9 +113,9 @@ install. Check the real number with `apx profile show <id>` or
|
|
|
113
113
|
|
|
114
114
|
## HTTP
|
|
115
115
|
|
|
116
|
-
`GET /profiles` · `GET /profiles/:id` (includes `preview`) · `GET /profiles/doctor` ·
|
|
117
|
-
`POST /profiles/install` · `POST /profiles/use` · `POST /profiles/off` ·
|
|
118
|
-
`PATCH /profiles/config` · `DELETE /profiles/:id`
|
|
116
|
+
`GET /api/profiles` · `GET /api/profiles/:id` (includes `preview`) · `GET /api/profiles/doctor` ·
|
|
117
|
+
`POST /api/profiles/install` · `POST /api/profiles/use` · `POST /api/profiles/off` ·
|
|
118
|
+
`PATCH /api/profiles/config` · `DELETE /api/profiles/:id`
|
|
119
119
|
|
|
120
120
|
## Gotchas
|
|
121
121
|
|
|
@@ -36,7 +36,7 @@ apx project config unset <project> super_agent.model # back to glo
|
|
|
36
36
|
apx project config edit <project> # opens $EDITOR on project_only JSON
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Every `project config` write triggers `POST /admin/reload` so the daemon picks up changes without restart.
|
|
39
|
+
Every `project config` write triggers `POST /api/admin/reload` so the daemon picks up changes without restart.
|
|
40
40
|
|
|
41
41
|
## `<project>` argument resolution
|
|
42
42
|
|
|
@@ -79,14 +79,14 @@ apx task drop t_abc # "no longer needed; archive without completion"
|
|
|
79
79
|
## Endpoint surface
|
|
80
80
|
|
|
81
81
|
```
|
|
82
|
-
GET /projects/:pid/tasks ?state=open|done|dropped|all&tag=X&agent=Y&due_before=ISO&limit=N
|
|
83
|
-
POST /projects/:pid/tasks { title, body?, tags?, due?, agent?, source?, meta? }
|
|
84
|
-
GET /projects/:pid/tasks/:id
|
|
85
|
-
PATCH /projects/:pid/tasks/:id { patch: {...} }
|
|
86
|
-
POST /projects/:pid/tasks/:id/done { by? }
|
|
87
|
-
POST /projects/:pid/tasks/:id/drop { by? }
|
|
88
|
-
POST /projects/:pid/tasks/:id/reopen
|
|
89
|
-
GET /projects/:pid/tasks-summary → { open, done, dropped, overdue, total }
|
|
82
|
+
GET /api/projects/:pid/tasks ?state=open|done|dropped|all&tag=X&agent=Y&due_before=ISO&limit=N
|
|
83
|
+
POST /api/projects/:pid/tasks { title, body?, tags?, due?, agent?, source?, meta? }
|
|
84
|
+
GET /api/projects/:pid/tasks/:id
|
|
85
|
+
PATCH /api/projects/:pid/tasks/:id { patch: {...} }
|
|
86
|
+
POST /api/projects/:pid/tasks/:id/done { by? }
|
|
87
|
+
POST /api/projects/:pid/tasks/:id/drop { by? }
|
|
88
|
+
POST /api/projects/:pid/tasks/:id/reopen
|
|
89
|
+
GET /api/projects/:pid/tasks-summary → { open, done, dropped, overdue, total }
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
## Don't
|
|
@@ -71,17 +71,17 @@ apx telegram send "text" --chat 123456789
|
|
|
71
71
|
apx telegram send "text" --interrupt # bypass pending-agent queue (also: --force)
|
|
72
72
|
|
|
73
73
|
# Media (daemon HTTP API — no dedicated CLI subcommand yet)
|
|
74
|
-
curl -X POST http://127.0.0.1:7430/telegram/send_photo \
|
|
74
|
+
curl -X POST http://127.0.0.1:7430/api/telegram/send_photo \
|
|
75
75
|
-H "Authorization: Bearer $(cat ~/.apx/daemon.token)" \
|
|
76
76
|
-H "Content-Type: application/json" \
|
|
77
77
|
-d '{"photo":"/abs/path.png","caption":"...","channel":"clientes"}'
|
|
78
|
-
curl -X POST http://127.0.0.1:7430/telegram/send_voice \
|
|
78
|
+
curl -X POST http://127.0.0.1:7430/api/telegram/send_voice \
|
|
79
79
|
-H "Authorization: Bearer $(cat ~/.apx/daemon.token)" \
|
|
80
80
|
-H "Content-Type: application/json" \
|
|
81
81
|
-d '{"audio":"/abs/path.ogg","duration":5,"channel":"default"}'
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Every `channel` CRUD write triggers `POST /admin/reload` so polling picks up the new wiring without restart.
|
|
84
|
+
Every `channel` CRUD write triggers `POST /api/admin/reload` so polling picks up the new wiring without restart.
|
|
85
85
|
|
|
86
86
|
## What "pin to project" does
|
|
87
87
|
|
|
@@ -92,7 +92,7 @@ On a message to a channel with `project: "iacrmar"`:
|
|
|
92
92
|
|
|
93
93
|
## What "master agent" does
|
|
94
94
|
|
|
95
|
-
With `route_to_agent: "reviewer"`, messages go through `/projects/:pid/agents/reviewer/chat` instead of `/super-agent/chat`. The agent's `AGENT.md` + memory is used. No tools (project agents are `exec_agent`-shaped — text in, text out). Single LLM call. Use this for persona channels (reviewer, sales, support) instead of the general assistant. Empty = super-agent (default).
|
|
95
|
+
With `route_to_agent: "reviewer"`, messages go through `/api/projects/:pid/agents/reviewer/chat` instead of `/api/super-agent/chat`. The agent's `AGENT.md` + memory is used. No tools (project agents are `exec_agent`-shaped — text in, text out). Single LLM call. Use this for persona channels (reviewer, sales, support) instead of the general assistant. Empty = super-agent (default).
|
|
96
96
|
|
|
97
97
|
## Anti-examples
|
|
98
98
|
|
|
@@ -117,16 +117,16 @@ apx voice say "Hello from APX" --provider gemini
|
|
|
117
117
|
|
|
118
118
|
## Unified voice channel
|
|
119
119
|
|
|
120
|
-
`POST /voice/turn` is one round-trip: send audio (or text), get back `{ user_text, reply_text, reply_audio_path }`. STT in, agent loop, TTS out. For overlay and future "voice room" clients.
|
|
120
|
+
`POST /api/voice/turn` is one round-trip: send audio (or text), get back `{ user_text, reply_text, reply_audio_path }`. STT in, agent loop, TTS out. For overlay and future "voice room" clients.
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
curl -X POST http://127.0.0.1:7430/voice/turn \
|
|
123
|
+
curl -X POST http://127.0.0.1:7430/api/voice/turn \
|
|
124
124
|
-H "Authorization: Bearer $(cat ~/.apx/daemon.token)" \
|
|
125
125
|
-H "Content-Type: application/json" \
|
|
126
126
|
-d '{"text":"Hello APX","channel":"voice"}'
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
Telegram voice messages and overlay mascot still have their own STT pipelines — they don't go through `/voice/turn` yet.
|
|
129
|
+
Telegram voice messages and overlay mascot still have their own STT pipelines — they don't go through `/api/voice/turn` yet.
|
|
130
130
|
|
|
131
131
|
## Anti-examples
|
|
132
132
|
|
|
@@ -146,4 +146,4 @@ Telegram voice messages and overlay mascot still have their own STT pipelines
|
|
|
146
146
|
|
|
147
147
|
- Paste base64 audio into chat. Use file paths or `send_voice` / `send_audio`.
|
|
148
148
|
- Switch providers mid-routine without testing — quality varies a lot across Piper voices and cloud engines.
|
|
149
|
-
- Expect TTS streaming yet — `apx voice say` returns a complete file. `/tts/stream` is open work.
|
|
149
|
+
- Expect TTS streaming yet — `apx voice say` returns a complete file. `/api/tts/stream` is open work.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Best-effort detection of installed agent CLIs and LLM runners.
|
|
2
2
|
// We just probe the binary with `--version` (or equivalent) and don't fail if
|
|
3
3
|
// it isn't there — caller decides what to do with absence.
|
|
4
|
-
import { runProcess } from "
|
|
5
|
-
import { resolveAntigravityCli } from "
|
|
4
|
+
import { runProcess } from "./_spawn.js";
|
|
5
|
+
import { resolveAntigravityCli } from "./antigravity.js";
|
|
6
6
|
|
|
7
7
|
const PROBES = [
|
|
8
8
|
// Coding-agent CLIs (runtimes/)
|