@ai-ecoverse/slicc-agent 2.0.0 → 2.2.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 (48) hide show
  1. package/README.md +39 -0
  2. package/dist/agent.js +2 -1
  3. package/dist/agent.js.map +2 -2
  4. package/dist/control.js +9 -1
  5. package/dist/control.js.map +2 -2
  6. package/dist/index.js +6 -1
  7. package/dist/index.js.map +2 -2
  8. package/dist/kernel/client.js +1 -0
  9. package/dist/kernel/client.js.map +7 -0
  10. package/dist/kernel/env.js +204 -0
  11. package/dist/kernel/env.js.map +7 -0
  12. package/dist/kernel/exec.js +115 -0
  13. package/dist/kernel/exec.js.map +7 -0
  14. package/dist/kernel/files.js +153 -0
  15. package/dist/kernel/files.js.map +7 -0
  16. package/dist/kernel/paths.js +31 -0
  17. package/dist/kernel/paths.js.map +7 -0
  18. package/dist/kernel/watch.js +71 -0
  19. package/dist/kernel/watch.js.map +7 -0
  20. package/dist/owner.js +32 -9
  21. package/dist/owner.js.map +2 -2
  22. package/dist/services.js.map +2 -2
  23. package/dist/spectrum/agent-port.js +156 -0
  24. package/dist/spectrum/agent-port.js.map +7 -0
  25. package/dist/spectrum/emitter.js +20 -0
  26. package/dist/spectrum/emitter.js.map +7 -0
  27. package/dist/spectrum/index.js +17 -0
  28. package/dist/spectrum/index.js.map +7 -0
  29. package/dist/spectrum/messages.js +161 -0
  30. package/dist/spectrum/messages.js.map +7 -0
  31. package/dist/types/agent.d.ts +1 -0
  32. package/dist/types/index.d.ts +4 -2
  33. package/dist/types/kernel/client.d.ts +39 -0
  34. package/dist/types/kernel/env.d.ts +57 -0
  35. package/dist/types/kernel/exec.d.ts +5 -0
  36. package/dist/types/kernel/files.d.ts +34 -0
  37. package/dist/types/kernel/paths.d.ts +4 -0
  38. package/dist/types/kernel/watch.d.ts +10 -0
  39. package/dist/types/owner.d.ts +6 -2
  40. package/dist/types/services.d.ts +9 -0
  41. package/dist/types/spectrum/agent-port.d.ts +32 -0
  42. package/dist/types/spectrum/emitter.d.ts +7 -0
  43. package/dist/types/spectrum/index.d.ts +7 -0
  44. package/dist/types/spectrum/messages.d.ts +37 -0
  45. package/dist/types/worker.d.ts +1 -0
  46. package/dist/worker.js +9 -0
  47. package/dist/worker.js.map +2 -2
  48. package/package.json +13 -2
