@agentorg/cli 0.0.7 → 0.0.9
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 +3 -3
- package/dist/node_modules/@agentorg/computer/dist/types/generated/schema.d.ts +3 -0
- package/dist/node_modules/@agentorg/computer/package.json +1 -1
- package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.js +3 -3
- package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.d.ts +1 -1
- package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.js +34 -30
- package/dist/node_modules/@agentorg/computer-connector/package.json +1 -1
- package/dist/node_modules/@agentorg/interfaces/dist/src/index.d.ts +0 -1
- package/dist/node_modules/@agentorg/interfaces/dist/src/index.js +0 -1
- package/dist/node_modules/@agentorg/interfaces/dist/src/manager.d.ts +1 -1
- package/dist/node_modules/@agentorg/interfaces/dist/src/manager.js +1 -1
- package/dist/node_modules/@agentorg/looper/dist/src/loop.d.ts +40 -17
- package/dist/node_modules/@agentorg/looper/dist/src/loop.js +142 -69
- package/dist/node_modules/@agentorg/looper/dist/src/looper.d.ts +62 -18
- package/dist/node_modules/@agentorg/looper/dist/src/looper.js +588 -108
- package/dist/node_modules/@agentorg/looper/dist/src/main.d.ts +90 -0
- package/dist/node_modules/@agentorg/looper/dist/src/main.js +205 -0
- package/dist/node_modules/@agentorg/looper/dist/src/record.d.ts +156 -16
- package/dist/node_modules/@agentorg/looper/dist/src/record.js +292 -58
- package/dist/node_modules/@agentorg/manager/dist/src/control.d.ts +1 -1
- package/dist/node_modules/@agentorg/manager/dist/src/control.js +1 -1
- package/dist/node_modules/@agentorg/shell/dist/app.css +290 -375
- package/dist/node_modules/@agentorg/shell/dist/app.js +141 -144
- package/dist/node_modules/assistant/dist/src/chats.d.ts +14 -7
- package/dist/node_modules/assistant/dist/src/chats.js +24 -25
- package/dist/node_modules/assistant/dist/src/engine.js +11 -5
- package/dist/node_modules/chatgpt/dist/src/account.js +1 -1
- package/dist/src/gateway.js +0 -3
- package/package.json +1 -1
- package/dist/node_modules/@agentorg/interfaces/dist/src/folders.d.ts +0 -19
- package/dist/node_modules/@agentorg/interfaces/dist/src/folders.js +0 -25
- package/dist/src/folders.d.ts +0 -2
- package/dist/src/folders.js +0 -45
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* for it, and for a tool message the line a person sees.
|
|
4
|
-
*
|
|
2
|
+
* What a loop runs on, kept in a store. A thread keeps its messages, one key each: the items a
|
|
3
|
+
* model reads for it, and for a tool message the line a person sees. A thread is read once, then
|
|
4
|
+
* kept in memory, and its oldest messages are deleted past a retention cap. A piece of work reads
|
|
5
|
+
* its context from the threads it follows: each message is kept once, in the thread where it is
|
|
6
|
+
* shown, and says which work it belongs to when that isn't its thread's own.
|
|
5
7
|
*/
|
|
6
8
|
import { z } from "zod";
|
|
7
9
|
import { Item } from "./types.js";
|
|
@@ -15,14 +17,32 @@ export const Entry = z.object({
|
|
|
15
17
|
items: z.array(Item),
|
|
16
18
|
/** For a tool message whose call ran: how it ended. */
|
|
17
19
|
state: z.enum(["done", "refused"]).optional(),
|
|
18
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* For a user message said while a turn was running, or while a stopped turn was still writing:
|
|
22
|
+
* it is part of that turn. Also for what the main loop said in a thread, taken with such
|
|
23
|
+
* messages or said as it stopped the turn: it stays in its place among them.
|
|
24
|
+
*/
|
|
19
25
|
joined: z.literal(true).optional(),
|
|
20
26
|
/**
|
|
21
|
-
* For what came of a model request that had read
|
|
22
|
-
*
|
|
23
|
-
* doesn't answer.
|
|
27
|
+
* For what came of a model request that had read its work up to this place, when a user message
|
|
28
|
+
* was said after that, or the main loop said it stopped the turn: the model reads it ahead of
|
|
29
|
+
* those, which it doesn't answer.
|
|
24
30
|
*/
|
|
25
31
|
ahead: z.number().optional(),
|
|
32
|
+
/** The piece of work it belongs to, when that isn't its thread's own. */
|
|
33
|
+
work: z.string().optional(),
|
|
34
|
+
/**
|
|
35
|
+
* For what the main loop said itself, which no piece of work said: the number in its thread it
|
|
36
|
+
* stands after, ahead of any said after that. For a reply that is the number it had read up to;
|
|
37
|
+
* for what it said as it stopped a piece of work, all the thread held then.
|
|
38
|
+
*/
|
|
39
|
+
main: z.number().optional(),
|
|
40
|
+
/**
|
|
41
|
+
* Its place in its work's order, once that work follows more than one thread. Without it, its
|
|
42
|
+
* place is where it stands in its thread: its number, or for what the main loop said, right
|
|
43
|
+
* after the number that names.
|
|
44
|
+
*/
|
|
45
|
+
place: z.number().optional(),
|
|
26
46
|
});
|
|
27
47
|
/** Where a record's messages are kept in its store. */
|
|
28
48
|
export const MESSAGES = "msg/";
|
|
@@ -96,9 +116,24 @@ const kept = (entry) => ({
|
|
|
96
116
|
});
|
|
97
117
|
/** Stored values read at once when what is kept is first loaded. */
|
|
98
118
|
export const READS = 16;
|
|
99
|
-
/**
|
|
100
|
-
const
|
|
101
|
-
|
|
119
|
+
/** A user message as it is kept when said. */
|
|
120
|
+
export const userEntry = (text) => ({
|
|
121
|
+
role: "user",
|
|
122
|
+
items: [{ type: "message", role: "user", content: text }],
|
|
123
|
+
});
|
|
124
|
+
/** What the main loop said, as it is kept: it stands after `after`, a number in its thread. */
|
|
125
|
+
const mainEntry = (text, after) => ({
|
|
126
|
+
role: "assistant",
|
|
127
|
+
main: after,
|
|
128
|
+
items: [{ type: "message", role: "assistant", content: text }],
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* Where a message stands in its thread: its number, but what the main loop said stands right
|
|
132
|
+
* after the number it names, ahead of a message said while it answered.
|
|
133
|
+
*/
|
|
134
|
+
const orderOf = ({ seq, entry }) => (entry.main === undefined ? seq : entry.main + 0.5);
|
|
135
|
+
/** A thread's messages in a store, by their numbers. */
|
|
136
|
+
export function createThread(store, log, limits = { keep: KEEP, keepBytes: KEEP_BYTES }) {
|
|
102
137
|
let loaded;
|
|
103
138
|
const load = () => {
|
|
104
139
|
if (loaded)
|
|
@@ -126,7 +161,7 @@ export function createRecord(store, log, limits = { keep: KEEP, keepBytes: KEEP_
|
|
|
126
161
|
log.warn("A stored message didn't read back; it is left out.", { key });
|
|
127
162
|
return;
|
|
128
163
|
}
|
|
129
|
-
const record = { key, entry: parsed.data, bytes: size(parsed.data) };
|
|
164
|
+
const record = { seq: seqOf(key), key, entry: parsed.data, bytes: size(parsed.data) };
|
|
130
165
|
records.push(record);
|
|
131
166
|
bytes += record.bytes;
|
|
132
167
|
});
|
|
@@ -142,58 +177,97 @@ export function createRecord(store, log, limits = { keep: KEEP, keepBytes: KEEP_
|
|
|
142
177
|
});
|
|
143
178
|
return attempt;
|
|
144
179
|
};
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
state.bytes += record.bytes;
|
|
180
|
+
/**
|
|
181
|
+
* Keep a message in a thread already read, at once, under `id` or its own number; `stored`
|
|
182
|
+
* settles when it is written and the oldest past the cap are deleted. A tool message the store
|
|
183
|
+
* refuses is still kept in memory, since its call has run; any other is taken out again.
|
|
184
|
+
*/
|
|
185
|
+
const push = (held, entry, id) => {
|
|
186
|
+
const seq = ++held.last;
|
|
187
|
+
const key = keyOf(seq);
|
|
188
|
+
const record = {
|
|
189
|
+
seq,
|
|
190
|
+
key,
|
|
191
|
+
entry: kept({
|
|
192
|
+
id: id ?? key.slice(MESSAGES.length),
|
|
193
|
+
at: new Date().toISOString(),
|
|
194
|
+
...entry,
|
|
195
|
+
}),
|
|
196
|
+
bytes: 0,
|
|
197
|
+
writing: entry.role === "user",
|
|
198
|
+
};
|
|
199
|
+
record.bytes = size(record.entry);
|
|
200
|
+
held.records.push(record);
|
|
201
|
+
held.bytes += record.bytes;
|
|
202
|
+
const stored = (async () => {
|
|
169
203
|
try {
|
|
170
204
|
await store.set({ key, value: record.entry });
|
|
171
205
|
record.writing = false;
|
|
172
206
|
}
|
|
173
207
|
catch (error) {
|
|
174
208
|
if (entry.role !== "tool") {
|
|
175
|
-
|
|
176
|
-
|
|
209
|
+
held.records.splice(held.records.indexOf(record), 1);
|
|
210
|
+
held.bytes -= record.bytes;
|
|
177
211
|
throw error;
|
|
178
212
|
}
|
|
179
213
|
log.error("A tool message couldn't be stored; it is kept until a restart.", {
|
|
180
214
|
error: String(error),
|
|
181
215
|
});
|
|
182
216
|
}
|
|
183
|
-
while (
|
|
184
|
-
(
|
|
185
|
-
const oldest =
|
|
186
|
-
|
|
217
|
+
while (held.records.length > 1 &&
|
|
218
|
+
(held.records.length > limits.keep || held.bytes > limits.keepBytes)) {
|
|
219
|
+
const oldest = held.records.shift();
|
|
220
|
+
held.bytes -= oldest.bytes;
|
|
187
221
|
await store.delete({ key: oldest.key }).catch((error) => log.warn("An old message couldn't be deleted.", {
|
|
188
222
|
key: oldest.key,
|
|
189
223
|
error: String(error),
|
|
190
224
|
}));
|
|
191
225
|
}
|
|
192
|
-
|
|
226
|
+
})();
|
|
227
|
+
return { record, stored };
|
|
228
|
+
};
|
|
229
|
+
return {
|
|
230
|
+
/** What it holds, read once. */
|
|
231
|
+
load,
|
|
232
|
+
push,
|
|
233
|
+
/**
|
|
234
|
+
* What was said in it, as a conversation: each message and each reply the main loop gave, in
|
|
235
|
+
* the order they were answered; and the number it holds up to.
|
|
236
|
+
*/
|
|
237
|
+
async said() {
|
|
238
|
+
const held = await load();
|
|
239
|
+
const said = held.records
|
|
240
|
+
.filter(({ entry }) => entry.role !== "tool")
|
|
241
|
+
.sort((a, b) => orderOf(a) - orderOf(b))
|
|
242
|
+
.map(({ entry }) => ({ role: entry.role, text: textOf(entry) }));
|
|
243
|
+
return { said, upTo: held.last };
|
|
193
244
|
},
|
|
194
|
-
/**
|
|
195
|
-
|
|
196
|
-
|
|
245
|
+
/**
|
|
246
|
+
* Keep, under `id`, a reply the main loop gave after it had read up to `upTo`. `late` says
|
|
247
|
+
* whether a message was said after that, which this reply doesn't answer.
|
|
248
|
+
*/
|
|
249
|
+
async answer(text, upTo, id) {
|
|
250
|
+
const held = await load();
|
|
251
|
+
const { record, stored } = push(held, mainEntry(text, upTo), id);
|
|
252
|
+
await stored;
|
|
253
|
+
const late = held.records.some(({ seq, entry }) => seq > upTo && entry.role === "user");
|
|
254
|
+
return { entry: record.entry, late };
|
|
255
|
+
},
|
|
256
|
+
/**
|
|
257
|
+
* Hold a message as `entry` from now on, in memory: `store` writes it as it then is, and
|
|
258
|
+
* `undo` puts it back as it was.
|
|
259
|
+
*/
|
|
260
|
+
change(held, record, entry) {
|
|
261
|
+
const was = { entry: record.entry, bytes: record.bytes };
|
|
262
|
+
const swap = (to) => {
|
|
263
|
+
held.bytes += to.bytes - record.bytes;
|
|
264
|
+
Object.assign(record, to);
|
|
265
|
+
};
|
|
266
|
+
swap({ entry, bytes: size(entry) });
|
|
267
|
+
return {
|
|
268
|
+
store: () => store.set({ key: record.key, value: record.entry }),
|
|
269
|
+
undo: () => swap(was),
|
|
270
|
+
};
|
|
197
271
|
},
|
|
198
272
|
/** Messages before `before`, oldest first, as many as fit `limit` and `PAGE_BUDGET`. */
|
|
199
273
|
async page(before, limit) {
|
|
@@ -215,19 +289,179 @@ export function createRecord(store, log, limits = { keep: KEEP, keepBytes: KEEP_
|
|
|
215
289
|
}
|
|
216
290
|
return { messages, more: start > 0 };
|
|
217
291
|
},
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* A piece of work's record: its messages across the threads it follows, in the order it took them.
|
|
296
|
+
* Its id is the name of its own thread, whose messages are its unless they name another work; in
|
|
297
|
+
* any other thread, the messages that name it are. A message's place is where it stands in its
|
|
298
|
+
* own thread until the work follows a second thread, and a count kept with each message after. A
|
|
299
|
+
* message waiting in a thread it follows, said before the work had the thread, names no work yet:
|
|
300
|
+
* the work takes it, in the order it was said, before it keeps anything else there.
|
|
301
|
+
*/
|
|
302
|
+
export function createRecord(options) {
|
|
303
|
+
const { id } = options;
|
|
304
|
+
const placeOf = (record) => record.entry.place ?? orderOf(record);
|
|
305
|
+
const mine = (thread, record) => record.entry.work === undefined ? thread === id : record.entry.work === id;
|
|
306
|
+
/** Every thread it follows, read: what each holds, as it changes. */
|
|
307
|
+
const load = async () => {
|
|
308
|
+
const held = new Map();
|
|
309
|
+
for (const name of options.follows())
|
|
310
|
+
held.set(name, await options.thread(name).load());
|
|
311
|
+
return held;
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* Its own messages in the threads read, in order, as they stand now. Nothing waits between
|
|
315
|
+
* this and what is decided from it.
|
|
316
|
+
*/
|
|
317
|
+
const own = (held) => {
|
|
318
|
+
const records = [...held].flatMap(([thread, { records }]) => records.flatMap((record) => (mine(thread, record) ? [{ thread, record }] : [])));
|
|
319
|
+
return records.sort((a, b) => placeOf(a.record) - placeOf(b.record));
|
|
320
|
+
};
|
|
321
|
+
/** The highest place among its messages. */
|
|
322
|
+
const topOf = (records) => {
|
|
323
|
+
const last = records.at(-1);
|
|
324
|
+
return last ? placeOf(last.record) : 0;
|
|
325
|
+
};
|
|
326
|
+
/**
|
|
327
|
+
* Take the messages waiting in `thread` as its own, after all it holds: at once in memory, and
|
|
328
|
+
* `written` settles when each is stored, or rejects with the first that isn't, which stays
|
|
329
|
+
* waiting with those after it. Like a message being written, the model is sent none of them
|
|
330
|
+
* until that has settled.
|
|
331
|
+
*/
|
|
332
|
+
const take = (held, thread, joined) => {
|
|
333
|
+
const from = held.get(thread);
|
|
334
|
+
const waiting = thread === id
|
|
335
|
+
? []
|
|
336
|
+
: from.records.filter(({ entry }) => !entry.work).sort((a, b) => orderOf(a) - orderOf(b));
|
|
337
|
+
let top = topOf(own(held));
|
|
338
|
+
// Each gets its place in the order it was said and answered: at once in memory.
|
|
339
|
+
const changes = waiting.map((record) => {
|
|
340
|
+
record.writing = true;
|
|
341
|
+
return options.thread(thread).change(from, record, {
|
|
342
|
+
...record.entry,
|
|
343
|
+
work: id,
|
|
344
|
+
place: ++top,
|
|
345
|
+
...(joined ? { joined: true } : {}),
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
// Stored one after another in that order, so what a crash or a refusal leaves taken is the
|
|
349
|
+
// start of them: the rest stay waiting, and are taken after it.
|
|
350
|
+
const written = (async () => {
|
|
351
|
+
try {
|
|
352
|
+
for (const [i, change] of changes.entries())
|
|
353
|
+
await change.store().catch((error) => {
|
|
354
|
+
for (const rest of changes.slice(i))
|
|
355
|
+
rest.undo();
|
|
356
|
+
throw error;
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
for (const record of waiting)
|
|
361
|
+
record.writing = false;
|
|
362
|
+
}
|
|
363
|
+
})();
|
|
364
|
+
return { taken: waiting.length, written };
|
|
365
|
+
};
|
|
366
|
+
/** Whether a user message of its, stored already, follows the place `read`. */
|
|
367
|
+
const saidAfter = (records, read) => records.some(({ record }) => record.entry.role === "user" && placeOf(record) > read && !record.writing);
|
|
368
|
+
/**
|
|
369
|
+
* Whether something the model reads after what a request made stands past the place `read`,
|
|
370
|
+
* which that request had read up to: a user message, or what the main loop said as it stopped
|
|
371
|
+
* the turn.
|
|
372
|
+
*/
|
|
373
|
+
const heldBack = (records, read) => records.some(({ record }) => placeOf(record) > read && (record.entry.role === "user" || record.entry.joined === true));
|
|
374
|
+
/** The thread of its newest user message: where it answers. Its own, with none. */
|
|
375
|
+
const whereOf = (records) => records.findLast(({ record }) => record.entry.role === "user")?.thread ?? id;
|
|
376
|
+
/** Keep an entry of its in `thread`, made once nothing waits there, from what the thread holds. */
|
|
377
|
+
const keep = async (thread, make, at) => {
|
|
378
|
+
const held = await load();
|
|
379
|
+
const from = held.get(thread);
|
|
380
|
+
// What waits there is taken and stored first, so this is never kept ahead of it: it joins
|
|
381
|
+
// a turn if this does, or comes of one. If the store won't take it, nothing is kept.
|
|
382
|
+
const joins = make(from).joined === true || at.read !== undefined;
|
|
383
|
+
await take(held, thread, joins).written;
|
|
384
|
+
// From here to the push nothing waits, so its place and what is ahead of it are decided
|
|
385
|
+
// with the record as it stands.
|
|
386
|
+
const records = own(held);
|
|
387
|
+
const { record, stored } = options.thread(thread).push(from, {
|
|
388
|
+
...make(from),
|
|
389
|
+
...(thread === id ? {} : { work: id }),
|
|
390
|
+
...(held.size > 1 ? { place: topOf(records) + 1 } : {}),
|
|
391
|
+
...(at.read !== undefined && heldBack(records, at.read) ? { ahead: at.read } : {}),
|
|
392
|
+
}, at.id);
|
|
393
|
+
await stored;
|
|
394
|
+
return { entry: record.entry, thread };
|
|
395
|
+
};
|
|
396
|
+
return {
|
|
397
|
+
id,
|
|
398
|
+
/**
|
|
399
|
+
* Keep a message of its in `thread`, one of those it follows, after any waiting there. `read`
|
|
400
|
+
* is given for what came of a model request that had read it up to that place: when a user
|
|
401
|
+
* message was said since, or the turn was stopped by saying so, it is kept as `ahead` of
|
|
402
|
+
* that.
|
|
403
|
+
*/
|
|
404
|
+
append: (entry, at) => keep(at.thread, () => entry, at),
|
|
405
|
+
/**
|
|
406
|
+
* Keep in `thread` what the main loop said as it stopped a turn of this work. It stands after
|
|
407
|
+
* all the thread holds, and like a message said in that turn, the work reads it after
|
|
408
|
+
* whatever the turn still writes.
|
|
409
|
+
*/
|
|
410
|
+
stopLine: (text, thread) => keep(thread, (from) => ({ ...mainEntry(text, from.last), joined: true }), {}),
|
|
411
|
+
/**
|
|
412
|
+
* Take the messages waiting in `thread`, which it has come to follow, as its own: `joined`,
|
|
413
|
+
* when a turn of its is running or a stopped one is still writing. It says how many there were to answer: in its own thread,
|
|
414
|
+
* where nothing needs taking, those said since it last did anything itself.
|
|
415
|
+
*/
|
|
416
|
+
async adopt(thread, joined) {
|
|
417
|
+
const held = await load();
|
|
418
|
+
const { taken, written } = take(held, thread, joined);
|
|
419
|
+
await written;
|
|
420
|
+
if (thread !== id)
|
|
421
|
+
return taken;
|
|
422
|
+
const records = own(held);
|
|
423
|
+
const done = records.findLastIndex(({ record: { entry } }) => entry.role !== "user" && entry.main === undefined);
|
|
424
|
+
return records.slice(done + 1).filter(({ record }) => record.entry.role === "user").length;
|
|
425
|
+
},
|
|
426
|
+
/**
|
|
427
|
+
* Whether it has had a turn that did something: it holds more than what was said to it and
|
|
428
|
+
* what the main loop said.
|
|
429
|
+
*/
|
|
430
|
+
async begun() {
|
|
431
|
+
return own(await load()).some(({ record: { entry } }) => entry.role !== "user" && entry.main === undefined);
|
|
432
|
+
},
|
|
433
|
+
/** What it last said, if anything. */
|
|
434
|
+
async last() {
|
|
435
|
+
const said = own(await load()).findLast(({ record: { entry } }) => entry.role === "assistant" && entry.main === undefined);
|
|
436
|
+
return said ? textOf(said.record.entry) : undefined;
|
|
437
|
+
},
|
|
438
|
+
/** Whether it has no message. */
|
|
439
|
+
async empty() {
|
|
440
|
+
return own(await load()).length === 0;
|
|
441
|
+
},
|
|
442
|
+
/** The thread it answers in now. */
|
|
443
|
+
async where() {
|
|
444
|
+
return whereOf(own(await load()));
|
|
445
|
+
},
|
|
446
|
+
/** Its first user message, for a title. */
|
|
447
|
+
async opening() {
|
|
448
|
+
const first = own(await load()).find(({ record }) => record.entry.role === "user");
|
|
449
|
+
return first ? textOf(first.record.entry) : "";
|
|
450
|
+
},
|
|
218
451
|
/**
|
|
219
|
-
* The conversation to send: the newest exchanges (each from
|
|
452
|
+
* The conversation to send: the newest exchanges (each from a user message that is not `joined`
|
|
220
453
|
* on) that fit the budget, and always the latest two, so "go on" after a long turn still has
|
|
221
454
|
* that turn. When those two are over the budget, their oldest function arguments and outputs
|
|
222
455
|
* are left out, each call still paired with an output. A message said during a turn comes after
|
|
223
|
-
* whatever is `ahead` of it, so the model reads it as not yet answered. `read` is the
|
|
224
|
-
*
|
|
225
|
-
*
|
|
456
|
+
* whatever is `ahead` of it, so the model reads it as not yet answered. `read` is the place up
|
|
457
|
+
* to which every user message was read, for `append` and `saidAfter`: one still being written
|
|
458
|
+
* is not read yet. `thread` is where what comes of it is kept.
|
|
226
459
|
*/
|
|
227
460
|
async input() {
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
const
|
|
461
|
+
const records = own(await load());
|
|
462
|
+
const last = topOf(records);
|
|
463
|
+
const unwritten = records.find(({ record }) => record.writing);
|
|
464
|
+
const read = unwritten ? placeOf(unwritten.record) - 1 : last;
|
|
231
465
|
const exchanges = [];
|
|
232
466
|
/** Said during a turn, and not yet put: what is ahead of them goes first. */
|
|
233
467
|
const late = [];
|
|
@@ -236,12 +470,12 @@ export function createRecord(store, log, limits = { keep: KEEP, keepBytes: KEEP_
|
|
|
236
470
|
exchanges.push([]);
|
|
237
471
|
exchanges.at(-1)?.push(...entry.items);
|
|
238
472
|
};
|
|
239
|
-
/** Put the late messages
|
|
473
|
+
/** Put the late messages placed up to `read`. */
|
|
240
474
|
const putLate = (read) => {
|
|
241
|
-
while (late[0] &&
|
|
475
|
+
while (late[0] && placeOf(late[0]) <= read)
|
|
242
476
|
put(late.shift().entry);
|
|
243
477
|
};
|
|
244
|
-
for (const record of records) {
|
|
478
|
+
for (const { record } of records) {
|
|
245
479
|
// Nothing to send: a user message still being written, or a line with no items.
|
|
246
480
|
if (record.writing || record.entry.items.length === 0)
|
|
247
481
|
continue;
|
|
@@ -268,11 +502,11 @@ export function createRecord(store, log, limits = { keep: KEEP, keepBytes: KEEP_
|
|
|
268
502
|
items[i] = { ...item, arguments: ARGUMENTS_LEFT_OUT };
|
|
269
503
|
}
|
|
270
504
|
}
|
|
271
|
-
return { items, read };
|
|
505
|
+
return { items, read, thread: whereOf(records.filter(({ record }) => !record.writing)) };
|
|
272
506
|
},
|
|
273
|
-
/** Whether a user message has been stored after the
|
|
507
|
+
/** Whether a user message of its has been stored after the place `read`, which `input` gave. */
|
|
274
508
|
async saidAfter(read) {
|
|
275
|
-
return saidAfter((await load())
|
|
509
|
+
return saidAfter(own(await load()), read);
|
|
276
510
|
},
|
|
277
511
|
};
|
|
278
512
|
}
|
|
@@ -16,7 +16,7 @@ export declare const LIMIT_MAX = 8;
|
|
|
16
16
|
export declare const DEPTH_MAX = 3;
|
|
17
17
|
/** Above this many agents in the home, none is made by an agent. They share one plan. */
|
|
18
18
|
export declare const HOME_CAP = 24;
|
|
19
|
-
export declare const skillFile: (path: string) => "---\nname: delegating\ndescription: How to hand work to agents of your own and see it through, and what else your control tools reach. Use it before creating an agent, and whenever you have work that can run apart from yours.\n---\nYour `control` connection's tools reach what the person allowed you: agents, and perhaps connections, skills and templates. A tool you don't have is one you weren't given.\n\n## Before you create an agent\n\nDo the work yourself when it is short. An agent costs model usage from the plan everyone here shares, and you have a limit on how many you can have. Use one when work can run apart from yours, or needs a shape you were not given.\n\nThere is one create tool per template you may use. Read its description and fields. Give the agent a plain name and a purpose: one sentence on what it is for, which it will be told. Fields you leave out keep the template's value.\n\n## Working with it\n\n- `agent_send` gives it a message and returns at once. It works on its own after that. Your name is on the message's first line.\n- A message with no chat named starts a new chat with it, and tells you which. Name that chat to go on in it. Start another only for work that is apart from the first.\n- `agent_chats` lists its chats and says whether it is working. A chat with a `problem` has a message that got no answer: send it another once the problem is dealt with. `agent_read` shows what was said in one. Check back when you need the result, rather than after every step.\n- Say what you want back and in what form. It knows only what you send it and its purpose.\n\n## When it is done\n\n`agent_remove` it when its work is finished, so your limit is free for the next one. `agent_stop` it to keep it for later. You can remove only agents you made, and theirs. The person sees every agent you create
|
|
19
|
+
export declare const skillFile: (path: string) => "---\nname: delegating\ndescription: How to hand work to agents of your own and see it through, and what else your control tools reach. Use it before creating an agent, and whenever you have work that can run apart from yours.\n---\nYour `control` connection's tools reach what the person allowed you: agents, and perhaps connections, skills and templates. A tool you don't have is one you weren't given.\n\n## Before you create an agent\n\nDo the work yourself when it is short. An agent costs model usage from the plan everyone here shares, and you have a limit on how many you can have. Use one when work can run apart from yours, or needs a shape you were not given.\n\nThere is one create tool per template you may use. Read its description and fields. Give the agent a plain name and a purpose: one sentence on what it is for, which it will be told. Fields you leave out keep the template's value.\n\n## Working with it\n\n- `agent_send` gives it a message and returns at once. It works on its own after that. Your name is on the message's first line.\n- A message with no chat named starts a new chat with it, and tells you which. Name that chat to go on in it. Start another only for work that is apart from the first.\n- `agent_chats` lists its chats and says whether it is working. A chat with a `problem` has a message that got no answer: send it another once the problem is dealt with. `agent_read` shows what was said in one. Check back when you need the result, rather than after every step.\n- Say what you want back and in what form. It knows only what you send it and its purpose.\n\n## When it is done\n\n`agent_remove` it when its work is finished, so your limit is free for the next one. `agent_stop` it to keep it for later. You can remove only agents you made, and theirs. The person sees every agent you create: it is listed with the person's own agents, and has a page of its own. The person also sees every change you make through these tools, and can undo any of it.\n" | undefined;
|
|
20
20
|
type Values = z.infer<typeof FieldValues>;
|
|
21
21
|
type TheUnit = z.infer<typeof Unit>;
|
|
22
22
|
type TheAgent = z.infer<typeof AgentRecord>;
|
|
@@ -58,7 +58,7 @@ There is one create tool per template you may use. Read its description and fiel
|
|
|
58
58
|
|
|
59
59
|
## When it is done
|
|
60
60
|
|
|
61
|
-
\`agent_remove\` it when its work is finished, so your limit is free for the next one. \`agent_stop\` it to keep it for later. You can remove only agents you made, and theirs. The person sees every agent you create
|
|
61
|
+
\`agent_remove\` it when its work is finished, so your limit is free for the next one. \`agent_stop\` it to keep it for later. You can remove only agents you made, and theirs. The person sees every agent you create: it is listed with the person's own agents, and has a page of its own. The person also sees every change you make through these tools, and can undo any of it.
|
|
62
62
|
`;
|
|
63
63
|
export const skillFile = (path) => (path === SKILL_FILE ? SKILL_TEXT : undefined);
|
|
64
64
|
/** The agents unit's form, with what can be chosen today. */
|