@guuey/threads 0.31.1 → 0.33.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/README.md +81 -0
- package/dist/closed.d.ts +22 -0
- package/dist/closed.d.ts.map +1 -0
- package/dist/closed.js +28 -0
- package/dist/fold-rows.d.ts +278 -5
- package/dist/fold-rows.d.ts.map +1 -1
- package/dist/fold-rows.js +475 -21
- package/dist/http-read.d.ts +47 -0
- package/dist/http-read.d.ts.map +1 -0
- package/dist/http-read.js +274 -0
- package/dist/http.d.ts +37 -34
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +145 -22
- package/dist/in-memory.d.ts +2 -7
- package/dist/in-memory.d.ts.map +1 -1
- package/dist/in-memory.js +27 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/item-size.d.ts +56 -0
- package/dist/item-size.d.ts.map +1 -0
- package/dist/item-size.js +125 -0
- package/dist/rows.d.ts +122 -1
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +13 -1
- package/dist/seal.d.ts +63 -0
- package/dist/seal.d.ts.map +1 -0
- package/dist/seal.js +120 -0
- package/dist/snapshot-plan.d.ts +61 -0
- package/dist/snapshot-plan.d.ts.map +1 -0
- package/dist/snapshot-plan.js +71 -0
- package/dist/store.d.ts +130 -2
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +274 -66
- package/dist/stored-row.d.ts +17 -3
- package/dist/stored-row.d.ts.map +1 -1
- package/dist/stored-row.js +2 -21
- package/dist/testing/contract-suite.d.ts +37 -1
- package/dist/testing/contract-suite.d.ts.map +1 -1
- package/dist/testing/contract-suite.js +122 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -79,6 +79,87 @@ and Cognito sessions are served on-platform only. Errors surface as
|
|
|
79
79
|
`HttpThreadStoreError` (`status`, `code`). Reads retry once on a network
|
|
80
80
|
failure or 5xx; writes never do.
|
|
81
81
|
|
|
82
|
+
## Row size limits
|
|
83
|
+
|
|
84
|
+
A store with an item-size limit declares it as the port's optional
|
|
85
|
+
`rowBudget` (`{ maxBytes, bytesOf(row), numberFits?(n) }`). The DynamoDB-backed
|
|
86
|
+
bindings, `HttpThreadPersistence` included, declare `DYNAMODB_ROW_BUDGET`:
|
|
87
|
+
380,000 bytes measured by `dynamoItemBytes`, an upper bound under DynamoDB's
|
|
88
|
+
own item-size rules, and `dynamoNumberFits`, which refuses a number DynamoDB
|
|
89
|
+
cannot hold as written (outside the safe-integer range, NaN or an infinity, or
|
|
90
|
+
a non-zero magnitude below 1e-130). A port without a budget stores rows exactly
|
|
91
|
+
as mapped.
|
|
92
|
+
|
|
93
|
+
`appendFold` checks every row of a turn against the budget before it writes any:
|
|
94
|
+
|
|
95
|
+
- A value is stored as a marker in its place,
|
|
96
|
+
`{ "com.guuey/elided": { "bytes": <UTF-8 length of its JSON> } }`. A
|
|
97
|
+
tool-call value is, when it carries a number the store cannot hold
|
|
98
|
+
(`reason: "number"`). An oversized row leaves values out until it fits
|
|
99
|
+
(`reason: "size"`), the largest first within each step: first a
|
|
100
|
+
tool-result's `uiData` that is an inline UI resource with text
|
|
101
|
+
(`{ uri, text }`) when a card row of the same turn carries the same value
|
|
102
|
+
for the same call (`field: "uiData"`; the card row holds the resource, and
|
|
103
|
+
the thread's readers draw the card from it), then each
|
|
104
|
+
`providerMetadata.wireInput` copy, then each `input`. Text blocks are never
|
|
105
|
+
elided. The result lists each one in `elidedToolInputs`.
|
|
106
|
+
- A turn that still cannot be stored is never written in part. With
|
|
107
|
+
`unstorableNotice: { text }` the turn is stored as ONE agent row carrying that
|
|
108
|
+
text and `content.error.code` `"stored_turn_too_large"` or
|
|
109
|
+
`"stored_turn_unstorable_number"` (`classifyStoredRow` reads either as a
|
|
110
|
+
failure), and the result carries `unstorable`. Without it, `appendFold`
|
|
111
|
+
throws `StoredRowTooLargeError` or `StoredRowUnstorableNumberError` and
|
|
112
|
+
writes nothing.
|
|
113
|
+
|
|
114
|
+
`appendMessage` refuses such a row the same way before it allocates a seq.
|
|
115
|
+
`withItemSizeLimit(port)` from `@guuey/threads/testing` wraps any port to
|
|
116
|
+
declare the budget and refuse what DynamoDB would (on `putMessage` and
|
|
117
|
+
`putSnapshot`), for tests.
|
|
118
|
+
|
|
119
|
+
The turn's snapshot is planned under the same budget, also before any row is
|
|
120
|
+
written (`planSnapshot`), so the snapshot write never fails after the rows
|
|
121
|
+
landed:
|
|
122
|
+
|
|
123
|
+
- A `workingState` that carries a number the store cannot hold is not stored.
|
|
124
|
+
The snapshot keeps `priorWorkingState` (the state the turn was seeded with),
|
|
125
|
+
or no state when none is given.
|
|
126
|
+
- A thread-memory element that carries such a number is left out.
|
|
127
|
+
- Over the budget, the turn's state is refused first, then the memory records
|
|
128
|
+
this turn wrote are left out, the largest first. Records stored unchanged
|
|
129
|
+
from `priorThreadMemory`, and carried elements, stay.
|
|
130
|
+
- A snapshot that still does not fit is not written, and the prior one stands.
|
|
131
|
+
|
|
132
|
+
The result's `refusedSnapshot` (`{ state?, memoryNumber, memorySize,
|
|
133
|
+
notWritten }`) reports what was left out, as counts.
|
|
134
|
+
|
|
135
|
+
## Sealed messages
|
|
136
|
+
|
|
137
|
+
A thread row may carry `sealIntervals`: stretches of messages (`fromSeq` to
|
|
138
|
+
`toSeq`, both inclusive; no `toSeq` = still open) that the app's operator may
|
|
139
|
+
not read. A reader that shows conversation data to the operator checks them
|
|
140
|
+
with the exported helpers, never by hand:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { isSeqSealed, readableThreadPreview, readSealState } from "@guuey/threads";
|
|
144
|
+
|
|
145
|
+
const seal = readSealState(row.sealIntervals); // absent = legacy, wholly readable
|
|
146
|
+
if (isSeqSealed(seal, message.seq)) {
|
|
147
|
+
/* withhold this message */
|
|
148
|
+
}
|
|
149
|
+
const preview = readableThreadPreview(row); // '' when its source message is sealed
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
A seal record that is present but malformed reads as wholly sealed. Each
|
|
153
|
+
preview records the seq it was taken from (`lastMessagePreviewSeq`) and a
|
|
154
|
+
digest of its text (`lastMessagePreviewDigest`, `previewDigest(preview)`) in
|
|
155
|
+
the same update. On a thread with any sealed part, a preview whose seq is
|
|
156
|
+
missing, or whose digest is missing or does not match its text, is withheld. A
|
|
157
|
+
binding that implements the port writes both with the preview.
|
|
158
|
+
|
|
159
|
+
An event row (a hand-off, a report) leaves the preview as it was, like a card
|
|
160
|
+
row: it is written from the whole conversation, so it never becomes the
|
|
161
|
+
thread's preview.
|
|
162
|
+
|
|
82
163
|
## Support
|
|
83
164
|
|
|
84
165
|
Questions and help: the guuey community on Discord — https://guuey.com/discord.
|
package/dist/closed.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A closed conversation (see {@link ThreadRow.closedAt}): how a stored row
|
|
3
|
+
* reads as closed, and the error a binding answers an append on one with.
|
|
4
|
+
*/
|
|
5
|
+
import type { ThreadClosure, ThreadRow } from "./rows.js";
|
|
6
|
+
/**
|
|
7
|
+
* The thread's closure, or `undefined` while it is open. `closedAt` alone
|
|
8
|
+
* decides: a row without it (every row written before closing existed) is
|
|
9
|
+
* open, and a row with it is closed even when its reason did not land
|
|
10
|
+
* (`code`/`message` then read as `""`).
|
|
11
|
+
*/
|
|
12
|
+
export declare function threadClosure(row: ThreadRow): ThreadClosure | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* A binding's answer to `incrementSeq` on a closed thread: the conversation
|
|
15
|
+
* takes no new message. A caller that meant to continue it starts a new one.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ThreadClosedError extends Error {
|
|
18
|
+
readonly threadId: string;
|
|
19
|
+
readonly code = "THREAD_CLOSED";
|
|
20
|
+
constructor(threadId: string);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=closed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"closed.d.ts","sourceRoot":"","sources":["../src/closed.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG,aAAa,GAAG,SAAS,CAOvE;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAE9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;IADrC,QAAQ,CAAC,IAAI,mBAAmB;gBACX,QAAQ,EAAE,MAAM;CAItC"}
|
package/dist/closed.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The thread's closure, or `undefined` while it is open. `closedAt` alone
|
|
3
|
+
* decides: a row without it (every row written before closing existed) is
|
|
4
|
+
* open, and a row with it is closed even when its reason did not land
|
|
5
|
+
* (`code`/`message` then read as `""`).
|
|
6
|
+
*/
|
|
7
|
+
export function threadClosure(row) {
|
|
8
|
+
if (typeof row.closedAt !== "string" || row.closedAt.length === 0)
|
|
9
|
+
return undefined;
|
|
10
|
+
return {
|
|
11
|
+
code: typeof row.closedCode === "string" ? row.closedCode : "",
|
|
12
|
+
message: typeof row.closedMessage === "string" ? row.closedMessage : "",
|
|
13
|
+
at: row.closedAt,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A binding's answer to `incrementSeq` on a closed thread: the conversation
|
|
18
|
+
* takes no new message. A caller that meant to continue it starts a new one.
|
|
19
|
+
*/
|
|
20
|
+
export class ThreadClosedError extends Error {
|
|
21
|
+
threadId;
|
|
22
|
+
code = "THREAD_CLOSED";
|
|
23
|
+
constructor(threadId) {
|
|
24
|
+
super(`thread ${threadId} is closed`);
|
|
25
|
+
this.threadId = threadId;
|
|
26
|
+
this.name = "ThreadClosedError";
|
|
27
|
+
}
|
|
28
|
+
}
|
package/dist/fold-rows.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* docs/superpowers/specs/2026-06-23-agjson-persistence-fold-design.md §6–§9.
|
|
6
6
|
*/
|
|
7
7
|
import type { AgMessage, AgArtifact, AgTurnRecord, AgReduceResult, AgEvent, AgMemoryRecord, JsonValue } from "@silverprotocol/core";
|
|
8
|
-
import type { ThreadMessageRow, ThreadSnapshotRow } from "./rows.js";
|
|
8
|
+
import type { RowBudget, ThreadMessageRow, ThreadSnapshotRow } from "./rows.js";
|
|
9
9
|
export interface RowCtx {
|
|
10
10
|
threadId: string;
|
|
11
11
|
userId: string;
|
|
@@ -37,6 +37,12 @@ export declare function messageNarration(msg: AgMessage): string[];
|
|
|
37
37
|
* bytes whether a row was written before the split or after it.
|
|
38
38
|
*/
|
|
39
39
|
export declare function messageFullText(msg: AgMessage): string;
|
|
40
|
+
/**
|
|
41
|
+
* A stored row's `text` as storage can hand it to a reader: a string, absent, or NULL. The row type
|
|
42
|
+
* says `string | undefined`, but a raw DynamoDB read cast to it can carry a NULL attribute, so the
|
|
43
|
+
* readers that take the row's text accept null and read it as no text.
|
|
44
|
+
*/
|
|
45
|
+
export type StoredRowText = string | null | undefined;
|
|
40
46
|
/** A stored message's text, split: the answer, the narration, and everything (the model's view). */
|
|
41
47
|
export interface StoredTextParts {
|
|
42
48
|
answer: string;
|
|
@@ -47,13 +53,261 @@ export interface StoredTextParts {
|
|
|
47
53
|
* Split a stored row's `content` into answer, narration and the model's full
|
|
48
54
|
* text, when `content` is a stored `AgMessage` (an object, or the JSON string
|
|
49
55
|
* an AppSync writer stores). Anything else is null, and a reader falls back to
|
|
50
|
-
* the row's `text`.
|
|
51
|
-
*
|
|
56
|
+
* the row's `text`. The message is read by {@link readStoredRowMessage}, so an
|
|
57
|
+
* unknown block is omitted rather than failing the row, and an elided answer
|
|
58
|
+
* reads from the row's `text`. `text` is required so that every caller passes
|
|
59
|
+
* the row's `text` on purpose (`undefined` or null when the row has none).
|
|
60
|
+
*/
|
|
61
|
+
export declare function storedTextParts(content: unknown, text: StoredRowText): StoredTextParts | null;
|
|
62
|
+
/** A tool-result block as a fold stores it. */
|
|
63
|
+
export type StoredToolResultBlock = Extract<AgMessage["content"][number], {
|
|
64
|
+
type: "tool-result";
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* A stored tool call as a reader serves it (guuey#2388): its id, the tool's
|
|
68
|
+
* raw wire name (guuey#402), its display title when the producer gave one,
|
|
69
|
+
* and its input, exactly what a host's live tool-call row reads. Built field
|
|
70
|
+
* by field, never core's block: core's call also carries provider and
|
|
71
|
+
* transport fields (`providerMetadata`, whose `wireInput` is a second copy of
|
|
72
|
+
* the input, `_meta`, `signature`, `toolMetadata`, `uiVisibility` and more)
|
|
73
|
+
* that a reader must not serve, and a served view only ever gains fields.
|
|
74
|
+
*/
|
|
75
|
+
export interface StoredToolCallView {
|
|
76
|
+
toolCallId: string;
|
|
77
|
+
name: string;
|
|
78
|
+
title?: string;
|
|
79
|
+
input: JsonValue;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The tool calls a stored row's message makes, in block order, as
|
|
83
|
+
* {@link StoredToolCallView}s (guuey#2388). The name rides only the call; a
|
|
84
|
+
* result carries just the id, and a facet may store the result in a message
|
|
85
|
+
* (and so a row) of its own, so a reader that names a result reads the calls
|
|
86
|
+
* of the rows around it (guuey#2487). Empty when `content` is not a stored
|
|
87
|
+
* message.
|
|
88
|
+
*/
|
|
89
|
+
export declare function storedToolCallViews(content: unknown, text: StoredRowText): StoredToolCallView[];
|
|
90
|
+
/**
|
|
91
|
+
* The tool results a stored row's message carries that NO card row stands for
|
|
92
|
+
* (guuey#2487): every `tool-result` block that does not carry a UI resource
|
|
93
|
+
* ({@link toolResultCarriesUi}), without its `_meta` (guuey#122), in block
|
|
94
|
+
* order. A host draws from such a result (an in-process tool's
|
|
95
|
+
* `structuredContent`, or its text) live; this is how a reader finds it again
|
|
96
|
+
* after a reload. A UI-carrying result is left out: its card row already
|
|
97
|
+
* carries it. Empty when `content` is not a stored message.
|
|
98
|
+
*/
|
|
99
|
+
export declare function storedToolResults(content: unknown, text: StoredRowText): StoredToolResultBlock[];
|
|
100
|
+
/**
|
|
101
|
+
* The call id of EVERY `tool-result` block a stored row's message carries, in
|
|
102
|
+
* block order, whether it carries a UI resource or not (guuey#2487). A reader
|
|
103
|
+
* that names results by their calls uses it to tell where a call's results
|
|
104
|
+
* sit on a page, card-drawn ones included: a call's first result row is
|
|
105
|
+
* written straight after the call row, and a UI-carrying result's card row
|
|
106
|
+
* straight after the result (guuey#2396). Empty when `content` is not a
|
|
107
|
+
* stored message.
|
|
108
|
+
*/
|
|
109
|
+
export declare function storedToolResultCallIds(content: unknown, text: StoredRowText): string[];
|
|
110
|
+
/**
|
|
111
|
+
* A row's stored message as every reader of a row reads it ({@link storedTextParts},
|
|
112
|
+
* {@link rowToAgMessage}, `classifyStoredRow`): `content` (a stored `AgMessage`
|
|
113
|
+
* object) through core's lenient stored-record reader, with an ELIDED ANSWER
|
|
114
|
+
* restored from the row's `text`. `undefined` when core cannot materialize the
|
|
115
|
+
* message. Like core's reader, it returns a view, never a record to persist.
|
|
116
|
+
*
|
|
117
|
+
* A stored message may leave its answer out of `content` because the row's
|
|
118
|
+
* `text` carries the same words: an answer block whose `text` is the
|
|
119
|
+
* {@link ELIDED_VALUE_KEY} marker ({@link isElidedAnswerBlock}). Such a message
|
|
120
|
+
* is rebuilt once, before it is read: the row's `text` (every answer block,
|
|
121
|
+
* joined) becomes the text of the first answer block, and every later answer
|
|
122
|
+
* block is left out, since that `text` already holds it. An answer block here
|
|
123
|
+
* is a block core can read as a text block, not narration, that is elided or
|
|
124
|
+
* non-empty. Every other block stays as stored. When the answer blocks stand
|
|
125
|
+
* together, as a reply's do, the rebuilt message reads the same text as the
|
|
126
|
+
* unelided one.
|
|
127
|
+
*
|
|
128
|
+
* Only the marker reads the row's `text`: a message with no answer blocks reads
|
|
129
|
+
* as it always has, with an empty answer, whatever the row's `text` says. On a
|
|
130
|
+
* row with no `text` (absent, NULL or empty) there is nothing to restore: only
|
|
131
|
+
* the elided blocks are left out and every other block reads as stored, so a
|
|
132
|
+
* stored word is never erased. An elided answer alone then reads as an empty
|
|
133
|
+
* answer in {@link storedTextParts} and `classifyStoredRow`, as its unelided
|
|
134
|
+
* twin with an empty answer would; the rebuilt message leaves the block out.
|
|
52
135
|
*/
|
|
53
|
-
export declare function
|
|
136
|
+
export declare function readStoredRowMessage(content: unknown, text: StoredRowText): AgMessage | undefined;
|
|
137
|
+
/** A stored text element as a stored message carries it, before core reads it. */
|
|
138
|
+
interface StoredTextElement {
|
|
139
|
+
type: "text";
|
|
140
|
+
text: unknown;
|
|
141
|
+
}
|
|
54
142
|
export declare function agMessageToRow(msg: AgMessage, ctx: RowCtx & {
|
|
55
143
|
turnRecord?: AgTurnRecord;
|
|
56
144
|
}): ThreadMessageRow;
|
|
145
|
+
/**
|
|
146
|
+
* The key of the marker a stored value is replaced by when the row would not
|
|
147
|
+
* fit its store's {@link RowBudget}: `{ "com.guuey/elided": { bytes } }`, where
|
|
148
|
+
* `bytes` is the UTF-8 length of the elided value's JSON. It stands in for the
|
|
149
|
+
* value whole (a tool-call `input`, its `providerMetadata.wireInput`, or a
|
|
150
|
+
* tool-result `uiData` the turn's card row also carries), so the block keeps
|
|
151
|
+
* an object where an object was.
|
|
152
|
+
*/
|
|
153
|
+
export declare const ELIDED_VALUE_KEY = "com.guuey/elided";
|
|
154
|
+
/**
|
|
155
|
+
* Which value of a block was elided: a tool-call's `input` or
|
|
156
|
+
* `providerMetadata.wireInput`, or a tool-result's `uiData` (an inline UI
|
|
157
|
+
* resource the turn's card row carries whole).
|
|
158
|
+
*/
|
|
159
|
+
export type ElidedField = "input" | "wireInput" | "uiData";
|
|
160
|
+
/**
|
|
161
|
+
* Why a tool-call value was elided: the row did not fit the store's row
|
|
162
|
+
* budget (`size`), or the value carried a number the store cannot hold as
|
|
163
|
+
* written (`number`, see {@link RowBudget.numberFits}).
|
|
164
|
+
*/
|
|
165
|
+
export type ElisionReason = "size" | "number";
|
|
166
|
+
/** One stored value replaced by the elided marker. */
|
|
167
|
+
export interface StoredElision {
|
|
168
|
+
toolCallId: string;
|
|
169
|
+
/** The tool's name (for a `uiData` elision, the name its card row stores). */
|
|
170
|
+
name: string;
|
|
171
|
+
field: ElidedField;
|
|
172
|
+
reason: ElisionReason;
|
|
173
|
+
/** UTF-8 length of the elided value's JSON. */
|
|
174
|
+
bytes: number;
|
|
175
|
+
}
|
|
176
|
+
/** The kind of row a stored-row refusal was raised for. */
|
|
177
|
+
export type RefusedRowKind = "message" | "card" | "append";
|
|
178
|
+
/**
|
|
179
|
+
* A row cannot fit its store's {@link RowBudget}, even with every value it
|
|
180
|
+
* carries that may be elided elided. Counts only, never row content.
|
|
181
|
+
*/
|
|
182
|
+
export declare class StoredRowTooLargeError extends Error {
|
|
183
|
+
readonly bytes: number;
|
|
184
|
+
readonly maxBytes: number;
|
|
185
|
+
readonly rowKind: RefusedRowKind;
|
|
186
|
+
/** The row's index among the turn's message or card rows (0 for an append). */
|
|
187
|
+
readonly index: number;
|
|
188
|
+
readonly name = "StoredRowTooLargeError";
|
|
189
|
+
constructor(bytes: number, maxBytes: number, rowKind: RefusedRowKind,
|
|
190
|
+
/** The row's index among the turn's message or card rows (0 for an append). */
|
|
191
|
+
index: number);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* A row carries a number its store cannot hold as written (see
|
|
195
|
+
* {@link RowBudget.numberFits}) outside any tool-call value that could be
|
|
196
|
+
* elided. Never names the number: it may be part of a tool's input or result.
|
|
197
|
+
*/
|
|
198
|
+
export declare class StoredRowUnstorableNumberError extends Error {
|
|
199
|
+
readonly rowKind: RefusedRowKind;
|
|
200
|
+
/** The row's index among the turn's message or card rows (0 for an append). */
|
|
201
|
+
readonly index: number;
|
|
202
|
+
readonly name = "StoredRowUnstorableNumberError";
|
|
203
|
+
constructor(rowKind: RefusedRowKind,
|
|
204
|
+
/** The row's index among the turn's message or card rows (0 for an append). */
|
|
205
|
+
index: number);
|
|
206
|
+
}
|
|
207
|
+
/** Either reason a row cannot be stored: too large, or carrying an unstorable number. */
|
|
208
|
+
export type StoredRowRefusal = StoredRowTooLargeError | StoredRowUnstorableNumberError;
|
|
209
|
+
export declare function isStoredRowRefusal(err: unknown): err is StoredRowRefusal;
|
|
210
|
+
/** Whether `value` (any JSON-shaped data) holds a number `fits` refuses, at any depth. */
|
|
211
|
+
export declare function carriesUnfitNumber(value: unknown, fits: (n: number) => boolean): boolean;
|
|
212
|
+
/**
|
|
213
|
+
* Throw when `row` cannot be stored under `budget`: {@link StoredRowUnstorableNumberError}
|
|
214
|
+
* when it carries a number the store cannot hold, {@link StoredRowTooLargeError}
|
|
215
|
+
* when it measures over the budget. No-op without a budget.
|
|
216
|
+
*/
|
|
217
|
+
export declare function assertRowFits(row: ThreadMessageRow, budget: RowBudget | undefined, rowKind: RefusedRowKind, index: number): void;
|
|
218
|
+
/** One tool-result `uiData` a card row of the turn carries, with the tool name that row stores. */
|
|
219
|
+
export interface CardUiData {
|
|
220
|
+
name: string;
|
|
221
|
+
uiData: JsonValue;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* What a turn's card rows carry, by tool call: for each `toolCallId`, the
|
|
225
|
+
* `uiData` of every tool-result part of a card row that names its producing
|
|
226
|
+
* tool. A message row's tool-result `uiData` equal to one of these is a second
|
|
227
|
+
* copy of what that card row stores.
|
|
228
|
+
*/
|
|
229
|
+
export type CardUiDataByCallId = ReadonlyMap<string, readonly CardUiData[]>;
|
|
230
|
+
/** {@link CardUiDataByCallId} over a turn's card rows (rows of another kind are skipped). */
|
|
231
|
+
export declare function cardUiDataByCallId(cardRows: readonly ThreadMessageRow[]): CardUiDataByCallId;
|
|
232
|
+
/**
|
|
233
|
+
* A stored ANSWER block left out because the row's `text` carries the same
|
|
234
|
+
* words: a `text` block whose `text` is the {@link ELIDED_VALUE_KEY} marker
|
|
235
|
+
* (`{ "com.guuey/elided": { bytes } }`, `bytes` the UTF-8 length of the
|
|
236
|
+
* elided string's JSON) in place of the string. A narration block
|
|
237
|
+
* (`phase: "interim"`) is never one: the row's `text` is the answer only, so
|
|
238
|
+
* it holds no narration to read back. Read on the raw stored element, since
|
|
239
|
+
* core's lenient reader leaves such a block out (its `text` is not a string).
|
|
240
|
+
*/
|
|
241
|
+
export declare function isElidedAnswerBlock(element: unknown): element is StoredTextElement;
|
|
242
|
+
/**
|
|
243
|
+
* {@link agMessageToRow}, bounded by the store's {@link RowBudget}. Under the
|
|
244
|
+
* budget (or with none) the row is exactly `agMessageToRow(msg, ctx)`.
|
|
245
|
+
*
|
|
246
|
+
* First, when the budget declares `numberFits`, every tool-call value that
|
|
247
|
+
* carries a number the store cannot hold is replaced by the
|
|
248
|
+
* {@link ELIDED_VALUE_KEY} marker (`reason: "number"`; after `JSON.parse` such
|
|
249
|
+
* a number has already lost its digits, so storing it would store a wrong
|
|
250
|
+
* one). A row that still carries one elsewhere throws
|
|
251
|
+
* {@link StoredRowUnstorableNumberError}.
|
|
252
|
+
*
|
|
253
|
+
* Then, over the size budget, values are replaced one at a time
|
|
254
|
+
* (`reason: "size"`) until the row fits. Pure duplicates go first: a
|
|
255
|
+
* tool-result's `uiData` that is an inline UI resource with text, when a card
|
|
256
|
+
* row of the turn (`cards`, see {@link cardUiDataByCallId}) carries the same
|
|
257
|
+
* value for the same call. Then every `providerMetadata.wireInput` (a second
|
|
258
|
+
* copy of the input, carried only when it differs), then every `input`.
|
|
259
|
+
* Within each tier the largest goes first, ties in block order. A row that
|
|
260
|
+
* still does not fit throws {@link StoredRowTooLargeError}.
|
|
261
|
+
*/
|
|
262
|
+
export declare function agMessageToBoundedRow(msg: AgMessage, ctx: RowCtx & {
|
|
263
|
+
turnRecord?: AgTurnRecord;
|
|
264
|
+
}, budget: RowBudget | undefined, index: number, cards?: CardUiDataByCallId): {
|
|
265
|
+
row: ThreadMessageRow;
|
|
266
|
+
elided: StoredElision[];
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Whether a tool-result block carries a UI resource, and so becomes a card row
|
|
270
|
+
* ({@link uiCardArtifactsFromMessages}) rather than a stored tool result
|
|
271
|
+
* ({@link storedToolResults}). The one predicate both share, so a result is a
|
|
272
|
+
* card or a stored tool result, never both and never neither.
|
|
273
|
+
*
|
|
274
|
+
* It judges the block AS STORED: without its `_meta` (guuey#122), which never
|
|
275
|
+
* persists. The card projection sees the live block and the stored-row reader
|
|
276
|
+
* sees the stored one, so a predicate that read `_meta` would answer the two
|
|
277
|
+
* differently (a `_meta.ui` locator is visible to the first only). Judging the
|
|
278
|
+
* stored view gives one answer on both sides by construction.
|
|
279
|
+
*
|
|
280
|
+
* A block carries UI only on DURABLE evidence, what a card row needs to mount
|
|
281
|
+
* after a reload. As stored:
|
|
282
|
+
* - its `uiData` is an MCP resource payload (`{ uri, text|blob }`, bare or as
|
|
283
|
+
* `{ resource }`), which mounts inline;
|
|
284
|
+
* - its `uiData` or `structuredContent` names a `ui://` locator, which mounts
|
|
285
|
+
* by a fresh read of the uri (`structuredContent` for a producer that
|
|
286
|
+
* withholds `_meta`, guuey#209);
|
|
287
|
+
* - its `uiData` is the {@link ELIDED_VALUE_KEY} marker, which stands in for
|
|
288
|
+
* an inline resource the turn's card row carries whole
|
|
289
|
+
* ({@link agMessageToBoundedRow});
|
|
290
|
+
* - or a `provider-raw` part carries a `ui://` resource.
|
|
291
|
+
*
|
|
292
|
+
* Anything else is a stored tool result, which a host reads by its tool name.
|
|
293
|
+
* That includes plain view data in `uiData`: AgJSON §2.1 routes a result's
|
|
294
|
+
* payload there whenever the producer set any `_meta.ui` sibling, so an
|
|
295
|
+
* object in `uiData` alone is no evidence that a card can mount. When
|
|
296
|
+
* `_meta.ui` named no `ui://` locator, nothing could ever mount it; when it
|
|
297
|
+
* did, the locator rode `_meta` alone and the writer strips it, so the stored
|
|
298
|
+
* row cannot mount it either. A card row for either would draw as an expired
|
|
299
|
+
* chip on every reload. (A writer that persisted that locator would make it a
|
|
300
|
+
* card here, by this same rule.)
|
|
301
|
+
*
|
|
302
|
+
* `_meta` alone never mints a card (the guuey#170 pin). Across a rolling
|
|
303
|
+
* release: a writer before this predicate minted a card row from a `_meta.ui`
|
|
304
|
+
* locator, so a thread written then holds that card row while this predicate
|
|
305
|
+
* reads the same stored result as one with no UI resource. A reader that
|
|
306
|
+
* serves both kinds keeps one item per result by leaving out a stored tool
|
|
307
|
+
* result whose call already has a card row on its read (the public transcript
|
|
308
|
+
* read does).
|
|
309
|
+
*/
|
|
310
|
+
export declare function toolResultCarriesUi(block: StoredToolResultBlock): boolean;
|
|
57
311
|
export declare function uiCardArtifactsFromMessages(messages: AgMessage[]): AgArtifact[];
|
|
58
312
|
/**
|
|
59
313
|
* toolCallId → tool name, read off every `tool-call` block in the fold's
|
|
@@ -71,6 +325,21 @@ export declare function toolNamesByCallId(messages: AgMessage[]): Map<string, st
|
|
|
71
325
|
* never a guess (humanization and fallbacks are the kit's, one owner).
|
|
72
326
|
*/
|
|
73
327
|
export declare function producingToolName(art: AgArtifact, toolNames: ReadonlyMap<string, string>): string | undefined;
|
|
328
|
+
/**
|
|
329
|
+
* toolCallId → the index of the fold message that carries that call's
|
|
330
|
+
* `tool-result` block (guuey#2396). A card is drawn when its tool-result
|
|
331
|
+
* arrives, so this is where its card row belongs in the turn's stored order.
|
|
332
|
+
* First message wins on a duplicate id, as in {@link toolNamesByCallId}.
|
|
333
|
+
*/
|
|
334
|
+
export declare function toolResultMessageIndexByCallId(messages: AgMessage[]): Map<string, number>;
|
|
335
|
+
/**
|
|
336
|
+
* The index of the fold message a card artifact was drawn with: the message
|
|
337
|
+
* holding the tool-result its first tool-result part names (guuey#2396).
|
|
338
|
+
* `undefined` when unresolvable (a first-class `artifact.*` event with no
|
|
339
|
+
* tool-result part, or a call outside this fold): such a card keeps the
|
|
340
|
+
* turn's tail.
|
|
341
|
+
*/
|
|
342
|
+
export declare function producingMessageIndex(art: AgArtifact, resultIndices: ReadonlyMap<string, number>): number | undefined;
|
|
74
343
|
export declare function agArtifactToCardRow(art: AgArtifact, ctx: RowCtx, toolName?: string): ThreadMessageRow;
|
|
75
344
|
/**
|
|
76
345
|
* Reconstruct an AgMessage from a row. Agent-fold rows store the verbatim
|
|
@@ -83,7 +352,8 @@ export declare function agArtifactToCardRow(art: AgArtifact, ctx: RowCtx, toolNa
|
|
|
83
352
|
* undefined value in a closed set, is omitted whole and the rest restores in
|
|
84
353
|
* order; unknown fields pass through untouched. Only a record the reader
|
|
85
354
|
* cannot materialize (no string `id`, an undefined `role`, no `content`
|
|
86
|
-
* array) falls to the text projection.
|
|
355
|
+
* array) falls to the text projection. A stored message whose answer block is
|
|
356
|
+
* elided reads its answer from the row's `text` ({@link readStoredRowMessage}).
|
|
87
357
|
*/
|
|
88
358
|
export declare function rowToAgMessage(row: ThreadMessageRow): AgMessage;
|
|
89
359
|
/** Extract the AgArtifact from a kind='card' row, or undefined if malformed. */
|
|
@@ -126,6 +396,8 @@ export declare function splitStoredThreadMemory(stored: readonly JsonValue[]): P
|
|
|
126
396
|
* turn, so write order stays time order.
|
|
127
397
|
*/
|
|
128
398
|
export declare function joinStoredThreadMemory(row: Pick<ThreadSnapshotRow, "threadMemory" | "carriedThreadMemory">): JsonValue[];
|
|
399
|
+
/** Structural equality over JSON values (object key order does not matter). */
|
|
400
|
+
export declare function jsonEqual(a: JsonValue | undefined, b: JsonValue | undefined): boolean;
|
|
129
401
|
/**
|
|
130
402
|
* The thread records a turn persists: each record of the fold, except that a
|
|
131
403
|
* record the turn did NOT change is persisted as the PRIOR stored record
|
|
@@ -179,4 +451,5 @@ export declare function keepUnchangedThreadMemory(priorView: readonly AgMemoryRe
|
|
|
179
451
|
* so it cannot round-trip through a live write — that is expected.)
|
|
180
452
|
*/
|
|
181
453
|
export declare function seedEventsForReducer(priorState: JsonValue | undefined, priorThreadMemory: AgMemoryRecord[]): AgEvent[];
|
|
454
|
+
export {};
|
|
182
455
|
//# sourceMappingURL=fold-rows.d.ts.map
|
package/dist/fold-rows.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fold-rows.d.ts","sourceRoot":"","sources":["../src/fold-rows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,YAAY,EAEZ,cAAc,EACd,OAAO,EACP,cAAc,EACd,SAAS,EACV,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,gBAAgB,EAAwC,iBAAiB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"fold-rows.d.ts","sourceRoot":"","sources":["../src/fold-rows.ts"],"names":[],"mappings":"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"}
|