@sixb/sqlite 0.1.26 → 0.2.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/dist/agents/agent-storage.d.ts +8 -3
- package/dist/agents/agent-storage.d.ts.map +1 -1
- package/dist/agents/computers.d.ts +22 -0
- package/dist/agents/computers.d.ts.map +1 -0
- package/dist/agents/rows.d.ts +3 -0
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/runs.d.ts.map +1 -1
- package/dist/agents/threads.d.ts +3 -1
- package/dist/agents/threads.d.ts.map +1 -1
- package/dist/agents/token-rates.d.ts +13 -0
- package/dist/agents/token-rates.d.ts.map +1 -0
- package/dist/ai-accounting-filters.d.ts +14 -0
- package/dist/ai-accounting-filters.d.ts.map +1 -0
- package/dist/ai-cost-groups.d.ts +1 -1
- package/dist/ai-cost-groups.d.ts.map +1 -1
- package/dist/ai-cost-storage.d.ts.map +1 -1
- package/dist/index.js +414 -69
- package/dist/index.js.map +16 -13
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/query-compiler.d.ts.map +1 -1
- package/dist/ontology-storage/commits.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts +2 -1
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/agents/agent-storage.ts +10 -3
- package/src/agents/computers.ts +112 -0
- package/src/agents/rows.ts +9 -1
- package/src/agents/runs.ts +25 -3
- package/src/agents/threads.ts +100 -22
- package/src/agents/token-rates.ts +90 -0
- package/src/ai-accounting-filters.ts +51 -0
- package/src/ai-cost-groups.ts +52 -14
- package/src/ai-cost-storage.ts +101 -39
- package/src/migrations/082-agent-token-rates.sql +17 -0
- package/src/migrations/083-agent-computer-sessions.sql +27 -0
- package/src/migrations.ts +6 -0
- package/src/objects/query-compiler.ts +26 -15
- package/src/ontology-storage/commits.ts +9 -0
- package/src/ontology-storage/materializations.ts +18 -1
package/dist/index.js
CHANGED
|
@@ -5975,6 +5975,56 @@ ALTER TABLE agent_threads ADD COLUMN runs_on TEXT CHECK (runs_on IS NULL OR runs
|
|
|
5975
5975
|
ALTER TABLE agent_threads ADD COLUMN computer_id TEXT;
|
|
5976
5976
|
`;
|
|
5977
5977
|
|
|
5978
|
+
// src/migrations/082-agent-token-rates.sql
|
|
5979
|
+
var _082_agent_token_rates_default = `-- What each model's tokenizer measured on a project's agent runs, one row per run: the bytes of a
|
|
5980
|
+
-- request's text as the Agent's context estimator weighs them, against the text tokens the
|
|
5981
|
+
-- provider counted. A record deletes the model's rows past its newest 20, so the table stays small.
|
|
5982
|
+
-- Timestamps are ISO-8601 UTC text and compare lexicographically.
|
|
5983
|
+
CREATE TABLE agent_token_rates (
|
|
5984
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
5985
|
+
run_id TEXT NOT NULL CHECK (length(trim(run_id)) > 0),
|
|
5986
|
+
provider_id TEXT NOT NULL CHECK (length(trim(provider_id)) > 0),
|
|
5987
|
+
model_id TEXT NOT NULL CHECK (length(trim(model_id)) > 0),
|
|
5988
|
+
bytes INTEGER NOT NULL CHECK (bytes > 0),
|
|
5989
|
+
tokens INTEGER NOT NULL CHECK (tokens > 0),
|
|
5990
|
+
measured_at TEXT NOT NULL,
|
|
5991
|
+
PRIMARY KEY (project_id, run_id)
|
|
5992
|
+
);
|
|
5993
|
+
|
|
5994
|
+
CREATE INDEX idx_agent_token_rates_model
|
|
5995
|
+
ON agent_token_rates (project_id, provider_id, model_id, measured_at DESC, run_id DESC);
|
|
5996
|
+
`;
|
|
5997
|
+
|
|
5998
|
+
// src/migrations/083-agent-computer-sessions.sql
|
|
5999
|
+
var _083_agent_computer_sessions_default = `-- Where a computer's thread runs: the computer's name and the folder there, beside its id. A
|
|
6000
|
+
-- computer kept before folders were has none until its owner moves the thread.
|
|
6001
|
+
ALTER TABLE agent_threads ADD COLUMN computer_name TEXT;
|
|
6002
|
+
ALTER TABLE agent_threads ADD COLUMN computer_folder TEXT;
|
|
6003
|
+
UPDATE agent_threads SET computer_id = NULL WHERE computer_id IS NOT NULL;
|
|
6004
|
+
-- When its turns last moved to where they run now: the files earlier turns used are not there.
|
|
6005
|
+
ALTER TABLE agent_threads ADD COLUMN moved_at TEXT;
|
|
6006
|
+
|
|
6007
|
+
-- Each open sixb on its owner's computers, a lease it renews: while one is live, the threads that
|
|
6008
|
+
-- run on its computer in its folder are reachable there.
|
|
6009
|
+
CREATE TABLE agent_computer_sessions (
|
|
6010
|
+
project_id TEXT NOT NULL,
|
|
6011
|
+
owner_principal_type TEXT NOT NULL CHECK (owner_principal_type IN ('user', 'serviceAccount', 'system')),
|
|
6012
|
+
owner_principal_id TEXT NOT NULL CHECK (length(owner_principal_id) > 0),
|
|
6013
|
+
id TEXT NOT NULL CHECK (length(id) > 0),
|
|
6014
|
+
computer_id TEXT NOT NULL,
|
|
6015
|
+
computer_name TEXT NOT NULL,
|
|
6016
|
+
folder TEXT NOT NULL,
|
|
6017
|
+
expires_at TEXT NOT NULL,
|
|
6018
|
+
PRIMARY KEY (project_id, owner_principal_type, owner_principal_id, id)
|
|
6019
|
+
);
|
|
6020
|
+
CREATE INDEX agent_computer_sessions_by_expiry ON agent_computer_sessions (project_id, expires_at);
|
|
6021
|
+
|
|
6022
|
+
-- Each open sixb asks every 20 seconds which of its owner's threads here have a turn active.
|
|
6023
|
+
CREATE INDEX agent_threads_active_on_computer
|
|
6024
|
+
ON agent_threads (project_id, owner_principal_type, owner_principal_id, computer_id, computer_folder)
|
|
6025
|
+
WHERE active_run_id IS NOT NULL;
|
|
6026
|
+
`;
|
|
6027
|
+
|
|
5978
6028
|
// src/migrations.ts
|
|
5979
6029
|
var MIGRATIONS_TABLE_SQL = `
|
|
5980
6030
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -6110,7 +6160,9 @@ var sqliteStorageMigrations = defineMigrations({
|
|
|
6110
6160
|
}, { checksum: checksum(_078_subagent_threads_default) }),
|
|
6111
6161
|
sqliteSql("079-subagent-questions", _079_subagent_questions_default),
|
|
6112
6162
|
sqliteSql("080-agent-run-cancel-requests", _080_agent_run_cancel_requests_default),
|
|
6113
|
-
sqliteSql("081-agent-thread-runs-on", _081_agent_thread_runs_on_default)
|
|
6163
|
+
sqliteSql("081-agent-thread-runs-on", _081_agent_thread_runs_on_default),
|
|
6164
|
+
sqliteSql("082-agent-token-rates", _082_agent_token_rates_default),
|
|
6165
|
+
sqliteSql("083-agent-computer-sessions", _083_agent_computer_sessions_default)
|
|
6114
6166
|
]
|
|
6115
6167
|
});
|
|
6116
6168
|
function sqliteStoragePath(basePath) {
|
|
@@ -7077,7 +7129,10 @@ function rowToThreadRecord(row) {
|
|
|
7077
7129
|
},
|
|
7078
7130
|
...row.sandbox_params == null ? {} : { sandboxParams: snapshotAgentThreadSandboxParams(JSON.parse(row.sandbox_params)) },
|
|
7079
7131
|
...row.runs_on == null ? {} : { runsOn: row.runs_on },
|
|
7080
|
-
...row.computer_id == null
|
|
7132
|
+
...row.computer_id == null || row.computer_name == null || row.computer_folder == null ? {} : {
|
|
7133
|
+
computer: { id: row.computer_id, name: row.computer_name, folder: row.computer_folder }
|
|
7134
|
+
},
|
|
7135
|
+
...row.moved_at == null ? {} : { movedAt: new Date(row.moved_at) },
|
|
7081
7136
|
status: row.status,
|
|
7082
7137
|
activeRunId: row.active_run_id,
|
|
7083
7138
|
lastMessageAt: row.last_message_at ? new Date(row.last_message_at) : undefined,
|
|
@@ -7560,6 +7615,55 @@ class SqliteAgentContextCheckpointStore {
|
|
|
7560
7615
|
}
|
|
7561
7616
|
}
|
|
7562
7617
|
|
|
7618
|
+
// src/agents/computers.ts
|
|
7619
|
+
import { assertAgentComputerSession } from "@sixb/core/internal/agent-run-storage-provider";
|
|
7620
|
+
|
|
7621
|
+
class SqliteAgentComputerSessionStore {
|
|
7622
|
+
db;
|
|
7623
|
+
constructor(db) {
|
|
7624
|
+
this.db = db;
|
|
7625
|
+
}
|
|
7626
|
+
async hold(input) {
|
|
7627
|
+
assertAgentComputerSession(input, "SixbSqlite");
|
|
7628
|
+
this.db.query(`INSERT INTO agent_computer_sessions (
|
|
7629
|
+
project_id, owner_principal_type, owner_principal_id, id,
|
|
7630
|
+
computer_id, computer_name, folder, expires_at
|
|
7631
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
7632
|
+
ON CONFLICT (project_id, owner_principal_type, owner_principal_id, id)
|
|
7633
|
+
DO UPDATE SET
|
|
7634
|
+
computer_id = excluded.computer_id,
|
|
7635
|
+
computer_name = excluded.computer_name,
|
|
7636
|
+
folder = excluded.folder,
|
|
7637
|
+
expires_at = excluded.expires_at`).run(input.projectId, input.ownerPrincipal.type, input.ownerPrincipal.id, input.id, input.computer.id, input.computer.name, input.computer.folder, input.expiresAt.toISOString());
|
|
7638
|
+
}
|
|
7639
|
+
async release(input) {
|
|
7640
|
+
const row = this.db.query(`DELETE FROM agent_computer_sessions
|
|
7641
|
+
WHERE project_id = ? AND owner_principal_type = ? AND owner_principal_id = ? AND id = ?
|
|
7642
|
+
RETURNING *`).get(input.projectId, input.ownerPrincipal.type, input.ownerPrincipal.id, input.id);
|
|
7643
|
+
return row && rowToSession(row);
|
|
7644
|
+
}
|
|
7645
|
+
async listLive(input) {
|
|
7646
|
+
const rows = this.db.query(`SELECT * FROM agent_computer_sessions
|
|
7647
|
+
WHERE project_id = ? AND owner_principal_type = ? AND owner_principal_id = ?
|
|
7648
|
+
AND expires_at > ?
|
|
7649
|
+
ORDER BY id`).all(input.projectId, input.ownerPrincipal.type, input.ownerPrincipal.id, input.now.toISOString());
|
|
7650
|
+
return rows.map(rowToSession);
|
|
7651
|
+
}
|
|
7652
|
+
async removeLapsed(input) {
|
|
7653
|
+
const rows = this.db.query(`DELETE FROM agent_computer_sessions WHERE project_id = ? AND expires_at <= ? RETURNING *`).all(input.projectId, input.now.toISOString());
|
|
7654
|
+
return rows.map(rowToSession);
|
|
7655
|
+
}
|
|
7656
|
+
}
|
|
7657
|
+
function rowToSession(row) {
|
|
7658
|
+
return {
|
|
7659
|
+
projectId: row.project_id,
|
|
7660
|
+
id: row.id,
|
|
7661
|
+
ownerPrincipal: { type: row.owner_principal_type, id: row.owner_principal_id },
|
|
7662
|
+
computer: { id: row.computer_id, name: row.computer_name, folder: row.folder },
|
|
7663
|
+
expiresAt: new Date(row.expires_at)
|
|
7664
|
+
};
|
|
7665
|
+
}
|
|
7666
|
+
|
|
7563
7667
|
// src/agents/memory.ts
|
|
7564
7668
|
import {
|
|
7565
7669
|
agentMemoryConflicts,
|
|
@@ -7806,7 +7910,9 @@ import {
|
|
|
7806
7910
|
assertConversationAgentRunSpec,
|
|
7807
7911
|
assertConversationThreadRow,
|
|
7808
7912
|
assertCreateSubagentRunInput,
|
|
7913
|
+
assertStartsOnComputer,
|
|
7809
7914
|
assertSubagentThreadTakesRun,
|
|
7915
|
+
assertTurnInThreadPlace,
|
|
7810
7916
|
newSubagentThreadRecord,
|
|
7811
7917
|
subagentRunMatchesCreateInput
|
|
7812
7918
|
} from "@sixb/core/internal/agent-run-storage-provider";
|
|
@@ -7888,7 +7994,7 @@ class SqliteAgentRunStore {
|
|
|
7888
7994
|
runId: input.id
|
|
7889
7995
|
});
|
|
7890
7996
|
return this.db.transaction(() => {
|
|
7891
|
-
const thread = this.db.query("SELECT id, kind, active_run_id FROM agent_threads WHERE project_id = ? AND id = ?").get(input.projectId, input.threadId);
|
|
7997
|
+
const thread = this.db.query("SELECT id, kind, active_run_id, runs_on FROM agent_threads WHERE project_id = ? AND id = ?").get(input.projectId, input.threadId);
|
|
7892
7998
|
if (!thread) {
|
|
7893
7999
|
throw new AgentStorageError4("thread_not_found", `[SixbSqlite] Agent thread '${input.threadId}' not found for project '${input.projectId}'.`);
|
|
7894
8000
|
}
|
|
@@ -7896,6 +8002,7 @@ class SqliteAgentRunStore {
|
|
|
7896
8002
|
if (thread.active_run_id !== null) {
|
|
7897
8003
|
throw new AgentStorageError4("active_run_exists", `[SixbSqlite] Agent thread '${input.threadId}' already has an active run '${thread.active_run_id}'.`);
|
|
7898
8004
|
}
|
|
8005
|
+
assertTurnInThreadPlace(thread.runs_on, input.spec, input.threadId, "SixbSqlite");
|
|
7899
8006
|
try {
|
|
7900
8007
|
this.db.query(`
|
|
7901
8008
|
INSERT INTO agent_runs (
|
|
@@ -7995,7 +8102,11 @@ class SqliteAgentRunStore {
|
|
|
7995
8102
|
async start(input) {
|
|
7996
8103
|
const startedAt = input.startedAt ?? new Date;
|
|
7997
8104
|
return this.db.transaction(() => {
|
|
7998
|
-
this.requireStatus(input.projectId, input.id, "queued");
|
|
8105
|
+
const run = this.requireStatus(input.projectId, input.id, "queued");
|
|
8106
|
+
if (input.onComputer) {
|
|
8107
|
+
const thread = this.db.query("SELECT computer_id AS id, computer_folder AS folder FROM agent_threads WHERE project_id = ? AND id = ?").get(input.projectId, run.thread_id);
|
|
8108
|
+
assertStartsOnComputer(rowToRunRecord(run), thread?.id ? thread : undefined, input.onComputer, "SixbSqlite");
|
|
8109
|
+
}
|
|
7999
8110
|
this.db.query(`
|
|
8000
8111
|
UPDATE agent_runs
|
|
8001
8112
|
SET
|
|
@@ -8179,6 +8290,9 @@ class SqliteAgentRunStore {
|
|
|
8179
8290
|
whereClauses.push("parent_run_id = ?");
|
|
8180
8291
|
args.push(input.parentRunId);
|
|
8181
8292
|
}
|
|
8293
|
+
if (input.excludeComputerTurns) {
|
|
8294
|
+
whereClauses.push("json_extract(spec, '$.runsOn') IS NOT 'computer'");
|
|
8295
|
+
}
|
|
8182
8296
|
appendRunListFilters(whereClauses, args, input, "COALESCE(started_at, created_at)");
|
|
8183
8297
|
const { rows, total, hasMore } = queryRunList({
|
|
8184
8298
|
db: this.db,
|
|
@@ -8296,12 +8410,15 @@ class SqliteAgentApprovalModeStore {
|
|
|
8296
8410
|
|
|
8297
8411
|
// src/agents/threads.ts
|
|
8298
8412
|
import {
|
|
8413
|
+
assertAgentThreadComputer,
|
|
8299
8414
|
assertAssignableComputer,
|
|
8300
|
-
|
|
8415
|
+
assertComputerPlace,
|
|
8301
8416
|
assertConversationThreadRow as assertConversationThreadRow2,
|
|
8302
|
-
|
|
8417
|
+
assertMovableToCloud,
|
|
8418
|
+
movesComputerPlace,
|
|
8303
8419
|
participantsToAdd,
|
|
8304
8420
|
planAgentThreadFork,
|
|
8421
|
+
queuedTurnInCloud,
|
|
8305
8422
|
remapArtifactIds,
|
|
8306
8423
|
snapshotAgentThreadSandboxParams as snapshotAgentThreadSandboxParams2,
|
|
8307
8424
|
transitionAgentThreadSandbox
|
|
@@ -8324,7 +8441,7 @@ class SqliteAgentThreadStore {
|
|
|
8324
8441
|
}).immediate();
|
|
8325
8442
|
}
|
|
8326
8443
|
async create(input) {
|
|
8327
|
-
|
|
8444
|
+
assertComputerPlace(input.runsOn, input.computer, "SixbSqlite");
|
|
8328
8445
|
const sandboxParams = input.sandboxParams === undefined ? null : JSON.stringify(snapshotAgentThreadSandboxParams2(input.sandboxParams));
|
|
8329
8446
|
const createdAt = input.createdAt ?? new Date;
|
|
8330
8447
|
const updatedAt = input.updatedAt ?? createdAt;
|
|
@@ -8338,14 +8455,17 @@ class SqliteAgentThreadStore {
|
|
|
8338
8455
|
title,
|
|
8339
8456
|
sandbox_params,
|
|
8340
8457
|
runs_on,
|
|
8458
|
+
computer_id,
|
|
8459
|
+
computer_name,
|
|
8460
|
+
computer_folder,
|
|
8341
8461
|
status,
|
|
8342
8462
|
active_run_id,
|
|
8343
8463
|
last_message_at,
|
|
8344
8464
|
message_count,
|
|
8345
8465
|
created_at,
|
|
8346
8466
|
updated_at
|
|
8347
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, 0, ?, ?)
|
|
8348
|
-
`).run(input.projectId, input.id, input.ownerPrincipal.type, input.ownerPrincipal.id, input.title ?? null, sandboxParams, input.runsOn ?? null, input.status ?? "active", createdAt.toISOString(), updatedAt.toISOString());
|
|
8467
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, 0, ?, ?)
|
|
8468
|
+
`).run(input.projectId, input.id, input.ownerPrincipal.type, input.ownerPrincipal.id, input.title ?? null, sandboxParams, input.runsOn ?? null, input.computer?.id ?? null, input.computer?.name ?? null, input.computer?.folder ?? null, input.status ?? "active", createdAt.toISOString(), updatedAt.toISOString());
|
|
8349
8469
|
} catch (error) {
|
|
8350
8470
|
if (isUniqueConstraintError(error)) {
|
|
8351
8471
|
throw new AgentStorageError6("duplicate_id", `[SixbSqlite] Agent thread '${input.id}' already exists for project '${input.projectId}'.`);
|
|
@@ -8354,9 +8474,13 @@ class SqliteAgentThreadStore {
|
|
|
8354
8474
|
}
|
|
8355
8475
|
return this.requireThread(input.projectId, input.id);
|
|
8356
8476
|
}
|
|
8477
|
+
activeRunOf(projectId, thread) {
|
|
8478
|
+
const row = thread?.activeRunId ? this.db.query("SELECT * FROM agent_runs WHERE project_id = ? AND id = ?").get(projectId, thread.activeRunId) : null;
|
|
8479
|
+
return row ? rowToRunRecord(row) : null;
|
|
8480
|
+
}
|
|
8357
8481
|
async fork(input) {
|
|
8358
8482
|
return this.db.transaction(() => {
|
|
8359
|
-
const source = this.db.query("SELECT id, kind, active_run_id FROM agent_threads WHERE project_id = ? AND id = ?").get(input.projectId, input.sourceThreadId);
|
|
8483
|
+
const source = this.db.query("SELECT id, kind, active_run_id, runs_on, moved_at FROM agent_threads WHERE project_id = ? AND id = ?").get(input.projectId, input.sourceThreadId);
|
|
8360
8484
|
if (!source) {
|
|
8361
8485
|
throw new AgentStorageError6("thread_not_found", `[SixbSqlite] Agent thread '${input.sourceThreadId}' not found for project '${input.projectId}'.`);
|
|
8362
8486
|
}
|
|
@@ -8378,6 +8502,7 @@ class SqliteAgentThreadStore {
|
|
|
8378
8502
|
ORDER BY summarized_through_seq DESC, created_at DESC, id DESC
|
|
8379
8503
|
`).all(input.projectId, source.id);
|
|
8380
8504
|
const plan = planAgentThreadFork(input, {
|
|
8505
|
+
workspace: { runsOn: source.runs_on, movedAt: source.moved_at },
|
|
8381
8506
|
...activeRun?.trigger_message_id ? { triggerMessageId: activeRun.trigger_message_id } : {},
|
|
8382
8507
|
messages,
|
|
8383
8508
|
checkpoints: checkpoints.map(rowToContextCheckpointRecord)
|
|
@@ -8480,6 +8605,10 @@ class SqliteAgentThreadStore {
|
|
|
8480
8605
|
)`);
|
|
8481
8606
|
args.push(input.participantPrincipal.type, input.participantPrincipal.id);
|
|
8482
8607
|
}
|
|
8608
|
+
if (input.activeOnComputer) {
|
|
8609
|
+
whereClauses.push("computer_id = ? AND computer_folder = ? AND active_run_id IS NOT NULL");
|
|
8610
|
+
args.push(input.activeOnComputer.id, input.activeOnComputer.folder);
|
|
8611
|
+
}
|
|
8483
8612
|
const dir = input.order === "asc" ? "ASC" : "DESC";
|
|
8484
8613
|
const { rows, total, hasMore } = queryAgentList({
|
|
8485
8614
|
db: this.db,
|
|
@@ -8527,16 +8656,40 @@ class SqliteAgentThreadStore {
|
|
|
8527
8656
|
return result.changes > 0;
|
|
8528
8657
|
}
|
|
8529
8658
|
async assignComputer(input) {
|
|
8530
|
-
|
|
8531
|
-
this.db.
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8659
|
+
assertAgentThreadComputer(input.computer, "SixbSqlite");
|
|
8660
|
+
return this.db.transaction(() => {
|
|
8661
|
+
const row = this.db.query("SELECT * FROM agent_threads WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
8662
|
+
const thread = row ? rowToThreadRecord(row) : null;
|
|
8663
|
+
assertAssignableComputer(thread, this.activeRunOf(input.projectId, thread), input.computer, input.id, "SixbSqlite");
|
|
8664
|
+
const movedAt = movesComputerPlace(thread, input.computer) ? (input.movedAt ?? new Date).toISOString() : null;
|
|
8665
|
+
this.db.query(`
|
|
8666
|
+
UPDATE agent_threads
|
|
8667
|
+
SET computer_id = ?, computer_name = ?, computer_folder = ?,
|
|
8668
|
+
moved_at = COALESCE(?, moved_at)
|
|
8669
|
+
WHERE project_id = ? AND id = ?
|
|
8670
|
+
`).run(input.computer.id, input.computer.name, input.computer.folder, movedAt, input.projectId, input.id);
|
|
8671
|
+
return this.requireThread(input.projectId, input.id);
|
|
8672
|
+
}).immediate();
|
|
8673
|
+
}
|
|
8674
|
+
async moveToCloud(input) {
|
|
8675
|
+
return this.db.transaction(() => {
|
|
8676
|
+
const row = this.db.query("SELECT * FROM agent_threads WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
8677
|
+
const thread = row ? rowToThreadRecord(row) : null;
|
|
8678
|
+
const active = this.activeRunOf(input.projectId, thread);
|
|
8679
|
+
assertMovableToCloud(thread, active, input.id, "SixbSqlite");
|
|
8680
|
+
const queued = queuedTurnInCloud(active);
|
|
8681
|
+
if (queued) {
|
|
8682
|
+
this.db.query("UPDATE agent_runs SET spec = ? WHERE project_id = ? AND id = ?").run(JSON.stringify(queued.spec), input.projectId, queued.id);
|
|
8683
|
+
}
|
|
8684
|
+
this.db.query(`
|
|
8685
|
+
UPDATE agent_threads
|
|
8686
|
+
SET runs_on = NULL, computer_id = NULL, computer_name = NULL, computer_folder = NULL,
|
|
8687
|
+
moved_at = ?
|
|
8688
|
+
WHERE project_id = ? AND id = ?
|
|
8689
|
+
`).run((input.movedAt ?? new Date).toISOString(), input.projectId, input.id);
|
|
8690
|
+
const moved = this.requireThread(input.projectId, input.id);
|
|
8691
|
+
return { thread: moved, ...queued ? { queued } : {} };
|
|
8692
|
+
}).immediate();
|
|
8540
8693
|
}
|
|
8541
8694
|
async listParticipants(input) {
|
|
8542
8695
|
return this.selectParticipants(input.projectId, [...new Set(input.threadIds)]);
|
|
@@ -8572,10 +8725,11 @@ class SqliteAgentThreadStore {
|
|
|
8572
8725
|
active_run_id,
|
|
8573
8726
|
last_message_at,
|
|
8574
8727
|
message_count,
|
|
8728
|
+
moved_at,
|
|
8575
8729
|
created_at,
|
|
8576
8730
|
updated_at
|
|
8577
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?)
|
|
8578
|
-
`).run(thread.projectId, thread.id, thread.ownerPrincipal.type, thread.ownerPrincipal.id, thread.title ?? null, thread.sandboxParams === undefined ? null : JSON.stringify(thread.sandboxParams), thread.sandboxState === undefined ? null : JSON.stringify(thread.sandboxState), thread.status, thread.lastMessageAt?.toISOString() ?? null, thread.messageCount, thread.createdAt.toISOString(), thread.updatedAt.toISOString());
|
|
8731
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?)
|
|
8732
|
+
`).run(thread.projectId, thread.id, thread.ownerPrincipal.type, thread.ownerPrincipal.id, thread.title ?? null, thread.sandboxParams === undefined ? null : JSON.stringify(thread.sandboxParams), thread.sandboxState === undefined ? null : JSON.stringify(thread.sandboxState), thread.status, thread.lastMessageAt?.toISOString() ?? null, thread.messageCount, thread.movedAt?.toISOString() ?? null, thread.createdAt.toISOString(), thread.updatedAt.toISOString());
|
|
8579
8733
|
} catch (error) {
|
|
8580
8734
|
if (isUniqueConstraintError(error)) {
|
|
8581
8735
|
throw new AgentStorageError6("duplicate_id", `[SixbSqlite] Agent thread '${thread.id}' already exists for project '${thread.projectId}'.`);
|
|
@@ -8623,6 +8777,53 @@ class SqliteAgentThreadStore {
|
|
|
8623
8777
|
}
|
|
8624
8778
|
}
|
|
8625
8779
|
|
|
8780
|
+
// src/agents/token-rates.ts
|
|
8781
|
+
import {
|
|
8782
|
+
AGENT_TOKEN_RATE_SAMPLES,
|
|
8783
|
+
assertAgentTokenRateRecord
|
|
8784
|
+
} from "@sixb/core/internal/agent-run-storage-provider";
|
|
8785
|
+
class SqliteAgentTokenRateStore {
|
|
8786
|
+
db;
|
|
8787
|
+
constructor(db) {
|
|
8788
|
+
this.db = db;
|
|
8789
|
+
}
|
|
8790
|
+
async record(input) {
|
|
8791
|
+
assertAgentTokenRateRecord(input, "SixbSqlite");
|
|
8792
|
+
runImmediateTransaction(this.db, () => {
|
|
8793
|
+
this.db.query(`INSERT INTO agent_token_rates (
|
|
8794
|
+
project_id, run_id, provider_id, model_id, bytes, tokens, measured_at
|
|
8795
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
8796
|
+
ON CONFLICT (project_id, run_id) DO UPDATE SET
|
|
8797
|
+
provider_id = excluded.provider_id, model_id = excluded.model_id,
|
|
8798
|
+
bytes = excluded.bytes, tokens = excluded.tokens, measured_at = excluded.measured_at`).run(input.projectId, input.runId, input.providerId, input.modelId, input.bytes, input.tokens, input.measuredAt.toISOString());
|
|
8799
|
+
this.db.query(`DELETE FROM agent_token_rates
|
|
8800
|
+
WHERE project_id = ?1 AND provider_id = ?2 AND model_id = ?3
|
|
8801
|
+
AND run_id NOT IN (
|
|
8802
|
+
SELECT run_id FROM agent_token_rates
|
|
8803
|
+
WHERE project_id = ?1 AND provider_id = ?2 AND model_id = ?3
|
|
8804
|
+
ORDER BY measured_at DESC, run_id DESC
|
|
8805
|
+
LIMIT ?4
|
|
8806
|
+
)`).run(input.projectId, input.providerId, input.modelId, AGENT_TOKEN_RATE_SAMPLES);
|
|
8807
|
+
});
|
|
8808
|
+
}
|
|
8809
|
+
async listLatest(input) {
|
|
8810
|
+
const rows = this.db.query(`SELECT project_id, run_id, provider_id, model_id, bytes, tokens, measured_at
|
|
8811
|
+
FROM agent_token_rates
|
|
8812
|
+
WHERE project_id = ? AND provider_id = ? AND model_id = ?
|
|
8813
|
+
ORDER BY measured_at DESC, run_id DESC
|
|
8814
|
+
LIMIT ?`).all(input.projectId, input.providerId, input.modelId, AGENT_TOKEN_RATE_SAMPLES);
|
|
8815
|
+
return rows.map((row) => ({
|
|
8816
|
+
projectId: row.project_id,
|
|
8817
|
+
providerId: row.provider_id,
|
|
8818
|
+
modelId: row.model_id,
|
|
8819
|
+
runId: row.run_id,
|
|
8820
|
+
bytes: row.bytes,
|
|
8821
|
+
tokens: row.tokens,
|
|
8822
|
+
measuredAt: new Date(row.measured_at)
|
|
8823
|
+
}));
|
|
8824
|
+
}
|
|
8825
|
+
}
|
|
8826
|
+
|
|
8626
8827
|
// src/agents/agent-storage.ts
|
|
8627
8828
|
class SqliteAgentStorage {
|
|
8628
8829
|
threads;
|
|
@@ -8632,6 +8833,8 @@ class SqliteAgentStorage {
|
|
|
8632
8833
|
memory;
|
|
8633
8834
|
approvals;
|
|
8634
8835
|
approvalModes;
|
|
8836
|
+
computers;
|
|
8837
|
+
tokenRates;
|
|
8635
8838
|
connection;
|
|
8636
8839
|
constructor(options) {
|
|
8637
8840
|
this.connection = openSqliteStoreConnection(options);
|
|
@@ -8642,6 +8845,8 @@ class SqliteAgentStorage {
|
|
|
8642
8845
|
this.memory = new SqliteAgentMemoryStore(this.connection.db);
|
|
8643
8846
|
this.approvals = new SqliteAgentApprovalStore(this.connection.db);
|
|
8644
8847
|
this.approvalModes = new SqliteAgentApprovalModeStore(this.connection.db);
|
|
8848
|
+
this.computers = new SqliteAgentComputerSessionStore(this.connection.db);
|
|
8849
|
+
this.tokenRates = new SqliteAgentTokenRateStore(this.connection.db);
|
|
8645
8850
|
}
|
|
8646
8851
|
close() {
|
|
8647
8852
|
closeSqliteStoreConnection(this.connection);
|
|
@@ -8665,15 +8870,52 @@ import {
|
|
|
8665
8870
|
AiCostStorageError
|
|
8666
8871
|
} from "@sixb/core/storage";
|
|
8667
8872
|
|
|
8873
|
+
// src/ai-accounting-filters.ts
|
|
8874
|
+
var SQLITE_SOURCE_WORKFLOW = `COALESCE(
|
|
8875
|
+
workflow_node.workflow_id,
|
|
8876
|
+
CASE WHEN execution.executor_kind = 'workflow' THEN execution.authority_primitive_id END
|
|
8877
|
+
)`;
|
|
8878
|
+
var SQLITE_SOURCE_KIND = `CASE
|
|
8879
|
+
WHEN direct_agent.id IS NOT NULL THEN 'agent'
|
|
8880
|
+
WHEN ${SQLITE_SOURCE_WORKFLOW} IS NOT NULL THEN 'workflow'
|
|
8881
|
+
WHEN execution.executor_kind = 'action' THEN 'action'
|
|
8882
|
+
ELSE 'other'
|
|
8883
|
+
END`;
|
|
8884
|
+
function sqliteAccountingFilter(columns) {
|
|
8885
|
+
return `(? IS NULL OR ${columns.kind} = ?)
|
|
8886
|
+
AND (? IS NULL OR ${columns.sourceKind} = ?)
|
|
8887
|
+
AND (? IS NULL OR ${columns.sourceWorkflow} = ?)
|
|
8888
|
+
AND (
|
|
8889
|
+
? IS NULL
|
|
8890
|
+
OR (? = 'none' AND ${columns.userId} IS NULL AND ${columns.serviceAccountId} IS NULL)
|
|
8891
|
+
OR (? = 'user' AND ${columns.userId} = ?)
|
|
8892
|
+
OR (? = 'serviceAccount' AND ${columns.serviceAccountId} = ?)
|
|
8893
|
+
)`;
|
|
8894
|
+
}
|
|
8895
|
+
function sqliteAccountingFilterParameters(query) {
|
|
8896
|
+
const kind = query.modelKind ?? null;
|
|
8897
|
+
const source = query.source?.kind ?? null;
|
|
8898
|
+
const workflow = query.source?.kind === "workflow" ? query.source.workflowId ?? null : null;
|
|
8899
|
+
const mode = query.requester === undefined ? null : query.requester === "none" ? "none" : query.requester.type;
|
|
8900
|
+
const id = query.requester === undefined || query.requester === "none" ? null : query.requester.id;
|
|
8901
|
+
return [kind, kind, source, source, workflow, workflow, mode, mode, mode, id, mode, id];
|
|
8902
|
+
}
|
|
8903
|
+
|
|
8668
8904
|
// src/ai-cost-groups.ts
|
|
8669
8905
|
import {
|
|
8670
8906
|
aiModelCallGroupFragmentFromRow,
|
|
8671
8907
|
buildAiModelCallGroupsFromFragments,
|
|
8672
8908
|
normalizeAiModelCallAccountingQuery,
|
|
8909
|
+
normalizeAiModelCallGroupSort,
|
|
8673
8910
|
TOKENLESS_MODEL_KINDS
|
|
8674
8911
|
} from "@sixb/core/internal/ai-cost-storage-provider";
|
|
8912
|
+
function numbered(sql, start) {
|
|
8913
|
+
let next = start;
|
|
8914
|
+
return sql.replace(/\?(?!\d)/g, () => `?${next++}`);
|
|
8915
|
+
}
|
|
8675
8916
|
async function listAiModelCallGroups(connection, input) {
|
|
8676
8917
|
const query = normalizeAiModelCallAccountingQuery(input);
|
|
8918
|
+
const sort = normalizeAiModelCallGroupSort(input.sort);
|
|
8677
8919
|
const parameters = [
|
|
8678
8920
|
query.projectId,
|
|
8679
8921
|
query.from.toISOString(),
|
|
@@ -8682,20 +8924,28 @@ async function listAiModelCallGroups(connection, input) {
|
|
|
8682
8924
|
query.modelId ?? null,
|
|
8683
8925
|
query.valuationStatus ?? null
|
|
8684
8926
|
];
|
|
8685
|
-
const
|
|
8686
|
-
const
|
|
8927
|
+
const filters = sqliteAccountingFilterParameters(query);
|
|
8928
|
+
const count = connection.db.query(COUNT_SQL).get(...parameters, ...filters);
|
|
8929
|
+
const rows = connection.db.query(PAGE_SQL).all(...parameters, ...filters, query.limit, query.offset, sort);
|
|
8687
8930
|
const total = Number(count?.total);
|
|
8688
8931
|
if (!Number.isSafeInteger(total) || total < 0)
|
|
8689
8932
|
throw new RangeError("[Sixb] Invalid model-call group count.");
|
|
8690
|
-
const items = buildAiModelCallGroupsFromFragments(rows.map(aiModelCallGroupFragmentFromRow));
|
|
8933
|
+
const items = buildAiModelCallGroupsFromFragments(rows.map(aiModelCallGroupFragmentFromRow), sort);
|
|
8691
8934
|
return { items, total, hasMore: query.offset + items.length < total };
|
|
8692
8935
|
}
|
|
8693
8936
|
var TOKENLESS_KINDS = TOKENLESS_MODEL_KINDS.map((kind) => `'${kind}'`).join(", ");
|
|
8694
8937
|
var FILTERED_SQL = `
|
|
8695
8938
|
WITH filtered AS (
|
|
8696
8939
|
SELECT COALESCE(root_agent.execution_id, usage.execution_id) AS root_execution_id,
|
|
8940
|
+
-- What the call is listed under, as aiModelCallGroupKey computes it.
|
|
8941
|
+
CASE
|
|
8942
|
+
WHEN root_agent.thread_id IS NOT NULL THEN 'thread:' || root_agent.thread_id
|
|
8943
|
+
WHEN workflow_node.workflow_run_id IS NOT NULL THEN 'workflowRun:' || workflow_node.workflow_run_id
|
|
8944
|
+
ELSE COALESCE(root_agent.execution_id, usage.execution_id)
|
|
8945
|
+
END AS group_key,
|
|
8697
8946
|
usage.execution_id, usage.provider_id, usage.requested_model_id, usage.occurred_at,
|
|
8698
|
-
usage.total_tokens, usage.
|
|
8947
|
+
usage.total_tokens, usage.input_tokens, usage.cache_read_input_tokens,
|
|
8948
|
+
usage.model_kind, usage.output_images, usage.input_characters,
|
|
8699
8949
|
usage.audio_duration_ms,
|
|
8700
8950
|
execution.executor_kind, execution.executor_id, execution.authority_primitive_id AS primitive_id,
|
|
8701
8951
|
COALESCE(cost.status, 'unvalued') AS valuation_status,
|
|
@@ -8708,7 +8958,8 @@ WITH filtered AS (
|
|
|
8708
8958
|
workflow_node.node_id AS workflow_agent_step_id,
|
|
8709
8959
|
workflow_agent.node_run_id AS workflow_node_run_id,
|
|
8710
8960
|
workflow_node.workflow_id AS workflow_id,
|
|
8711
|
-
workflow_node.workflow_run_id AS workflow_run_id
|
|
8961
|
+
workflow_node.workflow_run_id AS workflow_run_id,
|
|
8962
|
+
execution.requested_by_user_id, execution.requested_by_service_account_id
|
|
8712
8963
|
FROM ai_model_call_usage AS usage
|
|
8713
8964
|
JOIN executions AS execution ON execution.project_id = usage.project_id AND execution.id = usage.execution_id
|
|
8714
8965
|
LEFT JOIN agent_runs AS direct_agent
|
|
@@ -8728,23 +8979,33 @@ WITH filtered AS (
|
|
|
8728
8979
|
AND (?4 IS NULL OR usage.provider_id = ?4)
|
|
8729
8980
|
AND (?5 IS NULL OR usage.requested_model_id = ?5)
|
|
8730
8981
|
AND (?6 IS NULL OR COALESCE(cost.status, 'unvalued') = ?6)
|
|
8982
|
+
AND ${numbered(sqliteAccountingFilter({
|
|
8983
|
+
kind: "usage.model_kind",
|
|
8984
|
+
sourceKind: SQLITE_SOURCE_KIND,
|
|
8985
|
+
sourceWorkflow: SQLITE_SOURCE_WORKFLOW,
|
|
8986
|
+
userId: "execution.requested_by_user_id",
|
|
8987
|
+
serviceAccountId: "execution.requested_by_service_account_id"
|
|
8988
|
+
}), 7)}
|
|
8731
8989
|
), roots AS (
|
|
8732
|
-
SELECT
|
|
8733
|
-
FROM filtered GROUP BY
|
|
8990
|
+
SELECT group_key, MAX(occurred_at) AS last_call_at, TOTAL(amount_nanos) AS cost_nanos
|
|
8991
|
+
FROM filtered GROUP BY group_key
|
|
8734
8992
|
)
|
|
8735
8993
|
`;
|
|
8736
8994
|
var COUNT_SQL = `${FILTERED_SQL} SELECT CAST(COUNT(*) AS TEXT) AS total FROM roots`;
|
|
8737
8995
|
var PAGE_SQL = `${FILTERED_SQL}, page AS (
|
|
8738
|
-
SELECT
|
|
8739
|
-
ORDER BY last_call_at DESC,
|
|
8996
|
+
SELECT group_key FROM roots
|
|
8997
|
+
ORDER BY CASE WHEN ?21 = 'cost' THEN cost_nanos END DESC, last_call_at DESC, group_key ASC
|
|
8998
|
+
LIMIT ?19 OFFSET ?20
|
|
8740
8999
|
)
|
|
8741
|
-
SELECT filtered.root_execution_id, execution_id, provider_id, requested_model_id,
|
|
9000
|
+
SELECT filtered.group_key, root_execution_id, execution_id, provider_id, requested_model_id,
|
|
8742
9001
|
MIN(occurred_at) AS first_call_at, MAX(occurred_at) AS last_call_at,
|
|
8743
9002
|
CAST(COUNT(*) AS TEXT) AS call_count,
|
|
8744
9003
|
CAST(COUNT(total_tokens) AS TEXT) AS token_count,
|
|
8745
9004
|
CAST(COUNT(CASE WHEN total_tokens IS NULL AND model_kind IN (${TOKENLESS_KINDS}) THEN 1 END) AS TEXT)
|
|
8746
9005
|
AS tokenless_count,
|
|
8747
9006
|
CAST(SUM(total_tokens) AS TEXT) AS total_tokens,
|
|
9007
|
+
CAST(SUM(input_tokens) AS TEXT) AS input_tokens,
|
|
9008
|
+
CAST(SUM(cache_read_input_tokens) AS TEXT) AS cache_read_input_tokens,
|
|
8748
9009
|
CAST(SUM(output_images) AS TEXT) AS output_images,
|
|
8749
9010
|
CAST(SUM(input_characters) AS TEXT) AS input_characters,
|
|
8750
9011
|
CAST(SUM(audio_duration_ms) AS TEXT) AS audio_duration_ms,
|
|
@@ -8761,9 +9022,11 @@ SELECT filtered.root_execution_id, execution_id, provider_id, requested_model_id
|
|
|
8761
9022
|
MAX(workflow_agent_step_id) AS workflow_agent_step_id,
|
|
8762
9023
|
MAX(workflow_node_run_id) AS workflow_node_run_id,
|
|
8763
9024
|
MAX(workflow_id) AS workflow_id,
|
|
8764
|
-
MAX(workflow_run_id) AS workflow_run_id
|
|
8765
|
-
|
|
8766
|
-
|
|
9025
|
+
MAX(workflow_run_id) AS workflow_run_id,
|
|
9026
|
+
MAX(requested_by_user_id) AS requested_by_user_id,
|
|
9027
|
+
MAX(requested_by_service_account_id) AS requested_by_service_account_id
|
|
9028
|
+
FROM filtered JOIN page ON page.group_key = filtered.group_key
|
|
9029
|
+
GROUP BY filtered.group_key, root_execution_id, execution_id, provider_id, requested_model_id,
|
|
8767
9030
|
valuation_status, amount_currency
|
|
8768
9031
|
`;
|
|
8769
9032
|
|
|
@@ -9067,7 +9330,7 @@ class SqliteAiCostStorage {
|
|
|
9067
9330
|
}
|
|
9068
9331
|
async queryProjectOverview(input) {
|
|
9069
9332
|
const query = normalizeAiAccountingQuery(input);
|
|
9070
|
-
const rows = this.connection.db.query(SQLITE_ACCOUNTING_OVERVIEW_SQL).all(query.projectId, query.from.toISOString(), query.to.toISOString(), query.providerId ?? null, query.providerId ?? null, query.modelId ?? null, query.modelId ?? null, input.bucket);
|
|
9333
|
+
const rows = this.connection.db.query(SQLITE_ACCOUNTING_OVERVIEW_SQL).all(query.projectId, query.from.toISOString(), query.to.toISOString(), query.providerId ?? null, query.providerId ?? null, query.modelId ?? null, query.modelId ?? null, ...sqliteAccountingFilterParameters(query), input.bucket, input.bucket);
|
|
9071
9334
|
return buildAiAccountingOverviewFromFragments(input, rows.map(aggregateFragmentFromRow));
|
|
9072
9335
|
}
|
|
9073
9336
|
async listModelCalls(input) {
|
|
@@ -9114,12 +9377,32 @@ var SQLITE_ACCOUNTING_LIST_FILTER = `
|
|
|
9114
9377
|
ELSE 'unvalued'
|
|
9115
9378
|
END
|
|
9116
9379
|
)
|
|
9380
|
+
AND ${sqliteAccountingFilter({
|
|
9381
|
+
kind: "usage.model_kind",
|
|
9382
|
+
sourceKind: SQLITE_SOURCE_KIND,
|
|
9383
|
+
sourceWorkflow: SQLITE_SOURCE_WORKFLOW,
|
|
9384
|
+
userId: "execution.requested_by_user_id",
|
|
9385
|
+
serviceAccountId: "execution.requested_by_service_account_id"
|
|
9386
|
+
})}
|
|
9387
|
+
`;
|
|
9388
|
+
var SQLITE_ACCOUNTING_LIST_JOINS = `
|
|
9389
|
+
JOIN executions AS execution ON execution.project_id = usage.project_id AND execution.id = usage.execution_id
|
|
9390
|
+
LEFT JOIN agent_runs AS direct_agent
|
|
9391
|
+
ON direct_agent.project_id = usage.project_id
|
|
9392
|
+
AND direct_agent.execution_id = usage.execution_id
|
|
9393
|
+
LEFT JOIN workflow_agent_node_runs AS workflow_agent
|
|
9394
|
+
ON workflow_agent.project_id = usage.project_id
|
|
9395
|
+
AND workflow_agent.execution_id = usage.execution_id
|
|
9396
|
+
LEFT JOIN workflow_node_runs AS workflow_node
|
|
9397
|
+
ON workflow_node.project_id = workflow_agent.project_id
|
|
9398
|
+
AND workflow_node.id = workflow_agent.node_run_id
|
|
9399
|
+
LEFT JOIN ai_model_call_valuations AS cost
|
|
9400
|
+
ON cost.project_id = usage.project_id AND cost.usage_record_id = usage.id
|
|
9117
9401
|
`;
|
|
9118
9402
|
var SQLITE_ACCOUNTING_LIST_COUNT_SQL = `
|
|
9119
9403
|
SELECT CAST(COUNT(*) AS TEXT) AS total
|
|
9120
9404
|
FROM ai_model_call_usage AS usage
|
|
9121
|
-
|
|
9122
|
-
ON cost.project_id = usage.project_id AND cost.usage_record_id = usage.id
|
|
9405
|
+
${SQLITE_ACCOUNTING_LIST_JOINS}
|
|
9123
9406
|
WHERE ${SQLITE_ACCOUNTING_LIST_FILTER}
|
|
9124
9407
|
`;
|
|
9125
9408
|
var SQLITE_ACCOUNTING_LIST_PAGE_SQL = `
|
|
@@ -9154,18 +9437,7 @@ var SQLITE_ACCOUNTING_LIST_PAGE_SQL = `
|
|
|
9154
9437
|
cost.details AS cost_details,
|
|
9155
9438
|
cost.rated_at AS cost_rated_at
|
|
9156
9439
|
FROM ai_model_call_usage AS usage
|
|
9157
|
-
|
|
9158
|
-
LEFT JOIN agent_runs AS direct_agent
|
|
9159
|
-
ON direct_agent.project_id = usage.project_id
|
|
9160
|
-
AND direct_agent.execution_id = usage.execution_id
|
|
9161
|
-
LEFT JOIN workflow_agent_node_runs AS workflow_agent
|
|
9162
|
-
ON workflow_agent.project_id = usage.project_id
|
|
9163
|
-
AND workflow_agent.execution_id = usage.execution_id
|
|
9164
|
-
LEFT JOIN workflow_node_runs AS workflow_node
|
|
9165
|
-
ON workflow_node.project_id = workflow_agent.project_id
|
|
9166
|
-
AND workflow_node.id = workflow_agent.node_run_id
|
|
9167
|
-
LEFT JOIN ai_model_call_valuations AS cost
|
|
9168
|
-
ON cost.project_id = usage.project_id AND cost.usage_record_id = usage.id
|
|
9440
|
+
${SQLITE_ACCOUNTING_LIST_JOINS}
|
|
9169
9441
|
WHERE ${SQLITE_ACCOUNTING_LIST_FILTER}
|
|
9170
9442
|
ORDER BY usage.occurred_at DESC, usage.id ASC
|
|
9171
9443
|
LIMIT ? OFFSET ?
|
|
@@ -9204,7 +9476,10 @@ var SQLITE_ACCOUNTING_OVERVIEW_SQL = `
|
|
|
9204
9476
|
ELSE 'unvalued'
|
|
9205
9477
|
END AS valuation_status,
|
|
9206
9478
|
CASE WHEN cost.status = 'rated' THEN cost.currency ELSE NULL END AS amount_currency,
|
|
9207
|
-
CASE WHEN cost.status = 'rated' THEN cost.amount_nanos ELSE NULL END AS amount_nanos
|
|
9479
|
+
CASE WHEN cost.status = 'rated' THEN cost.amount_nanos ELSE NULL END AS amount_nanos,
|
|
9480
|
+
execution.requested_by_user_id AS requester_user_id,
|
|
9481
|
+
execution.requested_by_service_account_id AS requester_service_account_id,
|
|
9482
|
+
${SQLITE_SOURCE_KIND} AS source_kind
|
|
9208
9483
|
FROM ai_model_call_usage AS usage
|
|
9209
9484
|
JOIN executions AS execution ON execution.project_id = usage.project_id AND execution.id = usage.execution_id
|
|
9210
9485
|
LEFT JOIN agent_runs AS direct_agent
|
|
@@ -9221,10 +9496,19 @@ var SQLITE_ACCOUNTING_OVERVIEW_SQL = `
|
|
|
9221
9496
|
WHERE usage.project_id = ? AND usage.occurred_at >= ? AND usage.occurred_at < ?
|
|
9222
9497
|
AND (? IS NULL OR usage.provider_id = ?)
|
|
9223
9498
|
AND (? IS NULL OR usage.requested_model_id = ?)
|
|
9499
|
+
), filtered AS (
|
|
9500
|
+
SELECT * FROM classified
|
|
9501
|
+
WHERE ${sqliteAccountingFilter({
|
|
9502
|
+
kind: "model_kind",
|
|
9503
|
+
sourceKind: "source_kind",
|
|
9504
|
+
sourceWorkflow: "attribution_workflow_id",
|
|
9505
|
+
userId: "requester_user_id",
|
|
9506
|
+
serviceAccountId: "requester_service_account_id"
|
|
9507
|
+
})}
|
|
9224
9508
|
), expanded AS (
|
|
9225
9509
|
SELECT 'totals' AS dimension, NULL AS key_1, NULL AS key_2, NULL AS key_3, NULL AS bucket_start,
|
|
9226
|
-
|
|
9227
|
-
FROM
|
|
9510
|
+
filtered.*
|
|
9511
|
+
FROM filtered
|
|
9228
9512
|
UNION ALL
|
|
9229
9513
|
SELECT 'series', NULL, NULL, NULL,
|
|
9230
9514
|
CASE ?
|
|
@@ -9236,18 +9520,39 @@ var SQLITE_ACCOUNTING_OVERVIEW_SQL = `
|
|
|
9236
9520
|
printf('-%d days', (CAST(strftime('%w', occurred_at) AS INTEGER) + 6) % 7)
|
|
9237
9521
|
)
|
|
9238
9522
|
END,
|
|
9239
|
-
|
|
9240
|
-
FROM
|
|
9523
|
+
filtered.*
|
|
9524
|
+
FROM filtered
|
|
9241
9525
|
UNION ALL
|
|
9242
|
-
SELECT '
|
|
9526
|
+
SELECT 'modelSeries', provider_id, requested_model_id, NULL,
|
|
9527
|
+
CASE ?
|
|
9528
|
+
WHEN 'hour' THEN strftime('%Y-%m-%dT%H:00:00.000Z', occurred_at)
|
|
9529
|
+
WHEN 'day' THEN strftime('%Y-%m-%dT00:00:00.000Z', occurred_at)
|
|
9530
|
+
ELSE strftime(
|
|
9531
|
+
'%Y-%m-%dT00:00:00.000Z',
|
|
9532
|
+
occurred_at,
|
|
9533
|
+
printf('-%d days', (CAST(strftime('%w', occurred_at) AS INTEGER) + 6) % 7)
|
|
9534
|
+
)
|
|
9535
|
+
END,
|
|
9536
|
+
filtered.*
|
|
9537
|
+
FROM filtered
|
|
9243
9538
|
UNION ALL
|
|
9244
|
-
SELECT '
|
|
9539
|
+
SELECT 'model', provider_id, requested_model_id, NULL, NULL, filtered.* FROM filtered
|
|
9245
9540
|
UNION ALL
|
|
9246
|
-
SELECT '
|
|
9247
|
-
|
|
9541
|
+
SELECT 'person',
|
|
9542
|
+
CASE
|
|
9543
|
+
WHEN requester_user_id IS NOT NULL THEN 'user'
|
|
9544
|
+
WHEN requester_service_account_id IS NOT NULL THEN 'serviceAccount'
|
|
9545
|
+
END,
|
|
9546
|
+
COALESCE(requester_user_id, requester_service_account_id), NULL, NULL, filtered.*
|
|
9547
|
+
FROM filtered
|
|
9248
9548
|
UNION ALL
|
|
9249
|
-
SELECT '
|
|
9250
|
-
|
|
9549
|
+
SELECT 'kind', model_kind, NULL, NULL, NULL, filtered.* FROM filtered
|
|
9550
|
+
UNION ALL
|
|
9551
|
+
SELECT 'agent', attribution_agent_kind, attribution_workflow_id, attribution_agent_step_id, NULL, filtered.*
|
|
9552
|
+
FROM filtered WHERE attribution_agent_kind IS NOT NULL
|
|
9553
|
+
UNION ALL
|
|
9554
|
+
SELECT 'workflow', attribution_workflow_id, NULL, NULL, NULL, filtered.*
|
|
9555
|
+
FROM filtered WHERE attribution_workflow_id IS NOT NULL
|
|
9251
9556
|
)
|
|
9252
9557
|
SELECT dimension,
|
|
9253
9558
|
key_1,
|
|
@@ -9308,11 +9613,16 @@ function accountingListFilterParameters(query) {
|
|
|
9308
9613
|
query.executionId ?? null,
|
|
9309
9614
|
query.executionId ?? null,
|
|
9310
9615
|
query.valuationStatus ?? null,
|
|
9311
|
-
query.valuationStatus ?? null
|
|
9616
|
+
query.valuationStatus ?? null,
|
|
9617
|
+
...sqliteAccountingFilterParameters(query)
|
|
9312
9618
|
];
|
|
9313
9619
|
}
|
|
9314
9620
|
function aggregateFragmentFromRow(row) {
|
|
9315
|
-
const dimensionKeys = row.dimension === "model" ? { providerId: required(row.key_1), modelId: required(row.key_2) } : row.dimension === "
|
|
9621
|
+
const dimensionKeys = row.dimension === "model" ? { providerId: required(row.key_1), modelId: required(row.key_2) } : row.dimension === "modelSeries" ? {
|
|
9622
|
+
providerId: required(row.key_1),
|
|
9623
|
+
modelId: required(row.key_2),
|
|
9624
|
+
start: new Date(required(row.bucket_start))
|
|
9625
|
+
} : row.dimension === "person" ? row.key_1 && row.key_2 ? { requesterType: row.key_1, requesterId: row.key_2 } : {} : row.dimension === "kind" ? withModelKind(aiAccountingModelKind(row.key_1)) : row.dimension === "agent" ? {
|
|
9316
9626
|
agentKind: required(row.key_1),
|
|
9317
9627
|
...row.key_1 === "workflowAgent" ? { workflowId: required(row.key_2), agentStepId: required(row.key_3) } : {}
|
|
9318
9628
|
} : row.dimension === "workflow" ? { workflowId: required(row.key_1) } : row.dimension === "series" ? { start: new Date(required(row.bucket_start)) } : {};
|
|
@@ -13263,6 +13573,7 @@ import {
|
|
|
13263
13573
|
import {
|
|
13264
13574
|
hasVectorProfile,
|
|
13265
13575
|
isVectorProfileQuery,
|
|
13576
|
+
linkEndpointObjectTypeIds,
|
|
13266
13577
|
normalizeVector,
|
|
13267
13578
|
vectorSearchCandidateLimit
|
|
13268
13579
|
} from "@sixb/core/internal/query";
|
|
@@ -13324,7 +13635,7 @@ function compileObjectQueryInternal(projectId, query, ctx) {
|
|
|
13324
13635
|
case "page":
|
|
13325
13636
|
return compilePage(projectId, query.input, query.pageSize, query.pageToken, ctx);
|
|
13326
13637
|
case "traverse":
|
|
13327
|
-
return compileTraversal(projectId, query
|
|
13638
|
+
return compileTraversal(projectId, query, ctx);
|
|
13328
13639
|
case "set":
|
|
13329
13640
|
return compileSet(projectId, query.op, query.inputs, ctx);
|
|
13330
13641
|
case "project":
|
|
@@ -13605,9 +13916,11 @@ function compilePage(projectId, inputQuery, rawPageSize, pageToken, ctx) {
|
|
|
13605
13916
|
}
|
|
13606
13917
|
};
|
|
13607
13918
|
}
|
|
13608
|
-
function compileTraversal(projectId,
|
|
13609
|
-
const
|
|
13919
|
+
function compileTraversal(projectId, traversal, ctx) {
|
|
13920
|
+
const { linkId, direction, sourceObjectTypeId } = traversal;
|
|
13921
|
+
const input = compileObjectQueryInternal(projectId, traversal.input, exactContext(ctx));
|
|
13610
13922
|
const outputAlias = direction === "outgoing" ? "target_object" : "source_object";
|
|
13923
|
+
const endpointType = compileEndpointTypes(outputAlias, linkEndpointObjectTypeIds(traversal));
|
|
13611
13924
|
const joinSql = direction === "outgoing" ? `
|
|
13612
13925
|
JOIN ${ctx.source.linksTable} AS edge
|
|
13613
13926
|
ON edge.project_id = input.project_id
|
|
@@ -13618,6 +13931,7 @@ function compileTraversal(projectId, inputQuery, linkId, direction, sourceObject
|
|
|
13618
13931
|
ON target_object.project_id = edge.project_id
|
|
13619
13932
|
AND target_object.object_type_id = edge.target_type_id
|
|
13620
13933
|
AND target_object.primary_id = edge.target_id
|
|
13934
|
+
${endpointType.sql}
|
|
13621
13935
|
` : `
|
|
13622
13936
|
JOIN ${ctx.source.linksTable} AS edge
|
|
13623
13937
|
ON edge.project_id = input.project_id
|
|
@@ -13629,6 +13943,7 @@ function compileTraversal(projectId, inputQuery, linkId, direction, sourceObject
|
|
|
13629
13943
|
ON source_object.project_id = edge.project_id
|
|
13630
13944
|
AND source_object.object_type_id = edge.source_type_id
|
|
13631
13945
|
AND source_object.primary_id = edge.source_id
|
|
13946
|
+
${endpointType.sql}
|
|
13632
13947
|
`;
|
|
13633
13948
|
const order = compileOrder(identityOrderFields());
|
|
13634
13949
|
const qualifiedOrder = compileOrder(identityOrderFields(), outputAlias);
|
|
@@ -13641,7 +13956,8 @@ function compileTraversal(projectId, inputQuery, linkId, direction, sourceObject
|
|
|
13641
13956
|
const args = [
|
|
13642
13957
|
...input.args,
|
|
13643
13958
|
linkId,
|
|
13644
|
-
...
|
|
13959
|
+
...direction === "incoming" && sourceObjectTypeId !== undefined ? [sourceObjectTypeId] : [],
|
|
13960
|
+
...endpointType.args,
|
|
13645
13961
|
...qualifiedOrder.args
|
|
13646
13962
|
];
|
|
13647
13963
|
return {
|
|
@@ -13657,6 +13973,14 @@ function compileTraversal(projectId, inputQuery, linkId, direction, sourceObject
|
|
|
13657
13973
|
}
|
|
13658
13974
|
};
|
|
13659
13975
|
}
|
|
13976
|
+
function compileEndpointTypes(alias, objectTypeIds) {
|
|
13977
|
+
if (!objectTypeIds?.length)
|
|
13978
|
+
return { sql: "", args: [] };
|
|
13979
|
+
return {
|
|
13980
|
+
sql: `AND ${alias}.object_type_id IN (${objectTypeIds.map(() => "?").join(", ")})`,
|
|
13981
|
+
args: [...objectTypeIds]
|
|
13982
|
+
};
|
|
13983
|
+
}
|
|
13660
13984
|
function compileExpand(projectId, inputQuery, expansions, ctx) {
|
|
13661
13985
|
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx));
|
|
13662
13986
|
const expand = compileExpansionsObject(expansions, { project: "input.project_id", type: "input.object_type_id", id: "input.primary_id" }, "", ctx);
|
|
@@ -13707,7 +14031,8 @@ function compileExpansionValue(expansion, parent, path, ctx) {
|
|
|
13707
14031
|
`${parentId} = ${parent.id}`,
|
|
13708
14032
|
`${edge}.link_id = ?`
|
|
13709
14033
|
];
|
|
13710
|
-
const
|
|
14034
|
+
const endpointType = compileEndpointTypes(target, expansion.endpointObjectTypeIds);
|
|
14035
|
+
const whereArgs = [...endpointType.args, expansion.linkId];
|
|
13711
14036
|
if (incoming && expansion.sourceObjectTypeId !== undefined) {
|
|
13712
14037
|
whereParts.push(`${edge}.source_type_id = ?`);
|
|
13713
14038
|
whereArgs.push(expansion.sourceObjectTypeId);
|
|
@@ -13718,6 +14043,7 @@ function compileExpansionValue(expansion, parent, path, ctx) {
|
|
|
13718
14043
|
ON ${target}.project_id = ${edge}.project_id
|
|
13719
14044
|
AND ${target}.object_type_id = ${neighborType}
|
|
13720
14045
|
AND ${target}.primary_id = ${neighborId}
|
|
14046
|
+
${endpointType.sql}
|
|
13721
14047
|
WHERE ${whereParts.join(" AND ")}
|
|
13722
14048
|
`;
|
|
13723
14049
|
if (expansion.cardinality === "one") {
|
|
@@ -15620,6 +15946,9 @@ class SqliteOntologyCommitStorage {
|
|
|
15620
15946
|
assertNonnegativeInteger(offset, "Ontology commit list offset");
|
|
15621
15947
|
if (limit !== -1)
|
|
15622
15948
|
assertNonnegativeInteger(limit, "Ontology commit list limit");
|
|
15949
|
+
if (input.committedAt !== undefined) {
|
|
15950
|
+
assertTimestamp(input.committedAt, "Ontology commit list committedAt");
|
|
15951
|
+
}
|
|
15623
15952
|
const filters = ["project_id = ?"];
|
|
15624
15953
|
const values = [input.projectId];
|
|
15625
15954
|
if (input.run?.kind === "action") {
|
|
@@ -15629,6 +15958,10 @@ class SqliteOntologyCommitStorage {
|
|
|
15629
15958
|
filters.push("origin_run_id = ? AND origin_kind IN ('projection', 'telemetry')");
|
|
15630
15959
|
values.push(input.run.id);
|
|
15631
15960
|
}
|
|
15961
|
+
if (input.committedAt !== undefined) {
|
|
15962
|
+
filters.push("committed_at = ?");
|
|
15963
|
+
values.push(input.committedAt);
|
|
15964
|
+
}
|
|
15632
15965
|
const where = filters.join(" AND ");
|
|
15633
15966
|
const totalRow = this.db.query(`SELECT COUNT(*) AS total FROM ontology_commits WHERE ${where}`).get(...values);
|
|
15634
15967
|
const direction = input.order === "desc" ? "DESC" : "ASC";
|
|
@@ -15680,6 +16013,7 @@ import {
|
|
|
15680
16013
|
invalidCorrelation as invalidCorrelation2,
|
|
15681
16014
|
materializationOutboxWrite,
|
|
15682
16015
|
materializationPlanChunk,
|
|
16016
|
+
prepareMaterializationStateRead,
|
|
15683
16017
|
sameNonnegativeCounts as sameCounts,
|
|
15684
16018
|
uniqueSorted
|
|
15685
16019
|
} from "@sixb/core/internal/ontology-storage-provider";
|
|
@@ -17851,6 +18185,17 @@ class SqliteOntologyMaterializationStorage {
|
|
|
17851
18185
|
}
|
|
17852
18186
|
}
|
|
17853
18187
|
}
|
|
18188
|
+
async readState(input) {
|
|
18189
|
+
const request = prepareMaterializationStateRead(input);
|
|
18190
|
+
return runDeferredReadTransaction(this.db, () => {
|
|
18191
|
+
const reader = new SqliteMaterializationStateReader(this.db, request.projectId);
|
|
18192
|
+
return {
|
|
18193
|
+
objects: reader.objectStates(request.objects),
|
|
18194
|
+
links: reader.linkStates(request.links),
|
|
18195
|
+
linkScopes: reader.linkSlotStates(request.linkScopes)
|
|
18196
|
+
};
|
|
18197
|
+
});
|
|
18198
|
+
}
|
|
17854
18199
|
async stageWork(input) {
|
|
17855
18200
|
this.sessions.stage(input);
|
|
17856
18201
|
await yieldSqliteEventLoop();
|
|
@@ -21865,4 +22210,4 @@ export {
|
|
|
21865
22210
|
migrateSqliteStorage
|
|
21866
22211
|
};
|
|
21867
22212
|
|
|
21868
|
-
//# debugId=
|
|
22213
|
+
//# debugId=38D04B34BA5E877464756E2164756E21
|