@ai-ecoverse/slicc-agent 5.0.3 → 5.1.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.
@@ -0,0 +1,135 @@
1
+ import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
2
+ import { Emitter } from "./emitter.js";
3
+ const ENDS = {
4
+ approved: "answered",
5
+ rejected: "answered",
6
+ unanswered: "expired",
7
+ withdrawn: "withdrawn"
8
+ };
9
+ function requesterOf(item) {
10
+ const { kind, name, agentId, where } = item.requester;
11
+ return {
12
+ kind,
13
+ name,
14
+ ...agentId ? { agentId } : {},
15
+ ...where ? { where } : {}
16
+ };
17
+ }
18
+ function shown(item, agentName) {
19
+ const base = {
20
+ id: item.id,
21
+ requester: requesterOf(item),
22
+ createdAt: item.createdAt,
23
+ expiresAt: item.expiresAt
24
+ };
25
+ if (item.kind === "sudo") {
26
+ const { command, target, cwd, alwaysScope } = item.detail;
27
+ return {
28
+ ...base,
29
+ kind: "sudo",
30
+ command,
31
+ ...target ? { target } : {},
32
+ ...cwd ? { cwd } : {},
33
+ always: item.always,
34
+ ...alwaysScope ? { alwaysScope } : {}
35
+ };
36
+ }
37
+ const guest = {
38
+ ...base,
39
+ agentId: item.agentId,
40
+ ...agentName ? { agentName } : {},
41
+ always: false,
42
+ ...item.verdict ? { verdict: { ...item.verdict } } : {}
43
+ };
44
+ if (item.kind === "guest-tool")
45
+ return { ...guest, kind: "guest-tool", tool: item.detail.tool, summary: item.detail.summary };
46
+ return {
47
+ ...guest,
48
+ kind: "guest-message",
49
+ text: item.detail.text,
50
+ ...item.detail.attachments.length ? { attachments: item.detail.attachments.map((file) => ({ ...file })) } : {}
51
+ };
52
+ }
53
+ const NOT_HERE = "This request can't be answered in this tab.";
54
+ const asked = (item) => item.state === "pending" && item.tier === "user";
55
+ class ApprovalsAdapter extends Emitter {
56
+ #connection;
57
+ #host;
58
+ #ours;
59
+ #mine = /* @__PURE__ */ new Set();
60
+ #deciding = /* @__PURE__ */ new Set();
61
+ #listed = /* @__PURE__ */ new Set();
62
+ decide;
63
+ constructor(connection, host) {
64
+ super();
65
+ this.#connection = connection;
66
+ this.#host = host;
67
+ this.#ours = !connection.readOnly && !connection.mismatch;
68
+ if (this.#ours || host?.decide) this.decide = (...args) => this.#route(...args);
69
+ this.#listed = new Set(this.#agent().map((approval) => approval.id));
70
+ connection.approvals?.subscribe(() => this.#changed());
71
+ host?.on("approvals", () => this.emit("approvals", this.list()));
72
+ host?.on("ended", (detail) => this.emit("ended", detail));
73
+ }
74
+ #items() {
75
+ return this.#connection.approvals?.value ?? [];
76
+ }
77
+ list() {
78
+ return [...this.#host?.list() ?? [], ...this.#agent()].sort(
79
+ (a, b) => a.createdAt - b.createdAt
80
+ );
81
+ }
82
+ #agent() {
83
+ const names = new Map(
84
+ (this.#connection.agents?.value?.agents ?? []).map((agent) => [agent.id, agent.name])
85
+ );
86
+ return this.#items().filter((item) => asked(item) && !this.#mine.has(item.id)).sort((a, b) => a.createdAt - b.createdAt).map((item) => shown(item, names.get(item.agentId)));
87
+ }
88
+ #changed() {
89
+ const items = new Map(this.#items().map((item) => [item.id, item]));
90
+ const listed = this.#agent();
91
+ const now = new Set(listed.map((approval) => approval.id));
92
+ for (const id of this.#listed) {
93
+ if (now.has(id) || this.#mine.has(id) || this.#deciding.has(id)) continue;
94
+ const state = items.get(id)?.state;
95
+ this.emit("ended", { id, reason: state && ENDS[state] || "answered" });
96
+ }
97
+ for (const id of this.#mine) {
98
+ const item = items.get(id);
99
+ if (!item || !asked(item)) this.#mine.delete(id);
100
+ }
101
+ this.#listed = now;
102
+ this.emit("approvals", this.list());
103
+ }
104
+ #route(id, decision, reason) {
105
+ const host = this.#host;
106
+ if (host?.list().some((approval) => approval.id === id)) {
107
+ if (!host.decide) return Promise.reject(new Error(NOT_HERE));
108
+ return host.decide(id, decision, reason);
109
+ }
110
+ if (!this.#ours) return Promise.reject(new Error(NOT_HERE));
111
+ return this.#decide(id, decision, reason);
112
+ }
113
+ async #decide(id, decision, reason) {
114
+ this.#deciding.add(id);
115
+ try {
116
+ const answer = await this.#connection.control.decide(
117
+ id,
118
+ decision,
119
+ reason ?? null,
120
+ BACKGROUND_CONTEXT
121
+ );
122
+ if (!answer.done) throw new Error(answer.error);
123
+ this.#mine.add(id);
124
+ } finally {
125
+ this.#deciding.delete(id);
126
+ }
127
+ this.#changed();
128
+ }
129
+ }
130
+ export {
131
+ ApprovalsAdapter,
132
+ NOT_HERE,
133
+ shown
134
+ };
135
+ //# sourceMappingURL=approvals-port.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/spectrum/approvals-port.ts"],
4
+ "sourcesContent": ["import type {\n Approval,\n ApprovalDecision,\n ApprovalEnd,\n ApprovalRequester,\n ApprovalsEvents,\n ApprovalsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Approval as Item } from '../approvals/record.ts';\nimport type { AgentConnection } from '../client.ts';\nimport { Emitter } from './emitter.ts';\n\nconst ENDS: Record<string, ApprovalEnd> = {\n approved: 'answered',\n rejected: 'answered',\n unanswered: 'expired',\n withdrawn: 'withdrawn',\n};\n\nfunction requesterOf(item: Item): ApprovalRequester {\n const { kind, name, agentId, where } = item.requester;\n return {\n kind,\n name,\n ...(agentId ? { agentId } : {}),\n ...(where ? { where } : {}),\n };\n}\n\nexport function shown(item: Item, agentName: string | undefined): Approval {\n const base = {\n id: item.id,\n requester: requesterOf(item),\n createdAt: item.createdAt,\n expiresAt: item.expiresAt,\n };\n if (item.kind === 'sudo') {\n const { command, target, cwd, alwaysScope } = item.detail;\n return {\n ...base,\n kind: 'sudo',\n command,\n ...(target ? { target } : {}),\n ...(cwd ? { cwd } : {}),\n always: item.always,\n ...(alwaysScope ? { alwaysScope } : {}),\n };\n }\n const guest = {\n ...base,\n agentId: item.agentId,\n ...(agentName ? { agentName } : {}),\n always: false as const,\n ...(item.verdict ? { verdict: { ...item.verdict } } : {}),\n };\n if (item.kind === 'guest-tool')\n return { ...guest, kind: 'guest-tool', tool: item.detail.tool, summary: item.detail.summary };\n return {\n ...guest,\n kind: 'guest-message',\n text: item.detail.text,\n ...(item.detail.attachments.length\n ? { attachments: item.detail.attachments.map((file) => ({ ...file })) }\n : {}),\n };\n}\n\nexport type HostApprovals = ApprovalsPort;\n\nexport const NOT_HERE = \"This request can't be answered in this tab.\";\n\nconst asked = (item: Item) => item.state === 'pending' && item.tier === 'user';\n\nexport class ApprovalsAdapter extends Emitter<ApprovalsEvents> implements ApprovalsPort {\n readonly #connection: AgentConnection;\n readonly #host: HostApprovals | undefined;\n readonly #ours: boolean;\n readonly #mine = new Set<string>();\n readonly #deciding = new Set<string>();\n #listed = new Set<string>();\n readonly decide?: (id: string, decision: ApprovalDecision, reason?: string) => Promise<void>;\n\n constructor(connection: AgentConnection, host?: HostApprovals) {\n super();\n this.#connection = connection;\n this.#host = host;\n this.#ours = !connection.readOnly && !connection.mismatch;\n if (this.#ours || host?.decide) this.decide = (...args) => this.#route(...args);\n this.#listed = new Set(this.#agent().map((approval) => approval.id));\n connection.approvals?.subscribe(() => this.#changed());\n host?.on('approvals', () => this.emit('approvals', this.list()));\n host?.on('ended', (detail) => this.emit('ended', detail));\n }\n\n #items(): readonly Item[] {\n return this.#connection.approvals?.value ?? [];\n }\n\n list(): readonly Approval[] {\n return [...(this.#host?.list() ?? []), ...this.#agent()].sort(\n (a, b) => a.createdAt - b.createdAt\n );\n }\n\n #agent(): readonly Approval[] {\n const names = new Map(\n (this.#connection.agents?.value?.agents ?? []).map((agent) => [agent.id, agent.name])\n );\n return this.#items()\n .filter((item) => asked(item) && !this.#mine.has(item.id))\n .sort((a, b) => a.createdAt - b.createdAt)\n .map((item) => shown(item, names.get(item.agentId)));\n }\n\n #changed(): void {\n const items = new Map(this.#items().map((item) => [item.id, item]));\n const listed = this.#agent();\n const now = new Set(listed.map((approval) => approval.id));\n for (const id of this.#listed) {\n if (now.has(id) || this.#mine.has(id) || this.#deciding.has(id)) continue;\n const state = items.get(id)?.state;\n this.emit('ended', { id, reason: (state && ENDS[state]) || 'answered' });\n }\n for (const id of this.#mine) {\n const item = items.get(id);\n if (!item || !asked(item)) this.#mine.delete(id);\n }\n this.#listed = now;\n this.emit('approvals', this.list());\n }\n\n #route(id: string, decision: ApprovalDecision, reason?: string): Promise<void> {\n const host = this.#host;\n if (host?.list().some((approval) => approval.id === id)) {\n if (!host.decide) return Promise.reject(new Error(NOT_HERE));\n return host.decide(id, decision, reason);\n }\n if (!this.#ours) return Promise.reject(new Error(NOT_HERE));\n return this.#decide(id, decision, reason);\n }\n\n async #decide(id: string, decision: ApprovalDecision, reason?: string): Promise<void> {\n this.#deciding.add(id);\n try {\n const answer = await this.#connection.control.decide(\n id,\n decision,\n reason ?? null,\n BACKGROUND_CONTEXT\n );\n if (!answer.done) throw new Error(answer.error);\n this.#mine.add(id);\n } finally {\n this.#deciding.delete(id);\n }\n this.#changed();\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,4 +1,5 @@
1
1
  import { AgentAdapter } from "./agent-port.js";
2
+ import { ApprovalsAdapter } from "./approvals-port.js";
2
3
  import { ChangesAdapter } from "./changes-port.js";
3
4
  import { MemoryAdapter } from "./memory-port.js";
4
5
  import { MonitorAdapter } from "./monitor-port.js";
@@ -8,6 +9,11 @@ import { SettingsAdapter } from "./settings-port.js";
8
9
  import { SprinkleAdapter } from "./sprinkle-port.js";
9
10
  import { TrayAdapter } from "./tray-port.js";
10
11
  import { AgentAdapter as AgentAdapter2, CONE } from "./agent-port.js";
12
+ import {
13
+ ApprovalsAdapter as ApprovalsAdapter2,
14
+ NOT_HERE,
15
+ shown
16
+ } from "./approvals-port.js";
11
17
  import { ChangesAdapter as ChangesAdapter2 } from "./changes-port.js";
12
18
  import { MemoryAdapter as MemoryAdapter2 } from "./memory-port.js";
13
19
  import {
@@ -43,6 +49,7 @@ function createAgentModel(connection, options = {}) {
43
49
  const run = options.page?.run;
44
50
  return {
45
51
  agent,
52
+ approvals: new ApprovalsAdapter(connection, options.approvals),
46
53
  page: options.page && run ? new PageAdapter(connection, agent, { ...options.page, run }) : null,
47
54
  settings: new SettingsAdapter(
48
55
  connection.settings,
@@ -63,12 +70,14 @@ function createAgentModel(connection, options = {}) {
63
70
  }
64
71
  export {
65
72
  AgentAdapter2 as AgentAdapter,
73
+ ApprovalsAdapter2 as ApprovalsAdapter,
66
74
  CONE,
67
75
  ChangesAdapter2 as ChangesAdapter,
68
76
  KEYS_MOVED,
69
77
  MISMATCH,
70
78
  MemoryAdapter2 as MemoryAdapter,
71
79
  MonitorAdapter2 as MonitorAdapter,
80
+ NOT_HERE,
72
81
  NoticesAdapter2 as NoticesAdapter,
73
82
  PageAdapter2 as PageAdapter,
74
83
  SETTINGS_KEY,
@@ -85,6 +94,7 @@ export {
85
94
  movedList,
86
95
  movedNotice,
87
96
  queued,
97
+ shown as shownApproval,
88
98
  textOf,
89
99
  toMessages
90
100
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/spectrum/index.ts"],
4
- "sourcesContent": ["import type { MonitorSection } from '@ai-ecoverse/slicc-spectrum/ui';\nimport type { AgentConnection } from '../client.ts';\nimport { AgentAdapter } from './agent-port.ts';\nimport { ChangesAdapter } from './changes-port.ts';\nimport { MemoryAdapter } from './memory-port.ts';\nimport { MonitorAdapter } from './monitor-port.ts';\nimport { type HostNotices, NoticesAdapter } from './notices-port.ts';\nimport { PageAdapter, type PageOptions } from './page-port.ts';\nimport { type Login, SettingsAdapter } from './settings-port.ts';\nimport { SprinkleAdapter } from './sprinkle-port.ts';\nimport { TrayAdapter } from './tray-port.ts';\n\nexport { AgentAdapter, CONE } from './agent-port.ts';\nexport { ChangesAdapter, type ChangesEvents } from './changes-port.ts';\nexport { MemoryAdapter } from './memory-port.ts';\nexport {\n assistant,\n errorAction,\n errorPart,\n isBusy,\n queued,\n textOf,\n toMessages,\n} from './messages.ts';\nexport {\n MonitorAdapter,\n type MonitorAdapterOptions,\n type MonitorInput,\n monitorSnapshot,\n} from './monitor-port.ts';\nexport {\n type HostNotices,\n KEYS_MOVED,\n MISMATCH,\n mismatchBanner,\n movedList,\n movedNotice,\n NoticesAdapter,\n} from './notices-port.ts';\nexport {\n PageAdapter,\n type PageDocument,\n type PageOptions,\n type PageRun,\n type PageTarget,\n} from './page-port.ts';\nexport { type Login, SETTINGS_KEY, SettingsAdapter } from './settings-port.ts';\nexport { SprinkleAdapter } from './sprinkle-port.ts';\nexport { TrayAdapter } from './tray-port.ts';\n\nexport function createAgentModel(\n connection: AgentConnection,\n options: {\n storage?: Pick<Storage, 'getItem' | 'setItem'> | null;\n login?: Login;\n monitor?: { extra?: () => readonly MonitorSection[] };\n page?: PageOptions;\n notices?: HostNotices;\n } = {}\n): {\n agent: AgentAdapter;\n settings: SettingsAdapter;\n tray: TrayAdapter;\n sprinkles: SprinkleAdapter;\n memory: MemoryAdapter;\n changes: ChangesAdapter;\n monitor: MonitorAdapter;\n notices: NoticesAdapter;\n page: PageAdapter | null;\n} {\n const agent = new AgentAdapter(connection);\n const report = (text: string) => agent.notify(text);\n const run = options.page?.run;\n return {\n agent,\n page: options.page && run ? new PageAdapter(connection, agent, { ...options.page, run }) : null,\n settings: new SettingsAdapter(\n connection.settings,\n agent,\n options.storage ?? null,\n options.login ?? null\n ),\n tray: new TrayAdapter(connection.settings),\n sprinkles: new SprinkleAdapter(connection, report),\n memory: new MemoryAdapter(connection, report),\n changes: new ChangesAdapter(connection, report),\n notices: new NoticesAdapter(connection.settings, report, connection.mismatch, options.notices),\n monitor: new MonitorAdapter(\n connection,\n options.monitor?.extra ? { extra: options.monitor.extra } : {}\n ),\n };\n}\n"],
5
- "mappings": "AAEA,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B,SAA2B,sBAAsB;AACjD,SAAS,mBAAqC;AAC9C,SAAqB,uBAAuB;AAC5C,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAE5B,SAAS,gBAAAA,eAAc,YAAY;AACnC,SAAS,kBAAAC,uBAA0C;AACnD,SAAS,iBAAAC,sBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE,kBAAAC;AAAA,EAGA;AAAA,OACK;AACP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,OACK;AACP;AAAA,EACE,eAAAC;AAAA,OAKK;AACP,SAAqB,cAAc,mBAAAC,wBAAuB;AAC1D,SAAS,mBAAAC,wBAAuB;AAChC,SAAS,eAAAC,oBAAmB;AAErB,SAAS,iBACd,YACA,UAMI,CAAC,GAWL;AACA,QAAM,QAAQ,IAAI,aAAa,UAAU;AACzC,QAAM,SAAS,CAAC,SAAiB,MAAM,OAAO,IAAI;AAClD,QAAM,MAAM,QAAQ,MAAM;AAC1B,SAAO;AAAA,IACL;AAAA,IACA,MAAM,QAAQ,QAAQ,MAAM,IAAI,YAAY,YAAY,OAAO,EAAE,GAAG,QAAQ,MAAM,IAAI,CAAC,IAAI;AAAA,IAC3F,UAAU,IAAI;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MACA,QAAQ,WAAW;AAAA,MACnB,QAAQ,SAAS;AAAA,IACnB;AAAA,IACA,MAAM,IAAI,YAAY,WAAW,QAAQ;AAAA,IACzC,WAAW,IAAI,gBAAgB,YAAY,MAAM;AAAA,IACjD,QAAQ,IAAI,cAAc,YAAY,MAAM;AAAA,IAC5C,SAAS,IAAI,eAAe,YAAY,MAAM;AAAA,IAC9C,SAAS,IAAI,eAAe,WAAW,UAAU,QAAQ,WAAW,UAAU,QAAQ,OAAO;AAAA,IAC7F,SAAS,IAAI;AAAA,MACX;AAAA,MACA,QAAQ,SAAS,QAAQ,EAAE,OAAO,QAAQ,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC/D;AAAA,EACF;AACF;",
6
- "names": ["AgentAdapter", "ChangesAdapter", "MemoryAdapter", "MonitorAdapter", "NoticesAdapter", "PageAdapter", "SettingsAdapter", "SprinkleAdapter", "TrayAdapter"]
4
+ "sourcesContent": ["import type { MonitorSection } from '@ai-ecoverse/slicc-spectrum/ui';\nimport type { AgentConnection } from '../client.ts';\nimport { AgentAdapter } from './agent-port.ts';\nimport { ApprovalsAdapter, type HostApprovals } from './approvals-port.ts';\nimport { ChangesAdapter } from './changes-port.ts';\nimport { MemoryAdapter } from './memory-port.ts';\nimport { MonitorAdapter } from './monitor-port.ts';\nimport { type HostNotices, NoticesAdapter } from './notices-port.ts';\nimport { PageAdapter, type PageOptions } from './page-port.ts';\nimport { type Login, SettingsAdapter } from './settings-port.ts';\nimport { SprinkleAdapter } from './sprinkle-port.ts';\nimport { TrayAdapter } from './tray-port.ts';\n\nexport { AgentAdapter, CONE } from './agent-port.ts';\nexport {\n ApprovalsAdapter,\n type HostApprovals,\n NOT_HERE,\n shown as shownApproval,\n} from './approvals-port.ts';\nexport { ChangesAdapter, type ChangesEvents } from './changes-port.ts';\nexport { MemoryAdapter } from './memory-port.ts';\nexport {\n assistant,\n errorAction,\n errorPart,\n isBusy,\n queued,\n textOf,\n toMessages,\n} from './messages.ts';\nexport {\n MonitorAdapter,\n type MonitorAdapterOptions,\n type MonitorInput,\n monitorSnapshot,\n} from './monitor-port.ts';\nexport {\n type HostNotices,\n KEYS_MOVED,\n MISMATCH,\n mismatchBanner,\n movedList,\n movedNotice,\n NoticesAdapter,\n} from './notices-port.ts';\nexport {\n PageAdapter,\n type PageDocument,\n type PageOptions,\n type PageRun,\n type PageTarget,\n} from './page-port.ts';\nexport { type Login, SETTINGS_KEY, SettingsAdapter } from './settings-port.ts';\nexport { SprinkleAdapter } from './sprinkle-port.ts';\nexport { TrayAdapter } from './tray-port.ts';\n\nexport function createAgentModel(\n connection: AgentConnection,\n options: {\n storage?: Pick<Storage, 'getItem' | 'setItem'> | null;\n login?: Login;\n monitor?: { extra?: () => readonly MonitorSection[] };\n page?: PageOptions;\n approvals?: HostApprovals;\n notices?: HostNotices;\n } = {}\n): {\n agent: AgentAdapter;\n approvals: ApprovalsAdapter;\n settings: SettingsAdapter;\n tray: TrayAdapter;\n sprinkles: SprinkleAdapter;\n memory: MemoryAdapter;\n changes: ChangesAdapter;\n monitor: MonitorAdapter;\n notices: NoticesAdapter;\n page: PageAdapter | null;\n} {\n const agent = new AgentAdapter(connection);\n const report = (text: string) => agent.notify(text);\n const run = options.page?.run;\n return {\n agent,\n approvals: new ApprovalsAdapter(connection, options.approvals),\n page: options.page && run ? new PageAdapter(connection, agent, { ...options.page, run }) : null,\n settings: new SettingsAdapter(\n connection.settings,\n agent,\n options.storage ?? null,\n options.login ?? null\n ),\n tray: new TrayAdapter(connection.settings),\n sprinkles: new SprinkleAdapter(connection, report),\n memory: new MemoryAdapter(connection, report),\n changes: new ChangesAdapter(connection, report),\n notices: new NoticesAdapter(connection.settings, report, connection.mismatch, options.notices),\n monitor: new MonitorAdapter(\n connection,\n options.monitor?.extra ? { extra: options.monitor.extra } : {}\n ),\n };\n}\n"],
5
+ "mappings": "AAEA,SAAS,oBAAoB;AAC7B,SAAS,wBAA4C;AACrD,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B,SAA2B,sBAAsB;AACjD,SAAS,mBAAqC;AAC9C,SAAqB,uBAAuB;AAC5C,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAE5B,SAAS,gBAAAA,eAAc,YAAY;AACnC;AAAA,EACE,oBAAAC;AAAA,EAEA;AAAA,EACS;AAAA,OACJ;AACP,SAAS,kBAAAC,uBAA0C;AACnD,SAAS,iBAAAC,sBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE,kBAAAC;AAAA,EAGA;AAAA,OACK;AACP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,OACK;AACP;AAAA,EACE,eAAAC;AAAA,OAKK;AACP,SAAqB,cAAc,mBAAAC,wBAAuB;AAC1D,SAAS,mBAAAC,wBAAuB;AAChC,SAAS,eAAAC,oBAAmB;AAErB,SAAS,iBACd,YACA,UAOI,CAAC,GAYL;AACA,QAAM,QAAQ,IAAI,aAAa,UAAU;AACzC,QAAM,SAAS,CAAC,SAAiB,MAAM,OAAO,IAAI;AAClD,QAAM,MAAM,QAAQ,MAAM;AAC1B,SAAO;AAAA,IACL;AAAA,IACA,WAAW,IAAI,iBAAiB,YAAY,QAAQ,SAAS;AAAA,IAC7D,MAAM,QAAQ,QAAQ,MAAM,IAAI,YAAY,YAAY,OAAO,EAAE,GAAG,QAAQ,MAAM,IAAI,CAAC,IAAI;AAAA,IAC3F,UAAU,IAAI;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MACA,QAAQ,WAAW;AAAA,MACnB,QAAQ,SAAS;AAAA,IACnB;AAAA,IACA,MAAM,IAAI,YAAY,WAAW,QAAQ;AAAA,IACzC,WAAW,IAAI,gBAAgB,YAAY,MAAM;AAAA,IACjD,QAAQ,IAAI,cAAc,YAAY,MAAM;AAAA,IAC5C,SAAS,IAAI,eAAe,YAAY,MAAM;AAAA,IAC9C,SAAS,IAAI,eAAe,WAAW,UAAU,QAAQ,WAAW,UAAU,QAAQ,OAAO;AAAA,IAC7F,SAAS,IAAI;AAAA,MACX;AAAA,MACA,QAAQ,SAAS,QAAQ,EAAE,OAAO,QAAQ,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC/D;AAAA,EACF;AACF;",
6
+ "names": ["AgentAdapter", "ApprovalsAdapter", "ChangesAdapter", "MemoryAdapter", "MonitorAdapter", "NoticesAdapter", "PageAdapter", "SettingsAdapter", "SprinkleAdapter", "TrayAdapter"]
7
7
  }
@@ -0,0 +1,28 @@
1
+ import { type Context, type ReplicatedState } from '@earendil-works/chord';
2
+ import type { Harness } from '@earendil-works/pi-durable';
3
+ import { type Approval, type ApprovalDraft, type ApprovalState, type DecidedBy } from './record.ts';
4
+ export * from './record.ts';
5
+ export type ApprovalDecided = {
6
+ done: true;
7
+ state: ApprovalState;
8
+ error: null;
9
+ } | {
10
+ done: false;
11
+ state: null;
12
+ error: string;
13
+ };
14
+ export interface Approvals {
15
+ readonly state: ReplicatedState<Approval[]>;
16
+ request(draft: ApprovalDraft, context: Context): Promise<Approval>;
17
+ decide(id: string, answer: unknown, reason: string | null, by: DecidedBy, context: Context): Promise<ApprovalDecided>;
18
+ settled(id: string, context: Context): Promise<Approval>;
19
+ withdraw(id: string, reason: string | null, context: Context): Promise<Approval | undefined>;
20
+ withdrawSeat(seat: string, context: Context): Promise<number>;
21
+ close(): void;
22
+ }
23
+ export interface ApprovalsAttach {
24
+ harness: Pick<Harness, 'commit'>;
25
+ now?: () => number;
26
+ ttlMs?: number;
27
+ }
28
+ export declare function attachApprovals(options: ApprovalsAttach, context?: Context): Promise<Approvals>;
@@ -0,0 +1,108 @@
1
+ export type ApprovalKind = 'guest-message' | 'guest-tool' | 'sudo';
2
+ export type ApprovalState = 'pending' | 'approved' | 'rejected' | 'unanswered' | 'withdrawn';
3
+ export type ApprovalTier = 'user' | 'agent' | 'cone' | `scoop:${string}`;
4
+ export type ApprovalAnswer = 'once' | 'always' | 'deny';
5
+ export type DecidedBy = 'owner' | 'follower' | 'judge' | 'host';
6
+ export type ApprovalRequester = {
7
+ kind: 'guest' | 'agent' | 'user';
8
+ name: string;
9
+ seat?: string;
10
+ agentId?: string;
11
+ where?: string;
12
+ };
13
+ export type ApprovalVerdict = {
14
+ decision: 'allow' | 'deny';
15
+ reason: string;
16
+ };
17
+ export type ApprovalAttachment = {
18
+ name: string;
19
+ mimeType: string;
20
+ size: number;
21
+ };
22
+ export type GuestMessageDetail = {
23
+ text: string;
24
+ attachments: ApprovalAttachment[];
25
+ };
26
+ export type GuestToolDetail = {
27
+ tool: string;
28
+ summary: string;
29
+ };
30
+ export type SudoDetail = {
31
+ command: string;
32
+ target?: string;
33
+ cwd?: string;
34
+ alwaysScope?: 'cwd';
35
+ };
36
+ type Base = {
37
+ id: string;
38
+ seat?: string;
39
+ agentId: string;
40
+ requester: ApprovalRequester;
41
+ tier: string;
42
+ state: ApprovalState;
43
+ decidedBy: DecidedBy | null;
44
+ answer?: 'once' | 'always';
45
+ reason?: string;
46
+ verdict?: ApprovalVerdict;
47
+ always: boolean;
48
+ createdAt: number;
49
+ expiresAt: number;
50
+ decidedAt?: number;
51
+ };
52
+ export type GuestMessageApproval = Base & {
53
+ kind: 'guest-message';
54
+ detail: GuestMessageDetail;
55
+ };
56
+ export type GuestToolApproval = Base & {
57
+ kind: 'guest-tool';
58
+ detail: GuestToolDetail;
59
+ };
60
+ export type SudoApproval = Base & {
61
+ kind: 'sudo';
62
+ detail: SudoDetail;
63
+ };
64
+ export type Approval = GuestMessageApproval | GuestToolApproval | SudoApproval;
65
+ type DraftOf<T extends Approval> = Pick<T, 'kind' | 'detail' | 'agentId' | 'requester'> & {
66
+ seat?: string;
67
+ tier: string;
68
+ always?: boolean;
69
+ expiresAt?: number;
70
+ };
71
+ export type ApprovalDraft = DraftOf<GuestMessageApproval> | DraftOf<GuestToolApproval> | DraftOf<SudoApproval>;
72
+ export type ApprovalsState = {
73
+ items: Approval[];
74
+ };
75
+ export declare const ApprovalsDoc: import("@earendil-works/pi-durable").SessionDocToken<ApprovalsState>;
76
+ export declare const APPROVAL_MS = 300000;
77
+ export declare const APPROVALS_KEPT = 100;
78
+ export declare const MAX_DELAY = 2147483647;
79
+ export declare const REASON_LENGTH = 500;
80
+ export declare const REASONS: {
81
+ readonly timeout: 'timeout';
82
+ readonly unknownTier: 'unknown-tier';
83
+ readonly unroutable: 'unroutable';
84
+ readonly unknownAnswer: 'unknown-answer';
85
+ readonly restart: 'restart';
86
+ readonly revoked: 'revoked';
87
+ };
88
+ export declare const guestKind: (kind: ApprovalKind) => boolean;
89
+ export declare function knownTier(tier: unknown): tier is ApprovalTier;
90
+ export declare function routable(kind: ApprovalKind, tier: ApprovalTier): boolean;
91
+ export declare function answerOf(value: unknown): ApprovalAnswer | null;
92
+ export declare const personal: (by: DecidedBy) => boolean;
93
+ export declare function answerer(by: DecidedBy, tier: string): boolean;
94
+ export declare function gone(state: ApprovalState): string;
95
+ export declare function cleanReason(reason: unknown): string | undefined;
96
+ export declare function prune(items: Approval[], kept?: number): Approval[];
97
+ export type Settle = {
98
+ state: Exclude<ApprovalState, 'pending'>;
99
+ by: DecidedBy;
100
+ reason?: string;
101
+ };
102
+ export type Ruling = {
103
+ error?: string;
104
+ settle?: Settle;
105
+ answer?: 'once' | 'always';
106
+ };
107
+ export declare function ruled(item: Approval, answer: unknown, reason: unknown, by: DecidedBy, at: number): Ruling;
108
+ export {};
@@ -1,5 +1,6 @@
1
1
  import { type Context, type ReplicatedState } from '@earendil-works/chord';
2
2
  import type { ConversationView } from '@earendil-works/pi-durable';
3
+ import type { Approval } from './approvals/record.ts';
3
4
  import type { ChangesView } from './changes/git.ts';
4
5
  import type { FrozenCone } from './freezer/index.ts';
5
6
  import type { MemoryEntry, MemoryScope } from './memory/format.ts';
@@ -26,11 +27,13 @@ export interface AgentConnection {
26
27
  readonly monitor?: ReplicatedState<MonitorFeed>;
27
28
  readonly vault?: ReplicatedState<VaultState>;
28
29
  readonly labels?: ReplicatedState<Record<string, string>>;
30
+ readonly approvals?: ReplicatedState<Approval[]>;
29
31
  readonly settings: AgentSettings;
30
32
  readonly remote?: AgentRemote;
31
33
  readonly pages?: AgentPages;
32
34
  readonly closed: Promise<Error | undefined>;
33
35
  readonly mismatch?: string;
36
+ readonly readOnly?: boolean;
34
37
  prompt(text: string, whenBusy?: SendMode): Promise<string>;
35
38
  webhook(name: string, delivery: {
36
39
  id?: string | null;
@@ -1,5 +1,6 @@
1
1
  import { type Context, type Host, type ReplicatedState } from '@earendil-works/chord';
2
2
  import type { Agent } from './agent.ts';
3
+ import { type Approvals, type DecidedBy } from './approvals/index.ts';
3
4
  import type { ChangesRuntime } from './changes/index.ts';
4
5
  import { type HostLicks, type HostScoops } from './control.ts';
5
6
  import type { FreezerRuntime } from './freezer/index.ts';
@@ -27,6 +28,7 @@ export interface AgentHost {
27
28
  readonly agent: Agent;
28
29
  readonly users?: UserClients;
29
30
  readonly pages: Pages;
31
+ readonly approvals: Approvals;
30
32
  connect(endpoint: PortEndpoint, options?: ConnectOptions): void;
31
33
  close(): Promise<void>;
32
34
  }
@@ -54,6 +56,7 @@ export declare function hostAgent(agent: Agent, options?: {
54
56
  uploads?: Uploads;
55
57
  thumbnail?: Thumbnail;
56
58
  labels?: LabelsRuntime;
59
+ approvals?: Approvals;
57
60
  }): Promise<AgentHost>;
58
61
  interface Served {
59
62
  trusted: AgentControl;
@@ -63,6 +66,7 @@ interface Served {
63
66
  settings: AgentSettings;
64
67
  remote: AgentRemote;
65
68
  pages: Pages;
69
+ decide: (by: DecidedBy) => AgentControl['decide'];
66
70
  }
67
71
  export declare function serveAgent(serving: Served): Host;
68
72
  export {};
@@ -1,5 +1,6 @@
1
1
  export { ADOBE, ADOBE_PROXY, type AdobeConfig, type AdobeModelInfo, adobeClassifiers, adobeConfig, adobeIdentity, adobeModel, adobeProvider, adobeUsage, type Budget, SESSION_HEADER, VERSION_HEADER, withAdobeIdentity, } from './adobe.ts';
2
2
  export { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';
3
+ export { APPROVAL_MS, type Approval, type ApprovalAnswer, type ApprovalDecided, type ApprovalDraft, type ApprovalKind, type ApprovalRequester, type ApprovalState, type Approvals, ApprovalsDoc, type ApprovalTier, type ApprovalVerdict, attachApprovals, type DecidedBy, REASONS, } from './approvals/index.ts';
3
4
  export { FILE_LIMIT, IMAGE_LIMIT, type SendAttachment, type ShownAttachment, splitUser, TOTAL_LIMIT, userParts, } from './attachments.ts';
4
5
  export { type AgentConnection, connectAgent } from './client.ts';
5
6
  export { createAgentControl } from './control.ts';
@@ -1,5 +1,6 @@
1
1
  import type { Context, JsonValue, RemoteContract, ReplicatedState } from '@earendil-works/chord';
2
2
  import type { ConversationView } from '@earendil-works/pi-durable';
3
+ import type { Approval, ApprovalAnswer, ApprovalDecided } from './approvals/index.ts';
3
4
  import type { SendAttachment, ShownAttachment } from './attachments.ts';
4
5
  import type { ChangesView } from './changes/git.ts';
5
6
  import type { FrozenCone } from './freezer/index.ts';
@@ -87,6 +88,7 @@ export interface AgentControl {
87
88
  image(ref: ImageRef, context: Context): Promise<StoredImage>;
88
89
  agentCommands(agentId: string, context: Context): Promise<Command[]>;
89
90
  toolLabel(agentId: string, callIds: string[], context: Context): Promise<string | null>;
91
+ decide(id: string, decision: ApprovalAnswer, reason: string | null, context: Context): Promise<ApprovalDecided>;
90
92
  }
91
93
  export interface ImageRef {
92
94
  entry: number;
@@ -231,7 +233,7 @@ export interface AgentSettingsChange {
231
233
  thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;
232
234
  agentId?: string | null;
233
235
  }
234
- export declare const CONTROL_METHODS: ("abort" | "agentCommands" | "changeAccept" | "changeRevert" | "changesOpen" | "compact" | "compactAgent" | "configure" | "createCone" | "createScoop" | "discard" | "drop" | "freeze" | "image" | "memoryRemove" | "memorySave" | "monitorClose" | "monitorOpen" | "newChat" | "reset" | "resolveAgentLick" | "resolveLick" | "rewind" | "rewindAgent" | "selectCone" | "send" | "sprinkleCall" | "sprinkleSend" | "stopAgent" | "thaw" | "toolLabel" | "unqueue" | "wait" | "webhook" | "withdraw")[];
236
+ export declare const CONTROL_METHODS: ("abort" | "agentCommands" | "changeAccept" | "changeRevert" | "changesOpen" | "compact" | "compactAgent" | "configure" | "createCone" | "createScoop" | "decide" | "discard" | "drop" | "freeze" | "image" | "memoryRemove" | "memorySave" | "monitorClose" | "monitorOpen" | "newChat" | "reset" | "resolveAgentLick" | "resolveLick" | "rewind" | "rewindAgent" | "selectCone" | "send" | "sprinkleCall" | "sprinkleSend" | "stopAgent" | "thaw" | "toolLabel" | "unqueue" | "wait" | "webhook" | "withdraw")[];
235
237
  export declare const CONTROL_READS: readonly (keyof AgentControl & string)[];
236
238
  export declare const AgentControl: RemoteContract;
237
239
  export type Delivered = 'run' | 'steer' | 'follow-up';
@@ -250,6 +252,7 @@ export interface AgentTranscript {
250
252
  readonly monitor: ReplicatedState<MonitorFeed>;
251
253
  readonly vault: ReplicatedState<VaultState>;
252
254
  readonly labels: ReplicatedState<Record<string, string>>;
255
+ readonly approvals: ReplicatedState<Approval[]>;
253
256
  }
254
257
  export interface PrivateRevision {
255
258
  revision: number;
@@ -259,7 +262,7 @@ export interface Command {
259
262
  description: string;
260
263
  kind: 'prompt' | 'skill' | 'action';
261
264
  }
262
- export declare const TRANSCRIPT_STATES: ("agents" | "changes" | "commands" | "deliveries" | "frozen" | "labels" | "memories" | "memoryScopes" | "monitor" | "privateRevision" | "sprinkles" | "state" | "vault" | "views")[];
265
+ export declare const TRANSCRIPT_STATES: ("agents" | "approvals" | "changes" | "commands" | "deliveries" | "frozen" | "labels" | "memories" | "memoryScopes" | "monitor" | "privateRevision" | "sprinkles" | "state" | "vault" | "views")[];
263
266
  export declare const AgentTranscript: RemoteContract;
264
267
  export declare const REMOTE_METHODS: ("abort" | "close" | "next" | "prompt" | "watch")[];
265
268
  export declare const REMOTE_READS: readonly (keyof AgentRemote & string)[];
@@ -0,0 +1,13 @@
1
+ import type { Approval, ApprovalDecision, ApprovalsEvents, ApprovalsPort } from '@ai-ecoverse/slicc-spectrum/ui';
2
+ import type { Approval as Item } from '../approvals/record.ts';
3
+ import type { AgentConnection } from '../client.ts';
4
+ import { Emitter } from './emitter.ts';
5
+ export declare function shown(item: Item, agentName: string | undefined): Approval;
6
+ export type HostApprovals = ApprovalsPort;
7
+ export declare const NOT_HERE = "This request can't be answered in this tab.";
8
+ export declare class ApprovalsAdapter extends Emitter<ApprovalsEvents> implements ApprovalsPort {
9
+ #private;
10
+ readonly decide?: (id: string, decision: ApprovalDecision, reason?: string) => Promise<void>;
11
+ constructor(connection: AgentConnection, host?: HostApprovals);
12
+ list(): readonly Approval[];
13
+ }
@@ -1,6 +1,7 @@
1
1
  import type { MonitorSection } from '@ai-ecoverse/slicc-spectrum/ui';
2
2
  import type { AgentConnection } from '../client.ts';
3
3
  import { AgentAdapter } from './agent-port.ts';
4
+ import { ApprovalsAdapter, type HostApprovals } from './approvals-port.ts';
4
5
  import { ChangesAdapter } from './changes-port.ts';
5
6
  import { MemoryAdapter } from './memory-port.ts';
6
7
  import { MonitorAdapter } from './monitor-port.ts';
@@ -10,6 +11,7 @@ import { type Login, SettingsAdapter } from './settings-port.ts';
10
11
  import { SprinkleAdapter } from './sprinkle-port.ts';
11
12
  import { TrayAdapter } from './tray-port.ts';
12
13
  export { AgentAdapter, CONE } from './agent-port.ts';
14
+ export { ApprovalsAdapter, type HostApprovals, NOT_HERE, shown as shownApproval, } from './approvals-port.ts';
13
15
  export { ChangesAdapter, type ChangesEvents } from './changes-port.ts';
14
16
  export { MemoryAdapter } from './memory-port.ts';
15
17
  export { assistant, errorAction, errorPart, isBusy, queued, textOf, toMessages, } from './messages.ts';
@@ -26,9 +28,11 @@ export declare function createAgentModel(connection: AgentConnection, options?:
26
28
  extra?: () => readonly MonitorSection[];
27
29
  };
28
30
  page?: PageOptions;
31
+ approvals?: HostApprovals;
29
32
  notices?: HostNotices;
30
33
  }): {
31
34
  agent: AgentAdapter;
35
+ approvals: ApprovalsAdapter;
32
36
  settings: SettingsAdapter;
33
37
  tray: TrayAdapter;
34
38
  sprinkles: SprinkleAdapter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-agent",
3
- "version": "5.0.3",
3
+ "version": "5.1.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",
@@ -64,7 +64,7 @@
64
64
  "@ai-ecoverse/slicc-kernel": "1.94.0",
65
65
  "@ai-ecoverse/slicc-scrub": "1.0.0",
66
66
  "@ai-ecoverse/slicc-shared-web": "1.20.0",
67
- "@ai-ecoverse/slicc-spectrum": "1.77.1",
67
+ "@ai-ecoverse/slicc-spectrum": "1.79.0",
68
68
  "@ai-ecoverse/wasm-bash": "5.3.0-18",
69
69
  "@ai-ecoverse/wasm-coreutils": "9.12.0-6",
70
70
  "@ai-ecoverse/wasm-git": "2.55.0-15",
@@ -92,7 +92,7 @@
92
92
  },
93
93
  "peerDependencies": {
94
94
  "@ai-ecoverse/slicc-kernel": ">=1.90.0 <2",
95
- "@ai-ecoverse/slicc-spectrum": "^1.75.0"
95
+ "@ai-ecoverse/slicc-spectrum": "^1.78.0"
96
96
  },
97
97
  "peerDependenciesMeta": {
98
98
  "@ai-ecoverse/slicc-spectrum": {