@ai-ecoverse/slicc-agent 3.6.0 → 3.8.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.
Files changed (92) hide show
  1. package/README.md +20 -3
  2. package/bin/agent +76 -0
  3. package/dist/agent.js +7 -14
  4. package/dist/agent.js.map +2 -2
  5. package/dist/agents.js +133 -0
  6. package/dist/agents.js.map +7 -0
  7. package/dist/client.js +3 -1
  8. package/dist/client.js.map +2 -2
  9. package/dist/cone.js +2 -16
  10. package/dist/cone.js.map +2 -2
  11. package/dist/control.js +68 -10
  12. package/dist/control.js.map +2 -2
  13. package/dist/host.js +11 -2
  14. package/dist/host.js.map +2 -2
  15. package/dist/kernel/env.js +30 -3
  16. package/dist/kernel/env.js.map +2 -2
  17. package/dist/kernel/exec.js +2 -1
  18. package/dist/kernel/exec.js.map +2 -2
  19. package/dist/kernel/groups.js +31 -0
  20. package/dist/kernel/groups.js.map +7 -0
  21. package/dist/licks/index.js +16 -1
  22. package/dist/licks/index.js.map +2 -2
  23. package/dist/licks/lick.js.map +1 -1
  24. package/dist/licks/licks.js +12 -1
  25. package/dist/licks/licks.js.map +2 -2
  26. package/dist/main.js +38 -9
  27. package/dist/main.js.map +2 -2
  28. package/dist/roles/frontmatter.js +59 -0
  29. package/dist/roles/frontmatter.js.map +7 -0
  30. package/dist/roles/roles.js +204 -0
  31. package/dist/roles/roles.js.map +7 -0
  32. package/dist/scoops/cli.js +391 -0
  33. package/dist/scoops/cli.js.map +7 -0
  34. package/dist/scoops/extension.js +330 -0
  35. package/dist/scoops/extension.js.map +7 -0
  36. package/dist/scoops/from.js +5 -0
  37. package/dist/scoops/from.js.map +7 -0
  38. package/dist/scoops/identity.js +33 -0
  39. package/dist/scoops/identity.js.map +7 -0
  40. package/dist/scoops/index.js +120 -0
  41. package/dist/scoops/index.js.map +7 -0
  42. package/dist/scoops/requests.js +136 -0
  43. package/dist/scoops/requests.js.map +7 -0
  44. package/dist/scoops/service.js +419 -0
  45. package/dist/scoops/service.js.map +7 -0
  46. package/dist/scoops/sync.js +253 -0
  47. package/dist/scoops/sync.js.map +7 -0
  48. package/dist/scoops/visible.js +15 -0
  49. package/dist/scoops/visible.js.map +7 -0
  50. package/dist/services.js.map +2 -2
  51. package/dist/spectrum/agent-port.js +137 -54
  52. package/dist/spectrum/agent-port.js.map +2 -2
  53. package/dist/spectrum/messages.js +39 -16
  54. package/dist/spectrum/messages.js.map +2 -2
  55. package/dist/types/agent.d.ts +3 -1
  56. package/dist/types/agents.d.ts +54 -0
  57. package/dist/types/client.d.ts +3 -1
  58. package/dist/types/cone.d.ts +1 -3
  59. package/dist/types/control.d.ts +7 -1
  60. package/dist/types/host.d.ts +2 -1
  61. package/dist/types/kernel/client.d.ts +4 -0
  62. package/dist/types/kernel/env.d.ts +13 -2
  63. package/dist/types/kernel/exec.d.ts +2 -2
  64. package/dist/types/kernel/groups.d.ts +7 -0
  65. package/dist/types/licks/index.d.ts +5 -0
  66. package/dist/types/licks/lick.d.ts +1 -1
  67. package/dist/types/licks/licks.d.ts +2 -1
  68. package/dist/types/main.d.ts +3 -0
  69. package/dist/types/roles/frontmatter.d.ts +7 -0
  70. package/dist/types/roles/roles.d.ts +48 -0
  71. package/dist/types/scoops/cli.d.ts +66 -0
  72. package/dist/types/scoops/extension.d.ts +79 -0
  73. package/dist/types/scoops/from.d.ts +5 -0
  74. package/dist/types/scoops/identity.d.ts +6 -0
  75. package/dist/types/scoops/index.d.ts +37 -0
  76. package/dist/types/scoops/requests.d.ts +32 -0
  77. package/dist/types/scoops/service.d.ts +119 -0
  78. package/dist/types/scoops/sync.d.ts +22 -0
  79. package/dist/types/scoops/visible.d.ts +4 -0
  80. package/dist/types/services.d.ts +30 -0
  81. package/dist/types/spectrum/agent-port.d.ts +13 -11
  82. package/dist/types/spectrum/messages.d.ts +2 -1
  83. package/dist/types/views.d.ts +12 -0
  84. package/dist/views.js +89 -0
  85. package/dist/views.js.map +7 -0
  86. package/package.json +5 -3
  87. package/packages/vfs-root/agents/delegate.md +8 -0
  88. package/packages/vfs-root/agents/oracle.md +25 -0
  89. package/packages/vfs-root/agents/reviewer.md +23 -0
  90. package/packages/vfs-root/agents/scout.md +30 -0
  91. package/packages/vfs-root/agents/worker.md +23 -0
  92. 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,79 @@