@@ -0,0 +1,161 @@
1
+ function textOf(content) {
2
+ if (typeof content === "string") return content;
3
+ return (content ?? []).map((block) => block.type === "text" ? block.text ?? "" : "").join("");
4
+ }
5
+ const paths = (args) => typeof args?.path === "string" ? [args.path] : [];
6
+ function title(name, args) {
7
+ const subject = args?.command ?? args?.path;
8
+ return typeof subject === "string" ? `${name} ${subject}` : name;
9
+ }
10
+ function toolCall(block) {
11
+ return {
12
+ id: block.id ?? "",
13
+ name: block.name ?? "tool",
14
+ title: title(block.name ?? "tool", block.arguments),
15
+ input: JSON.stringify(block.arguments ?? {}),
16
+ output: "",
17
+ status: "running",
18
+ paths: paths(block.arguments)
19
+ };
20
+ }
21
+ function part(block) {
22
+ if (block.type === "text") return { type: "text", text: block.text ?? "" };
23
+ if (block.type === "thinking") return { type: "thinking", text: block.thinking ?? "" };
24
+ if (block.type === "toolCall") return { type: "tool", tool: toolCall(block) };
25
+ return void 0;
26
+ }
27
+ function usage(message) {
28
+ const used = message.usage;
29
+ if (!used) return void 0;
30
+ return {
31
+ input: used.input ?? 0,
32
+ output: used.output ?? 0,
33
+ cost: used.cost?.total ?? 0,
34
+ cacheRead: used.cacheRead ?? 0,
35
+ cacheWrite: used.cacheWrite ?? 0
36
+ };
37
+ }
38
+ const statuses = { error: "error", aborted: "stopped" };
39
+ function assistant(id, message, status) {
40
+ const blocks = Array.isArray(message.content) ? message.content : [];
41
+ const parts = blocks.map(part).filter((item) => item !== void 0);
42
+ if (message.errorMessage)
43
+ parts.push({ type: "error", message: message.errorMessage, action: "retry" });
44
+ const used = usage(message);
45
+ return {
46
+ id,
47
+ role: "assistant",
48
+ parts,
49
+ status: status ?? statuses[message.stopReason ?? ""] ?? "done",
50
+ createdAt: message.timestamp ?? 0,
51
+ ...message.provider && message.model ? { model: `${message.provider}/${message.model}` } : {},
52
+ ...used ? { usage: used } : {}
53
+ };
54
+ }
55
+ function user(id, message) {
56
+ return { id, role: "user", text: textOf(message.content), createdAt: message.timestamp ?? 0 };
57
+ }
58
+ function system(id, entry, text) {
59
+ const reason = entry.data?.reason;
60
+ return {
61
+ id,
62
+ role: "system",
63
+ kind: "compaction",
64
+ text,
65
+ createdAt: 0,
66
+ state: "summarized",
67
+ ...reason ? { trigger: reason } : {}
68
+ };
69
+ }
70
+ function tools(messages) {
71
+ const found = /* @__PURE__ */ new Map();
72
+ for (const message of messages) {
73
+ if (message.role !== "assistant") continue;
74
+ for (const item of message.parts) if (item.type === "tool") found.set(item.tool.id, item.tool);
75
+ }
76
+ return found;
77
+ }
78
+ function settle(calls, result) {
79
+ const call = calls.get(result.toolCallId ?? "");
80
+ if (!call) return;
81
+ call.output = textOf(result.content);
82
+ call.status = result.isError ? "error" : "done";
83
+ }
84
+ function entryMessage(entry, out, calls) {
85
+ const id = `e${entry.id}`;
86
+ const model = entry.model?.[0];
87
+ if (entry.kind === "pi.user" && model) out.push(user(id, model));
88
+ else if (entry.kind === "pi.assistant" && model) {
89
+ const message = assistant(id, model);
90
+ out.push(message);
91
+ for (const [key, value] of tools([message])) calls.set(key, value);
92
+ } else if (entry.kind === "pi.tool-result" && model) settle(calls, model);
93
+ else if (entry.kind === "pi.compaction") out.push(system(id, entry, textOf(model?.content)));
94
+ }
95
+ const slotStatus = {
96
+ pending: "running",
97
+ running: "running",
98
+ done: "done"
99
+ };
100
+ function live(view, out, calls) {
101
+ const state = view.docs["pi.live"];
102
+ for (const slot of state?.tools ?? []) {
103
+ const call = calls.get(slot.callId);
104
+ if (call && call.status === "running") {
105
+ call.status = slotStatus[slot.status] ?? "running";
106
+ call.output = slot.output ?? call.output;
107
+ }
108
+ }
109
+ const partial = state?.generation?.message;
110
+ if (partial) out.push(assistant("live", partial, "streaming"));
111
+ for (const compaction of state?.compactions ?? []) {
112
+ out.push({
113
+ id: `compaction-${compaction.taskId}`,
114
+ role: "system",
115
+ kind: "compaction",
116
+ text: "",
117
+ createdAt: 0,
118
+ state: "summarizing",
119
+ trigger: compaction.reason
120
+ });
121
+ }
122
+ const retry = state?.generation?.retry;
123
+ if (retry)
124
+ out.push({
125
+ id: "retry",
126
+ role: "system",
127
+ kind: "notice",
128
+ text: retry.error,
129
+ createdAt: retry.at
130
+ });
131
+ }
132
+ function toMessages(view) {
133
+ const out = [];
134
+ if (!view) return out;
135
+ const calls = /* @__PURE__ */ new Map();
136
+ for (const entry of view.entries) entryMessage(entry, out, calls);
137
+ live(view, out, calls);
138
+ return out;
139
+ }
140
+ function isBusy(view) {
141
+ return Boolean(view?.docs["pi.live"]?.run);
142
+ }
143
+ function queued(view) {
144
+ const items = view?.docs["pi.inbox"]?.items ?? [];
145
+ return items.filter((item) => item.mode !== "write").map((item) => ({
146
+ id: `q${item.id}`,
147
+ role: "user",
148
+ text: textOf(item.content),
149
+ createdAt: 0,
150
+ queued: true,
151
+ mode: item.mode === "steer" ? "steer" : "queue"
152
+ }));
153
+ }
154
+ export {
155
+ assistant,
156
+ isBusy,
157
+ queued,
158
+ textOf,
159
+ toMessages
160
+ };
161
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/spectrum/messages.ts"],
4
+ "sourcesContent": ["import type {\n AssistantMessage,\n AssistantStatus,\n Message,\n MessagePart,\n SystemMessage,\n ToolCall,\n ToolStatus,\n Usage,\n UserMessage,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport type { ConversationView, EntryRecord } from '@earendil-works/pi-durable';\n\ntype Json = Record<string, unknown>;\n\ninterface Block {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n arguments?: Json;\n}\n\ninterface ModelMessage {\n role: string;\n content?: string | Block[];\n timestamp?: number;\n stopReason?: string;\n errorMessage?: string;\n provider?: string;\n model?: string;\n usage?: {\n input?: number;\n output?: number;\n cacheRead?: number;\n cacheWrite?: number;\n cost?: { total?: number };\n };\n toolCallId?: string;\n isError?: boolean;\n}\n\ninterface Slot {\n callId: string;\n status: string;\n output?: string;\n}\n\ninterface Live {\n run?: unknown;\n generation?: { message?: ModelMessage; retry?: { at: number; error: string } };\n tools?: Slot[];\n compactions?: { taskId: number; reason: string }[];\n}\n\nexport function textOf(content: ModelMessage['content']): string {\n if (typeof content === 'string') return content;\n return (content ?? []).map((block) => (block.type === 'text' ? (block.text ?? '') : '')).join('');\n}\n\nconst paths = (args: Json | undefined): string[] =>\n typeof args?.path === 'string' ? [args.path] : [];\n\nfunction title(name: string, args: Json | undefined): string {\n const subject = args?.command ?? args?.path;\n return typeof subject === 'string' ? `${name} ${subject}` : name;\n}\n\nfunction toolCall(block: Block): ToolCall {\n return {\n id: block.id ?? '',\n name: block.name ?? 'tool',\n title: title(block.name ?? 'tool', block.arguments),\n input: JSON.stringify(block.arguments ?? {}),\n output: '',\n status: 'running',\n paths: paths(block.arguments),\n };\n}\n\nfunction part(block: Block): MessagePart | undefined {\n if (block.type === 'text') return { type: 'text', text: block.text ?? '' };\n if (block.type === 'thinking') return { type: 'thinking', text: block.thinking ?? '' };\n if (block.type === 'toolCall') return { type: 'tool', tool: toolCall(block) };\n return undefined;\n}\n\nfunction usage(message: ModelMessage): Usage | undefined {\n const used = message.usage;\n if (!used) return undefined;\n return {\n input: used.input ?? 0,\n output: used.output ?? 0,\n cost: used.cost?.total ?? 0,\n cacheRead: used.cacheRead ?? 0,\n cacheWrite: used.cacheWrite ?? 0,\n };\n}\n\nconst statuses: Record<string, AssistantStatus> = { error: 'error', aborted: 'stopped' };\n\nexport function assistant(\n id: string,\n message: ModelMessage,\n status?: AssistantStatus\n): AssistantMessage {\n const blocks = Array.isArray(message.content) ? message.content : [];\n const parts = blocks.map(part).filter((item): item is MessagePart => item !== undefined);\n if (message.errorMessage)\n parts.push({ type: 'error', message: message.errorMessage, action: 'retry' });\n const used = usage(message);\n return {\n id,\n role: 'assistant',\n parts,\n status: status ?? statuses[message.stopReason ?? ''] ?? 'done',\n createdAt: message.timestamp ?? 0,\n ...(message.provider && message.model ? { model: `${message.provider}/${message.model}` } : {}),\n ...(used ? { usage: used } : {}),\n };\n}\n\nfunction user(id: string, message: ModelMessage): UserMessage {\n return { id, role: 'user', text: textOf(message.content), createdAt: message.timestamp ?? 0 };\n}\n\nfunction system(id: string, entry: EntryRecord, text: string): SystemMessage {\n const reason = (entry.data as Json | undefined)?.reason as SystemMessage['trigger'] | undefined;\n return {\n id,\n role: 'system',\n kind: 'compaction',\n text,\n createdAt: 0,\n state: 'summarized',\n ...(reason ? { trigger: reason } : {}),\n };\n}\n\nfunction tools(messages: Message[]): Map<string, ToolCall> {\n const found = new Map<string, ToolCall>();\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const item of message.parts) if (item.type === 'tool') found.set(item.tool.id, item.tool);\n }\n return found;\n}\n\nfunction settle(calls: Map<string, ToolCall>, result: ModelMessage): void {\n const call = calls.get(result.toolCallId ?? '');\n if (!call) return;\n call.output = textOf(result.content);\n call.status = result.isError ? 'error' : 'done';\n}\n\nfunction entryMessage(entry: EntryRecord, out: Message[], calls: Map<string, ToolCall>): void {\n const id = `e${entry.id}`;\n const model = entry.model?.[0] as ModelMessage | undefined;\n if (entry.kind === 'pi.user' && model) out.push(user(id, model));\n else if (entry.kind === 'pi.assistant' && model) {\n const message = assistant(id, model);\n out.push(message);\n for (const [key, value] of tools([message])) calls.set(key, value);\n } else if (entry.kind === 'pi.tool-result' && model) settle(calls, model);\n else if (entry.kind === 'pi.compaction') out.push(system(id, entry, textOf(model?.content)));\n}\n\nconst slotStatus: Record<string, ToolStatus> = {\n pending: 'running',\n running: 'running',\n done: 'done',\n};\n\nfunction live(view: ConversationView, out: Message[], calls: Map<string, ToolCall>): void {\n const state = view.docs['pi.live'] as Live | undefined;\n for (const slot of state?.tools ?? []) {\n const call = calls.get(slot.callId);\n if (call && call.status === 'running') {\n call.status = slotStatus[slot.status] ?? 'running';\n call.output = slot.output ?? call.output;\n }\n }\n const partial = state?.generation?.message;\n if (partial) out.push(assistant('live', partial, 'streaming'));\n for (const compaction of state?.compactions ?? []) {\n out.push({\n id: `compaction-${compaction.taskId}`,\n role: 'system',\n kind: 'compaction',\n text: '',\n createdAt: 0,\n state: 'summarizing',\n trigger: compaction.reason as SystemMessage['trigger'],\n });\n }\n const retry = state?.generation?.retry;\n if (retry)\n out.push({\n id: 'retry',\n role: 'system',\n kind: 'notice',\n text: retry.error,\n createdAt: retry.at,\n });\n}\n\nexport function toMessages(view: ConversationView | undefined): Message[] {\n const out: Message[] = [];\n if (!view) return out;\n const calls = new Map<string, ToolCall>();\n for (const entry of view.entries) entryMessage(entry, out, calls);\n live(view, out, calls);\n return out;\n}\n\nexport function isBusy(view: ConversationView | undefined): boolean {\n return Boolean((view?.docs['pi.live'] as Live | undefined)?.run);\n}\n\nexport function queued(view: ConversationView | undefined): UserMessage[] {\n const items = ((view?.docs['pi.inbox'] as { items?: Json[] } | undefined)?.items ?? []) as {\n id: number;\n mode: string;\n content?: ModelMessage['content'];\n }[];\n return items\n .filter((item) => item.mode !== 'write')\n .map((item) => ({\n id: `q${item.id}`,\n role: 'user',\n text: textOf(item.content),\n createdAt: 0,\n queued: true,\n mode: item.mode === 'steer' ? 'steer' : 'queue',\n }));\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -7,6 +7,7 @@ export interface AgentOptions {
7
7
  storage?: Storage;
8
8
  registry?: Registry;
9
9
  settings?: HarnessOptions['settings'];
10
+ env?: HarnessOptions['env'];
10
11
  context?: Context;
11
12
  }
