@anvia/studio 1.0.6 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +138 -32
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -6480,10 +6480,11 @@ var InMemoryStudioStore = class {
|
|
|
6480
6480
|
kind = "memory";
|
|
6481
6481
|
compaction = {
|
|
6482
6482
|
snapshot: ({ scope }) => {
|
|
6483
|
-
const
|
|
6483
|
+
const session = this.sessions.get(scope.sessionId);
|
|
6484
|
+
const messages = session?.messages ?? [];
|
|
6484
6485
|
return Promise.resolve({
|
|
6485
|
-
revision:
|
|
6486
|
-
messages:
|
|
6486
|
+
revision: String(session?.storeRevision ?? 0),
|
|
6487
|
+
messages: projectedMessages(messages, session?.compactionState)
|
|
6487
6488
|
});
|
|
6488
6489
|
},
|
|
6489
6490
|
replacePrefix: (options) => this.replaceCompactionPrefix(options)
|
|
@@ -6504,6 +6505,7 @@ var InMemoryStudioStore = class {
|
|
|
6504
6505
|
updatedAt: now,
|
|
6505
6506
|
messageCount: 0,
|
|
6506
6507
|
messages: [],
|
|
6508
|
+
storeRevision: 0,
|
|
6507
6509
|
runs: [],
|
|
6508
6510
|
logs: []
|
|
6509
6511
|
};
|
|
@@ -6536,6 +6538,7 @@ var InMemoryStudioStore = class {
|
|
|
6536
6538
|
const session = this.sessions.get(input.scope.sessionId);
|
|
6537
6539
|
if (session !== void 0) {
|
|
6538
6540
|
session.messages.push(...cloneMessages(input.messages));
|
|
6541
|
+
session.storeRevision += 1;
|
|
6539
6542
|
session.messageCount = session.messages.length;
|
|
6540
6543
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6541
6544
|
}
|
|
@@ -6545,6 +6548,8 @@ var InMemoryStudioStore = class {
|
|
|
6545
6548
|
const session = this.sessions.get(scope.sessionId);
|
|
6546
6549
|
if (session !== void 0) {
|
|
6547
6550
|
session.messages = [];
|
|
6551
|
+
delete session.compactionState;
|
|
6552
|
+
session.storeRevision += 1;
|
|
6548
6553
|
session.runs = [];
|
|
6549
6554
|
session.messageCount = 0;
|
|
6550
6555
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -6565,11 +6570,20 @@ var InMemoryStudioStore = class {
|
|
|
6565
6570
|
throw new RangeError("messageCount must be a positive integer.");
|
|
6566
6571
|
}
|
|
6567
6572
|
const session = this.sessions.get(input.scope.sessionId);
|
|
6568
|
-
if (session === void 0 ||
|
|
6573
|
+
if (session === void 0 || String(session.storeRevision) !== input.revision) {
|
|
6569
6574
|
return Promise.resolve({ status: "conflict" });
|
|
6570
6575
|
}
|
|
6571
|
-
|
|
6572
|
-
|
|
6576
|
+
const physicalPrefixCount = input.messageCount - (session.compactionState === void 0 ? 0 : 1);
|
|
6577
|
+
const activeMessageCount = session.messages.length - (session.compactionState?.summarizedThroughPosition ?? -1) - 1;
|
|
6578
|
+
if (physicalPrefixCount < 0 || physicalPrefixCount > activeMessageCount) {
|
|
6579
|
+
return Promise.resolve({ status: "conflict" });
|
|
6580
|
+
}
|
|
6581
|
+
session.compactionState = {
|
|
6582
|
+
generation: (session.compactionState?.generation ?? 0) + 1,
|
|
6583
|
+
summary: structuredClone(input.replacement),
|
|
6584
|
+
summarizedThroughPosition: (session.compactionState?.summarizedThroughPosition ?? -1) + physicalPrefixCount
|
|
6585
|
+
};
|
|
6586
|
+
session.storeRevision += 1;
|
|
6573
6587
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6574
6588
|
return Promise.resolve({ status: "committed" });
|
|
6575
6589
|
}
|
|
@@ -6713,8 +6727,12 @@ function studioRunId(scope) {
|
|
|
6713
6727
|
const value = scope.metadata?.studioRunId;
|
|
6714
6728
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
6715
6729
|
}
|
|
6716
|
-
function
|
|
6717
|
-
return
|
|
6730
|
+
function projectedMessages(messages, state) {
|
|
6731
|
+
if (state === void 0) return cloneMessages(messages);
|
|
6732
|
+
return [
|
|
6733
|
+
structuredClone(state.summary),
|
|
6734
|
+
...cloneMessages(messages.slice(state.summarizedThroughPosition + 1))
|
|
6735
|
+
];
|
|
6718
6736
|
}
|
|
6719
6737
|
function serializeJsonError(error) {
|
|
6720
6738
|
if (error instanceof Error) {
|
|
@@ -7496,6 +7514,50 @@ import { mkdirSync } from "fs";
|
|
|
7496
7514
|
import { createRequire } from "module";
|
|
7497
7515
|
import { dirname, resolve } from "path";
|
|
7498
7516
|
import { isJsonValue as isJsonValue3 } from "@anvia/core/completion";
|
|
7517
|
+
|
|
7518
|
+
// src/storage/compaction-state.ts
|
|
7519
|
+
import { parseMessage } from "@anvia/core/completion";
|
|
7520
|
+
import { isMemoryCompactionMessage } from "@anvia/core/memory";
|
|
7521
|
+
function parseStudioCompactionState(value) {
|
|
7522
|
+
if (value === null) return void 0;
|
|
7523
|
+
const parsed = JSON.parse(value);
|
|
7524
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
7525
|
+
throw new Error("Stored Studio memory compaction state is invalid.");
|
|
7526
|
+
}
|
|
7527
|
+
const record = parsed;
|
|
7528
|
+
let summary;
|
|
7529
|
+
try {
|
|
7530
|
+
summary = parseMessage(record.summary);
|
|
7531
|
+
} catch (cause) {
|
|
7532
|
+
throw new Error("Stored Studio memory compaction state summary is invalid.", { cause });
|
|
7533
|
+
}
|
|
7534
|
+
if (record.version !== 1 || !Number.isSafeInteger(record.generation) || record.generation < 1 || !isMemoryCompactionMessage(summary) || !Number.isSafeInteger(record.summarizedThroughPosition) || record.summarizedThroughPosition < 0) {
|
|
7535
|
+
throw new Error("Stored Studio memory compaction state is invalid.");
|
|
7536
|
+
}
|
|
7537
|
+
return {
|
|
7538
|
+
version: 1,
|
|
7539
|
+
generation: record.generation,
|
|
7540
|
+
summary,
|
|
7541
|
+
summarizedThroughPosition: record.summarizedThroughPosition
|
|
7542
|
+
};
|
|
7543
|
+
}
|
|
7544
|
+
function projectStudioCompactionMessages(rows, state) {
|
|
7545
|
+
if (state === void 0) return rows.map((row) => row.message);
|
|
7546
|
+
return [state.summary, ...activeStudioCompactionMessages(rows, state).map((row) => row.message)];
|
|
7547
|
+
}
|
|
7548
|
+
function activeStudioCompactionMessages(rows, state) {
|
|
7549
|
+
if (state === void 0) return rows;
|
|
7550
|
+
const boundaryIndex = rows.findIndex((row) => row.position === state.summarizedThroughPosition);
|
|
7551
|
+
if (boundaryIndex === -1) {
|
|
7552
|
+
throw new Error("Stored Studio memory compaction state boundary is invalid.");
|
|
7553
|
+
}
|
|
7554
|
+
return rows.slice(boundaryIndex + 1);
|
|
7555
|
+
}
|
|
7556
|
+
function studioCompactionRevision(rows, state) {
|
|
7557
|
+
return JSON.stringify([state?.generation ?? 0, rows]);
|
|
7558
|
+
}
|
|
7559
|
+
|
|
7560
|
+
// src/storage/sqlite-store.ts
|
|
7499
7561
|
var DatabaseSync;
|
|
7500
7562
|
function createSqliteSessionStore(options = {}) {
|
|
7501
7563
|
return new SqliteSessionStore(options.path ?? ":memory:");
|
|
@@ -7508,8 +7570,13 @@ var SqliteSessionStore = class {
|
|
|
7508
7570
|
kind = "sqlite";
|
|
7509
7571
|
compaction = {
|
|
7510
7572
|
snapshot: ({ scope }) => {
|
|
7511
|
-
const
|
|
7512
|
-
|
|
7573
|
+
const session = this.getCompactionSessionRow(scope.sessionId);
|
|
7574
|
+
const state = parseStudioCompactionState(session?.compaction_state_json ?? null);
|
|
7575
|
+
const rows = this.listCompactionMessages(scope.sessionId, state);
|
|
7576
|
+
return Promise.resolve({
|
|
7577
|
+
revision: studioCompactionRevision(rows, state),
|
|
7578
|
+
messages: projectStudioCompactionMessages(rows, state)
|
|
7579
|
+
});
|
|
7513
7580
|
},
|
|
7514
7581
|
replacePrefix: (options) => this.replaceCompactionPrefix(options)
|
|
7515
7582
|
};
|
|
@@ -7628,7 +7695,8 @@ var SqliteSessionStore = class {
|
|
|
7628
7695
|
db.exec("BEGIN IMMEDIATE");
|
|
7629
7696
|
db.prepare(
|
|
7630
7697
|
`UPDATE anvia_studio_sessions
|
|
7631
|
-
SET
|
|
7698
|
+
SET compaction_state_json = NULL,
|
|
7699
|
+
updated_at = $updatedAt
|
|
7632
7700
|
WHERE id = $id`
|
|
7633
7701
|
).run({
|
|
7634
7702
|
$id: scope.sessionId,
|
|
@@ -7668,26 +7736,41 @@ var SqliteSessionStore = class {
|
|
|
7668
7736
|
const db = this.database();
|
|
7669
7737
|
try {
|
|
7670
7738
|
db.exec("BEGIN IMMEDIATE");
|
|
7671
|
-
const
|
|
7672
|
-
|
|
7739
|
+
const session = this.getCompactionSessionRow(input.scope.sessionId);
|
|
7740
|
+
const state = parseStudioCompactionState(session?.compaction_state_json ?? null);
|
|
7741
|
+
const rows = this.listCompactionMessages(input.scope.sessionId, state);
|
|
7742
|
+
if (session === void 0 || studioCompactionRevision(rows, state) !== input.revision) {
|
|
7673
7743
|
db.exec("ROLLBACK");
|
|
7674
7744
|
return Promise.resolve({ status: "conflict" });
|
|
7675
7745
|
}
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7746
|
+
const physicalPrefixCount = input.messageCount - (state === void 0 ? 0 : 1);
|
|
7747
|
+
const activeRows = activeStudioCompactionMessages(rows, state);
|
|
7748
|
+
if (physicalPrefixCount < 0 || physicalPrefixCount > activeRows.length) {
|
|
7749
|
+
db.exec("ROLLBACK");
|
|
7750
|
+
return Promise.resolve({ status: "conflict" });
|
|
7751
|
+
}
|
|
7752
|
+
const summarizedThroughPosition = physicalPrefixCount === 0 ? state?.summarizedThroughPosition : activeRows[physicalPrefixCount - 1]?.position;
|
|
7753
|
+
if (summarizedThroughPosition === void 0) {
|
|
7754
|
+
db.exec("ROLLBACK");
|
|
7755
|
+
return Promise.resolve({ status: "conflict" });
|
|
7756
|
+
}
|
|
7757
|
+
const nextState = {
|
|
7758
|
+
version: 1,
|
|
7759
|
+
generation: (state?.generation ?? 0) + 1,
|
|
7760
|
+
summary: input.replacement,
|
|
7761
|
+
summarizedThroughPosition
|
|
7762
|
+
};
|
|
7679
7763
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7680
|
-
this.insertMessages(
|
|
7681
|
-
input.scope.sessionId,
|
|
7682
|
-
[input.replacement, ...messages.slice(input.messageCount)],
|
|
7683
|
-
0,
|
|
7684
|
-
updatedAt
|
|
7685
|
-
);
|
|
7686
7764
|
db.prepare(
|
|
7687
7765
|
`UPDATE anvia_studio_sessions
|
|
7688
|
-
SET
|
|
7766
|
+
SET compaction_state_json = $compactionState,
|
|
7767
|
+
updated_at = $updatedAt
|
|
7689
7768
|
WHERE id = $id`
|
|
7690
|
-
).run({
|
|
7769
|
+
).run({
|
|
7770
|
+
$id: input.scope.sessionId,
|
|
7771
|
+
$compactionState: JSON.stringify(nextState),
|
|
7772
|
+
$updatedAt: updatedAt
|
|
7773
|
+
});
|
|
7691
7774
|
db.exec("COMMIT");
|
|
7692
7775
|
return Promise.resolve({ status: "committed" });
|
|
7693
7776
|
} catch (error) {
|
|
@@ -8185,6 +8268,7 @@ var SqliteSessionStore = class {
|
|
|
8185
8268
|
agent_id TEXT NOT NULL,
|
|
8186
8269
|
title TEXT,
|
|
8187
8270
|
metadata_json TEXT,
|
|
8271
|
+
compaction_state_json TEXT,
|
|
8188
8272
|
created_at TEXT NOT NULL,
|
|
8189
8273
|
updated_at TEXT NOT NULL
|
|
8190
8274
|
) STRICT;
|
|
@@ -8290,6 +8374,7 @@ var SqliteSessionStore = class {
|
|
|
8290
8374
|
CREATE INDEX IF NOT EXISTS anvia_studio_traces_session_started_idx
|
|
8291
8375
|
ON anvia_studio_traces(session_id, started_at DESC);
|
|
8292
8376
|
`);
|
|
8377
|
+
ensureSessionCompactionStateColumn(db);
|
|
8293
8378
|
ensureMessageMetadataColumn(db);
|
|
8294
8379
|
this.db = db;
|
|
8295
8380
|
return db;
|
|
@@ -8301,6 +8386,13 @@ var SqliteSessionStore = class {
|
|
|
8301
8386
|
WHERE id = $id`
|
|
8302
8387
|
).get({ $id: id });
|
|
8303
8388
|
}
|
|
8389
|
+
getCompactionSessionRow(id) {
|
|
8390
|
+
return this.database().prepare(
|
|
8391
|
+
`SELECT id, compaction_state_json
|
|
8392
|
+
FROM anvia_studio_sessions
|
|
8393
|
+
WHERE id = $id`
|
|
8394
|
+
).get({ $id: id });
|
|
8395
|
+
}
|
|
8304
8396
|
getSessionRun(sessionId, runId) {
|
|
8305
8397
|
return this.database().prepare(
|
|
8306
8398
|
`SELECT run_id, session_id, status, title, transcript_json, error_json, created_at, updated_at
|
|
@@ -8333,13 +8425,22 @@ var SqliteSessionStore = class {
|
|
|
8333
8425
|
return row.next_sequence;
|
|
8334
8426
|
}
|
|
8335
8427
|
listSessionMessages(sessionId) {
|
|
8428
|
+
return this.listSessionMessageEntries(sessionId).map((entry) => entry.message);
|
|
8429
|
+
}
|
|
8430
|
+
listCompactionMessages(sessionId, state) {
|
|
8431
|
+
return this.listSessionMessageEntries(sessionId, state?.summarizedThroughPosition);
|
|
8432
|
+
}
|
|
8433
|
+
listSessionMessageEntries(sessionId, minimumIndex) {
|
|
8336
8434
|
const db = this.database();
|
|
8435
|
+
const boundaryClause = minimumIndex === void 0 ? "" : "AND message_index >= $minimumIndex";
|
|
8436
|
+
const parameters = minimumIndex === void 0 ? { $sessionId: sessionId } : { $sessionId: sessionId, $minimumIndex: minimumIndex };
|
|
8337
8437
|
const messageRows = db.prepare(
|
|
8338
8438
|
`SELECT session_id, message_index, role, message_id, metadata_json, created_at
|
|
8339
8439
|
FROM anvia_studio_session_messages
|
|
8340
8440
|
WHERE session_id = $sessionId
|
|
8441
|
+
${boundaryClause}
|
|
8341
8442
|
ORDER BY message_index ASC`
|
|
8342
|
-
).all(
|
|
8443
|
+
).all(parameters);
|
|
8343
8444
|
if (messageRows.length === 0) {
|
|
8344
8445
|
return [];
|
|
8345
8446
|
}
|
|
@@ -8347,17 +8448,19 @@ var SqliteSessionStore = class {
|
|
|
8347
8448
|
`SELECT session_id, message_index, part_index, type, part_json
|
|
8348
8449
|
FROM anvia_studio_session_message_parts
|
|
8349
8450
|
WHERE session_id = $sessionId
|
|
8451
|
+
${boundaryClause}
|
|
8350
8452
|
ORDER BY message_index ASC, part_index ASC`
|
|
8351
|
-
).all(
|
|
8453
|
+
).all(parameters);
|
|
8352
8454
|
const partsByMessage = /* @__PURE__ */ new Map();
|
|
8353
8455
|
for (const partRow of partRows) {
|
|
8354
8456
|
const parts = partsByMessage.get(partRow.message_index) ?? [];
|
|
8355
8457
|
parts.push(partRow);
|
|
8356
8458
|
partsByMessage.set(partRow.message_index, parts);
|
|
8357
8459
|
}
|
|
8358
|
-
return messageRows.map(
|
|
8359
|
-
|
|
8360
|
-
|
|
8460
|
+
return messageRows.map((row) => ({
|
|
8461
|
+
position: row.message_index,
|
|
8462
|
+
message: messageFromRows(row, partsByMessage.get(row.message_index) ?? [])
|
|
8463
|
+
}));
|
|
8361
8464
|
}
|
|
8362
8465
|
nextMessageIndex(sessionId) {
|
|
8363
8466
|
const row = this.database().prepare(
|
|
@@ -8561,6 +8664,12 @@ function ensureMessageMetadataColumn(db) {
|
|
|
8561
8664
|
db.exec("ALTER TABLE anvia_studio_session_messages ADD COLUMN metadata_json TEXT");
|
|
8562
8665
|
}
|
|
8563
8666
|
}
|
|
8667
|
+
function ensureSessionCompactionStateColumn(db) {
|
|
8668
|
+
const columns = db.prepare("PRAGMA table_info('anvia_studio_sessions')").all();
|
|
8669
|
+
if (!columns.some((column) => column.name === "compaction_state_json")) {
|
|
8670
|
+
db.exec("ALTER TABLE anvia_studio_sessions ADD COLUMN compaction_state_json TEXT");
|
|
8671
|
+
}
|
|
8672
|
+
}
|
|
8564
8673
|
function loadDatabaseSync() {
|
|
8565
8674
|
if (DatabaseSync !== void 0) {
|
|
8566
8675
|
return DatabaseSync;
|
|
@@ -8624,9 +8733,6 @@ function studioRunId2(scope) {
|
|
|
8624
8733
|
const value = scope.metadata?.studioRunId;
|
|
8625
8734
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
8626
8735
|
}
|
|
8627
|
-
function memoryRevision2(messages) {
|
|
8628
|
-
return JSON.stringify(messages);
|
|
8629
|
-
}
|
|
8630
8736
|
function serializeJsonError2(error) {
|
|
8631
8737
|
if (error instanceof Error) {
|
|
8632
8738
|
return {
|