@desplega.ai/agent-swarm 1.79.3 → 1.80.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/openapi.json +98 -19
- package/package.json +12 -6
- package/src/be/db.ts +101 -30
- package/src/be/migrations/063_cost_context_schema_relax.sql +133 -0
- package/src/be/pricing-normalize.ts +81 -0
- package/src/be/seed-pricing.ts +293 -0
- package/src/commands/claude-managed-setup.ts +19 -3
- package/src/commands/runner.ts +592 -237
- package/src/http/context.ts +6 -2
- package/src/http/index.ts +115 -68
- package/src/http/session-data.ts +74 -23
- package/src/otel-impl.ts +200 -0
- package/src/otel.ts +127 -0
- package/src/providers/claude-adapter.ts +30 -5
- package/src/providers/claude-managed-adapter.ts +43 -17
- package/src/providers/claude-managed-pricing.ts +34 -0
- package/src/providers/codex-adapter.ts +38 -27
- package/src/providers/codex-models.ts +22 -3
- package/src/providers/devin-adapter.ts +11 -0
- package/src/providers/opencode-adapter.ts +31 -7
- package/src/providers/pi-mono-adapter.ts +39 -7
- package/src/providers/pricing-sources.md +52 -0
- package/src/providers/swarm-events-shared.ts +8 -4
- package/src/providers/types.ts +33 -10
- package/src/server.ts +6 -0
- package/src/tests/claude-managed-adapter.test.ts +17 -3
- package/src/tests/claude-managed-setup.test.ts +10 -1
- package/src/tests/codex-adapter.test.ts +20 -19
- package/src/tests/context-snapshot.test.ts +2 -2
- package/src/tests/context-window.test.ts +65 -1
- package/src/tests/devin-adapter.test.ts +2 -0
- package/src/tests/http/context-routes.test.ts +161 -0
- package/src/tests/migration-063-schema-relax.test.ts +109 -0
- package/src/tests/opencode-adapter.test.ts +146 -1
- package/src/tests/otel-impl-secret-scrubbing.test.ts +33 -0
- package/src/tests/pages-view-count.test.ts +30 -5
- package/src/tests/providers/codex-cost.test.ts +18 -0
- package/src/tests/providers/opencode-cost.test.ts +74 -0
- package/src/tests/providers/pi-cost.test.ts +128 -0
- package/src/tests/secret-scrubber.test.ts +19 -0
- package/src/tests/session-costs-codex-recompute.test.ts +35 -22
- package/src/tests/session-costs-model-key-normalize.test.ts +271 -0
- package/src/tests/session-costs-recompute-all-providers.test.ts +170 -0
- package/src/tests/store-progress-cost.test.ts +6 -1
- package/src/tools/store-progress.ts +16 -60
- package/src/tools/utils.ts +65 -12
- package/src/types.ts +62 -9
- package/src/utils/context-window.ts +104 -4
- package/src/utils/secret-scrubber.ts +7 -0
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.80.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": [
|
|
@@ -2147,7 +2147,8 @@
|
|
|
2147
2147
|
"type": "string",
|
|
2148
2148
|
"enum": [
|
|
2149
2149
|
"auto",
|
|
2150
|
-
"manual"
|
|
2150
|
+
"manual",
|
|
2151
|
+
"auto-inferred"
|
|
2151
2152
|
]
|
|
2152
2153
|
},
|
|
2153
2154
|
"preCompactTokens": {
|
|
@@ -2161,6 +2162,18 @@
|
|
|
2161
2162
|
"cumulativeOutputTokens": {
|
|
2162
2163
|
"type": "integer",
|
|
2163
2164
|
"minimum": 0
|
|
2165
|
+
},
|
|
2166
|
+
"contextFormula": {
|
|
2167
|
+
"type": "string",
|
|
2168
|
+
"enum": [
|
|
2169
|
+
"input-cache-output",
|
|
2170
|
+
"input-cache-no-output",
|
|
2171
|
+
"input-output-no-cache",
|
|
2172
|
+
"peak-proxy",
|
|
2173
|
+
"pi-delegated",
|
|
2174
|
+
"harness-reported",
|
|
2175
|
+
"unknown"
|
|
2176
|
+
]
|
|
2164
2177
|
}
|
|
2165
2178
|
},
|
|
2166
2179
|
"required": [
|
|
@@ -5393,8 +5406,12 @@
|
|
|
5393
5406
|
"type": "string",
|
|
5394
5407
|
"enum": [
|
|
5395
5408
|
"claude",
|
|
5409
|
+
"claude-managed",
|
|
5396
5410
|
"codex",
|
|
5397
|
-
"pi"
|
|
5411
|
+
"pi",
|
|
5412
|
+
"opencode",
|
|
5413
|
+
"devin",
|
|
5414
|
+
"gemini"
|
|
5398
5415
|
]
|
|
5399
5416
|
},
|
|
5400
5417
|
"model": {
|
|
@@ -5405,7 +5422,10 @@
|
|
|
5405
5422
|
"enum": [
|
|
5406
5423
|
"input",
|
|
5407
5424
|
"cached_input",
|
|
5408
|
-
"output"
|
|
5425
|
+
"output",
|
|
5426
|
+
"cache_write",
|
|
5427
|
+
"runtime_hour",
|
|
5428
|
+
"acu"
|
|
5409
5429
|
]
|
|
5410
5430
|
},
|
|
5411
5431
|
"effectiveFrom": {
|
|
@@ -5462,8 +5482,12 @@
|
|
|
5462
5482
|
"type": "string",
|
|
5463
5483
|
"enum": [
|
|
5464
5484
|
"claude",
|
|
5485
|
+
"claude-managed",
|
|
5465
5486
|
"codex",
|
|
5466
|
-
"pi"
|
|
5487
|
+
"pi",
|
|
5488
|
+
"opencode",
|
|
5489
|
+
"devin",
|
|
5490
|
+
"gemini"
|
|
5467
5491
|
]
|
|
5468
5492
|
},
|
|
5469
5493
|
"required": true,
|
|
@@ -5485,7 +5509,10 @@
|
|
|
5485
5509
|
"enum": [
|
|
5486
5510
|
"input",
|
|
5487
5511
|
"cached_input",
|
|
5488
|
-
"output"
|
|
5512
|
+
"output",
|
|
5513
|
+
"cache_write",
|
|
5514
|
+
"runtime_hour",
|
|
5515
|
+
"acu"
|
|
5489
5516
|
]
|
|
5490
5517
|
},
|
|
5491
5518
|
"required": true,
|
|
@@ -5515,8 +5542,12 @@
|
|
|
5515
5542
|
"type": "string",
|
|
5516
5543
|
"enum": [
|
|
5517
5544
|
"claude",
|
|
5545
|
+
"claude-managed",
|
|
5518
5546
|
"codex",
|
|
5519
|
-
"pi"
|
|
5547
|
+
"pi",
|
|
5548
|
+
"opencode",
|
|
5549
|
+
"devin",
|
|
5550
|
+
"gemini"
|
|
5520
5551
|
]
|
|
5521
5552
|
},
|
|
5522
5553
|
"required": true,
|
|
@@ -5538,7 +5569,10 @@
|
|
|
5538
5569
|
"enum": [
|
|
5539
5570
|
"input",
|
|
5540
5571
|
"cached_input",
|
|
5541
|
-
"output"
|
|
5572
|
+
"output",
|
|
5573
|
+
"cache_write",
|
|
5574
|
+
"runtime_hour",
|
|
5575
|
+
"acu"
|
|
5542
5576
|
]
|
|
5543
5577
|
},
|
|
5544
5578
|
"required": true,
|
|
@@ -5580,8 +5614,12 @@
|
|
|
5580
5614
|
"type": "string",
|
|
5581
5615
|
"enum": [
|
|
5582
5616
|
"claude",
|
|
5617
|
+
"claude-managed",
|
|
5583
5618
|
"codex",
|
|
5584
|
-
"pi"
|
|
5619
|
+
"pi",
|
|
5620
|
+
"opencode",
|
|
5621
|
+
"devin",
|
|
5622
|
+
"gemini"
|
|
5585
5623
|
]
|
|
5586
5624
|
},
|
|
5587
5625
|
"model": {
|
|
@@ -5592,7 +5630,10 @@
|
|
|
5592
5630
|
"enum": [
|
|
5593
5631
|
"input",
|
|
5594
5632
|
"cached_input",
|
|
5595
|
-
"output"
|
|
5633
|
+
"output",
|
|
5634
|
+
"cache_write",
|
|
5635
|
+
"runtime_hour",
|
|
5636
|
+
"acu"
|
|
5596
5637
|
]
|
|
5597
5638
|
},
|
|
5598
5639
|
"effectiveFrom": {
|
|
@@ -5649,8 +5690,12 @@
|
|
|
5649
5690
|
"type": "string",
|
|
5650
5691
|
"enum": [
|
|
5651
5692
|
"claude",
|
|
5693
|
+
"claude-managed",
|
|
5652
5694
|
"codex",
|
|
5653
|
-
"pi"
|
|
5695
|
+
"pi",
|
|
5696
|
+
"opencode",
|
|
5697
|
+
"devin",
|
|
5698
|
+
"gemini"
|
|
5654
5699
|
]
|
|
5655
5700
|
},
|
|
5656
5701
|
"required": true,
|
|
@@ -5672,7 +5717,10 @@
|
|
|
5672
5717
|
"enum": [
|
|
5673
5718
|
"input",
|
|
5674
5719
|
"cached_input",
|
|
5675
|
-
"output"
|
|
5720
|
+
"output",
|
|
5721
|
+
"cache_write",
|
|
5722
|
+
"runtime_hour",
|
|
5723
|
+
"acu"
|
|
5676
5724
|
]
|
|
5677
5725
|
},
|
|
5678
5726
|
"required": true,
|
|
@@ -5692,8 +5740,12 @@
|
|
|
5692
5740
|
"type": "string",
|
|
5693
5741
|
"enum": [
|
|
5694
5742
|
"claude",
|
|
5743
|
+
"claude-managed",
|
|
5695
5744
|
"codex",
|
|
5696
|
-
"pi"
|
|
5745
|
+
"pi",
|
|
5746
|
+
"opencode",
|
|
5747
|
+
"devin",
|
|
5748
|
+
"gemini"
|
|
5697
5749
|
]
|
|
5698
5750
|
},
|
|
5699
5751
|
"model": {
|
|
@@ -5704,7 +5756,10 @@
|
|
|
5704
5756
|
"enum": [
|
|
5705
5757
|
"input",
|
|
5706
5758
|
"cached_input",
|
|
5707
|
-
"output"
|
|
5759
|
+
"output",
|
|
5760
|
+
"cache_write",
|
|
5761
|
+
"runtime_hour",
|
|
5762
|
+
"acu"
|
|
5708
5763
|
]
|
|
5709
5764
|
},
|
|
5710
5765
|
"effectiveFrom": {
|
|
@@ -5758,8 +5813,12 @@
|
|
|
5758
5813
|
"type": "string",
|
|
5759
5814
|
"enum": [
|
|
5760
5815
|
"claude",
|
|
5816
|
+
"claude-managed",
|
|
5761
5817
|
"codex",
|
|
5762
|
-
"pi"
|
|
5818
|
+
"pi",
|
|
5819
|
+
"opencode",
|
|
5820
|
+
"devin",
|
|
5821
|
+
"gemini"
|
|
5763
5822
|
]
|
|
5764
5823
|
},
|
|
5765
5824
|
"required": true,
|
|
@@ -5781,7 +5840,10 @@
|
|
|
5781
5840
|
"enum": [
|
|
5782
5841
|
"input",
|
|
5783
5842
|
"cached_input",
|
|
5784
|
-
"output"
|
|
5843
|
+
"output",
|
|
5844
|
+
"cache_write",
|
|
5845
|
+
"runtime_hour",
|
|
5846
|
+
"acu"
|
|
5785
5847
|
]
|
|
5786
5848
|
},
|
|
5787
5849
|
"required": true,
|
|
@@ -6951,13 +7013,27 @@
|
|
|
6951
7013
|
"type": "integer"
|
|
6952
7014
|
},
|
|
6953
7015
|
"cacheWriteTokens": {
|
|
6954
|
-
"type":
|
|
7016
|
+
"type": [
|
|
7017
|
+
"integer",
|
|
7018
|
+
"null"
|
|
7019
|
+
]
|
|
7020
|
+
},
|
|
7021
|
+
"reasoningOutputTokens": {
|
|
7022
|
+
"type": "integer",
|
|
7023
|
+
"minimum": 0
|
|
7024
|
+
},
|
|
7025
|
+
"thinkingTokens": {
|
|
7026
|
+
"type": "integer",
|
|
7027
|
+
"minimum": 0
|
|
6955
7028
|
},
|
|
6956
7029
|
"durationMs": {
|
|
6957
7030
|
"type": "integer"
|
|
6958
7031
|
},
|
|
6959
7032
|
"numTurns": {
|
|
6960
|
-
"type":
|
|
7033
|
+
"type": [
|
|
7034
|
+
"integer",
|
|
7035
|
+
"null"
|
|
7036
|
+
]
|
|
6961
7037
|
},
|
|
6962
7038
|
"model": {
|
|
6963
7039
|
"type": "string"
|
|
@@ -6969,9 +7045,12 @@
|
|
|
6969
7045
|
"type": "string",
|
|
6970
7046
|
"enum": [
|
|
6971
7047
|
"claude",
|
|
7048
|
+
"claude-managed",
|
|
6972
7049
|
"codex",
|
|
6973
7050
|
"pi",
|
|
6974
|
-
"opencode"
|
|
7051
|
+
"opencode",
|
|
7052
|
+
"devin",
|
|
7053
|
+
"gemini"
|
|
6975
7054
|
]
|
|
6976
7055
|
},
|
|
6977
7056
|
"createdAt": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.80.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>",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"deploy:docker": "bun deploy/docker-push.ts",
|
|
74
74
|
"e2e:workflows": "bun scripts/e2e-workflow-test.ts",
|
|
75
75
|
"e2e:workflows:docker": "bun scripts/e2e-workflow-test.ts --with-docker",
|
|
76
|
+
"e2e:otel:jaeger": "bun scripts/e2e-otel-jaeger.ts",
|
|
76
77
|
"docs:mcp": "bun scripts/generate-mcp-docs.ts",
|
|
77
78
|
"docs:openapi": "bun scripts/generate-openapi.ts",
|
|
78
79
|
"docs:business-use": "bun scripts/generate-business-use-docs.ts",
|
|
@@ -104,13 +105,18 @@
|
|
|
104
105
|
"@desplega.ai/localtunnel": "^2.2.0",
|
|
105
106
|
"@inkjs/ui": "^2.0.0",
|
|
106
107
|
"@linear/sdk": "^77.0.0",
|
|
107
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
108
|
-
"@earendil-works/pi-ai": "^0.
|
|
109
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
108
|
+
"@earendil-works/pi-agent-core": "^0.75.3",
|
|
109
|
+
"@earendil-works/pi-ai": "^0.75.3",
|
|
110
|
+
"@earendil-works/pi-coding-agent": "^0.75.3",
|
|
110
111
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
111
|
-
"@openai/codex-sdk": "^0.
|
|
112
|
-
"@opencode-ai/sdk": "^1.
|
|
112
|
+
"@openai/codex-sdk": "^0.130.0",
|
|
113
|
+
"@opencode-ai/sdk": "^1.15.4",
|
|
113
114
|
"@openfort/openfort-node": "^0.9.1",
|
|
115
|
+
"@opentelemetry/api": "^1.9.1",
|
|
116
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
|
|
117
|
+
"@opentelemetry/resources": "^2.7.1",
|
|
118
|
+
"@opentelemetry/sdk-node": "^0.218.0",
|
|
119
|
+
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
114
120
|
"@slack/bolt": "^4.6.0",
|
|
115
121
|
"@types/react": "^19.2.7",
|
|
116
122
|
"@x402/core": "^2.5.0",
|
package/src/be/db.ts
CHANGED
|
@@ -980,7 +980,7 @@ type AgentTaskRow = {
|
|
|
980
980
|
progress: string | null;
|
|
981
981
|
compactionCount: number | null;
|
|
982
982
|
peakContextPercent: number | null;
|
|
983
|
-
|
|
983
|
+
peakContextTokens: number | null;
|
|
984
984
|
contextWindowSize: number | null;
|
|
985
985
|
was_paused: number;
|
|
986
986
|
credentialKeySuffix: string | null;
|
|
@@ -1036,7 +1036,7 @@ function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
|
1036
1036
|
contextKey: row.contextKey ?? undefined,
|
|
1037
1037
|
compactionCount: row.compactionCount ?? undefined,
|
|
1038
1038
|
peakContextPercent: row.peakContextPercent ?? undefined,
|
|
1039
|
-
|
|
1039
|
+
peakContextTokens: row.peakContextTokens ?? undefined,
|
|
1040
1040
|
contextWindowSize: row.contextWindowSize ?? undefined,
|
|
1041
1041
|
createdAt: row.createdAt,
|
|
1042
1042
|
lastUpdatedAt: row.lastUpdatedAt,
|
|
@@ -3761,8 +3761,11 @@ type SessionCostRow = {
|
|
|
3761
3761
|
outputTokens: number;
|
|
3762
3762
|
cacheReadTokens: number;
|
|
3763
3763
|
cacheWriteTokens: number;
|
|
3764
|
+
// Migration 063 additions:
|
|
3765
|
+
reasoningOutputTokens: number;
|
|
3766
|
+
thinkingTokens: number;
|
|
3764
3767
|
durationMs: number;
|
|
3765
|
-
numTurns: number;
|
|
3768
|
+
numTurns: number | null;
|
|
3766
3769
|
model: string;
|
|
3767
3770
|
isError: number;
|
|
3768
3771
|
costSource: string;
|
|
@@ -3780,6 +3783,8 @@ function rowToSessionCost(row: SessionCostRow): SessionCost {
|
|
|
3780
3783
|
outputTokens: row.outputTokens,
|
|
3781
3784
|
cacheReadTokens: row.cacheReadTokens,
|
|
3782
3785
|
cacheWriteTokens: row.cacheWriteTokens,
|
|
3786
|
+
reasoningOutputTokens: row.reasoningOutputTokens ?? 0,
|
|
3787
|
+
thinkingTokens: row.thinkingTokens ?? 0,
|
|
3783
3788
|
durationMs: row.durationMs,
|
|
3784
3789
|
numTurns: row.numTurns,
|
|
3785
3790
|
model: row.model,
|
|
@@ -3803,15 +3808,24 @@ const sessionCostQueries = {
|
|
|
3803
3808
|
number,
|
|
3804
3809
|
number,
|
|
3805
3810
|
number,
|
|
3806
|
-
number,
|
|
3807
|
-
number,
|
|
3808
|
-
|
|
3809
|
-
number,
|
|
3810
|
-
string,
|
|
3811
|
+
number, // reasoningOutputTokens
|
|
3812
|
+
number, // thinkingTokens
|
|
3813
|
+
number, // durationMs
|
|
3814
|
+
number | null, // numTurns
|
|
3815
|
+
string, // model
|
|
3816
|
+
number, // isError
|
|
3817
|
+
string, // costSource
|
|
3811
3818
|
]
|
|
3812
3819
|
>(
|
|
3813
|
-
`INSERT INTO session_costs (
|
|
3814
|
-
|
|
3820
|
+
`INSERT INTO session_costs (
|
|
3821
|
+
id, sessionId, taskId, agentId,
|
|
3822
|
+
totalCostUsd, inputTokens, outputTokens,
|
|
3823
|
+
cacheReadTokens, cacheWriteTokens,
|
|
3824
|
+
reasoningOutputTokens, thinkingTokens,
|
|
3825
|
+
durationMs, numTurns, model, isError,
|
|
3826
|
+
costSource, createdAt
|
|
3827
|
+
)
|
|
3828
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))`,
|
|
3815
3829
|
),
|
|
3816
3830
|
|
|
3817
3831
|
getByTaskId: () =>
|
|
@@ -3839,16 +3853,22 @@ export interface CreateSessionCostInput {
|
|
|
3839
3853
|
outputTokens?: number;
|
|
3840
3854
|
cacheReadTokens?: number;
|
|
3841
3855
|
cacheWriteTokens?: number;
|
|
3856
|
+
// Migration 063 additions — adapters that have these numbers should pass
|
|
3857
|
+
// them; defaulting to 0 preserves the old write shape for callers that don't.
|
|
3858
|
+
reasoningOutputTokens?: number;
|
|
3859
|
+
thinkingTokens?: number;
|
|
3842
3860
|
durationMs: number;
|
|
3843
|
-
|
|
3861
|
+
// Nullable: some adapters (claude when num_turns is absent) can't honestly
|
|
3862
|
+
// report a turn count; we prefer null over a faked 1.
|
|
3863
|
+
numTurns: number | null;
|
|
3844
3864
|
model: string;
|
|
3845
3865
|
isError?: boolean;
|
|
3846
3866
|
/**
|
|
3847
|
-
* Phase 6: where
|
|
3867
|
+
* Phase 6 (migration 063 added 'unpriced'): where `totalCostUsd` came from.
|
|
3848
3868
|
* - 'harness' — value reported by the harness as-is (default).
|
|
3849
|
-
* - 'pricing-table' — value recomputed by the API from `pricing` rows
|
|
3850
|
-
*
|
|
3851
|
-
*
|
|
3869
|
+
* - 'pricing-table' — value recomputed by the API from `pricing` rows.
|
|
3870
|
+
* - 'unpriced' — recompute attempted but no matching pricing rows;
|
|
3871
|
+
* `totalCostUsd` is whatever the worker submitted.
|
|
3852
3872
|
*/
|
|
3853
3873
|
costSource?: SessionCostSource;
|
|
3854
3874
|
}
|
|
@@ -3856,6 +3876,8 @@ export interface CreateSessionCostInput {
|
|
|
3856
3876
|
export function createSessionCost(input: CreateSessionCostInput): SessionCost {
|
|
3857
3877
|
const id = crypto.randomUUID();
|
|
3858
3878
|
const costSource: SessionCostSource = input.costSource ?? "harness";
|
|
3879
|
+
const reasoningOutputTokens = input.reasoningOutputTokens ?? 0;
|
|
3880
|
+
const thinkingTokens = input.thinkingTokens ?? 0;
|
|
3859
3881
|
sessionCostQueries
|
|
3860
3882
|
.insert()
|
|
3861
3883
|
.run(
|
|
@@ -3868,6 +3890,8 @@ export function createSessionCost(input: CreateSessionCostInput): SessionCost {
|
|
|
3868
3890
|
input.outputTokens ?? 0,
|
|
3869
3891
|
input.cacheReadTokens ?? 0,
|
|
3870
3892
|
input.cacheWriteTokens ?? 0,
|
|
3893
|
+
reasoningOutputTokens,
|
|
3894
|
+
thinkingTokens,
|
|
3871
3895
|
input.durationMs,
|
|
3872
3896
|
input.numTurns,
|
|
3873
3897
|
input.model,
|
|
@@ -3885,6 +3909,8 @@ export function createSessionCost(input: CreateSessionCostInput): SessionCost {
|
|
|
3885
3909
|
outputTokens: input.outputTokens ?? 0,
|
|
3886
3910
|
cacheReadTokens: input.cacheReadTokens ?? 0,
|
|
3887
3911
|
cacheWriteTokens: input.cacheWriteTokens ?? 0,
|
|
3912
|
+
reasoningOutputTokens,
|
|
3913
|
+
thinkingTokens,
|
|
3888
3914
|
durationMs: input.durationMs,
|
|
3889
3915
|
numTurns: input.numTurns,
|
|
3890
3916
|
model: input.model,
|
|
@@ -4110,16 +4136,33 @@ export interface DashboardCostSummary {
|
|
|
4110
4136
|
}
|
|
4111
4137
|
|
|
4112
4138
|
export function getDashboardCostSummary(): DashboardCostSummary {
|
|
4139
|
+
// Phase 13: compute the date boundaries in TS and pass them as ISO 8601
|
|
4140
|
+
// strings. `session_costs.createdAt` is a TEXT ISO 8601 column; lexicographic
|
|
4141
|
+
// comparison on ISO 8601 sorts correctly, so the comparison works as long
|
|
4142
|
+
// as both sides are the same shape. The old code compared an ISO string
|
|
4143
|
+
// (`2026-05-15T03:45:12.123Z`) against `date('now')` (which returns the
|
|
4144
|
+
// string `2026-05-15`) — lexicographically `2026-05-15T...` > `2026-05-15`,
|
|
4145
|
+
// so post-midnight rows correctly counted, BUT rows whose ISO began with
|
|
4146
|
+
// the EXACT bare-date string would fail the `>=` check inconsistently
|
|
4147
|
+
// depending on millisecond precision. Use a proper ISO-millisecond boundary
|
|
4148
|
+
// for both halves so the comparison is unambiguous.
|
|
4149
|
+
const now = new Date();
|
|
4150
|
+
const startOfDayUtc = new Date(
|
|
4151
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()),
|
|
4152
|
+
).toISOString();
|
|
4153
|
+
const startOfMonthUtc = new Date(
|
|
4154
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1),
|
|
4155
|
+
).toISOString();
|
|
4113
4156
|
type CostRow = { costToday: number; costMtd: number };
|
|
4114
4157
|
const row = getDb()
|
|
4115
|
-
.prepare<CostRow, []>(
|
|
4158
|
+
.prepare<CostRow, [string, string]>(
|
|
4116
4159
|
`SELECT
|
|
4117
|
-
COALESCE(SUM(CASE WHEN createdAt >=
|
|
4160
|
+
COALESCE(SUM(CASE WHEN createdAt >= ? THEN totalCostUsd ELSE 0 END), 0) as costToday,
|
|
4118
4161
|
COALESCE(SUM(totalCostUsd), 0) as costMtd
|
|
4119
4162
|
FROM session_costs
|
|
4120
|
-
WHERE createdAt >=
|
|
4163
|
+
WHERE createdAt >= ?`,
|
|
4121
4164
|
)
|
|
4122
|
-
.get();
|
|
4165
|
+
.get(startOfDayUtc, startOfMonthUtc);
|
|
4123
4166
|
|
|
4124
4167
|
return row ?? { costToday: 0, costMtd: 0 };
|
|
4125
4168
|
}
|
|
@@ -8245,6 +8288,8 @@ type ContextSnapshotRow = {
|
|
|
8245
8288
|
preCompactTokens: number | null;
|
|
8246
8289
|
cumulativeInputTokens: number;
|
|
8247
8290
|
cumulativeOutputTokens: number;
|
|
8291
|
+
// Migration 063 — see ContextFormulaSchema in src/types.ts for the value set.
|
|
8292
|
+
contextFormula: string | null;
|
|
8248
8293
|
createdAt: string;
|
|
8249
8294
|
};
|
|
8250
8295
|
|
|
@@ -8258,10 +8303,11 @@ function rowToContextSnapshot(row: ContextSnapshotRow): ContextSnapshot {
|
|
|
8258
8303
|
contextTotalTokens: row.contextTotalTokens ?? undefined,
|
|
8259
8304
|
contextPercent: row.contextPercent ?? undefined,
|
|
8260
8305
|
eventType: row.eventType,
|
|
8261
|
-
compactTrigger: (row.compactTrigger as "auto" | "manual" | null) ?? undefined,
|
|
8306
|
+
compactTrigger: (row.compactTrigger as "auto" | "manual" | "auto-inferred" | null) ?? undefined,
|
|
8262
8307
|
preCompactTokens: row.preCompactTokens ?? undefined,
|
|
8263
8308
|
cumulativeInputTokens: row.cumulativeInputTokens,
|
|
8264
8309
|
cumulativeOutputTokens: row.cumulativeOutputTokens,
|
|
8310
|
+
contextFormula: (row.contextFormula as ContextSnapshot["contextFormula"]) ?? undefined,
|
|
8265
8311
|
createdAt: row.createdAt,
|
|
8266
8312
|
};
|
|
8267
8313
|
}
|
|
@@ -8283,11 +8329,12 @@ const contextSnapshotQueries = {
|
|
|
8283
8329
|
number | null,
|
|
8284
8330
|
number,
|
|
8285
8331
|
number,
|
|
8332
|
+
string | null, // contextFormula (migration 063)
|
|
8286
8333
|
string,
|
|
8287
8334
|
]
|
|
8288
8335
|
>(
|
|
8289
|
-
`INSERT INTO task_context_snapshots (id, taskId, agentId, sessionId, contextUsedTokens, contextTotalTokens, contextPercent, eventType, compactTrigger, preCompactTokens, cumulativeInputTokens, cumulativeOutputTokens, createdAt)
|
|
8290
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
8336
|
+
`INSERT INTO task_context_snapshots (id, taskId, agentId, sessionId, contextUsedTokens, contextTotalTokens, contextPercent, eventType, compactTrigger, preCompactTokens, cumulativeInputTokens, cumulativeOutputTokens, contextFormula, createdAt)
|
|
8337
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
8291
8338
|
),
|
|
8292
8339
|
|
|
8293
8340
|
getByTaskId: () =>
|
|
@@ -8309,10 +8356,12 @@ export interface CreateContextSnapshotInput {
|
|
|
8309
8356
|
contextTotalTokens?: number;
|
|
8310
8357
|
contextPercent?: number;
|
|
8311
8358
|
eventType: ContextSnapshotEventType;
|
|
8312
|
-
compactTrigger?: "auto" | "manual";
|
|
8359
|
+
compactTrigger?: "auto" | "manual" | "auto-inferred";
|
|
8313
8360
|
preCompactTokens?: number;
|
|
8314
8361
|
cumulativeInputTokens?: number;
|
|
8315
8362
|
cumulativeOutputTokens?: number;
|
|
8363
|
+
// Migration 063 — adapter-supplied formula tag.
|
|
8364
|
+
contextFormula?: ContextSnapshot["contextFormula"];
|
|
8316
8365
|
}
|
|
8317
8366
|
|
|
8318
8367
|
export function createContextSnapshot(input: CreateContextSnapshotInput): ContextSnapshot {
|
|
@@ -8334,6 +8383,7 @@ export function createContextSnapshot(input: CreateContextSnapshotInput): Contex
|
|
|
8334
8383
|
input.preCompactTokens ?? null,
|
|
8335
8384
|
input.cumulativeInputTokens ?? 0,
|
|
8336
8385
|
input.cumulativeOutputTokens ?? 0,
|
|
8386
|
+
input.contextFormula ?? null,
|
|
8337
8387
|
now,
|
|
8338
8388
|
);
|
|
8339
8389
|
|
|
@@ -8347,10 +8397,15 @@ export function createContextSnapshot(input: CreateContextSnapshotInput): Contex
|
|
|
8347
8397
|
.run(input.contextPercent, input.taskId);
|
|
8348
8398
|
}
|
|
8349
8399
|
|
|
8350
|
-
//
|
|
8400
|
+
// Migration 063: peakContextTokens is monotonic-max across snapshots, not a
|
|
8401
|
+
// rolling latest. Mirrors Claude Code's status-line "peak context" semantic.
|
|
8351
8402
|
if (input.contextUsedTokens != null) {
|
|
8352
8403
|
getDb()
|
|
8353
|
-
.prepare(
|
|
8404
|
+
.prepare(
|
|
8405
|
+
`UPDATE agent_tasks
|
|
8406
|
+
SET peakContextTokens = MAX(COALESCE(peakContextTokens, 0), ?)
|
|
8407
|
+
WHERE id = ?`,
|
|
8408
|
+
)
|
|
8354
8409
|
.run(input.contextUsedTokens, input.taskId);
|
|
8355
8410
|
}
|
|
8356
8411
|
|
|
@@ -8362,9 +8417,17 @@ export function createContextSnapshot(input: CreateContextSnapshotInput): Contex
|
|
|
8362
8417
|
.run(input.taskId);
|
|
8363
8418
|
}
|
|
8364
8419
|
|
|
8365
|
-
|
|
8420
|
+
// Phase 10: set contextWindowSize on the FIRST snapshot that carries one
|
|
8421
|
+
// (was previously gated on eventType === 'completion', meaning the UI saw
|
|
8422
|
+
// NULL throughout running tasks). Subsequent snapshots leave it alone — the
|
|
8423
|
+
// window doesn't change mid-session.
|
|
8424
|
+
if (input.contextTotalTokens != null) {
|
|
8366
8425
|
getDb()
|
|
8367
|
-
.prepare(
|
|
8426
|
+
.prepare(
|
|
8427
|
+
`UPDATE agent_tasks
|
|
8428
|
+
SET contextWindowSize = ?
|
|
8429
|
+
WHERE id = ? AND contextWindowSize IS NULL`,
|
|
8430
|
+
)
|
|
8368
8431
|
.run(input.contextTotalTokens, input.taskId);
|
|
8369
8432
|
}
|
|
8370
8433
|
|
|
@@ -8381,6 +8444,7 @@ export function createContextSnapshot(input: CreateContextSnapshotInput): Contex
|
|
|
8381
8444
|
preCompactTokens: input.preCompactTokens,
|
|
8382
8445
|
cumulativeInputTokens: input.cumulativeInputTokens ?? 0,
|
|
8383
8446
|
cumulativeOutputTokens: input.cumulativeOutputTokens ?? 0,
|
|
8447
|
+
contextFormula: input.contextFormula,
|
|
8384
8448
|
createdAt: now,
|
|
8385
8449
|
};
|
|
8386
8450
|
}
|
|
@@ -8396,7 +8460,8 @@ export function getContextSnapshotsBySessionId(sessionId: string, limit = 500):
|
|
|
8396
8460
|
export interface ContextSummary {
|
|
8397
8461
|
compactionCount: number;
|
|
8398
8462
|
peakContextPercent: number | null;
|
|
8399
|
-
|
|
8463
|
+
// Migration 063: renamed from totalContextTokensUsed.
|
|
8464
|
+
peakContextTokens: number | null;
|
|
8400
8465
|
contextWindowSize: number | null;
|
|
8401
8466
|
snapshotCount: number;
|
|
8402
8467
|
}
|
|
@@ -8412,7 +8477,7 @@ export function getContextSummaryByTaskId(taskId: string): ContextSummary {
|
|
|
8412
8477
|
return {
|
|
8413
8478
|
compactionCount: task?.compactionCount ?? 0,
|
|
8414
8479
|
peakContextPercent: task?.peakContextPercent ?? null,
|
|
8415
|
-
|
|
8480
|
+
peakContextTokens: task?.peakContextTokens ?? null,
|
|
8416
8481
|
contextWindowSize: task?.contextWindowSize ?? null,
|
|
8417
8482
|
snapshotCount: countRow?.cnt ?? 0,
|
|
8418
8483
|
};
|
|
@@ -8635,6 +8700,12 @@ export function getKeyCostSummary(keyType?: string): KeyCostSummary[] {
|
|
|
8635
8700
|
}
|
|
8636
8701
|
|
|
8637
8702
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
8703
|
+
// Phase 13: INNER JOIN -> LEFT JOIN. The `WHERE t.credentialKeySuffix IS NOT NULL`
|
|
8704
|
+
// still filters out rows whose taskId doesn't link to a task with credentials,
|
|
8705
|
+
// but switching to LEFT JOIN means a future change that drops the WHERE
|
|
8706
|
+
// (or a debugging query that wants orphan rows visible) doesn't silently
|
|
8707
|
+
// disappear them. Equivalent for the current `WHERE … IS NOT NULL` filter;
|
|
8708
|
+
// makes the query's intent (cost rows owned by a credential) explicit.
|
|
8638
8709
|
return db
|
|
8639
8710
|
.prepare<KeyCostSummary, string[]>(
|
|
8640
8711
|
`SELECT
|
|
@@ -8645,7 +8716,7 @@ export function getKeyCostSummary(keyType?: string): KeyCostSummary[] {
|
|
|
8645
8716
|
COALESCE(SUM(sc.outputTokens), 0) as totalOutputTokens,
|
|
8646
8717
|
COUNT(DISTINCT sc.taskId) as taskCount
|
|
8647
8718
|
FROM session_costs sc
|
|
8648
|
-
JOIN agent_tasks t ON sc.taskId = t.id
|
|
8719
|
+
LEFT JOIN agent_tasks t ON sc.taskId = t.id
|
|
8649
8720
|
${where}
|
|
8650
8721
|
GROUP BY t.credentialKeyType, t.credentialKeySuffix`,
|
|
8651
8722
|
)
|