pilotswarm-sdk 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cms-migrations.d.ts.map +1 -1
- package/dist/cms-migrations.js +840 -1
- package/dist/cms-migrations.js.map +1 -1
- package/dist/cms.d.ts +31 -1
- package/dist/cms.d.ts.map +1 -1
- package/dist/cms.js +46 -1
- package/dist/cms.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/inspect-tools.d.ts.map +1 -1
- package/dist/inspect-tools.js +27 -0
- package/dist/inspect-tools.js.map +1 -1
- package/dist/managed-session.d.ts +1 -0
- package/dist/managed-session.d.ts.map +1 -1
- package/dist/managed-session.js +243 -21
- package/dist/managed-session.js.map +1 -1
- package/dist/management-client.d.ts +14 -1
- package/dist/management-client.d.ts.map +1 -1
- package/dist/management-client.js +49 -1
- package/dist/management-client.js.map +1 -1
- package/dist/orchestration/index.d.ts +2 -2
- package/dist/orchestration/index.js +1 -1
- package/dist/orchestration/lifecycle.d.ts.map +1 -1
- package/dist/orchestration/lifecycle.js +74 -4
- package/dist/orchestration/lifecycle.js.map +1 -1
- package/dist/orchestration/runtime.d.ts +1 -1
- package/dist/orchestration/state.d.ts +1 -0
- package/dist/orchestration/state.d.ts.map +1 -1
- package/dist/orchestration/state.js +1 -0
- package/dist/orchestration/state.js.map +1 -1
- package/dist/orchestration/turn.d.ts +11 -0
- package/dist/orchestration/turn.d.ts.map +1 -1
- package/dist/orchestration/turn.js +61 -4
- package/dist/orchestration/turn.js.map +1 -1
- package/dist/orchestration-registry.d.ts.map +1 -1
- package/dist/orchestration-registry.js +4 -2
- package/dist/orchestration-registry.js.map +1 -1
- package/dist/orchestration-version.d.ts +1 -1
- package/dist/orchestration-version.js +1 -1
- package/dist/orchestration.d.ts +2 -2
- package/dist/orchestration.js +1 -1
- package/dist/orchestration_1_0_46.d.ts +1 -1
- package/dist/orchestration_1_0_47.d.ts +1 -1
- package/dist/orchestration_1_0_48.d.ts +1 -1
- package/dist/orchestration_1_0_49.d.ts +1 -1
- package/dist/orchestration_1_0_50.d.ts +1 -1
- package/dist/orchestration_1_0_54/agents.d.ts +41 -0
- package/dist/orchestration_1_0_54/agents.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/agents.js +758 -0
- package/dist/orchestration_1_0_54/agents.js.map +1 -0
- package/dist/orchestration_1_0_54/index.d.ts +24 -0
- package/dist/orchestration_1_0_54/index.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/index.js +13 -0
- package/dist/orchestration_1_0_54/index.js.map +1 -0
- package/dist/orchestration_1_0_54/lifecycle.d.ts +41 -0
- package/dist/orchestration_1_0_54/lifecycle.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/lifecycle.js +510 -0
- package/dist/orchestration_1_0_54/lifecycle.js.map +1 -0
- package/dist/orchestration_1_0_54/queue.d.ts +7 -0
- package/dist/orchestration_1_0_54/queue.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/queue.js +644 -0
- package/dist/orchestration_1_0_54/queue.js.map +1 -0
- package/dist/orchestration_1_0_54/runtime.d.ts +29 -0
- package/dist/orchestration_1_0_54/runtime.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/runtime.js +194 -0
- package/dist/orchestration_1_0_54/runtime.js.map +1 -0
- package/dist/orchestration_1_0_54/state.d.ts +125 -0
- package/dist/orchestration_1_0_54/state.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/state.js +105 -0
- package/dist/orchestration_1_0_54/state.js.map +1 -0
- package/dist/orchestration_1_0_54/turn.d.ts +6 -0
- package/dist/orchestration_1_0_54/turn.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/turn.js +864 -0
- package/dist/orchestration_1_0_54/turn.js.map +1 -0
- package/dist/orchestration_1_0_54/utils.d.ts +22 -0
- package/dist/orchestration_1_0_54/utils.d.ts.map +1 -0
- package/dist/orchestration_1_0_54/utils.js +226 -0
- package/dist/orchestration_1_0_54/utils.js.map +1 -0
- package/dist/session-manager.d.ts +4 -0
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/session-manager.js +22 -0
- package/dist/session-manager.js.map +1 -1
- package/dist/session-proxy.d.ts +12 -0
- package/dist/session-proxy.d.ts.map +1 -1
- package/dist/session-proxy.js +137 -13
- package/dist/session-proxy.js.map +1 -1
- package/dist/sweeper-tools.d.ts +1 -1
- package/dist/sweeper-tools.d.ts.map +1 -1
- package/dist/sweeper-tools.js +153 -92
- package/dist/sweeper-tools.js.map +1 -1
- package/dist/system-agents.d.ts +2 -0
- package/dist/system-agents.d.ts.map +1 -1
- package/dist/system-agents.js +3 -0
- package/dist/system-agents.js.map +1 -1
- package/dist/types.d.ts +14 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -2
- package/plugins/mgmt/agents/agent-tuner.agent.md +36 -2
- package/plugins/mgmt/agents/sweeper.agent.md +7 -4
- package/plugins/mgmt/skills/sweeper/SKILL.md +4 -1
- package/plugins/system/agents/default.agent.md +3 -1
package/dist/cms-migrations.js
CHANGED
|
@@ -117,6 +117,16 @@ export function CMS_MIGRATIONS(schema) {
|
|
|
117
117
|
name: "retrieval_usage_procs",
|
|
118
118
|
sql: migration_0021_retrieval_usage_procs(schema),
|
|
119
119
|
},
|
|
120
|
+
{
|
|
121
|
+
version: "0022",
|
|
122
|
+
name: "turn_metrics_reasoning_effort",
|
|
123
|
+
sql: migration_0022_turn_metrics_reasoning_effort(schema),
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
version: "0023",
|
|
127
|
+
name: "turn_metrics_stats_fallbacks_and_group_owner_patch",
|
|
128
|
+
sql: migration_0023_turn_metrics_stats_fallbacks_and_group_owner_patch(schema),
|
|
129
|
+
},
|
|
120
130
|
];
|
|
121
131
|
}
|
|
122
132
|
// ─── Migration 0001: Baseline ────────────────────────────────────
|
|
@@ -2749,7 +2759,7 @@ BEGIN
|
|
|
2749
2759
|
is_system = CASE WHEN p_updates ? 'isSystem' THEN (p_updates->>'isSystem')::BOOLEAN ELSE is_system END,
|
|
2750
2760
|
agent_id = CASE WHEN p_updates ? 'agentId' THEN (p_updates->>'agentId') ELSE agent_id END,
|
|
2751
2761
|
splash = CASE WHEN p_updates ? 'splash' THEN (p_updates->>'splash') ELSE splash END,
|
|
2752
|
-
group_id =
|
|
2762
|
+
group_id = group_id,
|
|
2753
2763
|
updated_at = now()
|
|
2754
2764
|
WHERE session_id = p_session_id;
|
|
2755
2765
|
|
|
@@ -3384,4 +3394,833 @@ END;
|
|
|
3384
3394
|
$$ LANGUAGE plpgsql;
|
|
3385
3395
|
`;
|
|
3386
3396
|
}
|
|
3397
|
+
// ─── Migration 0022: Turn Metrics Reasoning Effort ──────────────
|
|
3398
|
+
function migration_0022_turn_metrics_reasoning_effort(schema) {
|
|
3399
|
+
const s = `"${schema}"`;
|
|
3400
|
+
return `
|
|
3401
|
+
-- 0022_turn_metrics_reasoning_effort:
|
|
3402
|
+
-- - Add reasoning_effort to per-turn metrics so token attribution aligns with
|
|
3403
|
+
-- the session row model:effort convention and survives mid-session switches.
|
|
3404
|
+
-- - Add model+effort composite indexes for by-model aggregation.
|
|
3405
|
+
-- - Extend insert/read procs; add per-session by-model rollup with turn count.
|
|
3406
|
+
|
|
3407
|
+
DO $$
|
|
3408
|
+
BEGIN
|
|
3409
|
+
IF to_regclass('${schema}.session_metrics') IS NULL
|
|
3410
|
+
AND to_regclass('${schema}.session_metric_summaries') IS NOT NULL THEN
|
|
3411
|
+
ALTER TABLE ${s}.session_metric_summaries RENAME TO session_metrics;
|
|
3412
|
+
END IF;
|
|
3413
|
+
END;
|
|
3414
|
+
$$ LANGUAGE plpgsql;
|
|
3415
|
+
|
|
3416
|
+
DO $$
|
|
3417
|
+
BEGIN
|
|
3418
|
+
IF to_regclass('${schema}.session_metric_summaries') IS NULL
|
|
3419
|
+
AND to_regclass('${schema}.session_metrics') IS NOT NULL THEN
|
|
3420
|
+
EXECUTE 'CREATE VIEW ${s}.session_metric_summaries AS SELECT * FROM ${s}.session_metrics';
|
|
3421
|
+
END IF;
|
|
3422
|
+
END;
|
|
3423
|
+
$$ LANGUAGE plpgsql;
|
|
3424
|
+
|
|
3425
|
+
CREATE INDEX IF NOT EXISTS idx_${schema}_session_metrics_agent_model
|
|
3426
|
+
ON ${s}.session_metrics(agent_id, model);
|
|
3427
|
+
CREATE INDEX IF NOT EXISTS idx_${schema}_session_metrics_agent_model_effort
|
|
3428
|
+
ON ${s}.session_metrics(agent_id, model, reasoning_effort);
|
|
3429
|
+
CREATE INDEX IF NOT EXISTS idx_${schema}_session_metrics_parent
|
|
3430
|
+
ON ${s}.session_metrics(parent_session_id);
|
|
3431
|
+
CREATE INDEX IF NOT EXISTS idx_${schema}_session_metrics_updated
|
|
3432
|
+
ON ${s}.session_metrics(updated_at DESC);
|
|
3433
|
+
|
|
3434
|
+
DROP INDEX IF EXISTS ${s}.idx_${schema}_sms_agent_model;
|
|
3435
|
+
DROP INDEX IF EXISTS ${s}.idx_${schema}_sms_agent_model_reasoning;
|
|
3436
|
+
DROP INDEX IF EXISTS ${s}.idx_${schema}_sms_parent;
|
|
3437
|
+
DROP INDEX IF EXISTS ${s}.idx_${schema}_sms_updated;
|
|
3438
|
+
|
|
3439
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_update_session_group(
|
|
3440
|
+
p_group_id TEXT,
|
|
3441
|
+
p_patch JSONB
|
|
3442
|
+
) RETURNS VOID AS $$
|
|
3443
|
+
BEGIN
|
|
3444
|
+
UPDATE ${s}.session_groups
|
|
3445
|
+
SET title = CASE WHEN p_patch ? 'title' THEN NULLIF(BTRIM(p_patch->>'title'), '') ELSE title END,
|
|
3446
|
+
description = CASE WHEN p_patch ? 'description' THEN p_patch->>'description' ELSE description END,
|
|
3447
|
+
owner = CASE WHEN p_patch ? 'owner' THEN p_patch->'owner' ELSE owner END,
|
|
3448
|
+
metadata = CASE WHEN p_patch ? 'metadataPatch' THEN metadata || COALESCE(p_patch->'metadataPatch', '{}'::jsonb) ELSE metadata END,
|
|
3449
|
+
updated_at = now()
|
|
3450
|
+
WHERE group_id = p_group_id;
|
|
3451
|
+
END;
|
|
3452
|
+
$$ LANGUAGE plpgsql;
|
|
3453
|
+
|
|
3454
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_get_session_metric_summary(
|
|
3455
|
+
p_session_id TEXT
|
|
3456
|
+
) RETURNS SETOF ${s}.session_metrics AS $$
|
|
3457
|
+
BEGIN
|
|
3458
|
+
RETURN QUERY
|
|
3459
|
+
SELECT * FROM ${s}.session_metrics
|
|
3460
|
+
WHERE session_id = p_session_id;
|
|
3461
|
+
END;
|
|
3462
|
+
$$ LANGUAGE plpgsql;
|
|
3463
|
+
|
|
3464
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_create_session(
|
|
3465
|
+
p_session_id TEXT,
|
|
3466
|
+
p_model TEXT,
|
|
3467
|
+
p_reasoning_effort TEXT,
|
|
3468
|
+
p_parent_session_id TEXT,
|
|
3469
|
+
p_is_system BOOLEAN,
|
|
3470
|
+
p_agent_id TEXT,
|
|
3471
|
+
p_splash TEXT,
|
|
3472
|
+
p_group_id TEXT
|
|
3473
|
+
) RETURNS VOID AS $$
|
|
3474
|
+
DECLARE
|
|
3475
|
+
v_reasoning_effort TEXT := NULLIF(BTRIM(p_reasoning_effort), '');
|
|
3476
|
+
v_group_id TEXT := NULLIF(BTRIM(p_group_id), '');
|
|
3477
|
+
BEGIN
|
|
3478
|
+
IF v_group_id IS NULL AND p_parent_session_id IS NOT NULL THEN
|
|
3479
|
+
SELECT group_id INTO v_group_id
|
|
3480
|
+
FROM ${s}.sessions
|
|
3481
|
+
WHERE session_id = p_parent_session_id;
|
|
3482
|
+
END IF;
|
|
3483
|
+
|
|
3484
|
+
INSERT INTO ${s}.sessions
|
|
3485
|
+
(session_id, model, reasoning_effort, parent_session_id, is_system, agent_id, splash, group_id)
|
|
3486
|
+
VALUES
|
|
3487
|
+
(p_session_id, p_model, v_reasoning_effort, p_parent_session_id, p_is_system, p_agent_id, p_splash, v_group_id)
|
|
3488
|
+
ON CONFLICT (session_id) DO UPDATE
|
|
3489
|
+
SET model = EXCLUDED.model,
|
|
3490
|
+
reasoning_effort = EXCLUDED.reasoning_effort,
|
|
3491
|
+
parent_session_id = EXCLUDED.parent_session_id,
|
|
3492
|
+
is_system = EXCLUDED.is_system,
|
|
3493
|
+
agent_id = EXCLUDED.agent_id,
|
|
3494
|
+
splash = EXCLUDED.splash,
|
|
3495
|
+
group_id = EXCLUDED.group_id,
|
|
3496
|
+
deleted_at = NULL,
|
|
3497
|
+
updated_at = now(),
|
|
3498
|
+
state = 'pending',
|
|
3499
|
+
orchestration_id = NULL,
|
|
3500
|
+
last_error = NULL,
|
|
3501
|
+
last_active_at = NULL,
|
|
3502
|
+
current_iteration = 0,
|
|
3503
|
+
wait_reason = NULL,
|
|
3504
|
+
title_locked = FALSE
|
|
3505
|
+
WHERE ${s}.sessions.deleted_at IS NOT NULL;
|
|
3506
|
+
|
|
3507
|
+
INSERT INTO ${s}.session_metrics
|
|
3508
|
+
(session_id, agent_id, model, reasoning_effort, parent_session_id)
|
|
3509
|
+
VALUES
|
|
3510
|
+
(p_session_id, p_agent_id, p_model, v_reasoning_effort, p_parent_session_id)
|
|
3511
|
+
ON CONFLICT (session_id) DO UPDATE
|
|
3512
|
+
SET agent_id = COALESCE(${s}.session_metrics.agent_id, EXCLUDED.agent_id),
|
|
3513
|
+
model = COALESCE(${s}.session_metrics.model, EXCLUDED.model),
|
|
3514
|
+
reasoning_effort = COALESCE(${s}.session_metrics.reasoning_effort, EXCLUDED.reasoning_effort),
|
|
3515
|
+
parent_session_id = COALESCE(${s}.session_metrics.parent_session_id, EXCLUDED.parent_session_id),
|
|
3516
|
+
updated_at = now();
|
|
3517
|
+
END;
|
|
3518
|
+
$$ LANGUAGE plpgsql;
|
|
3519
|
+
|
|
3520
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_update_session(
|
|
3521
|
+
p_session_id TEXT,
|
|
3522
|
+
p_updates JSONB
|
|
3523
|
+
) RETURNS VOID AS $$
|
|
3524
|
+
BEGIN
|
|
3525
|
+
UPDATE ${s}.sessions SET
|
|
3526
|
+
orchestration_id = CASE WHEN p_updates ? 'orchestrationId' THEN (p_updates->>'orchestrationId') ELSE orchestration_id END,
|
|
3527
|
+
title = CASE WHEN p_updates ? 'title' THEN (p_updates->>'title') ELSE title END,
|
|
3528
|
+
title_locked = CASE WHEN p_updates ? 'titleLocked' THEN (p_updates->>'titleLocked')::BOOLEAN ELSE title_locked END,
|
|
3529
|
+
state = CASE WHEN p_updates ? 'state' THEN (p_updates->>'state') ELSE state END,
|
|
3530
|
+
model = CASE WHEN p_updates ? 'model' THEN (p_updates->>'model') ELSE model END,
|
|
3531
|
+
reasoning_effort = CASE WHEN p_updates ? 'reasoningEffort' THEN NULLIF(BTRIM(p_updates->>'reasoningEffort'), '') ELSE reasoning_effort END,
|
|
3532
|
+
last_active_at = CASE WHEN p_updates ? 'lastActiveAt' THEN (p_updates->>'lastActiveAt')::TIMESTAMPTZ ELSE last_active_at END,
|
|
3533
|
+
current_iteration = CASE WHEN p_updates ? 'currentIteration' THEN (p_updates->>'currentIteration')::INT ELSE current_iteration END,
|
|
3534
|
+
last_error = CASE WHEN p_updates ? 'lastError' THEN (p_updates->>'lastError') ELSE last_error END,
|
|
3535
|
+
wait_reason = CASE WHEN p_updates ? 'waitReason' THEN (p_updates->>'waitReason') ELSE wait_reason END,
|
|
3536
|
+
is_system = CASE WHEN p_updates ? 'isSystem' THEN (p_updates->>'isSystem')::BOOLEAN ELSE is_system END,
|
|
3537
|
+
agent_id = CASE WHEN p_updates ? 'agentId' THEN (p_updates->>'agentId') ELSE agent_id END,
|
|
3538
|
+
splash = CASE WHEN p_updates ? 'splash' THEN (p_updates->>'splash') ELSE splash END,
|
|
3539
|
+
group_id = group_id,
|
|
3540
|
+
updated_at = now()
|
|
3541
|
+
WHERE session_id = p_session_id;
|
|
3542
|
+
|
|
3543
|
+
IF p_updates ? 'groupId' THEN
|
|
3544
|
+
PERFORM ${s}.cms_assign_session_group(p_session_id, p_updates->>'groupId');
|
|
3545
|
+
END IF;
|
|
3546
|
+
|
|
3547
|
+
UPDATE ${s}.session_metrics
|
|
3548
|
+
SET model = CASE WHEN p_updates ? 'model' THEN (p_updates->>'model') ELSE model END,
|
|
3549
|
+
reasoning_effort = CASE WHEN p_updates ? 'reasoningEffort' THEN NULLIF(BTRIM(p_updates->>'reasoningEffort'), '') ELSE reasoning_effort END,
|
|
3550
|
+
updated_at = CASE WHEN p_updates ? 'model' OR p_updates ? 'reasoningEffort' THEN now() ELSE updated_at END
|
|
3551
|
+
WHERE session_id = p_session_id
|
|
3552
|
+
AND (p_updates ? 'model' OR p_updates ? 'reasoningEffort');
|
|
3553
|
+
END;
|
|
3554
|
+
$$ LANGUAGE plpgsql;
|
|
3555
|
+
|
|
3556
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_upsert_session_metric_summary(
|
|
3557
|
+
p_session_id TEXT,
|
|
3558
|
+
p_updates JSONB
|
|
3559
|
+
) RETURNS VOID AS $$
|
|
3560
|
+
DECLARE
|
|
3561
|
+
v_snapshot BIGINT := COALESCE((p_updates->>'snapshotSizeBytes')::BIGINT, 0);
|
|
3562
|
+
v_dehydration INT := COALESCE((p_updates->>'dehydrationCountIncrement')::INT, 0);
|
|
3563
|
+
v_hydration INT := COALESCE((p_updates->>'hydrationCountIncrement')::INT, 0);
|
|
3564
|
+
v_lossy INT := COALESCE((p_updates->>'lossyHandoffCountIncrement')::INT, 0);
|
|
3565
|
+
v_tokens_in BIGINT := COALESCE((p_updates->>'tokensInputIncrement')::BIGINT, 0);
|
|
3566
|
+
v_tokens_out BIGINT := COALESCE((p_updates->>'tokensOutputIncrement')::BIGINT, 0);
|
|
3567
|
+
v_tokens_cread BIGINT := COALESCE((p_updates->>'tokensCacheReadIncrement')::BIGINT, 0);
|
|
3568
|
+
v_tokens_cwrite BIGINT := COALESCE((p_updates->>'tokensCacheWriteIncrement')::BIGINT, 0);
|
|
3569
|
+
v_set_dehydrated BOOLEAN := COALESCE((p_updates->>'lastDehydratedAt')::BOOLEAN, FALSE);
|
|
3570
|
+
v_set_hydrated BOOLEAN := COALESCE((p_updates->>'lastHydratedAt')::BOOLEAN, FALSE);
|
|
3571
|
+
v_set_checkpoint BOOLEAN := COALESCE((p_updates->>'lastCheckpointAt')::BOOLEAN, FALSE);
|
|
3572
|
+
BEGIN
|
|
3573
|
+
INSERT INTO ${s}.session_metrics (
|
|
3574
|
+
session_id, snapshot_size_bytes,
|
|
3575
|
+
dehydration_count, hydration_count, lossy_handoff_count,
|
|
3576
|
+
tokens_input, tokens_output, tokens_cache_read, tokens_cache_write
|
|
3577
|
+
) VALUES (
|
|
3578
|
+
p_session_id, v_snapshot,
|
|
3579
|
+
v_dehydration, v_hydration, v_lossy,
|
|
3580
|
+
v_tokens_in, v_tokens_out, v_tokens_cread, v_tokens_cwrite
|
|
3581
|
+
)
|
|
3582
|
+
ON CONFLICT (session_id) DO UPDATE SET
|
|
3583
|
+
snapshot_size_bytes = CASE
|
|
3584
|
+
WHEN p_updates ? 'snapshotSizeBytes'
|
|
3585
|
+
THEN v_snapshot
|
|
3586
|
+
ELSE ${s}.session_metrics.snapshot_size_bytes
|
|
3587
|
+
END,
|
|
3588
|
+
dehydration_count = ${s}.session_metrics.dehydration_count + v_dehydration,
|
|
3589
|
+
hydration_count = ${s}.session_metrics.hydration_count + v_hydration,
|
|
3590
|
+
lossy_handoff_count = ${s}.session_metrics.lossy_handoff_count + v_lossy,
|
|
3591
|
+
tokens_input = ${s}.session_metrics.tokens_input + v_tokens_in,
|
|
3592
|
+
tokens_output = ${s}.session_metrics.tokens_output + v_tokens_out,
|
|
3593
|
+
tokens_cache_read = ${s}.session_metrics.tokens_cache_read + v_tokens_cread,
|
|
3594
|
+
tokens_cache_write = ${s}.session_metrics.tokens_cache_write + v_tokens_cwrite,
|
|
3595
|
+
last_dehydrated_at = CASE WHEN v_set_dehydrated THEN now() ELSE ${s}.session_metrics.last_dehydrated_at END,
|
|
3596
|
+
last_hydrated_at = CASE WHEN v_set_hydrated THEN now() ELSE ${s}.session_metrics.last_hydrated_at END,
|
|
3597
|
+
last_checkpoint_at = CASE WHEN v_set_checkpoint THEN now() ELSE ${s}.session_metrics.last_checkpoint_at END,
|
|
3598
|
+
updated_at = now();
|
|
3599
|
+
END;
|
|
3600
|
+
$$ LANGUAGE plpgsql;
|
|
3601
|
+
|
|
3602
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_prune_deleted_summaries(
|
|
3603
|
+
p_older_than TIMESTAMPTZ
|
|
3604
|
+
) RETURNS BIGINT AS $$
|
|
3605
|
+
DECLARE
|
|
3606
|
+
deleted_count BIGINT;
|
|
3607
|
+
BEGIN
|
|
3608
|
+
DELETE FROM ${s}.session_metrics
|
|
3609
|
+
WHERE deleted_at IS NOT NULL AND deleted_at < p_older_than;
|
|
3610
|
+
GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
|
3611
|
+
RETURN deleted_count;
|
|
3612
|
+
END;
|
|
3613
|
+
$$ LANGUAGE plpgsql;
|
|
3614
|
+
|
|
3615
|
+
ALTER TABLE ${s}.session_turn_metrics ADD COLUMN IF NOT EXISTS reasoning_effort TEXT;
|
|
3616
|
+
|
|
3617
|
+
INSERT INTO ${s}.session_turn_metrics (
|
|
3618
|
+
session_id, agent_id, model, reasoning_effort, turn_index,
|
|
3619
|
+
started_at, ended_at, duration_ms,
|
|
3620
|
+
tokens_input, tokens_output, tokens_cache_read, tokens_cache_write,
|
|
3621
|
+
tool_calls, tool_errors, result_type, error_message, worker_node_id
|
|
3622
|
+
)
|
|
3623
|
+
SELECT
|
|
3624
|
+
m.session_id,
|
|
3625
|
+
m.agent_id,
|
|
3626
|
+
m.model,
|
|
3627
|
+
m.reasoning_effort,
|
|
3628
|
+
0,
|
|
3629
|
+
COALESCE(m.created_at, now()),
|
|
3630
|
+
GREATEST(COALESCE(m.updated_at, m.created_at, now()), COALESCE(m.created_at, now())),
|
|
3631
|
+
GREATEST(0, FLOOR(EXTRACT(EPOCH FROM (GREATEST(COALESCE(m.updated_at, m.created_at, now()), COALESCE(m.created_at, now())) - COALESCE(m.created_at, now()))) * 1000)::INT),
|
|
3632
|
+
m.tokens_input,
|
|
3633
|
+
m.tokens_output,
|
|
3634
|
+
m.tokens_cache_read,
|
|
3635
|
+
m.tokens_cache_write,
|
|
3636
|
+
0,
|
|
3637
|
+
0,
|
|
3638
|
+
'legacy_summary',
|
|
3639
|
+
NULL,
|
|
3640
|
+
NULL
|
|
3641
|
+
FROM ${s}.session_metrics m
|
|
3642
|
+
WHERE (COALESCE(m.tokens_input, 0) <> 0
|
|
3643
|
+
OR COALESCE(m.tokens_output, 0) <> 0
|
|
3644
|
+
OR COALESCE(m.tokens_cache_read, 0) <> 0
|
|
3645
|
+
OR COALESCE(m.tokens_cache_write, 0) <> 0)
|
|
3646
|
+
AND NOT EXISTS (
|
|
3647
|
+
SELECT 1
|
|
3648
|
+
FROM ${s}.session_turn_metrics t
|
|
3649
|
+
WHERE t.session_id = m.session_id
|
|
3650
|
+
);
|
|
3651
|
+
|
|
3652
|
+
CREATE INDEX IF NOT EXISTS idx_${schema}_turn_metrics_session_model
|
|
3653
|
+
ON ${s}.session_turn_metrics(session_id, model, reasoning_effort);
|
|
3654
|
+
CREATE INDEX IF NOT EXISTS idx_${schema}_turn_metrics_model_effort_started
|
|
3655
|
+
ON ${s}.session_turn_metrics(model, reasoning_effort, started_at DESC);
|
|
3656
|
+
CREATE INDEX IF NOT EXISTS idx_${schema}_turn_metrics_agent_model_started
|
|
3657
|
+
ON ${s}.session_turn_metrics(agent_id, model, reasoning_effort, started_at DESC);
|
|
3658
|
+
|
|
3659
|
+
-- Signature/return-type changes require drop-then-create.
|
|
3660
|
+
DROP FUNCTION IF EXISTS ${s}.cms_insert_turn_metric(
|
|
3661
|
+
TEXT, TEXT, TEXT, INTEGER, TIMESTAMPTZ, TIMESTAMPTZ, INTEGER,
|
|
3662
|
+
BIGINT, BIGINT, BIGINT, BIGINT, INTEGER, INTEGER, TEXT, TEXT, TEXT);
|
|
3663
|
+
DROP FUNCTION IF EXISTS ${s}.cms_get_session_turn_metrics(TEXT, TIMESTAMPTZ, INT);
|
|
3664
|
+
|
|
3665
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_insert_turn_metric(
|
|
3666
|
+
p_session_id TEXT,
|
|
3667
|
+
p_agent_id TEXT,
|
|
3668
|
+
p_model TEXT,
|
|
3669
|
+
p_reasoning_effort TEXT,
|
|
3670
|
+
p_turn_index INTEGER,
|
|
3671
|
+
p_started_at TIMESTAMPTZ,
|
|
3672
|
+
p_ended_at TIMESTAMPTZ,
|
|
3673
|
+
p_duration_ms INTEGER,
|
|
3674
|
+
p_tokens_input BIGINT,
|
|
3675
|
+
p_tokens_output BIGINT,
|
|
3676
|
+
p_tokens_cache_read BIGINT,
|
|
3677
|
+
p_tokens_cache_write BIGINT,
|
|
3678
|
+
p_tool_calls INTEGER,
|
|
3679
|
+
p_tool_errors INTEGER,
|
|
3680
|
+
p_result_type TEXT,
|
|
3681
|
+
p_error_message TEXT,
|
|
3682
|
+
p_worker_node_id TEXT
|
|
3683
|
+
) RETURNS VOID AS $$
|
|
3684
|
+
BEGIN
|
|
3685
|
+
INSERT INTO ${s}.session_turn_metrics (
|
|
3686
|
+
session_id, agent_id, model, reasoning_effort, turn_index,
|
|
3687
|
+
started_at, ended_at, duration_ms,
|
|
3688
|
+
tokens_input, tokens_output, tokens_cache_read, tokens_cache_write,
|
|
3689
|
+
tool_calls, tool_errors, result_type, error_message, worker_node_id
|
|
3690
|
+
) VALUES (
|
|
3691
|
+
p_session_id, p_agent_id, p_model, NULLIF(BTRIM(p_reasoning_effort), ''), p_turn_index,
|
|
3692
|
+
p_started_at, p_ended_at, p_duration_ms,
|
|
3693
|
+
p_tokens_input, p_tokens_output, p_tokens_cache_read, p_tokens_cache_write,
|
|
3694
|
+
p_tool_calls, p_tool_errors, p_result_type, p_error_message, p_worker_node_id
|
|
3695
|
+
);
|
|
3696
|
+
END;
|
|
3697
|
+
$$ LANGUAGE plpgsql;
|
|
3698
|
+
|
|
3699
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_complete_turn_writeback(
|
|
3700
|
+
p_session_id TEXT,
|
|
3701
|
+
p_agent_id TEXT,
|
|
3702
|
+
p_model TEXT,
|
|
3703
|
+
p_reasoning_effort TEXT,
|
|
3704
|
+
p_turn_index INTEGER,
|
|
3705
|
+
p_started_at TIMESTAMPTZ,
|
|
3706
|
+
p_ended_at TIMESTAMPTZ,
|
|
3707
|
+
p_duration_ms INTEGER,
|
|
3708
|
+
p_tokens_input BIGINT,
|
|
3709
|
+
p_tokens_output BIGINT,
|
|
3710
|
+
p_tokens_cache_read BIGINT,
|
|
3711
|
+
p_tokens_cache_write BIGINT,
|
|
3712
|
+
p_tool_calls INTEGER,
|
|
3713
|
+
p_tool_errors INTEGER,
|
|
3714
|
+
p_tool_names TEXT[],
|
|
3715
|
+
p_result_type TEXT,
|
|
3716
|
+
p_error_message TEXT,
|
|
3717
|
+
p_worker_node_id TEXT,
|
|
3718
|
+
p_state TEXT,
|
|
3719
|
+
p_last_active_at TIMESTAMPTZ,
|
|
3720
|
+
p_last_error TEXT,
|
|
3721
|
+
p_wait_reason TEXT,
|
|
3722
|
+
p_current_iteration INTEGER
|
|
3723
|
+
) RETURNS VOID AS $$
|
|
3724
|
+
DECLARE
|
|
3725
|
+
v_reasoning_effort TEXT := NULLIF(BTRIM(p_reasoning_effort), '');
|
|
3726
|
+
v_ended_at TIMESTAMPTZ := COALESCE(p_ended_at, now());
|
|
3727
|
+
v_started_at TIMESTAMPTZ := COALESCE(p_started_at, v_ended_at);
|
|
3728
|
+
v_duration_ms INTEGER := GREATEST(0, COALESCE(p_duration_ms, FLOOR(EXTRACT(EPOCH FROM (v_ended_at - v_started_at)) * 1000)::INT));
|
|
3729
|
+
BEGIN
|
|
3730
|
+
UPDATE ${s}.sessions
|
|
3731
|
+
SET state = COALESCE(p_state, state),
|
|
3732
|
+
last_active_at = COALESCE(p_last_active_at, v_ended_at),
|
|
3733
|
+
current_iteration = COALESCE(p_current_iteration, current_iteration),
|
|
3734
|
+
last_error = p_last_error,
|
|
3735
|
+
wait_reason = p_wait_reason,
|
|
3736
|
+
updated_at = now()
|
|
3737
|
+
WHERE session_id = p_session_id;
|
|
3738
|
+
|
|
3739
|
+
INSERT INTO ${s}.session_metrics (
|
|
3740
|
+
session_id, agent_id, model, reasoning_effort,
|
|
3741
|
+
tokens_input, tokens_output, tokens_cache_read, tokens_cache_write
|
|
3742
|
+
) VALUES (
|
|
3743
|
+
p_session_id, p_agent_id, p_model, v_reasoning_effort,
|
|
3744
|
+
COALESCE(p_tokens_input, 0), COALESCE(p_tokens_output, 0),
|
|
3745
|
+
COALESCE(p_tokens_cache_read, 0), COALESCE(p_tokens_cache_write, 0)
|
|
3746
|
+
)
|
|
3747
|
+
ON CONFLICT (session_id) DO UPDATE SET
|
|
3748
|
+
agent_id = COALESCE(${s}.session_metrics.agent_id, EXCLUDED.agent_id),
|
|
3749
|
+
model = COALESCE(EXCLUDED.model, ${s}.session_metrics.model),
|
|
3750
|
+
reasoning_effort = COALESCE(EXCLUDED.reasoning_effort, ${s}.session_metrics.reasoning_effort),
|
|
3751
|
+
tokens_input = ${s}.session_metrics.tokens_input + EXCLUDED.tokens_input,
|
|
3752
|
+
tokens_output = ${s}.session_metrics.tokens_output + EXCLUDED.tokens_output,
|
|
3753
|
+
tokens_cache_read = ${s}.session_metrics.tokens_cache_read + EXCLUDED.tokens_cache_read,
|
|
3754
|
+
tokens_cache_write = ${s}.session_metrics.tokens_cache_write + EXCLUDED.tokens_cache_write,
|
|
3755
|
+
updated_at = now();
|
|
3756
|
+
|
|
3757
|
+
INSERT INTO ${s}.session_turn_metrics (
|
|
3758
|
+
session_id, agent_id, model, reasoning_effort, turn_index,
|
|
3759
|
+
started_at, ended_at, duration_ms,
|
|
3760
|
+
tokens_input, tokens_output, tokens_cache_read, tokens_cache_write,
|
|
3761
|
+
tool_calls, tool_errors, result_type, error_message, worker_node_id
|
|
3762
|
+
) VALUES (
|
|
3763
|
+
p_session_id, p_agent_id, p_model, v_reasoning_effort, COALESCE(p_turn_index, 0),
|
|
3764
|
+
v_started_at, v_ended_at, v_duration_ms,
|
|
3765
|
+
COALESCE(p_tokens_input, 0), COALESCE(p_tokens_output, 0),
|
|
3766
|
+
COALESCE(p_tokens_cache_read, 0), COALESCE(p_tokens_cache_write, 0),
|
|
3767
|
+
COALESCE(p_tool_calls, 0), COALESCE(p_tool_errors, 0),
|
|
3768
|
+
p_result_type, p_error_message, p_worker_node_id
|
|
3769
|
+
);
|
|
3770
|
+
|
|
3771
|
+
INSERT INTO ${s}.session_events (session_id, event_type, data, worker_node_id)
|
|
3772
|
+
VALUES (
|
|
3773
|
+
p_session_id,
|
|
3774
|
+
'session.turn_completed',
|
|
3775
|
+
jsonb_build_object(
|
|
3776
|
+
'iteration', COALESCE(p_turn_index, 0),
|
|
3777
|
+
'turnIndex', COALESCE(p_turn_index, 0),
|
|
3778
|
+
'model', p_model,
|
|
3779
|
+
'reasoningEffort', v_reasoning_effort,
|
|
3780
|
+
'startedAt', v_started_at,
|
|
3781
|
+
'endedAt', v_ended_at,
|
|
3782
|
+
'durationMs', v_duration_ms,
|
|
3783
|
+
'tokensInput', COALESCE(p_tokens_input, 0),
|
|
3784
|
+
'tokensOutput', COALESCE(p_tokens_output, 0),
|
|
3785
|
+
'tokensCacheRead', COALESCE(p_tokens_cache_read, 0),
|
|
3786
|
+
'tokensCacheWrite', COALESCE(p_tokens_cache_write, 0),
|
|
3787
|
+
'toolCalls', COALESCE(p_tool_calls, 0),
|
|
3788
|
+
'toolErrors', COALESCE(p_tool_errors, 0),
|
|
3789
|
+
'toolNames', to_jsonb(COALESCE(p_tool_names, ARRAY[]::TEXT[])),
|
|
3790
|
+
'resultType', p_result_type,
|
|
3791
|
+
'errorMessage', p_error_message,
|
|
3792
|
+
'workerNodeId', p_worker_node_id
|
|
3793
|
+
),
|
|
3794
|
+
p_worker_node_id
|
|
3795
|
+
);
|
|
3796
|
+
END;
|
|
3797
|
+
$$ LANGUAGE plpgsql;
|
|
3798
|
+
|
|
3799
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_get_session_turn_metrics(
|
|
3800
|
+
p_session_id TEXT,
|
|
3801
|
+
p_since TIMESTAMPTZ DEFAULT NULL,
|
|
3802
|
+
p_limit INT DEFAULT 200
|
|
3803
|
+
) RETURNS TABLE (
|
|
3804
|
+
id BIGINT,
|
|
3805
|
+
session_id TEXT,
|
|
3806
|
+
agent_id TEXT,
|
|
3807
|
+
model TEXT,
|
|
3808
|
+
reasoning_effort TEXT,
|
|
3809
|
+
turn_index INT,
|
|
3810
|
+
started_at TIMESTAMPTZ,
|
|
3811
|
+
ended_at TIMESTAMPTZ,
|
|
3812
|
+
duration_ms INT,
|
|
3813
|
+
tokens_input BIGINT,
|
|
3814
|
+
tokens_output BIGINT,
|
|
3815
|
+
tokens_cache_read BIGINT,
|
|
3816
|
+
tokens_cache_write BIGINT,
|
|
3817
|
+
tool_calls INT,
|
|
3818
|
+
tool_errors INT,
|
|
3819
|
+
result_type TEXT,
|
|
3820
|
+
error_message TEXT,
|
|
3821
|
+
worker_node_id TEXT,
|
|
3822
|
+
created_at TIMESTAMPTZ
|
|
3823
|
+
) AS $$
|
|
3824
|
+
DECLARE
|
|
3825
|
+
v_limit INT := GREATEST(1, LEAST(COALESCE(p_limit, 200), 500));
|
|
3826
|
+
BEGIN
|
|
3827
|
+
RETURN QUERY
|
|
3828
|
+
SELECT
|
|
3829
|
+
t.id, t.session_id, t.agent_id, t.model, t.reasoning_effort, t.turn_index,
|
|
3830
|
+
t.started_at, t.ended_at, t.duration_ms,
|
|
3831
|
+
t.tokens_input, t.tokens_output, t.tokens_cache_read, t.tokens_cache_write,
|
|
3832
|
+
t.tool_calls, t.tool_errors, t.result_type, t.error_message,
|
|
3833
|
+
t.worker_node_id, t.created_at
|
|
3834
|
+
FROM ${s}.session_turn_metrics t
|
|
3835
|
+
WHERE t.session_id = p_session_id
|
|
3836
|
+
AND (p_since IS NULL OR t.started_at >= p_since)
|
|
3837
|
+
ORDER BY t.turn_index DESC, t.id DESC
|
|
3838
|
+
LIMIT v_limit;
|
|
3839
|
+
END;
|
|
3840
|
+
$$ LANGUAGE plpgsql;
|
|
3841
|
+
|
|
3842
|
+
-- Per-session token totals grouped by model:effort label, with per-bucket turn count.
|
|
3843
|
+
CREATE OR REPLACE FUNCTION ${s}.cms_get_session_tokens_by_model(
|
|
3844
|
+
p_session_id TEXT
|
|
3845
|
+
) RETURNS TABLE (
|
|
3846
|
+
model TEXT,
|
|
3847
|
+
turn_count BIGINT,
|
|
3848
|
+
total_tokens_input BIGINT,
|
|
3849
|
+
total_tokens_output BIGINT,
|
|
3850
|
+
total_tokens_cache_read BIGINT,
|
|
3851
|
+
total_tokens_cache_write BIGINT
|
|
3852
|
+
) AS $$
|
|
3853
|
+
BEGIN
|
|
3854
|
+
RETURN QUERY
|
|
3855
|
+
SELECT
|
|
3856
|
+
norm.label AS model,
|
|
3857
|
+
COUNT(*)::bigint AS turn_count,
|
|
3858
|
+
COALESCE(SUM(norm.tokens_input), 0)::bigint AS total_tokens_input,
|
|
3859
|
+
COALESCE(SUM(norm.tokens_output), 0)::bigint AS total_tokens_output,
|
|
3860
|
+
COALESCE(SUM(norm.tokens_cache_read), 0)::bigint AS total_tokens_cache_read,
|
|
3861
|
+
COALESCE(SUM(norm.tokens_cache_write), 0)::bigint AS total_tokens_cache_write
|
|
3862
|
+
FROM (
|
|
3863
|
+
SELECT
|
|
3864
|
+
CASE
|
|
3865
|
+
WHEN NULLIF(BTRIM(t.reasoning_effort), '') IS NULL
|
|
3866
|
+
THEN COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)')
|
|
3867
|
+
ELSE COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)') || ':' || BTRIM(t.reasoning_effort)
|
|
3868
|
+
END AS label,
|
|
3869
|
+
t.tokens_input, t.tokens_output, t.tokens_cache_read, t.tokens_cache_write
|
|
3870
|
+
FROM ${s}.session_turn_metrics t
|
|
3871
|
+
WHERE t.session_id = p_session_id
|
|
3872
|
+
) norm
|
|
3873
|
+
GROUP BY norm.label
|
|
3874
|
+
ORDER BY COALESCE(SUM(norm.tokens_input), 0) DESC, norm.label;
|
|
3875
|
+
END;
|
|
3876
|
+
$$ LANGUAGE plpgsql;
|
|
3877
|
+
|
|
3878
|
+
DROP FUNCTION IF EXISTS ${s}.cms_get_session_tree_stats_by_model(TEXT);
|
|
3879
|
+
CREATE FUNCTION ${s}.cms_get_session_tree_stats_by_model(
|
|
3880
|
+
p_session_id TEXT
|
|
3881
|
+
) RETURNS TABLE (
|
|
3882
|
+
model TEXT,
|
|
3883
|
+
session_count INT,
|
|
3884
|
+
turn_count BIGINT,
|
|
3885
|
+
total_tokens_input BIGINT,
|
|
3886
|
+
total_tokens_output BIGINT,
|
|
3887
|
+
total_tokens_cache_read BIGINT,
|
|
3888
|
+
total_tokens_cache_write BIGINT,
|
|
3889
|
+
total_snapshot_size_bytes BIGINT
|
|
3890
|
+
) AS $$
|
|
3891
|
+
BEGIN
|
|
3892
|
+
RETURN QUERY
|
|
3893
|
+
WITH RECURSIVE tree AS (
|
|
3894
|
+
SELECT m.session_id FROM ${s}.session_metrics m
|
|
3895
|
+
WHERE m.session_id = p_session_id
|
|
3896
|
+
UNION ALL
|
|
3897
|
+
SELECT m.session_id FROM ${s}.session_metrics m
|
|
3898
|
+
INNER JOIN tree tr ON m.parent_session_id = tr.session_id
|
|
3899
|
+
), token_rows AS (
|
|
3900
|
+
SELECT
|
|
3901
|
+
CASE
|
|
3902
|
+
WHEN NULLIF(BTRIM(t.reasoning_effort), '') IS NULL
|
|
3903
|
+
THEN COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)')
|
|
3904
|
+
ELSE COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)') || ':' || BTRIM(t.reasoning_effort)
|
|
3905
|
+
END AS model_label,
|
|
3906
|
+
t.session_id,
|
|
3907
|
+
t.tokens_input,
|
|
3908
|
+
t.tokens_output,
|
|
3909
|
+
t.tokens_cache_read,
|
|
3910
|
+
t.tokens_cache_write
|
|
3911
|
+
FROM ${s}.session_turn_metrics t
|
|
3912
|
+
INNER JOIN tree tr ON tr.session_id = t.session_id
|
|
3913
|
+
UNION ALL
|
|
3914
|
+
SELECT
|
|
3915
|
+
CASE
|
|
3916
|
+
WHEN NULLIF(BTRIM(m.reasoning_effort), '') IS NULL
|
|
3917
|
+
THEN COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)')
|
|
3918
|
+
ELSE COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)') || ':' || BTRIM(m.reasoning_effort)
|
|
3919
|
+
END AS model_label,
|
|
3920
|
+
m.session_id,
|
|
3921
|
+
m.tokens_input,
|
|
3922
|
+
m.tokens_output,
|
|
3923
|
+
m.tokens_cache_read,
|
|
3924
|
+
m.tokens_cache_write
|
|
3925
|
+
FROM ${s}.session_metrics m
|
|
3926
|
+
INNER JOIN tree tr ON tr.session_id = m.session_id
|
|
3927
|
+
WHERE NOT EXISTS (
|
|
3928
|
+
SELECT 1 FROM ${s}.session_turn_metrics existing
|
|
3929
|
+
WHERE existing.session_id = m.session_id
|
|
3930
|
+
)
|
|
3931
|
+
), token_rollup AS (
|
|
3932
|
+
SELECT
|
|
3933
|
+
model_label,
|
|
3934
|
+
COUNT(DISTINCT session_id)::INT AS session_count,
|
|
3935
|
+
COUNT(*)::BIGINT AS turn_count,
|
|
3936
|
+
COALESCE(SUM(tokens_input), 0)::BIGINT AS total_tokens_input,
|
|
3937
|
+
COALESCE(SUM(tokens_output), 0)::BIGINT AS total_tokens_output,
|
|
3938
|
+
COALESCE(SUM(tokens_cache_read), 0)::BIGINT AS total_tokens_cache_read,
|
|
3939
|
+
COALESCE(SUM(tokens_cache_write), 0)::BIGINT AS total_tokens_cache_write
|
|
3940
|
+
FROM token_rows
|
|
3941
|
+
GROUP BY model_label
|
|
3942
|
+
), metric_rollup AS (
|
|
3943
|
+
SELECT
|
|
3944
|
+
CASE
|
|
3945
|
+
WHEN NULLIF(BTRIM(m.reasoning_effort), '') IS NULL
|
|
3946
|
+
THEN COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)')
|
|
3947
|
+
ELSE COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)') || ':' || BTRIM(m.reasoning_effort)
|
|
3948
|
+
END AS model_label,
|
|
3949
|
+
COUNT(*)::INT AS session_count,
|
|
3950
|
+
COALESCE(SUM(m.snapshot_size_bytes), 0)::BIGINT AS total_snapshot_size_bytes
|
|
3951
|
+
FROM ${s}.session_metrics m
|
|
3952
|
+
INNER JOIN tree tr ON tr.session_id = m.session_id
|
|
3953
|
+
GROUP BY model_label
|
|
3954
|
+
)
|
|
3955
|
+
SELECT
|
|
3956
|
+
COALESCE(t.model_label, m.model_label) AS model,
|
|
3957
|
+
COALESCE(t.session_count, m.session_count, 0)::INT AS session_count,
|
|
3958
|
+
COALESCE(t.turn_count, 0)::BIGINT AS turn_count,
|
|
3959
|
+
COALESCE(t.total_tokens_input, 0)::BIGINT AS total_tokens_input,
|
|
3960
|
+
COALESCE(t.total_tokens_output, 0)::BIGINT AS total_tokens_output,
|
|
3961
|
+
COALESCE(t.total_tokens_cache_read, 0)::BIGINT AS total_tokens_cache_read,
|
|
3962
|
+
COALESCE(t.total_tokens_cache_write, 0)::BIGINT AS total_tokens_cache_write,
|
|
3963
|
+
COALESCE(m.total_snapshot_size_bytes, 0)::BIGINT AS total_snapshot_size_bytes
|
|
3964
|
+
FROM token_rollup t
|
|
3965
|
+
FULL OUTER JOIN metric_rollup m ON m.model_label = t.model_label
|
|
3966
|
+
ORDER BY COALESCE(t.total_tokens_input, 0) DESC, COALESCE(t.model_label, m.model_label);
|
|
3967
|
+
END;
|
|
3968
|
+
$$ LANGUAGE plpgsql;
|
|
3969
|
+
|
|
3970
|
+
DROP FUNCTION IF EXISTS ${s}.cms_get_fleet_stats_by_agent(BOOLEAN, TIMESTAMPTZ);
|
|
3971
|
+
CREATE FUNCTION ${s}.cms_get_fleet_stats_by_agent(
|
|
3972
|
+
p_include_deleted BOOLEAN,
|
|
3973
|
+
p_since TIMESTAMPTZ
|
|
3974
|
+
) RETURNS TABLE (
|
|
3975
|
+
agent_id TEXT,
|
|
3976
|
+
model TEXT,
|
|
3977
|
+
session_count INT,
|
|
3978
|
+
turn_count BIGINT,
|
|
3979
|
+
total_snapshot_size_bytes BIGINT,
|
|
3980
|
+
total_dehydration_count INT,
|
|
3981
|
+
total_hydration_count INT,
|
|
3982
|
+
total_lossy_handoff_count INT,
|
|
3983
|
+
total_tokens_input BIGINT,
|
|
3984
|
+
total_tokens_output BIGINT,
|
|
3985
|
+
total_tokens_cache_read BIGINT,
|
|
3986
|
+
total_tokens_cache_write BIGINT
|
|
3987
|
+
) AS $$
|
|
3988
|
+
BEGIN
|
|
3989
|
+
RETURN QUERY
|
|
3990
|
+
WITH token_rows AS (
|
|
3991
|
+
SELECT
|
|
3992
|
+
COALESCE(t.agent_id, m.agent_id, sess.agent_id) AS agent_id_value,
|
|
3993
|
+
CASE
|
|
3994
|
+
WHEN NULLIF(BTRIM(t.reasoning_effort), '') IS NULL
|
|
3995
|
+
THEN COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)')
|
|
3996
|
+
ELSE COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)') || ':' || BTRIM(t.reasoning_effort)
|
|
3997
|
+
END AS model_label,
|
|
3998
|
+
t.session_id,
|
|
3999
|
+
t.tokens_input,
|
|
4000
|
+
t.tokens_output,
|
|
4001
|
+
t.tokens_cache_read,
|
|
4002
|
+
t.tokens_cache_write
|
|
4003
|
+
FROM ${s}.session_turn_metrics t
|
|
4004
|
+
INNER JOIN ${s}.sessions sess ON sess.session_id = t.session_id
|
|
4005
|
+
LEFT JOIN ${s}.session_metrics m ON m.session_id = t.session_id
|
|
4006
|
+
WHERE (p_include_deleted OR sess.deleted_at IS NULL)
|
|
4007
|
+
AND (p_since IS NULL OR t.started_at >= p_since)
|
|
4008
|
+
UNION ALL
|
|
4009
|
+
SELECT
|
|
4010
|
+
COALESCE(m.agent_id, sess.agent_id) AS agent_id_value,
|
|
4011
|
+
CASE
|
|
4012
|
+
WHEN NULLIF(BTRIM(m.reasoning_effort), '') IS NULL
|
|
4013
|
+
THEN COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)')
|
|
4014
|
+
ELSE COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)') || ':' || BTRIM(m.reasoning_effort)
|
|
4015
|
+
END AS model_label,
|
|
4016
|
+
m.session_id,
|
|
4017
|
+
m.tokens_input,
|
|
4018
|
+
m.tokens_output,
|
|
4019
|
+
m.tokens_cache_read,
|
|
4020
|
+
m.tokens_cache_write
|
|
4021
|
+
FROM ${s}.session_metrics m
|
|
4022
|
+
INNER JOIN ${s}.sessions sess ON sess.session_id = m.session_id
|
|
4023
|
+
WHERE (p_include_deleted OR m.deleted_at IS NULL)
|
|
4024
|
+
AND (p_since IS NULL OR m.created_at >= p_since)
|
|
4025
|
+
AND NOT EXISTS (
|
|
4026
|
+
SELECT 1 FROM ${s}.session_turn_metrics existing
|
|
4027
|
+
WHERE existing.session_id = m.session_id
|
|
4028
|
+
)
|
|
4029
|
+
), token_rollup AS (
|
|
4030
|
+
SELECT
|
|
4031
|
+
agent_id_value,
|
|
4032
|
+
model_label,
|
|
4033
|
+
COUNT(DISTINCT session_id)::INT AS session_count,
|
|
4034
|
+
COUNT(*)::BIGINT AS turn_count,
|
|
4035
|
+
COALESCE(SUM(tokens_input), 0)::BIGINT AS total_tokens_input,
|
|
4036
|
+
COALESCE(SUM(tokens_output), 0)::BIGINT AS total_tokens_output,
|
|
4037
|
+
COALESCE(SUM(tokens_cache_read), 0)::BIGINT AS total_tokens_cache_read,
|
|
4038
|
+
COALESCE(SUM(tokens_cache_write), 0)::BIGINT AS total_tokens_cache_write
|
|
4039
|
+
FROM token_rows
|
|
4040
|
+
GROUP BY agent_id_value, model_label
|
|
4041
|
+
), metric_rollup AS (
|
|
4042
|
+
SELECT
|
|
4043
|
+
m.agent_id AS agent_id_value,
|
|
4044
|
+
CASE
|
|
4045
|
+
WHEN NULLIF(BTRIM(m.reasoning_effort), '') IS NULL
|
|
4046
|
+
THEN COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)')
|
|
4047
|
+
ELSE COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)') || ':' || BTRIM(m.reasoning_effort)
|
|
4048
|
+
END AS model_label,
|
|
4049
|
+
COUNT(*)::INT AS session_count,
|
|
4050
|
+
COALESCE(SUM(m.snapshot_size_bytes), 0)::BIGINT AS total_snapshot_size_bytes,
|
|
4051
|
+
COALESCE(SUM(m.dehydration_count), 0)::INT AS total_dehydration_count,
|
|
4052
|
+
COALESCE(SUM(m.hydration_count), 0)::INT AS total_hydration_count,
|
|
4053
|
+
COALESCE(SUM(m.lossy_handoff_count), 0)::INT AS total_lossy_handoff_count
|
|
4054
|
+
FROM ${s}.session_metrics m
|
|
4055
|
+
WHERE (p_include_deleted OR m.deleted_at IS NULL)
|
|
4056
|
+
AND (p_since IS NULL OR m.created_at >= p_since)
|
|
4057
|
+
GROUP BY m.agent_id, model_label
|
|
4058
|
+
)
|
|
4059
|
+
SELECT
|
|
4060
|
+
COALESCE(t.agent_id_value, m.agent_id_value) AS agent_id,
|
|
4061
|
+
COALESCE(t.model_label, m.model_label) AS model,
|
|
4062
|
+
COALESCE(t.session_count, m.session_count, 0)::INT AS session_count,
|
|
4063
|
+
COALESCE(t.turn_count, 0)::BIGINT AS turn_count,
|
|
4064
|
+
COALESCE(m.total_snapshot_size_bytes, 0)::BIGINT AS total_snapshot_size_bytes,
|
|
4065
|
+
COALESCE(m.total_dehydration_count, 0)::INT AS total_dehydration_count,
|
|
4066
|
+
COALESCE(m.total_hydration_count, 0)::INT AS total_hydration_count,
|
|
4067
|
+
COALESCE(m.total_lossy_handoff_count, 0)::INT AS total_lossy_handoff_count,
|
|
4068
|
+
COALESCE(t.total_tokens_input, 0)::BIGINT AS total_tokens_input,
|
|
4069
|
+
COALESCE(t.total_tokens_output, 0)::BIGINT AS total_tokens_output,
|
|
4070
|
+
COALESCE(t.total_tokens_cache_read, 0)::BIGINT AS total_tokens_cache_read,
|
|
4071
|
+
COALESCE(t.total_tokens_cache_write, 0)::BIGINT AS total_tokens_cache_write
|
|
4072
|
+
FROM token_rollup t
|
|
4073
|
+
FULL OUTER JOIN metric_rollup m
|
|
4074
|
+
ON m.agent_id_value IS NOT DISTINCT FROM t.agent_id_value
|
|
4075
|
+
AND m.model_label = t.model_label
|
|
4076
|
+
ORDER BY COALESCE(t.total_tokens_input, 0) DESC, COALESCE(t.model_label, m.model_label);
|
|
4077
|
+
END;
|
|
4078
|
+
$$ LANGUAGE plpgsql;
|
|
4079
|
+
|
|
4080
|
+
DROP FUNCTION IF EXISTS ${s}.cms_get_user_stats_by_model(BOOLEAN, TIMESTAMPTZ);
|
|
4081
|
+
CREATE FUNCTION ${s}.cms_get_user_stats_by_model(
|
|
4082
|
+
p_include_deleted BOOLEAN,
|
|
4083
|
+
p_since TIMESTAMPTZ
|
|
4084
|
+
) RETURNS TABLE (
|
|
4085
|
+
owner_kind TEXT,
|
|
4086
|
+
owner_provider TEXT,
|
|
4087
|
+
owner_subject TEXT,
|
|
4088
|
+
owner_email TEXT,
|
|
4089
|
+
owner_display_name TEXT,
|
|
4090
|
+
model TEXT,
|
|
4091
|
+
session_ids TEXT[],
|
|
4092
|
+
session_count INT,
|
|
4093
|
+
turn_count BIGINT,
|
|
4094
|
+
total_snapshot_size_bytes BIGINT,
|
|
4095
|
+
total_dehydration_count INT,
|
|
4096
|
+
total_hydration_count INT,
|
|
4097
|
+
total_lossy_handoff_count INT,
|
|
4098
|
+
total_tokens_input BIGINT,
|
|
4099
|
+
total_tokens_output BIGINT,
|
|
4100
|
+
total_tokens_cache_read BIGINT,
|
|
4101
|
+
total_tokens_cache_write BIGINT,
|
|
4102
|
+
earliest_session_created_at TIMESTAMPTZ
|
|
4103
|
+
) AS $$
|
|
4104
|
+
BEGIN
|
|
4105
|
+
RETURN QUERY
|
|
4106
|
+
WITH session_owner AS (
|
|
4107
|
+
SELECT
|
|
4108
|
+
sess.session_id,
|
|
4109
|
+
CASE
|
|
4110
|
+
WHEN sess.is_system THEN 'system'
|
|
4111
|
+
WHEN u.user_id IS NULL THEN 'unowned'
|
|
4112
|
+
ELSE 'user'
|
|
4113
|
+
END::TEXT AS owner_kind_value,
|
|
4114
|
+
u.provider AS owner_provider_value,
|
|
4115
|
+
u.subject AS owner_subject_value,
|
|
4116
|
+
u.email AS owner_email_value,
|
|
4117
|
+
u.display_name AS owner_display_name_value
|
|
4118
|
+
FROM ${s}.sessions sess
|
|
4119
|
+
LEFT JOIN ${s}.session_owners so ON so.session_id = sess.session_id
|
|
4120
|
+
LEFT JOIN ${s}.users u ON u.user_id = so.user_id
|
|
4121
|
+
), token_rows AS (
|
|
4122
|
+
SELECT
|
|
4123
|
+
so.owner_kind_value, so.owner_provider_value, so.owner_subject_value, so.owner_email_value, so.owner_display_name_value,
|
|
4124
|
+
CASE
|
|
4125
|
+
WHEN NULLIF(BTRIM(t.reasoning_effort), '') IS NULL
|
|
4126
|
+
THEN COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)')
|
|
4127
|
+
ELSE COALESCE(NULLIF(BTRIM(t.model), ''), '(unknown)') || ':' || BTRIM(t.reasoning_effort)
|
|
4128
|
+
END AS model_label,
|
|
4129
|
+
t.session_id,
|
|
4130
|
+
t.tokens_input, t.tokens_output, t.tokens_cache_read, t.tokens_cache_write
|
|
4131
|
+
FROM ${s}.session_turn_metrics t
|
|
4132
|
+
INNER JOIN ${s}.sessions sess ON sess.session_id = t.session_id
|
|
4133
|
+
INNER JOIN session_owner so ON so.session_id = t.session_id
|
|
4134
|
+
WHERE (p_include_deleted OR sess.deleted_at IS NULL)
|
|
4135
|
+
AND (p_since IS NULL OR t.started_at >= p_since)
|
|
4136
|
+
UNION ALL
|
|
4137
|
+
SELECT
|
|
4138
|
+
so.owner_kind_value, so.owner_provider_value, so.owner_subject_value, so.owner_email_value, so.owner_display_name_value,
|
|
4139
|
+
CASE
|
|
4140
|
+
WHEN NULLIF(BTRIM(m.reasoning_effort), '') IS NULL
|
|
4141
|
+
THEN COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)')
|
|
4142
|
+
ELSE COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)') || ':' || BTRIM(m.reasoning_effort)
|
|
4143
|
+
END AS model_label,
|
|
4144
|
+
m.session_id,
|
|
4145
|
+
m.tokens_input, m.tokens_output, m.tokens_cache_read, m.tokens_cache_write
|
|
4146
|
+
FROM ${s}.session_metrics m
|
|
4147
|
+
INNER JOIN ${s}.sessions sess ON sess.session_id = m.session_id
|
|
4148
|
+
INNER JOIN session_owner so ON so.session_id = m.session_id
|
|
4149
|
+
WHERE (p_include_deleted OR m.deleted_at IS NULL)
|
|
4150
|
+
AND (p_since IS NULL OR m.created_at >= p_since)
|
|
4151
|
+
AND NOT EXISTS (
|
|
4152
|
+
SELECT 1 FROM ${s}.session_turn_metrics existing
|
|
4153
|
+
WHERE existing.session_id = m.session_id
|
|
4154
|
+
)
|
|
4155
|
+
), token_rollup AS (
|
|
4156
|
+
SELECT
|
|
4157
|
+
owner_kind_value, owner_provider_value, owner_subject_value, owner_email_value, owner_display_name_value, model_label,
|
|
4158
|
+
ARRAY_AGG(DISTINCT session_id ORDER BY session_id) AS session_ids,
|
|
4159
|
+
COUNT(DISTINCT session_id)::INT AS session_count,
|
|
4160
|
+
COUNT(*)::BIGINT AS turn_count,
|
|
4161
|
+
COALESCE(SUM(tokens_input), 0)::BIGINT AS total_tokens_input,
|
|
4162
|
+
COALESCE(SUM(tokens_output), 0)::BIGINT AS total_tokens_output,
|
|
4163
|
+
COALESCE(SUM(tokens_cache_read), 0)::BIGINT AS total_tokens_cache_read,
|
|
4164
|
+
COALESCE(SUM(tokens_cache_write), 0)::BIGINT AS total_tokens_cache_write
|
|
4165
|
+
FROM token_rows
|
|
4166
|
+
GROUP BY owner_kind_value, owner_provider_value, owner_subject_value, owner_email_value, owner_display_name_value, model_label
|
|
4167
|
+
), metric_rollup AS (
|
|
4168
|
+
SELECT
|
|
4169
|
+
so.owner_kind_value, so.owner_provider_value, so.owner_subject_value, so.owner_email_value, so.owner_display_name_value,
|
|
4170
|
+
CASE
|
|
4171
|
+
WHEN NULLIF(BTRIM(m.reasoning_effort), '') IS NULL
|
|
4172
|
+
THEN COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)')
|
|
4173
|
+
ELSE COALESCE(NULLIF(BTRIM(m.model), ''), '(unknown)') || ':' || BTRIM(m.reasoning_effort)
|
|
4174
|
+
END AS model_label,
|
|
4175
|
+
ARRAY_AGG(DISTINCT m.session_id ORDER BY m.session_id) AS session_ids,
|
|
4176
|
+
COUNT(*)::INT AS session_count,
|
|
4177
|
+
COALESCE(SUM(m.snapshot_size_bytes), 0)::BIGINT AS total_snapshot_size_bytes,
|
|
4178
|
+
COALESCE(SUM(m.dehydration_count), 0)::INT AS total_dehydration_count,
|
|
4179
|
+
COALESCE(SUM(m.hydration_count), 0)::INT AS total_hydration_count,
|
|
4180
|
+
COALESCE(SUM(m.lossy_handoff_count), 0)::INT AS total_lossy_handoff_count,
|
|
4181
|
+
MIN(m.created_at) AS earliest_session_created_at
|
|
4182
|
+
FROM ${s}.session_metrics m
|
|
4183
|
+
INNER JOIN ${s}.sessions sess ON sess.session_id = m.session_id
|
|
4184
|
+
INNER JOIN session_owner so ON so.session_id = m.session_id
|
|
4185
|
+
WHERE (p_include_deleted OR m.deleted_at IS NULL)
|
|
4186
|
+
AND (p_since IS NULL OR m.created_at >= p_since)
|
|
4187
|
+
GROUP BY so.owner_kind_value, so.owner_provider_value, so.owner_subject_value, so.owner_email_value, so.owner_display_name_value, model_label
|
|
4188
|
+
)
|
|
4189
|
+
SELECT
|
|
4190
|
+
COALESCE(t.owner_kind_value, m.owner_kind_value) AS owner_kind,
|
|
4191
|
+
COALESCE(t.owner_provider_value, m.owner_provider_value) AS owner_provider,
|
|
4192
|
+
COALESCE(t.owner_subject_value, m.owner_subject_value) AS owner_subject,
|
|
4193
|
+
COALESCE(t.owner_email_value, m.owner_email_value) AS owner_email,
|
|
4194
|
+
COALESCE(t.owner_display_name_value, m.owner_display_name_value) AS owner_display_name,
|
|
4195
|
+
COALESCE(t.model_label, m.model_label) AS model,
|
|
4196
|
+
ARRAY(SELECT DISTINCT unnest(COALESCE(t.session_ids, ARRAY[]::TEXT[]) || COALESCE(m.session_ids, ARRAY[]::TEXT[])) ORDER BY 1) AS session_ids,
|
|
4197
|
+
COALESCE(t.session_count, m.session_count, 0)::INT AS session_count,
|
|
4198
|
+
COALESCE(t.turn_count, 0)::BIGINT AS turn_count,
|
|
4199
|
+
COALESCE(m.total_snapshot_size_bytes, 0)::BIGINT AS total_snapshot_size_bytes,
|
|
4200
|
+
COALESCE(m.total_dehydration_count, 0)::INT AS total_dehydration_count,
|
|
4201
|
+
COALESCE(m.total_hydration_count, 0)::INT AS total_hydration_count,
|
|
4202
|
+
COALESCE(m.total_lossy_handoff_count, 0)::INT AS total_lossy_handoff_count,
|
|
4203
|
+
COALESCE(t.total_tokens_input, 0)::BIGINT AS total_tokens_input,
|
|
4204
|
+
COALESCE(t.total_tokens_output, 0)::BIGINT AS total_tokens_output,
|
|
4205
|
+
COALESCE(t.total_tokens_cache_read, 0)::BIGINT AS total_tokens_cache_read,
|
|
4206
|
+
COALESCE(t.total_tokens_cache_write, 0)::BIGINT AS total_tokens_cache_write,
|
|
4207
|
+
m.earliest_session_created_at AS earliest_session_created_at
|
|
4208
|
+
FROM token_rollup t
|
|
4209
|
+
FULL OUTER JOIN metric_rollup m
|
|
4210
|
+
ON m.owner_kind_value = t.owner_kind_value
|
|
4211
|
+
AND m.owner_provider_value IS NOT DISTINCT FROM t.owner_provider_value
|
|
4212
|
+
AND m.owner_subject_value IS NOT DISTINCT FROM t.owner_subject_value
|
|
4213
|
+
AND m.model_label = t.model_label
|
|
4214
|
+
ORDER BY COALESCE(t.total_tokens_input, 0) DESC, COALESCE(t.model_label, m.model_label);
|
|
4215
|
+
END;
|
|
4216
|
+
$$ LANGUAGE plpgsql;
|
|
4217
|
+
`;
|
|
4218
|
+
}
|
|
4219
|
+
// ─── Migration 0023: Turn Metrics Stats Fallbacks And Group Owner Patch ───
|
|
4220
|
+
function migration_0023_turn_metrics_stats_fallbacks_and_group_owner_patch(schema) {
|
|
4221
|
+
// Migration 0022 was deployed before these stored-procedure fixes landed.
|
|
4222
|
+
// Its SQL is idempotent, so reapplying the corrected procedure layer under
|
|
4223
|
+
// a new version updates already-migrated schemas without requiring a reset.
|
|
4224
|
+
return migration_0022_turn_metrics_reasoning_effort(schema);
|
|
4225
|
+
}
|
|
3387
4226
|
//# sourceMappingURL=cms-migrations.js.map
|