@nyte-ai/sdk 0.0.0-stage → 0.0.19
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/LICENSE +21 -0
- package/THIRD-PARTY-NOTICES.md +866 -0
- package/dist/chunks/capability-2q3s96kg.js +57 -0
- package/dist/chunks/capability-9747w1b1.js +55 -0
- package/dist/chunks/capability-agj3gwwv.js +134 -0
- package/dist/chunks/capability-artgq59v.js +232 -0
- package/dist/chunks/capability-b52hty54.js +17 -0
- package/dist/chunks/capability-ctnsbfx9.js +203 -0
- package/dist/chunks/capability-ec663cyt.js +208 -0
- package/dist/chunks/capability-ke5yk1as.js +165 -0
- package/dist/chunks/capability-mr5m2wn2.js +6 -0
- package/dist/chunks/capability-nh422cp0.js +35 -0
- package/dist/chunks/capability-swbs68d8.js +32 -0
- package/dist/chunks/capability-t9k5jy3d.js +96 -0
- package/dist/chunks/capability-xavf3m2f.js +243 -0
- package/dist/src/capability.d.ts +2 -0
- package/dist/src/capability.js +6 -0
- package/dist/src/client.d.ts +13 -0
- package/dist/src/client.js +14 -0
- package/dist/src/connect.d.ts +2 -0
- package/dist/src/connect.js +15 -0
- package/dist/src/history.d.ts +14 -0
- package/dist/src/history.js +7 -0
- package/dist/src/index.client.d.ts +10 -0
- package/dist/src/index.client.js +57 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +58 -0
- package/dist/src/index.web.d.ts +8 -0
- package/dist/src/index.web.js +63 -0
- package/dist/src/journal.d.ts +15 -0
- package/dist/src/journal.js +9 -0
- package/dist/src/login.d.ts +8 -0
- package/dist/src/login.js +6 -0
- package/dist/src/paint-spans.d.ts +11 -0
- package/dist/src/paint-spans.js +6 -0
- package/dist/src/part.d.ts +4 -0
- package/dist/src/part.js +6 -0
- package/dist/src/receipts.d.ts +9 -0
- package/dist/src/receipts.js +16 -0
- package/dist/src/rows.d.ts +37 -0
- package/dist/src/rows.js +12 -0
- package/dist/src/surface.d.ts +12 -0
- package/dist/src/surface.js +39 -0
- package/dist/src/watch.d.ts +26 -0
- package/dist/src/watch.js +14 -0
- package/dist/src/workspace.d.ts +4 -0
- package/dist/src/workspace.js +9 -0
- package/package.json +59 -3
- package/README.md +0 -3
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createHeadViews2,
|
|
3
|
+
watchHead2,
|
|
4
|
+
watchHost2,
|
|
5
|
+
withUnsent2
|
|
6
|
+
} from "./capability-ctnsbfx9.js";
|
|
7
|
+
import {
|
|
8
|
+
createLink2,
|
|
9
|
+
createRows2
|
|
10
|
+
} from "./capability-artgq59v.js";
|
|
11
|
+
import {
|
|
12
|
+
journalLoop2
|
|
13
|
+
} from "./capability-ke5yk1as.js";
|
|
14
|
+
import {
|
|
15
|
+
partHandle2
|
|
16
|
+
} from "./capability-9747w1b1.js";
|
|
17
|
+
import {
|
|
18
|
+
receiptHandle2,
|
|
19
|
+
sendReceipt2,
|
|
20
|
+
runHandle2,
|
|
21
|
+
moveOutcome2
|
|
22
|
+
} from "./capability-2q3s96kg.js";
|
|
23
|
+
import {
|
|
24
|
+
loginHandle2
|
|
25
|
+
} from "./capability-nh422cp0.js";
|
|
26
|
+
import {
|
|
27
|
+
workspaceHandle2
|
|
28
|
+
} from "./capability-xavf3m2f.js";
|
|
29
|
+
|
|
30
|
+
// src/client.ts
|
|
31
|
+
import { asId, isJson, SdkError } from "@nyte-ai/schema";
|
|
32
|
+
import { dev, followTrace, traced, watchStore } from "@nyte-ai/core";
|
|
33
|
+
var MAIN = asId("main");
|
|
34
|
+
function createClient2(transport, context) {
|
|
35
|
+
const link = createLink2();
|
|
36
|
+
const rows = createRows2(transport, link);
|
|
37
|
+
const bound = {
|
|
38
|
+
rows,
|
|
39
|
+
journal: journalLoop2(rows, context.journal),
|
|
40
|
+
views: createHeadViews2(rows)
|
|
41
|
+
};
|
|
42
|
+
bound.journal.replay(context.journaled);
|
|
43
|
+
let hostFrames = context.hostFrames;
|
|
44
|
+
link.signal.addEventListener("abort", () => void hostFrames?.return?.(), { once: true });
|
|
45
|
+
const close = async () => {
|
|
46
|
+
link.close("client");
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
hostId: context.hostId,
|
|
50
|
+
principal: context.principal,
|
|
51
|
+
credential: context.credential,
|
|
52
|
+
sessions: {
|
|
53
|
+
watch: (input) => rows.watch("sessions.watch", input ?? {}),
|
|
54
|
+
async start(input) {
|
|
55
|
+
const id = input.id ?? asId(crypto.randomUUID());
|
|
56
|
+
followTrace(id, id);
|
|
57
|
+
const started = await traced("sdk.send", id, { session: id }, () => rows.wait("sessions.start", { ...input, id }));
|
|
58
|
+
return {
|
|
59
|
+
session: sessionHandle(bound, started.session),
|
|
60
|
+
receipt: sendReceipt2(rows, started.session, started.receipt, started.message)
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
list: (input) => rows.call("sessions.list", input ?? {})
|
|
64
|
+
},
|
|
65
|
+
workspaces: {
|
|
66
|
+
list: () => rows.call("workspaces.list", {}),
|
|
67
|
+
inspect: (target) => rows.call("workspaces.inspect", { target }),
|
|
68
|
+
add: (target, options) => rows.call("workspaces.add", { target, options }),
|
|
69
|
+
forget: (id) => rows.call("workspaces.forget", { id })
|
|
70
|
+
},
|
|
71
|
+
session: (id) => sessionHandle(bound, id),
|
|
72
|
+
workspace: (id) => workspaceHandle2(rows, id),
|
|
73
|
+
watch: () => {
|
|
74
|
+
const opened = hostFrames;
|
|
75
|
+
hostFrames = undefined;
|
|
76
|
+
return watchHost2(rows, opened);
|
|
77
|
+
},
|
|
78
|
+
blob: (id) => rows.bytes("connection.blob", { id }),
|
|
79
|
+
models: {
|
|
80
|
+
list: () => rows.call("models.list", {}),
|
|
81
|
+
accounts: (provider) => rows.call("models.accounts", { provider }),
|
|
82
|
+
async selectAccount(provider, account) {
|
|
83
|
+
await rows.call("models.selectAccount", { provider, account });
|
|
84
|
+
},
|
|
85
|
+
usage: () => rows.call("models.usage", {}),
|
|
86
|
+
async refresh(provider) {
|
|
87
|
+
await rows.call("models.refresh", { provider });
|
|
88
|
+
},
|
|
89
|
+
setDefault: (ref) => rows.call("models.setDefault", { ref }),
|
|
90
|
+
setListing: (refs, listing) => rows.call("models.setListing", { refs, listing }),
|
|
91
|
+
verify: (provider) => rows.call("models.verify", { provider }),
|
|
92
|
+
login: (input) => loginHandle2(rows, async () => {
|
|
93
|
+
await rows.call("models.login", input);
|
|
94
|
+
return input.provider;
|
|
95
|
+
}, input.provider),
|
|
96
|
+
async logout(provider) {
|
|
97
|
+
await rows.call("models.logout", { provider });
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
settings: { apply: (id, value) => rows.call("settings.apply", { id, value }) },
|
|
101
|
+
github: {
|
|
102
|
+
account: () => rows.call("github.account", {}),
|
|
103
|
+
signIn: () => rows.call("github.signIn", {}),
|
|
104
|
+
signOut: () => rows.call("github.signOut", {})
|
|
105
|
+
},
|
|
106
|
+
plugins: {
|
|
107
|
+
replace: (plugins, scope) => rows.call("plugins.replace", { plugins: files(plugins), scope }),
|
|
108
|
+
check: (plugins) => rows.call("plugins.check", { plugins: files(plugins) })
|
|
109
|
+
},
|
|
110
|
+
principals: {
|
|
111
|
+
list: async () => (await rows.call("principals.list", {})).map((view) => ({
|
|
112
|
+
...view,
|
|
113
|
+
authority: new Set(view.authority)
|
|
114
|
+
})),
|
|
115
|
+
pair: (input) => rows.call("principals.pair", { authority: [...input.authority], label: input.label }),
|
|
116
|
+
async revoke(id) {
|
|
117
|
+
await rows.call("principals.revoke", { id });
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
close,
|
|
121
|
+
[Symbol.asyncDispose]: close
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function sessionHandle(bound, session) {
|
|
125
|
+
const { rows } = bound;
|
|
126
|
+
return {
|
|
127
|
+
...headHandle(bound, session, MAIN),
|
|
128
|
+
id: session,
|
|
129
|
+
head: (name) => headHandle(bound, session, name),
|
|
130
|
+
heads: {
|
|
131
|
+
create: (name, input) => rows.call("heads.create", { session, name, input }),
|
|
132
|
+
merge: (name, options) => rows.call("heads.merge", { session, name, options }),
|
|
133
|
+
remove: (name, options) => rows.call("heads.remove", { session, name, options })
|
|
134
|
+
},
|
|
135
|
+
run: (id) => runHandle2(rows, session, id),
|
|
136
|
+
receipt: (id) => receiptHandle2(rows, session, id, (outcome) => outcome),
|
|
137
|
+
info: () => rows.call("session.info", { session }),
|
|
138
|
+
update: (patch) => rows.call("session.update", { session, patch }),
|
|
139
|
+
remove: () => rows.call("session.remove", { session }),
|
|
140
|
+
stop: () => rows.call("session.stop", { session }),
|
|
141
|
+
command: (name, text) => rows.call("session.command", { session, name, text }),
|
|
142
|
+
completeCommand: (name, prefix) => rows.call("session.completeCommand", { session, name, prefix }),
|
|
143
|
+
parts: {
|
|
144
|
+
async create(kind, input) {
|
|
145
|
+
const { part } = await rows.call("parts.create", {
|
|
146
|
+
session,
|
|
147
|
+
kind: kind.kind,
|
|
148
|
+
input: { ...input, state: jsonState(input.state) }
|
|
149
|
+
});
|
|
150
|
+
return partHandle2(rows, session, part, kind);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
part: (id) => partHandle2(rows, session, id, null)
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function headHandle(bound, session, head) {
|
|
157
|
+
const { rows, journal } = bound;
|
|
158
|
+
return {
|
|
159
|
+
sessionId: session,
|
|
160
|
+
name: head,
|
|
161
|
+
async send(content, options) {
|
|
162
|
+
const { id, ...rest } = options ?? {};
|
|
163
|
+
const receipt = id ?? asId(crypto.randomUUID());
|
|
164
|
+
dev("sdk", "send", { session, head, receipt });
|
|
165
|
+
followTrace(session, receipt);
|
|
166
|
+
const sent = await traced("sdk.send", receipt, { session }, () => journal.send({
|
|
167
|
+
id: receipt,
|
|
168
|
+
session,
|
|
169
|
+
head,
|
|
170
|
+
content,
|
|
171
|
+
options: rest,
|
|
172
|
+
at: Date.now()
|
|
173
|
+
}));
|
|
174
|
+
return sendReceipt2(rows, session, sent.receipt, sent.message);
|
|
175
|
+
},
|
|
176
|
+
configure: (patch) => rows.call("head.configure", { session, head, patch }),
|
|
177
|
+
async view(options) {
|
|
178
|
+
const view = await rows.call("head.view", { session, head, options });
|
|
179
|
+
journal.landed(session, head, view);
|
|
180
|
+
return withUnsent2(view, journal.unsent(session, head));
|
|
181
|
+
},
|
|
182
|
+
watch: (options) => watchHead2(bound.views, journal, { session, head, options }),
|
|
183
|
+
...watchStore(() => watchHead2(bound.views, journal, { session, head })),
|
|
184
|
+
history: (input) => rows.call("head.history", { session, head, ...input }),
|
|
185
|
+
tree: () => rows.call("head.tree", { session, head }),
|
|
186
|
+
async move(position, options) {
|
|
187
|
+
const { receipt } = await rows.call("head.move", {
|
|
188
|
+
session,
|
|
189
|
+
head,
|
|
190
|
+
position,
|
|
191
|
+
options,
|
|
192
|
+
id: asId(crypto.randomUUID())
|
|
193
|
+
});
|
|
194
|
+
return receiptHandle2(rows, session, receipt, moveOutcome2);
|
|
195
|
+
},
|
|
196
|
+
compact: (input) => rows.call("head.compact", { session, head, ...input })
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function jsonState(state) {
|
|
200
|
+
if (isJson(state))
|
|
201
|
+
return state;
|
|
202
|
+
throw new SdkError("invalid", "A part's state must be JSON.");
|
|
203
|
+
}
|
|
204
|
+
function files(plugins) {
|
|
205
|
+
return plugins.map((plugin) => ({ path: plugin.path }));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export { createClient2 };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import {
|
|
2
|
+
retryDelay2,
|
|
3
|
+
backoff2
|
|
4
|
+
} from "./capability-artgq59v.js";
|
|
5
|
+
|
|
6
|
+
// src/journal.ts
|
|
7
|
+
import { asId, SdkError } from "@nyte-ai/schema";
|
|
8
|
+
import { dev } from "@nyte-ai/core";
|
|
9
|
+
function createSendJournal2() {
|
|
10
|
+
const entries = new Map;
|
|
11
|
+
return {
|
|
12
|
+
load: async () => [...entries.values()],
|
|
13
|
+
async put(entry) {
|
|
14
|
+
entries.set(entry.id, entry);
|
|
15
|
+
},
|
|
16
|
+
async remove(id) {
|
|
17
|
+
entries.delete(id);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function journalLoop2(rows, journal) {
|
|
22
|
+
const held = new Map;
|
|
23
|
+
const tails = new Map;
|
|
24
|
+
const shown = new Map;
|
|
25
|
+
const listeners = new Set;
|
|
26
|
+
const changed = () => {
|
|
27
|
+
for (const listener of listeners)
|
|
28
|
+
listener();
|
|
29
|
+
};
|
|
30
|
+
const post = async (current) => {
|
|
31
|
+
const { id, session, head, content, options } = current.entry;
|
|
32
|
+
for (;; ) {
|
|
33
|
+
try {
|
|
34
|
+
return await rows.call("head.send", {
|
|
35
|
+
session,
|
|
36
|
+
head,
|
|
37
|
+
content,
|
|
38
|
+
options: { ...options, id }
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
const closing = rows.link.signal.aborted;
|
|
42
|
+
if (closing || !(error instanceof SdkError && (error.code === "unavailable" || error.code === "stale"))) {
|
|
43
|
+
if (!closing)
|
|
44
|
+
await journal.remove(id);
|
|
45
|
+
held.delete(id);
|
|
46
|
+
changed();
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
current.attempts += 1;
|
|
50
|
+
const delay = retryDelay2(current.attempts);
|
|
51
|
+
dev("sdk", "send retrying", { receipt: id, attempts: current.attempts, delay });
|
|
52
|
+
current.retrying = { at: Date.now() + delay, reason: error.message };
|
|
53
|
+
changed();
|
|
54
|
+
await backoff2(rows.link, delay, rows.link.signal);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const retarget = async (current, message) => {
|
|
59
|
+
const target = current.entry.options.replace ?? current.entry.id;
|
|
60
|
+
if (message === target)
|
|
61
|
+
return;
|
|
62
|
+
const all = [...held.values()];
|
|
63
|
+
const later = all.slice(all.findIndex((row) => row === current) + 1).filter(({ entry }) => entry.session === current.entry.session && entry.head === current.entry.head && entry.options.replace === target);
|
|
64
|
+
for (const row of later)
|
|
65
|
+
row.entry = { ...row.entry, options: { ...row.entry.options, replace: message } };
|
|
66
|
+
await Promise.all(later.map((row) => journal.put(row.entry)));
|
|
67
|
+
};
|
|
68
|
+
const hold = (entry) => {
|
|
69
|
+
const current = {
|
|
70
|
+
entry,
|
|
71
|
+
attempts: 0,
|
|
72
|
+
retrying: null,
|
|
73
|
+
answered: null,
|
|
74
|
+
answeredAfter: null
|
|
75
|
+
};
|
|
76
|
+
const key = JSON.stringify([entry.session, entry.head]);
|
|
77
|
+
const sent = (tails.get(key) ?? Promise.resolve()).then(async () => {
|
|
78
|
+
const answer = await post(current);
|
|
79
|
+
current.answered = answer.message;
|
|
80
|
+
current.answeredAfter = shown.get(key) ?? null;
|
|
81
|
+
await retarget(current, answer.message);
|
|
82
|
+
dev("sdk", "send answered", { receipt: entry.id, attempts: current.attempts + 1 });
|
|
83
|
+
changed();
|
|
84
|
+
return answer;
|
|
85
|
+
});
|
|
86
|
+
const tail = sent.then(() => {
|
|
87
|
+
return;
|
|
88
|
+
}, () => {
|
|
89
|
+
return;
|
|
90
|
+
});
|
|
91
|
+
tails.set(key, tail);
|
|
92
|
+
tail.then(() => {
|
|
93
|
+
if (tails.get(key) === tail)
|
|
94
|
+
tails.delete(key);
|
|
95
|
+
});
|
|
96
|
+
held.set(entry.id, current);
|
|
97
|
+
changed();
|
|
98
|
+
return sent;
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
async send(entry) {
|
|
102
|
+
await journal.put(entry);
|
|
103
|
+
return hold(entry);
|
|
104
|
+
},
|
|
105
|
+
replay(entries) {
|
|
106
|
+
for (const entry of entries)
|
|
107
|
+
hold(entry).catch((error) => dev("sdk", "replay failed", {
|
|
108
|
+
receipt: entry.id,
|
|
109
|
+
code: error instanceof SdkError ? error.code : "internal"
|
|
110
|
+
}));
|
|
111
|
+
},
|
|
112
|
+
unsent(session, head) {
|
|
113
|
+
const shown = new Map;
|
|
114
|
+
const slots = new Map;
|
|
115
|
+
for (const current of held.values()) {
|
|
116
|
+
if (current.entry.session !== session || current.entry.head !== head)
|
|
117
|
+
continue;
|
|
118
|
+
const target = current.entry.options.replace ?? asId(current.entry.id);
|
|
119
|
+
const slot = slots.get(target) ?? target;
|
|
120
|
+
shown.set(slot, current);
|
|
121
|
+
if (current.answered !== null && current.answered !== target)
|
|
122
|
+
slots.set(current.answered, slot);
|
|
123
|
+
}
|
|
124
|
+
return [...shown].map(([id, current]) => unsentMessage(id, current));
|
|
125
|
+
},
|
|
126
|
+
landed(session, head, view) {
|
|
127
|
+
const key = JSON.stringify([session, head]);
|
|
128
|
+
shown.set(key, Math.max(shown.get(key) ?? 0, view.seq));
|
|
129
|
+
if (held.size === 0)
|
|
130
|
+
return;
|
|
131
|
+
const ids = new Set(view.messages.map((message) => message.id));
|
|
132
|
+
if (view.leadingPrompt !== null)
|
|
133
|
+
ids.add(view.leadingPrompt.id);
|
|
134
|
+
for (const [receipt, current] of held) {
|
|
135
|
+
const { answered, answeredAfter, entry } = current;
|
|
136
|
+
if (answered === null || entry.session !== session || entry.head !== head || !ids.has(answered) && answeredAfter !== null && view.seq <= answeredAfter)
|
|
137
|
+
continue;
|
|
138
|
+
held.delete(receipt);
|
|
139
|
+
journal.remove(current.entry.id).catch(() => dev("sdk", "journal remove failed", { receipt }));
|
|
140
|
+
dev("sdk", "send landed", { receipt });
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
subscribe(listener) {
|
|
144
|
+
listeners.add(listener);
|
|
145
|
+
return () => {
|
|
146
|
+
listeners.delete(listener);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function unsentMessage(id, { entry, attempts, retrying }) {
|
|
152
|
+
return {
|
|
153
|
+
id,
|
|
154
|
+
turn: asId(`pending:${id}`),
|
|
155
|
+
at: entry.at,
|
|
156
|
+
kind: "user",
|
|
157
|
+
content: entry.content,
|
|
158
|
+
source: entry.options.source ?? { kind: "user" },
|
|
159
|
+
delivery: entry.options.delivery ?? "steer",
|
|
160
|
+
status: { kind: "unsent", attempts, retrying },
|
|
161
|
+
siblings: { index: 0, count: 1, ids: [] }
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export { createSendJournal2, journalLoop2 };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/login.ts
|
|
2
|
+
import { SdkError } from "@nyte-ai/schema";
|
|
3
|
+
import { closable } from "@nyte-ai/core";
|
|
4
|
+
function loginHandle2(rows, begin, known) {
|
|
5
|
+
let started = null;
|
|
6
|
+
return {
|
|
7
|
+
steps: () => closable(() => {
|
|
8
|
+
let steps = null;
|
|
9
|
+
let closed = false;
|
|
10
|
+
return {
|
|
11
|
+
async pull() {
|
|
12
|
+
if (steps === null) {
|
|
13
|
+
const provider = await (started ??= begin());
|
|
14
|
+
if (closed)
|
|
15
|
+
return { done: true, value: undefined };
|
|
16
|
+
steps = rows.frames("login.steps", { provider })[Symbol.asyncIterator]();
|
|
17
|
+
}
|
|
18
|
+
return steps.next();
|
|
19
|
+
},
|
|
20
|
+
close() {
|
|
21
|
+
closed = true;
|
|
22
|
+
steps?.return?.();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}),
|
|
26
|
+
async answer(code) {
|
|
27
|
+
const provider = started === null ? known : await started;
|
|
28
|
+
if (provider === null)
|
|
29
|
+
throw new SdkError("invalid", "Read the login's steps before answering.");
|
|
30
|
+
await rows.call("login.answer", { provider, code });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { loginHandle2 };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/paint-spans.ts
|
|
2
|
+
import { followedTrace, startSpan, tracing } from "@nyte-ai/core";
|
|
3
|
+
import { mapped } from "@nyte-ai/protocol";
|
|
4
|
+
function tracePaints2(views, session, painted) {
|
|
5
|
+
if (!tracing.enabled)
|
|
6
|
+
return views;
|
|
7
|
+
return {
|
|
8
|
+
[Symbol.asyncIterator]() {
|
|
9
|
+
let shown = null;
|
|
10
|
+
return mapped(views, (view) => {
|
|
11
|
+
if (view.messages === shown)
|
|
12
|
+
return view;
|
|
13
|
+
const known = shown === null ? null : new Set(shown.map((message) => message.id));
|
|
14
|
+
const followed = followedTrace(session);
|
|
15
|
+
for (const message of view.messages) {
|
|
16
|
+
if (known === null ? message.id !== followed : known.has(message.id))
|
|
17
|
+
continue;
|
|
18
|
+
const user = message.kind === "user";
|
|
19
|
+
const ended = startSpan("client.paint", user ? message.id : followed, {
|
|
20
|
+
session,
|
|
21
|
+
kind: user ? "user" : message.partKind
|
|
22
|
+
});
|
|
23
|
+
painted().then(() => ended());
|
|
24
|
+
}
|
|
25
|
+
shown = view.messages;
|
|
26
|
+
return view;
|
|
27
|
+
})[Symbol.asyncIterator]();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { tracePaints2 };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pushed2
|
|
3
|
+
} from "./capability-ctnsbfx9.js";
|
|
4
|
+
|
|
5
|
+
// src/history.ts
|
|
6
|
+
function pagedViews2(head, options) {
|
|
7
|
+
let pages = [];
|
|
8
|
+
let turns = [];
|
|
9
|
+
let leadingPrompt = null;
|
|
10
|
+
let latest = null;
|
|
11
|
+
let shown = null;
|
|
12
|
+
let push = null;
|
|
13
|
+
let loading = null;
|
|
14
|
+
let exhausted = null;
|
|
15
|
+
const show = (view) => {
|
|
16
|
+
const first = view.messages[0];
|
|
17
|
+
const moved = first === undefined || first.id !== latest?.messages[0]?.id;
|
|
18
|
+
const previous = moved || latest === null || shown === null ? null : { view: latest, shown };
|
|
19
|
+
if (moved) {
|
|
20
|
+
const before = shown?.messages ?? [];
|
|
21
|
+
const kept = first === undefined ? -1 : before.findIndex((message) => message.id === first.id);
|
|
22
|
+
pages = kept < 0 ? [] : before.slice(0, kept);
|
|
23
|
+
leadingPrompt = shown?.leadingPrompt ?? null;
|
|
24
|
+
const paged = new Set(pages.map((message) => message.turn));
|
|
25
|
+
turns = (shown?.turns ?? []).filter((turn) => paged.has(turn.id));
|
|
26
|
+
}
|
|
27
|
+
if (view.leadingPrompt !== null && view.leadingPrompt.id === leadingPrompt?.id)
|
|
28
|
+
leadingPrompt = view.leadingPrompt;
|
|
29
|
+
latest = view;
|
|
30
|
+
shown = pages.length === 0 ? view : withPages(view, { pages, turns, leadingPrompt }, previous);
|
|
31
|
+
push?.(shown);
|
|
32
|
+
};
|
|
33
|
+
const load = async (limit) => {
|
|
34
|
+
const oldest = shown?.messages[0];
|
|
35
|
+
if (oldest === undefined || oldest.id === exhausted)
|
|
36
|
+
return 0;
|
|
37
|
+
const page = await head.history({ before: oldest.id, limit });
|
|
38
|
+
const current = latest;
|
|
39
|
+
if (page.messages.length === 0) {
|
|
40
|
+
exhausted = oldest.id;
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
if (current === null || shown?.messages[0]?.id !== oldest.id)
|
|
44
|
+
return 0;
|
|
45
|
+
const known = new Set(turns.map((turn) => turn.id));
|
|
46
|
+
pages = [...page.messages, ...pages];
|
|
47
|
+
turns = [...page.turns.filter((turn) => !known.has(turn.id)), ...turns];
|
|
48
|
+
leadingPrompt = page.leadingPrompt;
|
|
49
|
+
shown = withPages(current, { pages, turns, leadingPrompt }, null);
|
|
50
|
+
push?.(shown);
|
|
51
|
+
return page.messages.length;
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
[Symbol.asyncIterator]: () => pushed2((sink) => {
|
|
55
|
+
const views = head.watch(options)[Symbol.asyncIterator]();
|
|
56
|
+
push = (view) => sink.next(view);
|
|
57
|
+
(async () => {
|
|
58
|
+
try {
|
|
59
|
+
for (;; ) {
|
|
60
|
+
const next = await views.next();
|
|
61
|
+
if (next.done === true)
|
|
62
|
+
break;
|
|
63
|
+
show(next.value);
|
|
64
|
+
}
|
|
65
|
+
sink.end();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
sink.fail(error instanceof Error ? error : new Error(String(error)));
|
|
68
|
+
}
|
|
69
|
+
})();
|
|
70
|
+
return () => {
|
|
71
|
+
push = null;
|
|
72
|
+
views.return?.();
|
|
73
|
+
};
|
|
74
|
+
})[Symbol.asyncIterator](),
|
|
75
|
+
earlier(limit) {
|
|
76
|
+
loading ??= load(limit).finally(() => {
|
|
77
|
+
loading = null;
|
|
78
|
+
});
|
|
79
|
+
return loading;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function withPages(view, paged, previous) {
|
|
84
|
+
return {
|
|
85
|
+
...view,
|
|
86
|
+
messages: previous?.view.messages === view.messages ? previous.shown.messages : [...paged.pages, ...view.messages],
|
|
87
|
+
leadingPrompt: paged.leadingPrompt,
|
|
88
|
+
turns: previous?.view.turns === view.turns ? previous.shown.turns : pagedTurns(paged.turns, view.turns)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function pagedTurns(paged, own) {
|
|
92
|
+
const ids = new Set(own.map((turn) => turn.id));
|
|
93
|
+
return [...paged.filter((turn) => !ids.has(turn.id)), ...own];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { pagedViews2 };
|