mixdog 1.2.6 → 1.3.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/LICENSES/simple-icons-CC0-1.0.txt +30 -0
- package/NOTICE.md +71 -9
- package/package.json +4 -1
- package/scripts/check-model-recommendations.mjs +89 -0
- package/scripts/gate-local.mjs +7 -0
- package/scripts/lib/isolated-test-env.mjs +16 -0
- package/src/agents/reviewer/AGENT.md +4 -2
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +10 -0
- package/src/defaults/skills/browser-use/SKILL.md +5 -0
- package/src/defaults/skills/memory-management/SKILL.md +4 -1
- package/src/defaults/skills/setup/references/actions.md +14 -4
- package/src/defaults/skills/setup-guide/SKILL.md +178 -0
- package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
- package/src/lib/rules-builder.cjs +55 -6
- package/src/output-styles/common.md +13 -8
- package/src/rules/agent/AGENT.md +4 -0
- package/src/rules/agent-mode/AGENT_MODE.md +24 -0
- package/src/rules/agent-mode/MIXY.md +28 -0
- package/src/rules/agent-mode/ROUTINE.md +6 -0
- package/src/rules/lead/LEAD.md +7 -3
- package/src/rules/shared/70-delivery.md +3 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +241 -14
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +4 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +216 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -4
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +115 -11
- package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
- package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +10 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +7 -8
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +14 -2
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +96 -1
- package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +14 -0
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +21 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +40 -7
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +52 -20
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +166 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +650 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +108 -6
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +74 -15
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +33 -24
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +58 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +86 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +329 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +28 -9
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +58 -10
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +92 -15
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +25 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +75 -57
- package/src/runtime/attachments/store.mjs +6 -0
- package/src/runtime/browser-bridge/client.mjs +24 -0
- package/src/runtime/channels/lib/scheduler.mjs +40 -12
- package/src/runtime/channels/lib/schedules-db.mjs +71 -12
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
- package/src/runtime/channels/lib/webhook.mjs +0 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
- package/src/runtime/channels/lib/worker-main.mjs +17 -20
- package/src/runtime/computer-bridge/client.mjs +28 -1
- package/src/runtime/connectors/gmail-app-password.mjs +690 -0
- package/src/runtime/connectors/google-mcp.mjs +446 -0
- package/src/runtime/effort-judge/judge-client.mjs +1 -1
- package/src/runtime/effort-judge/model-manifest.json +7 -7
- package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
- package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
- package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
- package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
- package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
- package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
- package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
- package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
- package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
- package/src/runtime/memory/lib/memory.mjs +7 -1
- package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
- package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
- package/src/runtime/memory/lib/tool-call-handler.mjs +2 -0
- package/src/runtime/memory/tool-defs.mjs +5 -0
- package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
- package/src/runtime/shared/agent-avatar.d.mts +64 -0
- package/src/runtime/shared/agent-avatar.mjs +320 -0
- package/src/runtime/shared/agent-kind.mjs +152 -0
- package/src/runtime/shared/agent-route-config.d.mts +4 -0
- package/src/runtime/shared/agent-route-config.mjs +30 -0
- package/src/runtime/shared/agent-store.mjs +132 -0
- package/src/runtime/shared/atomic-file.mjs +14 -1
- package/src/runtime/shared/bot-split-migration.mjs +457 -0
- package/src/runtime/shared/config-patch.mjs +20 -1
- package/src/runtime/shared/config.mjs +8 -1
- package/src/runtime/shared/connector-accounts.mjs +15 -0
- package/src/runtime/shared/connector-catalog.d.mts +51 -0
- package/src/runtime/shared/connector-catalog.mjs +228 -0
- package/src/runtime/shared/connector-triggers.d.mts +3 -0
- package/src/runtime/shared/connector-triggers.mjs +45 -0
- package/src/runtime/shared/err-text.mjs +3 -1
- package/src/runtime/shared/error-presentation.mjs +91 -6
- package/src/runtime/shared/google-oauth-client.mjs +24 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
- package/src/runtime/shared/handoff-artifacts.mjs +61 -0
- package/src/runtime/shared/held-request-host.d.mts +12 -0
- package/src/runtime/shared/held-request-host.mjs +71 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
- package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
- package/src/runtime/shared/model-route-fallback.mjs +79 -7
- package/src/runtime/shared/plain-preview.d.mts +1 -0
- package/src/runtime/shared/plain-preview.mjs +33 -0
- package/src/runtime/shared/routine-limits.d.mts +11 -0
- package/src/runtime/shared/routine-limits.mjs +21 -0
- package/src/runtime/shared/routine-trigger.d.mts +10 -0
- package/src/runtime/shared/routine-trigger.mjs +44 -0
- package/src/runtime/shared/schedule-model-ref.mjs +9 -10
- package/src/runtime/shared/sensitive-path-rules.d.mts +15 -0
- package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
- package/src/runtime/shared/slow-span.mjs +4 -12
- package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
- package/src/runtime/shared/transcript-metadata.mjs +10 -0
- package/src/runtime/shared/turn-changes.mjs +0 -8
- package/src/runtime/shared/usage-readout-totals.mjs +58 -0
- package/src/runtime/shared/user-data-guard.mjs +119 -38
- package/src/session-runtime/agent-home-delivery.mjs +826 -0
- package/src/session-runtime/agent-profile-changes.mjs +21 -0
- package/src/session-runtime/agent-room-delivery.mjs +133 -0
- package/src/session-runtime/agent-task-sessions.mjs +460 -0
- package/src/session-runtime/boot/apis.mjs +63 -18
- package/src/session-runtime/boot/facade.mjs +5 -8
- package/src/session-runtime/boot/infrastructure.mjs +28 -17
- package/src/session-runtime/boot/providers.mjs +14 -4
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +53 -5
- package/src/session-runtime/config-lifecycle.mjs +43 -2
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
- package/src/session-runtime/handoff-attachments.mjs +593 -0
- package/src/session-runtime/held-requests.mjs +228 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +56 -3
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +4 -0
- package/src/session-runtime/lifecycle/shared.mjs +6 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
- package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +112 -15
- package/src/session-runtime/model-route/route-persist.mjs +2 -2
- package/src/session-runtime/model-route/route-tuning.mjs +7 -1
- package/src/session-runtime/model-route/set-route.mjs +35 -4
- package/src/session-runtime/native-web-search.mjs +2 -2
- package/src/session-runtime/new-session-config.mjs +6 -1
- package/src/session-runtime/owned-automation-run.mjs +229 -0
- package/src/session-runtime/resource-api.mjs +5 -0
- package/src/session-runtime/resource-mcp-api.mjs +107 -13
- package/src/session-runtime/resource-skills-api.mjs +12 -0
- package/src/session-runtime/room-member-gate.mjs +48 -0
- package/src/session-runtime/route-resolution.mjs +5 -11
- package/src/session-runtime/routine-home-turn.mjs +156 -0
- package/src/session-runtime/routine-owner.mjs +48 -0
- package/src/session-runtime/schedule-session-run.mjs +30 -64
- package/src/session-runtime/services/agent-tool/helpers.mjs +30 -1
- package/src/session-runtime/services/agent-tool/send-flow.mjs +11 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- package/src/session-runtime/services/channel-admin.mjs +93 -24
- package/src/session-runtime/services/memory-access.mjs +37 -0
- package/src/session-runtime/services/provider-admin.mjs +74 -39
- package/src/session-runtime/services/schedule-access.mjs +91 -0
- package/src/session-runtime/session-create/session-options.mjs +34 -7
- package/src/session-runtime/session-hooks.mjs +16 -8
- package/src/session-runtime/setup-tool/executor.mjs +79 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +90 -20
- package/src/session-runtime/setup-tool/settings-contract.mjs +14 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
- package/src/session-runtime/skills-api.mjs +16 -1
- package/src/session-runtime/tool-policy-refresh.mjs +249 -29
- package/src/session-runtime/turn/session-ops.mjs +8 -1
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +10 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +14 -0
- package/src/session-runtime/webhook-session-run.mjs +49 -67
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +650 -25
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +67 -7
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
- package/src/session-runtime/workflow-agents-api.mjs +4 -1
- package/src/standalone/daemon-agent-control.mjs +1 -8
- package/src/standalone/daemon-session-control.mjs +21 -4
- package/src/standalone/daemon.mjs +31 -5
- package/src/standalone/session-protocol.mjs +27 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
- package/src/standalone/session-service/agent-tree.mjs +4 -3
- package/src/standalone/session-service/session-calls/session-turns.mjs +28 -0
- package/src/standalone/session-service.mjs +19 -0
- package/src/tui/app/slash-commands.mjs +20 -0
- package/src/tui/dist/index.mjs +234 -95
- package/src/tui/session/context-state.mjs +6 -1
- package/src/tui/session/notice-surface.mjs +34 -4
- package/src/tui/session/queue-helpers.mjs +2 -1
- package/src/tui/session/session-api/extensions.mjs +4 -0
- package/src/tui/session/session-api/intake/submission.mjs +5 -0
- package/src/tui/session/session-api/integrations.mjs +8 -0
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
- package/src/tui/session/session-api/lifecycle.mjs +17 -1
- package/src/tui/session/session-api/routes.mjs +61 -5
- package/src/tui/session/session-flow/drain.mjs +12 -3
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
- package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
- package/src/tui/session/session-flow/steering.mjs +58 -24
- package/src/tui/session/tool-approval.mjs +26 -5
- package/src/tui/session/transcript-intake.mjs +8 -2
- package/src/tui/session/transcript-spill.mjs +5 -1
- package/src/tui/session/tui-steering-persist.mjs +65 -42
- package/src/tui/session/turn-live-call.mjs +64 -0
- package/src/tui/session/turn.mjs +34 -8
- package/src/session-runtime/automation-agents.mjs +0 -94
- package/src/session-runtime/automation-workflow.mjs +0 -59
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
import { PRESET_ALIASES } from './tool-def.mjs';
|
|
13
13
|
import { positiveInt } from '../../../runtime/shared/numbers.mjs';
|
|
14
14
|
import { clean } from '../../../runtime/shared/clean.mjs';
|
|
15
|
+
import { readAgentDefinitionKind } from '../../../runtime/shared/agent-kind.mjs';
|
|
16
|
+
import { isStoreBot, userDefinitionDir } from '../../../runtime/shared/agent-store.mjs';
|
|
15
17
|
import { normalizeContextTokens } from '../../../runtime/shared/llm/default-context-window.mjs';
|
|
16
18
|
|
|
17
19
|
export { positiveInt };
|
|
@@ -300,13 +302,18 @@ const _frontmatterPermCache = new Map(); // key -> { value, atMs }
|
|
|
300
302
|
const FRONTMATTER_PERM_CACHE_TTL_MS = envTimeoutMs('MIXDOG_AGENT_FRONTMATTER_TTL_MS', 5_000);
|
|
301
303
|
|
|
302
304
|
function agentDeleted(cleanAgent, dataDir) {
|
|
303
|
-
return Boolean(dataDir) && existsSync(join(dataDir,
|
|
305
|
+
return Boolean(dataDir) && existsSync(join(userDefinitionDir(dataDir, cleanAgent), '.deleted'));
|
|
304
306
|
}
|
|
305
307
|
|
|
306
308
|
/** Where an agent's definition may live, in precedence order: the data dir
|
|
307
309
|
* (user/custom agents) before the shipped source root. */
|
|
308
310
|
function agentDefinitionFiles(cleanAgent, dataDir, standaloneSourceRoot) {
|
|
309
311
|
const candidates = [];
|
|
312
|
+
if (dataDir && isStoreBot(dataDir, cleanAgent)) {
|
|
313
|
+
// A bot of the store: only its own folder (never the agents/ original).
|
|
314
|
+
candidates.push(join(userDefinitionDir(dataDir, cleanAgent), 'AGENT.md'));
|
|
315
|
+
return candidates;
|
|
316
|
+
}
|
|
310
317
|
if (dataDir) {
|
|
311
318
|
candidates.push(join(dataDir, 'agents', cleanAgent, 'AGENT.md'));
|
|
312
319
|
candidates.push(join(dataDir, 'agents', `${cleanAgent}.md`));
|
|
@@ -352,6 +359,28 @@ export function readAgentFrontmatterPermission(agent, dataDir, standaloneSourceR
|
|
|
352
359
|
);
|
|
353
360
|
}
|
|
354
361
|
|
|
362
|
+
const _frontmatterKindCache = new Map(); // key -> { value, atMs }
|
|
363
|
+
const _frontmatterKindValueCache = new Map(); // key -> { value, atMs }
|
|
364
|
+
|
|
365
|
+
/** The agent definition's kind (isContactAgentId reads it), by the one
|
|
366
|
+
* read-only rule (agent-kind.mjs), cached per agent for the frontmatter TTL. */
|
|
367
|
+
export function readAgentFrontmatterKind(agent, dataDir, standaloneSourceRoot) {
|
|
368
|
+
const id = clean(agent);
|
|
369
|
+
if (!id || agentDeleted(id, dataDir)) return null;
|
|
370
|
+
const cacheKey = `${dataDir}\u0000${id}`;
|
|
371
|
+
const cached = _frontmatterKindCache.get(cacheKey);
|
|
372
|
+
if (cached && Date.now() - cached.atMs < FRONTMATTER_PERM_CACHE_TTL_MS) return cached.value;
|
|
373
|
+
// An explicit kind in the definition in effect (any layout) wins; only an
|
|
374
|
+
// unmarked user copy goes to the evidence rule.
|
|
375
|
+
const explicit = cachedFrontmatterValue(_frontmatterKindValueCache, id, dataDir, standaloneSourceRoot, (fm) =>
|
|
376
|
+
typeof fm.kind === 'string' && fm.kind.trim() ? fm.kind.trim().toLowerCase() : null
|
|
377
|
+
);
|
|
378
|
+
const value =
|
|
379
|
+
explicit || (dataDir ? readAgentDefinitionKind({ dataDir, shippedRoot: standaloneSourceRoot, id }) : null);
|
|
380
|
+
_frontmatterKindCache.set(cacheKey, { value, atMs: Date.now() });
|
|
381
|
+
return value;
|
|
382
|
+
}
|
|
383
|
+
|
|
355
384
|
/** The agent definition's `firstResponseTimeoutMs` (a non-negative integer;
|
|
356
385
|
* 0 disables the first-response deadline), or null when it sets none. */
|
|
357
386
|
export function readAgentFirstResponseTimeoutMs(agent, dataDir, standaloneSourceRoot) {
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
terminalResultHook,
|
|
17
17
|
} from './job-task-reconcile.mjs';
|
|
18
18
|
import { createTurnReviewCollector } from './turn-review.mjs';
|
|
19
|
+
import { handoffContent } from '../../handoff-attachments.mjs';
|
|
19
20
|
import { settledWorkerStatus } from './worker-index/row-liveness.mjs';
|
|
20
21
|
|
|
21
22
|
// `send` to an existing worker: resolve the live session, run one follow-up
|
|
@@ -69,8 +70,10 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
69
70
|
return hooks;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
function runTurn({ session, sessionId, prompt, args }, turnHooks) {
|
|
73
|
+
function runTurn({ session, sessionId, prompt: text, args }, turnHooks) {
|
|
73
74
|
const cwd = session.cwd || defaultCwd;
|
|
75
|
+
// The caller's forwarded files ride along as attachment parts.
|
|
76
|
+
const prompt = handoffContent(text, args.attachmentParts);
|
|
74
77
|
if (canUseSessionSurface(session)) {
|
|
75
78
|
return sessionSurface.runTurn({ session, prompt, context: args.context || null, cwd, ...turnHooks });
|
|
76
79
|
}
|
|
@@ -194,7 +197,11 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
194
197
|
const { session, sessionId, prompt } = prepared;
|
|
195
198
|
const tag = registry.tagForSession(sessionId);
|
|
196
199
|
if (canUseSessionSurface(session) && views.isSessionBusy(sessionId)) {
|
|
197
|
-
const queued = await sessionSurface.enqueueTurn({
|
|
200
|
+
const queued = await sessionSurface.enqueueTurn({
|
|
201
|
+
session,
|
|
202
|
+
prompt: handoffContent(prompt, prepared.args.attachmentParts),
|
|
203
|
+
context: prepared.args.context || null,
|
|
204
|
+
});
|
|
198
205
|
if (queued) {
|
|
199
206
|
return renderResult({ queued: true, ...extras, tag, sessionId, agent: session.agent || null, ...queued });
|
|
200
207
|
}
|
|
@@ -204,7 +211,8 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
204
211
|
views.isSessionBusy(sessionId) &&
|
|
205
212
|
typeof mgr.enqueuePendingMessage === 'function'
|
|
206
213
|
) {
|
|
207
|
-
|
|
214
|
+
// The queued follow-up keeps the forwarded files, as the canonical queue does.
|
|
215
|
+
const queueDepth = mgr.enqueuePendingMessage(sessionId, handoffContent(prompt, prepared.args.attachmentParts));
|
|
208
216
|
return renderResult({ queued: true, ...extras, tag, sessionId, agent: session.agent || null, queueDepth });
|
|
209
217
|
}
|
|
210
218
|
const job = spawnFlow.startJob(
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
agentDefinitionExists,
|
|
10
10
|
clean,
|
|
11
11
|
normalizeAgentName,
|
|
12
|
+
readAgentFrontmatterKind,
|
|
12
13
|
readAgentFrontmatterPermission,
|
|
13
14
|
resolvePrompt,
|
|
14
15
|
terminalPidForContext,
|
|
@@ -18,8 +19,13 @@ import { normalizeAgentPermission } from '../../../../runtime/shared/markdown-fr
|
|
|
18
19
|
import { resolveAgentSpawnPreset } from '../spawn-preset.mjs';
|
|
19
20
|
import { AGENT_OWNER } from '../../../../runtime/agent/orchestrator/agent-owner.mjs';
|
|
20
21
|
import { workspaceCwdLock } from '../../../workspace/admission-gate.mjs';
|
|
22
|
+
import { isContactAgentId } from '../../../../runtime/agent/orchestrator/runtime-core/workflow-ids.mjs';
|
|
23
|
+
import { AGENT_MODE, resolveSessionMode } from '../../../../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
24
|
+
import { MIXY_AGENT_ID } from '../../../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
25
|
+
import { mixyDisplayName } from '../../../../runtime/agent/orchestrator/session/mixy-name.mjs';
|
|
21
26
|
|
|
22
27
|
export function createSpawnPlanner({
|
|
28
|
+
mgr = null,
|
|
23
29
|
cfgMod,
|
|
24
30
|
dataDir,
|
|
25
31
|
STANDALONE_SOURCE_ROOT,
|
|
@@ -44,6 +50,18 @@ export function createSpawnPlanner({
|
|
|
44
50
|
if (isAgentDisabled(config, agent)) {
|
|
45
51
|
throw new Error(`agent spawn: agent "${agent}" is turned off`);
|
|
46
52
|
}
|
|
53
|
+
// Only Mixy hands work to a contact agent; any other agent-mode Lead
|
|
54
|
+
// delegates to sub-agents alone (its catalog lists no contact either).
|
|
55
|
+
if (isContactAgentId(agent, readAgentFrontmatterKind(agent, dataDir, STANDALONE_SOURCE_ROOT))) {
|
|
56
|
+
const callerId = clean(context?.callerSessionId || context?.sessionId);
|
|
57
|
+
const caller = (callerId && mgr?.getSession?.(callerId)) || null;
|
|
58
|
+
const { mode, agentId } = resolveSessionMode({ session: caller, sessionId: callerId });
|
|
59
|
+
if (mode === AGENT_MODE && agentId !== MIXY_AGENT_ID) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`agent spawn: only ${mixyDisplayName()} (the representative agent) can hand work to the contact agent "${agent}"; delegate to a sub-agent instead`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
47
65
|
const agentPermission = readAgentFrontmatterPermission(agent, dataDir, STANDALONE_SOURCE_ROOT);
|
|
48
66
|
const agentPerm = normalizeAgentPermission(agentPermission) || null;
|
|
49
67
|
const { presetName, preset } = resolveAgentSpawnPreset(config, args);
|
|
@@ -56,10 +74,7 @@ export function createSpawnPlanner({
|
|
|
56
74
|
// Workers share their Lead's execution root. While the Lead runs in its
|
|
57
75
|
// worktree, that root is locked: neither args.cwd nor an inherited
|
|
58
76
|
// (pre-transition) cwd can send a worker elsewhere.
|
|
59
|
-
const lockedCwd = workspaceCwdLock([
|
|
60
|
-
context?.ownerSessionId,
|
|
61
|
-
context?.callerSessionId || context?.sessionId,
|
|
62
|
-
]);
|
|
77
|
+
const lockedCwd = workspaceCwdLock([context?.ownerSessionId, context?.callerSessionId || context?.sessionId]);
|
|
63
78
|
const baseCwd = resolve(lockedCwd || callerCwd || defaultCwd || process.cwd());
|
|
64
79
|
const workerCwd = !lockedCwd && clean(args.cwd) ? resolve(baseCwd, args.cwd) : baseCwd;
|
|
65
80
|
const prompt = await resolvePrompt(args, workerCwd);
|
|
@@ -58,8 +58,10 @@ export function createSpawnPreparer({
|
|
|
58
58
|
ensureProvider,
|
|
59
59
|
sessionSurface = null,
|
|
60
60
|
refreshTagsFromSessions,
|
|
61
|
+
mgr = null,
|
|
61
62
|
}) {
|
|
62
63
|
const { resolveSpawnPlan, spawnSessionSpec } = createSpawnPlanner({
|
|
64
|
+
mgr,
|
|
63
65
|
cfgMod,
|
|
64
66
|
dataDir,
|
|
65
67
|
STANDALONE_SOURCE_ROOT,
|
|
@@ -25,6 +25,7 @@ import { settledWorkerStatus } from '../worker-index/row-liveness.mjs';
|
|
|
25
25
|
import { saveSessionAsync } from '../../../../runtime/agent/orchestrator/session/store.mjs';
|
|
26
26
|
import { presetDescriptor } from './spawn-prep.mjs';
|
|
27
27
|
import { workerStageForStatus } from '../worker-rows.mjs';
|
|
28
|
+
import { handoffContent } from '../../../handoff-attachments.mjs';
|
|
28
29
|
|
|
29
30
|
// Mid-turn worker persistence cadence. The watchdog sweep runs every second;
|
|
30
31
|
// a transcript save is far more expensive than a bookkeeping stamp, so the
|
|
@@ -117,7 +118,9 @@ export function createSpawnRunner({
|
|
|
117
118
|
};
|
|
118
119
|
|
|
119
120
|
async function runTurn(prepared, turnHooks) {
|
|
120
|
-
const { args, session,
|
|
121
|
+
const { args, session, workerCwd } = prepared;
|
|
122
|
+
// The caller's forwarded files ride along as attachment parts.
|
|
123
|
+
const prompt = handoffContent(prepared.prompt, args.attachmentParts);
|
|
121
124
|
if (typeof sessionSurface?.runTurn === 'function' && sessionSurface.canRun?.(session) !== false) {
|
|
122
125
|
return sessionSurface.runTurn({ session, prompt, context: args.context || null, cwd: workerCwd, ...turnHooks });
|
|
123
126
|
}
|
|
@@ -27,11 +27,10 @@ export function resolveAgentSpawnPreset(config, args = {}) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const agentName = normalizeAgentName(args.agent);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
: null;
|
|
30
|
+
// The agent's stored route: config.agents, or a store bot's own folder.
|
|
31
|
+
const candidates = !clean(args.preset) ? configuredAgentRouteCandidates(config, agentName) : [];
|
|
32
|
+
const agentRoute = candidates.map((candidate) => normalizeAgentRoute(candidate)).find(Boolean) || null;
|
|
33
|
+
const storedFallbacks = candidates.find((candidate) => normalizeAgentRoute(candidate))?.fallbacks;
|
|
35
34
|
if (agentRoute) {
|
|
36
35
|
return {
|
|
37
36
|
presetName: agentPresetName(agentName),
|
|
@@ -41,9 +40,7 @@ export function resolveAgentSpawnPreset(config, args = {}) {
|
|
|
41
40
|
type: 'agent',
|
|
42
41
|
provider: agentRoute.provider,
|
|
43
42
|
model: agentRoute.model,
|
|
44
|
-
...(
|
|
45
|
-
? { fallbacks: config.agents[agentName].fallbacks.map(normalizeAgentRoute) }
|
|
46
|
-
: {}),
|
|
43
|
+
...(storedFallbacks?.length ? { fallbacks: storedFallbacks.map(normalizeAgentRoute) } : {}),
|
|
47
44
|
effort: agentRoute.effort,
|
|
48
45
|
fast: agentRoute.fast === true,
|
|
49
46
|
...(agentRoute.autoEffort === false ? { autoEffort: false } : {}),
|
|
@@ -53,6 +53,13 @@ export const AGENT_TOOL = {
|
|
|
53
53
|
file: { type: 'string', description: 'Path to task text; alternative to prompt/message for spawn/send.' },
|
|
54
54
|
cwd: { type: 'string', description: 'Project directory for a new or respawned agent.' },
|
|
55
55
|
context: { type: 'string', description: 'Extra context for the spawn/send turn.' },
|
|
56
|
+
attachments: {
|
|
57
|
+
type: 'array',
|
|
58
|
+
items: { type: 'string' },
|
|
59
|
+
maxItems: 8,
|
|
60
|
+
description:
|
|
61
|
+
"spawn/send: files to attach (images, PDF/Office, text): a conversation attachment's file name or [attachment:id], or a path inside your folders. Produced files come back as paths; forward them by path.",
|
|
62
|
+
},
|
|
56
63
|
model: {
|
|
57
64
|
type: 'string',
|
|
58
65
|
description:
|
|
@@ -23,13 +23,14 @@ import {
|
|
|
23
23
|
setEndpointEnabled as dbSetEndpointEnabled,
|
|
24
24
|
} from '../../runtime/channels/lib/webhooks-db.mjs';
|
|
25
25
|
import { normalizeAutomationAttachments } from '../../runtime/shared/automation-attachments.mjs';
|
|
26
|
-
import {
|
|
26
|
+
import { assertRoutineOwner, routineOwnerProblem } from '../routine-owner.mjs';
|
|
27
27
|
import { hasEnabledAutomation } from '../../runtime/shared/automation-presence.mjs';
|
|
28
28
|
import { resolveScheduleTimezone, validateScheduleCron } from '../../runtime/shared/schedule-time.mjs';
|
|
29
29
|
import { pgClusterExists } from '../../runtime/memory/lib/pg/adapter.mjs';
|
|
30
30
|
import { resolvePluginData } from '../../runtime/shared/plugin-paths.mjs';
|
|
31
31
|
import { readHookPublicBase } from '../../runtime/channels/lib/webhook/relay-tunnel.mjs';
|
|
32
32
|
import { WEBHOOK_TEST_FIELD, WEBHOOK_TEST_HEADER } from '../../runtime/channels/lib/webhook/request-handler.mjs';
|
|
33
|
+
import { MIXY_AGENT_ID, agentHomeSessionId } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
33
34
|
|
|
34
35
|
const NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
35
36
|
|
|
@@ -187,7 +188,7 @@ function parseAtDatetime(at) {
|
|
|
187
188
|
// Map the store's def shape onto the flat display shape every schedule reader
|
|
188
189
|
// (channelSetup, renderChannelStatus, TUI pickers) consumes: `.time` renders
|
|
189
190
|
// the cron or the one-shot datetime, `.route` the channel/session target.
|
|
190
|
-
function scheduleToDisplay(s) {
|
|
191
|
+
function scheduleToDisplay(s, ownerProblem = '') {
|
|
191
192
|
return {
|
|
192
193
|
name: s.name,
|
|
193
194
|
description: s.description || '',
|
|
@@ -195,26 +196,85 @@ function scheduleToDisplay(s) {
|
|
|
195
196
|
whenAt: s.whenAt || undefined,
|
|
196
197
|
whenCron: s.whenCron || undefined,
|
|
197
198
|
timezone: s.timezone || undefined,
|
|
198
|
-
// Shown (and re-saved by the editor) on the catalog successor of a superseded model.
|
|
199
|
-
model: s.model ? migrateCodexModelRef(s.model) : undefined,
|
|
200
199
|
cwd: s.cwd || undefined,
|
|
201
|
-
workflow: s.workflow || undefined,
|
|
202
200
|
attachments: s.attachments || undefined,
|
|
203
201
|
enabled: s.enabled !== false,
|
|
204
202
|
instructions: s.prompt,
|
|
205
203
|
route: 'session',
|
|
204
|
+
// The bot it belongs to: each run is a turn in that bot's chat.
|
|
205
|
+
owner: s.ownerAgentId || MIXY_AGENT_ID,
|
|
206
|
+
// Why it is paused for its owner (routine-owner.mjs); absent when it runs.
|
|
207
|
+
...(ownerProblem ? { ownerProblem } : {}),
|
|
208
|
+
nextFireAt: isoOrUndefined(s.nextFireAt),
|
|
209
|
+
lastSuccessAt: isoOrUndefined(s.lastSuccessAt),
|
|
210
|
+
lastFailedAt: isoOrUndefined(s.lastFailedAt),
|
|
211
|
+
lastSkippedAt: isoOrUndefined(s.lastSkippedAt),
|
|
212
|
+
...routineHealth(s),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Failures in a row (the routine pauses itself at the limit) and the results
|
|
217
|
+
// of finished runs still not queued for the owner: `{ count, failed, error }`,
|
|
218
|
+
// `failed` when the queue refused one (the app offers a retry).
|
|
219
|
+
function routineHealth(row) {
|
|
220
|
+
const entries = Object.values(row.resultDelivery || {}).filter(Boolean);
|
|
221
|
+
const refused = entries.filter((entry) => entry.state === 'failed').at(-1);
|
|
222
|
+
return {
|
|
223
|
+
consecutiveFailures: Number(row.consecutiveFailures) || 0,
|
|
224
|
+
...(entries.length
|
|
225
|
+
? {
|
|
226
|
+
undelivered: {
|
|
227
|
+
count: entries.length,
|
|
228
|
+
failed: Boolean(refused),
|
|
229
|
+
...(refused?.error ? { error: String(refused.error) } : {}),
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
: {}),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function isoOrUndefined(value) {
|
|
237
|
+
if (!value) return undefined;
|
|
238
|
+
const at = new Date(value);
|
|
239
|
+
return Number.isNaN(at.getTime()) ? undefined : at.toISOString();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// A schedule's or webhook's owner: an explicit agent id, else the saved owner
|
|
243
|
+
// on an overwrite, else Mixy.
|
|
244
|
+
function scheduleOwner(owner, existing) {
|
|
245
|
+
const value = String(owner ?? '').trim();
|
|
246
|
+
if (value) {
|
|
247
|
+
if (!agentHomeSessionId(value)) throw new Error(`schedule owner "${value}" is not a valid agent id`);
|
|
248
|
+
return value;
|
|
249
|
+
}
|
|
250
|
+
return existing?.ownerAgentId || MIXY_AGENT_ID;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Each owner's problem (routine-owner.mjs), probed once per owner. */
|
|
254
|
+
function ownerProblems() {
|
|
255
|
+
const seen = new Map();
|
|
256
|
+
return (ownerAgentId) => {
|
|
257
|
+
const owner = ownerAgentId || MIXY_AGENT_ID;
|
|
258
|
+
if (!seen.has(owner))
|
|
259
|
+
seen.set(
|
|
260
|
+
owner,
|
|
261
|
+
routineOwnerProblem(owner).catch(() => '')
|
|
262
|
+
);
|
|
263
|
+
return seen.get(owner);
|
|
206
264
|
};
|
|
207
265
|
}
|
|
208
266
|
|
|
209
267
|
export async function listSchedules() {
|
|
210
268
|
const rows = await dbListSchedules();
|
|
211
|
-
|
|
269
|
+
const problemOf = ownerProblems();
|
|
270
|
+
return Promise.all(rows.map(async (row) => scheduleToDisplay(row, await problemOf(row.ownerAgentId))));
|
|
212
271
|
}
|
|
213
272
|
|
|
214
273
|
// Register or update a schedule in the PG store. Recurring input maps `time`
|
|
215
274
|
// (+ optional `days`) to a cron; one-shot input maps an `at` datetime; the two
|
|
216
275
|
// are mutually exclusive (also enforced by the store's when_at/when_cron XOR).
|
|
217
|
-
// Every schedule runs as a
|
|
276
|
+
// Every schedule runs as a turn in its owner bot's chat; a bot that does not
|
|
277
|
+
// exist (no representative bot yet, an archived bot) cannot own one.
|
|
218
278
|
export async function saveSchedule({
|
|
219
279
|
name,
|
|
220
280
|
description = '',
|
|
@@ -222,26 +282,26 @@ export async function saveSchedule({
|
|
|
222
282
|
at,
|
|
223
283
|
timezone,
|
|
224
284
|
days,
|
|
225
|
-
model,
|
|
226
285
|
cwd,
|
|
227
|
-
workflow,
|
|
228
286
|
attachments,
|
|
229
287
|
enabled,
|
|
230
288
|
instructions,
|
|
289
|
+
owner,
|
|
231
290
|
overwrite = false,
|
|
232
291
|
} = {}) {
|
|
233
292
|
const id = assertScheduleName(name);
|
|
234
293
|
const body = String(instructions || '').trim();
|
|
235
294
|
if (!body) throw new Error('schedule instructions are required');
|
|
236
|
-
const scheduleModel = String(model || '').trim();
|
|
237
|
-
if (!scheduleModel) throw new Error('schedule model is required — choose a model before saving');
|
|
238
295
|
const hasTime = time != null && String(time).trim() !== '';
|
|
239
296
|
const hasAt = at != null && String(at).trim() !== '';
|
|
240
297
|
if (hasTime && hasAt) throw new Error('provide either `time` (recurring) or `at` (one-shot), not both');
|
|
241
298
|
if (!hasTime && !hasAt) throw new Error('either `time` (recurring cron) or `at` (one-shot datetime) is required');
|
|
242
|
-
|
|
299
|
+
const existing = await dbGetSchedule(id);
|
|
300
|
+
if (overwrite !== true && existing) {
|
|
243
301
|
throw new Error(`schedule "${id}" already exists`);
|
|
244
302
|
}
|
|
303
|
+
const ownerAgentId = scheduleOwner(owner, existing);
|
|
304
|
+
await assertRoutineOwner(ownerAgentId);
|
|
245
305
|
const whenCron = hasTime ? validateScheduleCron(foldDaysIntoCron(normalizeCron(time), days)) : null;
|
|
246
306
|
const whenAt = hasAt ? parseAtDatetime(at) : null;
|
|
247
307
|
const scheduleTimezone = hasTime ? resolveScheduleTimezone(timezone) : null;
|
|
@@ -253,14 +313,13 @@ export async function saveSchedule({
|
|
|
253
313
|
timezone: scheduleTimezone,
|
|
254
314
|
target: 'session',
|
|
255
315
|
channelId: null,
|
|
256
|
-
model: scheduleModel,
|
|
257
316
|
cwd: cwd ? String(cwd).trim() : null,
|
|
258
|
-
workflow: workflow ? String(workflow).trim() : null,
|
|
259
317
|
attachments: normalizeAutomationAttachments(attachments),
|
|
260
318
|
delivery: 'app',
|
|
261
319
|
prompt: body,
|
|
262
320
|
enabled: enabled !== false,
|
|
263
321
|
nextFireAt: whenAt,
|
|
322
|
+
ownerAgentId,
|
|
264
323
|
});
|
|
265
324
|
automationProbe.invalidate();
|
|
266
325
|
return scheduleToDisplay(saved);
|
|
@@ -287,13 +346,13 @@ export async function setScheduleEnabled(name, enabled) {
|
|
|
287
346
|
// store's migration hook.
|
|
288
347
|
async function listWebhooks() {
|
|
289
348
|
const endpoints = await dbListEndpoints();
|
|
290
|
-
|
|
349
|
+
const problemOf = ownerProblems();
|
|
350
|
+
const problems = await Promise.all(endpoints.map((ep) => problemOf(ep.ownerAgentId)));
|
|
351
|
+
return endpoints.map((ep, index) => ({
|
|
291
352
|
name: ep.name,
|
|
292
353
|
description: ep.description || '',
|
|
293
354
|
parser: ep.parser || 'github',
|
|
294
|
-
...(ep.model ? { model: migrateCodexModelRef(ep.model) } : {}),
|
|
295
355
|
...(ep.cwd ? { cwd: ep.cwd } : {}),
|
|
296
|
-
...(ep.workflow ? { workflow: ep.workflow } : {}),
|
|
297
356
|
...(ep.attachments ? { attachments: ep.attachments } : {}),
|
|
298
357
|
enabled: ep.enabled,
|
|
299
358
|
// The store never projects the plaintext secret through list paths; it
|
|
@@ -302,6 +361,16 @@ async function listWebhooks() {
|
|
|
302
361
|
secret: undefined,
|
|
303
362
|
instructions: ep.instructions,
|
|
304
363
|
route: 'session',
|
|
364
|
+
// The bot it belongs to: each run is a turn in that bot's chat.
|
|
365
|
+
owner: ep.ownerAgentId || MIXY_AGENT_ID,
|
|
366
|
+
...(problems[index] ? { ownerProblem: problems[index] } : {}),
|
|
367
|
+
lastEventAt: isoOrUndefined(ep.lastEventAt),
|
|
368
|
+
lastSuccessAt: isoOrUndefined(ep.lastSuccessAt),
|
|
369
|
+
lastFailedAt: isoOrUndefined(ep.lastFailedAt),
|
|
370
|
+
lastSkippedAt: isoOrUndefined(ep.lastSkippedAt),
|
|
371
|
+
// Whether "Run now" has a received payload to re-run (never the payload).
|
|
372
|
+
hasLastPayload: ep.hasLastPayload === true,
|
|
373
|
+
...routineHealth(ep),
|
|
305
374
|
}));
|
|
306
375
|
}
|
|
307
376
|
|
|
@@ -310,12 +379,11 @@ export async function saveWebhook({
|
|
|
310
379
|
description = '',
|
|
311
380
|
parser = 'github',
|
|
312
381
|
secret,
|
|
313
|
-
model,
|
|
314
382
|
cwd,
|
|
315
|
-
workflow,
|
|
316
383
|
attachments,
|
|
317
384
|
enabled,
|
|
318
385
|
instructions,
|
|
386
|
+
owner,
|
|
319
387
|
overwrite = false,
|
|
320
388
|
} = {}) {
|
|
321
389
|
const id = assertName(name, 'webhook name');
|
|
@@ -327,9 +395,12 @@ export async function saveWebhook({
|
|
|
327
395
|
}
|
|
328
396
|
const body = String(instructions || '').trim();
|
|
329
397
|
if (!body) throw new Error('webhook instructions are required');
|
|
330
|
-
|
|
398
|
+
const existing = await dbLoadEndpoint(id);
|
|
399
|
+
if (overwrite !== true && existing) {
|
|
331
400
|
throw new Error(`webhook "${id}" already exists`);
|
|
332
401
|
}
|
|
402
|
+
const ownerAgentId = scheduleOwner(owner, existing);
|
|
403
|
+
await assertRoutineOwner(ownerAgentId);
|
|
333
404
|
// Secret semantics: an explicit value always wins; an EMPTY value on an
|
|
334
405
|
// overwrite PRESERVES the stored secret (editing instructions must not
|
|
335
406
|
// silently rotate the key the external service was configured with); only
|
|
@@ -343,23 +414,21 @@ export async function saveWebhook({
|
|
|
343
414
|
description: String(description || '').trim(),
|
|
344
415
|
parser: nextParser,
|
|
345
416
|
channelId: null,
|
|
346
|
-
model: model ? String(model).trim() : null,
|
|
347
417
|
cwd: cwd ? String(cwd).trim() : null,
|
|
348
|
-
workflow: workflow ? String(workflow).trim() : null,
|
|
349
418
|
attachments: normalizeAutomationAttachments(attachments),
|
|
350
419
|
delivery: 'app',
|
|
351
420
|
secret: secretValue,
|
|
352
421
|
instructions: body,
|
|
353
422
|
enabled: enabled !== false,
|
|
423
|
+
ownerAgentId,
|
|
354
424
|
});
|
|
355
425
|
automationProbe.invalidate();
|
|
356
426
|
return {
|
|
357
427
|
name: id,
|
|
428
|
+
owner: saved.ownerAgentId || ownerAgentId,
|
|
358
429
|
description: saved.description,
|
|
359
430
|
parser: saved.parser,
|
|
360
|
-
...(saved.model ? { model: saved.model } : {}),
|
|
361
431
|
...(saved.cwd ? { cwd: saved.cwd } : {}),
|
|
362
|
-
...(saved.workflow ? { workflow: saved.workflow } : {}),
|
|
363
432
|
...(saved.attachments ? { attachments: saved.attachments } : {}),
|
|
364
433
|
...(enabled === false ? { enabled: false } : {}),
|
|
365
434
|
secret: secretValue,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Whose memory a session reads and writes (runtime/memory/lib/
|
|
2
|
+
// core-memory-access.mjs enforces it). Mixy is the Lead configuration, so the
|
|
3
|
+
// user's own sessions (an ordinary Lead session, Mixy's home) act as Mixy; an
|
|
4
|
+
// agent's home thread and its room member sessions act as that agent; a
|
|
5
|
+
// schedule or webhook run acts for its owning agent (`ownerAgentId`, stamped
|
|
6
|
+
// at creation); a delegated agent as its own agent id.
|
|
7
|
+
import { MIXY_AGENT_ID, agentHomeSessionId } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
8
|
+
import { resolveSessionMode } from '../../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
9
|
+
import { isAgentOwner } from '../../runtime/agent/orchestrator/agent-owner.mjs';
|
|
10
|
+
import { scheduleCallerScope } from './schedule-access.mjs';
|
|
11
|
+
|
|
12
|
+
const validAgentId = (value) => {
|
|
13
|
+
const id = typeof value === 'string' ? value.trim() : '';
|
|
14
|
+
return id && agentHomeSessionId(id) ? id : '';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** The `memory_caller` `{ kind, agentId }` of a calling session record:
|
|
18
|
+
* 'human' and 'agent' are conversations with the user, 'room-member' and
|
|
19
|
+
* 'headless' unattended runs. */
|
|
20
|
+
export function memoryCallerScope(session) {
|
|
21
|
+
const scope = scheduleCallerScope(session);
|
|
22
|
+
if (scope.kind === 'human') return { kind: 'human', agentId: MIXY_AGENT_ID };
|
|
23
|
+
if (scope.kind !== 'headless') return scope;
|
|
24
|
+
const delegated = isAgentOwner(session) || Boolean(session?.parentSessionId);
|
|
25
|
+
return {
|
|
26
|
+
kind: 'headless',
|
|
27
|
+
agentId: validAgentId(session?.ownerAgentId) || (delegated ? validAgentId(session?.agent) : ''),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The agent whose own memory a session's prompt carries: its home thread's,
|
|
32
|
+
* room member's or run owner's agent, Mixy for the user's Lead sessions, and
|
|
33
|
+
* none for a delegated agent. `session` is the live record when there is
|
|
34
|
+
* one, else the reserved id and creation profile. */
|
|
35
|
+
export function injectedMemoryAgentId({ session = null, sessionId = '', profile = null } = {}) {
|
|
36
|
+
return resolveSessionMode({ session, sessionId, profile }).agentId;
|
|
37
|
+
}
|