agents 0.23.0 → 0.25.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/{agent-routing-DE5zmCQ8.d.ts → agent-routing-0DR0Tk2v.d.ts} +270 -190
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-routing.js.map +1 -1
- package/dist/agent-tool-types.d.ts +13 -7
- package/dist/agent-tool-types.js +23 -1
- package/dist/agent-tool-types.js.map +1 -1
- package/dist/{agent-tools-y7zLfw4Q.js → agent-tools-CdJC-8Dc.js} +72 -9
- package/dist/agent-tools-CdJC-8Dc.js.map +1 -0
- package/dist/{agent-tools-DtXMTDGM.d.ts → agent-tools-YrATZJu2.d.ts} +29 -15
- package/dist/agent-tools.d.ts +6 -4
- package/dist/agent-tools.js.map +1 -1
- package/dist/ai-fm7xx1BK.js +312 -0
- package/dist/ai-fm7xx1BK.js.map +1 -0
- package/dist/base64-redaction-C1Uu29t5.js +59 -0
- package/dist/base64-redaction-C1Uu29t5.js.map +1 -0
- package/dist/browser/ai-sdk.d.ts +90 -0
- package/dist/browser/ai-sdk.js +51 -0
- package/dist/browser/ai-sdk.js.map +1 -0
- package/dist/browser/ai.d.ts +4 -4
- package/dist/browser/ai.js +1 -347
- package/dist/browser/index.d.ts +81 -79
- package/dist/browser/index.js +361 -2
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/tanstack-ai.d.ts +96 -1
- package/dist/browser/tanstack-ai.js +62 -2
- package/dist/browser/tanstack-ai.js.map +1 -1
- package/dist/browser-DE3d-RLk.d.ts +275 -0
- package/dist/browser-tool-CQ10e6Kj.js +480 -0
- package/dist/browser-tool-CQ10e6Kj.js.map +1 -0
- package/dist/browser-tool-DuNdlwZ9.d.ts +73 -0
- package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
- package/dist/capability-B4WbF81e.js.map +1 -0
- package/dist/{capability-runner-Be_-PLR1.d.ts → capability-runner-DBAnGr6L.d.ts} +45 -15
- package/dist/chat/index.d.ts +341 -232
- package/dist/chat/index.js +602 -72
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +42 -2
- package/dist/chat/react.js +191 -35
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/transport.d.ts +1 -1
- package/dist/chat/transport.js +1 -1
- package/dist/chat-sdk/index.d.ts +17 -3
- package/dist/chat-sdk/index.js +28 -2
- package/dist/chat-sdk/index.js.map +1 -1
- package/dist/client-4OlMIJx-.js +591 -0
- package/dist/client-4OlMIJx-.js.map +1 -0
- package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
- package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
- package/dist/client-je3koD9Z.d.ts +446 -0
- package/dist/client.d.ts +29 -283
- package/dist/client.js +2 -274
- package/dist/{connector-CptFKzRh.js → connector-58XDGvc3.js} +251 -120
- package/dist/connector-58XDGvc3.js.map +1 -0
- package/dist/{connector-CkQD4MK3.d.ts → connector-Cl-VqPmA.d.ts} +244 -146
- package/dist/context/index.d.ts +29 -0
- package/dist/context/index.js +64 -17
- package/dist/context/index.js.map +1 -1
- package/dist/current-agent-DhoDkSnH.js.map +1 -1
- package/dist/current-agent-vAk_5JMt.d.ts +93 -0
- package/dist/{current-agent-Da_C9a3b.d.ts → durable-object-lifecycle-HhgOMWq9.d.ts} +26 -127
- package/dist/harnesses/pi/index.d.ts +348 -0
- package/dist/harnesses/pi/index.js +754 -0
- package/dist/harnesses/pi/index.js.map +1 -0
- package/dist/images-iiTDSyRu.js +1631 -0
- package/dist/images-iiTDSyRu.js.map +1 -0
- package/dist/index-BreL0YrQ.d.ts +78 -0
- package/dist/index-kbSUIer3.d.ts +343 -0
- package/dist/index.d.ts +43 -41
- package/dist/index.js +2 -2
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +19 -17
- package/dist/lifecycle/index.js +2 -2
- package/dist/{lifecycle-CMRGjZdw.js → lifecycle-CFu6OV03.js} +73 -29
- package/dist/lifecycle-CFu6OV03.js.map +1 -0
- package/dist/mcp/client/index.d.ts +20 -20
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/client/x402.js +21 -19
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +35 -35
- package/dist/mcp/index.js +2 -2
- package/dist/{message-builder-BymO4N_D.js → message-builder-DAl9AhHH.js} +89 -4
- package/dist/message-builder-DAl9AhHH.js.map +1 -0
- package/dist/models/ai-sdk/index.d.ts +353 -0
- package/dist/models/ai-sdk/index.js +2443 -0
- package/dist/models/ai-sdk/index.js.map +1 -0
- package/dist/models/pi-ai/index.d.ts +313 -0
- package/dist/models/pi-ai/index.js +1795 -0
- package/dist/models/pi-ai/index.js.map +1 -0
- package/dist/observability/ai/index.js +20 -4
- package/dist/observability/ai/index.js.map +1 -1
- package/dist/{protocol-B0nh6KNf.js → protocol-kHsr-f0X.js} +26 -12
- package/dist/{protocol-B0nh6KNf.js.map → protocol-kHsr-f0X.js.map} +1 -1
- package/dist/queue/index.d.ts +123 -0
- package/dist/queue/index.js +2 -0
- package/dist/queue-BB-zfIYF.js +406 -0
- package/dist/queue-BB-zfIYF.js.map +1 -0
- package/dist/react.d.ts +31 -13
- package/dist/react.js +190 -71
- package/dist/react.js.map +1 -1
- package/dist/{retries-D9Ds-1lz.d.ts → retries-CV6AkXmQ.d.ts} +23 -8
- package/dist/retries.d.ts +12 -8
- package/dist/retries.js +19 -1
- package/dist/retries.js.map +1 -1
- package/dist/routing/index.d.ts +2 -2
- package/dist/routing/index.js +1 -1
- package/dist/{scheduler-DD9NdYbF.js → scheduler-DZ3xQfeK.js} +4 -11
- package/dist/scheduler-DZ3xQfeK.js.map +1 -0
- package/dist/{scheduler-Dwh85ZGl.d.ts → scheduler-RdACNXDP.d.ts} +6 -6
- package/dist/schedules/index.d.ts +1 -1
- package/dist/schedules/index.js +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +70 -3
- package/dist/sessions/index.js +276 -67
- package/dist/sessions/index.js.map +1 -1
- package/dist/skills/index.d.ts +29 -314
- package/dist/socket-address.d.ts +16 -0
- package/dist/socket-address.js +19 -0
- package/dist/socket-address.js.map +1 -0
- package/dist/{src-DlSHshb2.js → src-BZeu-SCD.js} +541 -500
- package/dist/src-BZeu-SCD.js.map +1 -0
- package/dist/state/index.d.ts +6 -0
- package/dist/state/index.js +137 -0
- package/dist/state/index.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/{streams-D6tJ0NN9.d.ts → streams-Cmkj9QfW.d.ts} +4 -2
- package/dist/{streams-DZKgAj9b.js → streams-DW-UCOUc.js} +9 -2
- package/dist/streams-DW-UCOUc.js.map +1 -0
- package/dist/sub-routing.d.ts +12 -12
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{tasks-ylZgBjhj.js → tasks-68DESxf0.js} +3 -3
- package/dist/{tasks-ylZgBjhj.js.map → tasks-68DESxf0.js.map} +1 -1
- package/dist/{tasks-BRJ5zgya.d.ts → tasks-9YxYtByh.d.ts} +5 -5
- package/dist/transport-PfFnt-Ld.d.ts +525 -0
- package/dist/transport-protocol-BxyngQ_R.js +25 -0
- package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
- package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
- package/dist/types-BA4anrjI.d.ts +70 -0
- package/dist/voice/index.d.ts +2 -2
- package/dist/websockets/index.d.ts +195 -69
- package/dist/websockets/index.js +3 -2
- package/dist/websockets-Ci-LZFHH.js +1030 -0
- package/dist/websockets-Ci-LZFHH.js.map +1 -0
- package/dist/wire-types-CnMt6_HR.js.map +1 -1
- package/dist/wire-types-CrjKvDyi.d.ts +300 -0
- package/dist/workflow-types.d.ts +25 -25
- package/dist/workflows.d.ts +21 -21
- package/dist/workflows.js +1 -1
- package/dist/{ws-chat-transport-UNRIS2xl.d.ts → ws-chat-transport-BbT1A5Lc.d.ts} +51 -2
- package/dist/{ws-chat-transport-rWwta645.js → ws-chat-transport-cqMKq3IY.js} +143 -16
- package/dist/ws-chat-transport-cqMKq3IY.js.map +1 -0
- package/docs/agent-class.md +2 -2
- package/docs/agent-tools.md +29 -4
- package/docs/browse-the-web.md +87 -5
- package/docs/chat-agents.md +124 -16
- package/docs/client-sdk.md +30 -0
- package/docs/context.md +27 -0
- package/docs/durable-execution.md +2 -0
- package/docs/harnesses/pi.md +91 -0
- package/docs/human-in-the-loop.md +4 -0
- package/docs/index.md +4 -1
- package/docs/lifecycle.md +114 -23
- package/docs/models-pi-ai.md +325 -0
- package/docs/models.md +504 -0
- package/docs/queue.md +135 -241
- package/docs/resumable-streaming.md +2 -0
- package/docs/retries.md +1 -1
- package/docs/routing.md +13 -13
- package/docs/sessions.md +36 -1
- package/docs/state.md +1 -0
- package/docs/sub-agents.md +12 -3
- package/package.json +51 -3
- package/dist/agent-tools-y7zLfw4Q.js.map +0 -1
- package/dist/browser/ai.js.map +0 -1
- package/dist/capability-BjSKYpzg.js.map +0 -1
- package/dist/client-tools-aIBO0Fk7.d.ts +0 -53
- package/dist/client.js.map +0 -1
- package/dist/connector-CptFKzRh.js.map +0 -1
- package/dist/lifecycle-CMRGjZdw.js.map +0 -1
- package/dist/message-builder-BymO4N_D.js.map +0 -1
- package/dist/scheduler-DD9NdYbF.js.map +0 -1
- package/dist/src-DlSHshb2.js.map +0 -1
- package/dist/streams-DZKgAj9b.js.map +0 -1
- package/dist/websockets-DUfRHPRq.js +0 -502
- package/dist/websockets-DUfRHPRq.js.map +0 -1
- package/dist/ws-chat-transport-rWwta645.js.map +0 -1
package/dist/sessions/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../classPrivateFieldGet2-DZBYAB34.js";
|
|
2
|
-
import { t as LifecycleCapability } from "../capability-BjSKYpzg.js";
|
|
3
2
|
import { t as _classPrivateMethodInitSpec } from "../classPrivateMethodInitSpec-qMjJ6sHQ.js";
|
|
3
|
+
import { t as LifecycleCapability } from "../capability-B4WbF81e.js";
|
|
4
4
|
import { SqlError } from "../sql-error.js";
|
|
5
5
|
import { n as sanitizeMessage, t as byteLength } from "../sanitize-D9TujEK8.js";
|
|
6
6
|
import { i as estimatedDataUrlBytes, n as estimateMessageTokens, r as estimateStringTokens, t as estimateAttachmentTokens } from "../tokens-nHAKcN6M.js";
|
|
@@ -396,22 +396,46 @@ function extractAttachments(message) {
|
|
|
396
396
|
};
|
|
397
397
|
if (message.parts.length === 0) return {
|
|
398
398
|
message,
|
|
399
|
-
attachments
|
|
399
|
+
attachments,
|
|
400
|
+
references: []
|
|
400
401
|
};
|
|
401
402
|
const parts = walk(message.parts, 0);
|
|
403
|
+
const references = [...pointersOf(parts)];
|
|
402
404
|
if (parts === message.parts) return {
|
|
403
405
|
message,
|
|
404
|
-
attachments
|
|
406
|
+
attachments,
|
|
407
|
+
references
|
|
405
408
|
};
|
|
406
409
|
return {
|
|
407
410
|
message: {
|
|
408
411
|
...message,
|
|
409
412
|
parts
|
|
410
413
|
},
|
|
411
|
-
attachments
|
|
414
|
+
attachments,
|
|
415
|
+
references
|
|
412
416
|
};
|
|
413
417
|
}
|
|
414
418
|
/**
|
|
419
|
+
* The attachment addresses a read of this stored form restores. It walks
|
|
420
|
+
* exactly as {@link resolveAttachments} does, so a message holds a reference
|
|
421
|
+
* for every pointer a read would put back and for nothing else.
|
|
422
|
+
*/
|
|
423
|
+
function pointersOf(value, into = /* @__PURE__ */ new Set(), depth = 0) {
|
|
424
|
+
if (depth > MAX_WALK_DEPTH || value === null || typeof value !== "object") return into;
|
|
425
|
+
if (Array.isArray(value)) {
|
|
426
|
+
for (const entry of value) pointersOf(entry, into, depth + 1);
|
|
427
|
+
return into;
|
|
428
|
+
}
|
|
429
|
+
const record = value;
|
|
430
|
+
const hash = parseAttachmentUrl(record.url) ?? parseAttachmentUrl(record.data);
|
|
431
|
+
if (hash) {
|
|
432
|
+
into.add(hash);
|
|
433
|
+
return into;
|
|
434
|
+
}
|
|
435
|
+
for (const entry of Object.values(record)) pointersOf(entry, into, depth + 1);
|
|
436
|
+
return into;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
415
439
|
* Put payloads back inline, undoing extraction exactly.
|
|
416
440
|
*
|
|
417
441
|
* A pointer whose bytes cannot be loaded is left as it is: an unresolvable
|
|
@@ -747,6 +771,38 @@ const NEWEST_FIRST_WINDOW_ROWS = 8;
|
|
|
747
771
|
* recent rows only, and `getRecentHistory` reports that as truncated.
|
|
748
772
|
*/
|
|
749
773
|
const MAX_PATH_DEPTH = 1e4;
|
|
774
|
+
/**
|
|
775
|
+
* Hidden overlay rows: a stored `compaction_<id>` row whose `<id>` names one
|
|
776
|
+
* of the session's own compaction records, so it duplicates an overlay the
|
|
777
|
+
* session renders itself. Writes refuse overlays, but sessions written before
|
|
778
|
+
* that guard (#1984) can hold one, usually with later rows parented to it.
|
|
779
|
+
* Reads skip such a row and walk through it, so its children take its place.
|
|
780
|
+
* A `compaction_` row with no matching record, such as a summary imported
|
|
781
|
+
* from another session's history, is the only copy of that context and stays
|
|
782
|
+
* visible.
|
|
783
|
+
*/
|
|
784
|
+
function hasOverlayPrefix(id) {
|
|
785
|
+
return id.startsWith(COMPACTION_PREFIX);
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* SQL twin of the hidden-overlay test for the row id in `idColumn` of the
|
|
789
|
+
* session in `sessionExpr`. The record lookup runs only for prefixed ids.
|
|
790
|
+
* Both must be table-qualified: inside the lookup an unqualified `id` or
|
|
791
|
+
* `session_id` binds to the compactions table, not the row being tested.
|
|
792
|
+
*/
|
|
793
|
+
function hiddenOverlayRowSql(idColumn, sessionExpr) {
|
|
794
|
+
return `(substr(${idColumn}, 1, 11) = '${COMPACTION_PREFIX}'
|
|
795
|
+
AND EXISTS (SELECT 1 FROM cf_agents_session_compactions oc
|
|
796
|
+
WHERE oc.session_id = ${sessionExpr}
|
|
797
|
+
AND oc.id = substr(${idColumn}, 12)))`;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Digest of a message's stored form, stamped on the row by every write, so an
|
|
801
|
+
* update can decide "unchanged" without reading the stored content back.
|
|
802
|
+
*/
|
|
803
|
+
function contentDigest(json) {
|
|
804
|
+
return createHash("sha256").update(json, "utf8").digest("hex");
|
|
805
|
+
}
|
|
750
806
|
var _reservedMetadataKeys = /* @__PURE__ */ new WeakMap();
|
|
751
807
|
var _listeners = /* @__PURE__ */ new WeakMap();
|
|
752
808
|
var _tails = /* @__PURE__ */ new WeakMap();
|
|
@@ -782,8 +838,10 @@ var SessionsCore = class {
|
|
|
782
838
|
content_chunks INTEGER NOT NULL DEFAULT 0,
|
|
783
839
|
token_estimate INTEGER NOT NULL DEFAULT 0,
|
|
784
840
|
created_at INTEGER NOT NULL,
|
|
841
|
+
content_hash TEXT,
|
|
785
842
|
PRIMARY KEY (session_id, id)
|
|
786
843
|
) WITHOUT ROWID`, []);
|
|
844
|
+
_assertClassBrand(_SessionsCore_brand, this, _addMessageContentHashColumn).call(this);
|
|
787
845
|
this.io.sqlWrite(`CREATE TABLE IF NOT EXISTS cf_agents_session_message_chunks (
|
|
788
846
|
session_id TEXT NOT NULL,
|
|
789
847
|
id TEXT NOT NULL,
|
|
@@ -923,12 +981,15 @@ var SessionsCore = class {
|
|
|
923
981
|
return _assertClassBrand(_SessionsCore_brand, this, _tail).call(this, sessionId).leafId;
|
|
924
982
|
}
|
|
925
983
|
getLatestLeaf(sessionId) {
|
|
926
|
-
|
|
984
|
+
let leafId = this.latestLeafId(sessionId);
|
|
985
|
+
while (leafId !== null && _assertClassBrand(_SessionsCore_brand, this, _hiddenOverlayIds).call(this, sessionId, [leafId]).has(leafId)) {
|
|
986
|
+
const [row] = this.io.sql("SELECT parent_id FROM cf_agents_session_messages WHERE session_id = ? AND id = ?", [sessionId, leafId]);
|
|
987
|
+
leafId = row?.parent_id ?? null;
|
|
988
|
+
}
|
|
927
989
|
return leafId ? this.getMessage(sessionId, leafId) : null;
|
|
928
990
|
}
|
|
929
991
|
getBranches(sessionId, messageId) {
|
|
930
|
-
const rows = this.
|
|
931
|
-
WHERE session_id = ? AND parent_id = ? ORDER BY seq ASC`, [sessionId, messageId]);
|
|
992
|
+
const rows = _assertClassBrand(_SessionsCore_brand, this, _childRows).call(this, sessionId, messageId);
|
|
932
993
|
const continued = _assertClassBrand(_SessionsCore_brand, this, _continuations).call(this, sessionId, rows.filter((row) => row.content_chunks > 0).map((row) => row.id));
|
|
933
994
|
const result = [];
|
|
934
995
|
for (const row of rows) {
|
|
@@ -946,38 +1007,7 @@ var SessionsCore = class {
|
|
|
946
1007
|
* budget over these rows bounds real hydrated memory.
|
|
947
1008
|
*/
|
|
948
1009
|
pathRowStats(sessionId, leafId) {
|
|
949
|
-
|
|
950
|
-
if (!leaf) return [];
|
|
951
|
-
return this.io.sql(`WITH RECURSIVE path(id, parent_id, depth) AS (
|
|
952
|
-
SELECT id, parent_id, 0 FROM cf_agents_session_messages
|
|
953
|
-
WHERE session_id = ? AND id = ?
|
|
954
|
-
UNION ALL
|
|
955
|
-
SELECT m.id, m.parent_id, p.depth + 1 FROM cf_agents_session_messages m
|
|
956
|
-
JOIN path p ON m.id = p.parent_id
|
|
957
|
-
WHERE m.session_id = ? AND p.depth < ${MAX_PATH_DEPTH}
|
|
958
|
-
)
|
|
959
|
-
SELECT path.id AS id, am.role AS role,
|
|
960
|
-
LENGTH(CAST(am.content AS BLOB)) + CASE WHEN am.content_chunks = 0 THEN 0
|
|
961
|
-
ELSE COALESCE((
|
|
962
|
-
SELECT SUM(LENGTH(CAST(c.content AS BLOB)))
|
|
963
|
-
FROM cf_agents_session_message_chunks c
|
|
964
|
-
WHERE c.session_id = am.session_id AND c.id = am.id
|
|
965
|
-
), 0) END
|
|
966
|
-
+ COALESCE((
|
|
967
|
-
SELECT SUM((meta.bytes + 2) / 3 * 4)
|
|
968
|
-
FROM cf_agents_session_attachment_refs r
|
|
969
|
-
JOIN cf_agents_session_attachment_meta meta ON meta.hash = r.hash
|
|
970
|
-
WHERE r.session_id = am.session_id AND r.message_id = am.id
|
|
971
|
-
), 0) AS bytes,
|
|
972
|
-
am.token_estimate AS tokenEstimate
|
|
973
|
-
FROM path JOIN cf_agents_session_messages am
|
|
974
|
-
ON am.session_id = ? AND am.id = path.id
|
|
975
|
-
ORDER BY path.depth DESC`, [
|
|
976
|
-
sessionId,
|
|
977
|
-
leaf,
|
|
978
|
-
sessionId,
|
|
979
|
-
sessionId
|
|
980
|
-
]);
|
|
1010
|
+
return _assertClassBrand(_SessionsCore_brand, this, _pathRows).call(this, sessionId, leafId).rows;
|
|
981
1011
|
}
|
|
982
1012
|
/**
|
|
983
1013
|
* Stream the path ending at `leafId` (default: active leaf), root → leaf
|
|
@@ -1010,7 +1040,7 @@ var SessionsCore = class {
|
|
|
1010
1040
|
* skipped, showing the raw recent messages.
|
|
1011
1041
|
*/
|
|
1012
1042
|
async getRecentHistory(sessionId, maxContentBytes, leafId) {
|
|
1013
|
-
const stats = this.
|
|
1043
|
+
const { rows: stats, walked, oldestId } = _assertClassBrand(_SessionsCore_brand, this, _pathRows).call(this, sessionId, leafId);
|
|
1014
1044
|
if (stats.length === 0) return {
|
|
1015
1045
|
messages: [],
|
|
1016
1046
|
truncated: false,
|
|
@@ -1027,7 +1057,7 @@ var SessionsCore = class {
|
|
|
1027
1057
|
}
|
|
1028
1058
|
const messages = [];
|
|
1029
1059
|
for await (const message of _assertClassBrand(_SessionsCore_brand, this, _streamStats).call(this, sessionId, stats.slice(start))) messages.push(message);
|
|
1030
|
-
const capped =
|
|
1060
|
+
const capped = walked > MAX_PATH_DEPTH && oldestId !== null && _assertClassBrand(_SessionsCore_brand, this, _hasParent).call(this, sessionId, oldestId);
|
|
1031
1061
|
return {
|
|
1032
1062
|
messages,
|
|
1033
1063
|
truncated: start > 0 || capped,
|
|
@@ -1044,7 +1074,7 @@ var SessionsCore = class {
|
|
|
1044
1074
|
const leafId = this.latestLeafId(sessionId);
|
|
1045
1075
|
const memo = _classPrivateFieldGet2(_pathTokens, this).get(sessionId);
|
|
1046
1076
|
if (memo && memo.leafId === leafId) return Math.max(0, Math.ceil(memo.total));
|
|
1047
|
-
const stats = this.
|
|
1077
|
+
const { rows: stats, walked } = _assertClassBrand(_SessionsCore_brand, this, _pathRows).call(this, sessionId);
|
|
1048
1078
|
const counted = new Set(stats.map((row) => row.id));
|
|
1049
1079
|
let tokens = stats.reduce((sum, row) => sum + row.tokenEstimate, 0);
|
|
1050
1080
|
for (const span of planOverlays(stats.map((row) => row.id), this.getCompactions(sessionId))) {
|
|
@@ -1058,7 +1088,7 @@ var SessionsCore = class {
|
|
|
1058
1088
|
leafId,
|
|
1059
1089
|
counted,
|
|
1060
1090
|
total: tokens,
|
|
1061
|
-
depth:
|
|
1091
|
+
depth: walked
|
|
1062
1092
|
});
|
|
1063
1093
|
return Math.max(0, Math.ceil(tokens));
|
|
1064
1094
|
}
|
|
@@ -1109,14 +1139,15 @@ var SessionsCore = class {
|
|
|
1109
1139
|
let parent;
|
|
1110
1140
|
if (parentId === void 0) parent = tail.leafId;
|
|
1111
1141
|
else parent = parentId && this.exists(sessionId, parentId) ? parentId : null;
|
|
1112
|
-
const { message: staged, attachments } = extractAttachments(message);
|
|
1113
|
-
const
|
|
1142
|
+
const { message: staged, attachments, references } = extractAttachments(message);
|
|
1143
|
+
const json = JSON.stringify(staged);
|
|
1144
|
+
const slices = splitContent(json);
|
|
1114
1145
|
const seq = tail.nextSeq;
|
|
1115
1146
|
this.io.transaction(() => {
|
|
1116
1147
|
for (const attachment of attachments) _classPrivateFieldGet2(_attachments, this).put(attachment.payload, attachment.hash);
|
|
1117
1148
|
this.io.sqlWrite(`INSERT INTO cf_agents_session_messages
|
|
1118
|
-
(session_id, id, seq, parent_id, role, content, content_chunks, token_estimate, created_at)
|
|
1119
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1149
|
+
(session_id, id, seq, parent_id, role, content, content_chunks, token_estimate, created_at, content_hash)
|
|
1150
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1120
1151
|
sessionId,
|
|
1121
1152
|
message.id,
|
|
1122
1153
|
seq,
|
|
@@ -1125,10 +1156,11 @@ var SessionsCore = class {
|
|
|
1125
1156
|
slices[0],
|
|
1126
1157
|
slices.length - 1,
|
|
1127
1158
|
tokenEstimate,
|
|
1128
|
-
Date.now()
|
|
1159
|
+
Date.now(),
|
|
1160
|
+
contentDigest(json)
|
|
1129
1161
|
]);
|
|
1130
1162
|
_assertClassBrand(_SessionsCore_brand, this, _writeContinuations).call(this, sessionId, message.id, slices);
|
|
1131
|
-
_classPrivateFieldGet2(_attachments, this).addRefs(sessionId, message.id,
|
|
1163
|
+
_classPrivateFieldGet2(_attachments, this).addRefs(sessionId, message.id, references);
|
|
1132
1164
|
_assertClassBrand(_SessionsCore_brand, this, _indexFts).call(this, sessionId, staged, false);
|
|
1133
1165
|
});
|
|
1134
1166
|
_classPrivateFieldGet2(_tails, this).set(sessionId, {
|
|
@@ -1155,26 +1187,38 @@ var SessionsCore = class {
|
|
|
1155
1187
|
/**
|
|
1156
1188
|
* Durable update of an existing row. An identical row writes nothing: no
|
|
1157
1189
|
* row, no continuation, no FTS, no event. The no-op guard compares the
|
|
1158
|
-
* FULL
|
|
1190
|
+
* FULL content, through the digest the last write stamped, so neither the
|
|
1191
|
+
* payload nor a continuation row is read. A row without a digest compares
|
|
1192
|
+
* the reassembled content once and is stamped.
|
|
1159
1193
|
*/
|
|
1160
1194
|
update(sessionId, message, tokenEstimate) {
|
|
1161
|
-
const oldRows = this.io.sql("SELECT
|
|
1195
|
+
const oldRows = this.io.sql("SELECT content_chunks, token_estimate, content_hash FROM cf_agents_session_messages WHERE session_id = ? AND id = ?", [sessionId, message.id]);
|
|
1162
1196
|
if (oldRows.length === 0) return "missing";
|
|
1163
1197
|
const old = oldRows[0];
|
|
1164
|
-
const
|
|
1165
|
-
const { message: staged, attachments } = extractAttachments(message);
|
|
1198
|
+
const { message: staged, attachments, references } = extractAttachments(message);
|
|
1166
1199
|
const json = JSON.stringify(staged);
|
|
1167
|
-
|
|
1200
|
+
const digest = contentDigest(json);
|
|
1201
|
+
if (old.content_hash !== null) {
|
|
1202
|
+
if (old.content_hash === digest) return "unchanged";
|
|
1203
|
+
} else if (_assertClassBrand(_SessionsCore_brand, this, _content).call(this, sessionId, message.id) === json) {
|
|
1204
|
+
this.io.sqlWrite("UPDATE cf_agents_session_messages SET content_hash = ? WHERE session_id = ? AND id = ?", [
|
|
1205
|
+
digest,
|
|
1206
|
+
sessionId,
|
|
1207
|
+
message.id
|
|
1208
|
+
]);
|
|
1209
|
+
return "unchanged";
|
|
1210
|
+
}
|
|
1168
1211
|
const slices = splitContent(json);
|
|
1169
1212
|
this.io.transaction(() => {
|
|
1170
1213
|
for (const attachment of attachments) _classPrivateFieldGet2(_attachments, this).put(attachment.payload, attachment.hash);
|
|
1171
1214
|
this.io.sqlWrite(`UPDATE cf_agents_session_messages
|
|
1172
|
-
SET role = ?, content = ?, content_chunks = ?, token_estimate = ?
|
|
1215
|
+
SET role = ?, content = ?, content_chunks = ?, token_estimate = ?, content_hash = ?
|
|
1173
1216
|
WHERE session_id = ? AND id = ?`, [
|
|
1174
1217
|
message.role,
|
|
1175
1218
|
slices[0],
|
|
1176
1219
|
slices.length - 1,
|
|
1177
1220
|
tokenEstimate,
|
|
1221
|
+
digest,
|
|
1178
1222
|
sessionId,
|
|
1179
1223
|
message.id
|
|
1180
1224
|
]);
|
|
@@ -1185,7 +1229,7 @@ var SessionsCore = class {
|
|
|
1185
1229
|
slices.length - 1
|
|
1186
1230
|
]);
|
|
1187
1231
|
_assertClassBrand(_SessionsCore_brand, this, _writeContinuations).call(this, sessionId, message.id, slices);
|
|
1188
|
-
_classPrivateFieldGet2(_attachments, this).replaceRefs(sessionId, message.id,
|
|
1232
|
+
_classPrivateFieldGet2(_attachments, this).replaceRefs(sessionId, message.id, references);
|
|
1189
1233
|
_assertClassBrand(_SessionsCore_brand, this, _indexFts).call(this, sessionId, staged, true);
|
|
1190
1234
|
});
|
|
1191
1235
|
const memo = _classPrivateFieldGet2(_pathTokens, this).get(sessionId);
|
|
@@ -1316,6 +1360,7 @@ var SessionsCore = class {
|
|
|
1316
1360
|
INNER JOIN cf_agents_session_messages m
|
|
1317
1361
|
ON m.session_id = f.session_id AND m.id = f.id
|
|
1318
1362
|
WHERE cf_agents_session_fts MATCH ? AND f.session_id = ?
|
|
1363
|
+
AND NOT ${hiddenOverlayRowSql("f.id", "f.session_id")}
|
|
1319
1364
|
ORDER BY rank LIMIT ?`, [
|
|
1320
1365
|
sanitized,
|
|
1321
1366
|
sessionId,
|
|
@@ -1332,15 +1377,16 @@ var SessionsCore = class {
|
|
|
1332
1377
|
*/
|
|
1333
1378
|
/** Returns `false` when the id already exists and nothing was written. */
|
|
1334
1379
|
importMessage(sessionId, message, options) {
|
|
1335
|
-
const { message: staged, attachments } = extractAttachments(message);
|
|
1336
|
-
const
|
|
1380
|
+
const { message: staged, attachments, references } = extractAttachments(message);
|
|
1381
|
+
const json = JSON.stringify(staged);
|
|
1382
|
+
const slices = splitContent(json);
|
|
1337
1383
|
const tail = _assertClassBrand(_SessionsCore_brand, this, _tail).call(this, sessionId);
|
|
1338
1384
|
let inserted = 0;
|
|
1339
1385
|
this.io.transaction(() => {
|
|
1340
1386
|
for (const attachment of attachments) _classPrivateFieldGet2(_attachments, this).put(attachment.payload, attachment.hash);
|
|
1341
1387
|
inserted = this.io.sqlWrite(`INSERT OR IGNORE INTO cf_agents_session_messages
|
|
1342
|
-
(session_id, id, seq, parent_id, role, content, content_chunks, token_estimate, created_at)
|
|
1343
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1388
|
+
(session_id, id, seq, parent_id, role, content, content_chunks, token_estimate, created_at, content_hash)
|
|
1389
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1344
1390
|
sessionId,
|
|
1345
1391
|
message.id,
|
|
1346
1392
|
tail.nextSeq,
|
|
@@ -1349,11 +1395,12 @@ var SessionsCore = class {
|
|
|
1349
1395
|
slices[0],
|
|
1350
1396
|
slices.length - 1,
|
|
1351
1397
|
this.estimateRowTokens(message),
|
|
1352
|
-
options.createdAt
|
|
1398
|
+
options.createdAt,
|
|
1399
|
+
contentDigest(json)
|
|
1353
1400
|
]);
|
|
1354
1401
|
if (inserted === 0) return;
|
|
1355
1402
|
_assertClassBrand(_SessionsCore_brand, this, _writeContinuations).call(this, sessionId, message.id, slices);
|
|
1356
|
-
_classPrivateFieldGet2(_attachments, this).addRefs(sessionId, message.id,
|
|
1403
|
+
_classPrivateFieldGet2(_attachments, this).addRefs(sessionId, message.id, references);
|
|
1357
1404
|
_assertClassBrand(_SessionsCore_brand, this, _indexFts).call(this, sessionId, staged, false);
|
|
1358
1405
|
});
|
|
1359
1406
|
if (inserted === 0) return false;
|
|
@@ -1365,6 +1412,15 @@ var SessionsCore = class {
|
|
|
1365
1412
|
return true;
|
|
1366
1413
|
}
|
|
1367
1414
|
};
|
|
1415
|
+
/**
|
|
1416
|
+
* Add the digest column to a message table that predates it. Nullable, so
|
|
1417
|
+
* no existing row is rewritten; a `null` digest falls back to reading the
|
|
1418
|
+
* row back once.
|
|
1419
|
+
*/
|
|
1420
|
+
function _addMessageContentHashColumn() {
|
|
1421
|
+
if (this.io.sql("SELECT name FROM pragma_table_info('cf_agents_session_messages')", []).map((row) => row.name).includes("content_hash")) return;
|
|
1422
|
+
this.io.sqlWrite("ALTER TABLE cf_agents_session_messages ADD COLUMN content_hash TEXT", []);
|
|
1423
|
+
}
|
|
1368
1424
|
function _tableExists(name) {
|
|
1369
1425
|
return this.io.sql("SELECT name FROM sqlite_master WHERE type IN ('table', 'view') AND name = ?", [name]).length > 0;
|
|
1370
1426
|
}
|
|
@@ -1448,6 +1504,74 @@ function _resolveLeafId(sessionId, leafId) {
|
|
|
1448
1504
|
return this.latestLeafId(sessionId);
|
|
1449
1505
|
}
|
|
1450
1506
|
/**
|
|
1507
|
+
* Which of `ids` are hidden overlay rows. Reads the session's compaction
|
|
1508
|
+
* records only when some id carries the prefix.
|
|
1509
|
+
*/
|
|
1510
|
+
function _hiddenOverlayIds(sessionId, ids) {
|
|
1511
|
+
if (!ids.some(hasOverlayPrefix)) return /* @__PURE__ */ new Set();
|
|
1512
|
+
const overlays = new Set(this.getCompactions(sessionId).map((compaction) => `${COMPACTION_PREFIX}${compaction.id}`));
|
|
1513
|
+
return new Set(ids.filter((id) => overlays.has(id)));
|
|
1514
|
+
}
|
|
1515
|
+
/** Children of a row in `seq` order, hidden overlay rows replaced by theirs. */
|
|
1516
|
+
function _childRows(sessionId, parentId) {
|
|
1517
|
+
const rows = this.io.sql(`SELECT id, seq, content, content_chunks FROM cf_agents_session_messages
|
|
1518
|
+
WHERE session_id = ? AND parent_id = ? ORDER BY seq ASC`, [sessionId, parentId]);
|
|
1519
|
+
const hidden = _assertClassBrand(_SessionsCore_brand, this, _hiddenOverlayIds).call(this, sessionId, rows.map((row) => row.id));
|
|
1520
|
+
if (hidden.size === 0) return rows;
|
|
1521
|
+
return rows.flatMap((row) => hidden.has(row.id) ? _assertClassBrand(_SessionsCore_brand, this, _childRows).call(this, sessionId, row.id) : [row]).sort((a, b) => a.seq - b.seq);
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* `pathRowStats` plus what the walk itself saw: the path cap counts stored
|
|
1525
|
+
* rows, hidden overlay rows included, so whether the walk was cut short
|
|
1526
|
+
* is judged from the unfiltered path.
|
|
1527
|
+
*/
|
|
1528
|
+
function _pathRows(sessionId, leafId) {
|
|
1529
|
+
const leaf = _assertClassBrand(_SessionsCore_brand, this, _resolveLeafId).call(this, sessionId, leafId);
|
|
1530
|
+
if (!leaf) return {
|
|
1531
|
+
rows: [],
|
|
1532
|
+
walked: 0,
|
|
1533
|
+
oldestId: null
|
|
1534
|
+
};
|
|
1535
|
+
const walked = this.io.sql(`WITH RECURSIVE path(id, parent_id, depth) AS (
|
|
1536
|
+
SELECT id, parent_id, 0 FROM cf_agents_session_messages
|
|
1537
|
+
WHERE session_id = ? AND id = ?
|
|
1538
|
+
UNION ALL
|
|
1539
|
+
SELECT m.id, m.parent_id, p.depth + 1 FROM cf_agents_session_messages m
|
|
1540
|
+
JOIN path p ON m.id = p.parent_id
|
|
1541
|
+
WHERE m.session_id = ? AND p.depth < ${MAX_PATH_DEPTH}
|
|
1542
|
+
)
|
|
1543
|
+
SELECT path.id AS id, am.role AS role,
|
|
1544
|
+
LENGTH(CAST(am.content AS BLOB)) + CASE WHEN am.content_chunks = 0 THEN 0
|
|
1545
|
+
ELSE COALESCE((
|
|
1546
|
+
SELECT SUM(LENGTH(CAST(c.content AS BLOB)))
|
|
1547
|
+
FROM cf_agents_session_message_chunks c
|
|
1548
|
+
WHERE c.session_id = am.session_id AND c.id = am.id
|
|
1549
|
+
), 0) END
|
|
1550
|
+
+ COALESCE((
|
|
1551
|
+
SELECT SUM((meta.bytes + 2) / 3 * 4)
|
|
1552
|
+
FROM cf_agents_session_attachment_refs r
|
|
1553
|
+
JOIN cf_agents_session_attachment_meta meta ON meta.hash = r.hash
|
|
1554
|
+
WHERE r.session_id = am.session_id AND r.message_id = am.id
|
|
1555
|
+
), 0) AS bytes,
|
|
1556
|
+
am.token_estimate AS tokenEstimate,
|
|
1557
|
+
${hiddenOverlayRowSql("path.id", "am.session_id")} AS hidden
|
|
1558
|
+
FROM path JOIN cf_agents_session_messages am
|
|
1559
|
+
ON am.session_id = ? AND am.id = path.id
|
|
1560
|
+
ORDER BY path.depth DESC`, [
|
|
1561
|
+
sessionId,
|
|
1562
|
+
leaf,
|
|
1563
|
+
sessionId,
|
|
1564
|
+
sessionId
|
|
1565
|
+
]);
|
|
1566
|
+
const rows = [];
|
|
1567
|
+
for (const { hidden, ...row } of walked) if (!hidden) rows.push(row);
|
|
1568
|
+
return {
|
|
1569
|
+
rows,
|
|
1570
|
+
walked: walked.length,
|
|
1571
|
+
oldestId: walked[0]?.id ?? null
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1451
1575
|
* The active branch path as ids alone, root → leaf. The cheapest walk the
|
|
1452
1576
|
* tree allows — one row per step, following `parent_id` by primary key —
|
|
1453
1577
|
* for readers that will hydrate only a few rows and do not need the sizes
|
|
@@ -1464,9 +1588,12 @@ function _pathIds(sessionId, leafId) {
|
|
|
1464
1588
|
JOIN path p ON m.id = p.parent_id
|
|
1465
1589
|
WHERE m.session_id = ? AND p.depth < ${MAX_PATH_DEPTH}
|
|
1466
1590
|
)
|
|
1467
|
-
SELECT id FROM path
|
|
1591
|
+
SELECT path.id AS id FROM path
|
|
1592
|
+
WHERE NOT ${hiddenOverlayRowSql("path.id", "?")}
|
|
1593
|
+
ORDER BY depth DESC`, [
|
|
1468
1594
|
sessionId,
|
|
1469
1595
|
leaf,
|
|
1596
|
+
sessionId,
|
|
1470
1597
|
sessionId
|
|
1471
1598
|
]).map((row) => row.id);
|
|
1472
1599
|
}
|
|
@@ -1569,6 +1696,7 @@ async function* _streamStats(sessionId, stats, signal, newestFirst = false, plan
|
|
|
1569
1696
|
async function* _walkFromLeaf(sessionId, leafId, signal) {
|
|
1570
1697
|
const compactions = this.getCompactions(sessionId);
|
|
1571
1698
|
const spanEnds = new Set(compactions.map((c) => c.toMessageId));
|
|
1699
|
+
const hiddenIds = new Set(compactions.map((c) => `${COMPACTION_PREFIX}${c.id}`));
|
|
1572
1700
|
let next = _assertClassBrand(_SessionsCore_brand, this, _resolveLeafId).call(this, sessionId, leafId);
|
|
1573
1701
|
let depth = 0;
|
|
1574
1702
|
while (next !== null && depth <= MAX_PATH_DEPTH) {
|
|
@@ -1580,9 +1708,11 @@ async function* _walkFromLeaf(sessionId, leafId, signal) {
|
|
|
1580
1708
|
const [row] = this.io.sql(`SELECT parent_id, content, content_chunks FROM cf_agents_session_messages
|
|
1581
1709
|
WHERE session_id = ? AND id = ?`, [sessionId, next]);
|
|
1582
1710
|
if (!row) return;
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1711
|
+
if (!hiddenIds.has(next)) {
|
|
1712
|
+
const json = row.content_chunks === 0 ? row.content : row.content + (_assertClassBrand(_SessionsCore_brand, this, _continuations).call(this, sessionId, [next]).get(next) ?? "");
|
|
1713
|
+
const parsed = _assertClassBrand(_SessionsCore_brand, this, _parse).call(this, json);
|
|
1714
|
+
if (parsed) yield _assertClassBrand(_SessionsCore_brand, this, _inline).call(this, parsed);
|
|
1715
|
+
}
|
|
1586
1716
|
next = row.parent_id;
|
|
1587
1717
|
depth++;
|
|
1588
1718
|
}
|
|
@@ -1649,6 +1779,50 @@ function _parse(json) {
|
|
|
1649
1779
|
return null;
|
|
1650
1780
|
}
|
|
1651
1781
|
//#endregion
|
|
1782
|
+
//#region src/sessions/mirror.ts
|
|
1783
|
+
/**
|
|
1784
|
+
* The default reduction, per event:
|
|
1785
|
+
*
|
|
1786
|
+
* - `append` of a new row: replace the cached entry with its id, or push it.
|
|
1787
|
+
* A duplicate append (`inserted: false`) changed nothing.
|
|
1788
|
+
* - `update`: replace the cached entry with its id; a row the cache does not
|
|
1789
|
+
* hold stays out.
|
|
1790
|
+
* - `delete`: drop the removed ids. `clear`: empty the cache.
|
|
1791
|
+
* - `import`, `compact`, `compaction`: nothing, since no in-place patch
|
|
1792
|
+
* expresses them. A host that must react intercepts them.
|
|
1793
|
+
*/
|
|
1794
|
+
function mirrorSessionChanges(subscribe, sessionId, options) {
|
|
1795
|
+
const transform = options.transform ?? ((message) => message);
|
|
1796
|
+
return subscribe(async (event) => {
|
|
1797
|
+
if (event.sessionId !== sessionId) return;
|
|
1798
|
+
if (await options.intercept?.(event)) return;
|
|
1799
|
+
switch (event.type) {
|
|
1800
|
+
case "append":
|
|
1801
|
+
case "update": {
|
|
1802
|
+
if (event.type === "append" && !event.inserted) return;
|
|
1803
|
+
const cache = options.get();
|
|
1804
|
+
const index = cache.findIndex((m) => m.id === event.message.id);
|
|
1805
|
+
if (index === -1 && event.type === "update") return;
|
|
1806
|
+
const message = transform(event.message);
|
|
1807
|
+
const previous = index === -1 ? void 0 : cache[index];
|
|
1808
|
+
if (index === -1) cache.push(message);
|
|
1809
|
+
else cache[index] = message;
|
|
1810
|
+
options.onApplied?.(event, message, previous);
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
case "delete": {
|
|
1814
|
+
const removed = new Set(event.messageIds);
|
|
1815
|
+
options.set(options.get().filter((m) => !removed.has(m.id)));
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
case "clear":
|
|
1819
|
+
options.set([]);
|
|
1820
|
+
return;
|
|
1821
|
+
default: return;
|
|
1822
|
+
}
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
//#endregion
|
|
1652
1826
|
//#region src/sessions/handle.ts
|
|
1653
1827
|
var _core$1 = /* @__PURE__ */ new WeakMap();
|
|
1654
1828
|
var _ready = /* @__PURE__ */ new WeakMap();
|
|
@@ -1682,6 +1856,13 @@ var Session = class {
|
|
|
1682
1856
|
return this;
|
|
1683
1857
|
}
|
|
1684
1858
|
/**
|
|
1859
|
+
* Keep an in-memory transcript in step with this session's change feed,
|
|
1860
|
+
* so write sites never hand-patch it. Returns the unsubscribe function.
|
|
1861
|
+
*/
|
|
1862
|
+
mirror(options) {
|
|
1863
|
+
return mirrorSessionChanges((listener) => _classPrivateFieldGet2(_core$1, this).subscribe(listener), this.sessionId, options);
|
|
1864
|
+
}
|
|
1865
|
+
/**
|
|
1685
1866
|
* Stream the active branch path root → leaf (leaf → root with
|
|
1686
1867
|
* `newestFirst`) with compaction overlays applied. Peak memory is one
|
|
1687
1868
|
* bounded content window, never the whole transcript, and a consumer that
|
|
@@ -1768,9 +1949,18 @@ var Session = class {
|
|
|
1768
1949
|
/**
|
|
1769
1950
|
* Append one message. Idempotent on id: a repeated append returns the row
|
|
1770
1951
|
* already stored and dispatches an `append` event with `inserted: false`.
|
|
1952
|
+
*
|
|
1953
|
+
* A compaction overlay (a `compaction_` id) is derived on read and is never
|
|
1954
|
+
* stored. Clients post their transcript back after every compaction, so
|
|
1955
|
+
* this and every other write drops one silently: nothing is written and no
|
|
1956
|
+
* event is dispatched.
|
|
1771
1957
|
*/
|
|
1772
1958
|
async appendMessage(message, options = {}) {
|
|
1773
1959
|
await _classPrivateFieldGet2(_ready, this).call(this);
|
|
1960
|
+
if (isCompactionMessage(message)) return {
|
|
1961
|
+
inserted: false,
|
|
1962
|
+
message
|
|
1963
|
+
};
|
|
1774
1964
|
const prepared = _assertClassBrand(_Session_brand, this, _prepare).call(this, message, options.source);
|
|
1775
1965
|
const result = _classPrivateFieldGet2(_core$1, this).append(this.sessionId, prepared.message, options.parentId, prepared.tokenEstimate);
|
|
1776
1966
|
await _classPrivateFieldGet2(_core$1, this).notify({
|
|
@@ -1786,10 +1976,12 @@ var Session = class {
|
|
|
1786
1976
|
/**
|
|
1787
1977
|
* Update one stored row. Returns the stored form, or `null` when the id is
|
|
1788
1978
|
* not in this session. An unchanged message writes nothing and dispatches
|
|
1789
|
-
* no event.
|
|
1979
|
+
* no event. A compaction overlay is never a stored row, so it reports
|
|
1980
|
+
* `null`.
|
|
1790
1981
|
*/
|
|
1791
1982
|
async updateMessage(message, options = {}) {
|
|
1792
1983
|
await _classPrivateFieldGet2(_ready, this).call(this);
|
|
1984
|
+
if (isCompactionMessage(message)) return null;
|
|
1793
1985
|
const prepared = _assertClassBrand(_Session_brand, this, _prepare).call(this, message, options.source);
|
|
1794
1986
|
const outcome = _classPrivateFieldGet2(_core$1, this).update(this.sessionId, prepared.message, prepared.tokenEstimate);
|
|
1795
1987
|
if (outcome === "missing") return null;
|
|
@@ -1817,6 +2009,13 @@ var Session = class {
|
|
|
1817
2009
|
return {
|
|
1818
2010
|
abandon: () => _classPrivateFieldGet2(_core$1, this).forgetCaches(this.sessionId),
|
|
1819
2011
|
upsert: (message, options = {}) => {
|
|
2012
|
+
if (isCompactionMessage(message)) return {
|
|
2013
|
+
result: {
|
|
2014
|
+
inserted: false,
|
|
2015
|
+
message
|
|
2016
|
+
},
|
|
2017
|
+
after: () => Promise.resolve()
|
|
2018
|
+
};
|
|
1820
2019
|
const prepared = _assertClassBrand(_Session_brand, this, _prepare).call(this, message, options.source);
|
|
1821
2020
|
if (!_classPrivateFieldGet2(_core$1, this).exists(this.sessionId, message.id)) {
|
|
1822
2021
|
const result = _classPrivateFieldGet2(_core$1, this).append(this.sessionId, prepared.message, options.parentId, prepared.tokenEstimate);
|
|
@@ -1851,6 +2050,10 @@ var Session = class {
|
|
|
1851
2050
|
}
|
|
1852
2051
|
async upsertMessage(message, options = {}) {
|
|
1853
2052
|
await _classPrivateFieldGet2(_ready, this).call(this);
|
|
2053
|
+
if (isCompactionMessage(message)) return {
|
|
2054
|
+
inserted: false,
|
|
2055
|
+
message
|
|
2056
|
+
};
|
|
1854
2057
|
if (!_classPrivateFieldGet2(_core$1, this).exists(this.sessionId, message.id)) return this.appendMessage(message, options);
|
|
1855
2058
|
return {
|
|
1856
2059
|
inserted: false,
|
|
@@ -1863,6 +2066,12 @@ var Session = class {
|
|
|
1863
2066
|
* `import` change event so a host cache can mark itself stale; it is not
|
|
1864
2067
|
* an `append`, so a cache does not patch itself per imported row, and an
|
|
1865
2068
|
* id that already exists writes nothing and dispatches nothing.
|
|
2069
|
+
*
|
|
2070
|
+
* Unlike the other writes, a `compaction_` id is imported as given: a
|
|
2071
|
+
* summary copied from another session's `history()` is the only record of
|
|
2072
|
+
* the context it replaced, and later rows may be parented to it. History
|
|
2073
|
+
* reads hide such a row only when it duplicates one of this session's own
|
|
2074
|
+
* compaction overlays.
|
|
1866
2075
|
*/
|
|
1867
2076
|
async importMessage(message, options) {
|
|
1868
2077
|
await _classPrivateFieldGet2(_ready, this).call(this);
|