tinker-agent 2.0.0 → 2.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/CHANGELOG.md +44 -1
- package/README.md +27 -2
- package/package.json +2 -1
- package/src/agent/context-meter.ts +2 -4
- package/src/agent/runtime-session.ts +9 -2
- package/src/agent/session-ledger.ts +12 -5
- package/src/agent/tool-result-content.ts +76 -0
- package/src/agent/types.ts +14 -2
- package/src/cli/config.ts +4 -0
- package/src/cli/model-profiles.ts +41 -2
- package/src/cli/public-config-contract.ts +30 -7
- package/src/cli/runner-dependencies.ts +5 -0
- package/src/cli/tui-memory.ts +1 -0
- package/src/cli/tui-runner.tsx +4 -0
- package/src/context/compiled-context-hash.ts +2 -1
- package/src/context/compiled-context-validator.ts +13 -4
- package/src/context/context-protocol-validator.ts +33 -2
- package/src/context/context-revision-compiler.ts +2 -1
- package/src/context/context-revision.ts +8 -2
- package/src/context/context-swap-renderer.ts +46 -12
- package/src/context/prefix-retirement-planner.ts +13 -9
- package/src/context/protocol-frame.ts +74 -7
- package/src/context/swap-planner.ts +19 -14
- package/src/events/observation-text-log.ts +1 -1
- package/src/events/stdout-event-printer.ts +6 -0
- package/src/image/image-asset-store.ts +32 -3
- package/src/memory/contracts.ts +63 -3
- package/src/memory/memory-coordinator.ts +319 -49
- package/src/memory/memory-extractor.ts +48 -48
- package/src/memory/memory-get-tool.ts +86 -0
- package/src/memory/memory-search-tool.ts +122 -33
- package/src/memory/memory-store.ts +227 -20
- package/src/model/fake-model-client.ts +129 -76
- package/src/model/model-client.ts +62 -11
- package/src/model/openai-chat-mapping.ts +2 -1
- package/src/model/openai-chat-model-client.ts +22 -10
- package/src/model/openai-model-utils.ts +61 -30
- package/src/model/openai-responses-mapping.ts +25 -1
- package/src/model/openai-responses-model-client.ts +27 -11
- package/src/model/token-estimator.ts +10 -0
- package/src/observation/observation-builder.ts +100 -25
- package/src/session/session-history-reader.ts +128 -5
- package/src/session/session-schema.ts +59 -9
- package/src/session/session-store.ts +343 -196
- package/src/tools/registry.ts +18 -0
- package/src/tools/types.ts +46 -0
- package/src/tools/view-image.ts +89 -0
- package/src/tools/wait.ts +85 -0
- package/src/tui/components/memory-browser.tsx +3 -0
- package/src/tui/components/prompt-input.tsx +48 -25
- package/src/tui/event-store.ts +61 -2
|
@@ -5,6 +5,12 @@ import {
|
|
|
5
5
|
type MessageSource,
|
|
6
6
|
} from "../context/context-source";
|
|
7
7
|
import { contentHash, userMessageHash } from "../context/protocol-frame";
|
|
8
|
+
import type { ToolResultContent } from "../agent/types";
|
|
9
|
+
import {
|
|
10
|
+
canonicalToolResultContentHash,
|
|
11
|
+
toolResultDisplayText,
|
|
12
|
+
validateToolResultContent,
|
|
13
|
+
} from "../agent/tool-result-content";
|
|
8
14
|
import {
|
|
9
15
|
parseImageAssetId,
|
|
10
16
|
parseImageAttachmentId,
|
|
@@ -132,6 +138,18 @@ type RecallImageRow = {
|
|
|
132
138
|
height: unknown;
|
|
133
139
|
};
|
|
134
140
|
|
|
141
|
+
type RecallToolBlockRow = {
|
|
142
|
+
message_id: unknown;
|
|
143
|
+
position: unknown;
|
|
144
|
+
kind: unknown;
|
|
145
|
+
text_content: unknown;
|
|
146
|
+
asset_id: unknown;
|
|
147
|
+
mime_type: unknown;
|
|
148
|
+
byte_length: unknown;
|
|
149
|
+
width: unknown;
|
|
150
|
+
height: unknown;
|
|
151
|
+
};
|
|
152
|
+
|
|
135
153
|
export function createSessionHistoryReader(input: {
|
|
136
154
|
database: Database;
|
|
137
155
|
sessionId: SessionId;
|
|
@@ -233,11 +251,15 @@ class SqliteSessionHistoryReader implements SessionHistoryReader {
|
|
|
233
251
|
const imageAttachments = this.loadImageAttachments(
|
|
234
252
|
rows.map((row) => nonEmptyString(row.message_id, "message_id") as MessageId),
|
|
235
253
|
);
|
|
254
|
+
const toolBlocks = this.loadToolContentBlocks(
|
|
255
|
+
rows.map((row) => nonEmptyString(row.message_id, "message_id") as MessageId),
|
|
256
|
+
);
|
|
236
257
|
decoded = rows.map((row) => {
|
|
237
258
|
const metadata = decodeRecallRow(row);
|
|
238
259
|
const attachments = imageAttachments.get(metadata.messageId) ?? [];
|
|
239
|
-
|
|
240
|
-
|
|
260
|
+
const blocks = toolBlocks.get(metadata.messageId);
|
|
261
|
+
verifyRecallContent(metadata, attachments, blocks);
|
|
262
|
+
const content = renderRecallContent(metadata.content, attachments, blocks);
|
|
241
263
|
return {
|
|
242
264
|
...metadata,
|
|
243
265
|
content,
|
|
@@ -293,14 +315,18 @@ class SqliteSessionHistoryReader implements SessionHistoryReader {
|
|
|
293
315
|
|
|
294
316
|
let metadata: ReturnType<typeof decodeRecallRow>;
|
|
295
317
|
let attachments: readonly UserImageAttachment[];
|
|
318
|
+
let toolBlocks: readonly ToolResultContent[] | undefined;
|
|
296
319
|
try {
|
|
297
320
|
metadata = decodeRecallRow(row);
|
|
298
321
|
attachments =
|
|
299
322
|
this.loadImageAttachments([metadata.messageId]).get(metadata.messageId) ?? [];
|
|
323
|
+
toolBlocks = this.loadToolContentBlocks([metadata.messageId]).get(
|
|
324
|
+
metadata.messageId,
|
|
325
|
+
);
|
|
300
326
|
} catch (error) {
|
|
301
327
|
throw sessionReadError("decode_recall_get", this.sessionId, error);
|
|
302
328
|
}
|
|
303
|
-
const actualHash = recallContentHash(metadata, attachments);
|
|
329
|
+
const actualHash = recallContentHash(metadata, attachments, toolBlocks);
|
|
304
330
|
const observationHash = row.observation_sha256;
|
|
305
331
|
if (
|
|
306
332
|
actualHash !== metadata.contentSha256 ||
|
|
@@ -314,7 +340,11 @@ class SqliteSessionHistoryReader implements SessionHistoryReader {
|
|
|
314
340
|
);
|
|
315
341
|
}
|
|
316
342
|
|
|
317
|
-
const renderedContent = renderRecallContent(
|
|
343
|
+
const renderedContent = renderRecallContent(
|
|
344
|
+
metadata.content,
|
|
345
|
+
attachments,
|
|
346
|
+
toolBlocks,
|
|
347
|
+
);
|
|
318
348
|
const page = sliceUtf8Page(renderedContent, input.byteOffset, input.byteLimit);
|
|
319
349
|
return Object.freeze({
|
|
320
350
|
source: formatMessageSource(metadata.messageId),
|
|
@@ -428,12 +458,90 @@ class SqliteSessionHistoryReader implements SessionHistoryReader {
|
|
|
428
458
|
]),
|
|
429
459
|
);
|
|
430
460
|
}
|
|
461
|
+
|
|
462
|
+
private loadToolContentBlocks(
|
|
463
|
+
messageIds: readonly MessageId[],
|
|
464
|
+
): ReadonlyMap<MessageId, readonly ToolResultContent[]> {
|
|
465
|
+
if (messageIds.length === 0) return new Map();
|
|
466
|
+
const unique = [...new Set(messageIds)];
|
|
467
|
+
let rows: RecallToolBlockRow[];
|
|
468
|
+
try {
|
|
469
|
+
this.requireStoreOpen();
|
|
470
|
+
rows = this.database
|
|
471
|
+
.query(
|
|
472
|
+
`SELECT tcb.message_id, tcb.position, tcb.kind, tcb.text_content,
|
|
473
|
+
ia.asset_id, ia.mime_type, ia.byte_length, ia.width, ia.height
|
|
474
|
+
FROM tool_message_content_blocks tcb
|
|
475
|
+
LEFT JOIN image_assets ia ON ia.asset_id = tcb.asset_id
|
|
476
|
+
WHERE tcb.message_id IN (${unique.map(() => "?").join(", ")})
|
|
477
|
+
ORDER BY tcb.message_id, tcb.position`,
|
|
478
|
+
)
|
|
479
|
+
.all(...unique) as RecallToolBlockRow[];
|
|
480
|
+
} catch (error) {
|
|
481
|
+
throw sessionReadError("read_recall_tool_blocks", this.sessionId, error);
|
|
482
|
+
}
|
|
483
|
+
const grouped = new Map<MessageId, ToolResultContent[]>();
|
|
484
|
+
for (const row of rows) {
|
|
485
|
+
const messageId = nonEmptyString(row.message_id, "message_id") as MessageId;
|
|
486
|
+
const blocks = grouped.get(messageId) ?? [];
|
|
487
|
+
if (
|
|
488
|
+
nonNegativeSafeInteger(row.position, "tool block position") !== blocks.length
|
|
489
|
+
) {
|
|
490
|
+
throw new Error("Recall tool content block positions are not contiguous.");
|
|
491
|
+
}
|
|
492
|
+
const kind = enumValue(row.kind, ["text", "image"] as const, "tool block kind");
|
|
493
|
+
blocks.push(
|
|
494
|
+
kind === "text"
|
|
495
|
+
? Object.freeze({
|
|
496
|
+
type: "text",
|
|
497
|
+
text: nonEmptyString(row.text_content, "tool block text"),
|
|
498
|
+
})
|
|
499
|
+
: Object.freeze({
|
|
500
|
+
type: "image",
|
|
501
|
+
asset: Object.freeze({
|
|
502
|
+
assetId: parseImageAssetId(
|
|
503
|
+
nonEmptyString(row.asset_id, "tool block asset_id"),
|
|
504
|
+
),
|
|
505
|
+
mimeType: enumValue(
|
|
506
|
+
row.mime_type,
|
|
507
|
+
["image/png", "image/jpeg", "image/webp"] as const,
|
|
508
|
+
"tool block MIME type",
|
|
509
|
+
),
|
|
510
|
+
byteLength: safeInteger(row.byte_length, "tool block byte length"),
|
|
511
|
+
width: safeInteger(row.width, "tool block width"),
|
|
512
|
+
height: safeInteger(row.height, "tool block height"),
|
|
513
|
+
}),
|
|
514
|
+
}),
|
|
515
|
+
);
|
|
516
|
+
grouped.set(messageId, blocks);
|
|
517
|
+
}
|
|
518
|
+
return new Map(
|
|
519
|
+
[...grouped].map(([messageId, blocks]) => {
|
|
520
|
+
validateToolResultContent(blocks);
|
|
521
|
+
return [messageId, Object.freeze(blocks)] as const;
|
|
522
|
+
}),
|
|
523
|
+
);
|
|
524
|
+
}
|
|
431
525
|
}
|
|
432
526
|
|
|
433
527
|
export function renderRecallContent(
|
|
434
528
|
content: string,
|
|
435
529
|
attachments: readonly UserImageAttachment[],
|
|
530
|
+
toolBlocks?: readonly ToolResultContent[],
|
|
436
531
|
): string {
|
|
532
|
+
if (toolBlocks !== undefined) {
|
|
533
|
+
const text = toolBlocks
|
|
534
|
+
.flatMap((block) => (block.type === "text" ? [block.text] : []))
|
|
535
|
+
.join("\n");
|
|
536
|
+
const notes = toolBlocks.flatMap((block) =>
|
|
537
|
+
block.type === "image"
|
|
538
|
+
? [
|
|
539
|
+
`[Historical tool image omitted: ${block.asset.mimeType}, ${block.asset.width}x${block.asset.height}, asset=${block.asset.assetId.slice(0, 12)}….]`,
|
|
540
|
+
]
|
|
541
|
+
: [],
|
|
542
|
+
);
|
|
543
|
+
return notes.length === 0 ? text : `${text}\n\n${notes.join("\n")}`;
|
|
544
|
+
}
|
|
437
545
|
if (attachments.length === 0) return content;
|
|
438
546
|
const notes = attachments.map(
|
|
439
547
|
(attachment) =>
|
|
@@ -445,8 +553,9 @@ export function renderRecallContent(
|
|
|
445
553
|
function verifyRecallContent(
|
|
446
554
|
metadata: ReturnType<typeof decodeRecallRow>,
|
|
447
555
|
attachments: readonly UserImageAttachment[],
|
|
556
|
+
toolBlocks?: readonly ToolResultContent[],
|
|
448
557
|
): void {
|
|
449
|
-
if (recallContentHash(metadata, attachments) !== metadata.contentSha256) {
|
|
558
|
+
if (recallContentHash(metadata, attachments, toolBlocks) !== metadata.contentSha256) {
|
|
450
559
|
throw new Error("Canonical Recall content failed its integrity check.");
|
|
451
560
|
}
|
|
452
561
|
}
|
|
@@ -454,7 +563,21 @@ function verifyRecallContent(
|
|
|
454
563
|
function recallContentHash(
|
|
455
564
|
metadata: ReturnType<typeof decodeRecallRow>,
|
|
456
565
|
attachments: readonly UserImageAttachment[],
|
|
566
|
+
toolBlocks?: readonly ToolResultContent[],
|
|
457
567
|
): string {
|
|
568
|
+
if (metadata.role === "tool") {
|
|
569
|
+
if (attachments.length > 0 || toolBlocks === undefined) {
|
|
570
|
+
throw new Error("Tool Recall message has invalid media relations.");
|
|
571
|
+
}
|
|
572
|
+
validateToolResultContent(toolBlocks);
|
|
573
|
+
if (toolResultDisplayText(toolBlocks) !== metadata.content) {
|
|
574
|
+
throw new Error("Tool Recall display projection does not match its blocks.");
|
|
575
|
+
}
|
|
576
|
+
return canonicalToolResultContentHash(toolBlocks);
|
|
577
|
+
}
|
|
578
|
+
if (toolBlocks !== undefined) {
|
|
579
|
+
throw new Error("Non-tool Recall message has tool content blocks.");
|
|
580
|
+
}
|
|
458
581
|
if (metadata.role !== "user") {
|
|
459
582
|
if (attachments.length > 0) {
|
|
460
583
|
throw new Error("Non-user Recall message has image attachments.");
|
|
@@ -4,7 +4,7 @@ import type { SessionId } from "../ids/runtime-id";
|
|
|
4
4
|
import { SessionError } from "./session-errors";
|
|
5
5
|
|
|
6
6
|
export const SESSION_APPLICATION_ID = 0x544b5231;
|
|
7
|
-
export const SESSION_SCHEMA_VERSION =
|
|
7
|
+
export const SESSION_SCHEMA_VERSION = 10;
|
|
8
8
|
|
|
9
9
|
type SchemaDefinition = {
|
|
10
10
|
type: "table" | "index" | "trigger" | "view";
|
|
@@ -27,7 +27,7 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
27
27
|
name: "session_meta",
|
|
28
28
|
sql: `CREATE TABLE session_meta (
|
|
29
29
|
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
30
|
-
schema_version INTEGER NOT NULL CHECK (schema_version =
|
|
30
|
+
schema_version INTEGER NOT NULL CHECK (schema_version = 10),
|
|
31
31
|
schema_fingerprint TEXT NOT NULL,
|
|
32
32
|
initialization_state TEXT NOT NULL CHECK (initialization_state IN ('creating', 'ready')),
|
|
33
33
|
session_id TEXT NOT NULL UNIQUE,
|
|
@@ -231,6 +231,24 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
231
231
|
FOREIGN KEY (asset_id) REFERENCES image_assets(asset_id)
|
|
232
232
|
) STRICT`,
|
|
233
233
|
},
|
|
234
|
+
{
|
|
235
|
+
type: "table",
|
|
236
|
+
name: "tool_message_content_blocks",
|
|
237
|
+
sql: `CREATE TABLE tool_message_content_blocks (
|
|
238
|
+
message_id TEXT NOT NULL,
|
|
239
|
+
position INTEGER NOT NULL CHECK (position >= 0),
|
|
240
|
+
kind TEXT NOT NULL CHECK (kind IN ('text', 'image')),
|
|
241
|
+
text_content TEXT,
|
|
242
|
+
asset_id TEXT,
|
|
243
|
+
PRIMARY KEY (message_id, position),
|
|
244
|
+
FOREIGN KEY (message_id) REFERENCES messages(message_id),
|
|
245
|
+
FOREIGN KEY (asset_id) REFERENCES image_assets(asset_id),
|
|
246
|
+
CHECK (
|
|
247
|
+
(kind = 'text' AND text_content IS NOT NULL AND length(text_content) > 0 AND asset_id IS NULL) OR
|
|
248
|
+
(kind = 'image' AND text_content IS NULL AND asset_id IS NOT NULL)
|
|
249
|
+
)
|
|
250
|
+
) STRICT`,
|
|
251
|
+
},
|
|
234
252
|
{
|
|
235
253
|
type: "table",
|
|
236
254
|
name: "context_surfaces",
|
|
@@ -334,7 +352,7 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
334
352
|
frame_id TEXT NOT NULL,
|
|
335
353
|
ordinal INTEGER NOT NULL CHECK (ordinal >= 1),
|
|
336
354
|
representation TEXT NOT NULL CHECK (representation = 'swapped'),
|
|
337
|
-
renderer_format TEXT NOT NULL CHECK (renderer_format IN ('swap-observation-v1', 'skill-activation-receipt-v1')),
|
|
355
|
+
renderer_format TEXT NOT NULL CHECK (renderer_format IN ('swap-observation-v1', 'swap-tool-image-v1', 'skill-activation-receipt-v1')),
|
|
338
356
|
source TEXT NOT NULL,
|
|
339
357
|
original_content_sha256 TEXT NOT NULL CHECK (length(original_content_sha256) = 64),
|
|
340
358
|
rendered_content TEXT NOT NULL CHECK (length(rendered_content) > 0),
|
|
@@ -351,7 +369,7 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
351
369
|
FOREIGN KEY (message_id) REFERENCES messages(message_id),
|
|
352
370
|
FOREIGN KEY (frame_id) REFERENCES protocol_frames(frame_id),
|
|
353
371
|
CHECK (original_bytes = rendered_bytes + byte_savings),
|
|
354
|
-
CHECK (renderer_format
|
|
372
|
+
CHECK (renderer_format = 'swap-tool-image-v1' OR byte_savings > 0)
|
|
355
373
|
) STRICT`,
|
|
356
374
|
},
|
|
357
375
|
{
|
|
@@ -428,6 +446,11 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
428
446
|
name: "idx_message_image_attachments_asset",
|
|
429
447
|
sql: "CREATE INDEX idx_message_image_attachments_asset ON message_image_attachments(asset_id)",
|
|
430
448
|
},
|
|
449
|
+
{
|
|
450
|
+
type: "index",
|
|
451
|
+
name: "idx_tool_message_content_blocks_asset",
|
|
452
|
+
sql: "CREATE INDEX idx_tool_message_content_blocks_asset ON tool_message_content_blocks(asset_id)",
|
|
453
|
+
},
|
|
431
454
|
{
|
|
432
455
|
type: "index",
|
|
433
456
|
name: "idx_turns_session_recent",
|
|
@@ -476,9 +499,32 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
476
499
|
...immutableTriggers("tool_results"),
|
|
477
500
|
...immutableTriggers("image_assets"),
|
|
478
501
|
...immutableTriggers("message_image_attachments"),
|
|
502
|
+
...immutableTriggers("tool_message_content_blocks"),
|
|
479
503
|
...immutableTriggers("context_surfaces"),
|
|
480
504
|
...immutableTriggers("context_revisions"),
|
|
481
505
|
...immutableTriggers("context_overrides"),
|
|
506
|
+
{
|
|
507
|
+
type: "trigger",
|
|
508
|
+
name: "tool_message_content_blocks_validate_insert",
|
|
509
|
+
sql: `CREATE TRIGGER tool_message_content_blocks_validate_insert
|
|
510
|
+
BEFORE INSERT ON tool_message_content_blocks
|
|
511
|
+
WHEN NOT (
|
|
512
|
+
EXISTS (
|
|
513
|
+
SELECT 1 FROM messages m
|
|
514
|
+
WHERE m.message_id = NEW.message_id AND m.role = 'tool'
|
|
515
|
+
) AND
|
|
516
|
+
NEW.position = (
|
|
517
|
+
SELECT COUNT(*) FROM tool_message_content_blocks
|
|
518
|
+
WHERE message_id = NEW.message_id
|
|
519
|
+
) AND
|
|
520
|
+
NOT (
|
|
521
|
+
NEW.kind = 'text' AND NEW.position > 0 AND
|
|
522
|
+
(SELECT kind FROM tool_message_content_blocks
|
|
523
|
+
WHERE message_id = NEW.message_id AND position = NEW.position - 1) = 'text'
|
|
524
|
+
)
|
|
525
|
+
)
|
|
526
|
+
BEGIN SELECT RAISE(ABORT, 'invalid tool message content block insert'); END`,
|
|
527
|
+
},
|
|
482
528
|
{
|
|
483
529
|
type: "trigger",
|
|
484
530
|
name: "skill_activations_no_delete",
|
|
@@ -636,7 +682,7 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
636
682
|
SELECT 1 FROM context_revisions cr
|
|
637
683
|
WHERE cr.revision_id = NEW.introduced_revision_id
|
|
638
684
|
AND cr.session_id = NEW.session_id
|
|
639
|
-
AND ((cr.kind = 'swap_only' AND NEW.renderer_format
|
|
685
|
+
AND ((cr.kind = 'swap_only' AND NEW.renderer_format IN ('swap-observation-v1', 'swap-tool-image-v1')) OR
|
|
640
686
|
(cr.kind = 'skills_update' AND NEW.renderer_format = 'skill-activation-receipt-v1'))
|
|
641
687
|
AND NEW.ordinal >= cr.keep_from_ordinal
|
|
642
688
|
AND NEW.ordinal <= cr.source_through_ordinal
|
|
@@ -659,6 +705,10 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
659
705
|
AND tr.session_id = NEW.session_id
|
|
660
706
|
AND tr.frame_id = NEW.frame_id
|
|
661
707
|
AND tr.observation_sha256 = NEW.original_content_sha256
|
|
708
|
+
AND (NEW.renderer_format <> 'swap-tool-image-v1' OR
|
|
709
|
+
(m.name = 'ViewImage' AND tr.completion_kind = 'returned' AND
|
|
710
|
+
json_extract(tr.raw_json, '$.kind') = 'view_image' AND
|
|
711
|
+
json_extract(tr.raw_json, '$.ok') = 1))
|
|
662
712
|
AND (NEW.renderer_format <> 'skill-activation-receipt-v1' OR
|
|
663
713
|
(m.name = 'Skill' AND tr.completion_kind = 'returned' AND
|
|
664
714
|
json_extract(tr.raw_json, '$.kind') = 'skill' AND
|
|
@@ -845,7 +895,7 @@ const schemaDefinitions: readonly SchemaDefinition[] = [
|
|
|
845
895
|
},
|
|
846
896
|
];
|
|
847
897
|
|
|
848
|
-
export const
|
|
898
|
+
export const SESSION_SCHEMA_V10_FINGERPRINT = sha256(
|
|
849
899
|
stableJsonStringify({
|
|
850
900
|
definitions: schemaDefinitions.map((definition) => ({
|
|
851
901
|
type: definition.type,
|
|
@@ -1016,7 +1066,7 @@ export function upgradeActiveTurnRetirementContract(database: Database): boolean
|
|
|
1016
1066
|
WHERE singleton = 1 AND schema_fingerprint = ?`,
|
|
1017
1067
|
)
|
|
1018
1068
|
.run(
|
|
1019
|
-
|
|
1069
|
+
SESSION_SCHEMA_V10_FINGERPRINT,
|
|
1020
1070
|
PRE_ACTIVE_TURN_RETIREMENT_SCHEMA_V9_FINGERPRINT,
|
|
1021
1071
|
);
|
|
1022
1072
|
database.exec(metadataTrigger.sql);
|
|
@@ -1092,7 +1142,7 @@ export function verifyReadableSessionSchema(
|
|
|
1092
1142
|
|
|
1093
1143
|
let expectedDefinitions: readonly SchemaDefinition[];
|
|
1094
1144
|
let compatibility: "current" | "migratable";
|
|
1095
|
-
if (meta.schema_fingerprint ===
|
|
1145
|
+
if (meta.schema_fingerprint === SESSION_SCHEMA_V10_FINGERPRINT) {
|
|
1096
1146
|
expectedDefinitions = schemaDefinitions;
|
|
1097
1147
|
compatibility = "current";
|
|
1098
1148
|
} else if (
|
|
@@ -1195,7 +1245,7 @@ function verifySessionSchemaDefinitions(
|
|
|
1195
1245
|
throw new SessionError(
|
|
1196
1246
|
"SESSION_SCHEMA_INVALID",
|
|
1197
1247
|
"verify_schema",
|
|
1198
|
-
"Session FTS configuration does not match schema
|
|
1248
|
+
"Session FTS configuration does not match schema v10.",
|
|
1199
1249
|
{ sessionId },
|
|
1200
1250
|
);
|
|
1201
1251
|
}
|