@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.
Files changed (33) hide show
  1. package/README.md +3 -3
  2. package/dist/node_modules/@agentorg/computer/dist/types/generated/schema.d.ts +3 -0
  3. package/dist/node_modules/@agentorg/computer/package.json +1 -1
  4. package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.js +3 -3
  5. package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.d.ts +1 -1
  6. package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.js +34 -30
  7. package/dist/node_modules/@agentorg/computer-connector/package.json +1 -1
  8. package/dist/node_modules/@agentorg/interfaces/dist/src/index.d.ts +0 -1
  9. package/dist/node_modules/@agentorg/interfaces/dist/src/index.js +0 -1
  10. package/dist/node_modules/@agentorg/interfaces/dist/src/manager.d.ts +1 -1
  11. package/dist/node_modules/@agentorg/interfaces/dist/src/manager.js +1 -1
  12. package/dist/node_modules/@agentorg/looper/dist/src/loop.d.ts +40 -17
  13. package/dist/node_modules/@agentorg/looper/dist/src/loop.js +142 -69
  14. package/dist/node_modules/@agentorg/looper/dist/src/looper.d.ts +62 -18
  15. package/dist/node_modules/@agentorg/looper/dist/src/looper.js +588 -108
  16. package/dist/node_modules/@agentorg/looper/dist/src/main.d.ts +90 -0
  17. package/dist/node_modules/@agentorg/looper/dist/src/main.js +205 -0
  18. package/dist/node_modules/@agentorg/looper/dist/src/record.d.ts +156 -16
  19. package/dist/node_modules/@agentorg/looper/dist/src/record.js +292 -58
  20. package/dist/node_modules/@agentorg/manager/dist/src/control.d.ts +1 -1
  21. package/dist/node_modules/@agentorg/manager/dist/src/control.js +1 -1
  22. package/dist/node_modules/@agentorg/shell/dist/app.css +290 -375
  23. package/dist/node_modules/@agentorg/shell/dist/app.js +141 -144
  24. package/dist/node_modules/assistant/dist/src/chats.d.ts +14 -7
  25. package/dist/node_modules/assistant/dist/src/chats.js +24 -25
  26. package/dist/node_modules/assistant/dist/src/engine.js +11 -5
  27. package/dist/node_modules/chatgpt/dist/src/account.js +1 -1
  28. package/dist/src/gateway.js +0 -3
  29. package/package.json +1 -1
  30. package/dist/node_modules/@agentorg/interfaces/dist/src/folders.d.ts +0 -19
  31. package/dist/node_modules/@agentorg/interfaces/dist/src/folders.js +0 -25
  32. package/dist/src/folders.d.ts +0 -2
  33. package/dist/src/folders.js +0 -45
@@ -1,7 +1,9 @@
1
1
  /**
2
- * The record a loop runs on, kept in a store: one key per message, holding the items a model reads
3
- * for it, and for a tool message the line a person sees. It is read once, then kept in memory, and
4
- * the oldest messages are deleted past a retention cap.
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
- /** For a user message said while a turn was running: it is part of that turn. */
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 the record up to the message of this number,
22
- * when a user message was said after that: the model reads it ahead of that message, which it
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
- /** Whether a user message follows the one numbered `read`: one `stored` already, when asked so. */
100
- const saidAfter = (records, read, stored = false) => records.some((record) => record.entry.role === "user" && seqOf(record.key) > read && !(stored && record.writing));
101
- export function createRecord(store, log, limits = { keep: KEEP, keepBytes: KEEP_BYTES }) {
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
- return {
146
- /**
147
- * Keep a message, under `id` or its own number, and delete the oldest past the cap. A tool
148
- * message the store refuses is still kept in memory, since its call has run. `read` is given
149
- * for what came of a model request that had read the record up to that number: when a user
150
- * message was said since, it is kept as `ahead` of it.
151
- */
152
- async append(entry, id, read) {
153
- const state = await load();
154
- const key = keyOf(++state.last);
155
- const record = {
156
- key,
157
- entry: kept({
158
- id: id ?? key.slice(MESSAGES.length),
159
- at: new Date().toISOString(),
160
- ...entry,
161
- ...(read !== undefined && saidAfter(state.records, read) ? { ahead: read } : {}),
162
- }),
163
- bytes: 0,
164
- writing: entry.role === "user",
165
- };
166
- record.bytes = size(record.entry);
167
- state.records.push(record);
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
- state.records.splice(state.records.indexOf(record), 1);
176
- state.bytes -= record.bytes;
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 (state.records.length > 1 &&
184
- (state.records.length > limits.keep || state.bytes > limits.keepBytes)) {
185
- const oldest = state.records.shift();
186
- state.bytes -= oldest.bytes;
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
- return record.entry;
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
- /** Whether nothing is kept. */
195
- async empty() {
196
- return (await load()).records.length === 0;
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 the user message that starts a turn
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 number
224
- * up to which every user message was read, for `append` and `saidAfter`: one still being
225
- * written is not read yet.
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 { records, last } = await load();
229
- const unwritten = records.find((record) => record.writing);
230
- const read = unwritten ? seqOf(unwritten.key) - 1 : last;
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 numbered up to `read`. */
473
+ /** Put the late messages placed up to `read`. */
240
474
  const putLate = (read) => {
241
- while (late[0] && seqOf(late[0].key) <= read)
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 one numbered `read`, which `input` gave. */
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()).records, read, true);
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 on their Agents page, and every change you make through these tools, and can undo any of it.\n" | undefined;
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 on their Agents page, and every change you make through these tools, and can undo any of it.
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. */