@desplega.ai/agent-swarm 1.93.0 → 1.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/openapi.json +180 -1
- package/package.json +4 -3
- package/src/be/db.ts +74 -9
- package/src/be/migrations/090_model_tiers.sql +2 -0
- package/src/be/migrations/091_seed_swarm_operations_metrics.sql +12 -0
- package/src/be/migrations/092_metrics_dashboard_combobox_filters.sql +68 -0
- package/src/be/migrations/093_slack_message_tracking.sql +6 -0
- package/src/be/migrations/094_mcp_extra_authorize_params.sql +4 -0
- package/src/be/migrations/runner.ts +52 -0
- package/src/be/modelsdev-cache.json +2060 -198
- package/src/be/scripts/boot-reembed.ts +74 -0
- package/src/be/scripts/db.ts +19 -3
- package/src/be/seed/index.ts +1 -1
- package/src/be/seed/registry.ts +2 -2
- package/src/be/seed/runner.ts +5 -5
- package/src/be/seed/types.ts +6 -1
- package/src/be/seed-pricing.ts +1 -0
- package/src/be/seed-scripts/index.ts +3 -2
- package/src/be/skill-sync.ts +4 -4
- package/src/be/swarm-config-guard.ts +8 -0
- package/src/commands/provider-credentials.ts +14 -8
- package/src/commands/runner.ts +84 -13
- package/src/http/index.ts +13 -2
- package/src/http/mcp-oauth.ts +14 -0
- package/src/http/metrics.ts +55 -6
- package/src/http/schedules.ts +16 -15
- package/src/http/script-runs.ts +7 -1
- package/src/http/scripts.ts +147 -1
- package/src/http/tasks.ts +7 -0
- package/src/model-tiers.ts +140 -0
- package/src/oauth/mcp-wrapper.ts +14 -0
- package/src/providers/claude-managed-models.ts +9 -0
- package/src/providers/codex-skill-resolver.ts +22 -8
- package/src/providers/opencode-adapter.ts +21 -2
- package/src/providers/pi-mono-adapter.ts +143 -26
- package/src/providers/types.ts +12 -0
- package/src/scheduler/scheduler.ts +22 -34
- package/src/server-user.ts +8 -2
- package/src/slack/responses.ts +39 -11
- package/src/slack/watcher.ts +121 -8
- package/src/tests/agents-list-model-display.test.ts +13 -0
- package/src/tests/aws-error-classifier.test.ts +148 -0
- package/src/tests/claude-managed-adapter.test.ts +12 -0
- package/src/tests/context-window.test.ts +7 -0
- package/src/tests/credential-check.test.ts +185 -46
- package/src/tests/harness-provider-resolution.test.ts +23 -0
- package/src/tests/http-api-integration.test.ts +19 -0
- package/src/tests/mcp-oauth-queries.test.ts +71 -1
- package/src/tests/mcp-oauth-wrapper.test.ts +109 -0
- package/src/tests/metrics-http.test.ts +137 -3
- package/src/tests/migration-046-budgets.test.ts +33 -0
- package/src/tests/migration-runner-regressions.test.ts +69 -0
- package/src/tests/model-control.test.ts +162 -46
- package/src/tests/opencode-adapter.test.ts +38 -1
- package/src/tests/pi-mono-adapter.test.ts +319 -0
- package/src/tests/provider-command-format.test.ts +12 -0
- package/src/tests/providers/pi-cost.test.ts +9 -0
- package/src/tests/runner-fallback-output.test.ts +50 -0
- package/src/tests/scripts-boot-reembed.test.ts +163 -0
- package/src/tests/scripts-embeddings.test.ts +90 -0
- package/src/tests/seed.test.ts +26 -1
- package/src/tests/session-costs-model-key-normalize.test.ts +2 -0
- package/src/tests/skill-fs-writer.test.ts +7 -1
- package/src/tests/skill-sync.test.ts +15 -3
- package/src/tests/slack-watcher.test.ts +66 -0
- package/src/tests/workflow-agent-task.test.ts +5 -2
- package/src/tests/workflow-validation-port-routing.test.ts +181 -0
- package/src/tools/mcp-servers/mcp-server-create.ts +7 -0
- package/src/tools/mcp-servers/mcp-server-update.ts +8 -0
- package/src/tools/memory-get.ts +11 -0
- package/src/tools/memory-search.ts +18 -0
- package/src/tools/schedules/create-schedule.ts +71 -70
- package/src/tools/schedules/update-schedule.ts +43 -31
- package/src/tools/send-task.ts +16 -5
- package/src/tools/task-action.ts +11 -3
- package/src/types.ts +30 -0
- package/src/utils/aws-error-classifier.ts +97 -0
- package/src/utils/context-window.ts +2 -0
- package/src/utils/credentials.test.ts +68 -0
- package/src/utils/credentials.ts +44 -3
- package/src/utils/pretty-print.ts +25 -10
- package/src/utils/skill-fs-writer.ts +11 -3
- package/src/workflows/engine.ts +3 -2
- package/src/workflows/executors/agent-task.ts +3 -1
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
|
|
47
47
|
## What it does
|
|
48
48
|
|
|
49
|
-
Agent Swarm runs a team of AI agents that coordinate autonomously. A **lead agent** receives tasks (
|
|
49
|
+
Agent Swarm runs a team of AI agents that coordinate autonomously. A **lead agent** receives tasks (from Slack, GitHub, GitLab, Linear, Jira, email, or the API), breaks them down, and delegates to **worker agents** running in isolated environments (Docker). Workers execute tasks, ship solutions, and write their learnings back to a shared memory so the whole swarm gets smarter every session.
|
|
50
50
|
|
|
51
51
|
You can run agents for Marketing, Product, UX, Engineering, Support, Operations, HR, Finance, or any role you can think of. A centralized Lead coordinates them, and they share the learnings horizontally. That's the true difference between [*AI First*](https://www.pleasedontdeploy.com/i/197193364/ai-first) and [*AI Native*](https://www.pleasedontdeploy.com/i/197193364/third-the-ai-native-metamorphosis).
|
|
52
52
|
|
|
@@ -127,7 +127,7 @@ Check [our templates](https://templates.agent-swarm.dev) for a quick start.
|
|
|
127
127
|
- **Workflow engine with Human-in-the-Loop** — DAG-based automation with approval gates, retries, and structured I/O. [Workflows →](https://docs.agent-swarm.dev/docs/concepts/workflows)
|
|
128
128
|
- **Scheduled & recurring tasks** — cron-based automation for standing work. [Scheduling →](https://docs.agent-swarm.dev/docs/concepts/scheduling)
|
|
129
129
|
- **Durable script workflows** — launch background script runs, inspect their journals, and track them from the dashboard when a one-shot `script-run` is too small. [Guide →](https://docs.agent-swarm.dev/docs/guides/script-workflow-runs)
|
|
130
|
-
- **Harness & LLM agnostic** — run with Claude Code, Claude Bridge, OpenAI Codex, pi-mono, Devin, Claude Managed Agents, raw LLMs, or opencode. [Harness config →](https://docs.agent-swarm.dev/docs/guides/harness-configuration) · [Add a new provider →](https://docs.agent-swarm.dev/docs/guides/harness-providers)
|
|
130
|
+
- **Harness & LLM agnostic** — run with Claude Code, Claude Bridge, OpenAI Codex, pi-mono, Devin, Claude Managed Agents, raw LLMs, or opencode. Tasks, schedules, and workflow agent-task nodes can use portable `modelTier` intent (`smol`, `regular`, `smart`, `ultra`) and resolve it per worker/provider at run time. [Harness config →](https://docs.agent-swarm.dev/docs/guides/harness-configuration) · [Add a new provider →](https://docs.agent-swarm.dev/docs/guides/harness-providers)
|
|
131
131
|
- **Follow-up continuity across all harnesses** — child tasks inherit a bounded prior-task context preamble built from the task chain, so continuity survives restarts and works the same across every provider. [Task lifecycle →](https://docs.agent-swarm.dev/docs/concepts/task-lifecycle)
|
|
132
132
|
- **Skills & MCP servers** — reusable procedural knowledge, bundled skill reference files, and per-agent MCP servers with scope cascade. [MCP tools →](https://docs.agent-swarm.dev/docs/reference/mcp-tools)
|
|
133
133
|
- **External tool-router access** — the `x` command and `swarm_x` MCP tool let humans and agents execute approved third-party routes such as Composio without baking bespoke MCP servers first. [CLI →](https://docs.agent-swarm.dev/docs/reference/cli) · [Composio →](https://docs.agent-swarm.dev/docs/integrations/composio)
|
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.95.0",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
@@ -6894,6 +6894,15 @@
|
|
|
6894
6894
|
"model": {
|
|
6895
6895
|
"type": "string"
|
|
6896
6896
|
},
|
|
6897
|
+
"modelTier": {
|
|
6898
|
+
"type": "string",
|
|
6899
|
+
"enum": [
|
|
6900
|
+
"smol",
|
|
6901
|
+
"regular",
|
|
6902
|
+
"smart",
|
|
6903
|
+
"ultra"
|
|
6904
|
+
]
|
|
6905
|
+
},
|
|
6897
6906
|
"scheduleType": {
|
|
6898
6907
|
"type": "string",
|
|
6899
6908
|
"enum": [
|
|
@@ -7141,6 +7150,19 @@
|
|
|
7141
7150
|
"model": {
|
|
7142
7151
|
"type": "string"
|
|
7143
7152
|
},
|
|
7153
|
+
"modelTier": {
|
|
7154
|
+
"type": [
|
|
7155
|
+
"string",
|
|
7156
|
+
"null"
|
|
7157
|
+
],
|
|
7158
|
+
"enum": [
|
|
7159
|
+
"smol",
|
|
7160
|
+
"regular",
|
|
7161
|
+
"smart",
|
|
7162
|
+
"ultra",
|
|
7163
|
+
null
|
|
7164
|
+
]
|
|
7165
|
+
},
|
|
7144
7166
|
"nextRunAt": {
|
|
7145
7167
|
"type": [
|
|
7146
7168
|
"string",
|
|
@@ -7297,6 +7319,14 @@
|
|
|
7297
7319
|
"name": "agentId",
|
|
7298
7320
|
"in": "query"
|
|
7299
7321
|
},
|
|
7322
|
+
{
|
|
7323
|
+
"schema": {
|
|
7324
|
+
"type": "string"
|
|
7325
|
+
},
|
|
7326
|
+
"required": false,
|
|
7327
|
+
"name": "scriptName",
|
|
7328
|
+
"in": "query"
|
|
7329
|
+
},
|
|
7300
7330
|
{
|
|
7301
7331
|
"schema": {
|
|
7302
7332
|
"type": "integer",
|
|
@@ -9249,6 +9279,143 @@
|
|
|
9249
9279
|
}
|
|
9250
9280
|
}
|
|
9251
9281
|
},
|
|
9282
|
+
"/api/scripts": {
|
|
9283
|
+
"get": {
|
|
9284
|
+
"operationId": "scripts_list",
|
|
9285
|
+
"summary": "List saved scripts",
|
|
9286
|
+
"description": "Dashboard read: lean projection without source. Scratch scripts are excluded unless includeScratch=true.",
|
|
9287
|
+
"tags": [
|
|
9288
|
+
"Scripts"
|
|
9289
|
+
],
|
|
9290
|
+
"security": [
|
|
9291
|
+
{
|
|
9292
|
+
"bearerAuth": []
|
|
9293
|
+
}
|
|
9294
|
+
],
|
|
9295
|
+
"parameters": [
|
|
9296
|
+
{
|
|
9297
|
+
"schema": {
|
|
9298
|
+
"type": "string",
|
|
9299
|
+
"enum": [
|
|
9300
|
+
"global",
|
|
9301
|
+
"agent"
|
|
9302
|
+
]
|
|
9303
|
+
},
|
|
9304
|
+
"required": false,
|
|
9305
|
+
"name": "scope",
|
|
9306
|
+
"in": "query"
|
|
9307
|
+
},
|
|
9308
|
+
{
|
|
9309
|
+
"schema": {
|
|
9310
|
+
"type": "string",
|
|
9311
|
+
"enum": [
|
|
9312
|
+
"true",
|
|
9313
|
+
"false"
|
|
9314
|
+
]
|
|
9315
|
+
},
|
|
9316
|
+
"required": false,
|
|
9317
|
+
"name": "includeScratch",
|
|
9318
|
+
"in": "query"
|
|
9319
|
+
}
|
|
9320
|
+
],
|
|
9321
|
+
"responses": {
|
|
9322
|
+
"200": {
|
|
9323
|
+
"description": "Saved scripts"
|
|
9324
|
+
},
|
|
9325
|
+
"400": {
|
|
9326
|
+
"description": "Validation error"
|
|
9327
|
+
}
|
|
9328
|
+
}
|
|
9329
|
+
}
|
|
9330
|
+
},
|
|
9331
|
+
"/api/scripts/type-defs": {
|
|
9332
|
+
"get": {
|
|
9333
|
+
"operationId": "scripts_type_defs",
|
|
9334
|
+
"summary": "Get script SDK and stdlib type definitions",
|
|
9335
|
+
"description": "Static .d.ts blobs for editor integration (e.g. Monaco extraLibs). Cacheable.",
|
|
9336
|
+
"tags": [
|
|
9337
|
+
"Scripts"
|
|
9338
|
+
],
|
|
9339
|
+
"security": [
|
|
9340
|
+
{
|
|
9341
|
+
"bearerAuth": []
|
|
9342
|
+
}
|
|
9343
|
+
],
|
|
9344
|
+
"responses": {
|
|
9345
|
+
"200": {
|
|
9346
|
+
"description": "SDK and stdlib type definition blobs"
|
|
9347
|
+
}
|
|
9348
|
+
}
|
|
9349
|
+
}
|
|
9350
|
+
},
|
|
9351
|
+
"/api/scripts/{id}": {
|
|
9352
|
+
"get": {
|
|
9353
|
+
"operationId": "scripts_get",
|
|
9354
|
+
"summary": "Get a saved script by id",
|
|
9355
|
+
"description": "Dashboard read: full record including source and parsed signature.",
|
|
9356
|
+
"tags": [
|
|
9357
|
+
"Scripts"
|
|
9358
|
+
],
|
|
9359
|
+
"security": [
|
|
9360
|
+
{
|
|
9361
|
+
"bearerAuth": []
|
|
9362
|
+
}
|
|
9363
|
+
],
|
|
9364
|
+
"parameters": [
|
|
9365
|
+
{
|
|
9366
|
+
"schema": {
|
|
9367
|
+
"type": "string",
|
|
9368
|
+
"format": "uuid"
|
|
9369
|
+
},
|
|
9370
|
+
"required": true,
|
|
9371
|
+
"name": "id",
|
|
9372
|
+
"in": "path"
|
|
9373
|
+
}
|
|
9374
|
+
],
|
|
9375
|
+
"responses": {
|
|
9376
|
+
"200": {
|
|
9377
|
+
"description": "Script detail"
|
|
9378
|
+
},
|
|
9379
|
+
"404": {
|
|
9380
|
+
"description": "Script not found"
|
|
9381
|
+
}
|
|
9382
|
+
}
|
|
9383
|
+
}
|
|
9384
|
+
},
|
|
9385
|
+
"/api/scripts/{id}/versions": {
|
|
9386
|
+
"get": {
|
|
9387
|
+
"operationId": "scripts_versions",
|
|
9388
|
+
"summary": "List versions of a saved script",
|
|
9389
|
+
"description": "Dashboard read: version history, newest first.",
|
|
9390
|
+
"tags": [
|
|
9391
|
+
"Scripts"
|
|
9392
|
+
],
|
|
9393
|
+
"security": [
|
|
9394
|
+
{
|
|
9395
|
+
"bearerAuth": []
|
|
9396
|
+
}
|
|
9397
|
+
],
|
|
9398
|
+
"parameters": [
|
|
9399
|
+
{
|
|
9400
|
+
"schema": {
|
|
9401
|
+
"type": "string",
|
|
9402
|
+
"format": "uuid"
|
|
9403
|
+
},
|
|
9404
|
+
"required": true,
|
|
9405
|
+
"name": "id",
|
|
9406
|
+
"in": "path"
|
|
9407
|
+
}
|
|
9408
|
+
],
|
|
9409
|
+
"responses": {
|
|
9410
|
+
"200": {
|
|
9411
|
+
"description": "Script versions"
|
|
9412
|
+
},
|
|
9413
|
+
"404": {
|
|
9414
|
+
"description": "Script not found"
|
|
9415
|
+
}
|
|
9416
|
+
}
|
|
9417
|
+
}
|
|
9418
|
+
},
|
|
9252
9419
|
"/api/mcp-bridge": {
|
|
9253
9420
|
"post": {
|
|
9254
9421
|
"summary": "Generic MCP tool proxy for the scripts SDK bridge",
|
|
@@ -10745,6 +10912,18 @@
|
|
|
10745
10912
|
},
|
|
10746
10913
|
"requestedByUserId": {
|
|
10747
10914
|
"type": "string"
|
|
10915
|
+
},
|
|
10916
|
+
"model": {
|
|
10917
|
+
"type": "string"
|
|
10918
|
+
},
|
|
10919
|
+
"modelTier": {
|
|
10920
|
+
"type": "string",
|
|
10921
|
+
"enum": [
|
|
10922
|
+
"smol",
|
|
10923
|
+
"regular",
|
|
10924
|
+
"smart",
|
|
10925
|
+
"ultra"
|
|
10926
|
+
]
|
|
10748
10927
|
}
|
|
10749
10928
|
},
|
|
10750
10929
|
"required": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.95.0",
|
|
4
4
|
"description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "desplega.sh <contact@desplega.sh>",
|
|
@@ -108,13 +108,14 @@
|
|
|
108
108
|
"@ai-sdk/openai": "^3.0.41",
|
|
109
109
|
"@anthropic-ai/sdk": "^0.93.0",
|
|
110
110
|
"@asteasolutions/zod-to-openapi": "^8.0.0",
|
|
111
|
+
"@aws-sdk/client-bedrock": "3.1048.0",
|
|
111
112
|
"@desplega.ai/business-use": "^0.4.2",
|
|
112
113
|
"@desplega.ai/localtunnel": "^2.2.0",
|
|
113
|
-
"@inkjs/ui": "^2.0.0",
|
|
114
|
-
"@linear/sdk": "^77.0.0",
|
|
115
114
|
"@earendil-works/pi-agent-core": "^0.79.1",
|
|
116
115
|
"@earendil-works/pi-ai": "^0.79.1",
|
|
117
116
|
"@earendil-works/pi-coding-agent": "^0.79.1",
|
|
117
|
+
"@inkjs/ui": "^2.0.0",
|
|
118
|
+
"@linear/sdk": "^77.0.0",
|
|
118
119
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
119
120
|
"@openai/codex-sdk": "^0.139.0",
|
|
120
121
|
"@opencode-ai/sdk": "^1.16.2",
|
package/src/be/db.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Database } from "bun:sqlite";
|
|
|
2
2
|
import { parseProviderMeta } from "@/utils/provider-metadata.ts";
|
|
3
3
|
import pkg from "../../package.json";
|
|
4
4
|
import { addEyesReactionOnTaskStart } from "../github/task-reactions";
|
|
5
|
+
import { type ModelTier, parseModelTier } from "../model-tiers";
|
|
5
6
|
import { configureDbResolver } from "../prompts/resolver";
|
|
6
7
|
import type {
|
|
7
8
|
ActiveSession,
|
|
@@ -1000,6 +1001,8 @@ type AgentTaskRow = {
|
|
|
1000
1001
|
slackThreadTs: string | null;
|
|
1001
1002
|
slackUserId: string | null;
|
|
1002
1003
|
slackReplySent: number;
|
|
1004
|
+
slackProgressMessageTs: string | null;
|
|
1005
|
+
slackTreeRootMessageTs: string | null;
|
|
1003
1006
|
vcsProvider: string | null;
|
|
1004
1007
|
vcsRepo: string | null;
|
|
1005
1008
|
vcsEventType: string | null;
|
|
@@ -1018,6 +1021,7 @@ type AgentTaskRow = {
|
|
|
1018
1021
|
parentTaskId: string | null;
|
|
1019
1022
|
claudeSessionId: string | null;
|
|
1020
1023
|
model: string | null;
|
|
1024
|
+
modelTier: string | null;
|
|
1021
1025
|
scheduleId: string | null;
|
|
1022
1026
|
workflowRunId: string | null;
|
|
1023
1027
|
workflowRunStepId: string | null;
|
|
@@ -1088,6 +1092,8 @@ function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
|
1088
1092
|
slackThreadTs: row.slackThreadTs ?? undefined,
|
|
1089
1093
|
slackUserId: row.slackUserId ?? undefined,
|
|
1090
1094
|
slackReplySent: !!row.slackReplySent,
|
|
1095
|
+
slackProgressMessageTs: row.slackProgressMessageTs ?? undefined,
|
|
1096
|
+
slackTreeRootMessageTs: row.slackTreeRootMessageTs ?? undefined,
|
|
1091
1097
|
vcsProvider: (row.vcsProvider as "github" | "gitlab" | null) ?? undefined,
|
|
1092
1098
|
vcsRepo: row.vcsRepo ?? undefined,
|
|
1093
1099
|
vcsEventType: row.vcsEventType ?? undefined,
|
|
@@ -1105,7 +1111,8 @@ function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
|
1105
1111
|
dir: row.dir ?? undefined,
|
|
1106
1112
|
parentTaskId: row.parentTaskId ?? undefined,
|
|
1107
1113
|
claudeSessionId: row.claudeSessionId ?? undefined,
|
|
1108
|
-
model:
|
|
1114
|
+
model: row.model ?? undefined,
|
|
1115
|
+
modelTier: parseModelTier(row.modelTier) ?? undefined,
|
|
1109
1116
|
scheduleId: row.scheduleId ?? undefined,
|
|
1110
1117
|
workflowRunId: row.workflowRunId ?? undefined,
|
|
1111
1118
|
workflowRunStepId: row.workflowRunStepId ?? undefined,
|
|
@@ -1161,6 +1168,7 @@ function rowToAgentTaskSummary(row: AgentTaskRow): AgentTaskSummary {
|
|
|
1161
1168
|
parentTaskId: t.parentTaskId,
|
|
1162
1169
|
scheduleId: t.scheduleId,
|
|
1163
1170
|
model: t.model,
|
|
1171
|
+
modelTier: t.modelTier,
|
|
1164
1172
|
provider: t.provider,
|
|
1165
1173
|
requestedByUserId: t.requestedByUserId,
|
|
1166
1174
|
progress: t.progress,
|
|
@@ -1363,6 +1371,30 @@ export function markTaskSlackReplySent(taskId: string): void {
|
|
|
1363
1371
|
getDb().run(`UPDATE agent_tasks SET slackReplySent = 1 WHERE id = ?`, [taskId]);
|
|
1364
1372
|
}
|
|
1365
1373
|
|
|
1374
|
+
export function setSlackMessageTracking(
|
|
1375
|
+
taskId: string,
|
|
1376
|
+
fields: {
|
|
1377
|
+
slackProgressMessageTs?: string | null;
|
|
1378
|
+
slackTreeRootMessageTs?: string | null;
|
|
1379
|
+
},
|
|
1380
|
+
): void {
|
|
1381
|
+
const sets: string[] = [];
|
|
1382
|
+
const args: (string | null)[] = [];
|
|
1383
|
+
|
|
1384
|
+
if (Object.hasOwn(fields, "slackProgressMessageTs")) {
|
|
1385
|
+
sets.push("slackProgressMessageTs = ?");
|
|
1386
|
+
args.push(fields.slackProgressMessageTs ?? null);
|
|
1387
|
+
}
|
|
1388
|
+
if (Object.hasOwn(fields, "slackTreeRootMessageTs")) {
|
|
1389
|
+
sets.push("slackTreeRootMessageTs = ?");
|
|
1390
|
+
args.push(fields.slackTreeRootMessageTs ?? null);
|
|
1391
|
+
}
|
|
1392
|
+
if (sets.length === 0) return;
|
|
1393
|
+
|
|
1394
|
+
args.push(taskId);
|
|
1395
|
+
getDb().run(`UPDATE agent_tasks SET ${sets.join(", ")} WHERE id = ?`, args);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1366
1398
|
export function getChildTasks(parentTaskId: string): AgentTask[] {
|
|
1367
1399
|
return getDb()
|
|
1368
1400
|
.prepare<AgentTaskRow, [string]>(
|
|
@@ -2850,6 +2882,7 @@ export interface CreateTaskOptions {
|
|
|
2850
2882
|
dir?: string;
|
|
2851
2883
|
parentTaskId?: string;
|
|
2852
2884
|
model?: string;
|
|
2885
|
+
modelTier?: ModelTier;
|
|
2853
2886
|
scheduleId?: string;
|
|
2854
2887
|
workflowRunId?: string;
|
|
2855
2888
|
workflowRunStepId?: string;
|
|
@@ -3056,9 +3089,9 @@ export function createTaskExtended(task: string, options?: CreateTaskOptions): A
|
|
|
3056
3089
|
vcsProvider, vcsRepo, vcsEventType, vcsNumber, vcsCommentId, vcsAuthor, vcsUrl,
|
|
3057
3090
|
vcsInstallationId, vcsNodeId,
|
|
3058
3091
|
agentmailInboxId, agentmailMessageId, agentmailThreadId,
|
|
3059
|
-
mentionMessageId, mentionChannelId, dir, parentTaskId, model, scheduleId,
|
|
3092
|
+
mentionMessageId, mentionChannelId, dir, parentTaskId, model, modelTier, scheduleId,
|
|
3060
3093
|
workflowRunId, workflowRunStepId, outputSchema, followUpConfig, requestedByUserId, contextKey, swarmVersion, createdAt, lastUpdatedAt, created_by, updated_by
|
|
3061
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
|
3094
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
|
3062
3095
|
)
|
|
3063
3096
|
.get(
|
|
3064
3097
|
id,
|
|
@@ -3093,6 +3126,7 @@ export function createTaskExtended(task: string, options?: CreateTaskOptions): A
|
|
|
3093
3126
|
options?.dir ?? null,
|
|
3094
3127
|
options?.parentTaskId ?? null,
|
|
3095
3128
|
options?.model ?? null,
|
|
3129
|
+
options?.modelTier ?? null,
|
|
3096
3130
|
options?.scheduleId ?? null,
|
|
3097
3131
|
options?.workflowRunId ?? null,
|
|
3098
3132
|
options?.workflowRunStepId ?? null,
|
|
@@ -5266,6 +5300,7 @@ type ScheduledTaskRow = {
|
|
|
5266
5300
|
lastErrorAt: string | null;
|
|
5267
5301
|
lastErrorMessage: string | null;
|
|
5268
5302
|
model: string | null;
|
|
5303
|
+
modelTier: string | null;
|
|
5269
5304
|
scheduleType: string;
|
|
5270
5305
|
createdAt: string;
|
|
5271
5306
|
lastUpdatedAt: string;
|
|
@@ -5306,7 +5341,8 @@ function rowToScheduledTask(row: ScheduledTaskRow): ScheduledTask {
|
|
|
5306
5341
|
consecutiveErrors: row.consecutiveErrors ?? 0,
|
|
5307
5342
|
lastErrorAt: normalizeDate(row.lastErrorAt) ?? undefined,
|
|
5308
5343
|
lastErrorMessage: row.lastErrorMessage ?? undefined,
|
|
5309
|
-
model:
|
|
5344
|
+
model: row.model ?? undefined,
|
|
5345
|
+
modelTier: parseModelTier(row.modelTier) ?? undefined,
|
|
5310
5346
|
scheduleType: row.scheduleType as "recurring" | "one_time",
|
|
5311
5347
|
createdAt: normalizeDateRequired(row.createdAt),
|
|
5312
5348
|
lastUpdatedAt: normalizeDateRequired(row.lastUpdatedAt),
|
|
@@ -5401,6 +5437,7 @@ export interface CreateScheduledTaskData {
|
|
|
5401
5437
|
createdByAgentId?: string;
|
|
5402
5438
|
timezone?: string;
|
|
5403
5439
|
model?: string;
|
|
5440
|
+
modelTier?: ModelTier;
|
|
5404
5441
|
scheduleType?: "recurring" | "one_time";
|
|
5405
5442
|
}
|
|
5406
5443
|
|
|
@@ -5413,8 +5450,8 @@ export function createScheduledTask(data: CreateScheduledTaskData): ScheduledTas
|
|
|
5413
5450
|
`INSERT INTO scheduled_tasks (
|
|
5414
5451
|
id, name, description, cronExpression, intervalMs, taskTemplate,
|
|
5415
5452
|
taskType, tags, priority, targetAgentId, enabled, nextRunAt,
|
|
5416
|
-
createdByAgentId, timezone, model, scheduleType, createdAt, lastUpdatedAt
|
|
5417
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
|
5453
|
+
createdByAgentId, timezone, model, modelTier, scheduleType, createdAt, lastUpdatedAt
|
|
5454
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
|
5418
5455
|
)
|
|
5419
5456
|
.get(
|
|
5420
5457
|
id,
|
|
@@ -5432,6 +5469,7 @@ export function createScheduledTask(data: CreateScheduledTaskData): ScheduledTas
|
|
|
5432
5469
|
data.createdByAgentId ?? null,
|
|
5433
5470
|
data.timezone ?? "UTC",
|
|
5434
5471
|
data.model ?? null,
|
|
5472
|
+
data.modelTier ?? null,
|
|
5435
5473
|
data.scheduleType ?? "recurring",
|
|
5436
5474
|
now,
|
|
5437
5475
|
now,
|
|
@@ -5459,6 +5497,7 @@ export interface UpdateScheduledTaskData {
|
|
|
5459
5497
|
lastErrorAt?: string | null;
|
|
5460
5498
|
lastErrorMessage?: string | null;
|
|
5461
5499
|
model?: string | null;
|
|
5500
|
+
modelTier?: ModelTier | null;
|
|
5462
5501
|
scheduleType?: "recurring" | "one_time";
|
|
5463
5502
|
lastUpdatedAt?: string;
|
|
5464
5503
|
}
|
|
@@ -5538,6 +5577,10 @@ export function updateScheduledTask(
|
|
|
5538
5577
|
updates.push("model = ?");
|
|
5539
5578
|
params.push(data.model);
|
|
5540
5579
|
}
|
|
5580
|
+
if (data.modelTier !== undefined) {
|
|
5581
|
+
updates.push("modelTier = ?");
|
|
5582
|
+
params.push(data.modelTier);
|
|
5583
|
+
}
|
|
5541
5584
|
if (data.scheduleType !== undefined) {
|
|
5542
5585
|
updates.push("scheduleType = ?");
|
|
5543
5586
|
params.push(data.scheduleType);
|
|
@@ -9394,6 +9437,7 @@ type McpServerRow = {
|
|
|
9394
9437
|
headers: string | null;
|
|
9395
9438
|
envConfigKeys: string | null;
|
|
9396
9439
|
headerConfigKeys: string | null;
|
|
9440
|
+
extraAuthorizeParams: string | null;
|
|
9397
9441
|
authMethod: string | null;
|
|
9398
9442
|
isEnabled: number;
|
|
9399
9443
|
version: number;
|
|
@@ -9425,6 +9469,7 @@ function rowToMcpServer(row: McpServerRow): McpServer {
|
|
|
9425
9469
|
headers: row.headers,
|
|
9426
9470
|
envConfigKeys: row.envConfigKeys,
|
|
9427
9471
|
headerConfigKeys: row.headerConfigKeys,
|
|
9472
|
+
extraAuthorizeParams: row.extraAuthorizeParams,
|
|
9428
9473
|
authMethod: (row.authMethod as McpServer["authMethod"]) ?? "static",
|
|
9429
9474
|
isEnabled: row.isEnabled === 1,
|
|
9430
9475
|
version: row.version,
|
|
@@ -9463,6 +9508,7 @@ export interface McpServerInsert {
|
|
|
9463
9508
|
headers?: string;
|
|
9464
9509
|
envConfigKeys?: string;
|
|
9465
9510
|
headerConfigKeys?: string;
|
|
9511
|
+
extraAuthorizeParams?: string;
|
|
9466
9512
|
}
|
|
9467
9513
|
|
|
9468
9514
|
export function createMcpServer(data: McpServerInsert): McpServer {
|
|
@@ -9474,9 +9520,9 @@ export function createMcpServer(data: McpServerInsert): McpServer {
|
|
|
9474
9520
|
`INSERT INTO mcp_servers (
|
|
9475
9521
|
id, name, description, scope, ownerAgentId, transport,
|
|
9476
9522
|
command, args, url, headers,
|
|
9477
|
-
envConfigKeys, headerConfigKeys,
|
|
9523
|
+
envConfigKeys, headerConfigKeys, extraAuthorizeParams,
|
|
9478
9524
|
isEnabled, version, createdAt, lastUpdatedAt
|
|
9479
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?) RETURNING *`,
|
|
9525
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?) RETURNING *`,
|
|
9480
9526
|
)
|
|
9481
9527
|
.get(
|
|
9482
9528
|
id,
|
|
@@ -9491,6 +9537,7 @@ export function createMcpServer(data: McpServerInsert): McpServer {
|
|
|
9491
9537
|
data.headers ?? null,
|
|
9492
9538
|
data.envConfigKeys ?? null,
|
|
9493
9539
|
data.headerConfigKeys ?? null,
|
|
9540
|
+
data.extraAuthorizeParams ?? null,
|
|
9494
9541
|
now,
|
|
9495
9542
|
now,
|
|
9496
9543
|
);
|
|
@@ -9553,6 +9600,10 @@ export function updateMcpServer(
|
|
|
9553
9600
|
sets.push("headerConfigKeys = ?");
|
|
9554
9601
|
params.push(updates.headerConfigKeys ?? null);
|
|
9555
9602
|
}
|
|
9603
|
+
if (updates.extraAuthorizeParams !== undefined) {
|
|
9604
|
+
sets.push("extraAuthorizeParams = ?");
|
|
9605
|
+
params.push(updates.extraAuthorizeParams ?? null);
|
|
9606
|
+
}
|
|
9556
9607
|
if (updates.isEnabled !== undefined) {
|
|
9557
9608
|
sets.push("isEnabled = ?");
|
|
9558
9609
|
params.push(updates.isEnabled ? 1 : 0);
|
|
@@ -9574,6 +9625,7 @@ export function updateMcpServer(
|
|
|
9574
9625
|
"headers",
|
|
9575
9626
|
"envConfigKeys",
|
|
9576
9627
|
"headerConfigKeys",
|
|
9628
|
+
"extraAuthorizeParams",
|
|
9577
9629
|
"transport",
|
|
9578
9630
|
];
|
|
9579
9631
|
if (configFields.some((f) => (updates as Record<string, unknown>)[f] !== undefined)) {
|
|
@@ -11801,6 +11853,7 @@ export function getScriptRunByIdempotencyKey(idempotencyKey: string): ScriptRun
|
|
|
11801
11853
|
export function listScriptRuns(opts?: {
|
|
11802
11854
|
status?: ScriptRunStatus;
|
|
11803
11855
|
agentId?: string;
|
|
11856
|
+
scriptName?: string;
|
|
11804
11857
|
limit?: number;
|
|
11805
11858
|
offset?: number;
|
|
11806
11859
|
}): ScriptRunListItem[] {
|
|
@@ -11814,6 +11867,10 @@ export function listScriptRuns(opts?: {
|
|
|
11814
11867
|
conditions.push("agentId = ?");
|
|
11815
11868
|
params.push(opts.agentId);
|
|
11816
11869
|
}
|
|
11870
|
+
if (opts?.scriptName) {
|
|
11871
|
+
conditions.push("scriptName = ?");
|
|
11872
|
+
params.push(opts.scriptName);
|
|
11873
|
+
}
|
|
11817
11874
|
|
|
11818
11875
|
const limit = opts?.limit ?? 50;
|
|
11819
11876
|
const offset = opts?.offset ?? 0;
|
|
@@ -11842,7 +11899,11 @@ export function listScriptRuns(opts?: {
|
|
|
11842
11899
|
return rows.map(rowToScriptRunListItem);
|
|
11843
11900
|
}
|
|
11844
11901
|
|
|
11845
|
-
export function countScriptRuns(opts?: {
|
|
11902
|
+
export function countScriptRuns(opts?: {
|
|
11903
|
+
status?: ScriptRunStatus;
|
|
11904
|
+
agentId?: string;
|
|
11905
|
+
scriptName?: string;
|
|
11906
|
+
}): number {
|
|
11846
11907
|
const conditions: string[] = [];
|
|
11847
11908
|
const params: string[] = [];
|
|
11848
11909
|
if (opts?.status) {
|
|
@@ -11853,6 +11914,10 @@ export function countScriptRuns(opts?: { status?: ScriptRunStatus; agentId?: str
|
|
|
11853
11914
|
conditions.push("agentId = ?");
|
|
11854
11915
|
params.push(opts.agentId);
|
|
11855
11916
|
}
|
|
11917
|
+
if (opts?.scriptName) {
|
|
11918
|
+
conditions.push("scriptName = ?");
|
|
11919
|
+
params.push(opts.scriptName);
|
|
11920
|
+
}
|
|
11856
11921
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
11857
11922
|
const row = getDb()
|
|
11858
11923
|
.prepare<{ count: number }, string[]>(`SELECT COUNT(*) AS count FROM script_runs ${where}`)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- Keep the seeded system dashboard aligned with the production swarm dashboard.
|
|
2
|
+
-- Migration 081 created the starter row; this forward migration updates both
|
|
3
|
+
-- fresh installs and existing databases without rewriting the applied seed.
|
|
4
|
+
|
|
5
|
+
UPDATE metrics
|
|
6
|
+
SET
|
|
7
|
+
title = 'Swarm operations overview',
|
|
8
|
+
description = 'A starter dashboard mixing raw SQL widgets with chart and table visualizations.',
|
|
9
|
+
definition = '{"version":1,"widgets":[{"id":"tasks-created-per-day","title":"Tasks created per day","description":"Daily task volume for the selected time range.","query":{"sql":"SELECT date(createdAt) AS day, COUNT(*) AS tasks FROM agent_tasks WHERE createdAt >= datetime(''now'', ?) GROUP BY day ORDER BY day","params":["{{rangeModifier}}"],"maxRows":100},"viz":{"type":"line","x":"day","y":"tasks","columns":[{"key":"day","label":"Day"},{"key":"tasks","label":"Tasks","format":"integer"}],"format":"integer"}},{"id":"usage-by-user","title":"Usage by user","description":"Tasks requested and session cost by user for the selected time range, requester filter, and agent filter.","query":{"sql":"SELECT COALESCE(u.name, ''Unassigned'') AS user, COUNT(DISTINCT t.id) AS tasks, ROUND(COALESCE(SUM(sc.totalCostUsd), 0), 4) AS cost_usd FROM agent_tasks t LEFT JOIN users u ON u.id = t.requestedByUserId LEFT JOIN session_costs sc ON sc.taskId = t.id WHERE t.createdAt >= datetime(''now'', ?) AND (? = '''' OR COALESCE(u.id, '''') = ? OR COALESCE(u.name, '''') LIKE ''%'' || ? || ''%'') AND (? = '''' OR COALESCE(t.agentId, '''') = ?) GROUP BY COALESCE(u.name, ''Unassigned'') ORDER BY cost_usd DESC, tasks DESC","params":["{{rangeModifier}}","{{userFilter}}","{{userFilter}}","{{userFilter}}","{{agentFilter}}","{{agentFilter}}"],"maxRows":100},"viz":{"type":"bar","x":"user","y":"tasks","columns":[{"key":"user","label":"User"},{"key":"tasks","label":"Tasks","format":"integer"},{"key":"cost_usd","label":"Cost","format":"currency"}],"format":"integer"}},{"id":"usage-by-model","title":"Usage by model","description":"Tasks, sessions, tokens, and total cost by model for the selected time range and agent filter.","query":{"sql":"SELECT model, COUNT(DISTINCT taskId) AS tasks, COUNT(*) AS sessions, SUM(inputTokens + outputTokens) AS tokens, ROUND(SUM(totalCostUsd), 2) AS cost_usd FROM session_costs WHERE createdAt >= datetime(''now'', ?) AND (? = '''' OR agentId = ?) GROUP BY model ORDER BY cost_usd DESC","params":["{{rangeModifier}}","{{agentFilter}}","{{agentFilter}}"],"maxRows":100},"viz":{"type":"bar","x":"model","y":"cost_usd","columns":[{"key":"model","label":"Model"},{"key":"tasks","label":"Tasks","format":"integer"},{"key":"sessions","label":"Sessions","format":"integer"},{"key":"tokens","label":"Tokens","format":"integer"},{"key":"cost_usd","label":"Cost","format":"currency"}],"format":"currency"}},{"id":"avg-cost-per-task-by-model","title":"Avg cost per task by model","description":"Average session cost per task, grouped by model, for the selected time range and agent filter.","query":{"sql":"SELECT model, COUNT(DISTINCT taskId) AS tasks, ROUND(SUM(totalCostUsd) * 1.0 / NULLIF(COUNT(DISTINCT taskId), 0), 4) AS avg_cost_per_task FROM session_costs WHERE createdAt >= datetime(''now'', ?) AND (? = '''' OR agentId = ?) GROUP BY model ORDER BY avg_cost_per_task DESC","params":["{{rangeModifier}}","{{agentFilter}}","{{agentFilter}}"],"maxRows":100},"viz":{"type":"bar","x":"model","y":"avg_cost_per_task","columns":[{"key":"model","label":"Model"},{"key":"tasks","label":"Tasks","format":"integer"},{"key":"avg_cost_per_task","label":"Avg cost / task","format":"currency"}],"format":"currency"}},{"id":"avg-task-time-by-model","title":"Avg task time by model","description":"Average wall-clock task duration (minutes) by model for finished tasks in the selected time range and agent filter.","query":{"sql":"SELECT model, COUNT(*) AS tasks, ROUND(AVG((julianday(finishedAt) - julianday(createdAt)) * 1440), 1) AS avg_minutes FROM agent_tasks WHERE finishedAt IS NOT NULL AND model IS NOT NULL AND createdAt >= datetime(''now'', ?) AND (? = '''' OR agentId = ?) GROUP BY model ORDER BY tasks DESC","params":["{{rangeModifier}}","{{agentFilter}}","{{agentFilter}}"],"maxRows":100},"viz":{"type":"bar","x":"model","y":"avg_minutes","columns":[{"key":"model","label":"Model"},{"key":"tasks","label":"Tasks","format":"integer"},{"key":"avg_minutes","label":"Avg time","format":"duration"}],"format":"duration"}},{"id":"cost-per-minute-by-model","title":"Cost per minute by model","description":"Total session cost divided by active session minutes, grouped by model. Active minutes = sum of session durations.","query":{"sql":"SELECT model, ROUND(SUM(durationMs) / 60000.0, 1) AS active_minutes, ROUND(SUM(totalCostUsd), 2) AS cost_usd, ROUND(SUM(totalCostUsd) / NULLIF(SUM(durationMs) / 60000.0, 0), 4) AS cost_per_minute FROM session_costs WHERE createdAt >= datetime(''now'', ?) AND (? = '''' OR agentId = ?) AND durationMs > 0 GROUP BY model ORDER BY cost_per_minute DESC","params":["{{rangeModifier}}","{{agentFilter}}","{{agentFilter}}"],"maxRows":100},"viz":{"type":"bar","x":"model","y":"cost_per_minute","columns":[{"key":"model","label":"Model"},{"key":"active_minutes","label":"Active minutes","format":"number"},{"key":"cost_usd","label":"Total cost","format":"currency"},{"key":"cost_per_minute","label":"Cost / min","format":"currency"}],"format":"currency"}},{"id":"cost-per-minute-by-agent","title":"Cost per minute by agent","description":"Total session cost divided by active session minutes, grouped by agent.","query":{"sql":"SELECT COALESCE(a.name, sc.agentId, ''unknown'') AS agent, ROUND(SUM(sc.durationMs) / 60000.0, 1) AS active_minutes, ROUND(SUM(sc.totalCostUsd), 2) AS cost_usd, ROUND(SUM(sc.totalCostUsd) / NULLIF(SUM(sc.durationMs) / 60000.0, 0), 4) AS cost_per_minute FROM session_costs sc LEFT JOIN agents a ON a.id = sc.agentId WHERE sc.createdAt >= datetime(''now'', ?) AND (? = '''' OR sc.agentId = ?) AND sc.durationMs > 0 GROUP BY agent ORDER BY cost_per_minute DESC","params":["{{rangeModifier}}","{{agentFilter}}","{{agentFilter}}"],"maxRows":100},"viz":{"type":"bar","x":"agent","y":"cost_per_minute","columns":[{"key":"agent","label":"Agent"},{"key":"active_minutes","label":"Active minutes","format":"number"},{"key":"cost_usd","label":"Total cost","format":"currency"},{"key":"cost_per_minute","label":"Cost / min","format":"currency"}],"format":"currency"}},{"id":"agent-performance","title":"Tasks, avg time & cost by agent","description":"Finished tasks per agent with average wall-clock duration and average cost per task for the selected time range.","query":{"sql":"SELECT COALESCE(a.name, t.agentId, ''unassigned'') AS agent, COUNT(*) AS tasks, ROUND(AVG((julianday(t.finishedAt) - julianday(t.createdAt)) * 1440), 1) AS avg_minutes, ROUND(COALESCE(SUM(sc.cost), 0), 2) AS cost_usd, ROUND(COALESCE(SUM(sc.cost), 0) / COUNT(*), 4) AS avg_cost_per_task, ROUND(COALESCE(SUM(sc.cost), 0) / NULLIF(SUM(sc.dur) / 60000.0, 0), 4) AS cost_per_minute FROM agent_tasks t LEFT JOIN agents a ON a.id = t.agentId LEFT JOIN (SELECT taskId, SUM(totalCostUsd) AS cost, SUM(durationMs) AS dur FROM session_costs GROUP BY taskId) sc ON sc.taskId = t.id WHERE t.finishedAt IS NOT NULL AND t.createdAt >= datetime(''now'', ?) AND (? = '''' OR COALESCE(t.agentId, '''') = ?) GROUP BY agent ORDER BY tasks DESC","params":["{{rangeModifier}}","{{agentFilter}}","{{agentFilter}}"],"maxRows":100},"viz":{"type":"table","columns":[{"key":"agent","label":"Agent"},{"key":"tasks","label":"Tasks","format":"integer"},{"key":"avg_minutes","label":"Avg time","format":"duration"},{"key":"avg_cost_per_task","label":"Avg cost / task","format":"currency"},{"key":"cost_usd","label":"Total cost","format":"currency"},{"key":"cost_per_minute","label":"Cost / min","format":"currency"}]}},{"id":"task-outcomes-by-day","title":"Task outcomes by day","description":"Completed and failed tasks for the selected time range.","query":{"sql":"SELECT date(finishedAt) AS day, SUM(CASE WHEN status = ''completed'' THEN 1 ELSE 0 END) AS completed, SUM(CASE WHEN status = ''failed'' THEN 1 ELSE 0 END) AS failed FROM agent_tasks WHERE finishedAt IS NOT NULL AND finishedAt >= datetime(''now'', ?) GROUP BY day ORDER BY day","params":["{{rangeModifier}}"],"maxRows":100},"viz":{"type":"multi-line","x":"day","series":["completed","failed"],"columns":[{"key":"day","label":"Day"},{"key":"completed","label":"Completed","format":"integer"},{"key":"failed","label":"Failed","format":"integer"}],"format":"integer"}},{"id":"recent-task-outcomes","title":"Recent task outcomes","description":"Task status breakdown for tasks created in the selected time range.","query":{"sql":"SELECT status, COUNT(*) AS tasks FROM agent_tasks WHERE createdAt >= datetime(''now'', ?) GROUP BY status ORDER BY tasks DESC","params":["{{rangeModifier}}"],"maxRows":100},"viz":{"type":"table","columns":[{"key":"status","label":"Status"},{"key":"tasks","label":"Tasks","format":"integer"}]}}],"variables":[{"key":"rangeModifier","label":"Time range","type":"select","defaultValue":"-30 days","options":[{"label":"Last 7 days","value":"-7 days"},{"label":"Last 30 days","value":"-30 days"},{"label":"Last 90 days","value":"-90 days"}]},{"key":"userFilter","label":"Requester user ID or name","type":"text","defaultValue":""},{"key":"agentFilter","label":"Agent ID","type":"text","defaultValue":""}],"layout":{"columns":3},"refreshSeconds":60}',
|
|
10
|
+
updatedAt = CURRENT_TIMESTAMP
|
|
11
|
+
WHERE agentId = 'system'
|
|
12
|
+
AND slug = 'swarm-operations-overview';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
-- Convert the seeded system dashboard user/agent filters from free-text inputs
|
|
2
|
+
-- to dynamic select variables. The UI renders select variables with resolved
|
|
3
|
+
-- options as searchable comboboxes.
|
|
4
|
+
|
|
5
|
+
UPDATE metrics
|
|
6
|
+
SET
|
|
7
|
+
definition = json_set(
|
|
8
|
+
replace(
|
|
9
|
+
replace(
|
|
10
|
+
replace(
|
|
11
|
+
replace(
|
|
12
|
+
replace(
|
|
13
|
+
definition,
|
|
14
|
+
'? = '''' OR COALESCE(u.id, '''') = ? OR COALESCE(u.name, '''') LIKE ''%'' || ? || ''%''',
|
|
15
|
+
'? = ''all'' OR COALESCE(u.id, '''') = ? OR COALESCE(u.name, '''') LIKE ''%'' || ? || ''%'''
|
|
16
|
+
),
|
|
17
|
+
'? = '''' OR agentId = ?',
|
|
18
|
+
'? = ''all'' OR agentId = ?'
|
|
19
|
+
),
|
|
20
|
+
'? = '''' OR sc.agentId = ?',
|
|
21
|
+
'? = ''all'' OR sc.agentId = ?'
|
|
22
|
+
),
|
|
23
|
+
'? = '''' OR COALESCE(t.agentId, '''') = ?',
|
|
24
|
+
'? = ''all'' OR COALESCE(t.agentId, '''') = ?'
|
|
25
|
+
),
|
|
26
|
+
'? = '''' OR COALESCE(agentId, '''') = ?',
|
|
27
|
+
'? = ''all'' OR COALESCE(agentId, '''') = ?'
|
|
28
|
+
),
|
|
29
|
+
'$.variables',
|
|
30
|
+
json('[
|
|
31
|
+
{
|
|
32
|
+
"key": "rangeModifier",
|
|
33
|
+
"label": "Time range",
|
|
34
|
+
"type": "select",
|
|
35
|
+
"defaultValue": "-30 days",
|
|
36
|
+
"options": [
|
|
37
|
+
{ "label": "Last 7 days", "value": "-7 days" },
|
|
38
|
+
{ "label": "Last 30 days", "value": "-30 days" },
|
|
39
|
+
{ "label": "Last 90 days", "value": "-90 days" }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"key": "userFilter",
|
|
44
|
+
"label": "Requester",
|
|
45
|
+
"type": "select",
|
|
46
|
+
"defaultValue": "all",
|
|
47
|
+
"optionsQuery": {
|
|
48
|
+
"sql": "SELECT id, label FROM (SELECT ''all'' AS id, ''All requesters'' AS label, 0 AS sort_key UNION ALL SELECT id, COALESCE(NULLIF(name, ''''), email, id) AS label, 1 AS sort_key FROM users WHERE id IS NOT NULL) ORDER BY sort_key, label COLLATE NOCASE",
|
|
49
|
+
"valueKey": "id",
|
|
50
|
+
"labelKey": "label"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"key": "agentFilter",
|
|
55
|
+
"label": "Agent",
|
|
56
|
+
"type": "select",
|
|
57
|
+
"defaultValue": "all",
|
|
58
|
+
"optionsQuery": {
|
|
59
|
+
"sql": "SELECT id, label FROM (SELECT ''all'' AS id, ''All agents'' AS label, 0 AS sort_key UNION ALL SELECT id, COALESCE(NULLIF(name, ''''), id) AS label, 1 AS sort_key FROM agents WHERE id IS NOT NULL) ORDER BY sort_key, label COLLATE NOCASE",
|
|
60
|
+
"valueKey": "id",
|
|
61
|
+
"labelKey": "label"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
]')
|
|
65
|
+
),
|
|
66
|
+
updatedAt = CURRENT_TIMESTAMP
|
|
67
|
+
WHERE agentId = 'system'
|
|
68
|
+
AND slug = 'swarm-operations-overview';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- Persist Slack message timestamps used by the watcher to update progress in place.
|
|
2
|
+
-- Without this, a server restart drops process-local maps and the next watcher
|
|
3
|
+
-- tick posts a duplicate progress/tree message in the same Slack thread.
|
|
4
|
+
|
|
5
|
+
ALTER TABLE agent_tasks ADD COLUMN slackProgressMessageTs TEXT;
|
|
6
|
+
ALTER TABLE agent_tasks ADD COLUMN slackTreeRootMessageTs TEXT;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
-- Extra OAuth authorize-request params, applied at authorize time only.
|
|
2
|
+
-- JSON object string of flat string->string pairs, e.g. {"access_type":"offline","prompt":"consent"}.
|
|
3
|
+
-- NULL (default) => authorize URL is unchanged from today. Provider-agnostic.
|
|
4
|
+
ALTER TABLE mcp_servers ADD COLUMN extraAuthorizeParams TEXT;
|