12
13
  export interface Agent {
@@ -2,8 +2,10 @@ export { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts
2
2
  export { type AgentConnection, connectAgent } from './client.ts';
3
3
  export { createAgentControl } from './control.ts';
4
4
  export { type AgentHost, hostAgent } from './host.ts';
5
+ export type { KernelClient, KernelFs, KernelProcess, KernelStat, SpawnOptions, } from './kernel/client.ts';
6
+ export { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';
5
7
  export { AGENT_LOCK, type AgentOwner, type AgentWorker, type OwnerOptions, startAgent, } from './owner.ts';
6
- export { AGENT_SESSION, AgentControl, AgentSessions, AgentTranscript, type OperationError, type PromptResult, type SendMode, type SendRequest, type SendResponse, } from './services.ts';
8
+ export { AGENT_SESSION, AgentControl, AgentSessions, type AgentSettingsChange, AgentTranscript, type OperationError, type PromptResult, type SendMode, type SendRequest, type SendResponse, } from './services.ts';
7
9
  export { AGENT_DIRECTORY, type OpfsSqliteOptions, openMemorySqliteStorage, openOpfsSqliteStorage, WasmSqliteDatabase, } from './sqlite.ts';
8
10
  export { PortChannel, type PortEndpoint, PortListener, withUnrefTimers } from './wire.ts';
9
- export { serveConnections, type WorkerScope } from './worker.ts';
11
+ export { kernelPort, serveConnections, type WorkerScope } from './worker.ts';
@@ -0,0 +1,39 @@
1
+ export interface KernelStat {
2
+ isFile: boolean;
3
+ isDirectory: boolean;
4
+ isSymbolicLink: boolean;
5
+ size: number;
6
+ mtime: Date | number;
7
+ ino?: number;
8
+ }
9
+ export interface KernelFs {
10
+ readFile(path: string): Promise<Uint8Array>;
11
+ readText(path: string): Promise<string>;
12
+ writeFile(path: string, data: string | Uint8Array): Promise<void>;
13
+ stat(path: string): Promise<KernelStat>;
14
+ lstat(path: string): Promise<KernelStat>;
15
+ readdir(path: string): Promise<string[]>;
16
+ mkdir(path: string): Promise<void>;
17
+ rm(path: string, options?: {
18
+ force?: boolean;
19
+ }): Promise<void>;
20
+ rename(from: string, to: string): Promise<void>;
21
+ realpath(path: string): Promise<string>;
22
+ exists(path: string): Promise<boolean>;
23
+ }
24
+ export interface KernelProcess {
25
+ pid: number;
26
+ pgid: number;
27
+ exited: Promise<number>;
28
+ signal(name?: string): unknown;
29
+ }
30
+ export interface SpawnOptions {
31
+ cwd?: string;
32
+ env?: Record<string, string>;
33
+ onStdout?(bytes: Uint8Array): void;
34
+ onStderr?(bytes: Uint8Array): void;
35
+ }
36
+ export interface KernelClient {
37
+ fs: KernelFs;
38
+ spawn(argv: readonly string[], options: SpawnOptions): Promise<KernelProcess>;
39
+ }
@@ -0,0 +1,57 @@
1
+ import type { Context } from '@earendil-works/chord';
2
+ import { type BinaryReader, type DirReader, type ExecutionEnv, type ExecutionError, FileError, type FileInfo, type FileWatcher, type Result, type ShellExecOptions, type ShellExecResult, type TextLineReader, type WatchChange, type WatchTarget } from '@earendil-works/pi-durable/env';
3
+ import type { KernelClient } from './client.ts';
4
+ import { type PollOptions } from './watch.ts';
5
+ export interface KernelEnvOptions {
6
+ cwd: string;
7
+ id?: string;
8
+ watch?: PollOptions;
9
+ }
10
+ type FileResult<T> = Promise<Result<T, FileError>>;
11
+ export declare class SliccKernelEnv implements ExecutionEnv {
12
+ #private;
13
+ readonly id: string;
14
+ cwd: string;
15
+ constructor(client: KernelClient, options: KernelEnvOptions);
16
+ absolutePath(path: string): FileResult<string>;
17
+ joinPath(parts: string[]): FileResult<string>;
18
+ readTextFile(path: string, context: Context): FileResult<string>;
19
+ readBinaryFile(path: string, context: Context): FileResult<Uint8Array>;
20
+ openTextLineReader(path: string, context: Context): FileResult<TextLineReader>;
21
+ readTextLines(path: string, options: {
22
+ maxLines?: number;
23
+ } | undefined, context: Context): FileResult<string[]>;
24
+ openBinaryReader(path: string, options: {
25
+ noFollow?: boolean;
26
+ } | undefined, context: Context): FileResult<BinaryReader>;
27
+ writeFile(path: string, content: string | Uint8Array, context: Context): FileResult<void>;
28
+ appendFile(path: string, content: string | Uint8Array, context: Context): FileResult<void>;
29
+ truncateFile(path: string, size: number, context: Context): FileResult<void>;
30
+ flushFile(path: string, context: Context): FileResult<void>;
31
+ renameFile(sourcePath: string, destinationPath: string, context: Context): FileResult<void>;
32
+ fileInfo(path: string, context: Context): FileResult<FileInfo>;
33
+ listDir(path: string, context: Context): FileResult<FileInfo[]>;
34
+ openDirReader(path: string, context: Context): FileResult<DirReader>;
35
+ watch(targets: readonly WatchTarget[], onChange: (change: WatchChange) => void, context: Context): FileResult<FileWatcher>;
36
+ canonicalPath(path: string, context: Context): FileResult<string>;
37
+ exists(path: string, context: Context): FileResult<boolean>;
38
+ createDir(path: string, _options: {
39
+ recursive?: boolean;
40
+ } | undefined, context: Context): FileResult<void>;
41
+ remove(path: string, options: {
42
+ recursive?: boolean;
43
+ force?: boolean;
44
+ } | undefined, context: Context): FileResult<void>;
45
+ createTempDir(prefix: string | undefined, context: Context): FileResult<string>;
46
+ createTempFile(options: {
47
+ prefix?: string;
48
+ suffix?: string;
49
+ } | undefined, context: Context): FileResult<string>;
50
+ exec(command: string | readonly string[], options: ShellExecOptions | undefined, context: Context): Promise<Result<ShellExecResult, ExecutionError>>;
51
+ cleanup(context: Context): Promise<void>;
52
+ }
53
+ export declare const HOME = "/home";
54
+ export declare function kernelEnvironment(client: KernelClient, options?: Omit<KernelEnvOptions, 'cwd'>): (target: {
55
+ cwd?: string;
56
+ }) => SliccKernelEnv;
57
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { Context } from '@earendil-works/chord';
2
+ import { ExecutionError, type Result, type ShellExecOptions, type ShellExecResult } from '@earendil-works/pi-durable/env';
3
+ import type { KernelClient } from './client.ts';
4
+ export declare const SHELL: readonly ['bash', '-c'];
5
+ export declare function execute(client: KernelClient, cwd: string, command: string | readonly string[], options: ShellExecOptions | undefined, context: Context): Promise<Result<ShellExecResult, ExecutionError>>;
@@ -0,0 +1,34 @@
1
+ import type { Context } from '@earendil-works/chord';
2
+ import { type BinaryReader, type DirReader, FileError, type FileInfo, type LineScan, type Result, type TextLine, type TextLineReader } from '@earendil-works/pi-durable/env';
3
+ import type { KernelFs, KernelStat } from './client.ts';
4
+ export declare function fileError(error: unknown, path?: string): FileError;
5
+ export declare function aborted(context: Context, path?: string): Result<never, FileError> | undefined;
6
+ export declare function attempt<T>(context: Context, path: string, run: () => Promise<T>): Promise<Result<T, FileError>>;
7
+ export declare function info(path: string, stat: KernelStat): FileInfo;
8
+ export declare class SnapshotReader implements BinaryReader {
9
+ #private;
10
+ constructor(bytes: Uint8Array, fileInfo: FileInfo);
11
+ info(): Promise<Result<FileInfo, FileError>>;
12
+ read(offset: number, length: number, context: Context): Promise<Result<Uint8Array, FileError>>;
13
+ scanLines(options: {
14
+ startLine: number;
15
+ endLine?: number;
16
+ }, context: Context): Promise<Result<LineScan, FileError>>;
17
+ close(): Promise<void>;
18
+ }
19
+ export declare class SnapshotLines implements TextLineReader {
20
+ #private;
21
+ constructor(text: string);
22
+ readLine(): Promise<Result<TextLine | undefined, FileError>>;
23
+ close(): Promise<void>;
24
+ }
25
+ export declare class KernelDirReader implements DirReader {
26
+ #private;
27
+ constructor(fs: KernelFs, path: string, names: string[]);
28
+ next(maxEntries: number, context: Context): Promise<Result<{
29
+ entries: FileInfo[];
30
+ done: boolean;
31
+ }, FileError>>;
32
+ rest(): Promise<FileInfo[]>;
33
+ close(): Promise<void>;
34
+ }
@@ -0,0 +1,4 @@
1
+ export declare function normalize(path: string): string;
2
+ export declare function resolve(cwd: string, path: string): string;
3
+ export declare function dirname(path: string): string;
4
+ export declare function basename(path: string): string;
@@ -0,0 +1,10 @@
1
+ import type { FileWatcher, WatchChange, WatchTarget } from '@earendil-works/pi-durable/env';
2
+ import type { KernelFs } from './client.ts';
3
+ type Snapshot = Map<string, string>;
4
+ export declare function snapshot(fs: KernelFs, cwd: string, targets: readonly WatchTarget[]): Promise<Snapshot>;
5
+ export declare function differences(before: Snapshot, after: Snapshot): string[];
6
+ export interface PollOptions {
7
+ intervalMs?: number;
8
+ }
9
+ export declare function pollWatch(fs: KernelFs, cwd: string, targets: readonly WatchTarget[], onChange: (change: WatchChange) => void, options?: PollOptions): Promise<FileWatcher>;
10
+ export {};
@@ -7,11 +7,15 @@ export interface AgentWorker {
7
7
  }
8
8
  export interface AgentOwner {
9
9
  connect(): Promise<AgentConnection>;
10
- restart(): void;
11
- release(): void;
10
+ restart(): Promise<void>;
11
+ release(): Promise<void>;
12
+ }
13
+ export interface KernelSource {
14
+ connect(): Promise<Transferable>;
12
15
  }
13
16
  export interface OwnerOptions {
14
17
  worker: () => AgentWorker;
18
+ kernel?: KernelSource;
15
19
  locks?: LockManager;
16
20
  channel?: () => {
17
21
  port1: PortEndpoint;
@@ -36,6 +36,15 @@ export interface AgentControl {
36
36
  }>;
37
37
  abort(context: Context): Promise<void>;
38
38
  compact(instructions: string | null, context: Context): Promise<SendResponse>;
39
+ reset(handoff: string | null, context: Context): Promise<void>;
40
+ configure(change: AgentSettingsChange, context: Context): Promise<void>;
41
+ }
42
+ export interface AgentSettingsChange {
43
+ model: {
44
+ provider: string;
45
+ modelId: string;
46
+ } | null;
47
+ thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;
39
48
  }
40
49
  export declare const AgentControl: import("@earendil-works/chord").Service<AgentControl>;
41
50
  export interface AgentTranscript {
@@ -0,0 +1,32 @@
1
+ import type { Agent, AgentEvents, AgentPort, FrozenCone, Message, Outgoing, SlashCommand, Thinking, UserMessage } from '@ai-ecoverse/slicc-spectrum/ui';
2
+ import type { AgentConnection } from '../client.ts';
3
+ import { Emitter } from './emitter.ts';
4
+ export declare const CONE = "cone";
5
+ export declare class AgentAdapter extends Emitter<AgentEvents> implements AgentPort {
6
+ #private;
7
+ constructor(connection: AgentConnection);
8
+ ready(): Promise<void>;
9
+ list(): readonly Agent[];
10
+ active(): string;
11
+ select(): void;
12
+ messages(): readonly Message[];
13
+ send(_agentId: string, input: string | Outgoing): Promise<void>;
14
+ stop(): void;
15
+ busy(): boolean;
16
+ queue(): readonly UserMessage[];
17
+ unqueue(_agentId: string, messageId: string): void;
18
+ suggestion(): string | null;
19
+ answer(): void;
20
+ resolveLick(): void;
21
+ compact(): void;
22
+ clear(): void;
23
+ setModel(_agentId: string, model: string): void;
24
+ setThinking(_agentId: string, level: Thinking): void;
25
+ older(): Promise<readonly Message[]>;
26
+ commands(): readonly SlashCommand[];
27
+ createScoop(): Agent;
28
+ frozen(): readonly FrozenCone[];
29
+ freeze(): void;
30
+ thaw(): Agent | null;
31
+ discard(): void;
32
+ }
@@ -0,0 +1,7 @@
1
+ type Listener<T> = (detail: T) => void;
2
+ export declare class Emitter<Events extends object> {
3
+ #private;
4
+ on<K extends keyof Events>(type: K, listener: Listener<Events[K]>): () => void;
5
+ emit<K extends keyof Events>(type: K, detail: Events[K]): void;
6
+ }
7
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { AgentConnection } from '../client.ts';
2
+ import { AgentAdapter } from './agent-port.ts';
3
+ export { AgentAdapter, CONE } from './agent-port.ts';
4
+ export { assistant, isBusy, queued, textOf, toMessages } from './messages.ts';
5
+ export declare function createAgentModel(connection: AgentConnection): {
6
+ agent: AgentAdapter;
7
+ };
@@ -0,0 +1,37 @@
1
+ import type { AssistantMessage, AssistantStatus, Message, UserMessage } from '@ai-ecoverse/slicc-spectrum/ui';
2
+ import type { ConversationView } from '@earendil-works/pi-durable';
3
+ type Json = Record<string, unknown>;
4
+ interface Block {
5
+ type: string;
6
+ text?: string;
7
+ thinking?: string;
8
+ id?: string;
9
+ name?: string;
10
+ arguments?: Json;
11
+ }
12
+ interface ModelMessage {
13
+ role: string;
14
+ content?: string | Block[];
15
+ timestamp?: number;
16
+ stopReason?: string;
17
+ errorMessage?: string;
18
+ provider?: string;
19
+ model?: string;
20
+ usage?: {
21
+ input?: number;
22
+ output?: number;
23
+ cacheRead?: number;
24
+ cacheWrite?: number;
25
+ cost?: {
26
+ total?: number;
27
+ };
28
+ };
29
+ toolCallId?: string;
30
+ isError?: boolean;
31
+ }
32
+ export declare function textOf(content: ModelMessage['content']): string;
33
+ export declare function assistant(id: string, message: ModelMessage, status?: AssistantStatus): AssistantMessage;
34
+ export declare function toMessages(view: ConversationView | undefined): Message[];
35
+ export declare function isBusy(view: ConversationView | undefined): boolean;
36
+ export declare function queued(view: ConversationView | undefined): UserMessage[];
37
+ export {};
@@ -3,3 +3,4 @@ export interface WorkerScope {
3
3
  addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
4
4
  }
5
5
  export declare function serveConnections(scope: WorkerScope, host: Promise<AgentHost>): void;
6
+ export declare function kernelPort(scope: WorkerScope): Promise<MessagePort>;
package/dist/worker.js CHANGED
@@ -8,7 +8,16 @@ function serveConnections(scope, host) {
8
8
  );
9
9
  });
10
10
  }
11
+ function kernelPort(scope) {
12
+ return new Promise((resolve) => {
13
+ scope.addEventListener("message", ({ data }) => {
14
+ const port = data?.kernel;
15
+ if (port) resolve(port);
16
+ });
17
+ });
18
+ }
11
19
  export {
20
+ kernelPort,
12
21
  serveConnections
13
22
  };
14
23
  //# sourceMappingURL=worker.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/worker.ts"],
4
- "sourcesContent": ["import type { AgentHost } from './host.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport interface WorkerScope {\n addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;\n}\n\nexport function serveConnections(scope: WorkerScope, host: Promise<AgentHost>): void {\n scope.addEventListener('message', ({ data }) => {\n const port = (data as { connect?: PortEndpoint } | null)?.connect;\n if (!port) return;\n host.then(\n (ready) => ready.connect(port),\n () => port.close?.()\n );\n });\n}\n"],
5
- "mappings": "AAOO,SAAS,iBAAiB,OAAoB,MAAgC;AACnF,QAAM,iBAAiB,WAAW,CAAC,EAAE,KAAK,MAAM;AAC9C,UAAM,OAAQ,MAA4C;AAC1D,QAAI,CAAC,KAAM;AACX,SAAK;AAAA,MACH,CAAC,UAAU,MAAM,QAAQ,IAAI;AAAA,MAC7B,MAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF,CAAC;AACH;",
4
+ "sourcesContent": ["import type { AgentHost } from './host.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport interface WorkerScope {\n addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;\n}\n\nexport function serveConnections(scope: WorkerScope, host: Promise<AgentHost>): void {\n scope.addEventListener('message', ({ data }) => {\n const port = (data as { connect?: PortEndpoint } | null)?.connect;\n if (!port) return;\n host.then(\n (ready) => ready.connect(port),\n () => port.close?.()\n );\n });\n}\n\nexport function kernelPort(scope: WorkerScope): Promise<MessagePort> {\n return new Promise((resolve) => {\n scope.addEventListener('message', ({ data }) => {\n const port = (data as { kernel?: MessagePort } | null)?.kernel;\n if (port) resolve(port);\n });\n });\n}\n"],
5
+ "mappings": "AAOO,SAAS,iBAAiB,OAAoB,MAAgC;AACnF,QAAM,iBAAiB,WAAW,CAAC,EAAE,KAAK,MAAM;AAC9C,UAAM,OAAQ,MAA4C;AAC1D,QAAI,CAAC,KAAM;AACX,SAAK;AAAA,MACH,CAAC,UAAU,MAAM,QAAQ,IAAI;AAAA,MAC7B,MAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF,CAAC;AACH;AAEO,SAAS,WAAW,OAA0C;AACnE,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,iBAAiB,WAAW,CAAC,EAAE,KAAK,MAAM;AAC9C,YAAM,OAAQ,MAA0C;AACxD,UAAI,KAAM,SAAQ,IAAI;AAAA,IACxB,CAAC;AAAA,EACH,CAAC;AACH;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-agent",
3
- "version": "2.0.0",
3
+ "version": "2.2.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",
@@ -25,6 +25,10 @@
25
25
  ".": {
26
26
  "types": "./dist/types/index.d.ts",
27
27
  "default": "./dist/index.js"
28
+ },
29
+ "./spectrum": {
30
+ "types": "./dist/types/spectrum/index.d.ts",
31
+ "default": "./dist/spectrum/index.js"
28
32
  }
29
33
  },
30
34
  "files": [
@@ -36,7 +40,7 @@
36
40
  "prepack": "npm run build",
37
41
  "start": "npm run build && node test/integration/chrome.mjs",
38
42
  "pretest": "npm run build && node test/integration/build.mjs && playwright-core install --no-shell chromium",
39
- "test": "node --test --test-global-setup=node_modules/@ai-ecoverse/slicc-shared-web/harness/global.mjs 'test/integration/*.test.mjs'",
43
+ "test": "node --test --test-timeout=120000 --test-global-setup=node_modules/@ai-ecoverse/slicc-shared-web/harness/global.mjs 'test/integration/*.test.mjs'",
40
44
  "test:unit": "NODE_NO_WARNINGS=1 mcr -c node_modules/@ai-ecoverse/slicc-shared-web/mcr.config.mjs node --test 'test/unit/**/*.test.mjs'",
41
45
  "typecheck": "tsc",
42
46
  "lint": "slicc-lint",
@@ -46,7 +50,11 @@
46
50
  "release": "semantic-release"
47
51
  },
48
52
  "devDependencies": {
53
+ "@ai-ecoverse/slicc-kernel": "1.9.0",
49
54
  "@ai-ecoverse/slicc-shared-web": "1.5.0",
55
+ "@ai-ecoverse/slicc-spectrum": "1.7.0",
56
+ "@ai-ecoverse/wasm-bash": "5.3.0-7",
57
+ "@ai-ecoverse/wasm-coreutils": "9.7.0-3",
50
58
  "@biomejs/biome": "2.5.15",
51
59
  "@types/node": "24.19.1",
52
60
  "esbuild": "0.28.2",
@@ -64,5 +72,8 @@
64
72
  "@earendil-works/pi-protocol": "1.0.4",
65
73
  "@earendil-works/pi-server": "1.0.4",
66
74
  "@sqlite.org/sqlite-wasm": "3.53.4-build2"
75
+ },
76
+ "peerDependencies": {
77
+ "@ai-ecoverse/slicc-spectrum": "^1.7.0"
67
78
  }
68
79
  }