@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
|
@@ -13,12 +13,16 @@ type Input<M extends keyof (typeof chat)["methods"]> = z.output<(typeof chat)["m
|
|
|
13
13
|
type Emitted<E extends keyof (typeof chat)["events"]> = z.input<(typeof chat)["events"][E]["payload"]>;
|
|
14
14
|
export declare function createChats(options: {
|
|
15
15
|
store: Store;
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* The agent's model, and what a request to it says and offers, as its looper asks for them;
|
|
18
|
+
* `voice` is the agent's own instructions, which its main loop speaks as.
|
|
19
|
+
*/
|
|
17
20
|
model: Model;
|
|
18
21
|
request(): Promise<{
|
|
19
22
|
instructions: string;
|
|
20
23
|
tools: Tool[];
|
|
21
24
|
model?: string | undefined;
|
|
25
|
+
voice?: string | undefined;
|
|
22
26
|
}>;
|
|
23
27
|
/** Whether the agent is stopped when its chats are first held. */
|
|
24
28
|
stopped: boolean;
|
|
@@ -31,8 +35,11 @@ export declare function createChats(options: {
|
|
|
31
35
|
log: Log;
|
|
32
36
|
}): {
|
|
33
37
|
/**
|
|
34
|
-
* Say a message in a chat, or in a new chat it starts.
|
|
35
|
-
*
|
|
38
|
+
* Say a message in a chat, or in a new chat it starts. A message in a chat no work follows is
|
|
39
|
+
* put to the agent's main loop. When that answers it itself, the chat stays no work's, and its
|
|
40
|
+
* next message is put to the main loop too. When it gives it to new work or to work there is,
|
|
41
|
+
* the chat's messages are that work's from then on: with no turn of it running one starts a
|
|
42
|
+
* turn, and a turn running takes it at its next model request.
|
|
36
43
|
*/
|
|
37
44
|
send({ chat, text }: Input<"send">): Promise<{
|
|
38
45
|
chat: string;
|
|
@@ -77,14 +84,14 @@ export declare function createChats(options: {
|
|
|
77
84
|
*/
|
|
78
85
|
stop: () => Promise<void>;
|
|
79
86
|
start: () => void;
|
|
80
|
-
/** Go on with
|
|
87
|
+
/** Go on with what was cut off when the agent last ran, each once: turns, and messages waiting. */
|
|
81
88
|
resume(): Promise<void>;
|
|
82
89
|
/**
|
|
83
|
-
* Close for good: its turns are cut, and none starts after. They stay marked,
|
|
84
|
-
* that opens this store next goes on with them.
|
|
90
|
+
* Close for good: its turns are cut, and none starts after. They stay marked, as do messages
|
|
91
|
+
* no work has taken, so the engine that opens this store next goes on with them.
|
|
85
92
|
*/
|
|
86
93
|
close: () => Promise<void>;
|
|
87
|
-
/** Settles when every
|
|
94
|
+
/** Settles when every piece of work's latest turn has written all it will. */
|
|
88
95
|
settled(): Promise<void>;
|
|
89
96
|
/** Streamed text of the model request running now. */
|
|
90
97
|
delta(requestId: string, text: string): void;
|
|
@@ -106,10 +106,10 @@ export function createChats(options) {
|
|
|
106
106
|
/** The chats, by id, once their entries are read. */
|
|
107
107
|
const chats = new Map();
|
|
108
108
|
let loaded;
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
const stateNow = () => ({ state:
|
|
112
|
-
/** The
|
|
109
|
+
/** Whether the agent is working, as its looper last said. */
|
|
110
|
+
let working = false;
|
|
111
|
+
const stateNow = () => ({ state: working ? "working" : "idle" });
|
|
112
|
+
/** The agent's loops: a chat is the looper's thread of the same name. */
|
|
113
113
|
const looper = forChats(createLooper({
|
|
114
114
|
store: forLooper(store),
|
|
115
115
|
model: options.model,
|
|
@@ -122,22 +122,18 @@ export function createChats(options) {
|
|
|
122
122
|
emit.message({ ...message, chat: thread });
|
|
123
123
|
},
|
|
124
124
|
delta: (thread, id, text) => emit.delta({ chat: thread, id, text }),
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// before the agent is said to be idle.
|
|
125
|
+
working(on) {
|
|
126
|
+
working = on;
|
|
127
|
+
emit.status(stateNow());
|
|
128
|
+
},
|
|
129
|
+
// A message in the chat got no answer: the chat is told why. The looper says this before
|
|
130
|
+
// it says the agent is idle.
|
|
131
|
+
failed(thread, { code, message }) {
|
|
133
132
|
const held = chats.get(thread);
|
|
134
|
-
if (
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
if (atWork.size > 0 !== was)
|
|
140
|
-
emit.status(stateNow());
|
|
133
|
+
if (!held)
|
|
134
|
+
return;
|
|
135
|
+
held.stored.problem = { code: head(code, 128), message: head(message, 2000) };
|
|
136
|
+
told(held);
|
|
141
137
|
},
|
|
142
138
|
},
|
|
143
139
|
stopped: options.stopped,
|
|
@@ -267,8 +263,11 @@ export function createChats(options) {
|
|
|
267
263
|
};
|
|
268
264
|
return {
|
|
269
265
|
/**
|
|
270
|
-
* Say a message in a chat, or in a new chat it starts.
|
|
271
|
-
*
|
|
266
|
+
* Say a message in a chat, or in a new chat it starts. A message in a chat no work follows is
|
|
267
|
+
* put to the agent's main loop. When that answers it itself, the chat stays no work's, and its
|
|
268
|
+
* next message is put to the main loop too. When it gives it to new work or to work there is,
|
|
269
|
+
* the chat's messages are that work's from then on: with no turn of it running one starts a
|
|
270
|
+
* turn, and a turn running takes it at its next model request.
|
|
272
271
|
*/
|
|
273
272
|
async send({ chat, text }) {
|
|
274
273
|
if (chat !== undefined) {
|
|
@@ -332,18 +331,18 @@ export function createChats(options) {
|
|
|
332
331
|
*/
|
|
333
332
|
stop: () => looper.stop(),
|
|
334
333
|
start: () => looper.start(),
|
|
335
|
-
/** Go on with
|
|
334
|
+
/** Go on with what was cut off when the agent last ran, each once: turns, and messages waiting. */
|
|
336
335
|
async resume() {
|
|
337
336
|
// The chats first: what a turn says moves its chat in the list.
|
|
338
337
|
await load();
|
|
339
338
|
await looper.resume();
|
|
340
339
|
},
|
|
341
340
|
/**
|
|
342
|
-
* Close for good: its turns are cut, and none starts after. They stay marked,
|
|
343
|
-
* that opens this store next goes on with them.
|
|
341
|
+
* Close for good: its turns are cut, and none starts after. They stay marked, as do messages
|
|
342
|
+
* no work has taken, so the engine that opens this store next goes on with them.
|
|
344
343
|
*/
|
|
345
344
|
close: () => looper.close(),
|
|
346
|
-
/** Settles when every
|
|
345
|
+
/** Settles when every piece of work's latest turn has written all it will. */
|
|
347
346
|
async settled() {
|
|
348
347
|
await loaded?.catch(() => undefined);
|
|
349
348
|
await looper.settled();
|
|
@@ -29,9 +29,9 @@ export function startEngine(ctx, options) {
|
|
|
29
29
|
*/
|
|
30
30
|
const request = async () => {
|
|
31
31
|
const settings = ctx.slots.settings.bound ? await ctx.slots.settings.call.get({}) : undefined;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// The agent's own instructions: who its main loop speaks as, with nothing of its skills.
|
|
33
|
+
const voice = settings ? settings.instructions : options.instructions();
|
|
34
|
+
const told = instructionsWith(voice, settings?.skills ?? []);
|
|
35
35
|
const own = settings?.skills.length ? [skillTool(ctx.slots.settings)] : [];
|
|
36
36
|
// In the order they came, each asked at once so one slow server delays only itself.
|
|
37
37
|
const exposed = await Promise.all(ctx
|
|
@@ -41,7 +41,13 @@ export function startEngine(ctx, options) {
|
|
|
41
41
|
const fitted = offered([...own, ...exposed.flatMap((one) => one.candidates)]);
|
|
42
42
|
const leftOut = [...told.leftOut, ...exposed.flatMap((one) => one.leftOut), ...fitted.leftOut];
|
|
43
43
|
report(leftOut);
|
|
44
|
-
return {
|
|
44
|
+
return {
|
|
45
|
+
instructions: told.instructions,
|
|
46
|
+
tools: fitted.tools,
|
|
47
|
+
model: await chosen(),
|
|
48
|
+
voice,
|
|
49
|
+
leftOut,
|
|
50
|
+
};
|
|
45
51
|
};
|
|
46
52
|
/** The model slot as the looper asks it: what it refuses is told with its code. */
|
|
47
53
|
const model = {
|
|
@@ -68,7 +74,7 @@ export function startEngine(ctx, options) {
|
|
|
68
74
|
* settings answer, and no tools slot is away. As the agent starts, what it is bound to may not
|
|
69
75
|
* be running yet, so this is looked at again whenever that may have changed: a slot's provider
|
|
70
76
|
* is back, a tools slot is made or gone, or one says its tools changed. A tools slot that stays
|
|
71
|
-
* away holds them back; a message in a chat starts
|
|
77
|
+
* away holds them back; a message in a chat starts a turn anyway.
|
|
72
78
|
*/
|
|
73
79
|
let wentOn = false;
|
|
74
80
|
/** Each tools slot heard for its tools changing, with how to stop hearing it. */
|
|
@@ -6,7 +6,7 @@ import { AGENT_NAME, AUTHORIZE, DYNAMIC_CLIENT, discover, GrantError, grant, ISS
|
|
|
6
6
|
const PENDING_FOR = 10 * 60_000;
|
|
7
7
|
const MAX_PENDING = 16;
|
|
8
8
|
const REFRESH_BEFORE = 5 * 60_000;
|
|
9
|
-
export const notSignedIn = () => new Refused("not_signed_in", "Not signed in to ChatGPT.
|
|
9
|
+
export const notSignedIn = () => new Refused("not_signed_in", "Not signed in to ChatGPT. Sign in to it to go on.");
|
|
10
10
|
export const notEligible = () => new Refused("ineligible", "This ChatGPT account isn't eligible to use its plan in this app. Signing in again won't change that.");
|
|
11
11
|
const unreachable = () => new Refused("unavailable", "OpenAI couldn't be reached. Try again later.");
|
|
12
12
|
const address = (url) => `${url.origin}${url.pathname}`;
|
package/dist/src/gateway.js
CHANGED
|
@@ -9,7 +9,6 @@ import { describeInterface, Refused } from "@agentorg/sdk";
|
|
|
9
9
|
import { connect } from "@agentorg/sdk/client";
|
|
10
10
|
import { WebSocketServer } from "ws";
|
|
11
11
|
import { serveSocket } from "./api.js";
|
|
12
|
-
import { callFolders } from "./folders.js";
|
|
13
12
|
import { LIVE_MAX, pipeLive } from "./live.js";
|
|
14
13
|
import { Notes } from "./notes.js";
|
|
15
14
|
import { oauthRoute } from "./oauth.js";
|
|
@@ -123,8 +122,6 @@ export async function startApp(options) {
|
|
|
123
122
|
async call(slot, method, input) {
|
|
124
123
|
if (slot === "store")
|
|
125
124
|
return notes.call(method, input);
|
|
126
|
-
if (slot === "folders")
|
|
127
|
-
return callFolders(method, input);
|
|
128
125
|
const exposed = Object.hasOwn(SLOTS, slot) ? undefined : exposedSlot(slot);
|
|
129
126
|
if (!exposed && !Object.hasOwn(SLOTS, slot))
|
|
130
127
|
throw new Refused("invalid", `The person has no slot ${slot}.`);
|
package/package.json
CHANGED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
/** The most folders one answer names. */
|
|
3
|
-
export declare const FOLDERS_MAX = 2000;
|
|
4
|
-
/**
|
|
5
|
-
* `folders@1`: the folders on the machine the app runs on, for a person choosing one. It names
|
|
6
|
-
* folders and nothing else. `list` starts at the person's home folder; `parent` is absent at the
|
|
7
|
-
* top. Refused `unknown` when there's no such folder, `invalid` for a path that isn't absolute.
|
|
8
|
-
*/
|
|
9
|
-
export declare const folders: import("@agentorg/sdk").RpcInterface<"folders", {
|
|
10
|
-
list: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
11
|
-
path: z.ZodOptional<z.ZodString>;
|
|
12
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
13
|
-
path: z.ZodString;
|
|
14
|
-
parent: z.ZodOptional<z.ZodString>;
|
|
15
|
-
folders: z.ZodArray<z.ZodObject<{
|
|
16
|
-
name: z.ZodString;
|
|
17
|
-
}, z.core.$strip>>;
|
|
18
|
-
}, z.core.$strip>>;
|
|
19
|
-
}, {}, 1>;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { defineInterface, method } from "@agentorg/sdk";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
/** The most folders one answer names. */
|
|
4
|
-
export const FOLDERS_MAX = 2000;
|
|
5
|
-
const Path = z.string().min(1).max(4096);
|
|
6
|
-
/**
|
|
7
|
-
* `folders@1`: the folders on the machine the app runs on, for a person choosing one. It names
|
|
8
|
-
* folders and nothing else. `list` starts at the person's home folder; `parent` is absent at the
|
|
9
|
-
* top. Refused `unknown` when there's no such folder, `invalid` for a path that isn't absolute.
|
|
10
|
-
*/
|
|
11
|
-
export const folders = defineInterface({
|
|
12
|
-
name: "folders",
|
|
13
|
-
major: 1,
|
|
14
|
-
kind: "rpc",
|
|
15
|
-
methods: {
|
|
16
|
-
list: method({
|
|
17
|
-
input: z.object({ path: Path.optional() }),
|
|
18
|
-
output: z.object({
|
|
19
|
-
path: Path,
|
|
20
|
-
parent: Path.optional(),
|
|
21
|
-
folders: z.array(z.object({ name: z.string().max(4096) })).max(FOLDERS_MAX),
|
|
22
|
-
}),
|
|
23
|
-
}),
|
|
24
|
-
},
|
|
25
|
-
});
|
package/dist/src/folders.d.ts
DELETED
package/dist/src/folders.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { readdir, stat } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { dirname, isAbsolute, join, normalize } from "node:path";
|
|
4
|
-
import { FOLDERS_MAX, folders } from "@agentorg/interfaces";
|
|
5
|
-
import { Refused } from "@agentorg/sdk";
|
|
6
|
-
async function isFolder(at, entry) {
|
|
7
|
-
if (entry.isDirectory())
|
|
8
|
-
return true;
|
|
9
|
-
if (!entry.isSymbolicLink())
|
|
10
|
-
return false;
|
|
11
|
-
return stat(join(at, entry.name)).then((found) => found.isDirectory(), () => false);
|
|
12
|
-
}
|
|
13
|
-
async function list(path) {
|
|
14
|
-
if (path !== undefined && !isAbsolute(path))
|
|
15
|
-
throw new Refused("invalid", "A folder's path starts at the top of the disk.");
|
|
16
|
-
const at = path === undefined ? homedir() : normalize(path);
|
|
17
|
-
const entries = await readdir(at, { withFileTypes: true }).catch((error) => {
|
|
18
|
-
if (error.code === "ENOENT" || error.code === "ENOTDIR")
|
|
19
|
-
throw new Refused("unknown", "There's no such folder.");
|
|
20
|
-
throw new Refused("invalid", "That folder can't be read.");
|
|
21
|
-
});
|
|
22
|
-
// Dot folders stay out of the list, as in a file picker; a path can still be typed.
|
|
23
|
-
const shown = entries.filter((entry) => !entry.name.startsWith("."));
|
|
24
|
-
const kept = await Promise.all(shown.map((entry) => isFolder(at, entry)));
|
|
25
|
-
const names = shown
|
|
26
|
-
.filter((_, i) => kept[i])
|
|
27
|
-
.map((entry) => entry.name)
|
|
28
|
-
.sort((a, b) => a.localeCompare(b))
|
|
29
|
-
.slice(0, FOLDERS_MAX);
|
|
30
|
-
const parent = dirname(at);
|
|
31
|
-
return {
|
|
32
|
-
path: at,
|
|
33
|
-
...(parent === at ? {} : { parent }),
|
|
34
|
-
folders: names.map((name) => ({ name })),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/** One `folders@1` call, checked as a call through the Hub would be. */
|
|
38
|
-
export function callFolders(method, input) {
|
|
39
|
-
if (method !== "list")
|
|
40
|
-
throw new Refused("invalid", `folders has no method ${method}.`);
|
|
41
|
-
const parsed = folders.methods.list.input.safeParse(input);
|
|
42
|
-
if (!parsed.success)
|
|
43
|
-
throw new Refused("invalid", `folders.list: ${parsed.error.message}`);
|
|
44
|
-
return list(parsed.data.path);
|
|
45
|
-
}
|