@fungi.computer/shiitake 0.5.0 → 0.7.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 +59 -21
- package/dist/agent-control.d.ts +94 -2
- package/dist/agent-control.js +147 -26
- package/dist/client-entry.d.ts +20 -0
- package/dist/client-entry.js +5 -0
- package/dist/client-visitor.d.ts +33 -0
- package/dist/client-visitor.js +231 -0
- package/dist/client-wire.d.ts +9 -0
- package/dist/client-wire.js +24 -3
- package/dist/client.d.ts +27 -6
- package/dist/client.js +23 -0
- package/dist/cloudflare.d.ts +20 -0
- package/dist/cloudflare.js +4 -1
- package/dist/delegation.d.ts +79 -53
- package/dist/delegation.js +26 -21
- package/dist/effect.d.ts +26 -1
- package/dist/effect.js +14 -1
- package/dist/errors.d.ts +2 -2
- package/dist/errors.js +2 -0
- package/dist/extensions.d.ts +22 -3
- package/dist/extensions.js +1 -1
- package/dist/fleet.d.ts +25 -2
- package/dist/fleet.js +108 -24
- package/dist/hosted.js +3 -0
- package/dist/http-routes.d.ts +23 -9
- package/dist/http.d.ts +1 -0
- package/dist/http.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/internal/accepted-run-executor.js +2 -1
- package/dist/internal/admission-door.d.ts +6 -1
- package/dist/internal/admission-door.js +33 -3
- package/dist/internal/contracts.d.ts +19 -1
- package/dist/internal/coordinator.js +115 -52
- package/dist/internal/effect-client.js +1 -1
- package/dist/internal/effect-contracts.d.ts +9 -2
- package/dist/internal/extension-command-registry.d.ts +2 -1
- package/dist/internal/extension-command-registry.js +3 -1
- package/dist/internal/extension-runtime.d.ts +3 -1
- package/dist/internal/extension-runtime.js +18 -8
- package/dist/internal/model-acquisition.js +2 -0
- package/dist/internal/observation-kernel.d.ts +2 -0
- package/dist/internal/observation-kernel.js +17 -6
- package/dist/internal/promise-facade.js +2 -0
- package/dist/internal/run-scope.d.ts +14 -0
- package/dist/internal/run-scope.js +58 -15
- package/dist/internal/runtime-coordinator.d.ts +14 -0
- package/dist/internal/runtime-coordinator.js +60 -11
- package/dist/internal/runtime-core.d.ts +3 -0
- package/dist/internal/runtime-core.js +1 -0
- package/dist/internal/runtime-reconciliation.js +123 -25
- package/dist/internal/session-context.d.ts +5 -5
- package/dist/internal/session-context.js +80 -83
- package/dist/internal/session-status.d.ts +2 -2
- package/dist/internal/session-status.js +5 -3
- package/dist/internal/woodstock/agent-reply.d.ts +5 -0
- package/dist/internal/woodstock/agent-reply.js +3 -0
- package/dist/internal/woodstock/client-projection.js +13 -11
- package/dist/internal/woodstock/fleet-store.d.ts +3 -2
- package/dist/internal/woodstock/fleet-store.js +24 -4
- package/dist/internal/woodstock/index.d.ts +7 -3
- package/dist/internal/woodstock/index.js +23 -6
- package/dist/internal/woodstock/progress.d.ts +11 -1
- package/dist/internal/woodstock/progress.js +126 -25
- package/dist/internal/woodstock/session-delegator.d.ts +13 -0
- package/dist/internal/woodstock/session-delegator.js +44 -0
- package/dist/internal/woodstock/session-entry.d.ts +12 -2
- package/dist/internal/woodstock/session-store.d.ts +16 -2
- package/dist/internal/woodstock/session-store.js +349 -66
- package/dist/internal/woodstock/work-senders.d.ts +32 -0
- package/dist/internal/woodstock/work-senders.js +70 -0
- package/dist/node.js +11 -2
- package/dist/remote-client.js +7 -2
- package/dist/server-visitor-stream.d.ts +13 -0
- package/dist/server-visitor-stream.js +124 -0
- package/dist/session-attention.d.ts +30 -0
- package/dist/session-attention.js +14 -0
- package/docs/api/agent-control.md +212 -15
- package/docs/api/client-entry.md +3 -0
- package/docs/api/client.md +209 -5
- package/docs/api/cloudflare.md +23 -1
- package/docs/api/delegation.md +284 -77
- package/docs/api/effect.md +100 -12
- package/docs/api/extensions.md +73 -12
- package/docs/api/fleet.md +138 -25
- package/docs/api/http.md +28 -0
- package/docs/api/index.md +43 -17
- package/docs/api/testing.md +9 -7
- package/package.json +10 -6
|
@@ -3,6 +3,92 @@ import * as Schema from "effect/Schema";
|
|
|
3
3
|
import * as Result from "effect/Result";
|
|
4
4
|
import { ShiitakeError } from "../../errors.js";
|
|
5
5
|
import { publishOwnerObservation } from "../observation-kernel.js";
|
|
6
|
+
const tailBytes = 65_536;
|
|
7
|
+
const chunkUnits = 2048;
|
|
8
|
+
const encoder = new TextEncoder();
|
|
9
|
+
const emptyTail = () => ({ chunks: [], length: 0, bytes: 0 });
|
|
10
|
+
/** Bounded chunks: no concatenation or encoding of the reply-so-far. */
|
|
11
|
+
function appendTail(tail, append) {
|
|
12
|
+
for (let index = 0; index < append.length;) {
|
|
13
|
+
let end = Math.min(index + chunkUnits, append.length);
|
|
14
|
+
// Do not cut a Unicode scalar when bounding a provider's large delta.
|
|
15
|
+
const code = append.charCodeAt(end - 1);
|
|
16
|
+
if (end < append.length && code >= 0xd800 && code <= 0xdbff)
|
|
17
|
+
end--;
|
|
18
|
+
const text = append.slice(index, end);
|
|
19
|
+
const bytes = encoder.encode(text).byteLength;
|
|
20
|
+
const last = tail.chunks.at(-1);
|
|
21
|
+
if (last !== undefined && last.text.length + text.length <= chunkUnits) {
|
|
22
|
+
last.text += text;
|
|
23
|
+
last.bytes += bytes;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
tail.chunks.push({ offset: tail.length, text, bytes });
|
|
27
|
+
}
|
|
28
|
+
tail.length += text.length;
|
|
29
|
+
tail.bytes += bytes;
|
|
30
|
+
index = end;
|
|
31
|
+
while (tail.bytes > tailBytes && tail.chunks.length > 1) {
|
|
32
|
+
const dropped = tail.chunks.shift();
|
|
33
|
+
if (dropped !== undefined)
|
|
34
|
+
tail.bytes -= dropped.bytes;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function tailOffset(tail) {
|
|
39
|
+
return tail.chunks[0]?.offset ?? 0;
|
|
40
|
+
}
|
|
41
|
+
function tailAfter(tail, offset) {
|
|
42
|
+
return tail.chunks
|
|
43
|
+
.flatMap((chunk) => chunk.offset + chunk.text.length <= offset
|
|
44
|
+
? []
|
|
45
|
+
: [chunk.text.slice(Math.max(0, offset - chunk.offset))])
|
|
46
|
+
.join("");
|
|
47
|
+
}
|
|
48
|
+
function snapshot(value) {
|
|
49
|
+
return value === null
|
|
50
|
+
? null
|
|
51
|
+
: {
|
|
52
|
+
messageId: value.messageId,
|
|
53
|
+
revision: value.revision,
|
|
54
|
+
text: tailAfter(value.text, tailOffset(value.text)),
|
|
55
|
+
thinking: tailAfter(value.thinking, tailOffset(value.thinking)),
|
|
56
|
+
textOffset: tailOffset(value.text),
|
|
57
|
+
thinkingOffset: tailOffset(value.thinking),
|
|
58
|
+
textTruncated: tailOffset(value.text) > 0,
|
|
59
|
+
thinkingTruncated: tailOffset(value.thinking) > 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function progressPosition(value) {
|
|
63
|
+
return value === null
|
|
64
|
+
? null
|
|
65
|
+
: {
|
|
66
|
+
messageId: value.messageId,
|
|
67
|
+
revision: value.revision,
|
|
68
|
+
text: value.textOffset + value.text.length,
|
|
69
|
+
thinking: value.thinkingOffset + value.thinking.length,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Undefined means continuity was lost; null means no new model progress. */
|
|
73
|
+
export function readProcessProgressDelta(owner, sessionId, workId, after) {
|
|
74
|
+
const current = progressByOwner.get(owner)?.get(sessionId);
|
|
75
|
+
const value = current?.workId === workId ? current.value : null;
|
|
76
|
+
if (value === null)
|
|
77
|
+
return null;
|
|
78
|
+
const position = after?.messageId === value.messageId ? after : null;
|
|
79
|
+
if (position !== null && position.revision >= value.revision)
|
|
80
|
+
return null;
|
|
81
|
+
const text = position?.text ?? 0;
|
|
82
|
+
const thinking = position?.thinking ?? 0;
|
|
83
|
+
if (text < tailOffset(value.text) || thinking < tailOffset(value.thinking))
|
|
84
|
+
return undefined;
|
|
85
|
+
return {
|
|
86
|
+
messageId: value.messageId,
|
|
87
|
+
revision: value.revision,
|
|
88
|
+
text: { offset: text, append: tailAfter(value.text, text) },
|
|
89
|
+
thinking: { offset: thinking, append: tailAfter(value.thinking, thinking) },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
6
92
|
const progressByOwner = new WeakMap();
|
|
7
93
|
export function readProcessToolOutputForWork(owner, sessionId, workId) {
|
|
8
94
|
const current = progressByOwner.get(owner)?.get(sessionId);
|
|
@@ -96,23 +182,12 @@ function rejected(message) {
|
|
|
96
182
|
}
|
|
97
183
|
/** Read the current process-local progress value for one addressed Session. */
|
|
98
184
|
export function readProcessProgress(owner, sessionId) {
|
|
99
|
-
return progressFor(owner).get(sessionId)?.value ?? null;
|
|
185
|
+
return snapshot(progressFor(owner).get(sessionId)?.value ?? null);
|
|
100
186
|
}
|
|
101
187
|
/** Read progress only when it belongs to the current durable work head. */
|
|
102
188
|
export function readProcessProgressForWork(owner, sessionId, workId) {
|
|
103
189
|
const current = progressFor(owner).get(sessionId);
|
|
104
|
-
return current?.workId === workId ? current.value : null;
|
|
105
|
-
}
|
|
106
|
-
function textFor(event) {
|
|
107
|
-
let text = "";
|
|
108
|
-
let thinking = "";
|
|
109
|
-
for (const content of event.value.content) {
|
|
110
|
-
if (content.type === "text")
|
|
111
|
-
text += content.text;
|
|
112
|
-
if (content.type === "thinking")
|
|
113
|
-
thinking += content.thinking;
|
|
114
|
-
}
|
|
115
|
-
return { text, thinking };
|
|
190
|
+
return snapshot(current?.workId === workId ? current.value : null);
|
|
116
191
|
}
|
|
117
192
|
/**
|
|
118
193
|
* Keep live model progress in the current process only.
|
|
@@ -124,7 +199,23 @@ export function openProgress(owner, accepted, complete) {
|
|
|
124
199
|
return Effect.gen(function* () {
|
|
125
200
|
const current = yield* openProcessProgress(owner, accepted);
|
|
126
201
|
let started;
|
|
202
|
+
let publishedLength = 0;
|
|
203
|
+
let flushTimer;
|
|
204
|
+
const cancelFlush = () => {
|
|
205
|
+
if (flushTimer !== undefined)
|
|
206
|
+
clearTimeout(flushTimer);
|
|
207
|
+
flushTimer = undefined;
|
|
208
|
+
};
|
|
209
|
+
const publish = () => {
|
|
210
|
+
cancelFlush();
|
|
211
|
+
const value = current.value;
|
|
212
|
+
if (value === null)
|
|
213
|
+
return;
|
|
214
|
+
publishedLength = value.text.length + value.thinking.length;
|
|
215
|
+
publishOwnerObservation(owner, accepted.sessionId, "progress");
|
|
216
|
+
};
|
|
127
217
|
const clear = Effect.sync(() => {
|
|
218
|
+
cancelFlush();
|
|
128
219
|
const hadProgress = current.value !== null;
|
|
129
220
|
current.value = null;
|
|
130
221
|
if (hadProgress)
|
|
@@ -134,8 +225,10 @@ export function openProgress(owner, accepted, complete) {
|
|
|
134
225
|
yield* Effect.addFinalizer(() => clear);
|
|
135
226
|
return Object.freeze({
|
|
136
227
|
started: (event) => Effect.sync(() => {
|
|
228
|
+
cancelFlush();
|
|
137
229
|
started = event;
|
|
138
230
|
current.value = null;
|
|
231
|
+
publishedLength = 0;
|
|
139
232
|
}),
|
|
140
233
|
update: (event) => Effect.suspend(() => {
|
|
141
234
|
const messageStart = started;
|
|
@@ -145,20 +238,28 @@ export function openProgress(owner, accepted, complete) {
|
|
|
145
238
|
messageStart.turn.value !== event.turn.value ||
|
|
146
239
|
messageStart.message.value !== event.message.value)
|
|
147
240
|
return Effect.fail(rejected("Mule progress identity conflicts"));
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
previous.thinking === content.thinking)
|
|
241
|
+
const delta = event.event;
|
|
242
|
+
if ((delta.type !== "text_delta" && delta.type !== "thinking_delta") ||
|
|
243
|
+
delta.delta.length === 0)
|
|
152
244
|
return Effect.void;
|
|
153
|
-
current.value
|
|
245
|
+
const first = current.value === null;
|
|
246
|
+
const value = current.value ?? {
|
|
154
247
|
messageId: event.message.value,
|
|
155
|
-
revision:
|
|
156
|
-
text:
|
|
157
|
-
thinking:
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
248
|
+
revision: 0,
|
|
249
|
+
text: emptyTail(),
|
|
250
|
+
thinking: emptyTail(),
|
|
251
|
+
};
|
|
252
|
+
appendTail(delta.type === "text_delta" ? value.text : value.thinking, delta.delta);
|
|
253
|
+
value.revision++;
|
|
254
|
+
current.value = value;
|
|
255
|
+
const length = value.text.length + value.thinking.length;
|
|
256
|
+
// Coalesce tiny tokens, but flush a paused provider within 100 ms.
|
|
257
|
+
// One scope-owned timer holds no reply text and never writes SQLite.
|
|
258
|
+
if (first || length - publishedLength >= 4096) {
|
|
259
|
+
publish();
|
|
260
|
+
}
|
|
261
|
+
else
|
|
262
|
+
flushTimer ??= setTimeout(publish, 100);
|
|
162
263
|
return Effect.void;
|
|
163
264
|
}),
|
|
164
265
|
terminal: (event) => clear.pipe(Effect.andThen(complete(event))),
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BirdDogDelegator, BirdDogMail } from "@fungi.computer/bird-dog";
|
|
2
|
+
import type { WatchdogSqliteOwner } from "@fungi.computer/watchdog";
|
|
3
|
+
import type { SqliteOwner } from "../contracts.js";
|
|
4
|
+
/** Woodstock keeps each Session's delegator of record beside the Session. */
|
|
5
|
+
export declare function prepareSessionDelegators(owner: SqliteOwner): void;
|
|
6
|
+
/**
|
|
7
|
+
* Record who sent a Session its work first, in the admitting transaction.
|
|
8
|
+
* Only an original mail that asks for replies names a delegator; the first one
|
|
9
|
+
* stays, so the relationship never moves once it exists.
|
|
10
|
+
*/
|
|
11
|
+
export declare function recordSessionDelegator(owner: SqliteOwner, sessionId: string, mail: BirdDogMail | undefined): void;
|
|
12
|
+
/** The Session's delegator of record, if any Agent has sent it work. */
|
|
13
|
+
export declare function readSessionDelegator(owner: WatchdogSqliteOwner, sessionId: string): BirdDogDelegator | undefined;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BirdDogAgentReferenceSchema } from "@fungi.computer/bird-dog/effect";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
const decodeRow = Schema.decodeUnknownSync(Schema.Struct({
|
|
4
|
+
mail_key: Schema.String,
|
|
5
|
+
agent_id: Schema.String,
|
|
6
|
+
reply_to_json: Schema.fromJsonString(Schema.Array(BirdDogAgentReferenceSchema)),
|
|
7
|
+
}));
|
|
8
|
+
const encodeReplyTo = Schema.encodeSync(Schema.fromJsonString(Schema.Array(BirdDogAgentReferenceSchema)));
|
|
9
|
+
/** Woodstock keeps each Session's delegator of record beside the Session. */
|
|
10
|
+
export function prepareSessionDelegators(owner) {
|
|
11
|
+
owner.sql.exec(`CREATE TABLE IF NOT EXISTS session_delegators (
|
|
12
|
+
session_id TEXT PRIMARY KEY,
|
|
13
|
+
mail_key TEXT NOT NULL,
|
|
14
|
+
agent_id TEXT NOT NULL,
|
|
15
|
+
reply_to_json TEXT NOT NULL
|
|
16
|
+
)`);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Record who sent a Session its work first, in the admitting transaction.
|
|
20
|
+
* Only an original mail that asks for replies names a delegator; the first one
|
|
21
|
+
* stays, so the relationship never moves once it exists.
|
|
22
|
+
*/
|
|
23
|
+
export function recordSessionDelegator(owner, sessionId, mail) {
|
|
24
|
+
if (mail === undefined ||
|
|
25
|
+
mail.reply !== undefined ||
|
|
26
|
+
mail.from.kind !== "agent" ||
|
|
27
|
+
mail.replyTo.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
owner.sql.exec("INSERT OR IGNORE INTO session_delegators (session_id, mail_key, agent_id, reply_to_json) VALUES (?, ?, ?, ?)", sessionId, mail.key, mail.to.agentId, encodeReplyTo(mail.replyTo));
|
|
30
|
+
}
|
|
31
|
+
/** The Session's delegator of record, if any Agent has sent it work. */
|
|
32
|
+
export function readSessionDelegator(owner, sessionId) {
|
|
33
|
+
const [row] = owner.sql
|
|
34
|
+
.exec("SELECT mail_key, agent_id, reply_to_json FROM session_delegators WHERE session_id = ?", sessionId)
|
|
35
|
+
.toArray();
|
|
36
|
+
if (row === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
const decoded = decodeRow(row);
|
|
39
|
+
return {
|
|
40
|
+
key: decoded.mail_key,
|
|
41
|
+
agentId: decoded.agent_id,
|
|
42
|
+
replyTo: decoded.reply_to_json,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -74,6 +74,11 @@ declare const StoredSessionEntrySchema: Schema.Union<readonly [Schema.Struct<{
|
|
|
74
74
|
readonly commandId: Schema.String;
|
|
75
75
|
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
76
76
|
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
77
|
+
readonly waitingOnYou: Schema.optionalKey<Schema.$Array<Schema.Struct<{
|
|
78
|
+
readonly itemId: Schema.String;
|
|
79
|
+
readonly kind: Schema.String;
|
|
80
|
+
readonly summary: Schema.String;
|
|
81
|
+
}>>>;
|
|
77
82
|
readonly agentId: Schema.String;
|
|
78
83
|
readonly sessionId: Schema.String;
|
|
79
84
|
}>, Schema.Struct<{
|
|
@@ -357,15 +362,20 @@ export declare function decodeStoredSessionEntry(value: string): Result.Result<{
|
|
|
357
362
|
readonly delivery?: "followUp" | "steer";
|
|
358
363
|
readonly meta?: import("../../extensions.js").Json;
|
|
359
364
|
readonly reply?: {
|
|
365
|
+
readonly agentId: string;
|
|
360
366
|
readonly sessionId: string;
|
|
361
367
|
readonly commandId: string;
|
|
362
368
|
readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
|
|
363
|
-
readonly agentId: string;
|
|
364
369
|
readonly diagnostic?: string;
|
|
370
|
+
readonly waitingOnYou?: readonly {
|
|
371
|
+
readonly itemId: string;
|
|
372
|
+
readonly kind: string;
|
|
373
|
+
readonly summary: string;
|
|
374
|
+
}[];
|
|
365
375
|
} | {
|
|
376
|
+
readonly agentId: string;
|
|
366
377
|
readonly reason: "recipient_offline" | "recipient_left";
|
|
367
378
|
readonly outcome: "undeliverable";
|
|
368
|
-
readonly agentId: string;
|
|
369
379
|
readonly sessionId?: string;
|
|
370
380
|
};
|
|
371
381
|
readonly targetWorkId?: string;
|
|
@@ -167,6 +167,7 @@ export type EnqueueAcceptedWork = (work: Readonly<{
|
|
|
167
167
|
jobId: string;
|
|
168
168
|
sessionId: string;
|
|
169
169
|
commandFactId: string;
|
|
170
|
+
delivery: "steer" | "followUp";
|
|
170
171
|
}>) => void;
|
|
171
172
|
export type RecordAcceptedCancellation = (input: Readonly<{
|
|
172
173
|
jobId: string;
|
|
@@ -192,6 +193,8 @@ export type ForkSessionAtInput = SelectSessionBranchInput;
|
|
|
192
193
|
export declare function hasStoredSession(owner: SqliteOwner, sessionId: string): boolean;
|
|
193
194
|
/** Read one retained Session entry by its globally unique row identity. */
|
|
194
195
|
export declare function readSessionEntryById(owner: SqliteOwner, id: string): StoredSessionRow | undefined;
|
|
196
|
+
/** A written run terminal closes the window for attaching another steer. */
|
|
197
|
+
export declare function hasRecordedRunTerminal(owner: SqliteOwner, sessionId: string, workId: string): boolean;
|
|
195
198
|
/** Host-owned metadata identity, interpreted by SQLite's JSON decoder only. */
|
|
196
199
|
export type AdmissionIdentity = Readonly<{
|
|
197
200
|
path: string;
|
|
@@ -237,6 +240,8 @@ export declare function settleSessionControls(owner: SqliteOwner, input: Readonl
|
|
|
237
240
|
export declare function readSessionCommandAdmission(owner: SqliteOwner, sessionId: string, id: string): StoredCommandAdmission | undefined;
|
|
238
241
|
/** Read one stable private command admission by accepted request identity. */
|
|
239
242
|
export declare function readSessionCommandAdmissionByRequest(owner: SqliteOwner, sessionId: string, requestId: string): StoredCommandAdmission | undefined;
|
|
243
|
+
/** Probe the indexed terminal facts without materializing a live work's body. */
|
|
244
|
+
export declare function hasSessionWorkTerminal(owner: SqliteOwner, sessionId: string, workId: string): boolean;
|
|
240
245
|
/** Read entries correlated to one accepted work identity in Session order. */
|
|
241
246
|
export declare function readSessionEntriesForWork(owner: SqliteOwner, sessionId: string, workId: string): readonly StoredSessionRow[];
|
|
242
247
|
/** Read the latest retained live-retry event for one accepted work item. */
|
|
@@ -330,9 +335,18 @@ export declare const lineageRowLimit = 200;
|
|
|
330
335
|
* deduplicating; the fork walk keeps every link for its whole-lineage check.
|
|
331
336
|
*/
|
|
332
337
|
declare const lineageWalks: {
|
|
333
|
-
readonly selected: "WITH RECURSIVE branch (id, parent_id, sequence, state) AS (\n SELECT id, parent_id, sequence, state\n FROM session_entries\n WHERE session_id = ? AND id = ?\n UNION ALL\n SELECT parent.id, parent.parent_id, parent.sequence, parent.state\n FROM
|
|
334
|
-
readonly fork: "WITH RECURSIVE branch (id, parent_id, sequence, state) AS (\n SELECT id, parent_id, sequence, state\n FROM session_entries\n WHERE session_id = ? AND id = ? AND state != 'streaming'\n UNION\n SELECT parent.id, parent.parent_id, parent.sequence, parent.state\n FROM
|
|
338
|
+
readonly selected: "WITH RECURSIVE branch (id, parent_id, sequence, state) AS (\n SELECT id, parent_id, sequence, state\n FROM session_entries\n WHERE session_id = ? AND id = ?\n UNION ALL\n SELECT parent.id, parent.parent_id, parent.sequence, parent.state\n FROM branch AS child\n CROSS JOIN session_entries AS parent\n WHERE parent.id = child.parent_id AND parent.session_id = ?\n AND child.sequence > ?\n AND +parent.sequence < child.sequence\n )";
|
|
339
|
+
readonly fork: "WITH RECURSIVE branch (id, parent_id, sequence, state) AS (\n SELECT id, parent_id, sequence, state\n FROM session_entries\n WHERE session_id = ? AND id = ? AND state != 'streaming'\n UNION\n SELECT parent.id, parent.parent_id, parent.sequence, parent.state\n FROM branch AS child\n CROSS JOIN session_entries AS parent\n WHERE parent.id = child.parent_id AND parent.session_id = ?\n AND child.sequence > ?\n AND parent.state != 'streaming'\n )";
|
|
335
340
|
};
|
|
341
|
+
/**
|
|
342
|
+
* One synchronous, transaction-consistent Session baseline. Activity, timeline,
|
|
343
|
+
* extension projections and context figures share its identity-only ancestry;
|
|
344
|
+
* asynchronous model description runs after this scope has ended. Nothing is
|
|
345
|
+
* retained between reads, and payload windows keep their row and byte bounds.
|
|
346
|
+
*/
|
|
347
|
+
export declare function withSessionRead<A>(owner: SqliteOwner, sessionId: string, read: () => A, before?: number): A;
|
|
348
|
+
/** Join the shared Session baseline, or keep a direct projection atomic. */
|
|
349
|
+
export declare function withSessionReadTransaction<A>(owner: SqliteOwner, sessionId: string, read: () => A): A;
|
|
336
350
|
/**
|
|
337
351
|
* One root-to-tip lineage. Its integrity is enforced where entries are
|
|
338
352
|
* written (`guardSessionLineage`), so locating it reads only its tip and its
|