chat-ui-agent-demo / src /lib /server /agent /AgentConfigurationLedger.ts
Mike0021's picture
Deploy hardened Agent UX and isolated previews (part 2)
2df2e7e verified
Raw History Blame Contribute Delete
10.5 kB
import { createHash } from "node:crypto";
import { MongoServerError, ObjectId } from "mongodb";
import { collections } from "$lib/server/database";
import type {
AgentConfigurationAction,
AgentConfigurationKey,
AgentConfigurationReceipt,
Workspace,
} from "$lib/types/Workspace";
export type AgentConfigurationPayload =
| { action: "set-model"; model: string }
| { action: "set-thinking"; level: string }
| { action: "set-policy"; policy: string };
export type AgentConfigurationReceiptState =
| { status: "missing" }
| { status: "pending"; receipt: AgentConfigurationReceipt }
| { status: "completed"; receipt: AgentConfigurationReceipt }
| { status: "conflict" }
| { status: "stale" };
/** Canonical hash which binds one stable client id to one exact setting. */
export function fingerprintAgentConfiguration(payload: AgentConfigurationPayload): string {
return createHash("sha256")
.update(
JSON.stringify({
action: payload.action,
value: configurationValue(payload),
})
)
.digest("hex");
}
/** Read-only preflight lets completed retries succeed without opening the sandbox. */
export async function inspectAgentConfiguration(options: {
workspaceId: Workspace["_id"];
controlId: string;
fingerprint: string;
}): Promise<AgentConfigurationReceiptState> {
const receipt = await collections.agentConfigurationReceipts.findOne({
workspaceId: options.workspaceId,
controlId: options.controlId,
});
return classifyReceipt(receipt, options.fingerprint);
}
/**
* Append a command to the durable per-workspace log and make it latest for its
* setting kind. Receipts are separate documents, so stable ids are never
* evicted and a hostile number of settings cannot grow the Workspace document.
*
* The placeholder's baseSequence closes both sides of the two-document crash
* window: a missing head update can be resumed, while a later request which
* advanced the same setting causes the older placeholder to be superseded.
*/
export async function registerAgentConfiguration(options: {
workspace: Workspace;
controlId: string;
payload: AgentConfigurationPayload;
now?: Date;
}): Promise<AgentConfigurationReceiptState> {
const fingerprint = fingerprintAgentConfiguration(options.payload);
const now = options.now ?? new Date();
const key = configurationKey(options.payload.action);
const sandbox = options.workspace.sandbox;
if (!sandbox.id || !sandbox.generation || !sandbox.nonce) return { status: "stale" };
await ensureLedger(options.workspace, now);
for (;;) {
const existing = await collections.agentConfigurationReceipts.findOne({
workspaceId: options.workspace._id,
controlId: options.controlId,
});
if (existing) {
return resumeReceipt({
workspace: options.workspace,
receipt: existing,
fingerprint,
key,
now,
});
}
const ledger = await collections.agentConfigurationLedgers.findOne({
_id: options.workspace._id,
});
if (!ledger) {
await ensureLedger(options.workspace, now);
continue;
}
const receipt: AgentConfigurationReceipt = {
_id: new ObjectId(),
workspaceId: options.workspace._id,
conversationId: options.workspace.conversationId,
controlId: options.controlId,
fingerprint,
action: options.payload.action,
value: configurationValue(options.payload),
baseSequence: ledger.nextSequence,
status: "pending",
requestedAt: now,
sandboxId: sandbox.id,
sandboxGeneration: sandbox.generation,
sandboxNonce: sandbox.nonce,
createdAt: now,
updatedAt: now,
};
try {
await collections.agentConfigurationReceipts.insertOne(receipt);
} catch (cause) {
if (cause instanceof MongoServerError && cause.code === 11000) continue;
throw cause;
}
return resumeReceipt({
workspace: options.workspace,
receipt,
fingerprint,
key,
now,
});
}
}
export async function completeAgentConfiguration(options: {
workspaceId: Workspace["_id"];
controlId: string;
fingerprint: string;
action: AgentConfigurationAction;
now?: Date;
}): Promise<boolean> {
const now = options.now ?? new Date();
const receipt = await collections.agentConfigurationReceipts.findOne({
workspaceId: options.workspaceId,
controlId: options.controlId,
});
const classified = classifyReceipt(receipt, options.fingerprint);
if (classified.status === "completed") return true;
if (classified.status !== "pending" || classified.receipt.sequence === undefined) return false;
const key = configurationKey(options.action);
const ledger = await collections.agentConfigurationLedgers.findOne({
_id: options.workspaceId,
});
const latest = ledger?.latest[key];
if (
!latest ||
latest.controlId !== options.controlId ||
latest.fingerprint !== options.fingerprint ||
latest.sequence !== classified.receipt.sequence
) {
if (latest && latest.sequence > classified.receipt.sequence) {
return markSuperseded(classified.receipt, options.fingerprint, now);
}
return false;
}
const completed = await collections.agentConfigurationReceipts.updateOne(
{
_id: classified.receipt._id,
fingerprint: options.fingerprint,
status: "pending",
sequence: classified.receipt.sequence,
},
{
$set: { status: "completed", completedAt: now, updatedAt: now },
}
);
if (completed.matchedCount === 1) return true;
const current = await inspectAgentConfiguration({
workspaceId: options.workspaceId,
controlId: options.controlId,
fingerprint: options.fingerprint,
});
return current.status === "completed";
}
async function ensureLedger(workspace: Workspace, now: Date): Promise<void> {
await collections.agentConfigurationLedgers.updateOne(
{ _id: workspace._id },
{
$setOnInsert: {
conversationId: workspace.conversationId,
nextSequence: 0,
latest: {},
createdAt: now,
updatedAt: now,
},
},
{ upsert: true }
);
}
async function resumeReceipt(options: {
workspace: Workspace;
receipt: AgentConfigurationReceipt;
fingerprint: string;
key: AgentConfigurationKey;
now: Date;
}): Promise<AgentConfigurationReceiptState> {
let receipt = options.receipt;
const classified = classifyReceipt(receipt, options.fingerprint);
if (classified.status !== "pending") return classified;
const sandbox = options.workspace.sandbox;
if (
receipt.sandboxId !== sandbox.id ||
receipt.sandboxGeneration !== sandbox.generation ||
receipt.sandboxNonce !== sandbox.nonce
) {
return { status: "stale" };
}
for (;;) {
const ledger = await collections.agentConfigurationLedgers.findOne({
_id: options.workspace._id,
});
if (!ledger) return { status: "stale" };
const latest = ledger.latest[options.key];
if (receipt.sequence !== undefined) {
if (latest && latest.sequence > receipt.sequence) {
await markSuperseded(receipt, options.fingerprint, options.now);
return inspectAgentConfiguration({
workspaceId: options.workspace._id,
controlId: receipt.controlId,
fingerprint: options.fingerprint,
});
}
if (
latest?.controlId === receipt.controlId &&
latest.fingerprint === options.fingerprint &&
latest.sequence === receipt.sequence
) {
return { status: "pending", receipt };
}
return { status: "stale" };
}
if (latest?.controlId === receipt.controlId && latest.fingerprint === options.fingerprint) {
const restored = await collections.agentConfigurationReceipts.findOneAndUpdate(
{ _id: receipt._id, fingerprint: options.fingerprint, sequence: { $exists: false } },
{ $set: { sequence: latest.sequence, updatedAt: options.now } },
{ returnDocument: "after", includeResultMetadata: false }
);
if (restored) return { status: "pending", receipt: restored };
const current = await collections.agentConfigurationReceipts.findOne({ _id: receipt._id });
if (!current) return { status: "stale" };
receipt = current;
continue;
}
if (latest && latest.sequence > receipt.baseSequence) {
await markSuperseded(receipt, options.fingerprint, options.now);
return inspectAgentConfiguration({
workspaceId: options.workspace._id,
controlId: receipt.controlId,
fingerprint: options.fingerprint,
});
}
const sequence = ledger.nextSequence + 1;
const advanced = await collections.agentConfigurationLedgers.updateOne(
{ _id: options.workspace._id, nextSequence: ledger.nextSequence },
{
$inc: { nextSequence: 1 },
$set: {
[`latest.${options.key}`]: {
controlId: receipt.controlId,
fingerprint: options.fingerprint,
sequence,
},
updatedAt: options.now,
},
}
);
if (advanced.matchedCount !== 1) continue;
const assigned = await collections.agentConfigurationReceipts.findOneAndUpdate(
{ _id: receipt._id, fingerprint: options.fingerprint, sequence: { $exists: false } },
{ $set: { sequence, updatedAt: options.now } },
{ returnDocument: "after", includeResultMetadata: false }
);
if (assigned) return { status: "pending", receipt: assigned };
const current = await collections.agentConfigurationReceipts.findOne({ _id: receipt._id });
if (!current) return { status: "stale" };
receipt = current;
}
}
async function markSuperseded(
receipt: AgentConfigurationReceipt,
fingerprint: string,
now: Date
): Promise<boolean> {
const superseded = await collections.agentConfigurationReceipts.updateOne(
{ _id: receipt._id, fingerprint, status: "pending" },
{ $set: { status: "superseded", completedAt: now, updatedAt: now } }
);
if (superseded.matchedCount === 1) return true;
const current = await collections.agentConfigurationReceipts.findOne({ _id: receipt._id });
return current?.fingerprint === fingerprint && current.status !== "pending";
}
function classifyReceipt(
receipt: AgentConfigurationReceipt | null | undefined,
fingerprint: string
): AgentConfigurationReceiptState {
if (!receipt) return { status: "missing" };
if (receipt.fingerprint !== fingerprint) return { status: "conflict" };
return receipt.status === "pending"
? { status: "pending", receipt }
: { status: "completed", receipt };
}
function configurationKey(action: AgentConfigurationAction): AgentConfigurationKey {
switch (action) {
case "set-model":
return "model";
case "set-thinking":
return "thinking";
case "set-policy":
return "policy";
}
}
function configurationValue(payload: AgentConfigurationPayload): string {
switch (payload.action) {
case "set-model":
return payload.model;
case "set-thinking":
return payload.level;
case "set-policy":
return payload.policy;
}
}