@nocobase/app-plugin-agents 0.1.0-beta.1 → 0.1.0-beta.11
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/CHANGELOG.md +398 -0
- package/README.md +129 -67
- package/dist/client/api/client.d.ts +25 -17
- package/dist/client/api/client.d.ts.map +1 -1
- package/dist/client/api/client.js +29 -27
- package/dist/client/api/client.js.map +1 -1
- package/dist/client/api/keys.d.ts +1 -1
- package/dist/client/api/keys.d.ts.map +1 -1
- package/dist/client/api/keys.js +1 -1
- package/dist/client/api/keys.js.map +1 -1
- package/dist/client/chat/api.d.ts +2 -7
- package/dist/client/chat/api.d.ts.map +1 -1
- package/dist/client/chat/api.js +0 -7
- package/dist/client/chat/api.js.map +1 -1
- package/dist/client/chat/consultation-identity.d.ts +7 -0
- package/dist/client/chat/consultation-identity.d.ts.map +1 -0
- package/dist/client/chat/consultation-identity.js +39 -0
- package/dist/client/chat/consultation-identity.js.map +1 -0
- package/dist/client/chat/message-model.d.ts +4 -2
- package/dist/client/chat/message-model.d.ts.map +1 -1
- package/dist/client/chat/message-model.js +28 -3
- package/dist/client/chat/message-model.js.map +1 -1
- package/dist/client/chat/use-chat.d.ts +2 -10
- package/dist/client/chat/use-chat.d.ts.map +1 -1
- package/dist/client/chat/use-chat.js +3 -10
- package/dist/client/chat/use-chat.js.map +1 -1
- package/dist/client/chat.d.ts +4 -1
- package/dist/client/chat.d.ts.map +1 -1
- package/dist/client/chat.js +3 -0
- package/dist/client/chat.js.map +1 -1
- package/dist/client/components/agent-picker.d.ts +6 -23
- package/dist/client/components/agent-picker.d.ts.map +1 -1
- package/dist/client/components/agent-picker.js +19 -39
- package/dist/client/components/agent-picker.js.map +1 -1
- package/dist/client/components/variables/variable-dialogs.d.ts +6 -1
- package/dist/client/components/variables/variable-dialogs.d.ts.map +1 -1
- package/dist/client/components/variables/variable-dialogs.js +27 -11
- package/dist/client/components/variables/variable-dialogs.js.map +1 -1
- package/dist/client/components/variables/variables-panel.d.ts.map +1 -1
- package/dist/client/components/variables/variables-panel.js +9 -2
- package/dist/client/components/variables/variables-panel.js.map +1 -1
- package/dist/client/hooks/use-agent-picker-labels.d.ts.map +1 -1
- package/dist/client/hooks/use-agent-picker-labels.js +3 -12
- package/dist/client/hooks/use-agent-picker-labels.js.map +1 -1
- package/dist/client/kit.d.ts +9 -12
- package/dist/client/kit.d.ts.map +1 -1
- package/dist/client/kit.js +12 -14
- package/dist/client/kit.js.map +1 -1
- package/dist/client/lib/agents.d.ts +5 -13
- package/dist/client/lib/agents.d.ts.map +1 -1
- package/dist/client/lib/agents.js +17 -32
- package/dist/client/lib/agents.js.map +1 -1
- package/dist/client/lib/install.js +1 -1
- package/dist/client/locales/chat.en-US.d.ts +9 -22
- package/dist/client/locales/chat.en-US.d.ts.map +1 -1
- package/dist/client/locales/chat.en-US.js +13 -25
- package/dist/client/locales/chat.en-US.js.map +1 -1
- package/dist/client/locales/chat.zh-CN.d.ts.map +1 -1
- package/dist/client/locales/chat.zh-CN.js +10 -22
- package/dist/client/locales/chat.zh-CN.js.map +1 -1
- package/dist/client/locales/en-US.d.ts +101 -219
- package/dist/client/locales/en-US.d.ts.map +1 -1
- package/dist/client/locales/en-US.js +106 -219
- package/dist/client/locales/en-US.js.map +1 -1
- package/dist/client/locales/runWait.en-US.d.ts +38 -0
- package/dist/client/locales/runWait.en-US.d.ts.map +1 -0
- package/dist/client/locales/runWait.en-US.js +37 -0
- package/dist/client/locales/runWait.en-US.js.map +1 -0
- package/dist/client/locales/runWait.zh-CN.d.ts +5 -0
- package/dist/client/locales/runWait.zh-CN.d.ts.map +1 -0
- package/dist/client/locales/runWait.zh-CN.js +32 -0
- package/dist/client/locales/runWait.zh-CN.js.map +1 -0
- package/dist/client/locales/runtimes.en-US.d.ts +54 -0
- package/dist/client/locales/runtimes.en-US.d.ts.map +1 -1
- package/dist/client/locales/runtimes.en-US.js +57 -3
- package/dist/client/locales/runtimes.en-US.js.map +1 -1
- package/dist/client/locales/runtimes.zh-CN.d.ts.map +1 -1
- package/dist/client/locales/runtimes.zh-CN.js +57 -3
- package/dist/client/locales/runtimes.zh-CN.js.map +1 -1
- package/dist/client/locales/skills.en-US.d.ts +1 -0
- package/dist/client/locales/skills.en-US.d.ts.map +1 -1
- package/dist/client/locales/skills.en-US.js +2 -1
- package/dist/client/locales/skills.en-US.js.map +1 -1
- package/dist/client/locales/skills.zh-CN.d.ts.map +1 -1
- package/dist/client/locales/skills.zh-CN.js +2 -1
- package/dist/client/locales/skills.zh-CN.js.map +1 -1
- package/dist/client/locales/zh-CN.d.ts.map +1 -1
- package/dist/client/locales/zh-CN.js +108 -221
- package/dist/client/locales/zh-CN.js.map +1 -1
- package/dist/client/online/services.d.ts.map +1 -1
- package/dist/client/online/services.js +5 -6
- package/dist/client/online/services.js.map +1 -1
- package/dist/client/pages/agents/agent-dialog.d.ts +9 -0
- package/dist/client/pages/agents/agent-dialog.d.ts.map +1 -0
- package/dist/client/pages/agents/agent-dialog.js +106 -0
- package/dist/client/pages/agents/agent-dialog.js.map +1 -0
- package/dist/client/pages/agents/agent-state.d.ts +11 -0
- package/dist/client/pages/agents/agent-state.d.ts.map +1 -0
- package/dist/client/pages/agents/agent-state.js +28 -0
- package/dist/client/pages/agents/agent-state.js.map +1 -0
- package/dist/client/pages/agents/index.d.ts +1 -1
- package/dist/client/pages/agents/index.d.ts.map +1 -1
- package/dist/client/pages/agents/index.js +6 -100
- package/dist/client/pages/agents/index.js.map +1 -1
- package/dist/client/pages/agents/runner-agents.d.ts +3 -0
- package/dist/client/pages/agents/runner-agents.d.ts.map +1 -0
- package/dist/client/pages/agents/runner-agents.js +172 -0
- package/dist/client/pages/agents/runner-agents.js.map +1 -0
- package/dist/client/pages/runtimes/connect.js +1 -1
- package/dist/client/pages/runtimes/connect.js.map +1 -1
- package/dist/client/pages/runtimes/index.d.ts.map +1 -1
- package/dist/client/pages/runtimes/index.js +3 -2
- package/dist/client/pages/runtimes/index.js.map +1 -1
- package/dist/client/pages/runtimes/runner-cells.d.ts +1 -1
- package/dist/client/pages/runtimes/runner-cells.d.ts.map +1 -1
- package/dist/client/pages/runtimes/runner-cells.js +4 -1
- package/dist/client/pages/runtimes/runner-cells.js.map +1 -1
- package/dist/client/pages/runtimes/runner-sheet.d.ts.map +1 -1
- package/dist/client/pages/runtimes/runner-sheet.js +12 -3
- package/dist/client/pages/runtimes/runner-sheet.js.map +1 -1
- package/dist/client/pages/runtimes/workspace-diagnostics.d.ts +9 -0
- package/dist/client/pages/runtimes/workspace-diagnostics.d.ts.map +1 -0
- package/dist/client/pages/runtimes/workspace-diagnostics.js +68 -0
- package/dist/client/pages/runtimes/workspace-diagnostics.js.map +1 -0
- package/dist/client/pages/skills/detail/index.d.ts.map +1 -1
- package/dist/client/pages/skills/detail/index.js +7 -10
- package/dist/client/pages/skills/detail/index.js.map +1 -1
- package/dist/client/pages/skills/index.d.ts.map +1 -1
- package/dist/client/pages/skills/index.js +2 -2
- package/dist/client/pages/skills/index.js.map +1 -1
- package/dist/client/pages/usage/index.js +2 -2
- package/dist/client/pages/usage/index.js.map +1 -1
- package/dist/client/profile/default-agent.d.ts.map +1 -1
- package/dist/client/profile/default-agent.js +2 -4
- package/dist/client/profile/default-agent.js.map +1 -1
- package/dist/client/routes.d.ts +1 -1
- package/dist/client/routes.d.ts.map +1 -1
- package/dist/client/routes.js +1 -13
- package/dist/client/routes.js.map +1 -1
- package/dist/client/runs/format-wait.d.ts +21 -0
- package/dist/client/runs/format-wait.d.ts.map +1 -0
- package/dist/client/runs/format-wait.js +90 -0
- package/dist/client/runs/format-wait.js.map +1 -0
- package/dist/client/runs/subject-runs.d.ts +5 -0
- package/dist/client/runs/subject-runs.d.ts.map +1 -1
- package/dist/client/runs/subject-runs.js +13 -7
- package/dist/client/runs/subject-runs.js.map +1 -1
- package/dist/client/runs.d.ts +3 -1
- package/dist/client/runs.d.ts.map +1 -1
- package/dist/client/runs.js +3 -1
- package/dist/client/runs.js.map +1 -1
- package/dist/database/migrations/.manifest.json +62 -2
- package/dist/database/migrations/202610020003_ag_create_runs.d.ts.map +1 -1
- package/dist/database/migrations/202610020003_ag_create_runs.js +0 -1
- package/dist/database/migrations/202610020003_ag_create_runs.js.map +1 -1
- package/dist/database/migrations/202610090001_ag_add_team_runner_variables.d.ts +9 -0
- package/dist/database/migrations/202610090001_ag_add_team_runner_variables.d.ts.map +1 -0
- package/dist/database/migrations/202610090001_ag_add_team_runner_variables.js +28 -0
- package/dist/database/migrations/202610090001_ag_add_team_runner_variables.js.map +1 -0
- package/dist/database/migrations/202610090002_ag_create_run_requests.d.ts +10 -0
- package/dist/database/migrations/202610090002_ag_create_run_requests.d.ts.map +1 -0
- package/dist/database/migrations/202610090002_ag_create_run_requests.js +105 -0
- package/dist/database/migrations/202610090002_ag_create_run_requests.js.map +1 -0
- package/dist/database/migrations/202610090003_ag_add_execution_history.d.ts +4 -0
- package/dist/database/migrations/202610090003_ag_add_execution_history.d.ts.map +1 -0
- package/dist/database/migrations/202610090003_ag_add_execution_history.js +17 -0
- package/dist/database/migrations/202610090003_ag_add_execution_history.js.map +1 -0
- package/dist/database/migrations/202610090004_ag_add_runner_workspace_usage.d.ts +9 -0
- package/dist/database/migrations/202610090004_ag_add_runner_workspace_usage.d.ts.map +1 -0
- package/dist/database/migrations/202610090004_ag_add_runner_workspace_usage.js +22 -0
- package/dist/database/migrations/202610090004_ag_add_runner_workspace_usage.js.map +1 -0
- package/dist/database/migrations/202610090005_ag_add_runner_variables.d.ts +10 -0
- package/dist/database/migrations/202610090005_ag_add_runner_variables.d.ts.map +1 -0
- package/dist/database/migrations/202610090005_ag_add_runner_variables.js +36 -0
- package/dist/database/migrations/202610090005_ag_add_runner_variables.js.map +1 -0
- package/dist/database/migrations/202610100001_ag_index_run_event_types.d.ts +4 -0
- package/dist/database/migrations/202610100001_ag_index_run_event_types.d.ts.map +1 -0
- package/dist/database/migrations/202610100001_ag_index_run_event_types.js +17 -0
- package/dist/database/migrations/202610100001_ag_index_run_event_types.js.map +1 -0
- package/dist/database/migrations/202610100002_ag_add_run_git_credentials.d.ts +9 -0
- package/dist/database/migrations/202610100002_ag_add_run_git_credentials.d.ts.map +1 -0
- package/dist/database/migrations/202610100002_ag_add_run_git_credentials.js +30 -0
- package/dist/database/migrations/202610100002_ag_add_run_git_credentials.js.map +1 -0
- package/dist/database/migrations/202610110001_ag_add_fresh_sessions.d.ts +4 -0
- package/dist/database/migrations/202610110001_ag_add_fresh_sessions.d.ts.map +1 -0
- package/dist/database/migrations/202610110001_ag_add_fresh_sessions.js +23 -0
- package/dist/database/migrations/202610110001_ag_add_fresh_sessions.js.map +1 -0
- package/dist/database/migrations/202610120001_ag_index_run_retries.d.ts +4 -0
- package/dist/database/migrations/202610120001_ag_index_run_retries.d.ts.map +1 -0
- package/dist/database/migrations/202610120001_ag_index_run_retries.js +17 -0
- package/dist/database/migrations/202610120001_ag_index_run_retries.js.map +1 -0
- package/dist/database/migrations/202610120002_ag_add_queue_entered_at.d.ts +4 -0
- package/dist/database/migrations/202610120002_ag_add_queue_entered_at.d.ts.map +1 -0
- package/dist/database/migrations/202610120002_ag_add_queue_entered_at.js +50 -0
- package/dist/database/migrations/202610120002_ag_add_queue_entered_at.js.map +1 -0
- package/dist/database/migrations/202610240020_ag_runner_agents.d.ts +4 -0
- package/dist/database/migrations/202610240020_ag_runner_agents.d.ts.map +1 -0
- package/dist/database/migrations/202610240020_ag_runner_agents.js +115 -0
- package/dist/database/migrations/202610240020_ag_runner_agents.js.map +1 -0
- package/dist/database/migrations/202610240040_ag_discovery_preferences.d.ts +4 -0
- package/dist/database/migrations/202610240040_ag_discovery_preferences.d.ts.map +1 -0
- package/dist/database/migrations/202610240040_ag_discovery_preferences.js +18 -0
- package/dist/database/migrations/202610240040_ag_discovery_preferences.js.map +1 -0
- package/dist/database/migrations/202610250001_ag_comment_runner_consent.d.ts +4 -0
- package/dist/database/migrations/202610250001_ag_comment_runner_consent.d.ts.map +1 -0
- package/dist/database/migrations/202610250001_ag_comment_runner_consent.js +41 -0
- package/dist/database/migrations/202610250001_ag_comment_runner_consent.js.map +1 -0
- package/dist/database/migrations/202610260001_ag_drop_directory_index.d.ts +4 -0
- package/dist/database/migrations/202610260001_ag_drop_directory_index.d.ts.map +1 -0
- package/dist/database/migrations/202610260001_ag_drop_directory_index.js +24 -0
- package/dist/database/migrations/202610260001_ag_drop_directory_index.js.map +1 -0
- package/dist/database/migrations/202610260001_ag_run_revision.d.ts +4 -0
- package/dist/database/migrations/202610260001_ag_run_revision.d.ts.map +1 -0
- package/dist/database/migrations/202610260001_ag_run_revision.js +19 -0
- package/dist/database/migrations/202610260001_ag_run_revision.js.map +1 -0
- package/dist/package.json +8 -10
- package/dist/server/cli/run-credential.js +1 -1
- package/dist/server/composition.d.ts +41 -37
- package/dist/server/composition.d.ts.map +1 -1
- package/dist/server/composition.js +66 -66
- package/dist/server/composition.js.map +1 -1
- package/dist/server/core/agents/agent.service.d.ts +51 -43
- package/dist/server/core/agents/agent.service.d.ts.map +1 -1
- package/dist/server/core/agents/agent.service.js +342 -317
- package/dist/server/core/agents/agent.service.js.map +1 -1
- package/dist/server/core/agents/agent.store.d.ts +24 -12
- package/dist/server/core/agents/agent.store.d.ts.map +1 -1
- package/dist/server/core/agents/agent.store.js +64 -66
- package/dist/server/core/agents/agent.store.js.map +1 -1
- package/dist/server/core/agents/agent.views.d.ts +29 -0
- package/dist/server/core/agents/agent.views.d.ts.map +1 -0
- package/dist/server/core/agents/agent.views.js +86 -0
- package/dist/server/core/agents/agent.views.js.map +1 -0
- package/dist/server/core/agents/discovery.d.ts +12 -0
- package/dist/server/core/agents/discovery.d.ts.map +1 -0
- package/dist/server/core/agents/discovery.js +39 -0
- package/dist/server/core/agents/discovery.js.map +1 -0
- package/dist/server/core/agents/index.d.ts +2 -1
- package/dist/server/core/agents/index.d.ts.map +1 -1
- package/dist/server/core/agents/index.js +2 -1
- package/dist/server/core/agents/index.js.map +1 -1
- package/dist/server/core/brief/brief.js +1 -1
- package/dist/server/core/brief/brief.js.map +1 -1
- package/dist/server/core/callers/index.d.ts +1 -1
- package/dist/server/core/conversations/availability.d.ts +11 -10
- package/dist/server/core/conversations/availability.d.ts.map +1 -1
- package/dist/server/core/conversations/availability.js +14 -32
- package/dist/server/core/conversations/availability.js.map +1 -1
- package/dist/server/core/conversations/chat-settings.d.ts.map +1 -1
- package/dist/server/core/conversations/chat-settings.js +5 -3
- package/dist/server/core/conversations/chat-settings.js.map +1 -1
- package/dist/server/core/conversations/conversation.service.d.ts +3 -5
- package/dist/server/core/conversations/conversation.service.d.ts.map +1 -1
- package/dist/server/core/conversations/conversation.service.js +161 -221
- package/dist/server/core/conversations/conversation.service.js.map +1 -1
- package/dist/server/core/conversations/ports.d.ts +3 -17
- package/dist/server/core/conversations/ports.d.ts.map +1 -1
- package/dist/server/core/reports/report.service.d.ts.map +1 -1
- package/dist/server/core/reports/report.service.js +5 -2
- package/dist/server/core/reports/report.service.js.map +1 -1
- package/dist/server/core/runs/availability.d.ts +18 -7
- package/dist/server/core/runs/availability.d.ts.map +1 -1
- package/dist/server/core/runs/availability.js +35 -24
- package/dist/server/core/runs/availability.js.map +1 -1
- package/dist/server/core/runs/claim.d.ts +47 -67
- package/dist/server/core/runs/claim.d.ts.map +1 -1
- package/dist/server/core/runs/claim.js +805 -313
- package/dist/server/core/runs/claim.js.map +1 -1
- package/dist/server/core/runs/comment-consent.d.ts +24 -0
- package/dist/server/core/runs/comment-consent.d.ts.map +1 -0
- package/dist/server/core/runs/comment-consent.js +116 -0
- package/dist/server/core/runs/comment-consent.js.map +1 -0
- package/dist/server/core/runs/eligibility.d.ts +51 -0
- package/dist/server/core/runs/eligibility.d.ts.map +1 -0
- package/dist/server/core/runs/eligibility.js +44 -0
- package/dist/server/core/runs/eligibility.js.map +1 -0
- package/dist/server/core/runs/execution-view.d.ts +10 -0
- package/dist/server/core/runs/execution-view.d.ts.map +1 -0
- package/dist/server/core/runs/execution-view.js +25 -0
- package/dist/server/core/runs/execution-view.js.map +1 -0
- package/dist/server/core/runs/execution.d.ts +13 -0
- package/dist/server/core/runs/execution.d.ts.map +1 -0
- package/dist/server/core/runs/execution.js +85 -0
- package/dist/server/core/runs/execution.js.map +1 -0
- package/dist/server/core/runs/extensions.d.ts +59 -4
- package/dist/server/core/runs/extensions.d.ts.map +1 -1
- package/dist/server/core/runs/extensions.js +45 -9
- package/dist/server/core/runs/extensions.js.map +1 -1
- package/dist/server/core/runs/git-credentials.d.ts +43 -0
- package/dist/server/core/runs/git-credentials.d.ts.map +1 -0
- package/dist/server/core/runs/git-credentials.js +129 -0
- package/dist/server/core/runs/git-credentials.js.map +1 -0
- package/dist/server/core/runs/identity.d.ts +9 -0
- package/dist/server/core/runs/identity.d.ts.map +1 -0
- package/dist/server/core/runs/identity.js +75 -0
- package/dist/server/core/runs/identity.js.map +1 -0
- package/dist/server/core/runs/index.d.ts +9 -5
- package/dist/server/core/runs/index.d.ts.map +1 -1
- package/dist/server/core/runs/index.js +9 -5
- package/dist/server/core/runs/index.js.map +1 -1
- package/dist/server/core/runs/input-gate.d.ts +34 -0
- package/dist/server/core/runs/input-gate.d.ts.map +1 -0
- package/dist/server/core/runs/input-gate.js +58 -0
- package/dist/server/core/runs/input-gate.js.map +1 -0
- package/dist/server/core/runs/lifecycle.d.ts +9 -19
- package/dist/server/core/runs/lifecycle.d.ts.map +1 -1
- package/dist/server/core/runs/lifecycle.js +98 -50
- package/dist/server/core/runs/lifecycle.js.map +1 -1
- package/dist/server/core/runs/policy.d.ts +8 -0
- package/dist/server/core/runs/policy.d.ts.map +1 -1
- package/dist/server/core/runs/policy.js +10 -0
- package/dist/server/core/runs/policy.js.map +1 -1
- package/dist/server/core/runs/ports.d.ts +91 -28
- package/dist/server/core/runs/ports.d.ts.map +1 -1
- package/dist/server/core/runs/ports.js +2 -13
- package/dist/server/core/runs/ports.js.map +1 -1
- package/dist/server/core/runs/preview.d.ts.map +1 -1
- package/dist/server/core/runs/preview.js +3 -3
- package/dist/server/core/runs/preview.js.map +1 -1
- package/dist/server/core/runs/run-data-purge.d.ts +15 -0
- package/dist/server/core/runs/run-data-purge.d.ts.map +1 -0
- package/dist/server/core/runs/run-data-purge.js +82 -0
- package/dist/server/core/runs/run-data-purge.js.map +1 -0
- package/dist/server/core/runs/run-requests.d.ts +245 -0
- package/dist/server/core/runs/run-requests.d.ts.map +1 -0
- package/dist/server/core/runs/run-requests.js +543 -0
- package/dist/server/core/runs/run-requests.js.map +1 -0
- package/dist/server/core/runs/run.service.d.ts +96 -11
- package/dist/server/core/runs/run.service.d.ts.map +1 -1
- package/dist/server/core/runs/run.service.js +921 -96
- package/dist/server/core/runs/run.service.js.map +1 -1
- package/dist/server/core/runs/run.store.d.ts +25 -3
- package/dist/server/core/runs/run.store.d.ts.map +1 -1
- package/dist/server/core/runs/run.store.js +52 -2
- package/dist/server/core/runs/run.store.js.map +1 -1
- package/dist/server/core/runs/runner-view.d.ts +6 -4
- package/dist/server/core/runs/runner-view.d.ts.map +1 -1
- package/dist/server/core/runs/runner-view.js +13 -11
- package/dist/server/core/runs/runner-view.js.map +1 -1
- package/dist/server/core/runs/selection.d.ts +13 -0
- package/dist/server/core/runs/selection.d.ts.map +1 -0
- package/dist/server/core/runs/selection.js +21 -0
- package/dist/server/core/runs/selection.js.map +1 -0
- package/dist/server/core/runs/sweeper.d.ts +1 -0
- package/dist/server/core/runs/sweeper.d.ts.map +1 -1
- package/dist/server/core/runs/sweeper.js +55 -10
- package/dist/server/core/runs/sweeper.js.map +1 -1
- package/dist/server/core/runs/transitions.d.ts +2 -2
- package/dist/server/core/runs/transitions.d.ts.map +1 -1
- package/dist/server/core/runs/transitions.js +80 -8
- package/dist/server/core/runs/transitions.js.map +1 -1
- package/dist/server/core/runs/workload.d.ts +3 -3
- package/dist/server/core/runs/workload.d.ts.map +1 -1
- package/dist/server/core/runs/workload.js +154 -45
- package/dist/server/core/runs/workload.js.map +1 -1
- package/dist/server/core/skills/skill.service.d.ts +6 -2
- package/dist/server/core/skills/skill.service.d.ts.map +1 -1
- package/dist/server/core/skills/skill.service.js +43 -58
- package/dist/server/core/skills/skill.service.js.map +1 -1
- package/dist/server/core/skills/skill.store.d.ts +14 -0
- package/dist/server/core/skills/skill.store.d.ts.map +1 -1
- package/dist/server/core/skills/skill.store.js +30 -0
- package/dist/server/core/skills/skill.store.js.map +1 -1
- package/dist/server/core/variables/index.d.ts +1 -1
- package/dist/server/core/variables/index.d.ts.map +1 -1
- package/dist/server/core/variables/index.js +1 -1
- package/dist/server/core/variables/index.js.map +1 -1
- package/dist/server/core/variables/variable.service.d.ts +38 -6
- package/dist/server/core/variables/variable.service.d.ts.map +1 -1
- package/dist/server/core/variables/variable.service.js +201 -30
- package/dist/server/core/variables/variable.service.js.map +1 -1
- package/dist/server/distribution/dist.service.d.ts +27 -5
- package/dist/server/distribution/dist.service.d.ts.map +1 -1
- package/dist/server/distribution/dist.service.js +41 -5
- package/dist/server/distribution/dist.service.js.map +1 -1
- package/dist/server/distribution/download-tokens.d.ts +1 -1
- package/dist/server/distribution/download-tokens.d.ts.map +1 -1
- package/dist/server/distribution/download-tokens.js +7 -4
- package/dist/server/distribution/download-tokens.js.map +1 -1
- package/dist/server/distribution/index.d.ts +11 -3
- package/dist/server/distribution/index.d.ts.map +1 -1
- package/dist/server/distribution/index.js +31 -8
- package/dist/server/distribution/index.js.map +1 -1
- package/dist/server/jobs/index.d.ts +1 -1
- package/dist/server/jobs/index.d.ts.map +1 -1
- package/dist/server/jobs/index.js +1 -1
- package/dist/server/jobs/index.js.map +1 -1
- package/dist/server/jobs/job.service.d.ts +3 -1
- package/dist/server/jobs/job.service.d.ts.map +1 -1
- package/dist/server/jobs/job.service.js +11 -3
- package/dist/server/jobs/job.service.js.map +1 -1
- package/dist/server/jobs/spec.d.ts +4 -0
- package/dist/server/jobs/spec.d.ts.map +1 -1
- package/dist/server/jobs/spec.js +6 -0
- package/dist/server/jobs/spec.js.map +1 -1
- package/dist/server/kernel/errors.d.ts +1 -1
- package/dist/server/kernel/errors.d.ts.map +1 -1
- package/dist/server/kernel/errors.js +1 -0
- package/dist/server/kernel/errors.js.map +1 -1
- package/dist/server/kernel/events.d.ts +34 -9
- package/dist/server/kernel/events.d.ts.map +1 -1
- package/dist/server/kernel/events.js.map +1 -1
- package/dist/server/kernel/redaction.d.ts +2 -0
- package/dist/server/kernel/redaction.d.ts.map +1 -1
- package/dist/server/kernel/redaction.js +17 -0
- package/dist/server/kernel/redaction.js.map +1 -1
- package/dist/server/kernel/scopes.d.ts.map +1 -1
- package/dist/server/kernel/scopes.js +3 -1
- package/dist/server/kernel/scopes.js.map +1 -1
- package/dist/server/online/index.d.ts +0 -5
- package/dist/server/online/index.d.ts.map +1 -1
- package/dist/server/online/index.js +0 -5
- package/dist/server/online/index.js.map +1 -1
- package/dist/server/online/routes.d.ts.map +1 -1
- package/dist/server/online/routes.js +6 -35
- package/dist/server/online/routes.js.map +1 -1
- package/dist/server/providers/agents.d.ts +8 -25
- package/dist/server/providers/agents.d.ts.map +1 -1
- package/dist/server/providers/agents.js +11 -75
- package/dist/server/providers/agents.js.map +1 -1
- package/dist/server/providers/runners.d.ts.map +1 -1
- package/dist/server/providers/runners.js +23 -0
- package/dist/server/providers/runners.js.map +1 -1
- package/dist/server/routes/admin.d.ts.map +1 -1
- package/dist/server/routes/admin.js +158 -209
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/chat.d.ts.map +1 -1
- package/dist/server/routes/chat.js +12 -70
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +11 -1
- package/dist/server/routes/index.js.map +1 -1
- package/dist/server/routes/roster.d.ts.map +1 -1
- package/dist/server/routes/roster.js +6 -21
- package/dist/server/routes/roster.js.map +1 -1
- package/dist/server/routes/run-requests.d.ts +6 -0
- package/dist/server/routes/run-requests.d.ts.map +1 -0
- package/dist/server/routes/run-requests.js +216 -0
- package/dist/server/routes/run-requests.js.map +1 -0
- package/dist/server/routes/runners/admin.d.ts +9 -1
- package/dist/server/routes/runners/admin.d.ts.map +1 -1
- package/dist/server/routes/runners/admin.js +62 -24
- package/dist/server/routes/runners/admin.js.map +1 -1
- package/dist/server/routes/runners/dist.d.ts +5 -1
- package/dist/server/routes/runners/dist.d.ts.map +1 -1
- package/dist/server/routes/runners/dist.js +36 -9
- package/dist/server/routes/runners/dist.js.map +1 -1
- package/dist/server/routes/runners/install.d.ts.map +1 -1
- package/dist/server/routes/runners/install.js +98 -15
- package/dist/server/routes/runners/install.js.map +1 -1
- package/dist/server/routes/runners/runner.d.ts.map +1 -1
- package/dist/server/routes/runners/runner.js +27 -7
- package/dist/server/routes/runners/runner.js.map +1 -1
- package/dist/server/routes/runners/runs.d.ts +1 -1
- package/dist/server/routes/runners/runs.d.ts.map +1 -1
- package/dist/server/routes/runners/runs.js +23 -3
- package/dist/server/routes/runners/runs.js.map +1 -1
- package/dist/server/routes/schemas.d.ts +37 -8
- package/dist/server/routes/schemas.d.ts.map +1 -1
- package/dist/server/routes/schemas.js +381 -84
- package/dist/server/routes/schemas.js.map +1 -1
- package/dist/server/runners/index.d.ts +1 -0
- package/dist/server/runners/index.d.ts.map +1 -1
- package/dist/server/runners/index.js +1 -0
- package/dist/server/runners/index.js.map +1 -1
- package/dist/server/runners/runner.service.d.ts +32 -8
- package/dist/server/runners/runner.service.d.ts.map +1 -1
- package/dist/server/runners/runner.service.js +130 -14
- package/dist/server/runners/runner.service.js.map +1 -1
- package/dist/server/runners/runner.store.d.ts +10 -1
- package/dist/server/runners/runner.store.d.ts.map +1 -1
- package/dist/server/runners/runner.store.js +117 -4
- package/dist/server/runners/runner.store.js.map +1 -1
- package/dist/server/runners/sweeper.d.ts +5 -0
- package/dist/server/runners/sweeper.d.ts.map +1 -1
- package/dist/server/runners/sweeper.js +4 -2
- package/dist/server/runners/sweeper.js.map +1 -1
- package/dist/server/runners/workspaces.d.ts +33 -0
- package/dist/server/runners/workspaces.d.ts.map +1 -0
- package/dist/server/runners/workspaces.js +248 -0
- package/dist/server/runners/workspaces.js.map +1 -0
- package/dist/server/testing.d.ts +0 -2
- package/dist/server/testing.d.ts.map +1 -1
- package/dist/server/testing.js +1 -4
- package/dist/server/testing.js.map +1 -1
- package/dist/server/tokens.d.ts +13 -9
- package/dist/server/tokens.d.ts.map +1 -1
- package/dist/server/tokens.js +7 -2
- package/dist/server/tokens.js.map +1 -1
- package/dist/shared/access.d.ts +2 -6
- package/dist/shared/access.d.ts.map +1 -1
- package/dist/shared/access.js +2 -6
- package/dist/shared/access.js.map +1 -1
- package/dist/shared/agents.d.ts +128 -167
- package/dist/shared/agents.d.ts.map +1 -1
- package/dist/shared/agents.js +46 -97
- package/dist/shared/agents.js.map +1 -1
- package/dist/shared/conversations.d.ts +43 -89
- package/dist/shared/conversations.d.ts.map +1 -1
- package/dist/shared/conversations.js +5 -24
- package/dist/shared/conversations.js.map +1 -1
- package/dist/shared/model-catalog.d.ts +48 -0
- package/dist/shared/model-catalog.d.ts.map +1 -0
- package/dist/shared/model-catalog.js +148 -0
- package/dist/shared/model-catalog.js.map +1 -0
- package/dist/shared/models.js +1 -1
- package/dist/shared/models.js.map +1 -1
- package/dist/shared/runners.d.ts +107 -17
- package/dist/shared/runners.d.ts.map +1 -1
- package/dist/shared/runners.js +49 -7
- package/dist/shared/runners.js.map +1 -1
- package/dist/shared/runs.d.ts +213 -1
- package/dist/shared/runs.d.ts.map +1 -1
- package/dist/shared/runs.js +24 -0
- package/dist/shared/runs.js.map +1 -1
- package/dist/shared/skills.d.ts +8 -4
- package/dist/shared/skills.d.ts.map +1 -1
- package/dist/shared/skills.js +7 -2
- package/dist/shared/skills.js.map +1 -1
- package/dist/shared/variables.d.ts +22 -0
- package/dist/shared/variables.d.ts.map +1 -1
- package/dist/shared/variables.js +10 -2
- package/dist/shared/variables.js.map +1 -1
- package/package.json +24 -26
- package/skills/nocobase-app-plugin-agents/SKILL.md +8 -7
- package/skills/nocobase-app-plugin-agents/references/agents.md +30 -0
- package/skills/nocobase-app-plugin-agents/references/distribution.md +21 -4
- package/skills/nocobase-app-plugin-agents/references/extension-points.md +30 -20
- package/skills/nocobase-app-plugin-agents/references/model-services.md +17 -0
- package/skills/nocobase-app-plugin-agents/references/runners.md +15 -1
- package/skills/nocobase-app-plugin-agents/references/setup-and-config.md +4 -7
- package/skills/nocobase-app-plugin-agents/references/variables-skills-usage.md +6 -4
- package/skills/nocobase-app-plugin-agents/references/verification-and-troubleshooting.md +33 -32
- package/dist/client/chat/settings-section.d.ts +0 -5
- package/dist/client/chat/settings-section.d.ts.map +0 -1
- package/dist/client/chat/settings-section.js +0 -76
- package/dist/client/chat/settings-section.js.map +0 -1
- package/dist/client/components/agent-fields.d.ts +0 -45
- package/dist/client/components/agent-fields.d.ts.map +0 -1
- package/dist/client/components/agent-fields.js +0 -83
- package/dist/client/components/agent-fields.js.map +0 -1
- package/dist/client/components/agent-type.d.ts +0 -32
- package/dist/client/components/agent-type.d.ts.map +0 -1
- package/dist/client/components/agent-type.js +0 -80
- package/dist/client/components/agent-type.js.map +0 -1
- package/dist/client/components/model-entries.d.ts +0 -35
- package/dist/client/components/model-entries.d.ts.map +0 -1
- package/dist/client/components/model-entries.js +0 -82
- package/dist/client/components/model-entries.js.map +0 -1
- package/dist/client/hooks/use-agent-save.d.ts +0 -9
- package/dist/client/hooks/use-agent-save.d.ts.map +0 -1
- package/dist/client/hooks/use-agent-save.js +0 -40
- package/dist/client/hooks/use-agent-save.js.map +0 -1
- package/dist/client/hooks/use-model-catalog.d.ts +0 -9
- package/dist/client/hooks/use-model-catalog.d.ts.map +0 -1
- package/dist/client/hooks/use-model-catalog.js +0 -27
- package/dist/client/hooks/use-model-catalog.js.map +0 -1
- package/dist/client/lib/tool-policy.d.ts +0 -5
- package/dist/client/lib/tool-policy.d.ts.map +0 -1
- package/dist/client/lib/tool-policy.js +0 -10
- package/dist/client/lib/tool-policy.js.map +0 -1
- package/dist/client/online/default-model.d.ts +0 -5
- package/dist/client/online/default-model.d.ts.map +0 -1
- package/dist/client/online/default-model.js +0 -65
- package/dist/client/online/default-model.js.map +0 -1
- package/dist/client/pages/agents/agent-model.d.ts +0 -73
- package/dist/client/pages/agents/agent-model.d.ts.map +0 -1
- package/dist/client/pages/agents/agent-model.js +0 -172
- package/dist/client/pages/agents/agent-model.js.map +0 -1
- package/dist/client/pages/agents/detail/brief-preview.d.ts +0 -7
- package/dist/client/pages/agents/detail/brief-preview.d.ts.map +0 -1
- package/dist/client/pages/agents/detail/brief-preview.js +0 -43
- package/dist/client/pages/agents/detail/brief-preview.js.map +0 -1
- package/dist/client/pages/agents/detail/history.d.ts +0 -11
- package/dist/client/pages/agents/detail/history.d.ts.map +0 -1
- package/dist/client/pages/agents/detail/history.js +0 -149
- package/dist/client/pages/agents/detail/history.js.map +0 -1
- package/dist/client/pages/agents/detail/index.d.ts +0 -3
- package/dist/client/pages/agents/detail/index.d.ts.map +0 -1
- package/dist/client/pages/agents/detail/index.js +0 -241
- package/dist/client/pages/agents/detail/index.js.map +0 -1
- package/dist/client/pages/agents/detail/sections.d.ts +0 -22
- package/dist/client/pages/agents/detail/sections.d.ts.map +0 -1
- package/dist/client/pages/agents/detail/sections.js +0 -311
- package/dist/client/pages/agents/detail/sections.js.map +0 -1
- package/dist/client/pages/agents/detail/tab-draft.d.ts +0 -43
- package/dist/client/pages/agents/detail/tab-draft.d.ts.map +0 -1
- package/dist/client/pages/agents/detail/tab-draft.js +0 -115
- package/dist/client/pages/agents/detail/tab-draft.js.map +0 -1
- package/dist/client/pages/agents/detail/unsaved-bar.d.ts +0 -13
- package/dist/client/pages/agents/detail/unsaved-bar.d.ts.map +0 -1
- package/dist/client/pages/agents/detail/unsaved-bar.js +0 -21
- package/dist/client/pages/agents/detail/unsaved-bar.js.map +0 -1
- package/dist/client/pages/agents/new.d.ts +0 -3
- package/dist/client/pages/agents/new.d.ts.map +0 -1
- package/dist/client/pages/agents/new.js +0 -149
- package/dist/client/pages/agents/new.js.map +0 -1
- package/dist/client/pages/agents/preset-picker.d.ts +0 -8
- package/dist/client/pages/agents/preset-picker.d.ts.map +0 -1
- package/dist/client/pages/agents/preset-picker.js +0 -41
- package/dist/client/pages/agents/preset-picker.js.map +0 -1
- package/dist/server/core/consultations/consultation.service.d.ts +0 -59
- package/dist/server/core/consultations/consultation.service.d.ts.map +0 -1
- package/dist/server/core/consultations/consultation.service.js +0 -195
- package/dist/server/core/consultations/consultation.service.js.map +0 -1
- package/dist/server/core/consultations/index.d.ts +0 -3
- package/dist/server/core/consultations/index.d.ts.map +0 -1
- package/dist/server/core/consultations/index.js +0 -3
- package/dist/server/core/consultations/index.js.map +0 -1
- package/dist/server/core/consultations/prompt.d.ts +0 -41
- package/dist/server/core/consultations/prompt.d.ts.map +0 -1
- package/dist/server/core/consultations/prompt.js +0 -64
- package/dist/server/core/consultations/prompt.js.map +0 -1
- package/dist/server/core/presets/index.d.ts +0 -19
- package/dist/server/core/presets/index.d.ts.map +0 -1
- package/dist/server/core/presets/index.js +0 -28
- package/dist/server/core/presets/index.js.map +0 -1
- package/dist/server/online/cli-command.d.ts +0 -20
- package/dist/server/online/cli-command.d.ts.map +0 -1
- package/dist/server/online/cli-command.js +0 -345
- package/dist/server/online/cli-command.js.map +0 -1
- package/dist/server/online/consult-tool.d.ts +0 -54
- package/dist/server/online/consult-tool.d.ts.map +0 -1
- package/dist/server/online/consult-tool.js +0 -177
- package/dist/server/online/consult-tool.js.map +0 -1
- package/dist/server/online/executor.d.ts +0 -83
- package/dist/server/online/executor.d.ts.map +0 -1
- package/dist/server/online/executor.js +0 -714
- package/dist/server/online/executor.js.map +0 -1
- package/dist/server/online/sandbox.d.ts +0 -32
- package/dist/server/online/sandbox.d.ts.map +0 -1
- package/dist/server/online/sandbox.js +0 -246
- package/dist/server/online/sandbox.js.map +0 -1
- package/dist/server/online/scripted.d.ts +0 -12
- package/dist/server/online/scripted.d.ts.map +0 -1
- package/dist/server/online/scripted.js +0 -176
- package/dist/server/online/scripted.js.map +0 -1
- package/dist/server/online/tools.d.ts +0 -17
- package/dist/server/online/tools.d.ts.map +0 -1
- package/dist/server/online/tools.js +0 -31
- package/dist/server/online/tools.js.map +0 -1
- package/dist/server/vendor/THIRD_PARTY_LICENSES.txt +0 -782
- package/dist/server/vendor/just-bash.d.ts +0 -83
- package/dist/server/vendor/just-bash.js +0 -2102
- package/dist/shared/presets.d.ts +0 -30
- package/dist/shared/presets.d.ts.map +0 -1
- package/dist/shared/presets.js +0 -2
- package/dist/shared/presets.js.map +0 -1
- package/skills/nocobase-app-plugin-agents/references/online-agents.md +0 -31
|
@@ -3,20 +3,39 @@
|
|
|
3
3
|
* cancelling and retrying, and reading runs and their transcripts. Who may read or change a run is decided by the
|
|
4
4
|
* callers (the admin routes, the application); this service checks only that the person who wakes an agent may wake it.
|
|
5
5
|
*
|
|
6
|
-
* Work is keyed by (agent, subject, thread). New work for a key joins the run already working on it
|
|
7
|
-
* still be told (dispatched, or running with input), else
|
|
6
|
+
* Work is keyed by (agent, subject, thread). New work for a key joins the run already working on it as the same person
|
|
7
|
+
* while it can still be told (dispatched, or running with input), else that person's run waiting for it (queued), else
|
|
8
|
+
* starts a new run. Runs of one key working as different people are claimed one at a time (`claim.ts`).
|
|
8
9
|
*/
|
|
9
10
|
import { ProtocolError, TERMINAL_RUN_STATUSES, } from '@nocobase/agent-protocol';
|
|
10
11
|
import { conflict, forbidden, invalid, notFound, precondition, } from '../../kernel/errors.js';
|
|
11
|
-
import { asJson, cleanList, jsonObject } from '../../kernel/values.js';
|
|
12
|
+
import { asJson, cleanList, jsonObject, stringArray, } from '../../kernel/values.js';
|
|
12
13
|
import { findAgent, lockAgentForClaim } from '../agents/index.js';
|
|
14
|
+
import { agentNamesOf } from '../agents/agent.store.js';
|
|
15
|
+
import { createRunRequestService, insertRunRequest, } from './run-requests.js';
|
|
13
16
|
import { authenticateRunToken } from './run-tokens.js';
|
|
14
|
-
import { ACTIVE, eventsRepo, findRunRecord, inputsOnSince, inputsRepo, isActive, isTerminal, lastSummary, openRunsOn, pendingInputs, reposRepo, runsOfKey, runsRepo, toInput, toInputView, toRepo, toRun, usageRepo, } from './run.store.js';
|
|
15
|
-
import { dialectOf, takesType } from './ports.js';
|
|
17
|
+
import { ACTIVE, eventsRepo, findRunRecord, inputsOnSince, inputsRepo, isActive, isTerminal, lastSummary, openRunsOn, openRunsOnEach, pendingInputs, reposRepo, runsOfKey, runsRepo, toInput, toInputView, toRepo, toRun, usageRepo, } from './run.store.js';
|
|
16
18
|
import { readWorkload } from './workload.js';
|
|
17
19
|
import { finishRun } from './transitions.js';
|
|
20
|
+
import { gateInputs, gatePending } from './input-gate.js';
|
|
18
21
|
import { findBrief, requestReset } from './workspace.store.js';
|
|
22
|
+
import { findCommentRoot, currentCommentOwner, commentConsent, commentFromOwner, } from './comment-consent.js';
|
|
19
23
|
export const DEFAULT_THREAD = 'main';
|
|
24
|
+
/**
|
|
25
|
+
* The run work went into, for a caller that names no responsible (a conversation, a consultation): such work is never
|
|
26
|
+
* pending, so a pending result is a programming error.
|
|
27
|
+
*/
|
|
28
|
+
export function queuedRun(result) {
|
|
29
|
+
if (result.outcome === 'pending')
|
|
30
|
+
throw new Error('Work that names no responsible was turned into a run request.');
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/** Who a chain of work a run belongs to started with: who confirmed it, else who it was requested by. */
|
|
34
|
+
function chainSourceOf(run) {
|
|
35
|
+
return run.commentRootRunId
|
|
36
|
+
? (run.requestedByUserId ?? run.actorUserId)
|
|
37
|
+
: (run.confirmedByUserId ?? run.requestedByUserId ?? run.actorUserId);
|
|
38
|
+
}
|
|
20
39
|
/** A delay as the moment a run may be claimed, or null for now (and for any moment already past). */
|
|
21
40
|
function fireAtOf(value, now) {
|
|
22
41
|
if (value === undefined)
|
|
@@ -26,8 +45,20 @@ function fireAtOf(value, now) {
|
|
|
26
45
|
throw invalid('fireAt is not a date.');
|
|
27
46
|
return at.getTime() > now.getTime() ? at.toISOString() : null;
|
|
28
47
|
}
|
|
48
|
+
const COMMENT_CANCEL_DETAIL = 'The personal runner request was declined or switched to the commenter.';
|
|
29
49
|
export function createRunService(deps) {
|
|
30
50
|
const { tx, ids, clock } = deps;
|
|
51
|
+
/** Ends one unfinished run of a declined chain; a run that moved since it was read rolls the decision back. */
|
|
52
|
+
async function endCommentRun(unit, run, byUserId) {
|
|
53
|
+
const ended = await finishRun(unit, deps, run, {
|
|
54
|
+
status: 'cancelled',
|
|
55
|
+
reason: null,
|
|
56
|
+
detail: COMMENT_CANCEL_DETAIL,
|
|
57
|
+
cancelledById: byUserId,
|
|
58
|
+
});
|
|
59
|
+
if (!ended)
|
|
60
|
+
throw conflict('The comment work changed; read it again.');
|
|
61
|
+
}
|
|
31
62
|
const require = async (conn, id) => {
|
|
32
63
|
const run = await findRunRecord(conn, id);
|
|
33
64
|
if (!run)
|
|
@@ -52,43 +83,55 @@ export function createRunService(deps) {
|
|
|
52
83
|
},
|
|
53
84
|
});
|
|
54
85
|
unit.emit({ type: 'run.input', runId, inputId: id });
|
|
86
|
+
await runsRepo(unit.conn).updateMany({
|
|
87
|
+
filter: { id: runId, status: 'queued' },
|
|
88
|
+
// New input may change the scopes its variables come from: the next claim tells again.
|
|
89
|
+
values: { teamOnlyVariables: null },
|
|
90
|
+
});
|
|
55
91
|
return id;
|
|
56
92
|
}
|
|
57
93
|
async function requireInvocable(unit, agentId, userId) {
|
|
58
94
|
const agent = await findAgent(unit.conn, agentId);
|
|
59
95
|
if (!agent)
|
|
60
96
|
throw notFound('Agent');
|
|
61
|
-
if (agent.
|
|
62
|
-
throw precondition('
|
|
97
|
+
if (agent.status !== 'enabled')
|
|
98
|
+
throw precondition('AGENT_NOT_ENABLED', 'The agent is not enabled.');
|
|
63
99
|
if (!deps.agents.mayInvoke(agent, userId))
|
|
64
100
|
throw forbidden('You may not wake this agent.');
|
|
65
101
|
return agent;
|
|
66
102
|
}
|
|
67
103
|
async function createRun(unit, agent, values) {
|
|
68
|
-
if (!takesType(deps.subjects.get(values.subject.kind), agent.type))
|
|
69
|
-
throw invalid(`A ${agent.type} agent cannot work on a ${values.subject.kind}.`, { reason: 'AGENT_TYPE_NOT_ALLOWED', agentType: agent.type });
|
|
70
104
|
const now = clock.now().toISOString();
|
|
71
105
|
const id = ids.next();
|
|
72
106
|
await runsRepo(unit.conn).createOne({
|
|
73
107
|
values: {
|
|
74
108
|
id,
|
|
75
109
|
agentId: agent.id,
|
|
76
|
-
agentType:
|
|
110
|
+
agentType: 'runner',
|
|
77
111
|
runnerId: null,
|
|
78
112
|
status: 'queued',
|
|
79
113
|
priority: values.priority,
|
|
80
114
|
attempt: 1,
|
|
81
115
|
maxAttempts: values.maxAttempts ?? agent.maxAttempts,
|
|
82
116
|
retryOfRunId: values.retryOfRunId,
|
|
117
|
+
freshSession: values.freshSession === true,
|
|
83
118
|
parentRunId: values.parentRunId ?? null,
|
|
84
119
|
subjectKind: values.subject.kind,
|
|
85
120
|
subjectId: values.subject.id,
|
|
86
121
|
threadScope: values.threadScope,
|
|
122
|
+
commentRootRunId: values.commentRootRunId === ''
|
|
123
|
+
? id
|
|
124
|
+
: (values.commentRootRunId ?? null),
|
|
125
|
+
commentExecution: values.commentExecution ?? null,
|
|
126
|
+
commentOwnerKey: values.commentOwnerKey ?? null,
|
|
87
127
|
actorUserId: values.actorUserId,
|
|
128
|
+
requestedByUserId: values.requestedByUserId,
|
|
129
|
+
confirmedByUserId: values.confirmedByUserId,
|
|
88
130
|
ownerUserId: values.ownerUserId,
|
|
89
131
|
requires: cleanList([...values.requires]),
|
|
90
132
|
acceptsInput: false,
|
|
91
133
|
availableAt: values.availableAt ?? null,
|
|
134
|
+
queueEnteredAt: now,
|
|
92
135
|
leaseExpiresAt: null,
|
|
93
136
|
dispatchedAt: null,
|
|
94
137
|
startedAt: null,
|
|
@@ -103,6 +146,7 @@ export function createRunService(deps) {
|
|
|
103
146
|
workDir: null,
|
|
104
147
|
directoryKey: null,
|
|
105
148
|
claimFailures: 0,
|
|
149
|
+
teamOnlyVariables: null,
|
|
106
150
|
payloadFingerprint: null,
|
|
107
151
|
createdAt: now,
|
|
108
152
|
updatedAt: now,
|
|
@@ -152,53 +196,630 @@ export function createRunService(deps) {
|
|
|
152
196
|
}
|
|
153
197
|
return [...totals.values()];
|
|
154
198
|
}
|
|
199
|
+
/** Legacy runs have no snapshots; report their known primary-tool models without inventing attempt boundaries. */
|
|
200
|
+
async function readRuns(records) {
|
|
201
|
+
const runs = records.map(toRun);
|
|
202
|
+
const legacy = runs.filter((run) => run.executions?.length === 0 &&
|
|
203
|
+
(run.dispatchedAt !== null ||
|
|
204
|
+
run.tool !== null ||
|
|
205
|
+
run.modelService !== null));
|
|
206
|
+
if (legacy.length === 0)
|
|
207
|
+
return runs;
|
|
208
|
+
const usage = await usageRepo(tx.read()).findMany({
|
|
209
|
+
select: (select) => select.fields('runId', 'tool', 'model'),
|
|
210
|
+
distinct: ['runId', 'tool', 'model'],
|
|
211
|
+
filter: (f) => f.and([
|
|
212
|
+
f.string('model').ne(null),
|
|
213
|
+
f.or(legacy.map((run) => f.and([
|
|
214
|
+
f.string('runId').eq(run.id),
|
|
215
|
+
f.string('tool').eq(run.tool ?? 'online'),
|
|
216
|
+
]))),
|
|
217
|
+
]),
|
|
218
|
+
});
|
|
219
|
+
const models = new Map();
|
|
220
|
+
for (const row of usage)
|
|
221
|
+
if (row.model)
|
|
222
|
+
models.set(row.runId, [...(models.get(row.runId) ?? []), row.model]);
|
|
223
|
+
return runs.map((run) => run.executions?.length
|
|
224
|
+
? run
|
|
225
|
+
: {
|
|
226
|
+
...run,
|
|
227
|
+
actualModels: models.get(run.id) ?? [],
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/** Cross-root appends require both sources to retain the same owner's authorization. */
|
|
231
|
+
async function equivalentCommentAuthority(unit, run, work) {
|
|
232
|
+
if (run.ownerUserId !== work.ownerUserId ||
|
|
233
|
+
(run.commentOwnerKey ?? null) !== (work.commentOwnerKey ?? null) ||
|
|
234
|
+
(run.commentExecution ?? 'owner') !== (work.commentExecution ?? 'owner'))
|
|
235
|
+
return false;
|
|
236
|
+
if ((run.commentRootRunId ?? null) === (work.commentRootRunId ?? null)) {
|
|
237
|
+
if (!run.commentRootRunId)
|
|
238
|
+
return true;
|
|
239
|
+
const root = await findCommentRoot(unit.conn, run.commentRootRunId);
|
|
240
|
+
// Requester execution keeps its own identity; it does not borrow the owner's consent.
|
|
241
|
+
if (root.commentExecution === 'requester')
|
|
242
|
+
return (root.actorUserId === work.actorUserId &&
|
|
243
|
+
(await currentCommentOwner(unit.conn, deps.subjects, root)));
|
|
244
|
+
return await authorizedRoot(root);
|
|
245
|
+
}
|
|
246
|
+
if (work.commentExecution === 'requester' ||
|
|
247
|
+
run.commentExecution === 'requester' ||
|
|
248
|
+
!work.sourceRunId)
|
|
249
|
+
return false;
|
|
250
|
+
const source = await findRunRecord(unit.conn, work.sourceRunId);
|
|
251
|
+
if (!source ||
|
|
252
|
+
source.subjectKind !== run.subjectKind ||
|
|
253
|
+
source.subjectId !== run.subjectId ||
|
|
254
|
+
source.ownerUserId !== run.ownerUserId ||
|
|
255
|
+
source.actorUserId !== run.actorUserId)
|
|
256
|
+
return false;
|
|
257
|
+
const sourceRoot = source.commentRootRunId
|
|
258
|
+
? await findCommentRoot(unit.conn, source.commentRootRunId)
|
|
259
|
+
: source;
|
|
260
|
+
const targetRoot = run.commentRootRunId
|
|
261
|
+
? await findCommentRoot(unit.conn, run.commentRootRunId)
|
|
262
|
+
: run;
|
|
263
|
+
return ((await authorizedRoot(sourceRoot)) && (await authorizedRoot(targetRoot)));
|
|
264
|
+
async function authorizedRoot(root) {
|
|
265
|
+
if (!(await currentCommentOwner(unit.conn, deps.subjects, root)))
|
|
266
|
+
return false;
|
|
267
|
+
if (!root.commentRootRunId)
|
|
268
|
+
return chainSourceOf(root) === root.ownerUserId;
|
|
269
|
+
const { decision } = await commentConsent(unit.conn, root);
|
|
270
|
+
if (decision === 'pending' || decision === 'rejected')
|
|
271
|
+
return false;
|
|
272
|
+
return (decision === 'confirmed' || (await commentFromOwner(unit.conn, root)));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Queues `work` for `agent`: it joins the run working on its key while that run can still be told, else the run
|
|
277
|
+
* waiting for it, else starts a new run.
|
|
278
|
+
*/
|
|
279
|
+
async function queue(unit, agent, work) {
|
|
280
|
+
if (work.commentRootRunId) {
|
|
281
|
+
// A plain read: the root's subject never changes, and the agent lock below serializes the chain's enqueues.
|
|
282
|
+
const root = await findCommentRoot(unit.conn, work.commentRootRunId);
|
|
283
|
+
if (root.subjectKind !== work.subject.kind ||
|
|
284
|
+
root.subjectId !== work.subject.id)
|
|
285
|
+
throw invalid('A comment authorization cannot cross subjects.');
|
|
286
|
+
}
|
|
287
|
+
// Serializes enqueues and claims for this agent, so a key never gets two waiting runs.
|
|
288
|
+
await lockAgentForClaim(unit.conn, agent.id, clock.now().toISOString());
|
|
289
|
+
if (work.preferActive) {
|
|
290
|
+
const commentId = jsonObject(work.input.payload).commentId;
|
|
291
|
+
if (typeof commentId === 'string') {
|
|
292
|
+
const prior = await inputsRepo(unit.conn).findOne({
|
|
293
|
+
filter: (f) => f.and([
|
|
294
|
+
f.string('type').eq('comment'),
|
|
295
|
+
f.json('payload').path(['commentId']).eq(commentId),
|
|
296
|
+
f
|
|
297
|
+
.relation('run')
|
|
298
|
+
.some((r) => r.and([
|
|
299
|
+
r.string('agentId').eq(agent.id),
|
|
300
|
+
r.string('subjectKind').eq(work.subject.kind),
|
|
301
|
+
r.string('subjectId').eq(work.subject.id),
|
|
302
|
+
])),
|
|
303
|
+
]),
|
|
304
|
+
});
|
|
305
|
+
if (prior) {
|
|
306
|
+
const run = (await findRunRecord(unit.conn, prior.runId));
|
|
307
|
+
return {
|
|
308
|
+
runId: run.id,
|
|
309
|
+
inputId: prior.id,
|
|
310
|
+
outcome: 'appended',
|
|
311
|
+
status: run.status,
|
|
312
|
+
duplicate: true,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const key = {
|
|
318
|
+
agentId: agent.id,
|
|
319
|
+
subjectKind: work.subject.kind,
|
|
320
|
+
subjectId: work.subject.id,
|
|
321
|
+
threadScope: work.threadScope,
|
|
322
|
+
};
|
|
323
|
+
// Only into work done as the same person: merged into another's run, it would borrow their identity, or wait
|
|
324
|
+
// for a runner that never takes it.
|
|
325
|
+
const unfiltered = await runsOfKey(unit.conn, key, ['queued', ...ACTIVE], work.actorUserId);
|
|
326
|
+
const open = unfiltered.filter((run) => (run.commentRootRunId ?? null) === (work.commentRootRunId ?? null) &&
|
|
327
|
+
(run.commentExecution ?? null) === (work.commentExecution ?? null));
|
|
328
|
+
let working;
|
|
329
|
+
for (let candidate of work.preferActive ? unfiltered : open) {
|
|
330
|
+
if (work.freshSession ||
|
|
331
|
+
candidate.cancelRequestedAt ||
|
|
332
|
+
!(candidate.status === 'dispatched' ||
|
|
333
|
+
(candidate.status === 'running' && Boolean(candidate.acceptsInput))))
|
|
334
|
+
continue;
|
|
335
|
+
if (work.preferActive) {
|
|
336
|
+
if (!candidate.runnerId ||
|
|
337
|
+
!['claude', 'codex', 'pi', 'opencode'].includes(candidate.tool ?? ''))
|
|
338
|
+
continue;
|
|
339
|
+
const runner = await deps.runners.find(unit.conn, candidate.runnerId);
|
|
340
|
+
if (!runner?.features.includes('steer'))
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
344
|
+
if (work.preferActive &&
|
|
345
|
+
!(await equivalentCommentAuthority(unit, candidate, work)))
|
|
346
|
+
break;
|
|
347
|
+
const input = {
|
|
348
|
+
id: '',
|
|
349
|
+
at: clock.now().toISOString(),
|
|
350
|
+
...work.input,
|
|
351
|
+
...(candidate.commentRootRunId
|
|
352
|
+
? {
|
|
353
|
+
payload: {
|
|
354
|
+
...jsonObject(work.input.payload),
|
|
355
|
+
commentRootRunId: candidate.commentRootRunId,
|
|
356
|
+
},
|
|
357
|
+
}
|
|
358
|
+
: {}),
|
|
359
|
+
};
|
|
360
|
+
if ((await gateInputs(unit.conn, deps, candidate, agent, [input]))
|
|
361
|
+
.length === 0)
|
|
362
|
+
break;
|
|
363
|
+
const touched = await runsRepo(unit.conn).updateMany({
|
|
364
|
+
filter: (f) => f.and([
|
|
365
|
+
f.string('id').eq(candidate.id),
|
|
366
|
+
f.string('status').eq(candidate.status),
|
|
367
|
+
f.number('revision').eq(candidate.revision),
|
|
368
|
+
f.date('cancelRequestedAt').empty(),
|
|
369
|
+
]),
|
|
370
|
+
values: { updatedAt: clock.now().toISOString() },
|
|
371
|
+
});
|
|
372
|
+
if (touched.updatedCount === 1) {
|
|
373
|
+
working = candidate;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
const current = await findRunRecord(unit.conn, candidate.id);
|
|
377
|
+
if (!current ||
|
|
378
|
+
current.cancelRequestedAt ||
|
|
379
|
+
!(current.status === 'dispatched' ||
|
|
380
|
+
(current.status === 'running' && current.acceptsInput)))
|
|
381
|
+
break;
|
|
382
|
+
// A claim/start may change the holder or tool; re-evaluate those on a subsequent dispatch.
|
|
383
|
+
if (current.actorUserId !== work.actorUserId ||
|
|
384
|
+
current.threadScope !== work.threadScope ||
|
|
385
|
+
current.runnerId !== candidate.runnerId ||
|
|
386
|
+
current.tool !== candidate.tool)
|
|
387
|
+
break;
|
|
388
|
+
candidate = current;
|
|
389
|
+
if (attempt === 3)
|
|
390
|
+
throw conflict('The run revision changed during append; retry the dispatch.');
|
|
391
|
+
}
|
|
392
|
+
if (working)
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
const waiting = open.find((run) => run.status === 'queued');
|
|
396
|
+
const target = working ?? waiting;
|
|
397
|
+
const commentInput = (rootId) => rootId
|
|
398
|
+
? {
|
|
399
|
+
...work.input,
|
|
400
|
+
payload: {
|
|
401
|
+
...jsonObject(work.input.payload),
|
|
402
|
+
commentRootRunId: rootId,
|
|
403
|
+
},
|
|
404
|
+
}
|
|
405
|
+
: work.input;
|
|
406
|
+
if (!working && waiting)
|
|
407
|
+
await hurry(unit, waiting, work.priority, work.fireAt);
|
|
408
|
+
if (target) {
|
|
409
|
+
if (!working && work.freshSession && !target.freshSession)
|
|
410
|
+
await runsRepo(unit.conn).updateMany({
|
|
411
|
+
filter: { id: target.id, status: 'queued' },
|
|
412
|
+
values: { freshSession: true, updatedAt: clock.now().toISOString() },
|
|
413
|
+
});
|
|
414
|
+
const inputId = await insertInput(unit, target.id, commentInput(target.commentRootRunId));
|
|
415
|
+
return {
|
|
416
|
+
runId: target.id,
|
|
417
|
+
outcome: working ? 'appended' : 'merged',
|
|
418
|
+
status: target.status,
|
|
419
|
+
inputId,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const runId = await createRun(unit, agent, {
|
|
423
|
+
commentRootRunId: work.commentRootRunId,
|
|
424
|
+
commentExecution: work.commentExecution,
|
|
425
|
+
commentOwnerKey: work.commentOwnerKey,
|
|
426
|
+
freshSession: work.freshSession,
|
|
427
|
+
subject: work.subject,
|
|
428
|
+
threadScope: work.threadScope,
|
|
429
|
+
actorUserId: work.actorUserId,
|
|
430
|
+
requestedByUserId: work.requestedByUserId,
|
|
431
|
+
confirmedByUserId: work.confirmedByUserId,
|
|
432
|
+
ownerUserId: work.ownerUserId,
|
|
433
|
+
priority: work.priority,
|
|
434
|
+
requires: work.requires,
|
|
435
|
+
retryOfRunId: null,
|
|
436
|
+
availableAt: work.fireAt,
|
|
437
|
+
...(work.parentRunId ? { parentRunId: work.parentRunId } : {}),
|
|
438
|
+
...(work.maxAttempts ? { maxAttempts: work.maxAttempts } : {}),
|
|
439
|
+
});
|
|
440
|
+
const inputId = await insertInput(unit, runId, commentInput(work.commentRootRunId === '' ? runId : work.commentRootRunId));
|
|
441
|
+
return { runId, outcome: 'created', status: 'queued', inputId };
|
|
442
|
+
}
|
|
443
|
+
/** The source of the chain of work a request belongs to (`EnqueueRequest.requestedByUserId`). */
|
|
444
|
+
async function sourceOf(unit, request) {
|
|
445
|
+
if (request.comment &&
|
|
446
|
+
request.input.actor.kind === 'user' &&
|
|
447
|
+
jsonObject(request.input.payload).byAgent !== true &&
|
|
448
|
+
(request.requestedByUserId ?? request.actorUserId))
|
|
449
|
+
return (request.requestedByUserId ?? request.actorUserId);
|
|
450
|
+
if (request.causedByRunId) {
|
|
451
|
+
const cause = await findRunRecord(unit.conn, request.causedByRunId);
|
|
452
|
+
if (!cause)
|
|
453
|
+
throw invalid('causedByRunId names no run.');
|
|
454
|
+
return request.comment
|
|
455
|
+
? (cause.requestedByUserId ?? cause.actorUserId)
|
|
456
|
+
: chainSourceOf(cause);
|
|
457
|
+
}
|
|
458
|
+
const source = request.requestedByUserId ??
|
|
459
|
+
request.actorUserId ??
|
|
460
|
+
request.responsibleUserId;
|
|
461
|
+
if (!source)
|
|
462
|
+
throw invalid('Name who woke the agent: actorUserId, requestedByUserId or responsibleUserId.');
|
|
463
|
+
return source;
|
|
464
|
+
}
|
|
465
|
+
async function selectedIdentity(unit, request, commentExecution) {
|
|
466
|
+
const identity = await deps.subjects
|
|
467
|
+
.get(request.subject.kind)
|
|
468
|
+
?.actsAs?.(unit.conn, {
|
|
469
|
+
subjectId: request.subject.id,
|
|
470
|
+
agentId: request.agentId,
|
|
471
|
+
causedByRunId: request.causedByRunId,
|
|
472
|
+
commentExecution,
|
|
473
|
+
actorUserId: request.actorUserId,
|
|
474
|
+
inputs: [request.input],
|
|
475
|
+
});
|
|
476
|
+
if (identity && !identity.actorUserId)
|
|
477
|
+
throw new ProtocolError('FORBIDDEN', 'The subject has no valid execution identity.', { identityReason: identity.reason ?? 'noOwner' });
|
|
478
|
+
return identity;
|
|
479
|
+
}
|
|
480
|
+
/** Refuses work run as `userId` when no runner they may use can run the agent now: it would only wait. */
|
|
481
|
+
async function requireRunnerFor(unit, agent, userId, requires) {
|
|
482
|
+
// By the claim's own rules, the agent's variables included; the subject's are the claim's to check.
|
|
483
|
+
if (!(await deps.eligibility.canClaim(unit.conn, agent, {
|
|
484
|
+
actorUserId: userId,
|
|
485
|
+
requires: requires,
|
|
486
|
+
})))
|
|
487
|
+
throw precondition('NO_RUNNER_AVAILABLE', 'No runner you may use can run this agent now: connect one of your own, or ask the person who answers for this to confirm it.', { agentId: agent.id });
|
|
488
|
+
}
|
|
489
|
+
const requests = createRunRequestService({
|
|
490
|
+
tx,
|
|
491
|
+
ids,
|
|
492
|
+
clock,
|
|
493
|
+
people: deps.people,
|
|
494
|
+
currentResponsible: (unit, subject) => deps.subjects
|
|
495
|
+
.get(subject.kind)
|
|
496
|
+
?.responsibleUserId?.(unit.conn, subject.id),
|
|
497
|
+
mayInvoke: (agent, userId) => deps.agents.mayInvoke(agent, userId),
|
|
498
|
+
requireInvocable,
|
|
499
|
+
requireRunnerFor,
|
|
500
|
+
prepareCommentActor: async (record, byUserId) => {
|
|
501
|
+
const mayRead = deps.subjects.get(record.subjectKind)?.commentActorMayRead;
|
|
502
|
+
if (mayRead && !(await mayRead(record.subjectId, byUserId)))
|
|
503
|
+
throw forbidden('The acting user may no longer read this issue.');
|
|
504
|
+
},
|
|
505
|
+
checkCommentRequest: async (unit, record) => {
|
|
506
|
+
const root = await findCommentRoot(unit.conn, record.commentRootRunId);
|
|
507
|
+
if (!(await currentCommentOwner(unit.conn, deps.subjects, root)) ||
|
|
508
|
+
root.commentExecution !== 'owner' ||
|
|
509
|
+
root.ownerUserId !== record.responsibleUserId ||
|
|
510
|
+
(root.commentOwnerKey ?? null) !== (record.commentOwnerKey ?? null))
|
|
511
|
+
throw precondition('RUN_REQUEST_SETTLED', 'This comment request belongs to an earlier owner assignment.');
|
|
512
|
+
},
|
|
513
|
+
releaseCommentRequest: async (unit, record, byUserId) => {
|
|
514
|
+
const run = await findRunRecord(unit.conn, record.commentRunId);
|
|
515
|
+
if (!run ||
|
|
516
|
+
run.status !== 'queued' ||
|
|
517
|
+
run.commentRootRunId !== record.commentRootRunId)
|
|
518
|
+
throw precondition('RUN_REQUEST_SETTLED', 'The requested work is no longer waiting.');
|
|
519
|
+
const inputs = await pendingInputs(unit.conn, run.id);
|
|
520
|
+
const now = clock.now().toISOString();
|
|
521
|
+
// Guarded on the requested run itself: a claim that took it first wins, and this confirmation rolls back.
|
|
522
|
+
const released = await runsRepo(unit.conn).updateMany({
|
|
523
|
+
filter: { id: run.id, status: 'queued' },
|
|
524
|
+
values: { confirmedByUserId: byUserId, updatedAt: now },
|
|
525
|
+
});
|
|
526
|
+
if (released.updatedCount !== 1)
|
|
527
|
+
throw precondition('RUN_REQUEST_SETTLED', 'The requested work is no longer waiting.');
|
|
528
|
+
await runsRepo(unit.conn).updateMany({
|
|
529
|
+
filter: {
|
|
530
|
+
commentRootRunId: record.commentRootRunId,
|
|
531
|
+
status: 'queued',
|
|
532
|
+
actorUserId: record.responsibleUserId,
|
|
533
|
+
},
|
|
534
|
+
values: { confirmedByUserId: byUserId, updatedAt: now },
|
|
535
|
+
});
|
|
536
|
+
unit.emit({ type: 'run.changed', runId: run.id, status: 'queued' });
|
|
537
|
+
return {
|
|
538
|
+
runId: run.id,
|
|
539
|
+
outcome: 'merged',
|
|
540
|
+
status: 'queued',
|
|
541
|
+
inputId: inputs[0].id,
|
|
542
|
+
};
|
|
543
|
+
},
|
|
544
|
+
cancelCommentRequest: async (unit, record, byUserId) => {
|
|
545
|
+
for (const run of await runsRepo(unit.conn).findMany({
|
|
546
|
+
filter: { commentRootRunId: record.commentRootRunId },
|
|
547
|
+
}))
|
|
548
|
+
if (!isTerminal(run.status))
|
|
549
|
+
await endCommentRun(unit, run, byUserId);
|
|
550
|
+
},
|
|
551
|
+
runCommentAsRequester: async (unit, record, byUserId) => {
|
|
552
|
+
// Queuing the replacements takes their agents' rows, as claims do before they take a run. Taking every agent of
|
|
553
|
+
// the chain first, in one order, keeps this from holding a run a claim waits on while it waits for that claim.
|
|
554
|
+
const agentIds = new Set((await runsRepo(unit.conn).findMany({
|
|
555
|
+
filter: { commentRootRunId: record.commentRootRunId },
|
|
556
|
+
})).map((run) => run.agentId));
|
|
557
|
+
for (const agentId of [...agentIds].sort())
|
|
558
|
+
await lockAgentForClaim(unit.conn, agentId, clock.now().toISOString());
|
|
559
|
+
const chain = await runsRepo(unit.conn).findMany({
|
|
560
|
+
filter: { commentRootRunId: record.commentRootRunId },
|
|
561
|
+
sort: (sort) => [sort.field('createdAt').asc(), sort.field('id').asc()],
|
|
562
|
+
});
|
|
563
|
+
const targets = [];
|
|
564
|
+
for (const old of chain) {
|
|
565
|
+
// Rejection ends the queued chain, but leaves its inputs unhandled. Do not revive independently ended work.
|
|
566
|
+
const declined = record.status === 'rejected' &&
|
|
567
|
+
old.status === 'cancelled' &&
|
|
568
|
+
old.cancelledById === record.responsibleUserId &&
|
|
569
|
+
old.failureDetail === COMMENT_CANCEL_DETAIL;
|
|
570
|
+
if (isTerminal(old.status) && !declined)
|
|
571
|
+
continue;
|
|
572
|
+
const inputs = await pendingInputs(unit.conn, old.id);
|
|
573
|
+
if (inputs.length === 0)
|
|
574
|
+
continue;
|
|
575
|
+
await selectedIdentity(unit, {
|
|
576
|
+
agentId: old.agentId,
|
|
577
|
+
subject: { kind: old.subjectKind, id: old.subjectId },
|
|
578
|
+
input: toInput(inputs[0]),
|
|
579
|
+
actorUserId: byUserId,
|
|
580
|
+
}, 'requester');
|
|
581
|
+
const agent = await requireInvocable(unit, old.agentId, byUserId);
|
|
582
|
+
const requires = stringArray(old.requires);
|
|
583
|
+
await requireRunnerFor(unit, agent, byUserId, requires);
|
|
584
|
+
targets.push({ old, inputs, agent, requires });
|
|
585
|
+
}
|
|
586
|
+
if (!targets.length)
|
|
587
|
+
throw precondition('RUN_REQUEST_SETTLED', 'No comment work is still waiting.');
|
|
588
|
+
// Validate all targets before stopping any of them. Each stop is guarded on the status read, so a run a claim took
|
|
589
|
+
// meanwhile rolls this back rather than being replaced twice; the settled request covers repeat clicks.
|
|
590
|
+
for (const old of chain)
|
|
591
|
+
if (!isTerminal(old.status))
|
|
592
|
+
await endCommentRun(unit, old, byUserId);
|
|
593
|
+
const replacements = new Map();
|
|
594
|
+
let rootId;
|
|
595
|
+
for (const { old, inputs, agent, requires } of targets) {
|
|
596
|
+
const first = inputs[0];
|
|
597
|
+
const next = await queue(unit, agent, {
|
|
598
|
+
commentRootRunId: rootId ?? '',
|
|
599
|
+
commentExecution: 'requester',
|
|
600
|
+
commentOwnerKey: record.commentOwnerKey ?? null,
|
|
601
|
+
freshSession: Boolean(old.freshSession),
|
|
602
|
+
subject: { kind: old.subjectKind, id: old.subjectId },
|
|
603
|
+
threadScope: old.threadScope,
|
|
604
|
+
actorUserId: byUserId,
|
|
605
|
+
requestedByUserId: byUserId,
|
|
606
|
+
confirmedByUserId: null,
|
|
607
|
+
ownerUserId: old.ownerUserId,
|
|
608
|
+
priority: Number(old.priority),
|
|
609
|
+
fireAt: fireAtOf(old.availableAt ?? undefined, clock.now()),
|
|
610
|
+
requires,
|
|
611
|
+
maxAttempts: Number(old.maxAttempts),
|
|
612
|
+
input: toInput(first),
|
|
613
|
+
});
|
|
614
|
+
rootId ??= next.runId;
|
|
615
|
+
replacements.set(old.id, next);
|
|
616
|
+
for (const input of inputs.slice(1))
|
|
617
|
+
await insertInput(unit, next.runId, {
|
|
618
|
+
...toInput(input),
|
|
619
|
+
payload: { ...jsonObject(input.payload), commentRootRunId: rootId },
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
// Remap causal references only for replaced work; completed ancestors remain the original historical runs.
|
|
623
|
+
for (const { old } of targets) {
|
|
624
|
+
const next = replacements.get(old.id);
|
|
625
|
+
if (old.parentRunId)
|
|
626
|
+
await runsRepo(unit.conn).updateMany({
|
|
627
|
+
filter: { id: next.runId },
|
|
628
|
+
values: {
|
|
629
|
+
parentRunId: replacements.get(old.parentRunId)?.runId ?? old.parentRunId,
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
for (const input of await pendingInputs(unit.conn, next.runId)) {
|
|
633
|
+
const payload = jsonObject(input.payload);
|
|
634
|
+
const cause = typeof payload.causedByRunId === 'string'
|
|
635
|
+
? replacements.get(payload.causedByRunId)
|
|
636
|
+
: undefined;
|
|
637
|
+
if (cause)
|
|
638
|
+
await inputsRepo(unit.conn).updateMany({
|
|
639
|
+
filter: { id: input.id },
|
|
640
|
+
values: {
|
|
641
|
+
payload: asJson({ ...payload, causedByRunId: cause.runId }),
|
|
642
|
+
},
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
const rootInputs = await pendingInputs(unit.conn, rootId);
|
|
647
|
+
if (!rootInputs.some((input) => input.type === record.inputType &&
|
|
648
|
+
input.text === record.inputText &&
|
|
649
|
+
jsonObject(input.payload).commentId ===
|
|
650
|
+
jsonObject(record.inputPayload).commentId)) {
|
|
651
|
+
const sourceId = await insertInput(unit, rootId, {
|
|
652
|
+
type: record.inputType,
|
|
653
|
+
actor: {
|
|
654
|
+
kind: record.inputActorKind,
|
|
655
|
+
id: record.inputActorId,
|
|
656
|
+
name: record.inputActorName,
|
|
657
|
+
},
|
|
658
|
+
text: record.inputText,
|
|
659
|
+
payload: {
|
|
660
|
+
...jsonObject(record.inputPayload),
|
|
661
|
+
commentSourceSnapshot: true,
|
|
662
|
+
commentRootRunId: rootId,
|
|
663
|
+
},
|
|
664
|
+
});
|
|
665
|
+
await inputsRepo(unit.conn).updateMany({
|
|
666
|
+
filter: { id: sourceId },
|
|
667
|
+
values: { handledAt: clock.now().toISOString() },
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return (replacements.get(record.commentRunId) ??
|
|
671
|
+
replacements.values().next().value);
|
|
672
|
+
},
|
|
673
|
+
direct: async (unit, run) => {
|
|
674
|
+
const identity = await selectedIdentity(unit, {
|
|
675
|
+
agentId: run.agent.id,
|
|
676
|
+
subject: run.subject,
|
|
677
|
+
input: run.input,
|
|
678
|
+
actorUserId: run.actorUserId,
|
|
679
|
+
});
|
|
680
|
+
const actorUserId = identity?.actorUserId ?? run.actorUserId;
|
|
681
|
+
const agent = await requireInvocable(unit, run.agent.id, actorUserId);
|
|
682
|
+
return queue(unit, agent, {
|
|
683
|
+
freshSession: run.freshSession,
|
|
684
|
+
subject: run.subject,
|
|
685
|
+
threadScope: run.threadScope,
|
|
686
|
+
actorUserId,
|
|
687
|
+
requestedByUserId: run.requestedByUserId,
|
|
688
|
+
confirmedByUserId: run.confirmedByUserId,
|
|
689
|
+
ownerUserId: identity ? actorUserId : run.ownerUserId,
|
|
690
|
+
priority: run.priority,
|
|
691
|
+
fireAt: fireAtOf(run.fireAt ?? undefined, clock.now()),
|
|
692
|
+
requires: run.requires,
|
|
693
|
+
...(run.maxAttempts === null ? {} : { maxAttempts: run.maxAttempts }),
|
|
694
|
+
input: run.input,
|
|
695
|
+
});
|
|
696
|
+
},
|
|
697
|
+
});
|
|
155
698
|
return {
|
|
156
699
|
enqueue: (request, outer) => tx.run(async (unit) => {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
700
|
+
const source = await sourceOf(unit, request);
|
|
701
|
+
const cause = request.causedByRunId
|
|
702
|
+
? await findRunRecord(unit.conn, request.causedByRunId)
|
|
703
|
+
: null;
|
|
704
|
+
const inherited = !request.comment &&
|
|
705
|
+
cause?.commentRootRunId &&
|
|
706
|
+
cause.subjectKind === request.subject.kind &&
|
|
707
|
+
cause.subjectId === request.subject.id
|
|
708
|
+
? cause
|
|
709
|
+
: null;
|
|
710
|
+
const commentRootRunId = request.comment?.rootRunId ??
|
|
711
|
+
inherited?.commentRootRunId ??
|
|
712
|
+
(request.comment ? '' : null);
|
|
713
|
+
const commentExecution = inherited?.commentExecution ?? (request.comment ? 'owner' : null);
|
|
714
|
+
const commentOwnerKey = request.comment?.ownerKey ?? inherited?.commentOwnerKey ?? null;
|
|
715
|
+
const identity = await selectedIdentity(unit, request, commentExecution);
|
|
716
|
+
const responsible = identity
|
|
717
|
+
? null
|
|
718
|
+
: (request.responsibleUserId ?? null);
|
|
719
|
+
const threadScope = request.threadScope ?? DEFAULT_THREAD;
|
|
720
|
+
const foreign = responsible !== null && source !== responsible;
|
|
721
|
+
if (foreign && (request.execution ?? 'auto') === 'auto') {
|
|
722
|
+
// A consultation's asker waits for its answer at once: it can never wait for someone's confirmation.
|
|
723
|
+
if (request.parentRunId)
|
|
724
|
+
throw invalid('A consultation cannot wait for confirmation: name no responsible for it.');
|
|
725
|
+
// Someone else's work waits for the responsible, who must be able to run it once they confirm it.
|
|
726
|
+
const agent = await requireInvocable(unit, request.agentId, source);
|
|
727
|
+
if (!deps.agents.mayInvoke(agent, responsible))
|
|
728
|
+
throw forbidden('The person who answers for this may not wake this agent.');
|
|
729
|
+
const created = await insertRunRequest(unit, { ids, clock }, {
|
|
730
|
+
agentId: agent.id,
|
|
731
|
+
freshSession: request.freshSession,
|
|
732
|
+
subject: request.subject,
|
|
733
|
+
threadScope,
|
|
734
|
+
responsibleUserId: responsible,
|
|
735
|
+
requestedByUserId: source,
|
|
736
|
+
ownerUserId: request.ownerUserId ?? null,
|
|
737
|
+
priority: request.priority ?? 0,
|
|
738
|
+
requires: request.requires ?? [],
|
|
739
|
+
fireAt: fireAtOf(request.fireAt, clock.now()),
|
|
740
|
+
maxAttempts: request.maxAttempts ?? null,
|
|
741
|
+
input: request.input,
|
|
742
|
+
});
|
|
176
743
|
return {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
status:
|
|
180
|
-
|
|
744
|
+
outcome: 'pending',
|
|
745
|
+
requestId: created.id,
|
|
746
|
+
status: 'pending',
|
|
747
|
+
runId: null,
|
|
748
|
+
inputId: null,
|
|
181
749
|
};
|
|
182
750
|
}
|
|
183
|
-
|
|
751
|
+
// As the responsible when they caused it; as the source when they run it as themselves (`mine`); as whoever
|
|
752
|
+
// woke the agent when nobody answers for the subject.
|
|
753
|
+
const actorUserId = (commentExecution === 'requester'
|
|
754
|
+
? inherited?.actorUserId
|
|
755
|
+
: identity?.actorUserId) ??
|
|
756
|
+
(foreign ? source : (responsible ?? request.actorUserId ?? source));
|
|
757
|
+
const agent = await requireInvocable(unit, request.agentId, actorUserId);
|
|
758
|
+
if (foreign)
|
|
759
|
+
await requireRunnerFor(unit, agent, actorUserId, request.requires ?? []);
|
|
760
|
+
const result = await queue(unit, agent, {
|
|
761
|
+
preferActive: request.preferActive,
|
|
762
|
+
sourceRunId: request.causedByRunId,
|
|
763
|
+
commentRootRunId,
|
|
764
|
+
commentExecution,
|
|
765
|
+
commentOwnerKey,
|
|
766
|
+
freshSession: request.freshSession,
|
|
184
767
|
subject: request.subject,
|
|
185
|
-
threadScope
|
|
186
|
-
actorUserId
|
|
187
|
-
|
|
768
|
+
threadScope,
|
|
769
|
+
actorUserId,
|
|
770
|
+
requestedByUserId: source,
|
|
771
|
+
confirmedByUserId: inherited?.confirmedByUserId ?? null,
|
|
772
|
+
ownerUserId: commentExecution === 'requester'
|
|
773
|
+
? (inherited?.ownerUserId ?? request.ownerUserId ?? null)
|
|
774
|
+
: identity
|
|
775
|
+
? actorUserId
|
|
776
|
+
: (request.ownerUserId ?? null),
|
|
188
777
|
priority: request.priority ?? 0,
|
|
778
|
+
fireAt: fireAtOf(request.fireAt, clock.now()),
|
|
189
779
|
requires: request.requires ?? [],
|
|
190
|
-
retryOfRunId: null,
|
|
191
|
-
availableAt: fireAt,
|
|
192
780
|
...(request.parentRunId ? { parentRunId: request.parentRunId } : {}),
|
|
193
781
|
...(request.maxAttempts ? { maxAttempts: request.maxAttempts } : {}),
|
|
782
|
+
input: request.input,
|
|
194
783
|
});
|
|
195
|
-
|
|
196
|
-
|
|
784
|
+
if (commentRootRunId !== null)
|
|
785
|
+
await deps.reconcileCommentConsent?.(unit, result.runId);
|
|
786
|
+
return result;
|
|
197
787
|
}, outer),
|
|
788
|
+
requests,
|
|
789
|
+
identityInputs: async (conn, runId) => {
|
|
790
|
+
const run = await findRunRecord(conn, runId);
|
|
791
|
+
if (!run)
|
|
792
|
+
return null;
|
|
793
|
+
const inputs = await inputsRepo(conn).findMany({ filter: { runId } });
|
|
794
|
+
return { run: toRun(run), inputs: inputs.map(toInput) };
|
|
795
|
+
},
|
|
198
796
|
addInput: (runId, input, outer) => tx.run(async (unit) => {
|
|
199
797
|
const run = await require(unit.conn, runId);
|
|
798
|
+
if (run.commentRootRunId &&
|
|
799
|
+
input.type === 'comment' &&
|
|
800
|
+
jsonObject(input.payload).commentRootRunId !== run.commentRootRunId)
|
|
801
|
+
throw forbidden('A comment must be queued in its own authorized run chain.');
|
|
200
802
|
if (isTerminal(run.status))
|
|
201
803
|
throw new ProtocolError('RUN_NOT_ACTIVE', `The run is ${run.status}.`);
|
|
804
|
+
if (isActive(run.status)) {
|
|
805
|
+
let current = run;
|
|
806
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
807
|
+
const updated = await runsRepo(unit.conn).updateMany({
|
|
808
|
+
filter: {
|
|
809
|
+
id: current.id,
|
|
810
|
+
status: current.status,
|
|
811
|
+
revision: current.revision,
|
|
812
|
+
},
|
|
813
|
+
values: { updatedAt: clock.now().toISOString() },
|
|
814
|
+
});
|
|
815
|
+
if (updated.updatedCount === 1)
|
|
816
|
+
return insertInput(unit, current.id, input);
|
|
817
|
+
current = await require(unit.conn, run.id);
|
|
818
|
+
if (!isActive(current.status))
|
|
819
|
+
throw conflict('The run moved on before input was appended.');
|
|
820
|
+
}
|
|
821
|
+
throw conflict('The run revision changed during append; retry the input.');
|
|
822
|
+
}
|
|
202
823
|
return insertInput(unit, run.id, input);
|
|
203
824
|
}, outer),
|
|
204
825
|
cancel: (runId, byUserId, outer) => tx.run(async (unit) => {
|
|
@@ -263,44 +884,192 @@ export function createRunService(deps) {
|
|
|
263
884
|
}
|
|
264
885
|
return ended;
|
|
265
886
|
}, outer),
|
|
266
|
-
retry: (runId, byUserId
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
887
|
+
retry: async (runId, byUserId, source = 'api') => {
|
|
888
|
+
const target = await require(tx.read(), runId);
|
|
889
|
+
// Resolve collection metadata outside the transaction too. The lock must
|
|
890
|
+
// precede consistent reads so repeatable-read databases see a concurrent
|
|
891
|
+
// retry that committed while this request waited for the lock.
|
|
892
|
+
await findAgent(tx.read(), target.agentId);
|
|
893
|
+
return tx.run(async (unit) => {
|
|
894
|
+
await lockAgentForClaim(unit.conn, target.agentId, clock.now().toISOString());
|
|
895
|
+
const run = await require(unit.conn, runId);
|
|
896
|
+
if (run.status !== 'failed' && run.status !== 'cancelled')
|
|
897
|
+
throw precondition('RUN_NOT_RETRYABLE', 'Only a failed or cancelled run can be retried.');
|
|
898
|
+
if (run.parentRunId)
|
|
899
|
+
throw precondition('RUN_NOT_RETRYABLE', 'A consultation is not retried: the agent that asked asks again.');
|
|
900
|
+
// The agent lock serializes retry and enqueue across server instances. Check
|
|
901
|
+
// the relationship even after the replacement has already ended.
|
|
902
|
+
const retried = await runsRepo(unit.conn).findOne({
|
|
903
|
+
filter: { retryOfRunId: run.id },
|
|
904
|
+
sort: (sort) => [
|
|
905
|
+
sort.field('createdAt').asc(),
|
|
906
|
+
sort.field('id').asc(),
|
|
907
|
+
],
|
|
278
908
|
});
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
909
|
+
if (retried)
|
|
910
|
+
throw precondition('RUN_ALREADY_RETRIED', 'This run has already been retried.', {
|
|
911
|
+
runId: retried.id,
|
|
912
|
+
});
|
|
913
|
+
const previousInputs = await inputsRepo(unit.conn).findMany({
|
|
914
|
+
filter: { runId: run.id },
|
|
915
|
+
});
|
|
916
|
+
if (!run.commentRootRunId &&
|
|
917
|
+
deps.subjects.get(run.subjectKind)?.commentOwnerKey &&
|
|
918
|
+
previousInputs.some((input) => input.type === 'comment' &&
|
|
919
|
+
!(input.actorKind === 'user' &&
|
|
920
|
+
input.actorId === run.ownerUserId &&
|
|
921
|
+
jsonObject(input.payload).byAgent !== true)))
|
|
922
|
+
throw precondition('RUN_NOT_RETRYABLE', 'Post the comment again to start a new authorized comment chain.');
|
|
923
|
+
const oldRoot = run.commentRootRunId
|
|
924
|
+
? await findRunRecord(unit.conn, run.commentRootRunId)
|
|
925
|
+
: null;
|
|
926
|
+
const renewComment = oldRoot
|
|
927
|
+
? !(await currentCommentOwner(unit.conn, deps.subjects, oldRoot))
|
|
928
|
+
: false;
|
|
929
|
+
const commentExecution = renewComment &&
|
|
930
|
+
run.commentExecution === 'requester' &&
|
|
931
|
+
byUserId !== run.actorUserId
|
|
932
|
+
? 'owner'
|
|
933
|
+
: run.commentExecution;
|
|
934
|
+
const identity = await deps.subjects
|
|
935
|
+
.get(run.subjectKind)
|
|
936
|
+
?.actsAs?.(unit.conn, {
|
|
937
|
+
subjectId: run.subjectId,
|
|
938
|
+
agentId: run.agentId,
|
|
939
|
+
inputs: previousInputs.map(toInput),
|
|
940
|
+
causedByRunId: run.retryOfRunId ?? undefined,
|
|
941
|
+
commentExecution,
|
|
942
|
+
actorUserId: run.actorUserId,
|
|
943
|
+
});
|
|
944
|
+
if (identity && !identity.actorUserId)
|
|
945
|
+
throw forbidden(identity.reason ?? 'noOwner');
|
|
946
|
+
const actorUserId = commentExecution === 'requester'
|
|
947
|
+
? run.actorUserId
|
|
948
|
+
: (identity?.actorUserId ?? byUserId);
|
|
949
|
+
const agent = await requireInvocable(unit, run.agentId, actorUserId);
|
|
950
|
+
const open = await runsOfKey(unit.conn, run, ['queued', ...ACTIVE], actorUserId);
|
|
951
|
+
const sameChain = run.commentRootRunId
|
|
952
|
+
? open.filter((candidate) => candidate.commentRootRunId === run.commentRootRunId)
|
|
953
|
+
: open;
|
|
954
|
+
if (sameChain.length > 0)
|
|
955
|
+
throw precondition('AGENT_BUSY', 'The agent is already working on this.', {
|
|
956
|
+
runId: sameChain[0].id,
|
|
957
|
+
});
|
|
958
|
+
const newId = await createRun(unit, agent, {
|
|
959
|
+
subject: { kind: run.subjectKind, id: run.subjectId },
|
|
960
|
+
threadScope: run.threadScope,
|
|
961
|
+
actorUserId,
|
|
962
|
+
commentRootRunId: renewComment ? '' : run.commentRootRunId,
|
|
963
|
+
commentExecution,
|
|
964
|
+
commentOwnerKey: renewComment
|
|
965
|
+
? ((await deps.subjects
|
|
966
|
+
.get(run.subjectKind)
|
|
967
|
+
?.commentOwnerKey?.(unit.conn, run.subjectId)) ?? null)
|
|
968
|
+
: run.commentOwnerKey,
|
|
969
|
+
requestedByUserId: run.commentRootRunId
|
|
970
|
+
? (run.requestedByUserId ?? run.actorUserId)
|
|
971
|
+
: byUserId,
|
|
972
|
+
confirmedByUserId: null,
|
|
973
|
+
ownerUserId: run.commentRootRunId
|
|
974
|
+
? ((await deps.subjects
|
|
975
|
+
.get(run.subjectKind)
|
|
976
|
+
?.responsibleUserId?.(unit.conn, run.subjectId)) ?? null)
|
|
977
|
+
: identity
|
|
978
|
+
? actorUserId
|
|
979
|
+
: run.ownerUserId,
|
|
980
|
+
priority: Number(run.priority),
|
|
981
|
+
requires: toRun(run).requires,
|
|
982
|
+
retryOfRunId: run.id,
|
|
983
|
+
freshSession: run.freshSession,
|
|
984
|
+
});
|
|
985
|
+
if (renewComment && oldRoot) {
|
|
986
|
+
const origins = await inputsRepo(unit.conn).findMany({
|
|
987
|
+
filter: { runId: oldRoot.id },
|
|
988
|
+
sort: (s) => [s.field('createdAt').asc(), s.field('id').asc()],
|
|
989
|
+
});
|
|
990
|
+
const origin = origins.find((input) => input.type === 'comment' &&
|
|
991
|
+
jsonObject(input.payload).commentSourceSnapshot === true) ?? origins.find((input) => input.type === 'comment');
|
|
992
|
+
if (origin) {
|
|
993
|
+
const snapshotId = await insertInput(unit, newId, {
|
|
994
|
+
type: 'comment',
|
|
995
|
+
actor: toInput(origin).actor,
|
|
996
|
+
text: origin.text,
|
|
997
|
+
payload: {
|
|
998
|
+
...jsonObject(origin.payload),
|
|
999
|
+
commentRootRunId: newId,
|
|
1000
|
+
commentSourceSnapshot: true,
|
|
1001
|
+
},
|
|
1002
|
+
});
|
|
1003
|
+
await inputsRepo(unit.conn).updateMany({
|
|
1004
|
+
filter: { id: snapshotId },
|
|
1005
|
+
values: { handledAt: clock.now().toISOString() },
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
for (const input of await pendingInputs(unit.conn, run.id))
|
|
1010
|
+
await insertInput(unit, newId, {
|
|
1011
|
+
type: input.type,
|
|
1012
|
+
actor: toInput(input).actor,
|
|
1013
|
+
text: input.text,
|
|
1014
|
+
...(input.payload === null
|
|
1015
|
+
? {}
|
|
1016
|
+
: {
|
|
1017
|
+
payload: {
|
|
1018
|
+
...jsonObject(input.payload),
|
|
1019
|
+
...(renewComment ? { commentRootRunId: newId } : {}),
|
|
1020
|
+
},
|
|
1021
|
+
}),
|
|
1022
|
+
});
|
|
289
1023
|
await insertInput(unit, newId, {
|
|
290
|
-
type:
|
|
291
|
-
actor:
|
|
292
|
-
|
|
293
|
-
|
|
1024
|
+
type: 'retry',
|
|
1025
|
+
actor: {
|
|
1026
|
+
kind: 'user',
|
|
1027
|
+
id: byUserId,
|
|
1028
|
+
name: (await deps.people.names(unit.conn, [byUserId])).get(byUserId) ??
|
|
1029
|
+
byUserId,
|
|
1030
|
+
},
|
|
1031
|
+
text: 'Retry the work of the previous run.',
|
|
1032
|
+
payload: {
|
|
1033
|
+
retryOfRunId: run.id,
|
|
1034
|
+
failureReason: run.failureReason,
|
|
1035
|
+
source,
|
|
1036
|
+
},
|
|
1037
|
+
});
|
|
1038
|
+
unit.emit({
|
|
1039
|
+
type: 'run.retried',
|
|
1040
|
+
runId: newId,
|
|
1041
|
+
retryOfRunId: run.id,
|
|
1042
|
+
previousStatus: run.status,
|
|
294
1043
|
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
text: 'Retry the work of the previous run.',
|
|
299
|
-
payload: { retryOfRunId: run.id, failureReason: run.failureReason },
|
|
1044
|
+
if (run.commentRootRunId)
|
|
1045
|
+
await deps.reconcileCommentConsent?.(unit, newId);
|
|
1046
|
+
return toRun(await require(unit.conn, newId));
|
|
300
1047
|
});
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
1048
|
+
},
|
|
1049
|
+
get: async (runId) => (await readRuns([await require(tx.read(), runId)]))[0],
|
|
1050
|
+
async retryInfo(runId) {
|
|
1051
|
+
const conn = tx.read();
|
|
1052
|
+
const next = await runsRepo(conn).findOne({
|
|
1053
|
+
filter: { retryOfRunId: runId },
|
|
1054
|
+
sort: (sort) => [sort.field('createdAt').asc(), sort.field('id').asc()],
|
|
1055
|
+
});
|
|
1056
|
+
if (!next)
|
|
1057
|
+
return null;
|
|
1058
|
+
const input = await inputsRepo(conn).findOne({
|
|
1059
|
+
filter: { runId: next.id, type: 'retry' },
|
|
1060
|
+
sort: (sort) => [
|
|
1061
|
+
sort.field('createdAt').desc(),
|
|
1062
|
+
sort.field('id').desc(),
|
|
1063
|
+
],
|
|
1064
|
+
});
|
|
1065
|
+
const source = input?.payload?.source;
|
|
1066
|
+
return {
|
|
1067
|
+
runId: next.id,
|
|
1068
|
+
actorUserId: next.actorUserId,
|
|
1069
|
+
actorName: input ? toInputView(input).actor.name : next.actorUserId,
|
|
1070
|
+
source: typeof source === 'string' ? source : 'unknown',
|
|
1071
|
+
};
|
|
1072
|
+
},
|
|
304
1073
|
async detail(runId) {
|
|
305
1074
|
const conn = tx.read();
|
|
306
1075
|
const run = await require(conn, runId);
|
|
@@ -309,17 +1078,39 @@ export function createRunService(deps) {
|
|
|
309
1078
|
sort: (sort) => [sort.field('createdAt').asc(), sort.field('id').asc()],
|
|
310
1079
|
});
|
|
311
1080
|
const repos = await reposRepo(conn).findMany({ filter: { runId } });
|
|
1081
|
+
const retried = await runsRepo(conn).findOne({
|
|
1082
|
+
filter: { retryOfRunId: runId },
|
|
1083
|
+
sort: (sort) => [sort.field('createdAt').asc(), sort.field('id').asc()],
|
|
1084
|
+
});
|
|
312
1085
|
const children = await runsRepo(conn).findMany({
|
|
313
1086
|
filter: { parentRunId: runId },
|
|
314
1087
|
sort: (sort) => [sort.field('createdAt').asc(), sort.field('id').asc()],
|
|
315
1088
|
});
|
|
316
|
-
const names =
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
1089
|
+
const names = await agentNamesOf(conn, [
|
|
1090
|
+
...children.map((child) => child.agentId),
|
|
1091
|
+
...inputs.flatMap((input) => input.actorKind === 'agent' && input.actorId ? [input.actorId] : []),
|
|
1092
|
+
]);
|
|
320
1093
|
return {
|
|
321
|
-
...
|
|
322
|
-
|
|
1094
|
+
...(await readRuns([run]))[0],
|
|
1095
|
+
actorName: (await deps.people.names(conn, [run.actorUserId])).get(run.actorUserId) ?? run.actorUserId,
|
|
1096
|
+
confirmedByName: run.confirmedByUserId
|
|
1097
|
+
? ((await deps.people.names(conn, [run.confirmedByUserId])).get(run.confirmedByUserId) ?? run.confirmedByUserId)
|
|
1098
|
+
: undefined,
|
|
1099
|
+
requestedByName: (await deps.people.names(conn, [
|
|
1100
|
+
run.requestedByUserId ?? run.actorUserId,
|
|
1101
|
+
])).get(run.requestedByUserId ?? run.actorUserId) ??
|
|
1102
|
+
run.requestedByUserId ??
|
|
1103
|
+
run.actorUserId,
|
|
1104
|
+
retriedRunId: retried?.id ?? null,
|
|
1105
|
+
inputs: inputs.map((input) => {
|
|
1106
|
+
const view = toInputView(input);
|
|
1107
|
+
const name = view.actor.kind === 'agent' && view.actor.id
|
|
1108
|
+
? names.get(view.actor.id)
|
|
1109
|
+
: undefined;
|
|
1110
|
+
return name === undefined
|
|
1111
|
+
? view
|
|
1112
|
+
: { ...view, actor: { ...view.actor, name } };
|
|
1113
|
+
}),
|
|
323
1114
|
repos: repos.map(toRepo),
|
|
324
1115
|
usage: await usageOf(conn, runId),
|
|
325
1116
|
children: children.map((child) => ({
|
|
@@ -361,7 +1152,7 @@ export function createRunService(deps) {
|
|
|
361
1152
|
limit: Math.min(Math.max(filter.limit ?? 50, 1), 200),
|
|
362
1153
|
...(filter.cursor ? { cursor: filter.cursor } : {}),
|
|
363
1154
|
});
|
|
364
|
-
return records
|
|
1155
|
+
return readRuns(records);
|
|
365
1156
|
},
|
|
366
1157
|
async lastEnded(subjectKind, subjectIds) {
|
|
367
1158
|
if (subjectIds.length === 0)
|
|
@@ -383,16 +1174,44 @@ export function createRunService(deps) {
|
|
|
383
1174
|
if (!newest.has(key))
|
|
384
1175
|
newest.set(key, record);
|
|
385
1176
|
}
|
|
386
|
-
return [...newest.values()]
|
|
1177
|
+
return readRuns([...newest.values()]);
|
|
1178
|
+
},
|
|
1179
|
+
async workingOn(subjectKind, subjectIds) {
|
|
1180
|
+
const ids = [...new Set(subjectIds)];
|
|
1181
|
+
if (ids.length === 0)
|
|
1182
|
+
return [];
|
|
1183
|
+
const records = await runsRepo(tx.read()).findMany({
|
|
1184
|
+
select: (select) => select.fields('subjectId', 'agentId'),
|
|
1185
|
+
filter: (f) => f.and([
|
|
1186
|
+
f.string('subjectKind').eq(subjectKind),
|
|
1187
|
+
f.or(ids.map((id) => f.string('subjectId').eq(id))),
|
|
1188
|
+
f.or(['dispatched', 'running'].map((status) => f.string('status').eq(status))),
|
|
1189
|
+
]),
|
|
1190
|
+
});
|
|
1191
|
+
const pairs = new Map();
|
|
1192
|
+
for (const record of records) {
|
|
1193
|
+
pairs.set(JSON.stringify([record.subjectId, record.agentId]), {
|
|
1194
|
+
subjectId: record.subjectId,
|
|
1195
|
+
agentId: record.agentId,
|
|
1196
|
+
working: true,
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
return [...pairs.values()];
|
|
387
1200
|
},
|
|
388
1201
|
workload(query) {
|
|
389
|
-
return readWorkload(tx.read(), clock, deps.runners, query);
|
|
1202
|
+
return readWorkload(tx.read(), clock, deps.runners, query, deps.diagnose);
|
|
390
1203
|
},
|
|
391
|
-
async events(runId, afterSeq, limit) {
|
|
1204
|
+
async events(runId, afterSeq, limit, types) {
|
|
392
1205
|
const conn = tx.read();
|
|
393
1206
|
await require(conn, runId);
|
|
394
1207
|
const rows = await eventsRepo(conn).findMany({
|
|
395
|
-
filter: (f) => f.and([
|
|
1208
|
+
filter: (f) => f.and([
|
|
1209
|
+
f.string('runId').eq(runId),
|
|
1210
|
+
f.number('seq').gt(afterSeq),
|
|
1211
|
+
...(types?.length
|
|
1212
|
+
? [f.or(types.map((type) => f.string('type').eq(type)))]
|
|
1213
|
+
: []),
|
|
1214
|
+
]),
|
|
396
1215
|
sort: (sort) => sort.field('seq').asc(),
|
|
397
1216
|
limit: Math.min(Math.max(limit, 1), 1000),
|
|
398
1217
|
});
|
|
@@ -416,7 +1235,16 @@ export function createRunService(deps) {
|
|
|
416
1235
|
lastSeq: events.length > 0 ? events[events.length - 1].seq : afterSeq,
|
|
417
1236
|
};
|
|
418
1237
|
},
|
|
419
|
-
authenticateToken: (value) =>
|
|
1238
|
+
authenticateToken: async (value) => {
|
|
1239
|
+
const conn = tx.read();
|
|
1240
|
+
const identity = await authenticateRunToken(conn, clock, value);
|
|
1241
|
+
if (identity.run.commentRootRunId) {
|
|
1242
|
+
const root = await findRunRecord(conn, identity.run.commentRootRunId);
|
|
1243
|
+
if (!root || !(await currentCommentOwner(conn, deps.subjects, root)))
|
|
1244
|
+
throw precondition('RUN_TOKEN_INVALID', 'The comment authorization belongs to an earlier owner assignment.');
|
|
1245
|
+
}
|
|
1246
|
+
return identity;
|
|
1247
|
+
},
|
|
420
1248
|
async self({ run }) {
|
|
421
1249
|
const conn = tx.read();
|
|
422
1250
|
const agent = await findAgent(conn, run.agentId);
|
|
@@ -428,7 +1256,8 @@ export function createRunService(deps) {
|
|
|
428
1256
|
subjectRef: { kind: run.subjectKind, id: run.subjectId },
|
|
429
1257
|
actorUserId: run.actorUserId,
|
|
430
1258
|
cancelRequested: run.cancelRequestedAt !== null,
|
|
431
|
-
|
|
1259
|
+
// What the run may act on: a read never withholds anything, it only leaves out what delivery would.
|
|
1260
|
+
inputs: (await gatePending(conn, deps, run)).kept.map(toInput),
|
|
432
1261
|
};
|
|
433
1262
|
},
|
|
434
1263
|
async brief(runId) {
|
|
@@ -444,14 +1273,10 @@ export function createRunService(deps) {
|
|
|
444
1273
|
const conn = tx.read();
|
|
445
1274
|
const binding = deps.subjects.get(run.subjectKind);
|
|
446
1275
|
const agent = await findAgent(conn, run.agentId);
|
|
447
|
-
|
|
448
|
-
const runner = run.runnerId && agent?.type === 'runner'
|
|
1276
|
+
const runner = run.runnerId
|
|
449
1277
|
? await deps.runners.find(conn, run.runnerId)
|
|
450
1278
|
: null;
|
|
451
|
-
if (!binding ||
|
|
452
|
-
!agent ||
|
|
453
|
-
(agent.type === 'runner' && !runner) ||
|
|
454
|
-
!isActive(run.status))
|
|
1279
|
+
if (!binding || !agent || !runner || !isActive(run.status))
|
|
455
1280
|
throw notFound('Run context');
|
|
456
1281
|
const assembly = await binding.context.assemble(conn, {
|
|
457
1282
|
run: toRun(run),
|
|
@@ -460,11 +1285,11 @@ export function createRunService(deps) {
|
|
|
460
1285
|
inputs: (await pendingInputs(conn, run.id)).map(toInput),
|
|
461
1286
|
cli: deps.cliName,
|
|
462
1287
|
appName: deps.appName,
|
|
463
|
-
|
|
464
|
-
});
|
|
1288
|
+
}, await binding.context.prepare?.(toRun(run)));
|
|
465
1289
|
return assembly.data;
|
|
466
1290
|
},
|
|
467
1291
|
openOn: openRunsOn,
|
|
1292
|
+
openOnEach: openRunsOnEach,
|
|
468
1293
|
pendingInputs: async (conn, runId) => (await pendingInputs(conn, runId)).map(toInput),
|
|
469
1294
|
inputsSince: inputsOnSince,
|
|
470
1295
|
lastSummary,
|