1
+ import type { Context } from '@earendil-works/chord';
2
+ import { type ConversationId, type Extension, type Submission, type ToolRegistration, type Tx } from '@earendil-works/pi-durable';
3
+ import { type ScoopRecord } from '../agents.ts';
4
+ import type { LickEvent } from '../licks/licks.ts';
5
+ import type { Role } from '../roles/roles.ts';
6
+ import { type ScoopsHost } from './service.ts';
7
+ export declare const PREVIEW = 1000;
8
+ type Lookup = () => Promise<ScoopsHost>;
9
+ export declare function scoopFacts(record: Pick<ScoopRecord, 'name' | 'folder' | 'role'>): string;
10
+ export type ReportResult = {
11
+ text: string;
12
+ failed: string | null;
13
+ path: string | null;
14
+ };
15
+ export declare function reportLick(record: ScoopRecord, id: string, report: ReportResult, route?: {
16
+ target?: string | null;
17
+ channel?: 'scoop-notify' | 'bash';
18
+ }): LickEvent;
19
+ type Noting = {
20
+ commit: (write: (tx: Tx) => Promise<{
21
+ status: 'running';
22
+ checkpoint: {
23
+ phase: 'deliver';
24
+ noted: true;
25
+ };
26
+ }>, context: Context) => Promise<unknown>;
27
+ };
28
+ export declare function noteWhenPlaced(runtime: Noting, submission: Pick<Submission, 'status'>, conversation: ConversationId, note: {
29
+ from: string | undefined;
30
+ noted: boolean | undefined;
31
+ }, context: Context): Promise<void>;
32
+ export declare const NOTE_POLL_MS = 100;
33
+ export declare function waitTask(lookup: Lookup): import("@earendil-works/pi-durable").Task<{
34
+ scoops: string[];
35
+ cone: string;
36
+ deadline: number;
37
+ }, {
38
+ phase: 'start';
39
+ } | {
40
+ phase: 'watch';
41
+ }, null, object>;
42
+ export declare function scoopTasks(lookup: Lookup): {
43
+ anchor: import("@earendil-works/pi-durable").Task<null, {
44
+ phase: 'done';
45
+ }, null, object>;
46
+ reporter: import("@earendil-works/pi-durable").Task<{
47
+ scoop: string;
48
+ prompt: string;
49
+ followUp?: boolean;
50
+ request?: string;
51
+ }, {
52
+ phase: 'deliver';
53
+ noted?: boolean;
54
+ } | {
55
+ phase: 'report';
56
+ text: string;
57
+ failed: string | null;
58
+ }, ReportResult, object>;
59
+ wait: import("@earendil-works/pi-durable").Task<{
60
+ scoops: string[];
61
+ cone: string;
62
+ deadline: number;
63
+ }, {
64
+ phase: 'start';
65
+ } | {
66
+ phase: 'watch';
67
+ }, null, object>;
68
+ };
69
+ export declare function rolesSection(roles: readonly Role[]): string;
70
+ export interface ScoopSections {
71
+ roles(): readonly Role[];
72
+ skill(): string;
73
+ }
74
+ export declare function scoopsExtension(tasks: ReturnType<typeof scoopTasks>, sections: ScoopSections): Extension;
75
+ export declare function allowed(record: Pick<ScoopRecord, 'folder'> & {
76
+ roots?: ScoopRecord['roots'];
77
+ }, coneCwd: string, path: string, writing: boolean): boolean;
78
+ export declare function guardExtension(lookup: Lookup, tools: readonly ToolRegistration[]): Extension;
79
+ export {};
@@ -0,0 +1,5 @@
1
+ export declare const FROM_KIND = "slicc.from";
2
+ export type From = {
3
+ from: string;
4
+ entry: number;
5
+ };
@@ -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,119 @@
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
+ from?: string;
16
+ };
17
+ type Wait = {
18
+ scoops: string[];
19
+ done: Record<string, string>;
20
+ cone: string;
21
+ };
22
+ export type Answer = {
23
+ code: number;
24
+ out: string;
25
+ tasks?: number[];
26
+ };
27
+ type WorkState = {
28
+ feeds: Record<string, Feed>;
29
+ waits: Record<string, Wait>;
30
+ ledger: Record<string, Answer>;
31
+ turns: Record<string, {
32
+ at: number;
33
+ count: number;
34
+ }>;
35
+ };
36
+ export declare const ScoopWorkDoc: import("@earendil-works/pi-durable").SessionDocToken<WorkState>;
37
+ export interface ScoopTasks {
38
+ anchor: AnyTask;
39
+ reporter: AnyTask;
40
+ wait: AnyTask;
41
+ }
42
+ export interface ScoopsHost {
43
+ harness: Harness;
44
+ agents: Agents;
45
+ licks: Licks;
46
+ groups?: ProcessGroups;
47
+ tools?: readonly ToolRegistration[];
48
+ }
49
+ export interface Rewound {
50
+ stopped: string[];
51
+ restored: string[];
52
+ }
53
+ export interface ScoopSummary {
54
+ id: string;
55
+ folder: string;
56
+ name: string;
57
+ role: string | null;
58
+ busy: boolean;
59
+ }
60
+ export interface Limits {
61
+ maxLiveScoops: number;
62
+ maxPerTurn: number;
63
+ }
64
+ export interface SpawnRequest {
65
+ cone: string;
66
+ kind?: 'async' | 'sync';
67
+ parent?: string;
68
+ depth?: number;
69
+ roots?: {
70
+ write: string[];
71
+ read: string[];
72
+ };
73
+ cwd?: string;
74
+ instructions?: string;
75
+ target?: string | null;
76
+ asker?: string | null;
77
+ name: string;
78
+ role?: Role;
79
+ model?: {
80
+ provider: string;
81
+ modelId: string;
82
+ };
83
+ thinking?: AgentChange['thinkingLevel'];
84
+ tools?: string[];
85
+ prompts: string[];
86
+ fromAgent: boolean;
87
+ request?: string;
88
+ limits: Limits;
89
+ }
90
+ export declare function workspace(folder: string): string;
91
+ export declare function tail(conversation: Conversation, context: Context): Promise<Mark>;
92
+ export declare function turnStart(conversation: Conversation, context: Context): Promise<number>;
93
+ export declare function coneOf(state: Readonly<AgentsState>, conversation: number): string | undefined;
94
+ export declare function findScoop(state: Readonly<AgentsState>, handle: string, cone: string | null): [string, ScoopRecord] | undefined;
95
+ export declare function askerName(state: Readonly<AgentsState>, asker: string | null): string;
96
+ export declare function createScoops(host: Promise<ScoopsHost>, tasks: () => ScoopTasks): {
97
+ detach: (made: readonly number[], target: string, context: Context) => Promise<void>;
98
+ note: (id: string, text: string, context: Context) => Promise<Answer>;
99
+ spawn: (request: SpawnRequest, context: Context) => Promise<Answer>;
100
+ feed: (id: string, prompt: string, options: {
101
+ fromAgent: boolean;
102
+ request: string;
103
+ followUp: boolean;
104
+ target: string | null;
105
+ }, context: Context) => Promise<Answer>;
106
+ stop: (id: string, fromAgent: boolean, context: Context) => Promise<Answer>;
107
+ rename: (id: string, name: string, context: Context) => Promise<Answer>;
108
+ rewound: (coneId: string, fork: Conversation, context: Context) => Promise<Rewound>;
109
+ list: (coneId: string | null, context: Context) => Promise<ScoopSummary[]>;
110
+ busy: (conversation: number, context: Context) => Promise<boolean>;
111
+ working: (ids: readonly string[], context: Context) => Promise<string[]>;
112
+ notifyWhenDone: (coneId: string, ids: string[], deadline: number, context: Context) => Promise<void>;
113
+ };
114
+ export declare function modelOf(value: string | undefined): {
115
+ provider: string;
116
+ modelId: string;
117
+ } | undefined;
118
+ export type Scoops = ReturnType<typeof createScoops>;
119
+ 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>;
@@ -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(_agentId: string, input: string | Outgoing): Promise<void>;
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(_agentId: string, messageId: string): void;
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(_agentId: string, messageId: string, state: 'confirmed' | 'dismissed'): void;
21
+ resolveLick(agentId: string, messageId: string, state: 'confirmed' | 'dismissed'): void;
22
22
  compact(): void;
