aec-agent 1.0.1 → 1.0.4
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/dist/agent-core.d.ts +123 -3
- package/dist/agent-core.d.ts.map +1 -1
- package/dist/agent-core.js +219 -23
- package/dist/agent-core.js.map +1 -1
- package/dist/components/artifact-hub/artifact-hub.d.ts +11 -1
- package/dist/components/artifact-hub/artifact-hub.d.ts.map +1 -1
- package/dist/components/artifact-hub/artifact-hub.js +21 -1
- package/dist/components/artifact-hub/artifact-hub.js.map +1 -1
- package/dist/components/channel-platform-hub/adapter-kit.d.ts +51 -0
- package/dist/components/channel-platform-hub/adapter-kit.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/adapter-kit.js +153 -0
- package/dist/components/channel-platform-hub/adapter-kit.js.map +1 -0
- package/dist/components/channel-platform-hub/channel-platform-hub.d.ts +34 -0
- package/dist/components/channel-platform-hub/channel-platform-hub.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/channel-platform-hub.js +52 -0
- package/dist/components/channel-platform-hub/channel-platform-hub.js.map +1 -0
- package/dist/components/channel-platform-hub/discord/discord-adapter.d.ts +57 -0
- package/dist/components/channel-platform-hub/discord/discord-adapter.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/discord/discord-adapter.js +412 -0
- package/dist/components/channel-platform-hub/discord/discord-adapter.js.map +1 -0
- package/dist/components/channel-platform-hub/slack/slack-adapter.d.ts +56 -0
- package/dist/components/channel-platform-hub/slack/slack-adapter.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/slack/slack-adapter.js +349 -0
- package/dist/components/channel-platform-hub/slack/slack-adapter.js.map +1 -0
- package/dist/components/channel-platform-hub/slack/slack-mrkdwn.d.ts +3 -0
- package/dist/components/channel-platform-hub/slack/slack-mrkdwn.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/slack/slack-mrkdwn.js +70 -0
- package/dist/components/channel-platform-hub/slack/slack-mrkdwn.js.map +1 -0
- package/dist/components/channel-platform-hub/teams/teams-adapter.d.ts +51 -0
- package/dist/components/channel-platform-hub/teams/teams-adapter.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/teams/teams-adapter.js +333 -0
- package/dist/components/channel-platform-hub/teams/teams-adapter.js.map +1 -0
- package/dist/components/channel-platform-hub/telegram/telegram-adapter.d.ts +46 -0
- package/dist/components/channel-platform-hub/telegram/telegram-adapter.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/telegram/telegram-adapter.js +304 -0
- package/dist/components/channel-platform-hub/telegram/telegram-adapter.js.map +1 -0
- package/dist/components/channel-platform-hub/telegram/telegram-markdown.d.ts +3 -0
- package/dist/components/channel-platform-hub/telegram/telegram-markdown.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/telegram/telegram-markdown.js +87 -0
- package/dist/components/channel-platform-hub/telegram/telegram-markdown.js.map +1 -0
- package/dist/components/channel-platform-hub/types.d.ts +290 -0
- package/dist/components/channel-platform-hub/types.d.ts.map +1 -0
- package/dist/components/channel-platform-hub/types.js +23 -0
- package/dist/components/channel-platform-hub/types.js.map +1 -0
- package/dist/components/event-handler/event-dispatcher.d.ts +28 -3
- package/dist/components/event-handler/event-dispatcher.d.ts.map +1 -1
- package/dist/components/event-handler/event-dispatcher.js +77 -13
- package/dist/components/event-handler/event-dispatcher.js.map +1 -1
- package/dist/components/event-handler/events.d.ts +316 -15
- package/dist/components/event-handler/events.d.ts.map +1 -1
- package/dist/components/event-handler/events.js +94 -2
- package/dist/components/event-handler/events.js.map +1 -1
- package/dist/components/event-handler/types.d.ts +26 -0
- package/dist/components/event-handler/types.d.ts.map +1 -1
- package/dist/components/group-hub/group-hub.d.ts +117 -0
- package/dist/components/group-hub/group-hub.d.ts.map +1 -0
- package/dist/components/group-hub/group-hub.js +334 -0
- package/dist/components/group-hub/group-hub.js.map +1 -0
- package/dist/components/group-hub/group-turns.d.ts +109 -0
- package/dist/components/group-hub/group-turns.d.ts.map +1 -0
- package/dist/components/group-hub/group-turns.js +834 -0
- package/dist/components/group-hub/group-turns.js.map +1 -0
- package/dist/components/group-hub/member-prompt.d.ts +28 -0
- package/dist/components/group-hub/member-prompt.d.ts.map +1 -0
- package/dist/components/group-hub/member-prompt.js +111 -0
- package/dist/components/group-hub/member-prompt.js.map +1 -0
- package/dist/components/group-hub/recipients.d.ts +10 -0
- package/dist/components/group-hub/recipients.d.ts.map +1 -0
- package/dist/components/group-hub/recipients.js +83 -0
- package/dist/components/group-hub/recipients.js.map +1 -0
- package/dist/components/group-hub/thread.d.ts +57 -0
- package/dist/components/group-hub/thread.d.ts.map +1 -0
- package/dist/components/group-hub/thread.js +126 -0
- package/dist/components/group-hub/thread.js.map +1 -0
- package/dist/components/group-hub/types.d.ts +277 -0
- package/dist/components/group-hub/types.d.ts.map +1 -0
- package/dist/components/group-hub/types.js +51 -0
- package/dist/components/group-hub/types.js.map +1 -0
- package/dist/components/llm-provider-hub/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/components/llm-provider-hub/providers/anthropic-provider.js +22 -2
- package/dist/components/llm-provider-hub/providers/anthropic-provider.js.map +1 -1
- package/dist/components/llm-provider-hub/providers/bedrock-provider.d.ts.map +1 -1
- package/dist/components/llm-provider-hub/providers/bedrock-provider.js +15 -3
- package/dist/components/llm-provider-hub/providers/bedrock-provider.js.map +1 -1
- package/dist/components/llm-provider-hub/providers/model-info-mappers.d.ts.map +1 -1
- package/dist/components/llm-provider-hub/providers/model-info-mappers.js +27 -0
- package/dist/components/llm-provider-hub/providers/model-info-mappers.js.map +1 -1
- package/dist/components/llm-provider-hub/providers/openai-compatible-provider.d.ts.map +1 -1
- package/dist/components/llm-provider-hub/providers/openai-compatible-provider.js +10 -3
- package/dist/components/llm-provider-hub/providers/openai-compatible-provider.js.map +1 -1
- package/dist/components/llm-provider-hub/providers/openai-subscription-provider.d.ts +1 -0
- package/dist/components/llm-provider-hub/providers/openai-subscription-provider.d.ts.map +1 -1
- package/dist/components/llm-provider-hub/providers/openai-subscription-provider.js +35 -3
- package/dist/components/llm-provider-hub/providers/openai-subscription-provider.js.map +1 -1
- package/dist/components/llm-provider-hub/types.d.ts +20 -0
- package/dist/components/llm-provider-hub/types.d.ts.map +1 -1
- package/dist/components/llm-provider-hub/types.js +5 -0
- package/dist/components/llm-provider-hub/types.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/agent-loop.d.ts +87 -8
- package/dist/components/multi-agent-orchestration/agent/agent-loop/agent-loop.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/agent-loop.js +465 -62
- package/dist/components/multi-agent-orchestration/agent/agent-loop/agent-loop.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/compactor.d.ts +14 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/compactor.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/compactor.js +25 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/compactor.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/counter.d.ts +14 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/counter.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/counter.js +14 -22
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/counter.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/harness-executor.d.ts +41 -3
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/harness-executor.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/harness-executor.js +152 -44
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/harness-executor.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/run-trace.d.ts +15 -0
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/run-trace.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/run-trace.js +35 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/run-trace.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/summarizer.d.ts +10 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/summarizer.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/summarizer.js +39 -6
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/summarizer.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/summarizer.types.d.ts +2 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/components/summarizer.types.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/context-usage.d.ts +47 -0
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/context-usage.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/context-usage.js +61 -0
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/context-usage.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/memory-recall.d.ts +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/memory-recall.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/memory-recall.js +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/functions/memory-recall.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/types.d.ts +131 -8
- package/dist/components/multi-agent-orchestration/agent/agent-loop/types.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/types.js +17 -1
- package/dist/components/multi-agent-orchestration/agent/agent-loop/types.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent.d.ts +101 -15
- package/dist/components/multi-agent-orchestration/agent/agent.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/agent.js +415 -44
- package/dist/components/multi-agent-orchestration/agent/agent.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-manager.d.ts +245 -1
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-manager.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-manager.js +1583 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-manager.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-prompts.d.ts +76 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-prompts.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-prompts.js +236 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/channel-prompts.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/text.d.ts +15 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/text.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/text.js +80 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/text.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-stream.d.ts +13 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-stream.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-stream.js +41 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-stream.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-view.d.ts +69 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-view.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-view.js +210 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/turn-view.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/types.d.ts +76 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/types.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/types.js +7 -0
- package/dist/components/multi-agent-orchestration/agent/channel-manager/types.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/built-in-commands.d.ts +37 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/built-in-commands.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/built-in-commands.js +544 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/built-in-commands.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/command-manager.d.ts +75 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/command-manager.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/command-manager.js +299 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/command-manager.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/parse.d.ts +17 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/parse.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/parse.js +19 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/parse.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/types.d.ts +197 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/types.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/types.js +3 -0
- package/dist/components/multi-agent-orchestration/agent/command-manager/types.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/context-manager/context-manager.d.ts +37 -1
- package/dist/components/multi-agent-orchestration/agent/context-manager/context-manager.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/context-manager/context-manager.js +54 -2
- package/dist/components/multi-agent-orchestration/agent/context-manager/context-manager.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation-manager.d.ts +118 -14
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation-manager.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation-manager.js +239 -50
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation-manager.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation.d.ts +34 -0
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation.js +74 -0
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/conversation.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/turn-gate.d.ts +49 -0
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/turn-gate.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/turn-gate.js +171 -0
- package/dist/components/multi-agent-orchestration/agent/conversation-manager/turn-gate.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/clock.d.ts +43 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/clock.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/clock.js +116 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/clock.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/internal-events.d.ts +17 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/internal-events.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/internal-events.js +93 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/internal-events.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/job-manager.d.ts +208 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/job-manager.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/job-manager.js +1207 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/job-manager.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/rules.d.ts +129 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/rules.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/rules.js +598 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/rules.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/schedule.d.ts +15 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/schedule.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/schedule.js +113 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/schedule.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/timers.d.ts +8 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/timers.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/timers.js +33 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/timers.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/types.d.ts +495 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/types.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/types.js +50 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/types.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/webhook.d.ts +37 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/webhook.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/webhook.js +157 -0
- package/dist/components/multi-agent-orchestration/agent/job-manager/webhook.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/memory-system/components/dreaming.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/memory-system/components/dreaming.js +17 -3
- package/dist/components/multi-agent-orchestration/agent/memory-system/components/dreaming.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/memory-system/components/memory.d.ts +7 -0
- package/dist/components/multi-agent-orchestration/agent/memory-system/components/memory.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/memory-system/components/memory.js +189 -30
- package/dist/components/multi-agent-orchestration/agent/memory-system/components/memory.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/memory-system/memory-system.d.ts +17 -0
- package/dist/components/multi-agent-orchestration/agent/memory-system/memory-system.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/memory-system/memory-system.js +51 -0
- package/dist/components/multi-agent-orchestration/agent/memory-system/memory-system.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/model-manager/model-manager.d.ts +5 -0
- package/dist/components/multi-agent-orchestration/agent/model-manager/model-manager.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/model-manager/model-manager.js +16 -0
- package/dist/components/multi-agent-orchestration/agent/model-manager/model-manager.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/secret-manager/secret-manager.d.ts +41 -0
- package/dist/components/multi-agent-orchestration/agent/secret-manager/secret-manager.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/secret-manager/secret-manager.js +98 -0
- package/dist/components/multi-agent-orchestration/agent/secret-manager/secret-manager.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/secret-manager/types.d.ts +37 -0
- package/dist/components/multi-agent-orchestration/agent/secret-manager/types.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/secret-manager/types.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/skill-manager/skill-manager.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/skill-manager/skill-manager.js +1 -0
- package/dist/components/multi-agent-orchestration/agent/skill-manager/skill-manager.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/brief.d.ts +21 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/brief.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/brief.js +113 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/brief.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/child-loop.d.ts +52 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/child-loop.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/child-loop.js +63 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/child-loop.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/semaphore.d.ts +18 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/semaphore.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/semaphore.js +56 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/semaphore.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/subagent-manager.d.ts +128 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/subagent-manager.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/subagent-manager.js +661 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/subagent-manager.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/types.d.ts +307 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/types.d.ts.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/types.js +60 -0
- package/dist/components/multi-agent-orchestration/agent/subagent-manager/types.js.map +1 -0
- package/dist/components/multi-agent-orchestration/agent/tool-manager/tool-manager.d.ts +14 -3
- package/dist/components/multi-agent-orchestration/agent/tool-manager/tool-manager.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/tool-manager/tool-manager.js +18 -5
- package/dist/components/multi-agent-orchestration/agent/tool-manager/tool-manager.js.map +1 -1
- package/dist/components/multi-agent-orchestration/agent/types.d.ts +84 -1
- package/dist/components/multi-agent-orchestration/agent/types.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/multi-agent-orchestration.d.ts +11 -4
- package/dist/components/multi-agent-orchestration/multi-agent-orchestration.d.ts.map +1 -1
- package/dist/components/multi-agent-orchestration/multi-agent-orchestration.js +72 -4
- package/dist/components/multi-agent-orchestration/multi-agent-orchestration.js.map +1 -1
- package/dist/components/persistence-hub/default-stores/memory-channel-store.d.ts +11 -0
- package/dist/components/persistence-hub/default-stores/memory-channel-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-channel-store.js +33 -0
- package/dist/components/persistence-hub/default-stores/memory-channel-store.js.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-group-store.d.ts +21 -0
- package/dist/components/persistence-hub/default-stores/memory-group-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-group-store.js +62 -0
- package/dist/components/persistence-hub/default-stores/memory-group-store.js.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-job-store.d.ts +31 -0
- package/dist/components/persistence-hub/default-stores/memory-job-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-job-store.js +234 -0
- package/dist/components/persistence-hub/default-stores/memory-job-store.js.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-secret-store.d.ts +12 -0
- package/dist/components/persistence-hub/default-stores/memory-secret-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-secret-store.js +38 -0
- package/dist/components/persistence-hub/default-stores/memory-secret-store.js.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-session-store.d.ts.map +1 -1
- package/dist/components/persistence-hub/default-stores/memory-session-store.js +7 -0
- package/dist/components/persistence-hub/default-stores/memory-session-store.js.map +1 -1
- package/dist/components/persistence-hub/default-stores/memory-subagent-run-store.d.ts +10 -0
- package/dist/components/persistence-hub/default-stores/memory-subagent-run-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-subagent-run-store.js +30 -0
- package/dist/components/persistence-hub/default-stores/memory-subagent-run-store.js.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-subagent-type-store.d.ts +9 -0
- package/dist/components/persistence-hub/default-stores/memory-subagent-type-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/default-stores/memory-subagent-type-store.js +17 -0
- package/dist/components/persistence-hub/default-stores/memory-subagent-type-store.js.map +1 -0
- package/dist/components/persistence-hub/persistence-hub.d.ts +41 -0
- package/dist/components/persistence-hub/persistence-hub.d.ts.map +1 -1
- package/dist/components/persistence-hub/persistence-hub.js +41 -0
- package/dist/components/persistence-hub/persistence-hub.js.map +1 -1
- package/dist/components/persistence-hub/types/channel-store.d.ts +12 -0
- package/dist/components/persistence-hub/types/channel-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/types/channel-store.js +2 -0
- package/dist/components/persistence-hub/types/channel-store.js.map +1 -0
- package/dist/components/persistence-hub/types/group-store.d.ts +27 -0
- package/dist/components/persistence-hub/types/group-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/types/group-store.js +2 -0
- package/dist/components/persistence-hub/types/group-store.js.map +1 -0
- package/dist/components/persistence-hub/types/job-store.d.ts +112 -0
- package/dist/components/persistence-hub/types/job-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/types/job-store.js +2 -0
- package/dist/components/persistence-hub/types/job-store.js.map +1 -0
- package/dist/components/persistence-hub/types/secret-store.d.ts +18 -0
- package/dist/components/persistence-hub/types/secret-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/types/secret-store.js +2 -0
- package/dist/components/persistence-hub/types/secret-store.js.map +1 -0
- package/dist/components/persistence-hub/types/session-store.d.ts +5 -0
- package/dist/components/persistence-hub/types/session-store.d.ts.map +1 -1
- package/dist/components/persistence-hub/types/subagent-run-store.d.ts +11 -0
- package/dist/components/persistence-hub/types/subagent-run-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/types/subagent-run-store.js +2 -0
- package/dist/components/persistence-hub/types/subagent-run-store.js.map +1 -0
- package/dist/components/persistence-hub/types/subagent-type-store.d.ts +9 -0
- package/dist/components/persistence-hub/types/subagent-type-store.d.ts.map +1 -0
- package/dist/components/persistence-hub/types/subagent-type-store.js +2 -0
- package/dist/components/persistence-hub/types/subagent-type-store.js.map +1 -0
- package/dist/components/sandbox-hub/docker/docker-sandbox.d.ts +4 -1
- package/dist/components/sandbox-hub/docker/docker-sandbox.d.ts.map +1 -1
- package/dist/components/sandbox-hub/docker/docker-sandbox.js +398 -1
- package/dist/components/sandbox-hub/docker/docker-sandbox.js.map +1 -1
- package/dist/components/sandbox-hub/docker/sandbox-helper.d.ts.map +1 -1
- package/dist/components/sandbox-hub/docker/sandbox-helper.js +386 -5
- package/dist/components/sandbox-hub/docker/sandbox-helper.js.map +1 -1
- package/dist/components/sandbox-hub/host/host-sandbox.d.ts +16 -0
- package/dist/components/sandbox-hub/host/host-sandbox.d.ts.map +1 -1
- package/dist/components/sandbox-hub/host/host-sandbox.js +283 -2
- package/dist/components/sandbox-hub/host/host-sandbox.js.map +1 -1
- package/dist/components/sandbox-hub/sandbox-hub.d.ts +9 -0
- package/dist/components/sandbox-hub/sandbox-hub.d.ts.map +1 -1
- package/dist/components/sandbox-hub/sandbox-hub.js +18 -0
- package/dist/components/sandbox-hub/sandbox-hub.js.map +1 -1
- package/dist/components/sandbox-hub/traced-sandbox.d.ts.map +1 -1
- package/dist/components/sandbox-hub/traced-sandbox.js +32 -0
- package/dist/components/sandbox-hub/traced-sandbox.js.map +1 -1
- package/dist/components/sandbox-hub/types/sandbox.d.ts +106 -1
- package/dist/components/sandbox-hub/types/sandbox.d.ts.map +1 -1
- package/dist/components/sandbox-hub/types/sandbox.js +0 -13
- package/dist/components/sandbox-hub/types/sandbox.js.map +1 -1
- package/dist/components/secret-hub/envelope.d.ts +48 -0
- package/dist/components/secret-hub/envelope.d.ts.map +1 -0
- package/dist/components/secret-hub/envelope.js +157 -0
- package/dist/components/secret-hub/envelope.js.map +1 -0
- package/dist/components/secret-hub/rules.d.ts +33 -0
- package/dist/components/secret-hub/rules.d.ts.map +1 -0
- package/dist/components/secret-hub/rules.js +142 -0
- package/dist/components/secret-hub/rules.js.map +1 -0
- package/dist/components/secret-hub/secret-hub-provider.d.ts +61 -0
- package/dist/components/secret-hub/secret-hub-provider.d.ts.map +1 -0
- package/dist/components/secret-hub/secret-hub-provider.js +73 -0
- package/dist/components/secret-hub/secret-hub-provider.js.map +1 -0
- package/dist/components/secret-hub/secret-hub.d.ts +102 -0
- package/dist/components/secret-hub/secret-hub.d.ts.map +1 -0
- package/dist/components/secret-hub/secret-hub.js +267 -0
- package/dist/components/secret-hub/secret-hub.js.map +1 -0
- package/dist/components/secret-hub/types.d.ts +77 -0
- package/dist/components/secret-hub/types.d.ts.map +1 -0
- package/dist/components/secret-hub/types.js +23 -0
- package/dist/components/secret-hub/types.js.map +1 -0
- package/dist/components/skill-hub/built-in-skills/essential-skills.d.ts +1 -1
- package/dist/components/skill-hub/built-in-skills/essential-skills.d.ts.map +1 -1
- package/dist/components/skill-hub/built-in-skills/essential-skills.js +7 -2
- package/dist/components/skill-hub/built-in-skills/essential-skills.js.map +1 -1
- package/dist/components/skill-hub/built-in-skills/watch-and-notify.d.ts +3 -0
- package/dist/components/skill-hub/built-in-skills/watch-and-notify.d.ts.map +1 -0
- package/dist/components/skill-hub/built-in-skills/watch-and-notify.js +94 -0
- package/dist/components/skill-hub/built-in-skills/watch-and-notify.js.map +1 -0
- package/dist/components/skill-hub/skill-hub.d.ts +9 -1
- package/dist/components/skill-hub/skill-hub.d.ts.map +1 -1
- package/dist/components/skill-hub/skill-hub.js +11 -1
- package/dist/components/skill-hub/skill-hub.js.map +1 -1
- package/dist/components/subagent-hub/built-in-types.d.ts +3 -0
- package/dist/components/subagent-hub/built-in-types.d.ts.map +1 -0
- package/dist/components/subagent-hub/built-in-types.js +24 -0
- package/dist/components/subagent-hub/built-in-types.js.map +1 -0
- package/dist/components/subagent-hub/subagent-hub.d.ts +41 -0
- package/dist/components/subagent-hub/subagent-hub.d.ts.map +1 -0
- package/dist/components/subagent-hub/subagent-hub.js +158 -0
- package/dist/components/subagent-hub/subagent-hub.js.map +1 -0
- package/dist/components/subagent-hub/types.d.ts +40 -0
- package/dist/components/subagent-hub/types.d.ts.map +1 -0
- package/dist/components/subagent-hub/types.js +8 -0
- package/dist/components/subagent-hub/types.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/artifacts/artifact-helpers.d.ts +4 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/artifact-helpers.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/artifact-helpers.js +4 -0
- package/dist/components/tool-hub/built-in-tools/artifacts/artifact-helpers.js.map +1 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/save-artifact-tool.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/save-artifact-tool.js +4 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/save-artifact-tool.js.map +1 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/update-artifact-tool.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/update-artifact-tool.js +4 -1
- package/dist/components/tool-hub/built-in-tools/artifacts/update-artifact-tool.js.map +1 -1
- package/dist/components/tool-hub/built-in-tools/jobs/create-job-tools.d.ts +10 -0
- package/dist/components/tool-hub/built-in-tools/jobs/create-job-tools.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/jobs/create-job-tools.js +13 -0
- package/dist/components/tool-hub/built-in-tools/jobs/create-job-tools.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/jobs/job-tool-helpers.d.ts +60 -0
- package/dist/components/tool-hub/built-in-tools/jobs/job-tool-helpers.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/jobs/job-tool-helpers.js +240 -0
- package/dist/components/tool-hub/built-in-tools/jobs/job-tool-helpers.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/jobs/list-jobs-tool.d.ts +14 -0
- package/dist/components/tool-hub/built-in-tools/jobs/list-jobs-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/jobs/list-jobs-tool.js +36 -0
- package/dist/components/tool-hub/built-in-tools/jobs/list-jobs-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/jobs/manage-job-tool.d.ts +32 -0
- package/dist/components/tool-hub/built-in-tools/jobs/manage-job-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/jobs/manage-job-tool.js +458 -0
- package/dist/components/tool-hub/built-in-tools/jobs/manage-job-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/create-preview-tools.d.ts +9 -0
- package/dist/components/tool-hub/built-in-tools/preview/create-preview-tools.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/create-preview-tools.js +20 -0
- package/dist/components/tool-hub/built-in-tools/preview/create-preview-tools.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/list-apps-tool.d.ts +12 -0
- package/dist/components/tool-hub/built-in-tools/preview/list-apps-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/list-apps-tool.js +57 -0
- package/dist/components/tool-hub/built-in-tools/preview/list-apps-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/open-in-app-tool.d.ts +15 -0
- package/dist/components/tool-hub/built-in-tools/preview/open-in-app-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/open-in-app-tool.js +80 -0
- package/dist/components/tool-hub/built-in-tools/preview/open-in-app-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-helpers.d.ts +53 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-helpers.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-helpers.js +100 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-helpers.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-tool.d.ts +14 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-tool.js +63 -0
- package/dist/components/tool-hub/built-in-tools/preview/preview-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/service-tools.d.ts +33 -0
- package/dist/components/tool-hub/built-in-tools/preview/service-tools.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/preview/service-tools.js +180 -0
- package/dist/components/tool-hub/built-in-tools/preview/service-tools.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/create-secret-tools.d.ts +6 -0
- package/dist/components/tool-hub/built-in-tools/secrets/create-secret-tools.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/create-secret-tools.js +9 -0
- package/dist/components/tool-hub/built-in-tools/secrets/create-secret-tools.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/list-secrets-tool.d.ts +12 -0
- package/dist/components/tool-hub/built-in-tools/secrets/list-secrets-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/list-secrets-tool.js +30 -0
- package/dist/components/tool-hub/built-in-tools/secrets/list-secrets-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/manage-secret-tool.d.ts +22 -0
- package/dist/components/tool-hub/built-in-tools/secrets/manage-secret-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/manage-secret-tool.js +113 -0
- package/dist/components/tool-hub/built-in-tools/secrets/manage-secret-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/secret-tool-helpers.d.ts +9 -0
- package/dist/components/tool-hub/built-in-tools/secrets/secret-tool-helpers.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/secrets/secret-tool-helpers.js +29 -0
- package/dist/components/tool-hub/built-in-tools/secrets/secret-tool-helpers.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/subagents/spawn-subagent-tool.d.ts +27 -0
- package/dist/components/tool-hub/built-in-tools/subagents/spawn-subagent-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/subagents/spawn-subagent-tool.js +112 -0
- package/dist/components/tool-hub/built-in-tools/subagents/spawn-subagent-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/web/http-request-tool.d.ts +43 -0
- package/dist/components/tool-hub/built-in-tools/web/http-request-tool.d.ts.map +1 -0
- package/dist/components/tool-hub/built-in-tools/web/http-request-tool.js +234 -0
- package/dist/components/tool-hub/built-in-tools/web/http-request-tool.js.map +1 -0
- package/dist/components/tool-hub/built-in-tools/web/web-extract-tool.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/web/web-extract-tool.js +2 -0
- package/dist/components/tool-hub/built-in-tools/web/web-extract-tool.js.map +1 -1
- package/dist/components/tool-hub/built-in-tools/web/web-search-tool.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/web/web-search-tool.js +2 -0
- package/dist/components/tool-hub/built-in-tools/web/web-search-tool.js.map +1 -1
- package/dist/components/tool-hub/built-in-tools/workspace/run-code-tool.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/workspace/run-code-tool.js +9 -1
- package/dist/components/tool-hub/built-in-tools/workspace/run-code-tool.js.map +1 -1
- package/dist/components/tool-hub/built-in-tools/workspace/terminal-tool.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/workspace/terminal-tool.js +9 -2
- package/dist/components/tool-hub/built-in-tools/workspace/terminal-tool.js.map +1 -1
- package/dist/components/tool-hub/built-in-tools/workspace/workspace-helpers.d.ts +17 -0
- package/dist/components/tool-hub/built-in-tools/workspace/workspace-helpers.d.ts.map +1 -1
- package/dist/components/tool-hub/built-in-tools/workspace/workspace-helpers.js +29 -0
- package/dist/components/tool-hub/built-in-tools/workspace/workspace-helpers.js.map +1 -1
- package/dist/components/tool-hub/tool-links.d.ts +9 -0
- package/dist/components/tool-hub/tool-links.d.ts.map +1 -0
- package/dist/components/tool-hub/tool-links.js +11 -0
- package/dist/components/tool-hub/tool-links.js.map +1 -0
- package/dist/components/tool-hub/types.d.ts +101 -1
- package/dist/components/tool-hub/types.d.ts.map +1 -1
- package/dist/index.d.ts +109 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -1
- package/dist/kernel/errors/channel-error.d.ts +24 -0
- package/dist/kernel/errors/channel-error.d.ts.map +1 -0
- package/dist/kernel/errors/channel-error.js +15 -0
- package/dist/kernel/errors/channel-error.js.map +1 -0
- package/dist/kernel/errors/command-error.d.ts +12 -0
- package/dist/kernel/errors/command-error.d.ts.map +1 -0
- package/dist/kernel/errors/command-error.js +11 -0
- package/dist/kernel/errors/command-error.js.map +1 -0
- package/dist/kernel/errors/group-error.d.ts +15 -0
- package/dist/kernel/errors/group-error.d.ts.map +1 -0
- package/dist/kernel/errors/group-error.js +10 -0
- package/dist/kernel/errors/group-error.js.map +1 -0
- package/dist/kernel/errors/job-error.d.ts +23 -0
- package/dist/kernel/errors/job-error.d.ts.map +1 -0
- package/dist/kernel/errors/job-error.js +15 -0
- package/dist/kernel/errors/job-error.js.map +1 -0
- package/dist/kernel/errors/secret-error.d.ts +19 -0
- package/dist/kernel/errors/secret-error.d.ts.map +1 -0
- package/dist/kernel/errors/secret-error.js +10 -0
- package/dist/kernel/errors/secret-error.js.map +1 -0
- package/dist/kernel/errors/session-error.d.ts +5 -1
- package/dist/kernel/errors/session-error.d.ts.map +1 -1
- package/dist/kernel/errors/session-error.js.map +1 -1
- package/dist/kernel/errors/subagent-error.d.ts +19 -0
- package/dist/kernel/errors/subagent-error.d.ts.map +1 -0
- package/dist/kernel/errors/subagent-error.js +10 -0
- package/dist/kernel/errors/subagent-error.js.map +1 -0
- package/dist/kernel/interfaces/kernel.d.ts +15 -0
- package/dist/kernel/interfaces/kernel.d.ts.map +1 -1
- package/dist/kernel/types.d.ts +80 -1
- package/dist/kernel/types.d.ts.map +1 -1
- package/dist/testing/fake-channel.d.ts +60 -0
- package/dist/testing/fake-channel.d.ts.map +1 -0
- package/dist/testing/fake-channel.js +135 -0
- package/dist/testing/fake-channel.js.map +1 -0
- package/dist/testing/in-memory-sandbox.d.ts +4 -1
- package/dist/testing/in-memory-sandbox.d.ts.map +1 -1
- package/dist/testing/in-memory-sandbox.js +63 -3
- package/dist/testing/in-memory-sandbox.js.map +1 -1
- package/dist/testing/mock-session-store.d.ts.map +1 -1
- package/dist/testing/mock-session-store.js +7 -0
- package/dist/testing/mock-session-store.js.map +1 -1
- package/package.json +2 -1
- package/dist/components/multi-agent-orchestration/agent/scheduled-job-manager/scheduled-job-manager.d.ts +0 -38
- package/dist/components/multi-agent-orchestration/agent/scheduled-job-manager/scheduled-job-manager.d.ts.map +0 -1
- package/dist/components/multi-agent-orchestration/agent/scheduled-job-manager/scheduled-job-manager.js +0 -155
- package/dist/components/multi-agent-orchestration/agent/scheduled-job-manager/scheduled-job-manager.js.map +0 -1
- package/dist/components/multi-agent-orchestration/agent/scheduled-job-manager/types.d.ts +0 -27
- package/dist/components/multi-agent-orchestration/agent/scheduled-job-manager/types.d.ts.map +0 -1
- package/dist/components/multi-agent-orchestration/agent/scheduled-job-manager/types.js.map +0 -1
- /package/dist/components/multi-agent-orchestration/agent/{scheduled-job-manager → secret-manager}/types.js +0 -0
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { SDKError } from "../../../../kernel/errors/sdk-error.js";
|
|
3
|
+
import { JobError } from "../../../../kernel/errors/job-error.js";
|
|
4
|
+
import { SDKEventType } from "../../../event-handler/events.js";
|
|
5
|
+
import { JobClock } from "./clock.js";
|
|
6
|
+
import { armTimer } from "./timers.js";
|
|
7
|
+
import { INTERNAL_BUS_EVENT_TYPES, internalEnvelope, resolvedSince } from "./internal-events.js";
|
|
8
|
+
import { DEFAULT_MAX_RUN_MS, DEFAULT_PAUSE_AFTER_FAILURES, MAX_EVENT_DATA_BYTES, MAX_JOBS_PER_AGENT, MAX_WEBHOOK_BODY_BYTES, canonicalJson, dataBytes, defaultLimits, filterMismatch, renderJobPrompt, replyOutcome, resolveCoalesce, resolveLimits, toRevision, toSubject, typeMatches, usesRunHistory, validateCreateInput, validateJobAction, validateJobDeliveries, validateJobDescription, validateJobFilter, validateJobName, validatePromptFor, validateJobWhen, validateSessionMode, } from "./rules.js";
|
|
9
|
+
import { describeSchedule } from "./schedule.js";
|
|
10
|
+
import { generateWebhookSecret, parseWebhookEvent, verifyWebhookSignature } from "./webhook.js";
|
|
11
|
+
import { isScheduleWhen, } from "./types.js";
|
|
12
|
+
/** How long a claimed run is leased; renewed every third of it while the turn runs. */
|
|
13
|
+
export const JOB_LEASE_MS = 60_000;
|
|
14
|
+
/** How often the worker looks for due runs it was not told about (other processes, expired leases). */
|
|
15
|
+
export const JOB_POLL_MS = 10_000;
|
|
16
|
+
/** First retry delay; doubles per attempt, with ±25% jitter, at most 15 minutes. */
|
|
17
|
+
export const JOB_RETRY_BASE_MS = 30_000;
|
|
18
|
+
/** Job runs of one agent at once in this process. */
|
|
19
|
+
export const MAX_PARALLEL_JOB_RUNS = 4;
|
|
20
|
+
/** History kept per job. */
|
|
21
|
+
export const KEEP_JOB_EVENTS = 200;
|
|
22
|
+
export const KEEP_JOB_RUNS = 100;
|
|
23
|
+
const MAX_RETRY_DELAY_MS = 15 * 60_000;
|
|
24
|
+
const MAX_OUTPUT_CHARS = 100_000;
|
|
25
|
+
/** A-103: most of a failed tool's output put into the run's error (the session keeps all of it). */
|
|
26
|
+
const MAX_TOOL_ERROR_CHARS = 2_000;
|
|
27
|
+
const HOUR = 60 * 60_000;
|
|
28
|
+
const DAY = 24 * HOUR;
|
|
29
|
+
/**
|
|
30
|
+
* One agent's event triggers (A-70): takes events into the durable inbox and
|
|
31
|
+
* runs them as agent turns.
|
|
32
|
+
*
|
|
33
|
+
* - Intake: the agent's own SDK events (pub-sub, never a direct call from the
|
|
34
|
+
* scheduler or channels), signed webhooks (handleWebhook) and test events go
|
|
35
|
+
* through one path: filter → loop guard → TriggerStore.accept() (dedupe +
|
|
36
|
+
* coalesce into a run, atomically).
|
|
37
|
+
* - Worker: claims due runs with a lease (TriggerStore.claim), so a run is
|
|
38
|
+
* worked by one worker at a time and a run whose worker died is taken over
|
|
39
|
+
* when its lease expires. Before a turn it re-checks the trigger (deleted,
|
|
40
|
+
* disabled, changed), stale revisions, a resolved condition and the rate and
|
|
41
|
+
* token limits. The turn goes through the host's TriggerRunner in a fresh
|
|
42
|
+
* session; per-session ordering and the agent's turn cap apply as for any turn,
|
|
43
|
+
* and runs leave a turn free for people's chats.
|
|
44
|
+
* - Results: the reply is checkpointed before the run is marked finished, so a
|
|
45
|
+
* crash in between only re-records the result, it does not re-run the turn.
|
|
46
|
+
* Transient failures retry with backoff within maxAttempts and the run's
|
|
47
|
+
* deadline. Approvals cannot be given in an unattended run: the tool is denied
|
|
48
|
+
* and the run ends "blocked".
|
|
49
|
+
*
|
|
50
|
+
* Update (A-126): the JobManager — one agent's jobs of every kind. Schedule jobs'
|
|
51
|
+
* ticks (the JobClock), run now, bus events, webhooks and test events all go through
|
|
52
|
+
* the intake above, and one worker runs them. A run's session follows the job's
|
|
53
|
+
* sessionMode (fresh, or one reused session). A run's reply may carry a marker:
|
|
54
|
+
* [[SILENT]] (nothing to report: succeeded, never delivered) or [[FAILED]] <reason>
|
|
55
|
+
* (failed, not retried).
|
|
56
|
+
*/
|
|
57
|
+
export class JobManager {
|
|
58
|
+
deps;
|
|
59
|
+
/** This worker's lease identity. */
|
|
60
|
+
owner = `job-worker:${randomUUID()}`;
|
|
61
|
+
active = new Map();
|
|
62
|
+
/** sessionId -> the run working in it. */
|
|
63
|
+
bySession = new Map();
|
|
64
|
+
/** Intakes and runs in flight — dispose() waits for them. */
|
|
65
|
+
inFlight = new Set();
|
|
66
|
+
/**
|
|
67
|
+
* Schedule jobs whose overlap check and queueing are in progress: a second tick or
|
|
68
|
+
* run now meanwhile sees the job as busy, so two fired at the same moment cannot
|
|
69
|
+
* both pass the check (the slot is taken before any await).
|
|
70
|
+
*/
|
|
71
|
+
queuing = new Set();
|
|
72
|
+
unsubscribe;
|
|
73
|
+
clock;
|
|
74
|
+
pollTimer;
|
|
75
|
+
wakeTimer;
|
|
76
|
+
pumping = false;
|
|
77
|
+
pumpAgain = false;
|
|
78
|
+
started = false;
|
|
79
|
+
disposed = false;
|
|
80
|
+
now;
|
|
81
|
+
random;
|
|
82
|
+
leaseMs;
|
|
83
|
+
constructor(deps) {
|
|
84
|
+
this.deps = deps;
|
|
85
|
+
this.now = deps.now ?? Date.now;
|
|
86
|
+
this.random = deps.random ?? Math.random;
|
|
87
|
+
this.leaseMs = deps.leaseMs ?? JOB_LEASE_MS;
|
|
88
|
+
this.clock = new JobClock({
|
|
89
|
+
agentId: deps.agentId,
|
|
90
|
+
getStore: deps.getStore,
|
|
91
|
+
onTick: (job, scheduledAt, cause) => this.onTick(job, scheduledAt, cause),
|
|
92
|
+
now: this.now,
|
|
93
|
+
});
|
|
94
|
+
// The "event" source: the agent's own SDK events, by subscription only.
|
|
95
|
+
this.unsubscribe = INTERNAL_BUS_EVENT_TYPES.map((type) => deps.eventBus.on(type, (event) => {
|
|
96
|
+
this.track(this.onBusEvent(event));
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The InteractionHandler for a session while a job run works in it: nobody
|
|
101
|
+
* is there to answer, so approvals are denied (the run ends "blocked") and
|
|
102
|
+
* questions fail. Undefined for any other session.
|
|
103
|
+
*/
|
|
104
|
+
interactionFor(sessionId) {
|
|
105
|
+
const entry = this.bySession.get(sessionId);
|
|
106
|
+
if (!entry)
|
|
107
|
+
return undefined;
|
|
108
|
+
return {
|
|
109
|
+
requestApproval: async (request) => {
|
|
110
|
+
// A-103: a tool job's stored call was approved when the job was made — exactly that
|
|
111
|
+
// tool with exactly those arguments, nothing else.
|
|
112
|
+
const approved = entry.approvedCall;
|
|
113
|
+
if (approved && request.toolName === approved.tool && canonicalJson(request.arguments) === approved.args) {
|
|
114
|
+
return { approved: true, reason: "approved with the job" };
|
|
115
|
+
}
|
|
116
|
+
if (!entry.deniedTools.includes(request.toolName))
|
|
117
|
+
entry.deniedTools.push(request.toolName);
|
|
118
|
+
return {
|
|
119
|
+
approved: false,
|
|
120
|
+
reason: "This run was started by a job and nobody is there to approve tools, so the tool is denied. Say in your reply which action needs approval.",
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
askUser: async () => {
|
|
124
|
+
throw new Error("this run was started by a job and nobody is there to answer");
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Lifecycle
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
/**
|
|
132
|
+
* Start the agent's jobs: arm schedule jobs (a time missed while the host was down
|
|
133
|
+
* runs once), and work the queue — due runs, runs left by a previous process (their
|
|
134
|
+
* leases expire) and retries. Call once the host is ready to run turns. Idempotent.
|
|
135
|
+
*/
|
|
136
|
+
async start() {
|
|
137
|
+
if (this.started || this.disposed)
|
|
138
|
+
return;
|
|
139
|
+
this.started = true;
|
|
140
|
+
this.pollTimer = setInterval(() => this.pump(), this.deps.pollMs ?? JOB_POLL_MS);
|
|
141
|
+
this.pollTimer.unref?.();
|
|
142
|
+
await this.clock.start();
|
|
143
|
+
this.pump();
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Stop the clock, intake and the worker. Runs in progress are aborted and released,
|
|
147
|
+
* so they are taken up again (not lost, not counted as an attempt) after a restart.
|
|
148
|
+
*/
|
|
149
|
+
async dispose() {
|
|
150
|
+
this.disposed = true;
|
|
151
|
+
this.clock.dispose();
|
|
152
|
+
for (const off of this.unsubscribe)
|
|
153
|
+
off();
|
|
154
|
+
if (this.pollTimer)
|
|
155
|
+
clearInterval(this.pollTimer);
|
|
156
|
+
this.wakeTimer?.cancel();
|
|
157
|
+
for (const entry of this.active.values())
|
|
158
|
+
entry.controller.abort();
|
|
159
|
+
while (this.inFlight.size > 0)
|
|
160
|
+
await Promise.allSettled([...this.inFlight]);
|
|
161
|
+
}
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// AgentJobs — configuration
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
async list() {
|
|
166
|
+
return this.store().listByAgent(this.deps.agentId);
|
|
167
|
+
}
|
|
168
|
+
async get(id) {
|
|
169
|
+
const job = await this.store().get(id);
|
|
170
|
+
return job && job.agentId === this.deps.agentId ? job : null;
|
|
171
|
+
}
|
|
172
|
+
async create(input) {
|
|
173
|
+
if (this.disposed)
|
|
174
|
+
throw new JobError("The agent is stopped", "invalid_argument");
|
|
175
|
+
if (typeof input !== "object" || input === null)
|
|
176
|
+
throw new JobError("A job needs a configuration object", "invalid_argument");
|
|
177
|
+
const fields = validateCreateInput(input);
|
|
178
|
+
if (fields.action)
|
|
179
|
+
this.checkToolAction(fields.action);
|
|
180
|
+
const existing = await this.store().listByAgent(this.deps.agentId);
|
|
181
|
+
if (existing.length >= MAX_JOBS_PER_AGENT) {
|
|
182
|
+
throw new JobError(`This agent already has ${MAX_JOBS_PER_AGENT} jobs — delete one first`, "limit_reached");
|
|
183
|
+
}
|
|
184
|
+
if (existing.some((j) => j.name === fields.name)) {
|
|
185
|
+
throw new JobError(`A job named "${fields.name}" already exists`, "name_conflict");
|
|
186
|
+
}
|
|
187
|
+
const nowIso = this.iso(this.now());
|
|
188
|
+
const job = {
|
|
189
|
+
id: randomUUID(),
|
|
190
|
+
agentId: this.deps.agentId,
|
|
191
|
+
...fields,
|
|
192
|
+
version: 1,
|
|
193
|
+
nextRunAt: fields.enabled && isScheduleWhen(fields.when) ? this.clock.firstRun(fields.when) : null,
|
|
194
|
+
...(fields.when.kind === "webhook" ? { secret: generateWebhookSecret() } : {}),
|
|
195
|
+
createdAt: nowIso,
|
|
196
|
+
updatedAt: nowIso,
|
|
197
|
+
};
|
|
198
|
+
await this.store().save(job);
|
|
199
|
+
this.clock.sync(job.id, job);
|
|
200
|
+
return job;
|
|
201
|
+
}
|
|
202
|
+
async update(id, patch) {
|
|
203
|
+
const job = await this.require(id);
|
|
204
|
+
if (typeof patch !== "object" || patch === null)
|
|
205
|
+
throw new JobError("A job update must be an object", "invalid_argument", id);
|
|
206
|
+
const next = { ...job };
|
|
207
|
+
if (patch.name !== undefined) {
|
|
208
|
+
const name = validateJobName(patch.name, id);
|
|
209
|
+
if (name !== job.name) {
|
|
210
|
+
const clash = await this.store().findByName(this.deps.agentId, name);
|
|
211
|
+
if (clash && clash.id !== id)
|
|
212
|
+
throw new JobError(`A job named "${name}" already exists`, "name_conflict", id);
|
|
213
|
+
}
|
|
214
|
+
next.name = name;
|
|
215
|
+
}
|
|
216
|
+
if (patch.description !== undefined) {
|
|
217
|
+
const description = validateJobDescription(patch.description, id);
|
|
218
|
+
if (description)
|
|
219
|
+
next.description = description;
|
|
220
|
+
else
|
|
221
|
+
delete next.description;
|
|
222
|
+
}
|
|
223
|
+
if (patch.enabled !== undefined) {
|
|
224
|
+
if (typeof patch.enabled !== "boolean")
|
|
225
|
+
throw new JobError('"enabled" must be true or false', "invalid_argument", id);
|
|
226
|
+
next.enabled = patch.enabled;
|
|
227
|
+
}
|
|
228
|
+
if (patch.sessionMode !== undefined)
|
|
229
|
+
next.sessionMode = validateSessionMode(patch.sessionMode, id);
|
|
230
|
+
const whenChanged = patch.when !== undefined;
|
|
231
|
+
if (whenChanged)
|
|
232
|
+
next.when = validateJobWhen(patch.when, id);
|
|
233
|
+
// A-103: the action is checked against the (possibly new) when, and the prompt against
|
|
234
|
+
// the action (a tool job needs a prompt only for its follow-up).
|
|
235
|
+
const actionChanged = patch.action !== undefined;
|
|
236
|
+
if (actionChanged || whenChanged) {
|
|
237
|
+
const action = validateJobAction(actionChanged ? patch.action : job.action, next.when, id);
|
|
238
|
+
if (action)
|
|
239
|
+
next.action = action;
|
|
240
|
+
else
|
|
241
|
+
delete next.action;
|
|
242
|
+
if (actionChanged && action)
|
|
243
|
+
this.checkToolAction(action, id);
|
|
244
|
+
}
|
|
245
|
+
if (patch.prompt !== undefined || actionChanged)
|
|
246
|
+
next.prompt = validatePromptFor(next.action, patch.prompt ?? job.prompt, id);
|
|
247
|
+
const kindChanged = isScheduleWhen(next.when) !== isScheduleWhen(job.when);
|
|
248
|
+
// The filter is checked against the (possibly new) when; a job that moves to a clock drops its filter.
|
|
249
|
+
if (patch.filter !== undefined || whenChanged) {
|
|
250
|
+
const filter = patch.filter !== undefined ? patch.filter : isScheduleWhen(next.when) ? {} : job.filter;
|
|
251
|
+
next.filter = validateJobFilter(filter, next.when, id);
|
|
252
|
+
}
|
|
253
|
+
if (patch.coalesce !== undefined)
|
|
254
|
+
next.coalesce = resolveCoalesce(patch.coalesce, job.coalesce, id);
|
|
255
|
+
// A job that changes between a clock and events takes the other kind's default limits.
|
|
256
|
+
const baseLimits = kindChanged ? defaultLimits(next.when) : job.limits;
|
|
257
|
+
if (patch.limits !== undefined || kindChanged)
|
|
258
|
+
next.limits = resolveLimits(patch.limits, baseLimits, id);
|
|
259
|
+
// Update (A-127): the deliveries are replaced as a whole; null or [] removes them.
|
|
260
|
+
if (patch.deliveries !== undefined) {
|
|
261
|
+
const deliveries = validateJobDeliveries(patch.deliveries, id);
|
|
262
|
+
if (deliveries.length)
|
|
263
|
+
next.deliveries = deliveries;
|
|
264
|
+
else
|
|
265
|
+
delete next.deliveries;
|
|
266
|
+
}
|
|
267
|
+
if (next.when.kind === "webhook" && !next.secret)
|
|
268
|
+
next.secret = generateWebhookSecret();
|
|
269
|
+
if (next.when.kind !== "webhook")
|
|
270
|
+
delete next.secret;
|
|
271
|
+
if (!next.enabled || !isScheduleWhen(next.when)) {
|
|
272
|
+
next.nextRunAt = null;
|
|
273
|
+
}
|
|
274
|
+
else if (whenChanged || !job.enabled || next.nextRunAt === null) {
|
|
275
|
+
// A new schedule, or turned back on: count from now — no catch-up for the time it was off.
|
|
276
|
+
const at = this.clock.firstRun(next.when);
|
|
277
|
+
if (!at)
|
|
278
|
+
throw new JobError(`${describeSchedule(next.when)} has no future run time`, "invalid_argument", id);
|
|
279
|
+
next.nextRunAt = at;
|
|
280
|
+
}
|
|
281
|
+
next.version = job.version + 1;
|
|
282
|
+
next.updatedAt = this.iso(this.now());
|
|
283
|
+
await this.store().save(next);
|
|
284
|
+
this.clock.sync(id, next);
|
|
285
|
+
// Re-enabled: queued runs may be due.
|
|
286
|
+
if (next.enabled && !job.enabled)
|
|
287
|
+
this.pump();
|
|
288
|
+
return next;
|
|
289
|
+
}
|
|
290
|
+
async delete(id) {
|
|
291
|
+
await this.require(id);
|
|
292
|
+
this.clock.sync(id, null);
|
|
293
|
+
for (const entry of this.active.values()) {
|
|
294
|
+
if (entry.run.jobId === id) {
|
|
295
|
+
entry.stopRequested = true;
|
|
296
|
+
entry.controller.abort();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
await this.store().delete(id);
|
|
300
|
+
}
|
|
301
|
+
async rotateSecret(id) {
|
|
302
|
+
const job = await this.require(id);
|
|
303
|
+
if (job.when.kind !== "webhook")
|
|
304
|
+
throw new JobError("Only a webhook job has a secret", "invalid_argument", id);
|
|
305
|
+
const next = { ...job, secret: generateWebhookSecret(), updatedAt: this.iso(this.now()) };
|
|
306
|
+
await this.store().save(next);
|
|
307
|
+
return next;
|
|
308
|
+
}
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
// AgentJobs — intake
|
|
311
|
+
// ---------------------------------------------------------------------------
|
|
312
|
+
async runNow(id) {
|
|
313
|
+
const job = await this.require(id);
|
|
314
|
+
if (this.disposed)
|
|
315
|
+
throw new JobError("The agent is stopped", "invalid_argument", id);
|
|
316
|
+
if (!isScheduleWhen(job.when)) {
|
|
317
|
+
throw new JobError("Run now is for schedule jobs — send a test event to an event or webhook job", "invalid_argument", id);
|
|
318
|
+
}
|
|
319
|
+
// Never overlap a job with itself.
|
|
320
|
+
if (this.queuing.has(id))
|
|
321
|
+
throw new JobError("A run of this job is already queued or running", "invalid_argument", id);
|
|
322
|
+
this.queuing.add(id);
|
|
323
|
+
try {
|
|
324
|
+
if (await this.store().hasActiveRun(id)) {
|
|
325
|
+
throw new JobError("A run of this job is already queued or running", "invalid_argument", id);
|
|
326
|
+
}
|
|
327
|
+
const nowIso = this.iso(this.now());
|
|
328
|
+
const result = await this.ingest(job, { source: "manual", sourceEventId: randomUUID(), type: "job.run-now", time: nowIso, data: null }, "manual");
|
|
329
|
+
if (!result.run)
|
|
330
|
+
throw new JobError(`The run was not queued: ${result.event.reason ?? result.event.status}`, "invalid_argument", id);
|
|
331
|
+
return result.run;
|
|
332
|
+
}
|
|
333
|
+
finally {
|
|
334
|
+
this.queuing.delete(id);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async sendTestEvent(id, input) {
|
|
338
|
+
const job = await this.require(id);
|
|
339
|
+
if (isScheduleWhen(job.when))
|
|
340
|
+
throw new JobError("A schedule job takes no events — use run now", "invalid_argument", id);
|
|
341
|
+
if (typeof input !== "object" || input === null)
|
|
342
|
+
throw new JobError("A test event must be an object", "invalid_argument", id);
|
|
343
|
+
const type = typeof input.type === "string" ? input.type.trim() : "";
|
|
344
|
+
if (!type || type.length > 200)
|
|
345
|
+
throw new JobError('A test event needs a "type" (at most 200 characters)', "invalid_argument", id);
|
|
346
|
+
if (input.subject !== undefined && toSubject(input.subject) === undefined) {
|
|
347
|
+
throw new JobError('"subject" must be a non-empty string', "invalid_argument", id);
|
|
348
|
+
}
|
|
349
|
+
if (input.revision !== undefined && toRevision(input.revision) === undefined) {
|
|
350
|
+
throw new JobError('"revision" must be a number', "invalid_argument", id);
|
|
351
|
+
}
|
|
352
|
+
if (dataBytes(input.data) > MAX_EVENT_DATA_BYTES) {
|
|
353
|
+
throw new JobError(`"data" is larger than ${MAX_EVENT_DATA_BYTES / 1024} KB`, "invalid_argument", id);
|
|
354
|
+
}
|
|
355
|
+
const subject = input.subject !== undefined ? toSubject(input.subject) : undefined;
|
|
356
|
+
const revision = input.revision !== undefined ? toRevision(input.revision) : undefined;
|
|
357
|
+
return this.ingest(job, {
|
|
358
|
+
source: "manual",
|
|
359
|
+
sourceEventId: randomUUID(),
|
|
360
|
+
type,
|
|
361
|
+
...(subject !== undefined ? { subject } : {}),
|
|
362
|
+
...(revision !== undefined ? { revision } : {}),
|
|
363
|
+
data: input.data ?? null,
|
|
364
|
+
}, "test");
|
|
365
|
+
}
|
|
366
|
+
async handleWebhook(id, request) {
|
|
367
|
+
if (request.method.toUpperCase() !== "POST")
|
|
368
|
+
return { status: 405, body: { error: "Use POST" } };
|
|
369
|
+
const job = await this.get(id);
|
|
370
|
+
if (!job || this.disposed)
|
|
371
|
+
return { status: 404, body: { error: "Job not found" } };
|
|
372
|
+
if (job.when.kind !== "webhook")
|
|
373
|
+
return { status: 404, body: { error: "This job takes no webhooks" } };
|
|
374
|
+
if (!job.enabled)
|
|
375
|
+
return { status: 409, body: { error: "The job is disabled" } };
|
|
376
|
+
if (!job.secret)
|
|
377
|
+
return { status: 503, body: { error: "The job has no secret" } };
|
|
378
|
+
const size = typeof request.body === "string" ? Buffer.byteLength(request.body, "utf8") : request.body.byteLength;
|
|
379
|
+
if (size > MAX_WEBHOOK_BODY_BYTES)
|
|
380
|
+
return { status: 413, body: { error: `The body is larger than ${MAX_WEBHOOK_BODY_BYTES / 1024} KB` } };
|
|
381
|
+
// The signature is checked on the raw bytes, before anything is parsed.
|
|
382
|
+
const invalid = verifyWebhookSignature(job.when.signature, job.secret, request, this.now());
|
|
383
|
+
if (invalid)
|
|
384
|
+
return { status: 401, body: { error: `Unauthorized: ${invalid}` } };
|
|
385
|
+
const envelope = parseWebhookEvent(job.when, request);
|
|
386
|
+
if ("error" in envelope)
|
|
387
|
+
return { status: 400, body: { error: envelope.error } };
|
|
388
|
+
if (dataBytes(envelope.data) > MAX_EVENT_DATA_BYTES) {
|
|
389
|
+
return { status: 413, body: { error: `The event data is larger than ${MAX_EVENT_DATA_BYTES / 1024} KB` } };
|
|
390
|
+
}
|
|
391
|
+
// Resolves only once the store has the event: a store failure rejects, so the host
|
|
392
|
+
// answers 5xx and the sender keeps the delivery.
|
|
393
|
+
const result = await this.ingest(job, envelope, "webhook");
|
|
394
|
+
if (result.duplicate)
|
|
395
|
+
return { status: 200, body: { duplicate: true, eventId: result.event.id } };
|
|
396
|
+
return {
|
|
397
|
+
status: 202,
|
|
398
|
+
body: {
|
|
399
|
+
eventId: result.event.id,
|
|
400
|
+
status: result.event.status,
|
|
401
|
+
...(result.run ? { runId: result.run.id } : {}),
|
|
402
|
+
...(result.event.reason ? { reason: result.event.reason } : {}),
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
// ---------------------------------------------------------------------------
|
|
407
|
+
// AgentJobs — history and control
|
|
408
|
+
// ---------------------------------------------------------------------------
|
|
409
|
+
async listEvents(id, limit = 50) {
|
|
410
|
+
await this.require(id);
|
|
411
|
+
return this.store().listEvents(id, clampLimit(limit));
|
|
412
|
+
}
|
|
413
|
+
async listRuns(id, limit = 50) {
|
|
414
|
+
await this.require(id);
|
|
415
|
+
return this.store().listRuns(id, clampLimit(limit));
|
|
416
|
+
}
|
|
417
|
+
async getRun(runId) {
|
|
418
|
+
const run = await this.store().getRun(runId);
|
|
419
|
+
return run && run.agentId === this.deps.agentId ? run : null;
|
|
420
|
+
}
|
|
421
|
+
async getRunEvents(runId) {
|
|
422
|
+
const run = await this.requireRun(runId);
|
|
423
|
+
return this.store().getEvents(run.eventIds);
|
|
424
|
+
}
|
|
425
|
+
async stopRun(runId) {
|
|
426
|
+
const run = await this.requireRun(runId);
|
|
427
|
+
const entry = this.active.get(runId);
|
|
428
|
+
if (entry) {
|
|
429
|
+
entry.stopRequested = true;
|
|
430
|
+
entry.controller.abort();
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
if (run.status !== "pending" && run.status !== "waiting")
|
|
434
|
+
return false;
|
|
435
|
+
const nowIso = this.iso(this.now());
|
|
436
|
+
const stopped = await this.store().updateRun(runId, null, { status: "stopped", finishedAt: nowIso, reason: "Stopped before it started" }, nowIso);
|
|
437
|
+
if (stopped)
|
|
438
|
+
await this.emitFinished(stopped, "stopped", { reason: "Stopped before it started" });
|
|
439
|
+
return stopped !== null;
|
|
440
|
+
}
|
|
441
|
+
async replayRun(runId) {
|
|
442
|
+
const original = await this.requireRun(runId);
|
|
443
|
+
if (original.status === "pending" || original.status === "waiting" || original.status === "running") {
|
|
444
|
+
throw new JobError("The run has not finished yet", "invalid_argument", original.jobId);
|
|
445
|
+
}
|
|
446
|
+
const job = await this.require(original.jobId);
|
|
447
|
+
const now = this.now();
|
|
448
|
+
const nowIso = this.iso(now);
|
|
449
|
+
const replay = {
|
|
450
|
+
id: randomUUID(),
|
|
451
|
+
jobId: job.id,
|
|
452
|
+
agentId: this.deps.agentId,
|
|
453
|
+
jobVersion: job.version,
|
|
454
|
+
cause: "replay",
|
|
455
|
+
bucketKey: original.bucketKey,
|
|
456
|
+
status: "waiting",
|
|
457
|
+
// The same events: replay keeps their identity.
|
|
458
|
+
eventIds: [...original.eventIds],
|
|
459
|
+
...(original.revision !== undefined ? { revision: original.revision } : {}),
|
|
460
|
+
correlationId: original.correlationId,
|
|
461
|
+
depth: original.depth,
|
|
462
|
+
notBefore: nowIso,
|
|
463
|
+
deadline: nowIso,
|
|
464
|
+
expiresAt: this.iso(now + job.limits.runDeadlineMs),
|
|
465
|
+
attempts: 0,
|
|
466
|
+
maxAttempts: job.limits.maxAttempts,
|
|
467
|
+
replayOf: original.id,
|
|
468
|
+
createdAt: nowIso,
|
|
469
|
+
updatedAt: nowIso,
|
|
470
|
+
};
|
|
471
|
+
await this.store().insertRun(replay);
|
|
472
|
+
this.pump();
|
|
473
|
+
return replay;
|
|
474
|
+
}
|
|
475
|
+
/** Whether a run of this job is queued or running. */
|
|
476
|
+
async isRunning(id) {
|
|
477
|
+
return this.store().hasActiveRun(id);
|
|
478
|
+
}
|
|
479
|
+
/** A-103: a tool job's tool must be one of the agent's tools and marked schedulable. */
|
|
480
|
+
checkToolAction(action, id) {
|
|
481
|
+
if (action.kind !== "tool")
|
|
482
|
+
return;
|
|
483
|
+
if (!this.deps.runTool)
|
|
484
|
+
throw new JobError("This agent can't run tool jobs", "invalid_argument", id);
|
|
485
|
+
const problem = this.deps.checkTool?.(action.tool);
|
|
486
|
+
if (problem)
|
|
487
|
+
throw new JobError(problem, "invalid_argument", id);
|
|
488
|
+
}
|
|
489
|
+
// ---------------------------------------------------------------------------
|
|
490
|
+
// Intake
|
|
491
|
+
// ---------------------------------------------------------------------------
|
|
492
|
+
/** A schedule job's time came (the JobClock): one tick into its inbox. */
|
|
493
|
+
async onTick(job, scheduledAt, cause) {
|
|
494
|
+
if (this.disposed)
|
|
495
|
+
return;
|
|
496
|
+
// Never overlap a job with itself: a tick while a run is still queued or running is
|
|
497
|
+
// recorded as suppressed (it was "skipped").
|
|
498
|
+
const taken = this.queuing.has(job.id);
|
|
499
|
+
if (!taken)
|
|
500
|
+
this.queuing.add(job.id);
|
|
501
|
+
try {
|
|
502
|
+
const busy = taken || (await this.store().hasActiveRun(job.id));
|
|
503
|
+
await this.ingest(job, { source: "schedule", sourceEventId: scheduledAt, type: "job.tick", time: scheduledAt, data: { scheduledAt } }, cause, undefined, undefined, busy ? "The previous run was still in progress" : undefined);
|
|
504
|
+
}
|
|
505
|
+
finally {
|
|
506
|
+
if (!taken)
|
|
507
|
+
this.queuing.delete(job.id);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/** One of the agent's SDK events: offer it to every enabled "event" job. */
|
|
511
|
+
async onBusEvent(event) {
|
|
512
|
+
if (this.disposed)
|
|
513
|
+
return;
|
|
514
|
+
const envelope = internalEnvelope(this.deps.agentId, event);
|
|
515
|
+
if (!envelope)
|
|
516
|
+
return;
|
|
517
|
+
try {
|
|
518
|
+
const jobs = (await this.store().listByAgent(this.deps.agentId)).filter((j) => j.enabled && j.when.kind === "event");
|
|
519
|
+
// Only jobs that asked for this type see it — no inbox entry for every job run.
|
|
520
|
+
const interested = jobs.filter((j) => j.filter.types?.some((p) => typeMatches(p, envelope.type)));
|
|
521
|
+
if (interested.length === 0)
|
|
522
|
+
return;
|
|
523
|
+
const origin = await this.originOf(event.sessionId);
|
|
524
|
+
for (const job of interested) {
|
|
525
|
+
await this.ingest(job, envelope, "event", origin, event.id);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
catch (err) {
|
|
529
|
+
console.error(`[jobs] agent=${this.deps.agentId} could not take event ${event.type}:`, err);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* The single intake path: build the inbox entry, filter it, apply the loop
|
|
534
|
+
* guard, and accept it into the store (dedupe + coalesce, atomically).
|
|
535
|
+
* `suppress` records the event as suppressed for that reason (a busy schedule job).
|
|
536
|
+
*/
|
|
537
|
+
async ingest(job, envelope, cause, origin, causationId, suppress) {
|
|
538
|
+
const now = this.now();
|
|
539
|
+
const nowIso = this.iso(now);
|
|
540
|
+
const event = {
|
|
541
|
+
id: randomUUID(),
|
|
542
|
+
jobId: job.id,
|
|
543
|
+
agentId: this.deps.agentId,
|
|
544
|
+
source: envelope.source,
|
|
545
|
+
sourceEventId: envelope.sourceEventId,
|
|
546
|
+
type: envelope.type,
|
|
547
|
+
...(envelope.subject !== undefined ? { subject: envelope.subject } : {}),
|
|
548
|
+
...(envelope.revision !== undefined ? { revision: envelope.revision } : {}),
|
|
549
|
+
time: envelope.time ?? nowIso,
|
|
550
|
+
receivedAt: nowIso,
|
|
551
|
+
data: envelope.data ?? null,
|
|
552
|
+
correlationId: origin?.correlationId ?? randomUUID(),
|
|
553
|
+
...(causationId ? { causationId } : {}),
|
|
554
|
+
...(origin ? { originRunId: origin.originRunId } : {}),
|
|
555
|
+
depth: origin?.depth ?? 0,
|
|
556
|
+
status: "accepted",
|
|
557
|
+
};
|
|
558
|
+
const schedule = isScheduleWhen(job.when);
|
|
559
|
+
const mismatch = schedule ? undefined : filterMismatch(job.filter, viewOf(event));
|
|
560
|
+
if (suppress) {
|
|
561
|
+
event.status = "suppressed";
|
|
562
|
+
event.reason = suppress;
|
|
563
|
+
}
|
|
564
|
+
else if (mismatch) {
|
|
565
|
+
event.status = "filtered";
|
|
566
|
+
event.reason = mismatch;
|
|
567
|
+
}
|
|
568
|
+
else if (event.depth > job.limits.maxDepth) {
|
|
569
|
+
// Loop guard: output of an event job's run does not wake a job unless allowed (maxDepth).
|
|
570
|
+
event.status = "suppressed";
|
|
571
|
+
event.reason = `caused by job run ${event.originRunId} (chain depth ${event.depth} is over the limit of ${job.limits.maxDepth})`;
|
|
572
|
+
}
|
|
573
|
+
let runPlan;
|
|
574
|
+
if (event.status === "accepted") {
|
|
575
|
+
const bucketKey = event.subject ?? "";
|
|
576
|
+
// A clock tick or run now is due at once and never coalesces with another one.
|
|
577
|
+
const coalesce = schedule ? { quietMs: 0, maxWaitMs: 0, maxBatch: 1 } : job.coalesce;
|
|
578
|
+
let notBefore = now + coalesce.quietMs;
|
|
579
|
+
if (job.limits.cooldownMs > 0) {
|
|
580
|
+
const last = await this.store().lastSucceeded(job.id, bucketKey);
|
|
581
|
+
if (last?.finishedAt)
|
|
582
|
+
notBefore = Math.max(notBefore, Date.parse(last.finishedAt) + job.limits.cooldownMs);
|
|
583
|
+
}
|
|
584
|
+
const deadline = Math.max(now + coalesce.maxWaitMs, notBefore);
|
|
585
|
+
runPlan = {
|
|
586
|
+
newRun: {
|
|
587
|
+
id: randomUUID(),
|
|
588
|
+
jobId: job.id,
|
|
589
|
+
agentId: this.deps.agentId,
|
|
590
|
+
jobVersion: job.version,
|
|
591
|
+
cause,
|
|
592
|
+
bucketKey,
|
|
593
|
+
status: "pending",
|
|
594
|
+
eventIds: [event.id],
|
|
595
|
+
...(event.revision !== undefined ? { revision: event.revision } : {}),
|
|
596
|
+
correlationId: event.correlationId,
|
|
597
|
+
depth: event.depth,
|
|
598
|
+
notBefore: this.iso(notBefore),
|
|
599
|
+
deadline: this.iso(deadline),
|
|
600
|
+
expiresAt: this.iso(notBefore + job.limits.runDeadlineMs),
|
|
601
|
+
attempts: 0,
|
|
602
|
+
maxAttempts: job.limits.maxAttempts,
|
|
603
|
+
createdAt: nowIso,
|
|
604
|
+
updatedAt: nowIso,
|
|
605
|
+
},
|
|
606
|
+
joinNotBefore: this.iso(now + coalesce.quietMs),
|
|
607
|
+
maxBatch: coalesce.maxBatch,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
const result = await this.store().accept({ event, ...(runPlan ? { run: runPlan } : {}) });
|
|
611
|
+
this.deps.eventBus.emit({
|
|
612
|
+
type: SDKEventType.JobEventReceived,
|
|
613
|
+
sessionId: "",
|
|
614
|
+
payload: {
|
|
615
|
+
agentId: this.deps.agentId,
|
|
616
|
+
jobId: job.id,
|
|
617
|
+
eventId: result.event.id,
|
|
618
|
+
type: result.event.type,
|
|
619
|
+
status: result.duplicate ? "duplicate" : result.event.status,
|
|
620
|
+
...(result.run ? { runId: result.run.id } : {}),
|
|
621
|
+
...(result.event.reason ? { reason: result.event.reason } : {}),
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
if (result.run)
|
|
625
|
+
this.wakeAt(Date.parse(result.run.notBefore));
|
|
626
|
+
// Filtered and suppressed events start no run (whose end prunes), so they prune here.
|
|
627
|
+
else if (!result.duplicate) {
|
|
628
|
+
await this.store()
|
|
629
|
+
.prune(job.id, KEEP_JOB_EVENTS, KEEP_JOB_RUNS)
|
|
630
|
+
.catch((err) => console.warn(`[jobs] agent=${this.deps.agentId} could not prune history:`, err));
|
|
631
|
+
}
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
634
|
+
/** When `sessionId` is a job run's session, the run and chain depth an event from it continues. */
|
|
635
|
+
async originOf(sessionId) {
|
|
636
|
+
if (!sessionId)
|
|
637
|
+
return undefined;
|
|
638
|
+
const entry = this.bySession.get(sessionId);
|
|
639
|
+
if (entry)
|
|
640
|
+
return { originRunId: entry.run.id, correlationId: entry.run.correlationId, depth: entry.eventDepth };
|
|
641
|
+
const session = await this.deps.getSessions().get(sessionId).catch(() => null);
|
|
642
|
+
const meta = session?.metadata;
|
|
643
|
+
if (!meta || meta["source"] !== "job" || typeof meta["runId"] !== "string")
|
|
644
|
+
return undefined;
|
|
645
|
+
return {
|
|
646
|
+
originRunId: meta["runId"],
|
|
647
|
+
correlationId: typeof meta["correlationId"] === "string" ? meta["correlationId"] : randomUUID(),
|
|
648
|
+
depth: typeof meta["eventDepth"] === "number" ? meta["eventDepth"] : 0,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
// ---------------------------------------------------------------------------
|
|
652
|
+
// Worker
|
|
653
|
+
// ---------------------------------------------------------------------------
|
|
654
|
+
/** Arm a wake-up for a run that becomes due at `at` (only the soonest is kept). */
|
|
655
|
+
wakeAt(at) {
|
|
656
|
+
if (!this.started || this.disposed)
|
|
657
|
+
return;
|
|
658
|
+
if (at <= this.now()) {
|
|
659
|
+
this.pump();
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
if (this.wakeTimer && this.wakeTimer.at <= at)
|
|
663
|
+
return;
|
|
664
|
+
this.wakeTimer?.cancel();
|
|
665
|
+
this.wakeTimer = armTimer(at, () => {
|
|
666
|
+
this.wakeTimer = undefined;
|
|
667
|
+
this.pump();
|
|
668
|
+
}, this.now);
|
|
669
|
+
}
|
|
670
|
+
/** Claim and start due runs while there is room. Re-entrant calls coalesce. */
|
|
671
|
+
pump() {
|
|
672
|
+
if (!this.started || this.disposed)
|
|
673
|
+
return;
|
|
674
|
+
if (this.pumping) {
|
|
675
|
+
this.pumpAgain = true;
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
this.pumping = true;
|
|
679
|
+
this.track(this.claimLoop()
|
|
680
|
+
.catch((err) => console.error(`[jobs] agent=${this.deps.agentId} could not claim runs:`, err))
|
|
681
|
+
.finally(() => {
|
|
682
|
+
this.pumping = false;
|
|
683
|
+
if (this.pumpAgain) {
|
|
684
|
+
this.pumpAgain = false;
|
|
685
|
+
this.pump();
|
|
686
|
+
}
|
|
687
|
+
}));
|
|
688
|
+
}
|
|
689
|
+
async claimLoop() {
|
|
690
|
+
while (!this.disposed && this.hasRoom()) {
|
|
691
|
+
// Jobs already at their own concurrency limit are skipped this round.
|
|
692
|
+
const jobs = await this.store().listByAgent(this.deps.agentId);
|
|
693
|
+
const exclude = jobs
|
|
694
|
+
.filter((j) => [...this.active.values()].filter((a) => a.run.jobId === j.id).length >= j.limits.maxConcurrentRuns)
|
|
695
|
+
.map((j) => j.id);
|
|
696
|
+
const now = this.now();
|
|
697
|
+
const run = await this.store().claim({
|
|
698
|
+
agentId: this.deps.agentId,
|
|
699
|
+
now: this.iso(now),
|
|
700
|
+
owner: this.owner,
|
|
701
|
+
leaseUntil: this.iso(now + this.leaseMs),
|
|
702
|
+
...(exclude.length ? { excludeJobIds: exclude } : {}),
|
|
703
|
+
});
|
|
704
|
+
if (!run)
|
|
705
|
+
return;
|
|
706
|
+
this.launch(run);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
/** Room for one more run: under this manager's cap, and a turn left for people's chats. */
|
|
710
|
+
hasRoom() {
|
|
711
|
+
if (this.active.size >= (this.deps.maxParallelRuns ?? MAX_PARALLEL_JOB_RUNS))
|
|
712
|
+
return false;
|
|
713
|
+
const { running, max } = this.deps.getCapacity();
|
|
714
|
+
if (max <= 0)
|
|
715
|
+
return true;
|
|
716
|
+
if (max === 1)
|
|
717
|
+
return running === 0;
|
|
718
|
+
return running < max - 1;
|
|
719
|
+
}
|
|
720
|
+
launch(run) {
|
|
721
|
+
const entry = { run, controller: new AbortController(), stopRequested: false, leaseLost: false, deniedTools: [], eventDepth: 0 };
|
|
722
|
+
this.active.set(run.id, entry);
|
|
723
|
+
this.track(this.process(entry)
|
|
724
|
+
.catch((err) => console.error(`[jobs] agent=${this.deps.agentId} run=${run.id} failed unexpectedly:`, err))
|
|
725
|
+
.finally(() => {
|
|
726
|
+
this.active.delete(run.id);
|
|
727
|
+
if (entry.sessionId && this.bySession.get(entry.sessionId) === entry)
|
|
728
|
+
this.bySession.delete(entry.sessionId);
|
|
729
|
+
this.pump();
|
|
730
|
+
}));
|
|
731
|
+
}
|
|
732
|
+
/** Work one claimed run to its next state. */
|
|
733
|
+
async process(entry) {
|
|
734
|
+
let run = entry.run;
|
|
735
|
+
const job = await this.store().get(run.jobId);
|
|
736
|
+
if (!job || job.agentId !== this.deps.agentId)
|
|
737
|
+
return void (await this.finish(entry, "suppressed", { reason: "The job was deleted" }));
|
|
738
|
+
// Run now works on a disabled job too (as before A-126), and a one-off ("at") job turns itself
|
|
739
|
+
// off as its time fires; anything else waits for the job to be enabled.
|
|
740
|
+
const oneOffTick = job.when.kind === "at" && (run.cause === "schedule" || run.cause === "catch-up");
|
|
741
|
+
if (!job.enabled && run.cause !== "manual" && !oneOffTick)
|
|
742
|
+
return void (await this.finish(entry, "suppressed", { reason: "The job is disabled" }));
|
|
743
|
+
entry.eventDepth = eventDepthOf(job, run);
|
|
744
|
+
// The turn already finished before a crash: only record the result.
|
|
745
|
+
if (run.resultAt)
|
|
746
|
+
return void (await this.finalize(entry, job));
|
|
747
|
+
if (run.attempts > run.maxAttempts) {
|
|
748
|
+
return void (await this.finish(entry, "failed", { error: `Gave up after ${run.maxAttempts} attempts${run.error ? `: ${run.error}` : ""}` }));
|
|
749
|
+
}
|
|
750
|
+
const now = this.now();
|
|
751
|
+
if (now > Date.parse(run.expiresAt)) {
|
|
752
|
+
return void (await this.finish(entry, "failed", { error: `The run's deadline passed${run.error ? `: ${run.error}` : ""}` }));
|
|
753
|
+
}
|
|
754
|
+
// -- Is the work still wanted? --
|
|
755
|
+
let events = await this.store().getEvents(run.eventIds);
|
|
756
|
+
if (run.jobVersion !== job.version && !isScheduleWhen(job.when)) {
|
|
757
|
+
// The job was edited after these events were queued: keep the ones it still accepts.
|
|
758
|
+
events = events.filter((e) => !filterMismatch(job.filter, viewOf(e)));
|
|
759
|
+
}
|
|
760
|
+
if (events.length === 0)
|
|
761
|
+
return void (await this.finish(entry, "suppressed", { reason: "The job no longer accepts these events" }));
|
|
762
|
+
if (run.revision !== undefined) {
|
|
763
|
+
const last = await this.store().lastSucceeded(job.id, run.bucketKey);
|
|
764
|
+
if (last && last.id !== run.id && last.revision !== undefined && last.revision >= run.revision) {
|
|
765
|
+
return void (await this.finish(entry, "suppressed", { reason: `Revision ${run.revision} is not newer than revision ${last.revision}, already handled` }));
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
const resolved = await resolvedSince(events, this.store());
|
|
769
|
+
if (resolved)
|
|
770
|
+
return void (await this.finish(entry, "suppressed", { reason: `Resolved: ${resolved}` }));
|
|
771
|
+
// -- Limits --
|
|
772
|
+
const maxRunsPerHour = job.limits.maxRunsPerHour;
|
|
773
|
+
if (maxRunsPerHour !== undefined) {
|
|
774
|
+
const hour = await this.store().usageSince(job.id, this.iso(now - HOUR));
|
|
775
|
+
if (hour.runs >= maxRunsPerHour) {
|
|
776
|
+
const retryAt = now + Math.max(60_000, Math.ceil(HOUR / maxRunsPerHour));
|
|
777
|
+
// Waiting for the window is not an attempt.
|
|
778
|
+
await this.write(entry, {
|
|
779
|
+
status: "waiting",
|
|
780
|
+
notBefore: this.iso(retryAt),
|
|
781
|
+
attempts: Math.max(0, run.attempts - 1),
|
|
782
|
+
reason: `Rate limit: ${hour.runs} runs in the last hour (limit ${maxRunsPerHour})`,
|
|
783
|
+
releaseLease: true,
|
|
784
|
+
});
|
|
785
|
+
this.wakeAt(retryAt);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (job.limits.maxTokensPerDay !== undefined) {
|
|
790
|
+
const day = await this.store().usageSince(job.id, this.iso(now - DAY));
|
|
791
|
+
if (day.tokens >= job.limits.maxTokensPerDay) {
|
|
792
|
+
return void (await this.finish(entry, "blocked", { reason: `Token budget used up: ${day.tokens} of ${job.limits.maxTokensPerDay} tokens in the last 24 hours` }));
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
// -- Run the turn --
|
|
796
|
+
// A-103: a tool job runs its stored call (and maybe a follow-up turn) instead of a turn.
|
|
797
|
+
const toolAction = job.action?.kind === "tool" ? job.action : undefined;
|
|
798
|
+
// A-103: "since last run" placeholders read the history before this run joins it.
|
|
799
|
+
const history = usesRunHistory(job.prompt) ? await this.runHistory(job.id, run.id) : undefined;
|
|
800
|
+
const sessionId = run.sessionId ?? (await this.resolveSession(job, run, entry.eventDepth));
|
|
801
|
+
const started = await this.write(entry, {
|
|
802
|
+
sessionId,
|
|
803
|
+
...(run.startedAt ? {} : { startedAt: this.iso(now) }),
|
|
804
|
+
...(toolAction ? { action: "tool" } : {}),
|
|
805
|
+
clear: ["reason"],
|
|
806
|
+
});
|
|
807
|
+
if (!started)
|
|
808
|
+
return;
|
|
809
|
+
run = started;
|
|
810
|
+
entry.sessionId = sessionId;
|
|
811
|
+
this.bySession.set(sessionId, entry);
|
|
812
|
+
await this.setJobState(job.id, { lastRunAt: run.startedAt, lastStatus: "running" });
|
|
813
|
+
this.deps.eventBus.emit({
|
|
814
|
+
type: SDKEventType.JobRunStarted,
|
|
815
|
+
sessionId,
|
|
816
|
+
payload: { agentId: this.deps.agentId, jobId: job.id, jobName: job.name, runId: run.id, cause: run.cause, attempt: run.attempts },
|
|
817
|
+
});
|
|
818
|
+
console.log(`[jobs] agent=${this.deps.agentId} job="${job.name}" run=${run.id} cause=${run.cause} attempt=${run.attempts} events=${events.length} session=${sessionId}`);
|
|
819
|
+
const renew = setInterval(() => {
|
|
820
|
+
void this.store()
|
|
821
|
+
.renewLease(run.id, this.owner, this.iso(this.now() + this.leaseMs))
|
|
822
|
+
.then((held) => {
|
|
823
|
+
if (!held && !entry.leaseLost) {
|
|
824
|
+
entry.leaseLost = true;
|
|
825
|
+
entry.controller.abort();
|
|
826
|
+
}
|
|
827
|
+
})
|
|
828
|
+
.catch(() => undefined);
|
|
829
|
+
}, Math.max(1_000, Math.floor(this.leaseMs / 3)));
|
|
830
|
+
renew.unref?.();
|
|
831
|
+
// A-103: no attempt runs longer than the job's time limit.
|
|
832
|
+
const maxRunMs = job.limits.maxRunMs ?? DEFAULT_MAX_RUN_MS;
|
|
833
|
+
const timeLimit = setTimeout(() => {
|
|
834
|
+
entry.timedOut = true;
|
|
835
|
+
entry.controller.abort();
|
|
836
|
+
}, maxRunMs);
|
|
837
|
+
timeLimit.unref?.();
|
|
838
|
+
const context = {
|
|
839
|
+
agentId: this.deps.agentId,
|
|
840
|
+
jobId: job.id,
|
|
841
|
+
jobName: job.name,
|
|
842
|
+
runId: run.id,
|
|
843
|
+
cause: run.cause,
|
|
844
|
+
attempt: run.attempts,
|
|
845
|
+
sessionId,
|
|
846
|
+
prompt: renderJobPrompt(job, events, history),
|
|
847
|
+
signal: entry.controller.signal,
|
|
848
|
+
};
|
|
849
|
+
let result;
|
|
850
|
+
let failure;
|
|
851
|
+
try {
|
|
852
|
+
result = toolAction ? await this.runToolAction(entry, toolAction, context) : await this.deps.getRunner()(context);
|
|
853
|
+
}
|
|
854
|
+
catch (err) {
|
|
855
|
+
failure = err;
|
|
856
|
+
}
|
|
857
|
+
finally {
|
|
858
|
+
clearInterval(renew);
|
|
859
|
+
clearTimeout(timeLimit);
|
|
860
|
+
entry.approvedCall = undefined;
|
|
861
|
+
}
|
|
862
|
+
if (entry.leaseLost) {
|
|
863
|
+
console.warn(`[jobs] agent=${this.deps.agentId} run=${run.id} lost its lease; another worker has it`);
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
// A-103: past its time limit — a failure, not a person's stop, and not retried.
|
|
867
|
+
if (entry.timedOut && !entry.stopRequested && !this.disposed) {
|
|
868
|
+
return void (await this.finish(entry, "failed", {
|
|
869
|
+
error: `Timed out after ${describeDuration(maxRunMs)} (the job's time limit)`,
|
|
870
|
+
...(result?.output ? { output: result.output.slice(0, MAX_OUTPUT_CHARS) } : {}),
|
|
871
|
+
}, job));
|
|
872
|
+
}
|
|
873
|
+
// Stopped here (stopRun / delete) or through the host (its stop button for the session).
|
|
874
|
+
if (entry.stopRequested || (failure === undefined && result?.aborted && !this.disposed)) {
|
|
875
|
+
return void (await this.finish(entry, "stopped", {
|
|
876
|
+
reason: "Stopped by a person",
|
|
877
|
+
...(result?.output ? { output: result.output.slice(0, MAX_OUTPUT_CHARS) } : {}),
|
|
878
|
+
}));
|
|
879
|
+
}
|
|
880
|
+
// A turn that finished before the shutdown keeps its result (recorded below), so it is not run again.
|
|
881
|
+
const finishedTurn = failure === undefined && result !== undefined && !result.aborted;
|
|
882
|
+
if (this.disposed && entry.controller.signal.aborted && !finishedTurn) {
|
|
883
|
+
// Shut down mid-run: give the run back so it is taken up after the restart.
|
|
884
|
+
await this.write(entry, {
|
|
885
|
+
status: "waiting",
|
|
886
|
+
notBefore: this.iso(this.now()),
|
|
887
|
+
attempts: Math.max(0, run.attempts - 1),
|
|
888
|
+
reason: "Interrupted: the agent stopped during the run",
|
|
889
|
+
releaseLease: true,
|
|
890
|
+
});
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
// A-103: the tool failed and no follow-up turn ran — the run failed with the start of
|
|
894
|
+
// the tool's output (the session keeps all of it). Retried like any failed attempt.
|
|
895
|
+
if (failure === undefined && result?.toolError !== undefined && !result.followedUp) {
|
|
896
|
+
failure = new Error(`${toolAction?.tool ?? "The tool"} failed: ${result.toolError.slice(0, MAX_TOOL_ERROR_CHARS)}`);
|
|
897
|
+
}
|
|
898
|
+
if (failure === undefined && result && !result.aborted) {
|
|
899
|
+
const blocked = entry.deniedTools.length ? `Needs approval: ${entry.deniedTools.join(", ")} (approvals cannot be given in a run started by a job)` : undefined;
|
|
900
|
+
// Checkpoint the result first: if the process dies now, a reclaim only records it.
|
|
901
|
+
const checkpoint = await this.write(entry, {
|
|
902
|
+
resultAt: this.iso(this.now()),
|
|
903
|
+
...(result.output ? { output: result.output.slice(0, MAX_OUTPUT_CHARS) } : {}),
|
|
904
|
+
...(result.usage ? { usage: { inputTokens: result.usage.inputTokens, outputTokens: result.usage.outputTokens } } : {}),
|
|
905
|
+
...(result.stopReason ? { stopReason: result.stopReason } : {}),
|
|
906
|
+
...(blocked ? { reason: blocked } : {}),
|
|
907
|
+
// A-103: a tool that printed nothing — a silent run (finalize).
|
|
908
|
+
...(result.empty ? { silent: true } : {}),
|
|
909
|
+
// A-103: a follow-up turn after a failed tool — the run stays failed (finalize).
|
|
910
|
+
...(result.toolError !== undefined ? { error: `${toolAction?.tool ?? "The tool"} failed: ${result.toolError.slice(0, MAX_TOOL_ERROR_CHARS)}` } : {}),
|
|
911
|
+
...(result.toolError !== undefined ? {} : { clear: ["error"] }),
|
|
912
|
+
});
|
|
913
|
+
if (!checkpoint)
|
|
914
|
+
return;
|
|
915
|
+
entry.run = checkpoint;
|
|
916
|
+
return void (await this.finalize(entry, job));
|
|
917
|
+
}
|
|
918
|
+
const error = failure !== undefined ? errorMessage(failure) : "The turn ended without a result";
|
|
919
|
+
// An SDKError says whether retrying can help; anything else (a network error...) is treated as transient.
|
|
920
|
+
const retryable = !(failure instanceof SDKError) || failure.retryable;
|
|
921
|
+
const delay = this.retryDelay(run.attempts);
|
|
922
|
+
const retryAt = this.now() + delay;
|
|
923
|
+
if (retryable && run.attempts < run.maxAttempts && retryAt < Date.parse(run.expiresAt)) {
|
|
924
|
+
await this.write(entry, { status: "waiting", notBefore: this.iso(retryAt), error, releaseLease: true });
|
|
925
|
+
this.deps.eventBus.emit({
|
|
926
|
+
type: SDKEventType.JobRunRetrying,
|
|
927
|
+
sessionId,
|
|
928
|
+
payload: { agentId: this.deps.agentId, jobId: job.id, jobName: job.name, runId: run.id, attempt: run.attempts, error, retryAt: this.iso(retryAt) },
|
|
929
|
+
});
|
|
930
|
+
console.warn(`[jobs] agent=${this.deps.agentId} run=${run.id} attempt ${run.attempts} failed, retrying at ${this.iso(retryAt)}: ${error}`);
|
|
931
|
+
this.wakeAt(retryAt);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
await this.finish(entry, "failed", { error });
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Record the checkpointed result as the run's outcome; the in-app delivery is this same write.
|
|
938
|
+
* Update (A-126): the reply's marker decides it — [[SILENT]] succeeds without anything to
|
|
939
|
+
* deliver, [[FAILED]] <reason> fails (a deliberate answer, so it is not retried).
|
|
940
|
+
*/
|
|
941
|
+
async finalize(entry, job) {
|
|
942
|
+
const run = entry.run;
|
|
943
|
+
const deliveredAt = this.iso(this.now());
|
|
944
|
+
if (run.reason)
|
|
945
|
+
return void (await this.finish(entry, "blocked", { deliveredAt }, job));
|
|
946
|
+
const outcome = replyOutcome(run.output);
|
|
947
|
+
if (outcome.kind === "silent")
|
|
948
|
+
return void (await this.finish(entry, "succeeded", { deliveredAt, silent: true }, job));
|
|
949
|
+
if (outcome.kind === "failed")
|
|
950
|
+
return void (await this.finish(entry, "failed", { deliveredAt, error: outcome.reason }, job));
|
|
951
|
+
// A-103: a tool job whose tool failed stays failed after its follow-up turn; the reply
|
|
952
|
+
// (e.g. "what went wrong and how to fix it") is the error people are told.
|
|
953
|
+
if (run.action === "tool" && run.error) {
|
|
954
|
+
const reply = run.output?.trim();
|
|
955
|
+
return void (await this.finish(entry, "failed", { deliveredAt, error: reply ? reply.slice(0, MAX_OUTPUT_CHARS) : run.error }, job));
|
|
956
|
+
}
|
|
957
|
+
// A-103: a tool job that printed nothing has nothing to report, like [[SILENT]].
|
|
958
|
+
if (run.action === "tool" && (run.silent || !run.output?.trim()))
|
|
959
|
+
return void (await this.finish(entry, "succeeded", { deliveredAt, silent: true }, job));
|
|
960
|
+
await this.finish(entry, "succeeded", { deliveredAt }, job);
|
|
961
|
+
}
|
|
962
|
+
async finish(entry, status, fields, job) {
|
|
963
|
+
const done = await this.write(entry, { status, finishedAt: this.iso(this.now()), releaseLease: true, ...fields });
|
|
964
|
+
if (!done)
|
|
965
|
+
return;
|
|
966
|
+
// A suppressed run did no work: the job's last status stays what it was.
|
|
967
|
+
let paused = false;
|
|
968
|
+
if (status !== "suppressed") {
|
|
969
|
+
const error = fields.error ?? (status === "blocked" ? done.reason : undefined);
|
|
970
|
+
// A-103: too many failed runs in a row turn the job off.
|
|
971
|
+
const streak = status === "failed" || status === "blocked" ? await this.failureStreak(done.jobId) : undefined;
|
|
972
|
+
paused = streak !== undefined;
|
|
973
|
+
await this.setJobState(done.jobId, {
|
|
974
|
+
lastStatus: status,
|
|
975
|
+
lastError: paused ? `Paused after ${streak} failed runs in a row${error ? `: ${error}` : ""}` : (error ?? null),
|
|
976
|
+
...(paused ? { enabled: false, nextRunAt: null } : {}),
|
|
977
|
+
});
|
|
978
|
+
if (paused) {
|
|
979
|
+
const off = await this.store().get(done.jobId).catch(() => null);
|
|
980
|
+
if (off)
|
|
981
|
+
this.clock.sync(off.id, off);
|
|
982
|
+
console.warn(`[jobs] agent=${this.deps.agentId} job=${done.jobId} paused after ${streak} failed runs in a row`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
await this.emitFinished(done, status, { ...fields, ...(paused ? { paused } : {}) }, job);
|
|
986
|
+
const log = `[jobs] agent=${this.deps.agentId} run=${done.id} ${status}${done.silent ? " (silent)" : ""}${fields.error ? `: ${fields.error}` : fields.reason ? `: ${fields.reason}` : ""}`;
|
|
987
|
+
if (status === "failed")
|
|
988
|
+
console.error(log);
|
|
989
|
+
else
|
|
990
|
+
console.log(log);
|
|
991
|
+
await this.store()
|
|
992
|
+
.prune(done.jobId, KEEP_JOB_EVENTS, KEEP_JOB_RUNS)
|
|
993
|
+
.catch((err) => console.warn(`[jobs] agent=${this.deps.agentId} could not prune history:`, err));
|
|
994
|
+
}
|
|
995
|
+
async emitFinished(run, status, fields, known) {
|
|
996
|
+
// The job as it is now: the user may have changed its delivery while the run went on.
|
|
997
|
+
// A job deleted meanwhile has nothing to deliver to.
|
|
998
|
+
const job = await this.store().get(run.jobId).catch(() => null);
|
|
999
|
+
this.deps.eventBus.emit({
|
|
1000
|
+
type: SDKEventType.JobRunFinished,
|
|
1001
|
+
sessionId: run.sessionId ?? "",
|
|
1002
|
+
payload: {
|
|
1003
|
+
agentId: this.deps.agentId,
|
|
1004
|
+
jobId: run.jobId,
|
|
1005
|
+
runId: run.id,
|
|
1006
|
+
cause: run.cause,
|
|
1007
|
+
status,
|
|
1008
|
+
// A blocked turn's reason was checkpointed on the run, not passed to finish().
|
|
1009
|
+
...((fields.error ?? run.error) ? { error: fields.error ?? run.error } : {}),
|
|
1010
|
+
...((fields.reason ?? run.reason) ? { reason: fields.reason ?? run.reason } : {}),
|
|
1011
|
+
...(job ? { jobName: job.name } : known ? { jobName: known.name } : {}),
|
|
1012
|
+
...(run.output !== undefined ? { output: run.output } : {}),
|
|
1013
|
+
...(run.silent ? { silent: true } : {}),
|
|
1014
|
+
...(run.action === "tool" ? { action: "tool" } : {}),
|
|
1015
|
+
...(fields.paused ? { paused: true } : {}),
|
|
1016
|
+
...(job?.deliveries?.length ? { deliveries: job.deliveries } : {}),
|
|
1017
|
+
},
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
/** A lease-guarded write. Null (and the entry marked) when this worker no longer holds the run. */
|
|
1021
|
+
async write(entry, patch) {
|
|
1022
|
+
const updated = await this.store().updateRun(entry.run.id, this.owner, patch, this.iso(this.now()));
|
|
1023
|
+
if (!updated) {
|
|
1024
|
+
entry.leaseLost = true;
|
|
1025
|
+
return null;
|
|
1026
|
+
}
|
|
1027
|
+
entry.run = updated;
|
|
1028
|
+
return updated;
|
|
1029
|
+
}
|
|
1030
|
+
/** Record a job's run state; a failure is logged — the run's own record is what counts. */
|
|
1031
|
+
async setJobState(jobId, patch) {
|
|
1032
|
+
await this.store()
|
|
1033
|
+
.updateJobState(jobId, patch)
|
|
1034
|
+
.catch((err) => console.warn(`[jobs] agent=${this.deps.agentId} job=${jobId} could not record its state:`, err));
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* The session a run writes into — created on the first attempt and reused by retries.
|
|
1038
|
+
* A "reuse" job appends every run to one session, created on its first run.
|
|
1039
|
+
*/
|
|
1040
|
+
async resolveSession(job, run, eventDepth) {
|
|
1041
|
+
const sessions = this.deps.getSessions();
|
|
1042
|
+
if (job.sessionMode === "reuse" && job.sessionId) {
|
|
1043
|
+
const existing = await sessions.get(job.sessionId).catch(() => null);
|
|
1044
|
+
if (existing && existing.metadata["agentId"] === this.deps.agentId) {
|
|
1045
|
+
// A session from before Session.jobId existed: tag it so it groups with the job's runs.
|
|
1046
|
+
if (existing.jobId === undefined)
|
|
1047
|
+
await sessions.update({ ...existing, jobId: job.id });
|
|
1048
|
+
return existing.id;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
const title = job.sessionMode === "reuse" ? job.name : `${job.name} · ${this.iso(this.now()).slice(0, 16).replace("T", " ")} UTC`;
|
|
1052
|
+
const session = await sessions.create({
|
|
1053
|
+
// Same ownership key the host routes use, so the session lists and opens like any other.
|
|
1054
|
+
agentId: this.deps.agentId,
|
|
1055
|
+
source: "job",
|
|
1056
|
+
jobId: job.id,
|
|
1057
|
+
jobName: job.name,
|
|
1058
|
+
runId: run.id,
|
|
1059
|
+
cause: run.cause,
|
|
1060
|
+
correlationId: run.correlationId,
|
|
1061
|
+
// The depth of events this session's runs cause (the loop guard reads it after a restart).
|
|
1062
|
+
eventDepth,
|
|
1063
|
+
title,
|
|
1064
|
+
});
|
|
1065
|
+
// Tag the session with its job (Session.jobId) so clients can group a job's runs.
|
|
1066
|
+
await sessions.update({ ...session, jobId: job.id });
|
|
1067
|
+
if (job.sessionMode === "reuse")
|
|
1068
|
+
await this.setJobState(job.id, { sessionId: session.id });
|
|
1069
|
+
return session.id;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* A-103: one attempt of a tool job. The stored call runs through the agent loop like a
|
|
1073
|
+
* turn's call (policy, approval gate, retries, traces); its approval handler approves
|
|
1074
|
+
* exactly this call. The call and its result go into the run's session, so the session
|
|
1075
|
+
* shows what ran and a follow-up turn sees the output. A follow-up turn ("always", or
|
|
1076
|
+
* "on-failure" when the tool failed) then runs through the host's runner as usual.
|
|
1077
|
+
*/
|
|
1078
|
+
async runToolAction(entry, action, context) {
|
|
1079
|
+
const runTool = this.deps.runTool;
|
|
1080
|
+
if (!runTool)
|
|
1081
|
+
throw new JobError("This agent can't run tool jobs", "invalid_argument", context.jobId);
|
|
1082
|
+
const call = { id: `job_${context.runId}_${context.attempt}`, name: action.tool, arguments: structuredClone(action.args) };
|
|
1083
|
+
entry.approvedCall = { tool: action.tool, args: canonicalJson(action.args) };
|
|
1084
|
+
await this.deps.appendMessage?.(context.sessionId, { role: "assistant", content: "", toolCalls: [call] });
|
|
1085
|
+
const result = await runTool(call, { sessionId: context.sessionId, signal: context.signal });
|
|
1086
|
+
entry.approvedCall = undefined;
|
|
1087
|
+
// Every call gets its result in the session, a stopped one too.
|
|
1088
|
+
const stored = {
|
|
1089
|
+
toolCallId: result.toolCallId,
|
|
1090
|
+
content: result.content,
|
|
1091
|
+
...(result.isError ? { isError: true } : {}),
|
|
1092
|
+
// A-132: what the call produced for the user to open, so the chat can link to it
|
|
1093
|
+
...(result.link ? { link: result.link } : {}),
|
|
1094
|
+
};
|
|
1095
|
+
await this.deps.appendMessage?.(context.sessionId, { role: "assistant", content: "", toolResults: [stored] });
|
|
1096
|
+
if (context.signal.aborted)
|
|
1097
|
+
return { aborted: true, output: result.content };
|
|
1098
|
+
const toolError = result.isError ? result.content || "the tool reported an error" : undefined;
|
|
1099
|
+
const followUp = action.followUp ?? "never";
|
|
1100
|
+
if (followUp === "always" || (followUp === "on-failure" && toolError !== undefined)) {
|
|
1101
|
+
const reply = await this.deps.getRunner()(context);
|
|
1102
|
+
return { ...reply, followedUp: true, ...(toolError !== undefined ? { toolError } : {}) };
|
|
1103
|
+
}
|
|
1104
|
+
return { output: result.content, ...(toolError !== undefined ? { toolError } : {}), ...(result.empty ? { empty: true } : {}) };
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* A-103: the number of finished runs in a row that failed or were blocked, when it has
|
|
1108
|
+
* reached the job's pauseAfterFailures (undefined otherwise, or when the job is already
|
|
1109
|
+
* off). Succeeded runs end the streak; suppressed and stopped runs are skipped. Runs from
|
|
1110
|
+
* before the job's last edit don't count, so turning it back on starts a fresh streak.
|
|
1111
|
+
*/
|
|
1112
|
+
async failureStreak(jobId) {
|
|
1113
|
+
const job = await this.store().get(jobId).catch(() => null);
|
|
1114
|
+
if (!job || !job.enabled)
|
|
1115
|
+
return undefined;
|
|
1116
|
+
const limit = job.limits.pauseAfterFailures ?? DEFAULT_PAUSE_AFTER_FAILURES;
|
|
1117
|
+
if (limit <= 0)
|
|
1118
|
+
return undefined;
|
|
1119
|
+
const runs = await this.store().listRuns(jobId, Math.min(200, limit * 4 + 10)).catch(() => []);
|
|
1120
|
+
let streak = 0;
|
|
1121
|
+
for (const r of runs) {
|
|
1122
|
+
if (r.createdAt < job.updatedAt)
|
|
1123
|
+
break;
|
|
1124
|
+
if (r.status === "succeeded")
|
|
1125
|
+
break;
|
|
1126
|
+
if (r.status === "failed" || r.status === "blocked") {
|
|
1127
|
+
streak++;
|
|
1128
|
+
if (streak >= limit)
|
|
1129
|
+
return streak;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
return undefined;
|
|
1133
|
+
}
|
|
1134
|
+
/** A-103: the job's earlier runs, for the "since last run" placeholders. */
|
|
1135
|
+
async runHistory(jobId, currentRunId) {
|
|
1136
|
+
const history = { now: this.iso(this.now()) };
|
|
1137
|
+
const runs = await this.store().listRuns(jobId, 50).catch(() => []);
|
|
1138
|
+
for (const r of runs) {
|
|
1139
|
+
if (r.id === currentRunId || !r.startedAt)
|
|
1140
|
+
continue;
|
|
1141
|
+
if (!history.lastRunAt && (r.status === "succeeded" || r.status === "failed" || r.status === "blocked"))
|
|
1142
|
+
history.lastRunAt = r.startedAt;
|
|
1143
|
+
if (r.status === "succeeded" && !r.silent && r.output?.trim()) {
|
|
1144
|
+
history.lastSuccessAt = r.startedAt;
|
|
1145
|
+
history.lastResult = r.output;
|
|
1146
|
+
break;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
return history;
|
|
1150
|
+
}
|
|
1151
|
+
retryDelay(attempt) {
|
|
1152
|
+
const base = (this.deps.retryBaseMs ?? JOB_RETRY_BASE_MS) * 2 ** Math.max(0, attempt - 1);
|
|
1153
|
+
return Math.min(MAX_RETRY_DELAY_MS, Math.round(base * (0.75 + this.random() * 0.5)));
|
|
1154
|
+
}
|
|
1155
|
+
// ---------------------------------------------------------------------------
|
|
1156
|
+
// Helpers
|
|
1157
|
+
// ---------------------------------------------------------------------------
|
|
1158
|
+
track(promise) {
|
|
1159
|
+
this.inFlight.add(promise);
|
|
1160
|
+
void promise.finally(() => this.inFlight.delete(promise));
|
|
1161
|
+
}
|
|
1162
|
+
async require(id) {
|
|
1163
|
+
const job = await this.get(id);
|
|
1164
|
+
if (!job)
|
|
1165
|
+
throw new JobError(`No job "${id}" for this agent`, "not_found", id);
|
|
1166
|
+
return job;
|
|
1167
|
+
}
|
|
1168
|
+
async requireRun(runId) {
|
|
1169
|
+
const run = await this.getRun(runId);
|
|
1170
|
+
if (!run)
|
|
1171
|
+
throw new JobError(`No job run "${runId}" for this agent`, "not_found");
|
|
1172
|
+
return run;
|
|
1173
|
+
}
|
|
1174
|
+
store() {
|
|
1175
|
+
return this.deps.getStore();
|
|
1176
|
+
}
|
|
1177
|
+
iso(ms) {
|
|
1178
|
+
return new Date(ms).toISOString();
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* The depth of an event a run causes. Only event and webhook jobs chain: an event
|
|
1183
|
+
* from their run is one level deeper than the run, so with maxDepth 0 it wakes no
|
|
1184
|
+
* event job. A schedule job's run (and run now) starts no chain: its events have
|
|
1185
|
+
* depth 0, so "when my scheduled job fails, look into it" works.
|
|
1186
|
+
*/
|
|
1187
|
+
function eventDepthOf(job, run) {
|
|
1188
|
+
return isScheduleWhen(job.when) ? 0 : run.depth + 1;
|
|
1189
|
+
}
|
|
1190
|
+
function viewOf(event) {
|
|
1191
|
+
return { type: event.type, ...(event.subject !== undefined ? { subject: event.subject } : {}), source: event.source, data: event.data };
|
|
1192
|
+
}
|
|
1193
|
+
/** A-103: "45 seconds", "30 minutes", "2 hours" — for the time-limit error. */
|
|
1194
|
+
function describeDuration(ms) {
|
|
1195
|
+
if (ms < 60_000)
|
|
1196
|
+
return `${Math.round(ms / 1000)} seconds`;
|
|
1197
|
+
if (ms < HOUR || ms % HOUR !== 0)
|
|
1198
|
+
return `${Math.round(ms / 60_000)} minutes`;
|
|
1199
|
+
return `${ms / HOUR} hour${ms === HOUR ? "" : "s"}`;
|
|
1200
|
+
}
|
|
1201
|
+
function clampLimit(limit) {
|
|
1202
|
+
return Math.min(Math.max(1, Math.floor(Number(limit) || 50)), 200);
|
|
1203
|
+
}
|
|
1204
|
+
function errorMessage(err) {
|
|
1205
|
+
return err instanceof Error ? err.message : String(err);
|
|
1206
|
+
}
|
|
1207
|
+
//# sourceMappingURL=job-manager.js.map
|