@ai-ecoverse/slicc-agent 5.7.0 → 5.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -6
- package/dist/agent.js +4 -2
- package/dist/agent.js.map +2 -2
- package/dist/approvals/record.js.map +1 -1
- package/dist/control.js +2 -1
- package/dist/control.js.map +2 -2
- package/dist/guests/guard.js +168 -23
- package/dist/guests/guard.js.map +3 -3
- package/dist/guests/index.js +13 -4
- package/dist/guests/index.js.map +2 -2
- package/dist/guests/seats.js.map +2 -2
- package/dist/host.js +13 -8
- package/dist/host.js.map +2 -2
- package/dist/services.js +2 -0
- package/dist/services.js.map +2 -2
- package/dist/types/agent.d.ts +2 -0
- package/dist/types/approvals/record.d.ts +2 -0
- package/dist/types/control.d.ts +1 -1
- package/dist/types/guests/guard.d.ts +29 -2
- package/dist/types/guests/index.d.ts +3 -0
- package/dist/types/guests/seats.d.ts +9 -0
- package/dist/types/services.d.ts +4 -1
- package/package.json +4 -4
package/dist/guests/guard.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/guests/guard.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n defineExtension,\n type Extension,\n type Harness,\n hook,\n LiveDoc,\n ToolTask,\n} from '@earendil-works/pi-durable';\n\nexport const GUEST_GUARD = 'slicc-guest-guard';\nexport const GUEST_REQUEST = 'guest:';\nexport const
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { awaitWithContext, BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport {\n defineExtension,\n type Extension,\n type Harness,\n type HookApi,\n hook,\n LiveDoc,\n type SubmissionId,\n type TaskId,\n type ToolHookCall,\n ToolTask,\n} from '@earendil-works/pi-durable';\nimport type { Approval, Approvals } from '../approvals/index.ts';\nimport { REASONS } from '../approvals/record.ts';\nimport { type GuestPolicy, gateKind, gateRefusal } from './policy.ts';\nimport { type AlwaysTool, GuestsDoc, isGate, liveSeat, type SeatRecord } from './seats.ts';\n\nexport const GUEST_GUARD = 'slicc-guest-guard';\nexport const GUEST_REQUEST = 'guest:';\nexport const GUEST_TOOL_MEMO = 'slicc.guest-tool';\nexport const SUMMARY_LENGTH = 2000;\n\nexport const GATE_REASONS = {\n unknown:\n 'A guest started this run, and its seat names no review for tool calls that this agent knows.',\n ended: \"A guest started this run, and that guest's seat has ended.\",\n rejected: 'The owner declined this tool call in a run a guest started.',\n judged: 'The automatic check declined this tool call in a run a guest started',\n unanswered: 'Nobody approved this tool call in a run a guest started in time.',\n unroutable: \"The cone can't review a tool call it is itself waiting on.\",\n scoop: \"No scoop can review a guest's tool call yet, so this one is denied.\",\n withdrawn: 'The review of this tool call was withdrawn.',\n} as const;\n\nexport interface GateHost {\n approvals: Pick<Approvals, 'state' | 'request' | 'settled' | 'withdraw'>;\n policy(): GuestPolicy;\n now?: () => number;\n}\n\nexport interface GuestToolGate {\n readonly extension: Extension;\n bind(host: GateHost): void;\n}\n\ntype Held = Pick<Harness, 'submission' | 'commit' | 'waitForTask'>;\n\ntype Taint = { seat: SeatRecord | null; tier: string };\n\nexport function canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;\n if (value && typeof value === 'object')\n return `{${Object.keys(value)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${canonical((value as Record<string, unknown>)[key])}`)\n .join(',')}}`;\n return JSON.stringify(value ?? null);\n}\n\nexport function summaryOf(args: Record<string, unknown>): string {\n const values = Object.values(args);\n const text = values.length === 1 && typeof values[0] === 'string' ? values[0] : canonical(args);\n return text.length > SUMMARY_LENGTH ? `${text.slice(0, SUMMARY_LENGTH - 1)}\u2026` : text;\n}\n\nexport function reasonOf(item: Approval): string {\n if (item.state === 'rejected' && item.decidedBy === 'judge')\n return item.verdict\n ? `${GATE_REASONS.judged}: ${item.verdict.reason}`\n : `${GATE_REASONS.judged}.`;\n if (item.state === 'rejected')\n return item.reason && item.reason !== REASONS.unknownAnswer\n ? `${GATE_REASONS.rejected} ${item.reason}`\n : GATE_REASONS.rejected;\n if (item.state === 'withdrawn') return GATE_REASONS.withdrawn;\n if (item.reason === REASONS.unknownTier) return GATE_REASONS.unknown;\n if (item.reason === REASONS.unroutable) return GATE_REASONS.unroutable;\n return GATE_REASONS.unanswered;\n}\n\nasync function taintsOf(\n inputs: readonly SubmissionId[],\n seats: Readonly<Record<string, SeatRecord>>,\n harness: Held,\n context: Context\n): Promise<Taint[]> {\n const found = new Map<string, Taint>();\n for (const id of inputs) {\n const seat = Object.values(seats).find((record) =>\n record.submissions?.some((entry) => entry.id === String(id))\n );\n const tier = seat?.submissions?.find((entry) => entry.id === String(id))?.tools;\n if (seat) {\n found.set(`${seat.id}\\n${tier}`, { seat, tier: String(tier) });\n continue;\n }\n const submission = await harness.submission(id, context);\n const record = submission ? await submission.status(context) : undefined;\n if (record?.requestId?.startsWith(GUEST_REQUEST)) return [{ seat: null, tier: '' }];\n }\n return [...found.values()];\n}\n\nfunction settledEarly(\n seat: SeatRecord,\n tier: string,\n policy: GuestPolicy,\n at: number,\n tool: string,\n args: string\n): string | null {\n if (!policy.allowedToolGates.includes(gateKind(tier)))\n return gateRefusal(\"a guest's tool calls\", policy.allowedToolGates);\n if (!liveSeat(seat, at)) return GATE_REASONS.ended;\n if (tier === 'off') return '';\n if (gateKind(tier) === 'scoop') return GATE_REASONS.scoop;\n const kept = seat.alwaysTools?.some((rule) => rule.tool === tool && rule.arguments === args);\n return policy.always.tools && kept ? '' : null;\n}\n\nconst ended = (status: string) => status === 'terminal' || status === 'completing';\n\nexport function guestToolGate(harness: () => Held | undefined): GuestToolGate {\n let resolveHost: (host: GateHost) => void = () => {};\n const bound = new Promise<GateHost>((resolve) => {\n resolveHost = resolve;\n });\n const watched = new Set<string>();\n const watch = (host: GateHost, id: string, task: number) => {\n const held = harness();\n if (!held || watched.has(id)) return;\n watched.add(id);\n void held\n .waitForTask(task as unknown as TaskId, BACKGROUND_CONTEXT)\n .then((record) =>\n ended(record.state.status)\n ? host.approvals.withdraw(id, REASONS.aborted, BACKGROUND_CONTEXT)\n : undefined\n )\n .catch(() => undefined)\n .finally(() => watched.delete(id));\n };\n const remember = (seat: string, rule: AlwaysTool) =>\n (harness() as Held).commit(async (tx) => {\n const record = (await tx.doc(GuestsDoc)).seats[seat];\n if (!record || record.revoked !== null) return;\n const kept = (record.alwaysTools ?? []).filter(\n (entry) => entry.tool !== rule.tool || entry.arguments !== rule.arguments\n );\n record.alwaysTools = [...kept, rule];\n }, BACKGROUND_CONTEXT);\n const review = async (\n taint: Taint,\n call: ToolHookCall,\n api: HookApi,\n context: Context\n ): Promise<string | undefined> => {\n const { seat } = taint;\n if (seat === null || !isGate(taint.tier)) return GATE_REASONS.unknown;\n const host = await awaitWithContext(bound, context);\n const policy = host.policy();\n const now = host.now ?? Date.now;\n const args = canonical(call.arguments);\n const always = policy.always.tools;\n const early = settledEarly(seat, taint.tier, policy, now(), call.name, args);\n if (early !== null) return early || undefined;\n const id = await api.memo<string>(\n `${GUEST_TOOL_MEMO}:${seat.id}:${taint.tier}`,\n `apr-${crypto.randomUUID()}`,\n context\n );\n const task = Number(api.taskId);\n const asked = await host.approvals.request(\n {\n id,\n kind: 'guest-tool',\n seat: seat.id,\n agentId: seat.agentId,\n requester: { kind: 'guest', name: seat.label, seat: seat.id },\n tier: taint.tier,\n detail: { tool: call.name, summary: summaryOf(call.arguments), arguments: args, task },\n },\n BACKGROUND_CONTEXT\n );\n watch(host, id, task);\n const live = async () =>\n liveSeat((await api.snapshot(GuestsDoc, context))?.seats[seat.id], now());\n if (!(await live())) {\n await host.approvals.withdraw(id, REASONS.revoked, BACKGROUND_CONTEXT);\n return GATE_REASONS.ended;\n }\n const item = asked.state === 'pending' ? await host.approvals.settled(id, context) : asked;\n if (item.state !== 'approved') return reasonOf(item);\n if (!(await live())) return GATE_REASONS.ended;\n if (item.answer === 'always' && always)\n await remember(seat.id, {\n approval: item.id,\n tool: call.name,\n arguments: args,\n by: item.decidedBy,\n at: item.decidedAt ?? now(),\n });\n return undefined;\n };\n return {\n extension: defineExtension({\n name: GUEST_GUARD,\n hooks: [\n hook(ToolTask, {\n async beforeTool(call, api, context) {\n const live = await api.snapshot(LiveDoc, api.conversationId, context);\n const inputs = live?.run?.inputs ?? [];\n if (!inputs.length) return undefined;\n const seats = (await api.snapshot(GuestsDoc, context))?.seats ?? {};\n const held = harness() as Held;\n for (const taint of await taintsOf(inputs, seats, held, context)) {\n const block = await review(taint, call, api, context);\n if (block) return { block };\n }\n return undefined;\n },\n }),\n ],\n }),\n bind(host) {\n resolveHost(host);\n for (const item of host.approvals.state.value ?? [])\n if (item.kind === 'guest-tool' && item.state === 'pending' && item.detail.task)\n watch(host, item.id, item.detail.task);\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["record"]
|
|
7
7
|
}
|
package/dist/guests/index.js
CHANGED
|
@@ -136,6 +136,15 @@ async function place(record, prepared, options, using, at) {
|
|
|
136
136
|
return { state: "queued", submissionId: null, review: id, reason: null };
|
|
137
137
|
}, using);
|
|
138
138
|
}
|
|
139
|
+
function forgotten(harness, id, approval, using) {
|
|
140
|
+
return harness.commit(async (tx) => {
|
|
141
|
+
const record = (await tx.doc(GuestsDoc)).seats[id];
|
|
142
|
+
const kept = record?.alwaysTools?.filter((rule) => rule.approval !== approval);
|
|
143
|
+
if (!record || !kept || kept.length === record.alwaysTools?.length) return { removed: false };
|
|
144
|
+
record.alwaysTools = kept;
|
|
145
|
+
return { removed: true };
|
|
146
|
+
}, using);
|
|
147
|
+
}
|
|
139
148
|
function keyedLine() {
|
|
140
149
|
const locks = /* @__PURE__ */ new Map();
|
|
141
150
|
return (id, run) => {
|
|
@@ -158,7 +167,8 @@ function shownSeats(records, links, at, pendingOf) {
|
|
|
158
167
|
expiresAt: record.expiresAt,
|
|
159
168
|
gates: { ...record.gates },
|
|
160
169
|
connected: (links.get(record.id) ?? 0) > 0,
|
|
161
|
-
pending: pendingOf(record.id)
|
|
170
|
+
pending: pendingOf(record.id),
|
|
171
|
+
alwaysTools: copy(record.alwaysTools ?? [])
|
|
162
172
|
}));
|
|
163
173
|
}
|
|
164
174
|
async function createGuests(options) {
|
|
@@ -276,9 +286,7 @@ async function createGuests(options) {
|
|
|
276
286
|
const changed = await write((all) => {
|
|
277
287
|
const record = all[id];
|
|
278
288
|
if (!record || record.revoked !== null) return void 0;
|
|
279
|
-
record
|
|
280
|
-
record.epoch += 1;
|
|
281
|
-
return record;
|
|
289
|
+
return Object.assign(record, { revoked: at, epoch: record.epoch + 1, alwaysTools: [] });
|
|
282
290
|
});
|
|
283
291
|
if (!changed) return { revoked: false };
|
|
284
292
|
records[id] = changed;
|
|
@@ -287,6 +295,7 @@ async function createGuests(options) {
|
|
|
287
295
|
await ending;
|
|
288
296
|
return { revoked: true };
|
|
289
297
|
},
|
|
298
|
+
forgetAlways: (id, approval, using) => forgotten(harness, id, approval, using),
|
|
290
299
|
admit(id, label) {
|
|
291
300
|
const record = records[id];
|
|
292
301
|
if (!record || !liveSeat(record, now()) || record.label !== cleanLabel(label)) return null;
|
package/dist/guests/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/guests/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { type Context, type ReplicatedState, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { type DocumentState, type Harness, InboxDoc } from '@earendil-works/pi-durable';\nimport type { Agents } from '../agents.ts';\nimport type { Approvals } from '../approvals/index.ts';\nimport type { ApprovalPolicies } from '../approvals/policy.ts';\nimport { scrubText } from '../secrets/scrub.ts';\nimport type { GuestPrincipal } from '../serving.ts';\nimport {\n ASKED_KIND,\n GUEST_INPUT_KIND,\n type GuestAsked,\n type GuestInput,\n guestContent,\n} from './attribution.ts';\nimport { GUEST_REQUEST } from './guard.ts';\nimport { DEFAULT_GUEST_POLICY, type GuestPolicy } from './policy.ts';\nimport {\n endReview,\n type GuestReviews,\n GuestReviewsDoc,\n KEPT_SUBMISSIONS,\n liveReviews,\n MAX_QUEUED,\n pruneReviews,\n type ReviewsState,\n told,\n} from './review.ts';\nimport {\n checkDraft,\n cleanLabel,\n type GuestDraft,\n type GuestSeat,\n GuestsDoc,\n type GuestsState,\n liveSeat,\n MAX_SEAT_MS,\n type SeatRecord,\n} from './seats.ts';\n\nexport type GuestOpened = { seat: GuestSeat; error: null } | { seat: null; error: string };\n\nexport type Proposed =\n | { state: 'submitted'; submissionId: string; reason: null }\n | { state: 'queued'; submissionId: null; review: string; reason: null }\n | { state: 'unanswered'; submissionId: null; reason: string };\n\nexport interface ProposeRequest {\n text: string;\n requestId: string | null;\n}\n\nexport interface Guests {\n readonly seats: ReplicatedState<GuestSeat[]>;\n readonly reviews: ReplicatedState<ReviewsState | null>;\n open(draft: GuestDraft, context: Context): Promise<GuestOpened>;\n revoke(id: string, context: Context): Promise<{ revoked: boolean }>;\n admit(id: string, label: string): GuestPrincipal | null;\n record(id: string): SeatRecord | undefined;\n current(guest: GuestPrincipal): SeatRecord | undefined;\n joined(id: string): () => void;\n onEnd(listener: (id: string) => void): () => void;\n propose(guest: GuestPrincipal, request: ProposeRequest, context: Context): Promise<Proposed>;\n policy(): GuestPolicy;\n dispose(): void;\n}\n\nexport interface GuestsOptions {\n harness: Pick<Harness, 'commit' | 'abortSubmission' | 'documentState'>;\n agents: Pick<Agents, 'state' | 'conversation'>;\n approvals?: Pick<Approvals, 'state' | 'request' | 'withdrawSeat' | 'expire' | 'withdraw'>;\n policy?: Pick<ApprovalPolicies, 'current'>;\n reviews?: Pick<GuestReviews, 'task' | 'bind'>;\n now?: () => number;\n context?: Context;\n}\n\nexport const MAX_PROPOSAL = 32_000;\nconst MAX_REQUEST = 128;\nconst LONGEST_TIMER = 2 ** 31 - 1;\n\nconst copy = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n\nconst unanswered = (reason: string): Proposed => ({\n state: 'unanswered',\n submissionId: null,\n reason,\n});\n\nfunction prune(all: Record<string, SeatRecord>, at: number) {\n for (const [id, record] of Object.entries(all)) {\n const over = record.revoked ?? record.expiresAt;\n if (over !== null && at - over > MAX_SEAT_MS) delete all[id];\n }\n}\n\nasync function withdrawQueued(\n harness: GuestsOptions['harness'],\n agents: GuestsOptions['agents'],\n record: SeatRecord,\n using: Context\n) {\n const conversation = await agents.conversation(record.agentId, using);\n if (!conversation) return;\n const queued = await harness.commit(\n async (tx) =>\n (await tx.doc(InboxDoc, conversation.id)).items\n .filter((item) => {\n const entry = item.entry as { kind?: string; data?: { seat?: unknown } } | undefined;\n return entry?.kind === GUEST_INPUT_KIND && entry.data?.seat === record.id;\n })\n .map((item) => item.id),\n using\n );\n for (const id of queued) await harness.abortSubmission(id, using, conversation.id);\n}\n\nasync function deliver(\n record: SeatRecord,\n text: string,\n requestId: string,\n options: GuestsOptions,\n using: Context\n): Promise<Proposed> {\n const conversation = await options.agents.conversation(record.agentId, using);\n if (!conversation) return unanswered('gone');\n const data: GuestInput = { seat: record.id, name: record.label, approval: null };\n const submitted = await conversation.submit(\n {\n type: 'input',\n content: guestContent(record.label, text),\n whenBusy: 'followUp',\n entry: { kind: GUEST_INPUT_KIND, data: { ...data } },\n requestId,\n },\n using\n );\n const id = String(submitted.id);\n await options.harness.commit(async (tx) => {\n const kept = (await tx.doc(GuestsDoc)).seats[record.id];\n if (!kept || kept.submissions?.some((entry) => entry.id === id)) return;\n kept.submissions = [\n ...(kept.submissions ?? []),\n { id, approval: null, tools: record.gates.tools },\n ].slice(-KEPT_SUBMISSIONS);\n }, using);\n return { state: 'submitted', submissionId: id, reason: null };\n}\n\ntype Prepared = { text: string; requestId: string };\n\nasync function prepare(record: SeatRecord, request: ProposeRequest): Promise<Prepared | Proposed> {\n const text = typeof request?.text === 'string' ? request.text.trim() : '';\n if (!text) return unanswered('empty');\n if (text.length > MAX_PROPOSAL) return unanswered('too-long');\n const asked =\n typeof request.requestId === 'string' &&\n request.requestId &&\n request.requestId.length <= MAX_REQUEST\n ? request.requestId\n : crypto.randomUUID();\n return { text: await scrubText(text), requestId: `${GUEST_REQUEST}${record.id}:${asked}` };\n}\n\nasync function place(\n record: SeatRecord,\n prepared: Prepared,\n options: GuestsOptions,\n using: Context,\n at: number\n): Promise<Proposed> {\n const gate = record.gates.messages;\n if (gate === 'off') return deliver(record, prepared.text, prepared.requestId, options, using);\n const { reviews } = options;\n if (!reviews || !options.approvals) return unanswered('unavailable');\n const conversation = await options.agents.conversation(record.agentId, using);\n if (!conversation) return unanswered('gone');\n return options.harness.commit(async (tx): Promise<Proposed> => {\n const doc = await tx.doc(GuestReviewsDoc);\n const again = Object.values(doc.reviews).find(\n (review) => review.seat === record.id && review.request === prepared.requestId\n );\n if (again) return { state: 'queued', submissionId: null, review: again.id, reason: null };\n if (liveReviews(doc, record.id).length > MAX_QUEUED) return unanswered('overflow');\n const id = `apr-${crypto.randomUUID()}`;\n const task = await tx.createTask(\n reviews.task,\n { review: id },\n { ownership: { kind: 'conversation' }, conversationId: conversation.id, background: true }\n );\n doc.reviews[id] = {\n id,\n seat: record.id,\n agentId: record.agentId,\n label: record.label,\n text: prepared.text,\n request: prepared.requestId,\n tier: gate,\n tools: record.gates.tools,\n n: doc.next,\n task: Number(task),\n state: 'queued',\n reason: null,\n createdAt: at,\n decidedAt: null,\n submissionId: null,\n ended: false,\n conversation: Number(conversation.id),\n };\n doc.next += 1;\n pruneReviews(doc);\n const asked: GuestAsked = {\n seat: record.id,\n name: record.label,\n review: id,\n text: prepared.text,\n at,\n };\n await tx.appendEntry(conversation.id, { kind: ASKED_KIND, data: { ...asked } });\n return { state: 'queued', submissionId: null, review: id, reason: null };\n }, using);\n}\n\nfunction keyedLine() {\n const locks = new Map<string, Promise<unknown>>();\n return <T>(id: string, run: () => Promise<T>): Promise<T> => {\n const next = (locks.get(id) ?? Promise.resolve()).then(run, run);\n const settled = next.catch(() => undefined);\n locks.set(id, settled);\n void settled.then(() => {\n if (locks.get(id) === settled) locks.delete(id);\n });\n return next;\n };\n}\n\nconst pendingIn =\n (approvals: GuestsOptions['approvals'], reviews: DocumentState<ReviewsState>) =>\n (id: string): number =>\n (approvals?.state.value ?? []).filter((item) => item.seat === id && item.state === 'pending')\n .length + liveReviews(reviews.value, id).filter((review) => review.state === 'queued').length;\n\nfunction shownSeats(\n records: Record<string, SeatRecord>,\n links: ReadonlyMap<string, number>,\n at: number,\n pendingOf: (id: string) => number\n): GuestSeat[] {\n return Object.values(records)\n .filter((record) => liveSeat(record, at))\n .sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id))\n .map((record) => ({\n id: record.id,\n label: record.label,\n agentId: record.agentId,\n createdAt: record.createdAt,\n expiresAt: record.expiresAt,\n gates: { ...record.gates },\n connected: (links.get(record.id) ?? 0) > 0,\n pending: pendingOf(record.id),\n }));\n}\n\nexport async function createGuests(options: GuestsOptions): Promise<Guests> {\n const { harness, agents } = options;\n const now = options.now ?? Date.now;\n const context = options.context ?? BACKGROUND_CONTEXT;\n const guestPolicy = () => options.policy?.current().guests ?? DEFAULT_GUEST_POLICY;\n const records: Record<string, SeatRecord> = await harness.commit(async (tx) => {\n await tx.doc(GuestReviewsDoc);\n return copy((await tx.doc(GuestsDoc)).seats);\n }, context);\n const seatsDoc = (await harness.documentState(GuestsDoc, context)) as DocumentState<GuestsState>;\n const reviews = (await harness.documentState(\n GuestReviewsDoc,\n context\n )) as DocumentState<ReviewsState>;\n const links = new Map<string, number>();\n const ended = new Set<(id: string) => void>();\n const gone = new Map<string, Promise<void>>();\n const shown = () => shownSeats(records, links, now(), pendingIn(options.approvals, reviews));\n const seats = replicatedState<GuestSeat[]>(shown());\n let timer: ReturnType<typeof setTimeout> | undefined;\n const locked = keyedLine();\n const cleanup = (record: SeatRecord, using: Context) =>\n locked(record.id, async () => {\n await withdrawQueued(harness, agents, record, using);\n await harness.commit(async (tx) => {\n const doc = await tx.doc(GuestReviewsDoc);\n for (const review of liveReviews(doc, record.id))\n if (review.state === 'queued') {\n endReview(review, 'withdrawn', 'revoked', now());\n await told(tx, review);\n }\n }, using);\n await options.approvals?.withdrawSeat(record.id, using);\n });\n const end = (id: string, using: Context = context): Promise<void> => {\n const going = gone.get(id);\n if (going !== undefined) return going;\n const cleaning = cleanup(records[id] as SeatRecord, using);\n gone.set(id, cleaning);\n for (const listener of [...ended]) listener(id);\n return cleaning;\n };\n const publish = () => {\n const at = now();\n for (const record of Object.values(records))\n if (!liveSeat(record, at)) void end(record.id).catch(() => undefined);\n seats.replace(context, shown());\n if (timer) clearTimeout(timer);\n timer = undefined;\n const next = Math.min(\n ...Object.values(records)\n .filter((record) => liveSeat(record, at) && record.expiresAt !== null)\n .map((record) => record.expiresAt as number)\n );\n if (Number.isFinite(next))\n timer = setTimeout(publish, Math.min(Math.max(0, next - at), LONGEST_TIMER));\n };\n publish();\n const offSeats = seatsDoc.subscribe((value) => {\n for (const id of Object.keys(records)) delete records[id];\n Object.assign(records, copy((value as GuestsState).seats));\n publish();\n });\n const write = (change: (seats: Record<string, SeatRecord>) => SeatRecord | undefined) =>\n harness.commit(async (tx) => {\n const doc = await tx.doc(GuestsDoc);\n const changed = change(doc.seats);\n return changed ? copy(changed) : undefined;\n }, context);\n const recount = () => seats.replace(context, shown());\n const offPending = options.approvals?.state.subscribe(recount);\n const offReviews = reviews.subscribe(recount);\n options.reviews?.bind({\n approvals: options.approvals as NonNullable<GuestsOptions['approvals']>,\n agents,\n line: locked,\n alwaysAllowed: () => guestPolicy().always.messages,\n });\n const current = (guest: GuestPrincipal) => {\n const record = records[guest.id];\n return record && liveSeat(record, now()) && record.epoch === guest.epoch ? record : undefined;\n };\n return {\n seats,\n reviews,\n async open(draft, using) {\n const at = now();\n const problem = checkDraft(draft, at, guestPolicy());\n if (problem) return { seat: null, error: problem };\n if (!agents.state().cones[draft.agentId])\n return { seat: null, error: `There is no cone ${draft.agentId}.` };\n const record: SeatRecord = {\n id: draft.id,\n label: cleanLabel(draft.label),\n agentId: draft.agentId,\n expiresAt: draft.expiresAt,\n gates: { messages: draft.gates.messages, tools: draft.gates.tools },\n createdAt: at,\n epoch: 1,\n revoked: null,\n };\n const kept = await harness.commit(async (tx) => {\n const doc = await tx.doc(GuestsDoc);\n if (doc.seats[record.id]) return null;\n prune(doc.seats, at);\n doc.seats[record.id] = copy(record);\n return copy(doc.seats);\n }, using);\n if (!kept) return { seat: null, error: 'That guest seat already exists.' };\n for (const id of Object.keys(records)) delete records[id];\n Object.assign(records, kept);\n publish();\n return { seat: shown().find((seat) => seat.id === record.id) as GuestSeat, error: null };\n },\n async revoke(id, using) {\n const at = now();\n const changed = await write((all) => {\n const record = all[id];\n if (!record || record.revoked !== null) return undefined;\n record.revoked = at;\n record.epoch += 1;\n return record;\n });\n if (!changed) return { revoked: false };\n records[id] = changed;\n const ending = end(id, using);\n publish();\n await ending;\n return { revoked: true };\n },\n admit(id, label) {\n const record = records[id];\n if (!record || !liveSeat(record, now()) || record.label !== cleanLabel(label)) return null;\n return { id: record.id, name: record.label, epoch: record.epoch };\n },\n record: (id) => records[id],\n current,\n joined(id) {\n links.set(id, (links.get(id) ?? 0) + 1);\n seats.replace(context, shown());\n let left = false;\n return () => {\n if (left) return;\n left = true;\n links.set(id, (links.get(id) ?? 1) - 1);\n seats.replace(context, shown());\n };\n },\n onEnd(listener) {\n ended.add(listener);\n return () => ended.delete(listener);\n },\n async propose(guest, request, using) {\n const record = current(guest);\n if (!record) return unanswered('revoked');\n const prepared = await prepare(record, request);\n if ('state' in prepared) return prepared;\n return locked(record.id, async () => {\n const still = current(guest);\n return still ? place(still, prepared, options, using, now()) : unanswered('revoked');\n });\n },\n policy: guestPolicy,\n dispose() {\n if (timer) clearTimeout(timer);\n offPending?.();\n offReviews();\n offSeats();\n seatsDoc.dispose();\n reviews.dispose();\n ended.clear();\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAA6C,uBAAuB;AACpE,SAAS,0BAA0B;AACnC,SAA2C,gBAAgB;AAI3D,SAAS,iBAAiB;AAE1B;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,OACK;AACP,SAAS,qBAAqB;AAC9B,SAAS,4BAA8C;AACvD;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EAEA;AAAA,EACA;AAAA,OAEK;
|
|
4
|
+
"sourcesContent": ["import { type Context, type ReplicatedState, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { type DocumentState, type Harness, InboxDoc } from '@earendil-works/pi-durable';\nimport type { Agents } from '../agents.ts';\nimport type { Approvals } from '../approvals/index.ts';\nimport type { ApprovalPolicies } from '../approvals/policy.ts';\nimport { scrubText } from '../secrets/scrub.ts';\nimport type { GuestPrincipal } from '../serving.ts';\nimport {\n ASKED_KIND,\n GUEST_INPUT_KIND,\n type GuestAsked,\n type GuestInput,\n guestContent,\n} from './attribution.ts';\nimport { GUEST_REQUEST } from './guard.ts';\nimport { DEFAULT_GUEST_POLICY, type GuestPolicy } from './policy.ts';\nimport {\n endReview,\n type GuestReviews,\n GuestReviewsDoc,\n KEPT_SUBMISSIONS,\n liveReviews,\n MAX_QUEUED,\n pruneReviews,\n type ReviewsState,\n told,\n} from './review.ts';\nimport {\n checkDraft,\n cleanLabel,\n type GuestDraft,\n type GuestSeat,\n GuestsDoc,\n type GuestsState,\n liveSeat,\n MAX_SEAT_MS,\n type SeatRecord,\n} from './seats.ts';\n\nexport type GuestOpened = { seat: GuestSeat; error: null } | { seat: null; error: string };\n\nexport type Proposed =\n | { state: 'submitted'; submissionId: string; reason: null }\n | { state: 'queued'; submissionId: null; review: string; reason: null }\n | { state: 'unanswered'; submissionId: null; reason: string };\n\nexport interface ProposeRequest {\n text: string;\n requestId: string | null;\n}\n\nexport interface Guests {\n readonly seats: ReplicatedState<GuestSeat[]>;\n readonly reviews: ReplicatedState<ReviewsState | null>;\n open(draft: GuestDraft, context: Context): Promise<GuestOpened>;\n revoke(id: string, context: Context): Promise<{ revoked: boolean }>;\n forgetAlways(id: string, approval: string, context: Context): Promise<{ removed: boolean }>;\n admit(id: string, label: string): GuestPrincipal | null;\n record(id: string): SeatRecord | undefined;\n current(guest: GuestPrincipal): SeatRecord | undefined;\n joined(id: string): () => void;\n onEnd(listener: (id: string) => void): () => void;\n propose(guest: GuestPrincipal, request: ProposeRequest, context: Context): Promise<Proposed>;\n policy(): GuestPolicy;\n dispose(): void;\n}\n\nexport interface GuestsOptions {\n harness: Pick<Harness, 'commit' | 'abortSubmission' | 'documentState'>;\n agents: Pick<Agents, 'state' | 'conversation'>;\n approvals?: Pick<Approvals, 'state' | 'request' | 'withdrawSeat' | 'expire' | 'withdraw'>;\n policy?: Pick<ApprovalPolicies, 'current'>;\n reviews?: Pick<GuestReviews, 'task' | 'bind'>;\n now?: () => number;\n context?: Context;\n}\n\nexport const MAX_PROPOSAL = 32_000;\nconst MAX_REQUEST = 128;\nconst LONGEST_TIMER = 2 ** 31 - 1;\n\nconst copy = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n\nconst unanswered = (reason: string): Proposed => ({\n state: 'unanswered',\n submissionId: null,\n reason,\n});\n\nfunction prune(all: Record<string, SeatRecord>, at: number) {\n for (const [id, record] of Object.entries(all)) {\n const over = record.revoked ?? record.expiresAt;\n if (over !== null && at - over > MAX_SEAT_MS) delete all[id];\n }\n}\n\nasync function withdrawQueued(\n harness: GuestsOptions['harness'],\n agents: GuestsOptions['agents'],\n record: SeatRecord,\n using: Context\n) {\n const conversation = await agents.conversation(record.agentId, using);\n if (!conversation) return;\n const queued = await harness.commit(\n async (tx) =>\n (await tx.doc(InboxDoc, conversation.id)).items\n .filter((item) => {\n const entry = item.entry as { kind?: string; data?: { seat?: unknown } } | undefined;\n return entry?.kind === GUEST_INPUT_KIND && entry.data?.seat === record.id;\n })\n .map((item) => item.id),\n using\n );\n for (const id of queued) await harness.abortSubmission(id, using, conversation.id);\n}\n\nasync function deliver(\n record: SeatRecord,\n text: string,\n requestId: string,\n options: GuestsOptions,\n using: Context\n): Promise<Proposed> {\n const conversation = await options.agents.conversation(record.agentId, using);\n if (!conversation) return unanswered('gone');\n const data: GuestInput = { seat: record.id, name: record.label, approval: null };\n const submitted = await conversation.submit(\n {\n type: 'input',\n content: guestContent(record.label, text),\n whenBusy: 'followUp',\n entry: { kind: GUEST_INPUT_KIND, data: { ...data } },\n requestId,\n },\n using\n );\n const id = String(submitted.id);\n await options.harness.commit(async (tx) => {\n const kept = (await tx.doc(GuestsDoc)).seats[record.id];\n if (!kept || kept.submissions?.some((entry) => entry.id === id)) return;\n kept.submissions = [\n ...(kept.submissions ?? []),\n { id, approval: null, tools: record.gates.tools },\n ].slice(-KEPT_SUBMISSIONS);\n }, using);\n return { state: 'submitted', submissionId: id, reason: null };\n}\n\ntype Prepared = { text: string; requestId: string };\n\nasync function prepare(record: SeatRecord, request: ProposeRequest): Promise<Prepared | Proposed> {\n const text = typeof request?.text === 'string' ? request.text.trim() : '';\n if (!text) return unanswered('empty');\n if (text.length > MAX_PROPOSAL) return unanswered('too-long');\n const asked =\n typeof request.requestId === 'string' &&\n request.requestId &&\n request.requestId.length <= MAX_REQUEST\n ? request.requestId\n : crypto.randomUUID();\n return { text: await scrubText(text), requestId: `${GUEST_REQUEST}${record.id}:${asked}` };\n}\n\nasync function place(\n record: SeatRecord,\n prepared: Prepared,\n options: GuestsOptions,\n using: Context,\n at: number\n): Promise<Proposed> {\n const gate = record.gates.messages;\n if (gate === 'off') return deliver(record, prepared.text, prepared.requestId, options, using);\n const { reviews } = options;\n if (!reviews || !options.approvals) return unanswered('unavailable');\n const conversation = await options.agents.conversation(record.agentId, using);\n if (!conversation) return unanswered('gone');\n return options.harness.commit(async (tx): Promise<Proposed> => {\n const doc = await tx.doc(GuestReviewsDoc);\n const again = Object.values(doc.reviews).find(\n (review) => review.seat === record.id && review.request === prepared.requestId\n );\n if (again) return { state: 'queued', submissionId: null, review: again.id, reason: null };\n if (liveReviews(doc, record.id).length > MAX_QUEUED) return unanswered('overflow');\n const id = `apr-${crypto.randomUUID()}`;\n const task = await tx.createTask(\n reviews.task,\n { review: id },\n { ownership: { kind: 'conversation' }, conversationId: conversation.id, background: true }\n );\n doc.reviews[id] = {\n id,\n seat: record.id,\n agentId: record.agentId,\n label: record.label,\n text: prepared.text,\n request: prepared.requestId,\n tier: gate,\n tools: record.gates.tools,\n n: doc.next,\n task: Number(task),\n state: 'queued',\n reason: null,\n createdAt: at,\n decidedAt: null,\n submissionId: null,\n ended: false,\n conversation: Number(conversation.id),\n };\n doc.next += 1;\n pruneReviews(doc);\n const asked: GuestAsked = {\n seat: record.id,\n name: record.label,\n review: id,\n text: prepared.text,\n at,\n };\n await tx.appendEntry(conversation.id, { kind: ASKED_KIND, data: { ...asked } });\n return { state: 'queued', submissionId: null, review: id, reason: null };\n }, using);\n}\n\nfunction forgotten(\n harness: GuestsOptions['harness'],\n id: string,\n approval: string,\n using: Context\n): Promise<{ removed: boolean }> {\n return harness.commit(async (tx) => {\n const record = (await tx.doc(GuestsDoc)).seats[id];\n const kept = record?.alwaysTools?.filter((rule) => rule.approval !== approval);\n if (!record || !kept || kept.length === record.alwaysTools?.length) return { removed: false };\n record.alwaysTools = kept;\n return { removed: true };\n }, using);\n}\n\nfunction keyedLine() {\n const locks = new Map<string, Promise<unknown>>();\n return <T>(id: string, run: () => Promise<T>): Promise<T> => {\n const next = (locks.get(id) ?? Promise.resolve()).then(run, run);\n const settled = next.catch(() => undefined);\n locks.set(id, settled);\n void settled.then(() => {\n if (locks.get(id) === settled) locks.delete(id);\n });\n return next;\n };\n}\n\nconst pendingIn =\n (approvals: GuestsOptions['approvals'], reviews: DocumentState<ReviewsState>) =>\n (id: string): number =>\n (approvals?.state.value ?? []).filter((item) => item.seat === id && item.state === 'pending')\n .length + liveReviews(reviews.value, id).filter((review) => review.state === 'queued').length;\n\nfunction shownSeats(\n records: Record<string, SeatRecord>,\n links: ReadonlyMap<string, number>,\n at: number,\n pendingOf: (id: string) => number\n): GuestSeat[] {\n return Object.values(records)\n .filter((record) => liveSeat(record, at))\n .sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id))\n .map((record) => ({\n id: record.id,\n label: record.label,\n agentId: record.agentId,\n createdAt: record.createdAt,\n expiresAt: record.expiresAt,\n gates: { ...record.gates },\n connected: (links.get(record.id) ?? 0) > 0,\n pending: pendingOf(record.id),\n alwaysTools: copy(record.alwaysTools ?? []),\n }));\n}\n\nexport async function createGuests(options: GuestsOptions): Promise<Guests> {\n const { harness, agents } = options;\n const now = options.now ?? Date.now;\n const context = options.context ?? BACKGROUND_CONTEXT;\n const guestPolicy = () => options.policy?.current().guests ?? DEFAULT_GUEST_POLICY;\n const records: Record<string, SeatRecord> = await harness.commit(async (tx) => {\n await tx.doc(GuestReviewsDoc);\n return copy((await tx.doc(GuestsDoc)).seats);\n }, context);\n const seatsDoc = (await harness.documentState(GuestsDoc, context)) as DocumentState<GuestsState>;\n const reviews = (await harness.documentState(\n GuestReviewsDoc,\n context\n )) as DocumentState<ReviewsState>;\n const links = new Map<string, number>();\n const ended = new Set<(id: string) => void>();\n const gone = new Map<string, Promise<void>>();\n const shown = () => shownSeats(records, links, now(), pendingIn(options.approvals, reviews));\n const seats = replicatedState<GuestSeat[]>(shown());\n let timer: ReturnType<typeof setTimeout> | undefined;\n const locked = keyedLine();\n const cleanup = (record: SeatRecord, using: Context) =>\n locked(record.id, async () => {\n await withdrawQueued(harness, agents, record, using);\n await harness.commit(async (tx) => {\n const doc = await tx.doc(GuestReviewsDoc);\n for (const review of liveReviews(doc, record.id))\n if (review.state === 'queued') {\n endReview(review, 'withdrawn', 'revoked', now());\n await told(tx, review);\n }\n }, using);\n await options.approvals?.withdrawSeat(record.id, using);\n });\n const end = (id: string, using: Context = context): Promise<void> => {\n const going = gone.get(id);\n if (going !== undefined) return going;\n const cleaning = cleanup(records[id] as SeatRecord, using);\n gone.set(id, cleaning);\n for (const listener of [...ended]) listener(id);\n return cleaning;\n };\n const publish = () => {\n const at = now();\n for (const record of Object.values(records))\n if (!liveSeat(record, at)) void end(record.id).catch(() => undefined);\n seats.replace(context, shown());\n if (timer) clearTimeout(timer);\n timer = undefined;\n const next = Math.min(\n ...Object.values(records)\n .filter((record) => liveSeat(record, at) && record.expiresAt !== null)\n .map((record) => record.expiresAt as number)\n );\n if (Number.isFinite(next))\n timer = setTimeout(publish, Math.min(Math.max(0, next - at), LONGEST_TIMER));\n };\n publish();\n const offSeats = seatsDoc.subscribe((value) => {\n for (const id of Object.keys(records)) delete records[id];\n Object.assign(records, copy((value as GuestsState).seats));\n publish();\n });\n const write = (change: (seats: Record<string, SeatRecord>) => SeatRecord | undefined) =>\n harness.commit(async (tx) => {\n const doc = await tx.doc(GuestsDoc);\n const changed = change(doc.seats);\n return changed ? copy(changed) : undefined;\n }, context);\n const recount = () => seats.replace(context, shown());\n const offPending = options.approvals?.state.subscribe(recount);\n const offReviews = reviews.subscribe(recount);\n options.reviews?.bind({\n approvals: options.approvals as NonNullable<GuestsOptions['approvals']>,\n agents,\n line: locked,\n alwaysAllowed: () => guestPolicy().always.messages,\n });\n const current = (guest: GuestPrincipal) => {\n const record = records[guest.id];\n return record && liveSeat(record, now()) && record.epoch === guest.epoch ? record : undefined;\n };\n return {\n seats,\n reviews,\n async open(draft, using) {\n const at = now();\n const problem = checkDraft(draft, at, guestPolicy());\n if (problem) return { seat: null, error: problem };\n if (!agents.state().cones[draft.agentId])\n return { seat: null, error: `There is no cone ${draft.agentId}.` };\n const record: SeatRecord = {\n id: draft.id,\n label: cleanLabel(draft.label),\n agentId: draft.agentId,\n expiresAt: draft.expiresAt,\n gates: { messages: draft.gates.messages, tools: draft.gates.tools },\n createdAt: at,\n epoch: 1,\n revoked: null,\n };\n const kept = await harness.commit(async (tx) => {\n const doc = await tx.doc(GuestsDoc);\n if (doc.seats[record.id]) return null;\n prune(doc.seats, at);\n doc.seats[record.id] = copy(record);\n return copy(doc.seats);\n }, using);\n if (!kept) return { seat: null, error: 'That guest seat already exists.' };\n for (const id of Object.keys(records)) delete records[id];\n Object.assign(records, kept);\n publish();\n return { seat: shown().find((seat) => seat.id === record.id) as GuestSeat, error: null };\n },\n async revoke(id, using) {\n const at = now();\n const changed = await write((all) => {\n const record = all[id];\n if (!record || record.revoked !== null) return undefined;\n return Object.assign(record, { revoked: at, epoch: record.epoch + 1, alwaysTools: [] });\n });\n if (!changed) return { revoked: false };\n records[id] = changed;\n const ending = end(id, using);\n publish();\n await ending;\n return { revoked: true };\n },\n forgetAlways: (id, approval, using) => forgotten(harness, id, approval, using),\n admit(id, label) {\n const record = records[id];\n if (!record || !liveSeat(record, now()) || record.label !== cleanLabel(label)) return null;\n return { id: record.id, name: record.label, epoch: record.epoch };\n },\n record: (id) => records[id],\n current,\n joined(id) {\n links.set(id, (links.get(id) ?? 0) + 1);\n seats.replace(context, shown());\n let left = false;\n return () => {\n if (left) return;\n left = true;\n links.set(id, (links.get(id) ?? 1) - 1);\n seats.replace(context, shown());\n };\n },\n onEnd(listener) {\n ended.add(listener);\n return () => ended.delete(listener);\n },\n async propose(guest, request, using) {\n const record = current(guest);\n if (!record) return unanswered('revoked');\n const prepared = await prepare(record, request);\n if ('state' in prepared) return prepared;\n return locked(record.id, async () => {\n const still = current(guest);\n return still ? place(still, prepared, options, using, now()) : unanswered('revoked');\n });\n },\n policy: guestPolicy,\n dispose() {\n if (timer) clearTimeout(timer);\n offPending?.();\n offReviews();\n offSeats();\n seatsDoc.dispose();\n reviews.dispose();\n ended.clear();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/guests/seats.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/guests/seats.ts"],
|
|
4
|
-
"sourcesContent": ["import { defineDoc } from '@earendil-works/pi-durable';\nimport type { ApprovalTier, DecidedBy } from '../approvals/record.ts';\nimport {\n DAY_MS,\n DEFAULT_GUEST_POLICY,\n type GuestPolicy,\n gateKind,\n gateRefusal,\n MAX_SEAT_DAYS,\n} from './policy.ts';\n\nexport type GuestGate = ApprovalTier | 'off';\n\nexport type GuestGates = {\n messages: GuestGate;\n tools: GuestGate;\n};\n\nexport type GuestDraft = {\n id: string;\n label: string;\n agentId: string;\n expiresAt: number | null;\n gates: GuestGates;\n};\n\nexport type SeatSubmission = { id: string; approval: string | null; tools: GuestGate };\n\nexport type SeatRecord = GuestDraft & {\n createdAt: number;\n epoch: number;\n revoked: number | null;\n delivered?: string[];\n submissions?: SeatSubmission[];\n always?: { by: DecidedBy | null; approval: string; at: number };\n};\n\nexport interface GuestSeat {\n id: string;\n label: string;\n agentId: string;\n createdAt: number;\n expiresAt: number | null;\n gates: GuestGates;\n connected: boolean;\n pending: number;\n}\n\nexport type GuestsState = { seats: Record<string, SeatRecord> };\n\nexport const GuestsDoc = defineDoc<GuestsState>({\n kind: 'slicc.guests',\n version: 1,\n scope: 'session',\n initial: () => ({ seats: {} }),\n});\n\nexport const MAX_SEAT_MS = MAX_SEAT_DAYS * DAY_MS;\nexport const MAX_LABEL = 64;\nconst MAX_ID = 256;\n\nexport function cleanLabel(raw: unknown): string {\n return String(raw ?? '')\n .replace(/[\\p{Cc}\\p{Cf}]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, MAX_LABEL);\n}\n\nexport function isGate(value: unknown): value is GuestGate {\n if (typeof value !== 'string') return false;\n if (value === 'user' || value === 'agent' || value === 'cone' || value === 'off') return true;\n return /^scoop:\\S+$/.test(value);\n}\n\nexport function checkDraft(\n draft: GuestDraft,\n now: number,\n policy: GuestPolicy = DEFAULT_GUEST_POLICY\n): string | null {\n if (typeof draft?.id !== 'string' || !draft.id || draft.id.length > MAX_ID)\n return 'A guest seat needs an id from the tray hub.';\n if (!cleanLabel(draft.label)) return 'A guest seat needs a label.';\n if (!isGate(draft.gates?.messages) || !isGate(draft.gates?.tools))\n return 'A guest seat needs a known gate for messages and for tools.';\n if (!policy.allowedMessageGates.includes(gateKind(draft.gates.messages)))\n return gateRefusal(\"a guest's messages\", policy.allowedMessageGates);\n if (!policy.allowedToolGates.includes(gateKind(draft.gates.tools)))\n return gateRefusal(\"a guest's tool calls\", policy.allowedToolGates);\n const { expiresAt } = draft;\n if (expiresAt !== null && (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)))\n return 'A guest seat expires at a time, or never.';\n if (expiresAt !== null && expiresAt <= now) return 'That expiry has already passed.';\n const days = policy.maxSeatDays;\n if (expiresAt !== null && expiresAt - now > days * DAY_MS)\n return `A guest seat lasts at most ${days} ${days === 1 ? 'day' : 'days'}.`;\n return null;\n}\n\nexport function liveSeat(seat: SeatRecord | undefined, now: number): boolean {\n return Boolean(\n seat && seat.revoked === null && (seat.expiresAt === null || seat.expiresAt > now)\n );\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,iBAAiB;AAE1B;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;
|
|
4
|
+
"sourcesContent": ["import { defineDoc } from '@earendil-works/pi-durable';\nimport type { ApprovalTier, DecidedBy } from '../approvals/record.ts';\nimport {\n DAY_MS,\n DEFAULT_GUEST_POLICY,\n type GuestPolicy,\n gateKind,\n gateRefusal,\n MAX_SEAT_DAYS,\n} from './policy.ts';\n\nexport type GuestGate = ApprovalTier | 'off';\n\nexport type GuestGates = {\n messages: GuestGate;\n tools: GuestGate;\n};\n\nexport type GuestDraft = {\n id: string;\n label: string;\n agentId: string;\n expiresAt: number | null;\n gates: GuestGates;\n};\n\nexport type SeatSubmission = { id: string; approval: string | null; tools: GuestGate };\n\nexport type AlwaysTool = {\n approval: string;\n tool: string;\n arguments: string;\n by: DecidedBy | null;\n at: number;\n};\n\nexport type SeatRecord = GuestDraft & {\n createdAt: number;\n epoch: number;\n revoked: number | null;\n delivered?: string[];\n submissions?: SeatSubmission[];\n always?: { by: DecidedBy | null; approval: string; at: number };\n alwaysTools?: AlwaysTool[];\n};\n\nexport interface GuestSeat {\n id: string;\n label: string;\n agentId: string;\n createdAt: number;\n expiresAt: number | null;\n gates: GuestGates;\n connected: boolean;\n pending: number;\n alwaysTools: AlwaysTool[];\n}\n\nexport type GuestsState = { seats: Record<string, SeatRecord> };\n\nexport const GuestsDoc = defineDoc<GuestsState>({\n kind: 'slicc.guests',\n version: 1,\n scope: 'session',\n initial: () => ({ seats: {} }),\n});\n\nexport const MAX_SEAT_MS = MAX_SEAT_DAYS * DAY_MS;\nexport const MAX_LABEL = 64;\nconst MAX_ID = 256;\n\nexport function cleanLabel(raw: unknown): string {\n return String(raw ?? '')\n .replace(/[\\p{Cc}\\p{Cf}]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, MAX_LABEL);\n}\n\nexport function isGate(value: unknown): value is GuestGate {\n if (typeof value !== 'string') return false;\n if (value === 'user' || value === 'agent' || value === 'cone' || value === 'off') return true;\n return /^scoop:\\S+$/.test(value);\n}\n\nexport function checkDraft(\n draft: GuestDraft,\n now: number,\n policy: GuestPolicy = DEFAULT_GUEST_POLICY\n): string | null {\n if (typeof draft?.id !== 'string' || !draft.id || draft.id.length > MAX_ID)\n return 'A guest seat needs an id from the tray hub.';\n if (!cleanLabel(draft.label)) return 'A guest seat needs a label.';\n if (!isGate(draft.gates?.messages) || !isGate(draft.gates?.tools))\n return 'A guest seat needs a known gate for messages and for tools.';\n if (!policy.allowedMessageGates.includes(gateKind(draft.gates.messages)))\n return gateRefusal(\"a guest's messages\", policy.allowedMessageGates);\n if (!policy.allowedToolGates.includes(gateKind(draft.gates.tools)))\n return gateRefusal(\"a guest's tool calls\", policy.allowedToolGates);\n const { expiresAt } = draft;\n if (expiresAt !== null && (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)))\n return 'A guest seat expires at a time, or never.';\n if (expiresAt !== null && expiresAt <= now) return 'That expiry has already passed.';\n const days = policy.maxSeatDays;\n if (expiresAt !== null && expiresAt - now > days * DAY_MS)\n return `A guest seat lasts at most ${days} ${days === 1 ? 'day' : 'days'}.`;\n return null;\n}\n\nexport function liveSeat(seat: SeatRecord | undefined, now: number): boolean {\n return Boolean(\n seat && seat.revoked === null && (seat.expiresAt === null || seat.expiresAt > now)\n );\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAE1B;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAmDA,MAAM,YAAY,UAAuB;AAAA,EAC9C,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS,OAAO,EAAE,OAAO,CAAC,EAAE;AAC9B,CAAC;AAEM,MAAM,cAAc,gBAAgB;AACpC,MAAM,YAAY;AACzB,MAAM,SAAS;AAER,SAAS,WAAW,KAAsB;AAC/C,SAAO,OAAO,OAAO,EAAE,EACpB,QAAQ,oBAAoB,GAAG,EAC/B,QAAQ,QAAQ,GAAG,EACnB,KAAK,EACL,MAAM,GAAG,SAAS;AACvB;AAEO,SAAS,OAAO,OAAoC;AACzD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,UAAU,UAAU,UAAU,WAAW,UAAU,UAAU,UAAU,MAAO,QAAO;AACzF,SAAO,cAAc,KAAK,KAAK;AACjC;AAEO,SAAS,WACd,OACA,KACA,SAAsB,sBACP;AACf,MAAI,OAAO,OAAO,OAAO,YAAY,CAAC,MAAM,MAAM,MAAM,GAAG,SAAS;AAClE,WAAO;AACT,MAAI,CAAC,WAAW,MAAM,KAAK,EAAG,QAAO;AACrC,MAAI,CAAC,OAAO,MAAM,OAAO,QAAQ,KAAK,CAAC,OAAO,MAAM,OAAO,KAAK;AAC9D,WAAO;AACT,MAAI,CAAC,OAAO,oBAAoB,SAAS,SAAS,MAAM,MAAM,QAAQ,CAAC;AACrE,WAAO,YAAY,sBAAsB,OAAO,mBAAmB;AACrE,MAAI,CAAC,OAAO,iBAAiB,SAAS,SAAS,MAAM,MAAM,KAAK,CAAC;AAC/D,WAAO,YAAY,wBAAwB,OAAO,gBAAgB;AACpE,QAAM,EAAE,UAAU,IAAI;AACtB,MAAI,cAAc,SAAS,OAAO,cAAc,YAAY,CAAC,OAAO,SAAS,SAAS;AACpF,WAAO;AACT,MAAI,cAAc,QAAQ,aAAa,IAAK,QAAO;AACnD,QAAM,OAAO,OAAO;AACpB,MAAI,cAAc,QAAQ,YAAY,MAAM,OAAO;AACjD,WAAO,8BAA8B,IAAI,IAAI,SAAS,IAAI,QAAQ,MAAM;AAC1E,SAAO;AACT;AAEO,SAAS,SAAS,MAA8B,KAAsB;AAC3E,SAAO;AAAA,IACL,QAAQ,KAAK,YAAY,SAAS,KAAK,cAAc,QAAQ,KAAK,YAAY;AAAA,EAChF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/host.js
CHANGED
|
@@ -109,6 +109,18 @@ function approving(agent, policy, judge, context) {
|
|
|
109
109
|
context
|
|
110
110
|
);
|
|
111
111
|
}
|
|
112
|
+
async function guestsOf(agent, approvals, policy, context) {
|
|
113
|
+
const guests = await createGuests({
|
|
114
|
+
harness: agent.harness,
|
|
115
|
+
agents: agent.agents,
|
|
116
|
+
approvals,
|
|
117
|
+
policy,
|
|
118
|
+
reviews: agent.reviews,
|
|
119
|
+
context
|
|
120
|
+
});
|
|
121
|
+
agent.gate.bind({ approvals, policy: () => guests.policy() });
|
|
122
|
+
return guests;
|
|
123
|
+
}
|
|
112
124
|
const noRevision = () => replicatedState({ revision: 0 });
|
|
113
125
|
async function hostAgent(agent, options = {}) {
|
|
114
126
|
const context = options.context ?? BACKGROUND_CONTEXT;
|
|
@@ -136,14 +148,7 @@ async function hostAgent(agent, options = {}) {
|
|
|
136
148
|
views: mounted.views,
|
|
137
149
|
context
|
|
138
150
|
});
|
|
139
|
-
const guests = await
|
|
140
|
-
harness: agent.harness,
|
|
141
|
-
agents: agent.agents,
|
|
142
|
-
approvals,
|
|
143
|
-
policy,
|
|
144
|
-
reviews: agent.reviews,
|
|
145
|
-
context
|
|
146
|
-
});
|
|
151
|
+
const guests = await guestsOf(agent, approvals, policy, context);
|
|
147
152
|
const control = {
|
|
148
153
|
...createAgentControl(
|
|
149
154
|
agent.harness,
|
package/dist/host.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/host.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n createHost,\n forbidden,\n type Host,\n type Readable,\n type ReplicatedState,\n replicatedState,\n resource,\n type Self,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { Agent } from './agent.ts';\nimport {\n type ApprovalJudge,\n type Approvals,\n attachApprovals,\n type Decider,\n} from './approvals/index.ts';\nimport { type ApprovalPolicies, alwaysFor, attachApprovalPolicy } from './approvals/policy.ts';\nimport { type AgentSudo, createSudo, ownedSudo } from './approvals/sudo.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport { createAgentControl, type HostLicks, type HostScoops } from './control.ts';\nimport { trackDeliveries } from './deliveries.ts';\nimport type { FreezerRuntime, FrozenCone } from './freezer/index.ts';\nimport { createGuests, type Guests } from './guests/index.ts';\nimport { admitGuest, guestOpener } from './guests/serve.ts';\nimport type { UserClients } from './kernel/users.ts';\nimport type { McpRuntime } from './mcp/index.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport { createMonitor, type MonitorOptions } from './monitor/index.ts';\nimport { viewRemote } from './readonly.ts';\nimport { type AgentRemote, createRemote } from './remote/host.ts';\nimport { createPages, ownedPages, type Pages } from './remote/pages.ts';\nimport type { SecretName } from './secrets/names.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport {\n AgentControl,\n type AgentGuest,\n AgentGuestService,\n AgentPagesService,\n AgentRemoteService,\n AgentSettings,\n AgentSudoService,\n AgentTranscript,\n CONTROL_METHODS,\n CONTROL_READS,\n type Command,\n GUEST_METHODS,\n OWNER_DEVICE_METHODS,\n PAGE_METHODS,\n type PrivateRevision,\n REMOTE_METHODS,\n REMOTE_READS,\n SETTINGS_METHODS,\n SUDO_METHODS,\n} from './services.ts';\nimport {\n AGENT_HOST,\n type AgentPrincipal,\n deviceOf,\n type GuestPrincipal,\n guestOf,\n principalKey,\n readable,\n readablesOf,\n type Seat,\n seatOf,\n served,\n} from './serving.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\nimport { slimmer, type Thumbnail, thumbnail } from './thumbs.ts';\nimport { type LabelsRuntime, visibleLabels, watchLabel } from './titles/labels.ts';\nimport type { Uploads } from './uploads.ts';\nimport { agentViews } from './views.ts';\nimport { type PortEndpoint, PortLink } from './wire.ts';\n\nexport interface ConnectOptions {\n readOnly?: boolean;\n pages?: boolean;\n guest?: { id: string; label: string };\n device?: string;\n}\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n readonly users?: UserClients;\n readonly pages: Pages;\n readonly guests: Guests;\n readonly approvals: Approvals;\n connect(endpoint: PortEndpoint, options?: ConnectOptions): void;\n close(): Promise<void>;\n}\n\nconst noSettings: AgentSettings = {\n state: replicatedState({ models: [], accounts: [] }),\n connect: async () => {\n throw new Error('this agent has no accounts');\n },\n disconnect: async () => {},\n signIn: async () => null,\n dismissMoved: async () => {},\n};\n\nasync function follow(\n agent: Agent,\n context: Context,\n slim: (view: ConversationView) => ConversationView\n) {\n let attached = await agent.cone().viewState(context);\n const state = replicatedState<ConversationView>(slim(attached.value));\n const mirror = (value: ConversationView, from: Context) => state.replace(from, slim(value));\n let off = attached.subscribe(mirror);\n const stop = agent.onCone(async (conversation) => {\n const next = await conversation.viewState(context);\n off();\n attached.dispose();\n attached = next;\n state.replace(context, slim(next.value));\n off = next.subscribe(mirror);\n });\n return {\n state,\n refresh: () => state.replace(context, slim(attached.value)),\n dispose() {\n stop();\n off();\n attached.dispose();\n },\n };\n}\n\nexport interface HostSecrets {\n vault: ReplicatedState<VaultState>;\n list(): readonly SecretName[];\n close?(): void;\n}\n\nconst idleVault = replicatedState<VaultState>({\n port: 'none',\n needed: false,\n version: 0,\n locked: 'no',\n held: 0,\n});\n\nfunction gatedControls(\n control: AgentControl,\n shown: (entry: number) => boolean,\n views: () => readonly ConversationView[],\n labels: ReplicatedState<Record<string, string>>\n) {\n const visible = (entry: number) =>\n views().some((view) => view.entries.some((item) => item.id === entry));\n const gated =\n (allowed: (entry: number) => boolean): AgentControl['image'] =>\n async (ref, using) =>\n allowed(ref.entry) ? control.image(ref, using) : { data: null, mimeType: null };\n const trusted: AgentControl = { ...control, image: gated(shown) };\n const viewed: AgentControl = { ...control, image: gated(visible), toolLabel: watchLabel(labels) };\n return { trusted, viewed };\n}\n\nfunction approving(\n agent: Agent,\n policy: ApprovalPolicies,\n judge: ApprovalJudge | undefined,\n context: Context\n): Promise<Approvals> {\n return attachApprovals(\n {\n harness: agent.harness,\n guestAlways: alwaysFor(policy),\n sudoApprover: () => policy.current().sudo.approver,\n ...(judge ? { judge } : {}),\n },\n context\n );\n}\n\nconst noRevision = () => replicatedState<PrivateRevision>({ revision: 0 });\n\nexport async function hostAgent(\n agent: Agent,\n options: {\n serverId?: string;\n context?: Context;\n settings?: AgentSettings;\n licks?: HostLicks;\n scoops?: HostScoops;\n skills?: SkillsRuntime;\n sprinkles?: SprinklesRuntime;\n memory?: MemoryRuntime;\n freezer?: FreezerRuntime;\n changes?: ChangesRuntime;\n mcp?: Pick<McpRuntime, 'close'>;\n users?: UserClients;\n monitor?: Pick<MonitorOptions, 'kernel' | 'groups' | 'users'>;\n pages?: Pages;\n secrets?: HostSecrets;\n uploads?: Uploads;\n thumbnail?: Thumbnail;\n labels?: LabelsRuntime;\n approvals?: Approvals;\n judge?: ApprovalJudge;\n } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n let refresh = () => {};\n const slims = slimmer(options.thumbnail ?? thumbnail, () => refresh());\n const transcript = await follow(agent, context, slims.slim);\n const { state } = transcript;\n const mounted = await agentViews(agent, context, slims.slim);\n refresh = () => {\n transcript.refresh();\n mounted.refresh();\n };\n const touch = () => options.freezer?.touch();\n const untouch = [state.subscribe(touch), mounted.views.subscribe(touch)];\n const pages = options.pages ?? createPages();\n const deliveries = trackDeliveries(agent.harness, state, context);\n const policy = await attachApprovalPolicy(agent.harness, context);\n const approvals = options.approvals ?? (await approving(agent, policy, options.judge, context));\n const monitor = createMonitor({\n ...options.monitor,\n harness: agent.harness,\n agents: agent.agents,\n views: mounted.views,\n context,\n });\n const guests = await createGuests({\n harness: agent.harness,\n agents: agent.agents,\n approvals,\n policy,\n reviews: agent.reviews,\n context,\n });\n const control: AgentControl = {\n ...createAgentControl(\n agent.harness,\n agent,\n deliveries,\n options.licks,\n options.scoops,\n options.skills,\n options.sprinkles,\n options.memory,\n options.freezer,\n options.changes,\n monitor,\n options.secrets?.list,\n options.uploads,\n options.labels,\n guests\n ),\n approvalPolicySet: (change, using) => policy.set(change, using),\n };\n const remote = createRemote({\n harness: agent.harness,\n send: (request, using) => control.send(request, using),\n vault: options.secrets?.vault ?? idleVault,\n async conversation(agentId, using) {\n if (!agentId) return agent.cone();\n const found = await agent.agents.conversation(agentId, using);\n if (!found) throw new Error(`There is no agent ${agentId}.`);\n return found;\n },\n });\n const shownViews = () => [state.value, ...Object.values(mounted.views.value)];\n const kept = options.labels?.labels ?? replicatedState<Record<string, string>>({});\n const labels = visibleLabels(kept, [state, mounted.views], shownViews);\n const transcriptService = {\n state,\n deliveries: deliveries.state,\n agents: mounted.agents,\n views: mounted.views,\n commands: options.skills?.commands ?? replicatedState<Command[]>([]),\n privateRevision: options.skills?.privateRevision ?? noRevision(),\n sprinkles: options.sprinkles?.sprinkles ?? replicatedState<Sprinkle[]>([]),\n memories: options.memory?.memories ?? replicatedState<MemoryEntry[]>([]),\n memoryScopes: options.memory?.scopes ?? replicatedState<MemoryScope[]>([]),\n frozen: options.freezer?.frozen ?? replicatedState<FrozenCone[]>([]),\n changes:\n options.changes?.view ?? replicatedState<ChangesView>({ unavailable: null, changes: [] }),\n monitor: monitor.state,\n vault: options.secrets?.vault ?? idleVault,\n labels: labels.state,\n guests: guests.seats,\n approvals: approvals.state,\n approvalPolicy: policy.state,\n };\n const sudo = createSudo({\n approvals,\n agents: () => agent.agents.state(),\n ...(options.licks ? { licks: options.licks.licks } : {}),\n });\n const settings = options.settings ?? noSettings;\n const gates = gatedControls(control, slims.shown, shownViews, transcriptService.labels);\n const { trusted, viewed } = gates;\n const host = serveAgent({\n trusted,\n viewed,\n transcript: transcriptService,\n viewMonitor: monitor.viewState,\n sudo,\n settings,\n remote,\n pages,\n guest: guestOpener(guests, agent.agents, mounted.views, context),\n decide: (by) => (id, decision, reason, using) =>\n approvals.decide(id, decision, reason, by, using),\n });\n const offGuests = guests.onEnd((id) => {\n void host.invalidatePrincipal((principal) => guestOf(principal)?.id === id);\n });\n let links = 0;\n return {\n serverId,\n agent,\n pages,\n guests,\n approvals,\n ...(options.users ? { users: options.users } : {}),\n connect(endpoint, connectOptions) {\n if (connectOptions?.guest) {\n links += 1;\n admitGuest(guests, endpoint, connectOptions.guest, serverId, links, host);\n return;\n }\n const seat: Seat = connectOptions?.readOnly\n ? 'view'\n : connectOptions?.pages === false\n ? 'control'\n : 'owner';\n links += 1;\n const link = new PortLink(endpoint);\n link.greet(serverId);\n const device = connectOptions?.device ? { device: connectOptions.device } : {};\n host.accept(link, {\n principal: { seat, link: links, ...device } satisfies AgentPrincipal,\n });\n },\n async close() {\n offGuests();\n await host.close();\n guests.dispose();\n await pages.dispose();\n await monitor.dispose();\n await remote.dispose();\n deliveries.dispose();\n sudo.close();\n approvals.close();\n transcript.dispose();\n mounted.dispose();\n labels.dispose();\n slims.dispose();\n for (const off of untouch) off();\n options.freezer?.close();\n options.secrets?.close?.();\n await options.changes?.close(context);\n await options.memory?.close(context);\n await options.sprinkles?.close(context);\n await options.skills?.close(context);\n await options.mcp?.close(context);\n await options.scoops?.runtime.close(context);\n await options.licks?.sources.close(context);\n await agent.close();\n await options.users?.close();\n },\n };\n}\n\ninterface Served {\n trusted: AgentControl;\n viewed: AgentControl;\n transcript: Record<keyof AgentTranscript, ReplicatedState<unknown>>;\n viewMonitor: ReplicatedState<unknown>;\n sudo?: AgentSudo;\n settings: AgentSettings;\n remote: AgentRemote;\n pages: Pages;\n guest?: (principal: GuestPrincipal) => { value: AgentGuest; dispose(): void } | undefined;\n decide: (by: Decider) => AgentControl['decide'];\n}\n\nexport const CLOSED_TO_GUESTS = 'a guest seat has only its transcript and propose';\n\nconst opened = new WeakSet<object>();\n\nexport const openToGuests = <F extends object>(factory: F): F => {\n opened.add(factory);\n return factory;\n};\n\nexport function closedToGuests(host: Host): Host {\n const serve = ((type: never, factory: (...args: unknown[]) => unknown, options?: never) =>\n host.serve(\n type,\n (opened.has(factory)\n ? factory\n : (input: unknown, principal: unknown, self: unknown) => {\n if (seatOf(principal as never) === 'guest') throw forbidden(CLOSED_TO_GUESTS);\n return factory(input, principal, self);\n }) as never,\n options\n )) as Host['serve'];\n return new Proxy(host, {\n get(target, key) {\n if (key === 'serve') return serve;\n const value = Reflect.get(target, key, target) as unknown;\n return typeof value === 'function' ? value.bind(target) : value;\n },\n });\n}\n\nexport function lazily<T>(state: () => ReplicatedState<T>): Readable<T> {\n return {\n get value() {\n return readable(state()).value;\n },\n subscribe: (listener) => readable(state()).subscribe(listener),\n events: (listener) => readable(state()).events(listener),\n };\n}\n\nconst seated = (serving: Served, seat: Seat, device: string | undefined): AgentControl => ({\n ...(seat === 'view' ? serving.viewed : serving.trusted),\n decide: serving.decide({\n by: seat === 'owner' ? 'owner' : 'follower',\n ...(device ? { device } : {}),\n }),\n});\n\nconst VIEW_METHODS = [...CONTROL_READS, ...OWNER_DEVICE_METHODS];\n\nexport function serveAgent(serving: Served): Host {\n const host = closedToGuests(createHost({ name: AGENT_HOST, principalKey }));\n const viewing = { ...serving.transcript, monitor: serving.viewMonitor };\n host.serve(AgentControl, ((_input: unknown, principal: unknown) => {\n const seat = seatOf(principal);\n const control = seated(serving, seat, deviceOf(principal));\n if (seat === 'view') return { kind: 'view', ...served(() => control, VIEW_METHODS) };\n return { kind: 'control', ...served(() => control, CONTROL_METHODS) };\n }) as never);\n host.serve(AgentTranscript, ((_input: unknown, principal: unknown) => ({\n kind: 'transcript',\n ...readablesOf(seatOf(principal) === 'view' ? viewing : serving.transcript),\n })) as never);\n host.serve(AgentSettings, ((_input: unknown, principal: unknown) => ({\n kind: seatOf(principal) === 'view' ? 'view' : 'settings',\n state: readable(serving.settings.state),\n ...(seatOf(principal) === 'view' ? {} : served(() => serving.settings, SETTINGS_METHODS)),\n })) as never);\n host.serve(AgentRemoteService, ((_input: unknown, principal: unknown) => {\n if (seatOf(principal) !== 'view')\n return { kind: 'remote', ...served(() => serving.remote, REMOTE_METHODS) };\n const scoped = viewRemote(serving.remote);\n return { kind: 'watch', ...served(() => scoped, REMOTE_READS) };\n }) as never);\n host.serve(AgentPagesService, ((_input: unknown, principal: unknown, self: Self) => {\n if (seatOf(principal) !== 'owner') return { kind: 'none' };\n const held = self.resources({\n mine: resource({\n rev: 1,\n open: () => ownedPages(serving.pages),\n close: (mine) => mine.release(),\n }),\n });\n return { kind: 'pages', ...served(() => held.mine.value, PAGE_METHODS) };\n }) as never);\n host.serve(\n AgentGuestService,\n openToGuests((_input: unknown, principal: unknown, self: Self) => {\n const guest = guestOf(principal as never);\n if (!guest) return { kind: 'none' };\n const opening = serving.guest?.(guest);\n if (!opening) throw forbidden(CLOSED_TO_GUESTS);\n const held = self.resources({\n seat: resource({ rev: 1, open: () => opening, close: (made) => made.dispose() }),\n });\n const later = (name: 'transcript' | 'seat' | 'proposals') =>\n lazily(() => held.seat.value.value[name] as ReplicatedState<unknown>);\n return {\n kind: 'guest',\n transcript: later('transcript'),\n seat: later('seat'),\n proposals: later('proposals'),\n ...served(() => held.seat.value.value, GUEST_METHODS),\n };\n }) as never\n );\n host.serve(AgentSudoService, ((_input: unknown, principal: unknown, self: Self) => {\n const sudo = serving.sudo;\n if (seatOf(principal) !== 'owner' || !sudo) return { kind: 'none' };\n const held = self.resources({\n mine: resource({ rev: 1, open: () => ownedSudo(sudo), close: (mine) => mine.release() }),\n });\n return {\n kind: 'sudo',\n approvals: readable(sudo.approvals),\n ...served(() => held.mine.value, SUDO_METHODS),\n };\n }) as never);\n return host;\n}\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEE;AAAA,EACA;AAAA,EAIA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,0BAA0B;AAGnC;AAAA,EAGE;AAAA,OAEK;AACP,SAAgC,WAAW,4BAA4B;AACvE,SAAyB,YAAY,iBAAiB;AAGtD,SAAS,0BAA2D;AACpE,SAAS,uBAAuB;AAEhC,SAAS,oBAAiC;AAC1C,SAAS,YAAY,mBAAmB;AAKxC,SAAS,qBAA0C;AACnD,SAAS,kBAAkB;AAC3B,SAA2B,oBAAoB;AAC/C,SAAS,aAAa,kBAA8B;AAGpD;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AAIP,SAAS,SAAyB,iBAAiB;AACnD,SAA6B,eAAe,kBAAkB;AAE9D,SAAS,kBAAkB;AAC3B,SAA4B,gBAAgB;AAoB5C,MAAM,aAA4B;AAAA,EAChC,OAAO,gBAAgB,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC;AAAA,EACnD,SAAS,YAAY;AACnB,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAAA,EACA,YAAY,YAAY;AAAA,EAAC;AAAA,EACzB,QAAQ,YAAY;AAAA,EACpB,cAAc,YAAY;AAAA,EAAC;AAC7B;AAEA,eAAe,OACb,OACA,SACA,MACA;AACA,MAAI,WAAW,MAAM,MAAM,KAAK,EAAE,UAAU,OAAO;AACnD,QAAM,QAAQ,gBAAkC,KAAK,SAAS,KAAK,CAAC;AACpE,QAAM,SAAS,CAAC,OAAyB,SAAkB,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAC1F,MAAI,MAAM,SAAS,UAAU,MAAM;AACnC,QAAM,OAAO,MAAM,OAAO,OAAO,iBAAiB;AAChD,UAAM,OAAO,MAAM,aAAa,UAAU,OAAO;AACjD,QAAI;AACJ,aAAS,QAAQ;AACjB,eAAW;AACX,UAAM,QAAQ,SAAS,KAAK,KAAK,KAAK,CAAC;AACvC,UAAM,KAAK,UAAU,MAAM;AAAA,EAC7B,CAAC;AACD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,MAAM,MAAM,QAAQ,SAAS,KAAK,SAAS,KAAK,CAAC;AAAA,IAC1D,UAAU;AACR,WAAK;AACL,UAAI;AACJ,eAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AACF;AAQA,MAAM,YAAY,gBAA4B;AAAA,EAC5C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AACR,CAAC;AAED,SAAS,cACP,SACA,OACA,OACA,QACA;AACA,QAAM,UAAU,CAAC,UACf,MAAM,EAAE,KAAK,CAAC,SAAS,KAAK,QAAQ,KAAK,CAAC,SAAS,KAAK,OAAO,KAAK,CAAC;AACvE,QAAM,QACJ,CAAC,YACD,OAAO,KAAK,UACV,QAAQ,IAAI,KAAK,IAAI,QAAQ,MAAM,KAAK,KAAK,IAAI,EAAE,MAAM,MAAM,UAAU,KAAK;AAClF,QAAM,UAAwB,EAAE,GAAG,SAAS,OAAO,MAAM,KAAK,EAAE;AAChE,QAAM,SAAuB,EAAE,GAAG,SAAS,OAAO,MAAM,OAAO,GAAG,WAAW,WAAW,MAAM,EAAE;AAChG,SAAO,EAAE,SAAS,OAAO;AAC3B;AAEA,SAAS,UACP,OACA,QACA,OACA,SACoB;AACpB,SAAO;AAAA,IACL;AAAA,MACE,SAAS,MAAM;AAAA,MACf,aAAa,UAAU,MAAM;AAAA,MAC7B,cAAc,MAAM,OAAO,QAAQ,EAAE,KAAK;AAAA,MAC1C,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AACF;AAEA,MAAM,aAAa,MAAM,gBAAiC,EAAE,UAAU,EAAE,CAAC;AAEzE,eAAsB,UACpB,OACA,UAqBI,CAAC,GACe;AACpB,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,WAAW,QAAQ,YAAY,OAAO,WAAW;AACvD,MAAI,UAAU,MAAM;AAAA,EAAC;AACrB,QAAM,QAAQ,QAAQ,QAAQ,aAAa,WAAW,MAAM,QAAQ,CAAC;AACrE,QAAM,aAAa,MAAM,OAAO,OAAO,SAAS,MAAM,IAAI;AAC1D,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,UAAU,MAAM,WAAW,OAAO,SAAS,MAAM,IAAI;AAC3D,YAAU,MAAM;AACd,eAAW,QAAQ;AACnB,YAAQ,QAAQ;AAAA,EAClB;AACA,QAAM,QAAQ,MAAM,QAAQ,SAAS,MAAM;AAC3C,QAAM,UAAU,CAAC,MAAM,UAAU,KAAK,GAAG,QAAQ,MAAM,UAAU,KAAK,CAAC;AACvE,QAAM,QAAQ,QAAQ,SAAS,YAAY;AAC3C,QAAM,aAAa,gBAAgB,MAAM,SAAS,OAAO,OAAO;AAChE,QAAM,SAAS,MAAM,qBAAqB,MAAM,SAAS,OAAO;AAChE,QAAM,YAAY,QAAQ,aAAc,MAAM,UAAU,OAAO,QAAQ,QAAQ,OAAO,OAAO;AAC7F,QAAM,UAAU,cAAc;AAAA,IAC5B,GAAG,QAAQ;AAAA,IACX,SAAS,MAAM;AAAA,IACf,QAAQ,MAAM;AAAA,IACd,OAAO,QAAQ;AAAA,IACf;AAAA,EACF,CAAC;AACD,QAAM,SAAS,MAAM,
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n createHost,\n forbidden,\n type Host,\n type Readable,\n type ReplicatedState,\n replicatedState,\n resource,\n type Self,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { Agent } from './agent.ts';\nimport {\n type ApprovalJudge,\n type Approvals,\n attachApprovals,\n type Decider,\n} from './approvals/index.ts';\nimport { type ApprovalPolicies, alwaysFor, attachApprovalPolicy } from './approvals/policy.ts';\nimport { type AgentSudo, createSudo, ownedSudo } from './approvals/sudo.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport { createAgentControl, type HostLicks, type HostScoops } from './control.ts';\nimport { trackDeliveries } from './deliveries.ts';\nimport type { FreezerRuntime, FrozenCone } from './freezer/index.ts';\nimport { createGuests, type Guests } from './guests/index.ts';\nimport { admitGuest, guestOpener } from './guests/serve.ts';\nimport type { UserClients } from './kernel/users.ts';\nimport type { McpRuntime } from './mcp/index.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport { createMonitor, type MonitorOptions } from './monitor/index.ts';\nimport { viewRemote } from './readonly.ts';\nimport { type AgentRemote, createRemote } from './remote/host.ts';\nimport { createPages, ownedPages, type Pages } from './remote/pages.ts';\nimport type { SecretName } from './secrets/names.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport {\n AgentControl,\n type AgentGuest,\n AgentGuestService,\n AgentPagesService,\n AgentRemoteService,\n AgentSettings,\n AgentSudoService,\n AgentTranscript,\n CONTROL_METHODS,\n CONTROL_READS,\n type Command,\n GUEST_METHODS,\n OWNER_DEVICE_METHODS,\n PAGE_METHODS,\n type PrivateRevision,\n REMOTE_METHODS,\n REMOTE_READS,\n SETTINGS_METHODS,\n SUDO_METHODS,\n} from './services.ts';\nimport {\n AGENT_HOST,\n type AgentPrincipal,\n deviceOf,\n type GuestPrincipal,\n guestOf,\n principalKey,\n readable,\n readablesOf,\n type Seat,\n seatOf,\n served,\n} from './serving.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\nimport { slimmer, type Thumbnail, thumbnail } from './thumbs.ts';\nimport { type LabelsRuntime, visibleLabels, watchLabel } from './titles/labels.ts';\nimport type { Uploads } from './uploads.ts';\nimport { agentViews } from './views.ts';\nimport { type PortEndpoint, PortLink } from './wire.ts';\n\nexport interface ConnectOptions {\n readOnly?: boolean;\n pages?: boolean;\n guest?: { id: string; label: string };\n device?: string;\n}\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n readonly users?: UserClients;\n readonly pages: Pages;\n readonly guests: Guests;\n readonly approvals: Approvals;\n connect(endpoint: PortEndpoint, options?: ConnectOptions): void;\n close(): Promise<void>;\n}\n\nconst noSettings: AgentSettings = {\n state: replicatedState({ models: [], accounts: [] }),\n connect: async () => {\n throw new Error('this agent has no accounts');\n },\n disconnect: async () => {},\n signIn: async () => null,\n dismissMoved: async () => {},\n};\n\nasync function follow(\n agent: Agent,\n context: Context,\n slim: (view: ConversationView) => ConversationView\n) {\n let attached = await agent.cone().viewState(context);\n const state = replicatedState<ConversationView>(slim(attached.value));\n const mirror = (value: ConversationView, from: Context) => state.replace(from, slim(value));\n let off = attached.subscribe(mirror);\n const stop = agent.onCone(async (conversation) => {\n const next = await conversation.viewState(context);\n off();\n attached.dispose();\n attached = next;\n state.replace(context, slim(next.value));\n off = next.subscribe(mirror);\n });\n return {\n state,\n refresh: () => state.replace(context, slim(attached.value)),\n dispose() {\n stop();\n off();\n attached.dispose();\n },\n };\n}\n\nexport interface HostSecrets {\n vault: ReplicatedState<VaultState>;\n list(): readonly SecretName[];\n close?(): void;\n}\n\nconst idleVault = replicatedState<VaultState>({\n port: 'none',\n needed: false,\n version: 0,\n locked: 'no',\n held: 0,\n});\n\nfunction gatedControls(\n control: AgentControl,\n shown: (entry: number) => boolean,\n views: () => readonly ConversationView[],\n labels: ReplicatedState<Record<string, string>>\n) {\n const visible = (entry: number) =>\n views().some((view) => view.entries.some((item) => item.id === entry));\n const gated =\n (allowed: (entry: number) => boolean): AgentControl['image'] =>\n async (ref, using) =>\n allowed(ref.entry) ? control.image(ref, using) : { data: null, mimeType: null };\n const trusted: AgentControl = { ...control, image: gated(shown) };\n const viewed: AgentControl = { ...control, image: gated(visible), toolLabel: watchLabel(labels) };\n return { trusted, viewed };\n}\n\nfunction approving(\n agent: Agent,\n policy: ApprovalPolicies,\n judge: ApprovalJudge | undefined,\n context: Context\n): Promise<Approvals> {\n return attachApprovals(\n {\n harness: agent.harness,\n guestAlways: alwaysFor(policy),\n sudoApprover: () => policy.current().sudo.approver,\n ...(judge ? { judge } : {}),\n },\n context\n );\n}\n\nasync function guestsOf(\n agent: Agent,\n approvals: Approvals,\n policy: ApprovalPolicies,\n context: Context\n): Promise<Guests> {\n const guests = await createGuests({\n harness: agent.harness,\n agents: agent.agents,\n approvals,\n policy,\n reviews: agent.reviews,\n context,\n });\n agent.gate.bind({ approvals, policy: () => guests.policy() });\n return guests;\n}\n\nconst noRevision = () => replicatedState<PrivateRevision>({ revision: 0 });\n\nexport async function hostAgent(\n agent: Agent,\n options: {\n serverId?: string;\n context?: Context;\n settings?: AgentSettings;\n licks?: HostLicks;\n scoops?: HostScoops;\n skills?: SkillsRuntime;\n sprinkles?: SprinklesRuntime;\n memory?: MemoryRuntime;\n freezer?: FreezerRuntime;\n changes?: ChangesRuntime;\n mcp?: Pick<McpRuntime, 'close'>;\n users?: UserClients;\n monitor?: Pick<MonitorOptions, 'kernel' | 'groups' | 'users'>;\n pages?: Pages;\n secrets?: HostSecrets;\n uploads?: Uploads;\n thumbnail?: Thumbnail;\n labels?: LabelsRuntime;\n approvals?: Approvals;\n judge?: ApprovalJudge;\n } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n let refresh = () => {};\n const slims = slimmer(options.thumbnail ?? thumbnail, () => refresh());\n const transcript = await follow(agent, context, slims.slim);\n const { state } = transcript;\n const mounted = await agentViews(agent, context, slims.slim);\n refresh = () => {\n transcript.refresh();\n mounted.refresh();\n };\n const touch = () => options.freezer?.touch();\n const untouch = [state.subscribe(touch), mounted.views.subscribe(touch)];\n const pages = options.pages ?? createPages();\n const deliveries = trackDeliveries(agent.harness, state, context);\n const policy = await attachApprovalPolicy(agent.harness, context);\n const approvals = options.approvals ?? (await approving(agent, policy, options.judge, context));\n const monitor = createMonitor({\n ...options.monitor,\n harness: agent.harness,\n agents: agent.agents,\n views: mounted.views,\n context,\n });\n const guests = await guestsOf(agent, approvals, policy, context);\n const control: AgentControl = {\n ...createAgentControl(\n agent.harness,\n agent,\n deliveries,\n options.licks,\n options.scoops,\n options.skills,\n options.sprinkles,\n options.memory,\n options.freezer,\n options.changes,\n monitor,\n options.secrets?.list,\n options.uploads,\n options.labels,\n guests\n ),\n approvalPolicySet: (change, using) => policy.set(change, using),\n };\n const remote = createRemote({\n harness: agent.harness,\n send: (request, using) => control.send(request, using),\n vault: options.secrets?.vault ?? idleVault,\n async conversation(agentId, using) {\n if (!agentId) return agent.cone();\n const found = await agent.agents.conversation(agentId, using);\n if (!found) throw new Error(`There is no agent ${agentId}.`);\n return found;\n },\n });\n const shownViews = () => [state.value, ...Object.values(mounted.views.value)];\n const kept = options.labels?.labels ?? replicatedState<Record<string, string>>({});\n const labels = visibleLabels(kept, [state, mounted.views], shownViews);\n const transcriptService = {\n state,\n deliveries: deliveries.state,\n agents: mounted.agents,\n views: mounted.views,\n commands: options.skills?.commands ?? replicatedState<Command[]>([]),\n privateRevision: options.skills?.privateRevision ?? noRevision(),\n sprinkles: options.sprinkles?.sprinkles ?? replicatedState<Sprinkle[]>([]),\n memories: options.memory?.memories ?? replicatedState<MemoryEntry[]>([]),\n memoryScopes: options.memory?.scopes ?? replicatedState<MemoryScope[]>([]),\n frozen: options.freezer?.frozen ?? replicatedState<FrozenCone[]>([]),\n changes:\n options.changes?.view ?? replicatedState<ChangesView>({ unavailable: null, changes: [] }),\n monitor: monitor.state,\n vault: options.secrets?.vault ?? idleVault,\n labels: labels.state,\n guests: guests.seats,\n approvals: approvals.state,\n approvalPolicy: policy.state,\n };\n const sudo = createSudo({\n approvals,\n agents: () => agent.agents.state(),\n ...(options.licks ? { licks: options.licks.licks } : {}),\n });\n const settings = options.settings ?? noSettings;\n const gates = gatedControls(control, slims.shown, shownViews, transcriptService.labels);\n const { trusted, viewed } = gates;\n const host = serveAgent({\n trusted,\n viewed,\n transcript: transcriptService,\n viewMonitor: monitor.viewState,\n sudo,\n settings,\n remote,\n pages,\n guest: guestOpener(guests, agent.agents, mounted.views, context),\n decide: (by) => (id, decision, reason, using) =>\n approvals.decide(id, decision, reason, by, using),\n });\n const offGuests = guests.onEnd((id) => {\n void host.invalidatePrincipal((principal) => guestOf(principal)?.id === id);\n });\n let links = 0;\n return {\n serverId,\n agent,\n pages,\n guests,\n approvals,\n ...(options.users ? { users: options.users } : {}),\n connect(endpoint, connectOptions) {\n if (connectOptions?.guest) {\n links += 1;\n admitGuest(guests, endpoint, connectOptions.guest, serverId, links, host);\n return;\n }\n const seat: Seat = connectOptions?.readOnly\n ? 'view'\n : connectOptions?.pages === false\n ? 'control'\n : 'owner';\n links += 1;\n const link = new PortLink(endpoint);\n link.greet(serverId);\n const device = connectOptions?.device ? { device: connectOptions.device } : {};\n host.accept(link, {\n principal: { seat, link: links, ...device } satisfies AgentPrincipal,\n });\n },\n async close() {\n offGuests();\n await host.close();\n guests.dispose();\n await pages.dispose();\n await monitor.dispose();\n await remote.dispose();\n deliveries.dispose();\n sudo.close();\n approvals.close();\n transcript.dispose();\n mounted.dispose();\n labels.dispose();\n slims.dispose();\n for (const off of untouch) off();\n options.freezer?.close();\n options.secrets?.close?.();\n await options.changes?.close(context);\n await options.memory?.close(context);\n await options.sprinkles?.close(context);\n await options.skills?.close(context);\n await options.mcp?.close(context);\n await options.scoops?.runtime.close(context);\n await options.licks?.sources.close(context);\n await agent.close();\n await options.users?.close();\n },\n };\n}\n\ninterface Served {\n trusted: AgentControl;\n viewed: AgentControl;\n transcript: Record<keyof AgentTranscript, ReplicatedState<unknown>>;\n viewMonitor: ReplicatedState<unknown>;\n sudo?: AgentSudo;\n settings: AgentSettings;\n remote: AgentRemote;\n pages: Pages;\n guest?: (principal: GuestPrincipal) => { value: AgentGuest; dispose(): void } | undefined;\n decide: (by: Decider) => AgentControl['decide'];\n}\n\nexport const CLOSED_TO_GUESTS = 'a guest seat has only its transcript and propose';\n\nconst opened = new WeakSet<object>();\n\nexport const openToGuests = <F extends object>(factory: F): F => {\n opened.add(factory);\n return factory;\n};\n\nexport function closedToGuests(host: Host): Host {\n const serve = ((type: never, factory: (...args: unknown[]) => unknown, options?: never) =>\n host.serve(\n type,\n (opened.has(factory)\n ? factory\n : (input: unknown, principal: unknown, self: unknown) => {\n if (seatOf(principal as never) === 'guest') throw forbidden(CLOSED_TO_GUESTS);\n return factory(input, principal, self);\n }) as never,\n options\n )) as Host['serve'];\n return new Proxy(host, {\n get(target, key) {\n if (key === 'serve') return serve;\n const value = Reflect.get(target, key, target) as unknown;\n return typeof value === 'function' ? value.bind(target) : value;\n },\n });\n}\n\nexport function lazily<T>(state: () => ReplicatedState<T>): Readable<T> {\n return {\n get value() {\n return readable(state()).value;\n },\n subscribe: (listener) => readable(state()).subscribe(listener),\n events: (listener) => readable(state()).events(listener),\n };\n}\n\nconst seated = (serving: Served, seat: Seat, device: string | undefined): AgentControl => ({\n ...(seat === 'view' ? serving.viewed : serving.trusted),\n decide: serving.decide({\n by: seat === 'owner' ? 'owner' : 'follower',\n ...(device ? { device } : {}),\n }),\n});\n\nconst VIEW_METHODS = [...CONTROL_READS, ...OWNER_DEVICE_METHODS];\n\nexport function serveAgent(serving: Served): Host {\n const host = closedToGuests(createHost({ name: AGENT_HOST, principalKey }));\n const viewing = { ...serving.transcript, monitor: serving.viewMonitor };\n host.serve(AgentControl, ((_input: unknown, principal: unknown) => {\n const seat = seatOf(principal);\n const control = seated(serving, seat, deviceOf(principal));\n if (seat === 'view') return { kind: 'view', ...served(() => control, VIEW_METHODS) };\n return { kind: 'control', ...served(() => control, CONTROL_METHODS) };\n }) as never);\n host.serve(AgentTranscript, ((_input: unknown, principal: unknown) => ({\n kind: 'transcript',\n ...readablesOf(seatOf(principal) === 'view' ? viewing : serving.transcript),\n })) as never);\n host.serve(AgentSettings, ((_input: unknown, principal: unknown) => ({\n kind: seatOf(principal) === 'view' ? 'view' : 'settings',\n state: readable(serving.settings.state),\n ...(seatOf(principal) === 'view' ? {} : served(() => serving.settings, SETTINGS_METHODS)),\n })) as never);\n host.serve(AgentRemoteService, ((_input: unknown, principal: unknown) => {\n if (seatOf(principal) !== 'view')\n return { kind: 'remote', ...served(() => serving.remote, REMOTE_METHODS) };\n const scoped = viewRemote(serving.remote);\n return { kind: 'watch', ...served(() => scoped, REMOTE_READS) };\n }) as never);\n host.serve(AgentPagesService, ((_input: unknown, principal: unknown, self: Self) => {\n if (seatOf(principal) !== 'owner') return { kind: 'none' };\n const held = self.resources({\n mine: resource({\n rev: 1,\n open: () => ownedPages(serving.pages),\n close: (mine) => mine.release(),\n }),\n });\n return { kind: 'pages', ...served(() => held.mine.value, PAGE_METHODS) };\n }) as never);\n host.serve(\n AgentGuestService,\n openToGuests((_input: unknown, principal: unknown, self: Self) => {\n const guest = guestOf(principal as never);\n if (!guest) return { kind: 'none' };\n const opening = serving.guest?.(guest);\n if (!opening) throw forbidden(CLOSED_TO_GUESTS);\n const held = self.resources({\n seat: resource({ rev: 1, open: () => opening, close: (made) => made.dispose() }),\n });\n const later = (name: 'transcript' | 'seat' | 'proposals') =>\n lazily(() => held.seat.value.value[name] as ReplicatedState<unknown>);\n return {\n kind: 'guest',\n transcript: later('transcript'),\n seat: later('seat'),\n proposals: later('proposals'),\n ...served(() => held.seat.value.value, GUEST_METHODS),\n };\n }) as never\n );\n host.serve(AgentSudoService, ((_input: unknown, principal: unknown, self: Self) => {\n const sudo = serving.sudo;\n if (seatOf(principal) !== 'owner' || !sudo) return { kind: 'none' };\n const held = self.resources({\n mine: resource({ rev: 1, open: () => ownedSudo(sudo), close: (mine) => mine.release() }),\n });\n return {\n kind: 'sudo',\n approvals: readable(sudo.approvals),\n ...served(() => held.mine.value, SUDO_METHODS),\n };\n }) as never);\n return host;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/services.js
CHANGED
|
@@ -38,6 +38,7 @@ const CONTROL_METHODS = keys({
|
|
|
38
38
|
toolLabel: true,
|
|
39
39
|
guestOpen: true,
|
|
40
40
|
guestRevoke: true,
|
|
41
|
+
guestAlwaysForget: true,
|
|
41
42
|
approvalPolicySet: true,
|
|
42
43
|
decide: true
|
|
43
44
|
});
|
|
@@ -45,6 +46,7 @@ const OWNER_DEVICE_METHODS = [
|
|
|
45
46
|
"decide",
|
|
46
47
|
"guestOpen",
|
|
47
48
|
"guestRevoke",
|
|
49
|
+
"guestAlwaysForget",
|
|
48
50
|
"approvalPolicySet"
|
|
49
51
|
];
|
|
50
52
|
const CONTROL_READS = [
|
package/dist/services.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/services.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context, JsonValue, RemoteContract, ReplicatedState } from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { Approval, ApprovalAnswer, ApprovalDecided } from './approvals/index.ts';\nimport type {\n ApprovalPolicy,\n ApprovalPolicyChange,\n ApprovalPolicySet,\n} from './approvals/policy.ts';\nimport type { AgentSudo } from './approvals/sudo.ts';\nimport type { SendAttachment, ShownAttachment } from './attachments.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { GuestOpened, Proposed, ProposeRequest } from './guests/index.ts';\nimport type { GuestDraft, GuestGates, GuestSeat } from './guests/seats.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { AgentPages } from './remote/pages.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport { contract } from './serving.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n attachments?: SendAttachment[];\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n monitorOpen(lease: string | null, resync: boolean, context: Context): Promise<MonitorLease>;\n monitorClose(lease: string, context: Context): Promise<void>;\n image(ref: ImageRef, context: Context): Promise<StoredImage>;\n agentCommands(agentId: string, context: Context): Promise<Command[]>;\n toolLabel(agentId: string, callIds: string[], context: Context): Promise<string | null>;\n guestOpen(draft: GuestDraft, context: Context): Promise<GuestOpened>;\n guestRevoke(id: string, context: Context): Promise<{ revoked: boolean }>;\n approvalPolicySet(change: ApprovalPolicyChange, context: Context): Promise<ApprovalPolicySet>;\n decide(\n id: string,\n decision: ApprovalAnswer,\n reason: string | null,\n context: Context\n ): Promise<ApprovalDecided>;\n}\n\nexport interface ImageRef {\n entry: number;\n message: number;\n part: number;\n}\n\nexport type StoredImage = { data: string; mimeType: string } | { data: null; mimeType: null };\n\nexport interface MonitorLease {\n lease: string;\n ttlMs: number;\n}\n\nexport interface MonitorAgent {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n model: string | null;\n running: boolean;\n queued: number;\n tool: string | null;\n retry: { attempt: number; since: number; error: string } | null;\n failed: string | null;\n context: number | null;\n cpu?: number | null;\n}\n\nexport interface MonitorTask {\n id: string;\n kind: string;\n detail: string | null;\n agentId: string | null;\n owner: string | null;\n status: 'pending' | 'running' | 'waiting' | 'completing';\n phase: string;\n background: boolean;\n aborting: number | null;\n since: number;\n waits: number;\n}\n\nexport interface MonitorProcess {\n pid: number;\n ppid: number;\n pgid: number;\n user: string | null;\n agentId: string | null;\n command: string;\n state: 'S' | 'Z';\n started: number;\n zombie: number | null;\n tty: boolean;\n rss: number | null;\n utime?: number;\n stime?: number;\n cpu?: number | null;\n}\n\nexport interface MonitorProblem {\n id: string;\n at: number;\n agentId: string | null;\n kind: 'task' | 'retry' | 'turn';\n message: string;\n}\n\nexport interface MonitorFeed {\n open: boolean;\n at: number;\n usage: { tokens: number; cost: number; free: boolean } | null;\n agents: MonitorAgent[];\n tasks: MonitorTask[];\n processes: MonitorProcess[] | null;\n kernel: 'checking' | 'ok' | 'unreachable';\n problems: MonitorProblem[];\n paused: boolean;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null; attachments?: ShownAttachment[] }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nconst keys = <T>(record: Record<keyof T, true>) => Object.keys(record) as (keyof T & string)[];\n\nexport const CONTROL_METHODS = keys<AgentControl>({\n send: true,\n wait: true,\n withdraw: true,\n abort: true,\n compact: true,\n compactAgent: true,\n reset: true,\n configure: true,\n rewind: true,\n rewindAgent: true,\n resolveLick: true,\n resolveAgentLick: true,\n webhook: true,\n stopAgent: true,\n selectCone: true,\n createCone: true,\n createScoop: true,\n drop: true,\n unqueue: true,\n sprinkleSend: true,\n sprinkleCall: true,\n memorySave: true,\n memoryRemove: true,\n freeze: true,\n newChat: true,\n thaw: true,\n discard: true,\n changesOpen: true,\n changeAccept: true,\n changeRevert: true,\n monitorOpen: true,\n monitorClose: true,\n image: true,\n agentCommands: true,\n toolLabel: true,\n guestOpen: true,\n guestRevoke: true,\n approvalPolicySet: true,\n decide: true,\n});\n\nexport const OWNER_DEVICE_METHODS: readonly (keyof AgentControl & string)[] = [\n 'decide',\n 'guestOpen',\n 'guestRevoke',\n 'approvalPolicySet',\n];\n\nexport const CONTROL_READS: readonly (keyof AgentControl & string)[] = [\n 'wait',\n 'changesOpen',\n 'monitorOpen',\n 'monitorClose',\n 'image',\n 'toolLabel',\n];\n\nexport const AgentControl: RemoteContract = contract('slicc.agent.control', {\n control: { methods: CONTROL_METHODS },\n view: { methods: [...CONTROL_READS, ...OWNER_DEVICE_METHODS] },\n});\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly privateRevision: ReplicatedState<PrivateRevision>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n readonly monitor: ReplicatedState<MonitorFeed>;\n readonly vault: ReplicatedState<VaultState>;\n readonly labels: ReplicatedState<Record<string, string>>;\n readonly guests: ReplicatedState<GuestSeat[]>;\n readonly approvals: ReplicatedState<Approval[]>;\n readonly approvalPolicy: ReplicatedState<ApprovalPolicy>;\n}\n\nexport interface PrivateRevision {\n revision: number;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill' | 'action';\n}\n\nexport const TRANSCRIPT_STATES = keys<AgentTranscript>({\n state: true,\n deliveries: true,\n agents: true,\n views: true,\n commands: true,\n privateRevision: true,\n sprinkles: true,\n memories: true,\n memoryScopes: true,\n frozen: true,\n changes: true,\n monitor: true,\n vault: true,\n labels: true,\n guests: true,\n approvals: true,\n approvalPolicy: true,\n});\n\nexport const AgentTranscript: RemoteContract = contract('slicc.agent.transcript', {\n transcript: { state: TRANSCRIPT_STATES },\n});\n\nexport const REMOTE_METHODS = keys<AgentRemote>({\n prompt: true,\n watch: true,\n next: true,\n close: true,\n abort: true,\n});\n\nexport const REMOTE_READS: readonly (keyof AgentRemote & string)[] = ['watch', 'next', 'close'];\n\nexport interface GuestShown {\n id: string;\n label: string;\n agentId: string;\n name: string;\n expiresAt: number | null;\n gates: GuestGates;\n}\n\nexport interface GuestProposal {\n id: string;\n text: string;\n state: 'queued' | 'pending' | 'approved' | 'rejected' | 'unanswered' | 'withdrawn';\n reason: string | null;\n createdAt: number;\n decidedAt: number | null;\n}\n\nexport interface AgentGuest {\n readonly transcript: ReplicatedState<ConversationView>;\n readonly seat: ReplicatedState<GuestShown>;\n readonly proposals: ReplicatedState<GuestProposal[]>;\n propose(request: ProposeRequest, context: Context): Promise<Proposed>;\n guestOpen(draft: GuestDraft, context: Context): Promise<GuestOpened>;\n guestRevoke(id: string, context: Context): Promise<{ revoked: boolean }>;\n}\n\nexport const GUEST_STATES = ['transcript', 'seat', 'proposals'] as const;\n\nexport const GUEST_METHODS = ['propose', 'guestOpen', 'guestRevoke'] as const;\n\nexport const AgentGuestService: RemoteContract = contract('slicc.agent.guest', {\n guest: { state: GUEST_STATES, methods: GUEST_METHODS },\n none: {},\n});\n\nexport const AgentRemoteService: RemoteContract = contract('slicc.agent.remote', {\n remote: { methods: REMOTE_METHODS },\n watch: { methods: REMOTE_READS },\n});\n\nexport const PAGE_METHODS = keys<AgentPages>({\n open: true,\n report: true,\n next: true,\n answer: true,\n close: true,\n});\n\nexport const AgentPagesService: RemoteContract = contract('slicc.agent.pages', {\n pages: { methods: PAGE_METHODS },\n none: {},\n});\n\nexport const SUDO_METHODS = keys<Omit<AgentSudo, 'approvals'>>({\n request: true,\n withdraw: true,\n});\n\nexport const AgentSudoService: RemoteContract = contract('slicc.agent.sudo', {\n sudo: { state: ['approvals'], methods: SUDO_METHODS },\n none: {},\n});\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected' | 'expired';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n group?: 'providers' | 'mcp';\n secret?: 'api-key' | 'token';\n store?: 'vault';\n fields?: AccountField[];\n}\n\nexport interface AccountField {\n name: string;\n label: string;\n required?: boolean;\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface McpSignIn {\n url: string;\n state: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n moved?: { kind: 'model' | 'mcp'; label: string }[];\n labels?: Record<string, string>;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string | null,\n fields: Record<string, string> | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;\n dismissMoved(context: Context): Promise<void>;\n}\n\nexport const SETTINGS_METHODS = keys<Omit<AgentSettings, 'state'>>({\n connect: true,\n disconnect: true,\n signIn: true,\n dismissMoved: true,\n});\n\nexport const AgentSettings: RemoteContract = contract('slicc.agent.settings', {\n settings: { state: ['state'], methods: SETTINGS_METHODS },\n view: { state: ['state'] },\n});\n"],
|
|
5
|
-
"mappings": "AAkBA,SAAS,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import type { Context, JsonValue, RemoteContract, ReplicatedState } from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { Approval, ApprovalAnswer, ApprovalDecided } from './approvals/index.ts';\nimport type {\n ApprovalPolicy,\n ApprovalPolicyChange,\n ApprovalPolicySet,\n} from './approvals/policy.ts';\nimport type { AgentSudo } from './approvals/sudo.ts';\nimport type { SendAttachment, ShownAttachment } from './attachments.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { GuestOpened, Proposed, ProposeRequest } from './guests/index.ts';\nimport type { GuestDraft, GuestGates, GuestSeat } from './guests/seats.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { AgentPages } from './remote/pages.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport { contract } from './serving.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n attachments?: SendAttachment[];\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n monitorOpen(lease: string | null, resync: boolean, context: Context): Promise<MonitorLease>;\n monitorClose(lease: string, context: Context): Promise<void>;\n image(ref: ImageRef, context: Context): Promise<StoredImage>;\n agentCommands(agentId: string, context: Context): Promise<Command[]>;\n toolLabel(agentId: string, callIds: string[], context: Context): Promise<string | null>;\n guestOpen(draft: GuestDraft, context: Context): Promise<GuestOpened>;\n guestRevoke(id: string, context: Context): Promise<{ revoked: boolean }>;\n guestAlwaysForget(\n seat: string,\n approval: string,\n context: Context\n ): Promise<{ removed: boolean }>;\n approvalPolicySet(change: ApprovalPolicyChange, context: Context): Promise<ApprovalPolicySet>;\n decide(\n id: string,\n decision: ApprovalAnswer,\n reason: string | null,\n context: Context\n ): Promise<ApprovalDecided>;\n}\n\nexport interface ImageRef {\n entry: number;\n message: number;\n part: number;\n}\n\nexport type StoredImage = { data: string; mimeType: string } | { data: null; mimeType: null };\n\nexport interface MonitorLease {\n lease: string;\n ttlMs: number;\n}\n\nexport interface MonitorAgent {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n model: string | null;\n running: boolean;\n queued: number;\n tool: string | null;\n retry: { attempt: number; since: number; error: string } | null;\n failed: string | null;\n context: number | null;\n cpu?: number | null;\n}\n\nexport interface MonitorTask {\n id: string;\n kind: string;\n detail: string | null;\n agentId: string | null;\n owner: string | null;\n status: 'pending' | 'running' | 'waiting' | 'completing';\n phase: string;\n background: boolean;\n aborting: number | null;\n since: number;\n waits: number;\n}\n\nexport interface MonitorProcess {\n pid: number;\n ppid: number;\n pgid: number;\n user: string | null;\n agentId: string | null;\n command: string;\n state: 'S' | 'Z';\n started: number;\n zombie: number | null;\n tty: boolean;\n rss: number | null;\n utime?: number;\n stime?: number;\n cpu?: number | null;\n}\n\nexport interface MonitorProblem {\n id: string;\n at: number;\n agentId: string | null;\n kind: 'task' | 'retry' | 'turn';\n message: string;\n}\n\nexport interface MonitorFeed {\n open: boolean;\n at: number;\n usage: { tokens: number; cost: number; free: boolean } | null;\n agents: MonitorAgent[];\n tasks: MonitorTask[];\n processes: MonitorProcess[] | null;\n kernel: 'checking' | 'ok' | 'unreachable';\n problems: MonitorProblem[];\n paused: boolean;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null; attachments?: ShownAttachment[] }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nconst keys = <T>(record: Record<keyof T, true>) => Object.keys(record) as (keyof T & string)[];\n\nexport const CONTROL_METHODS = keys<AgentControl>({\n send: true,\n wait: true,\n withdraw: true,\n abort: true,\n compact: true,\n compactAgent: true,\n reset: true,\n configure: true,\n rewind: true,\n rewindAgent: true,\n resolveLick: true,\n resolveAgentLick: true,\n webhook: true,\n stopAgent: true,\n selectCone: true,\n createCone: true,\n createScoop: true,\n drop: true,\n unqueue: true,\n sprinkleSend: true,\n sprinkleCall: true,\n memorySave: true,\n memoryRemove: true,\n freeze: true,\n newChat: true,\n thaw: true,\n discard: true,\n changesOpen: true,\n changeAccept: true,\n changeRevert: true,\n monitorOpen: true,\n monitorClose: true,\n image: true,\n agentCommands: true,\n toolLabel: true,\n guestOpen: true,\n guestRevoke: true,\n guestAlwaysForget: true,\n approvalPolicySet: true,\n decide: true,\n});\n\nexport const OWNER_DEVICE_METHODS: readonly (keyof AgentControl & string)[] = [\n 'decide',\n 'guestOpen',\n 'guestRevoke',\n 'guestAlwaysForget',\n 'approvalPolicySet',\n];\n\nexport const CONTROL_READS: readonly (keyof AgentControl & string)[] = [\n 'wait',\n 'changesOpen',\n 'monitorOpen',\n 'monitorClose',\n 'image',\n 'toolLabel',\n];\n\nexport const AgentControl: RemoteContract = contract('slicc.agent.control', {\n control: { methods: CONTROL_METHODS },\n view: { methods: [...CONTROL_READS, ...OWNER_DEVICE_METHODS] },\n});\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly privateRevision: ReplicatedState<PrivateRevision>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n readonly monitor: ReplicatedState<MonitorFeed>;\n readonly vault: ReplicatedState<VaultState>;\n readonly labels: ReplicatedState<Record<string, string>>;\n readonly guests: ReplicatedState<GuestSeat[]>;\n readonly approvals: ReplicatedState<Approval[]>;\n readonly approvalPolicy: ReplicatedState<ApprovalPolicy>;\n}\n\nexport interface PrivateRevision {\n revision: number;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill' | 'action';\n}\n\nexport const TRANSCRIPT_STATES = keys<AgentTranscript>({\n state: true,\n deliveries: true,\n agents: true,\n views: true,\n commands: true,\n privateRevision: true,\n sprinkles: true,\n memories: true,\n memoryScopes: true,\n frozen: true,\n changes: true,\n monitor: true,\n vault: true,\n labels: true,\n guests: true,\n approvals: true,\n approvalPolicy: true,\n});\n\nexport const AgentTranscript: RemoteContract = contract('slicc.agent.transcript', {\n transcript: { state: TRANSCRIPT_STATES },\n});\n\nexport const REMOTE_METHODS = keys<AgentRemote>({\n prompt: true,\n watch: true,\n next: true,\n close: true,\n abort: true,\n});\n\nexport const REMOTE_READS: readonly (keyof AgentRemote & string)[] = ['watch', 'next', 'close'];\n\nexport interface GuestShown {\n id: string;\n label: string;\n agentId: string;\n name: string;\n expiresAt: number | null;\n gates: GuestGates;\n}\n\nexport interface GuestProposal {\n id: string;\n text: string;\n state: 'queued' | 'pending' | 'approved' | 'rejected' | 'unanswered' | 'withdrawn';\n reason: string | null;\n createdAt: number;\n decidedAt: number | null;\n}\n\nexport interface AgentGuest {\n readonly transcript: ReplicatedState<ConversationView>;\n readonly seat: ReplicatedState<GuestShown>;\n readonly proposals: ReplicatedState<GuestProposal[]>;\n propose(request: ProposeRequest, context: Context): Promise<Proposed>;\n guestOpen(draft: GuestDraft, context: Context): Promise<GuestOpened>;\n guestRevoke(id: string, context: Context): Promise<{ revoked: boolean }>;\n}\n\nexport const GUEST_STATES = ['transcript', 'seat', 'proposals'] as const;\n\nexport const GUEST_METHODS = ['propose', 'guestOpen', 'guestRevoke'] as const;\n\nexport const AgentGuestService: RemoteContract = contract('slicc.agent.guest', {\n guest: { state: GUEST_STATES, methods: GUEST_METHODS },\n none: {},\n});\n\nexport const AgentRemoteService: RemoteContract = contract('slicc.agent.remote', {\n remote: { methods: REMOTE_METHODS },\n watch: { methods: REMOTE_READS },\n});\n\nexport const PAGE_METHODS = keys<AgentPages>({\n open: true,\n report: true,\n next: true,\n answer: true,\n close: true,\n});\n\nexport const AgentPagesService: RemoteContract = contract('slicc.agent.pages', {\n pages: { methods: PAGE_METHODS },\n none: {},\n});\n\nexport const SUDO_METHODS = keys<Omit<AgentSudo, 'approvals'>>({\n request: true,\n withdraw: true,\n});\n\nexport const AgentSudoService: RemoteContract = contract('slicc.agent.sudo', {\n sudo: { state: ['approvals'], methods: SUDO_METHODS },\n none: {},\n});\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected' | 'expired';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n group?: 'providers' | 'mcp';\n secret?: 'api-key' | 'token';\n store?: 'vault';\n fields?: AccountField[];\n}\n\nexport interface AccountField {\n name: string;\n label: string;\n required?: boolean;\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface McpSignIn {\n url: string;\n state: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n moved?: { kind: 'model' | 'mcp'; label: string }[];\n labels?: Record<string, string>;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string | null,\n fields: Record<string, string> | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;\n dismissMoved(context: Context): Promise<void>;\n}\n\nexport const SETTINGS_METHODS = keys<Omit<AgentSettings, 'state'>>({\n connect: true,\n disconnect: true,\n signIn: true,\n dismissMoved: true,\n});\n\nexport const AgentSettings: RemoteContract = contract('slicc.agent.settings', {\n settings: { state: ['state'], methods: SETTINGS_METHODS },\n view: { state: ['state'] },\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/types/agent.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Models } from '@earendil-works/pi-ai/models';
|
|
|
3
3
|
import { type Conversation, Harness, type HarnessOptions, type ModelRef, type Registry, type Storage } from '@earendil-works/pi-durable';
|
|
4
4
|
import { type Agents } from './agents.ts';
|
|
5
5
|
import type { Cones } from './cone.ts';
|
|
6
|
+
import { type GuestToolGate } from './guests/guard.ts';
|
|
6
7
|
import { type GuestReviews } from './guests/review.ts';
|
|
7
8
|
export interface AgentOptions {
|
|
8
9
|
models: Models;
|
|
@@ -20,6 +21,7 @@ export interface Agent extends Cones {
|
|
|
20
21
|
readonly root: Conversation;
|
|
21
22
|
readonly agents: Agents;
|
|
22
23
|
readonly reviews: GuestReviews;
|
|
24
|
+
readonly gate: GuestToolGate;
|
|
23
25
|
onCone(listener: (conversation: Conversation) => void | Promise<void>): () => void;
|
|
24
26
|
prompt(text: string): Promise<string>;
|
|
25
27
|
close(): Promise<void>;
|
package/dist/types/control.d.ts
CHANGED
|
@@ -24,4 +24,4 @@ export interface HostScoops {
|
|
|
24
24
|
}
|
|
25
25
|
export declare function readable(out: string): string;
|
|
26
26
|
export declare function submissionId(value: string): SubmissionId | undefined;
|
|
27
|
-
export declare function createAgentControl(harness: Harness, target: Conversation | Cones, deliveries?: Deliveries, licks?: HostLicks, scoops?: HostScoops, skills?: Pick<SkillsRuntime, 'expand' | 'commandsFor'>, sprinkles?: Pick<SprinklesRuntime, 'send' | 'call'>, memory?: Pick<MemoryRuntime, 'save' | 'remove'>, freezer?: Pick<FreezerRuntime, 'freeze' | 'newChat' | 'thaw' | 'discard'>, changes?: Pick<ChangesRuntime, 'open' | 'accept' | 'revert'>, monitor?: Pick<Monitor, 'open' | 'close'>, secrets?: () => readonly SecretName[], uploads?: Uploads, labels?: Pick<LabelsRuntime, 'label'>, guests?: Pick<Guests, 'open' | 'revoke'>): Omit<AgentControl, 'approvalPolicySet'>;
|
|
27
|
+
export declare function createAgentControl(harness: Harness, target: Conversation | Cones, deliveries?: Deliveries, licks?: HostLicks, scoops?: HostScoops, skills?: Pick<SkillsRuntime, 'expand' | 'commandsFor'>, sprinkles?: Pick<SprinklesRuntime, 'send' | 'call'>, memory?: Pick<MemoryRuntime, 'save' | 'remove'>, freezer?: Pick<FreezerRuntime, 'freeze' | 'newChat' | 'thaw' | 'discard'>, changes?: Pick<ChangesRuntime, 'open' | 'accept' | 'revert'>, monitor?: Pick<Monitor, 'open' | 'close'>, secrets?: () => readonly SecretName[], uploads?: Uploads, labels?: Pick<LabelsRuntime, 'label'>, guests?: Pick<Guests, 'open' | 'revoke' | 'forgetAlways'>): Omit<AgentControl, 'approvalPolicySet'>;
|