23
23
  clear(): void;
24
- setModel(_agentId: string, model: string): void;
25
- setThinking(_agentId: string, level: Thinking): void;
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;
@@ -1,5 +1,5 @@
1
1
  import type { AssistantMessage, AssistantStatus, ErrorAction, Message, MessagePart, ToolCall, UserMessage } from '@ai-ecoverse/slicc-spectrum/ui';
2
- import type { ConversationView } from '@earendil-works/pi-durable';
2
+ import type { ConversationView, EntryRecord } from '@earendil-works/pi-durable';
3
3
  import type { Delivered } from '../services.ts';
4
4
  type Json = Record<string, unknown>;
5
5
  interface Block {
@@ -38,6 +38,7 @@ export declare function fromPatch(patch: string): ToolCall['diff'];
38
38
  export declare function errorPart(error: string, provider?: string): MessagePart;
39
39
  export declare function errorAction(message: string): ErrorAction;
40
40
  export declare function assistant(id: string, message: ModelMessage, status?: AssistantStatus): AssistantMessage;
41
+ export declare function origins(entries: readonly EntryRecord[]): Map<number, string>;
41
42
  export declare function toMessages(view: ConversationView | undefined, deliveries?: Readonly<Record<string, Delivered>>): Message[];
42
43
  export declare function isBusy(view: ConversationView | undefined): boolean;
43
44
  export declare function queued(view: ConversationView | undefined): UserMessage[];
@@ -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.6.0",
3
+ "version": "3.8.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",
@@ -60,7 +62,7 @@
60
62
  },
61
63
  "devDependencies": {
62
64
  "@ai-ecoverse/slicc-shared-web": "1.8.0",
63
- "@ai-ecoverse/slicc-spectrum": "1.13.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.