@ai-ecoverse/slicc-agent 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -4
- package/bin/agent +76 -0
- package/dist/agent.js +7 -14
- package/dist/agent.js.map +2 -2
- package/dist/agents.js +133 -0
- package/dist/agents.js.map +7 -0
- package/dist/client.js +3 -1
- package/dist/client.js.map +2 -2
- package/dist/cone.js +2 -16
- package/dist/cone.js.map +2 -2
- package/dist/control.js +68 -10
- package/dist/control.js.map +2 -2
- package/dist/host.js +11 -2
- package/dist/host.js.map +2 -2
- package/dist/kernel/env.js +49 -5
- package/dist/kernel/env.js.map +2 -2
- package/dist/kernel/exec.js +2 -1
- package/dist/kernel/exec.js.map +2 -2
- package/dist/kernel/groups.js +31 -0
- package/dist/kernel/groups.js.map +7 -0
- package/dist/kernel/watch.js +86 -0
- package/dist/kernel/watch.js.map +2 -2
- package/dist/licks/index.js +16 -1
- package/dist/licks/index.js.map +2 -2
- package/dist/licks/lick.js.map +1 -1
- package/dist/licks/licks.js +12 -1
- package/dist/licks/licks.js.map +2 -2
- package/dist/main.js +38 -9
- package/dist/main.js.map +2 -2
- package/dist/roles/frontmatter.js +59 -0
- package/dist/roles/frontmatter.js.map +7 -0
- package/dist/roles/roles.js +204 -0
- package/dist/roles/roles.js.map +7 -0
- package/dist/scoops/cli.js +391 -0
- package/dist/scoops/cli.js.map +7 -0
- package/dist/scoops/extension.js +301 -0
- package/dist/scoops/extension.js.map +7 -0
- package/dist/scoops/identity.js +33 -0
- package/dist/scoops/identity.js.map +7 -0
- package/dist/scoops/index.js +120 -0
- package/dist/scoops/index.js.map +7 -0
- package/dist/scoops/requests.js +136 -0
- package/dist/scoops/requests.js.map +7 -0
- package/dist/scoops/service.js +409 -0
- package/dist/scoops/service.js.map +7 -0
- package/dist/scoops/sync.js +252 -0
- package/dist/scoops/sync.js.map +7 -0
- package/dist/scoops/visible.js +15 -0
- package/dist/scoops/visible.js.map +7 -0
- package/dist/services.js.map +2 -2
- package/dist/spectrum/agent-port.js +137 -54
- package/dist/spectrum/agent-port.js.map +2 -2
- package/dist/spectrum/messages.js +19 -10
- package/dist/spectrum/messages.js.map +2 -2
- package/dist/types/agent.d.ts +3 -1
- package/dist/types/agents.d.ts +54 -0
- package/dist/types/client.d.ts +3 -1
- package/dist/types/cone.d.ts +1 -3
- package/dist/types/control.d.ts +7 -1
- package/dist/types/host.d.ts +2 -1
- package/dist/types/kernel/client.d.ts +13 -0
- package/dist/types/kernel/env.d.ts +13 -2
- package/dist/types/kernel/exec.d.ts +2 -2
- package/dist/types/kernel/groups.d.ts +7 -0
- package/dist/types/kernel/watch.d.ts +12 -1
- package/dist/types/licks/index.d.ts +5 -0
- package/dist/types/licks/lick.d.ts +1 -1
- package/dist/types/licks/licks.d.ts +2 -1
- package/dist/types/main.d.ts +3 -0
- package/dist/types/roles/frontmatter.d.ts +7 -0
- package/dist/types/roles/roles.d.ts +48 -0
- package/dist/types/scoops/cli.d.ts +66 -0
- package/dist/types/scoops/extension.d.ts +63 -0
- package/dist/types/scoops/identity.d.ts +6 -0
- package/dist/types/scoops/index.d.ts +37 -0
- package/dist/types/scoops/requests.d.ts +32 -0
- package/dist/types/scoops/service.d.ts +116 -0
- package/dist/types/scoops/sync.d.ts +22 -0
- package/dist/types/scoops/visible.d.ts +4 -0
- package/dist/types/services.d.ts +30 -0
- package/dist/types/spectrum/agent-port.d.ts +13 -11
- package/dist/types/views.d.ts +12 -0
- package/dist/views.js +89 -0
- package/dist/views.js.map +7 -0
- package/package.json +6 -4
- package/packages/vfs-root/agents/delegate.md +8 -0
- package/packages/vfs-root/agents/oracle.md +25 -0
- package/packages/vfs-root/agents/reviewer.md +23 -0
- package/packages/vfs-root/agents/scout.md +30 -0
- package/packages/vfs-root/agents/worker.md +23 -0
- package/packages/vfs-root/skills/agent/SKILL.md +72 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Context } from '@earendil-works/chord';
|
|
2
|
+
import type { Harness } from '@earendil-works/pi-durable';
|
|
3
|
+
import type { ExecutionEnv } from '@earendil-works/pi-durable/env';
|
|
4
|
+
import type { Agents } from '../agents.ts';
|
|
5
|
+
import { type Roles } from '../roles/roles.ts';
|
|
6
|
+
import type { Request, Runner } from './requests.ts';
|
|
7
|
+
import { type Answer, type Scoops } from './service.ts';
|
|
8
|
+
import { type SyncState } from './sync.ts';
|
|
9
|
+
export declare const DEFAULT_WAIT_S = 30;
|
|
10
|
+
export declare const MAX_DEPTH = 3;
|
|
11
|
+
export declare const RUN_DIR = "/var/lib/slicc/agent/scoops";
|
|
12
|
+
export declare const THINKING: Set<string>;
|
|
13
|
+
export declare const USAGE = "usage:\n agent [options] (--prompt <text> | --file <path> | -)... run a scoop, wait, print its answer\n agent --async [options] (--prompt <text> | --file <path> | -)... start a scoop, print its handle\n agent <cwd> <allowed-commands> <prompt> the same as a synchronous run, in v6's form\n agent list [--agents] | status <handle> | rename <handle> <name>\n agent send <handle> [--follow-up] (<message> | --file <path> | -)\n agent send parent <note> from a scoop: a progress note to its cone\n agent wait <handle>... [--timeout <seconds>] [--notify]\n agent stop <handle>\n\noptions:\n --name <name> --agent <role> --model <provider/model> --thinking <level> | --effort <low|medium|high|max>\n --tools <a,b> --read-only <path,path> --system-prompt <text> | --system-prompt-file <path>\n --background-after <seconds> --persist-session | --no-persist-session\n\nA synchronous run removes the scoop's folder afterwards. Its transcript is archived in\n/tmp/agent-sessions/<handle>.md, in /home/sessions/<handle>.md with --persist-session, or nowhere\nwith --no-persist-session. subagent is the same command: subagent spawn = agent --async.\n";
|
|
14
|
+
export interface CliOptions {
|
|
15
|
+
env: ExecutionEnv;
|
|
16
|
+
harness: Harness;
|
|
17
|
+
agents: Agents;
|
|
18
|
+
scoops: Scoops;
|
|
19
|
+
roles: () => Promise<Roles>;
|
|
20
|
+
alive?: (pid: number) => Promise<boolean>;
|
|
21
|
+
now?: () => number;
|
|
22
|
+
}
|
|
23
|
+
export type Deps = CliOptions & {
|
|
24
|
+
now: () => number;
|
|
25
|
+
sync: SyncState;
|
|
26
|
+
};
|
|
27
|
+
export interface Caller {
|
|
28
|
+
id: string | null;
|
|
29
|
+
cone: string;
|
|
30
|
+
fromAgent: boolean;
|
|
31
|
+
scoop: string | null;
|
|
32
|
+
depth: number;
|
|
33
|
+
}
|
|
34
|
+
export type Flags = {
|
|
35
|
+
values: Map<string, string[]>;
|
|
36
|
+
switches: Set<string>;
|
|
37
|
+
rest: string[];
|
|
38
|
+
};
|
|
39
|
+
export declare const ok: (out: string) => Answer;
|
|
40
|
+
export declare const fail: (out: string, code?: number) => Answer;
|
|
41
|
+
export declare function isAnswer(value: unknown): value is Answer;
|
|
42
|
+
export declare function flags(argv: readonly string[], withValue: readonly string[]): Flags;
|
|
43
|
+
export declare function last(parsed: Flags, flag: string): string | undefined;
|
|
44
|
+
export declare function callerOf(agents: Agents, request: Request): Caller;
|
|
45
|
+
export declare function readText(deps: Deps, value: string, request: Request, context: Context): Promise<string>;
|
|
46
|
+
export declare function prompts(deps: Deps, argv: readonly string[], request: Request, context: Context): Promise<string[]>;
|
|
47
|
+
export type Choice = {
|
|
48
|
+
model?: {
|
|
49
|
+
provider: string;
|
|
50
|
+
modelId: string;
|
|
51
|
+
};
|
|
52
|
+
thinking?: string;
|
|
53
|
+
tools?: string[];
|
|
54
|
+
};
|
|
55
|
+
export declare function choices(parsed: Flags): Choice | Answer;
|
|
56
|
+
export declare function role(deps: Deps, parsed: Flags): Promise<{
|
|
57
|
+
roles: Roles;
|
|
58
|
+
error: Answer;
|
|
59
|
+
role?: undefined;
|
|
60
|
+
} | {
|
|
61
|
+
error?: undefined;
|
|
62
|
+
roles: Roles;
|
|
63
|
+
role: import("../roles/roles.ts").Role | undefined;
|
|
64
|
+
}>;
|
|
65
|
+
export declare function unsupported(argv: readonly string[]): Answer | undefined;
|
|
66
|
+
export declare function createCli(options: CliOptions): Runner;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type Extension, type ToolRegistration } from '@earendil-works/pi-durable';
|
|
2
|
+
import { type ScoopRecord } from '../agents.ts';
|
|
3
|
+
import type { LickEvent } from '../licks/licks.ts';
|
|
4
|
+
import type { Role } from '../roles/roles.ts';
|
|
5
|
+
import { type ScoopsHost } from './service.ts';
|
|
6
|
+
export declare const PREVIEW = 1000;
|
|
7
|
+
type Lookup = () => Promise<ScoopsHost>;
|
|
8
|
+
export declare function scoopFacts(record: Pick<ScoopRecord, 'name' | 'folder' | 'role'>): string;
|
|
9
|
+
export type ReportResult = {
|
|
10
|
+
text: string;
|
|
11
|
+
failed: string | null;
|
|
12
|
+
path: string | null;
|
|
13
|
+
};
|
|
14
|
+
export declare function reportLick(record: ScoopRecord, id: string, report: ReportResult, route?: {
|
|
15
|
+
target?: string | null;
|
|
16
|
+
channel?: 'scoop-notify' | 'bash';
|
|
17
|
+
}): LickEvent;
|
|
18
|
+
export declare function waitTask(lookup: Lookup): import("@earendil-works/pi-durable").Task<{
|
|
19
|
+
scoops: string[];
|
|
20
|
+
cone: string;
|
|
21
|
+
deadline: number;
|
|
22
|
+
}, {
|
|
23
|
+
phase: 'start';
|
|
24
|
+
} | {
|
|
25
|
+
phase: 'watch';
|
|
26
|
+
}, null, object>;
|
|
27
|
+
export declare function scoopTasks(lookup: Lookup): {
|
|
28
|
+
anchor: import("@earendil-works/pi-durable").Task<null, {
|
|
29
|
+
phase: 'done';
|
|
30
|
+
}, null, object>;
|
|
31
|
+
reporter: import("@earendil-works/pi-durable").Task<{
|
|
32
|
+
scoop: string;
|
|
33
|
+
prompt: string;
|
|
34
|
+
followUp?: boolean;
|
|
35
|
+
request?: string;
|
|
36
|
+
}, {
|
|
37
|
+
phase: 'deliver';
|
|
38
|
+
} | {
|
|
39
|
+
phase: 'report';
|
|
40
|
+
text: string;
|
|
41
|
+
failed: string | null;
|
|
42
|
+
}, ReportResult, object>;
|
|
43
|
+
wait: import("@earendil-works/pi-durable").Task<{
|
|
44
|
+
scoops: string[];
|
|
45
|
+
cone: string;
|
|
46
|
+
deadline: number;
|
|
47
|
+
}, {
|
|
48
|
+
phase: 'start';
|
|
49
|
+
} | {
|
|
50
|
+
phase: 'watch';
|
|
51
|
+
}, null, object>;
|
|
52
|
+
};
|
|
53
|
+
export declare function rolesSection(roles: readonly Role[]): string;
|
|
54
|
+
export interface ScoopSections {
|
|
55
|
+
roles(): readonly Role[];
|
|
56
|
+
skill(): string;
|
|
57
|
+
}
|
|
58
|
+
export declare function scoopsExtension(tasks: ReturnType<typeof scoopTasks>, sections: ScoopSections): Extension;
|
|
59
|
+
export declare function allowed(record: Pick<ScoopRecord, 'folder'> & {
|
|
60
|
+
roots?: ScoopRecord['roots'];
|
|
61
|
+
}, coneCwd: string, path: string, writing: boolean): boolean;
|
|
62
|
+
export declare function guardExtension(lookup: Lookup, tools: readonly ToolRegistration[]): Extension;
|
|
63
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Context } from '@earendil-works/chord';
|
|
2
|
+
import { type ModelRef } from '@earendil-works/pi-durable';
|
|
3
|
+
import type { Agents } from '../agents.ts';
|
|
4
|
+
import type { EnvTargetLike } from '../kernel/env.ts';
|
|
5
|
+
export declare function callerOf(agents: Agents | undefined, conversation: number | undefined): string | undefined;
|
|
6
|
+
export declare function identity(agents: () => Agents | undefined, fallback: ModelRef): (target: EnvTargetLike, context: Context) => Promise<Record<string, string>>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Context } from '@earendil-works/chord';
|
|
2
|
+
import type { Harness, Registry, ToolRegistration } from '@earendil-works/pi-durable';
|
|
3
|
+
import type { ExecutionEnv } from '@earendil-works/pi-durable/env';
|
|
4
|
+
import { type Agents } from '../agents.ts';
|
|
5
|
+
import type { ProcessGroups } from '../kernel/groups.ts';
|
|
6
|
+
import type { Licks } from '../licks/licks.ts';
|
|
7
|
+
import { type Roles } from '../roles/roles.ts';
|
|
8
|
+
import { type ControlPlane } from './requests.ts';
|
|
9
|
+
import { type Scoops } from './service.ts';
|
|
10
|
+
export declare const BUILTIN_ROLES: string[];
|
|
11
|
+
export declare const PNPM_HOME = "/home/.local/share/pnpm";
|
|
12
|
+
export type Assets = (path: string) => Promise<string>;
|
|
13
|
+
export declare function packageAssets(base?: URL): Assets;
|
|
14
|
+
export interface AttachOptions {
|
|
15
|
+
harness: Harness;
|
|
16
|
+
agents: Agents;
|
|
17
|
+
groups?: ProcessGroups;
|
|
18
|
+
env: ExecutionEnv;
|
|
19
|
+
home: string;
|
|
20
|
+
assets?: Assets;
|
|
21
|
+
pnpmHome?: string;
|
|
22
|
+
controlDir?: string;
|
|
23
|
+
sweepEvery?: number;
|
|
24
|
+
alive?: (pid: number) => Promise<boolean>;
|
|
25
|
+
}
|
|
26
|
+
export interface ScoopsRuntime {
|
|
27
|
+
roles(context: Context): Promise<Roles>;
|
|
28
|
+
plane: ControlPlane;
|
|
29
|
+
close(context: Context): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export interface ScoopsSetup {
|
|
32
|
+
scoops: Scoops;
|
|
33
|
+
attach(options: AttachOptions, context: Context): Promise<ScoopsRuntime>;
|
|
34
|
+
}
|
|
35
|
+
export declare const COMMANDS: string[];
|
|
36
|
+
export declare function setupScoops(registry: Registry, licks: Licks, fileTools?: readonly ToolRegistration[]): ScoopsSetup;
|
|
37
|
+
export type { Rewound, Scoops } from './service.ts';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Context } from '@earendil-works/chord';
|
|
2
|
+
import type { ExecutionEnv } from '@earendil-works/pi-durable/env';
|
|
3
|
+
import type { Answer } from './service.ts';
|
|
4
|
+
export declare const CONTROL_DIR = "/var/lib/slicc/agent/requests";
|
|
5
|
+
export declare const PROTOCOL = "slicc-agent/1";
|
|
6
|
+
export declare const STALE_MS: number;
|
|
7
|
+
export interface Request {
|
|
8
|
+
id: string;
|
|
9
|
+
as: 'agent' | 'subagent';
|
|
10
|
+
caller: string;
|
|
11
|
+
cwd: string;
|
|
12
|
+
pid: number | null;
|
|
13
|
+
argv: string[];
|
|
14
|
+
stdin: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function parseRequest(id: string, bytes: Uint8Array): Request | undefined;
|
|
17
|
+
export interface Runner {
|
|
18
|
+
run(request: Request, context: Context): Promise<Answer>;
|
|
19
|
+
blocking(request: Request): boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ControlPlane {
|
|
22
|
+
start(context: Context): Promise<void>;
|
|
23
|
+
sweep(context: Context): Promise<void>;
|
|
24
|
+
close(context: Context): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export interface PlaneOptions {
|
|
27
|
+
dir?: string;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
sweepEvery?: number;
|
|
30
|
+
mirror?: (context: Context) => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare function controlPlane(env: ExecutionEnv, runner: Runner, options?: PlaneOptions): ControlPlane;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Context } from '@earendil-works/chord';
|
|
2
|
+
import { type AgentChange, type AnyTask, type Conversation, type Harness, type ToolRegistration } from '@earendil-works/pi-durable';
|
|
3
|
+
import { type Agents, type AgentsState, type Mark, type ScoopRecord } from '../agents.ts';
|
|
4
|
+
import type { ProcessGroups } from '../kernel/groups.ts';
|
|
5
|
+
import type { Licks } from '../licks/licks.ts';
|
|
6
|
+
import type { Role } from '../roles/roles.ts';
|
|
7
|
+
export declare const SCOOPS_ROOT = "/scoops";
|
|
8
|
+
export declare const LEDGER_SIZE = 512;
|
|
9
|
+
export type Feed = {
|
|
10
|
+
scoop: string;
|
|
11
|
+
created: Mark | null;
|
|
12
|
+
report: boolean;
|
|
13
|
+
target: string | null;
|
|
14
|
+
channel: 'scoop-notify' | 'bash';
|
|
15
|
+
};
|
|
16
|
+
type Wait = {
|
|
17
|
+
scoops: string[];
|
|
18
|
+
done: Record<string, string>;
|
|
19
|
+
cone: string;
|
|
20
|
+
};
|
|
21
|
+
export type Answer = {
|
|
22
|
+
code: number;
|
|
23
|
+
out: string;
|
|
24
|
+
tasks?: number[];
|
|
25
|
+
};
|
|
26
|
+
type WorkState = {
|
|
27
|
+
feeds: Record<string, Feed>;
|
|
28
|
+
waits: Record<string, Wait>;
|
|
29
|
+
ledger: Record<string, Answer>;
|
|
30
|
+
turns: Record<string, {
|
|
31
|
+
at: number;
|
|
32
|
+
count: number;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
export declare const ScoopWorkDoc: import("@earendil-works/pi-durable").SessionDocToken<WorkState>;
|
|
36
|
+
export interface ScoopTasks {
|
|
37
|
+
anchor: AnyTask;
|
|
38
|
+
reporter: AnyTask;
|
|
39
|
+
wait: AnyTask;
|
|
40
|
+
}
|
|
41
|
+
export interface ScoopsHost {
|
|
42
|
+
harness: Harness;
|
|
43
|
+
agents: Agents;
|
|
44
|
+
licks: Licks;
|
|
45
|
+
groups?: ProcessGroups;
|
|
46
|
+
tools?: readonly ToolRegistration[];
|
|
47
|
+
}
|
|
48
|
+
export interface Rewound {
|
|
49
|
+
stopped: string[];
|
|
50
|
+
restored: string[];
|
|
51
|
+
}
|
|
52
|
+
export interface ScoopSummary {
|
|
53
|
+
id: string;
|
|
54
|
+
folder: string;
|
|
55
|
+
name: string;
|
|
56
|
+
role: string | null;
|
|
57
|
+
busy: boolean;
|
|
58
|
+
}
|
|
59
|
+
export interface Limits {
|
|
60
|
+
maxLiveScoops: number;
|
|
61
|
+
maxPerTurn: number;
|
|
62
|
+
}
|
|
63
|
+
export interface SpawnRequest {
|
|
64
|
+
cone: string;
|
|
65
|
+
kind?: 'async' | 'sync';
|
|
66
|
+
parent?: string;
|
|
67
|
+
depth?: number;
|
|
68
|
+
roots?: {
|
|
69
|
+
write: string[];
|
|
70
|
+
read: string[];
|
|
71
|
+
};
|
|
72
|
+
cwd?: string;
|
|
73
|
+
instructions?: string;
|
|
74
|
+
target?: string | null;
|
|
75
|
+
name: string;
|
|
76
|
+
role?: Role;
|
|
77
|
+
model?: {
|
|
78
|
+
provider: string;
|
|
79
|
+
modelId: string;
|
|
80
|
+
};
|
|
81
|
+
thinking?: AgentChange['thinkingLevel'];
|
|
82
|
+
tools?: string[];
|
|
83
|
+
prompts: string[];
|
|
84
|
+
fromAgent: boolean;
|
|
85
|
+
request?: string;
|
|
86
|
+
limits: Limits;
|
|
87
|
+
}
|
|
88
|
+
export declare function workspace(folder: string): string;
|
|
89
|
+
export declare function tail(conversation: Conversation, context: Context): Promise<Mark>;
|
|
90
|
+
export declare function turnStart(conversation: Conversation, context: Context): Promise<number>;
|
|
91
|
+
export declare function coneOf(state: Readonly<AgentsState>, conversation: number): string | undefined;
|
|
92
|
+
export declare function findScoop(state: Readonly<AgentsState>, handle: string, cone: string | null): [string, ScoopRecord] | undefined;
|
|
93
|
+
export declare function createScoops(host: Promise<ScoopsHost>, tasks: () => ScoopTasks): {
|
|
94
|
+
detach: (made: readonly number[], target: string, context: Context) => Promise<void>;
|
|
95
|
+
note: (id: string, text: string, context: Context) => Promise<Answer>;
|
|
96
|
+
spawn: (request: SpawnRequest, context: Context) => Promise<Answer>;
|
|
97
|
+
feed: (id: string, prompt: string, options: {
|
|
98
|
+
fromAgent: boolean;
|
|
99
|
+
request: string;
|
|
100
|
+
followUp: boolean;
|
|
101
|
+
target: string | null;
|
|
102
|
+
}, context: Context) => Promise<Answer>;
|
|
103
|
+
stop: (id: string, fromAgent: boolean, context: Context) => Promise<Answer>;
|
|
104
|
+
rename: (id: string, name: string, context: Context) => Promise<Answer>;
|
|
105
|
+
rewound: (coneId: string, fork: Conversation, context: Context) => Promise<Rewound>;
|
|
106
|
+
list: (coneId: string | null, context: Context) => Promise<ScoopSummary[]>;
|
|
107
|
+
busy: (conversation: number, context: Context) => Promise<boolean>;
|
|
108
|
+
working: (ids: readonly string[], context: Context) => Promise<string[]>;
|
|
109
|
+
notifyWhenDone: (coneId: string, ids: string[], deadline: number, context: Context) => Promise<void>;
|
|
110
|
+
};
|
|
111
|
+
export declare function modelOf(value: string | undefined): {
|
|
112
|
+
provider: string;
|
|
113
|
+
modelId: string;
|
|
114
|
+
} | undefined;
|
|
115
|
+
export type Scoops = ReturnType<typeof createScoops>;
|
|
116
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Context } from '@earendil-works/chord';
|
|
2
|
+
import type { EntryRecord } from '@earendil-works/pi-durable';
|
|
3
|
+
import type { ScoopRecord } from '../agents.ts';
|
|
4
|
+
import { type Caller, type Deps } from './cli.ts';
|
|
5
|
+
import type { Request } from './requests.ts';
|
|
6
|
+
import { type Answer } from './service.ts';
|
|
7
|
+
export declare const SESSIONS: {
|
|
8
|
+
tmp: string;
|
|
9
|
+
durable: string;
|
|
10
|
+
};
|
|
11
|
+
type Ending = 'cancel' | 'detach';
|
|
12
|
+
interface Pending {
|
|
13
|
+
end: (ending: Ending) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface SyncState {
|
|
16
|
+
pending: Map<string, Pending>;
|
|
17
|
+
}
|
|
18
|
+
export declare function transcript(record: ScoopRecord, entries: readonly EntryRecord[]): string;
|
|
19
|
+
export declare function runSync(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer>;
|
|
20
|
+
export declare function cancelSync(deps: Deps, requestId: string, _context: Context): Promise<Answer>;
|
|
21
|
+
export declare function detachSync(deps: Deps, requestId: string, _context: Context): Promise<Answer>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ConversationRecord } from '@earendil-works/pi-durable';
|
|
2
|
+
import type { Mark } from '../agents.ts';
|
|
3
|
+
export type ReadConversation = (id: number) => Promise<ConversationRecord | undefined>;
|
|
4
|
+
export declare function visible(read: ReadConversation, conversation: number, mark: Mark): Promise<boolean>;
|
package/dist/types/services.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface SendRequest {
|
|
|
5
5
|
text: string;
|
|
6
6
|
whenBusy: SendMode;
|
|
7
7
|
requestId: string | null;
|
|
8
|
+
agentId?: string | null;
|
|
8
9
|
}
|
|
9
10
|
export interface OperationError {
|
|
10
11
|
code: string;
|
|
@@ -43,6 +44,32 @@ export interface AgentControl {
|
|
|
43
44
|
webhook(name: string, delivery: WebhookRequest, context: Context): Promise<{
|
|
44
45
|
delivered: boolean;
|
|
45
46
|
}>;
|
|
47
|
+
stopAgent(agentId: string, context: Context): Promise<void>;
|
|
48
|
+
selectCone(agentId: string, context: Context): Promise<void>;
|
|
49
|
+
createCone(name: string, context: Context): Promise<Created>;
|
|
50
|
+
createScoop(parentId: string, name: string, context: Context): Promise<Created>;
|
|
51
|
+
drop(agentId: string, context: Context): Promise<Created>;
|
|
52
|
+
unqueue(agentId: string | null, submissionId: string, context: Context): Promise<{
|
|
53
|
+
outcome: 'withdrawn' | 'already_placed' | 'not_found';
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
export type Created = {
|
|
57
|
+
id: string;
|
|
58
|
+
error: null;
|
|
59
|
+
} | {
|
|
60
|
+
id: null;
|
|
61
|
+
error: string;
|
|
62
|
+
};
|
|
63
|
+
export interface AgentSummary {
|
|
64
|
+
id: string;
|
|
65
|
+
name: string;
|
|
66
|
+
kind: 'cone' | 'scoop';
|
|
67
|
+
parentId: string | null;
|
|
68
|
+
role: string | null;
|
|
69
|
+
}
|
|
70
|
+
export interface AgentsSummary {
|
|
71
|
+
active: string;
|
|
72
|
+
agents: AgentSummary[];
|
|
46
73
|
}
|
|
47
74
|
export type LickResolved = {
|
|
48
75
|
done: true;
|
|
@@ -73,12 +100,15 @@ export interface AgentSettingsChange {
|
|
|
73
100
|
modelId: string;
|
|
74
101
|
} | null;
|
|
75
102
|
thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;
|
|
103
|
+
agentId?: string | null;
|
|
76
104
|
}
|
|
77
105
|
export declare const AgentControl: import("@earendil-works/chord").Service<AgentControl>;
|
|
78
106
|
export type Delivered = 'run' | 'steer' | 'follow-up';
|
|
79
107
|
export interface AgentTranscript {
|
|
80
108
|
readonly state: ReplicatedState<ConversationView>;
|
|
81
109
|
readonly deliveries: ReplicatedState<Record<string, Delivered>>;
|
|
110
|
+
readonly agents: ReplicatedState<AgentsSummary>;
|
|
111
|
+
readonly views: ReplicatedState<Record<string, ConversationView>>;
|
|
82
112
|
}
|
|
83
113
|
export declare const AgentTranscript: import("@earendil-works/chord").Service<AgentTranscript>;
|
|
84
114
|
export interface AgentSessions {
|
|
@@ -8,24 +8,26 @@ export declare class AgentAdapter extends Emitter<AgentEvents> implements AgentP
|
|
|
8
8
|
ready(): Promise<void>;
|
|
9
9
|
list(): readonly Agent[];
|
|
10
10
|
active(): string;
|
|
11
|
-
select(): void;
|
|
12
|
-
messages(): readonly Message[];
|
|
13
|
-
send(
|
|
11
|
+
select(id: string): void;
|
|
12
|
+
messages(agentId?: string): readonly Message[];
|
|
13
|
+
send(agentId: string, input: string | Outgoing): Promise<void>;
|
|
14
14
|
rewind(_agentId: string, messageId: string): Promise<Outgoing | null>;
|
|
15
|
-
stop(): void;
|
|
16
|
-
busy(): boolean;
|
|
17
|
-
queue(): readonly UserMessage[];
|
|
18
|
-
unqueue(
|
|
15
|
+
stop(agentId?: string): void;
|
|
16
|
+
busy(agentId?: string): boolean;
|
|
17
|
+
queue(agentId?: string): readonly UserMessage[];
|
|
18
|
+
unqueue(agentId: string, messageId: string): void;
|
|
19
19
|
suggestion(): string | null;
|
|
20
20
|
answer(): void;
|
|
21
|
-
resolveLick(
|
|
21
|
+
resolveLick(agentId: string, messageId: string, state: 'confirmed' | 'dismissed'): void;
|
|
22
22
|
compact(): void;
|
|
23
23
|
clear(): void;
|
|
24
|
-
setModel(
|
|
25
|
-
setThinking(
|
|
24
|
+
setModel(agentId: string, model: string): void;
|
|
25
|
+
setThinking(agentId: string, level: Thinking): void;
|
|
26
26
|
older(): Promise<readonly Message[]>;
|
|
27
27
|
commands(): readonly SlashCommand[];
|
|
28
|
-
createScoop(): Agent;
|
|
28
|
+
createScoop(parentId: string, name: string): Agent;
|
|
29
|
+
drop(agentId: string): Promise<void>;
|
|
30
|
+
createCone(name: string): Promise<Agent>;
|
|
29
31
|
frozen(): readonly FrozenCone[];
|
|
30
32
|
freeze(): void;
|
|
31
33
|
thaw(): Agent | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Context } from '@earendil-works/chord';
|
|
2
|
+
import type { ConversationView } from '@earendil-works/pi-durable';
|
|
3
|
+
import type { Agent } from './agent.ts';
|
|
4
|
+
import { type AgentsState } from './agents.ts';
|
|
5
|
+
import type { AgentsSummary } from './services.ts';
|
|
6
|
+
export declare function summarize(state: Readonly<AgentsState>): AgentsSummary;
|
|
7
|
+
export declare function agentViews(agent: Agent, context: Context): Promise<{
|
|
8
|
+
agents: import("@earendil-works/chord").MutableReplicatedState<AgentsSummary>;
|
|
9
|
+
views: import("@earendil-works/chord").MutableReplicatedState<Record<string, ConversationView>>;
|
|
10
|
+
sync: () => Promise<unknown>;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}>;
|
package/dist/views.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { replicatedState } from "@earendil-works/chord";
|
|
2
|
+
import { live } from "./agents.js";
|
|
3
|
+
function summarize(state) {
|
|
4
|
+
const cones = Object.entries(state.cones).map(([id, cone]) => ({
|
|
5
|
+
id,
|
|
6
|
+
name: cone.name,
|
|
7
|
+
kind: "cone",
|
|
8
|
+
parentId: null,
|
|
9
|
+
role: null
|
|
10
|
+
}));
|
|
11
|
+
const scoops = Object.entries(state.scoops).filter(([, scoop]) => live(scoop)).map(([id, scoop]) => ({
|
|
12
|
+
id,
|
|
13
|
+
name: scoop.name,
|
|
14
|
+
kind: "scoop",
|
|
15
|
+
parentId: scoop.parent ?? scoop.cone,
|
|
16
|
+
role: scoop.role
|
|
17
|
+
}));
|
|
18
|
+
return { active: state.active, agents: [...cones, ...scoops] };
|
|
19
|
+
}
|
|
20
|
+
function wanted(state) {
|
|
21
|
+
const out = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const [id, cone] of Object.entries(state.cones)) out.set(id, cone.conversation);
|
|
23
|
+
for (const [id, scoop] of Object.entries(state.scoops))
|
|
24
|
+
if (live(scoop)) out.set(id, scoop.conversation);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
async function agentViews(agent, context) {
|
|
28
|
+
const agents = replicatedState(summarize(agent.agents.state()));
|
|
29
|
+
const views = replicatedState({});
|
|
30
|
+
const mounted = /* @__PURE__ */ new Map();
|
|
31
|
+
let lock = Promise.resolve();
|
|
32
|
+
const sync = () => {
|
|
33
|
+
lock = lock.then(async () => {
|
|
34
|
+
const state = agent.agents.state();
|
|
35
|
+
agents.replace(context, summarize(state));
|
|
36
|
+
const target = wanted(state);
|
|
37
|
+
for (const [id, entry] of [...mounted]) {
|
|
38
|
+
if (target.get(id) === entry.conversation) continue;
|
|
39
|
+
entry.off();
|
|
40
|
+
entry.attached.dispose();
|
|
41
|
+
mounted.delete(id);
|
|
42
|
+
if (!target.has(id))
|
|
43
|
+
views.change(context, (draft) => {
|
|
44
|
+
delete draft[id];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
for (const [id, conversation] of target) {
|
|
48
|
+
if (mounted.has(id)) continue;
|
|
49
|
+
const handle = await agent.agents.conversation(id, context);
|
|
50
|
+
if (!handle) continue;
|
|
51
|
+
const attached = await handle.viewState(context);
|
|
52
|
+
const put = (value) => views.change(context, (draft) => {
|
|
53
|
+
draft[id] = value;
|
|
54
|
+
});
|
|
55
|
+
put(attached.value);
|
|
56
|
+
mounted.set(id, {
|
|
57
|
+
conversation,
|
|
58
|
+
attached,
|
|
59
|
+
off: attached.subscribe((value) => put(value))
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}).catch(() => void 0);
|
|
63
|
+
return lock;
|
|
64
|
+
};
|
|
65
|
+
await sync();
|
|
66
|
+
const offChange = agent.agents.onChange(() => void sync());
|
|
67
|
+
const offCone = agent.agents.onCone(async () => {
|
|
68
|
+
await sync();
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
agents,
|
|
72
|
+
views,
|
|
73
|
+
sync,
|
|
74
|
+
dispose() {
|
|
75
|
+
offChange();
|
|
76
|
+
offCone();
|
|
77
|
+
for (const entry of mounted.values()) {
|
|
78
|
+
entry.off();
|
|
79
|
+
entry.attached.dispose();
|
|
80
|
+
}
|
|
81
|
+
mounted.clear();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
agentViews,
|
|
87
|
+
summarize
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=views.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/views.ts"],
|
|
4
|
+
"sourcesContent": ["import { type AttachedReplicatedState, type Context, replicatedState } from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { Agent } from './agent.ts';\nimport { type AgentsState, live } from './agents.ts';\nimport type { AgentsSummary } from './services.ts';\n\nexport function summarize(state: Readonly<AgentsState>): AgentsSummary {\n const cones = Object.entries(state.cones).map(([id, cone]) => ({\n id,\n name: cone.name,\n kind: 'cone' as const,\n parentId: null,\n role: null,\n }));\n const scoops = Object.entries(state.scoops)\n .filter(([, scoop]) => live(scoop))\n .map(([id, scoop]) => ({\n id,\n name: scoop.name,\n kind: 'scoop' as const,\n parentId: scoop.parent ?? scoop.cone,\n role: scoop.role,\n }));\n return { active: state.active, agents: [...cones, ...scoops] };\n}\n\nfunction wanted(state: Readonly<AgentsState>): Map<string, number> {\n const out = new Map<string, number>();\n for (const [id, cone] of Object.entries(state.cones)) out.set(id, cone.conversation);\n for (const [id, scoop] of Object.entries(state.scoops))\n if (live(scoop)) out.set(id, scoop.conversation);\n return out;\n}\n\ninterface Mounted {\n conversation: number;\n attached: AttachedReplicatedState<ConversationView>;\n off: () => void;\n}\n\nexport async function agentViews(agent: Agent, context: Context) {\n const agents = replicatedState<AgentsSummary>(summarize(agent.agents.state()));\n const views = replicatedState<Record<string, ConversationView>>({});\n const mounted = new Map<string, Mounted>();\n let lock: Promise<unknown> = Promise.resolve();\n const sync = () => {\n lock = lock\n .then(async () => {\n const state = agent.agents.state();\n agents.replace(context, summarize(state));\n const target = wanted(state);\n for (const [id, entry] of [...mounted]) {\n if (target.get(id) === entry.conversation) continue;\n entry.off();\n entry.attached.dispose();\n mounted.delete(id);\n if (!target.has(id))\n views.change(context, (draft) => {\n delete draft[id];\n });\n }\n for (const [id, conversation] of target) {\n if (mounted.has(id)) continue;\n const handle = await agent.agents.conversation(id, context);\n if (!handle) continue;\n const attached = await handle.viewState(context);\n const put = (value: ConversationView) =>\n views.change(context, (draft) => {\n (draft as Record<string, unknown>)[id] = value;\n });\n put(attached.value);\n mounted.set(id, {\n conversation,\n attached,\n off: attached.subscribe((value) => put(value)),\n });\n }\n })\n .catch(() => undefined);\n return lock;\n };\n await sync();\n const offChange = agent.agents.onChange(() => void sync());\n const offCone = agent.agents.onCone(async () => {\n await sync();\n });\n return {\n agents,\n views,\n sync,\n dispose() {\n offChange();\n offCone();\n for (const entry of mounted.values()) {\n entry.off();\n entry.attached.dispose();\n }\n mounted.clear();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-agent",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -40,7 +40,9 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
|
-
"dist"
|
|
43
|
+
"dist",
|
|
44
|
+
"bin",
|
|
45
|
+
"packages/vfs-root"
|
|
44
46
|
],
|
|
45
47
|
"scripts": {
|
|
46
48
|
"prepare": "lefthook install",
|
|
@@ -59,8 +61,8 @@
|
|
|
59
61
|
"release": "semantic-release"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
|
-
"@ai-ecoverse/slicc-shared-web": "1.
|
|
63
|
-
"@ai-ecoverse/slicc-spectrum": "1.
|
|
64
|
+
"@ai-ecoverse/slicc-shared-web": "1.8.0",
|
|
65
|
+
"@ai-ecoverse/slicc-spectrum": "1.23.0",
|
|
64
66
|
"@ai-ecoverse/wasm-bash": "5.3.0-7",
|
|
65
67
|
"@ai-ecoverse/wasm-coreutils": "9.7.0-3",
|
|
66
68
|
"@biomejs/biome": "2.5.15",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: delegate
|
|
3
|
+
description: A general helper that works like the cone itself, for a self-contained piece of work
|
|
4
|
+
tools: read, write, edit, bash
|
|
5
|
+
systemPromptMode: append
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are a delegate: you work the way the cone does, on one self-contained piece of work the cone handed you. Finish it, check it, and answer with what you did, what you found, and anything the cone has to decide.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle
|
|
3
|
+
description: Thinks through a hard question or decision and advises, without changing anything
|
|
4
|
+
tools: read, bash
|
|
5
|
+
thinking: high
|
|
6
|
+
aliases: advisor
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are an oracle. You are asked when a question is hard, a decision has trade-offs, or something does not make sense. You advise; you never change files.
|
|
10
|
+
|
|
11
|
+
Read what you need to ground your answer in the actual code and data. Separate what you verified from what you infer.
|
|
12
|
+
|
|
13
|
+
Answer in this shape:
|
|
14
|
+
|
|
15
|
+
## Answer
|
|
16
|
+
The recommendation or explanation, in a few sentences.
|
|
17
|
+
|
|
18
|
+
## Why
|
|
19
|
+
The evidence and the reasoning, with file and line references where they matter.
|
|
20
|
+
|
|
21
|
+
## Alternatives
|
|
22
|
+
Other options you considered and why they lose. Write "none worth naming" if so.
|
|
23
|
+
|
|
24
|
+
## Confidence
|
|
25
|
+
High, medium or low, and what would change your mind.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: Reviews a change or a set of files for bugs, risks and clarity, without editing anything
|
|
4
|
+
tools: read, bash
|
|
5
|
+
thinking: high
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are a reviewer. Find what is wrong or risky in the code or change you are given. You do not edit files; use bash only to read, search and run checks.
|
|
9
|
+
|
|
10
|
+
Look for, in this order: correctness bugs, data loss or security risks, missing error handling, behavior that does not match the request, then clarity and simplification.
|
|
11
|
+
|
|
12
|
+
Label every finding:
|
|
13
|
+
- P0: must fix before it ships (broken behavior, data loss, security);
|
|
14
|
+
- P1: should fix now (a likely bug, a missing case);
|
|
15
|
+
- P2: worth considering (clarity, small simplifications).
|
|
16
|
+
|
|
17
|
+
Answer in this shape:
|
|
18
|
+
|
|
19
|
+
## Findings
|
|
20
|
+
One entry per finding: label, file and line, what is wrong, and a concrete fix.
|
|
21
|
+
|
|
22
|
+
## Verdict
|
|
23
|
+
Exactly one of: "Merge verdict: BLOCK", "Merge verdict: OK", "Merge verdict: OK with notes".
|