@tangle-network/agent-app 0.60.177 → 0.60.178
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/dist/agent-profiles/d1.js +1 -1
- package/dist/agent-profiles/index.js +9 -1
- package/dist/agent-profiles/self-management.d.ts +82 -0
- package/dist/{chunk-6VXBUIM5.js → chunk-ARBBJWZA.js} +63 -6
- package/dist/{chunk-6VXBUIM5.js.map → chunk-ARBBJWZA.js.map} +1 -1
- package/dist/{chunk-MCAIZKQ5.js → chunk-CPNJRLPN.js} +15 -4
- package/dist/chunk-CPNJRLPN.js.map +1 -0
- package/dist/hub-approvals/index.js +1 -1
- package/dist/hub-approvals/present.d.ts +1 -1
- package/dist/hub-approvals/types.d.ts +35 -0
- package/dist/hub-approvals-react/dock.d.ts +3 -2
- package/dist/hub-approvals-react/email.d.ts +13 -0
- package/dist/hub-approvals-react/feedback.d.ts +20 -0
- package/dist/hub-approvals-react/index.d.ts +1 -0
- package/dist/hub-approvals-react/index.js +535 -286
- package/dist/hub-approvals-react/index.js.map +1 -1
- package/dist/hub-approvals-react/parts.d.ts +1 -1
- package/dist/hub-approvals-react/row.d.ts +3 -2
- package/package.json +1 -1
- package/dist/chunk-MCAIZKQ5.js.map +0 -1
|
@@ -7,8 +7,11 @@ import {
|
|
|
7
7
|
addProfileKnowledgeDocument,
|
|
8
8
|
admitProfileTurn,
|
|
9
9
|
bindProfileText,
|
|
10
|
+
createDrizzleSelfMountStorage,
|
|
10
11
|
createInMemorySelfMountStorage,
|
|
12
|
+
createKVSelfMountStorage,
|
|
11
13
|
createMountProfileChangeTool,
|
|
14
|
+
createProductSelfMount,
|
|
12
15
|
createTextProfile,
|
|
13
16
|
handleProfileSwitchText,
|
|
14
17
|
parseProfileRevisionDiff,
|
|
@@ -25,9 +28,10 @@ import {
|
|
|
25
28
|
readProfileAdmission,
|
|
26
29
|
removeProfileKnowledgeDocument,
|
|
27
30
|
rollbackProfileBinding,
|
|
31
|
+
selfMountTable,
|
|
28
32
|
serializeProfileRevisionDiff,
|
|
29
33
|
switchProfile
|
|
30
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-ARBBJWZA.js";
|
|
31
35
|
import {
|
|
32
36
|
normalizeProfileName,
|
|
33
37
|
parseProfileSwitch
|
|
@@ -44,8 +48,11 @@ export {
|
|
|
44
48
|
addProfileKnowledgeDocument,
|
|
45
49
|
admitProfileTurn,
|
|
46
50
|
bindProfileText,
|
|
51
|
+
createDrizzleSelfMountStorage,
|
|
47
52
|
createInMemorySelfMountStorage,
|
|
53
|
+
createKVSelfMountStorage,
|
|
48
54
|
createMountProfileChangeTool,
|
|
55
|
+
createProductSelfMount,
|
|
49
56
|
createTextProfile,
|
|
50
57
|
handleProfileSwitchText,
|
|
51
58
|
normalizeProfileName,
|
|
@@ -64,6 +71,7 @@ export {
|
|
|
64
71
|
readProfileAdmission,
|
|
65
72
|
removeProfileKnowledgeDocument,
|
|
66
73
|
rollbackProfileBinding,
|
|
74
|
+
selfMountTable,
|
|
67
75
|
serializeProfileRevisionDiff,
|
|
68
76
|
switchProfile
|
|
69
77
|
};
|
|
@@ -75,3 +75,85 @@ export interface MountProfileChangeResult {
|
|
|
75
75
|
* MCP surface like any other app tool.
|
|
76
76
|
*/
|
|
77
77
|
export declare function createMountProfileChangeTool(deps: MountProfileChangeDeps): AppToolDefinition<Record<string, unknown>>;
|
|
78
|
+
/** Any drizzle database instance (structural — the adapters only use
|
|
79
|
+
* select/insert with the standard builder chain). */
|
|
80
|
+
type DrizzleLike = any;
|
|
81
|
+
/** Create (or use) the standard self-mount table in a drizzle/D1 database. */
|
|
82
|
+
export declare function selfMountTable(tableName: string): import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
83
|
+
name: string;
|
|
84
|
+
schema: undefined;
|
|
85
|
+
columns: {
|
|
86
|
+
scope: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
87
|
+
name: "scope";
|
|
88
|
+
tableName: string;
|
|
89
|
+
dataType: "string";
|
|
90
|
+
columnType: "SQLiteText";
|
|
91
|
+
data: string;
|
|
92
|
+
driverParam: string;
|
|
93
|
+
notNull: true;
|
|
94
|
+
hasDefault: false;
|
|
95
|
+
isPrimaryKey: true;
|
|
96
|
+
isAutoincrement: false;
|
|
97
|
+
hasRuntimeDefault: false;
|
|
98
|
+
enumValues: [string, ...string[]];
|
|
99
|
+
baseColumn: never;
|
|
100
|
+
identity: undefined;
|
|
101
|
+
generated: undefined;
|
|
102
|
+
}, {}, {
|
|
103
|
+
length: number | undefined;
|
|
104
|
+
}>;
|
|
105
|
+
mounted: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
106
|
+
name: "mounted";
|
|
107
|
+
tableName: string;
|
|
108
|
+
dataType: "string";
|
|
109
|
+
columnType: "SQLiteText";
|
|
110
|
+
data: string;
|
|
111
|
+
driverParam: string;
|
|
112
|
+
notNull: true;
|
|
113
|
+
hasDefault: false;
|
|
114
|
+
isPrimaryKey: false;
|
|
115
|
+
isAutoincrement: false;
|
|
116
|
+
hasRuntimeDefault: false;
|
|
117
|
+
enumValues: [string, ...string[]];
|
|
118
|
+
baseColumn: never;
|
|
119
|
+
identity: undefined;
|
|
120
|
+
generated: undefined;
|
|
121
|
+
}, {}, {
|
|
122
|
+
length: number | undefined;
|
|
123
|
+
}>;
|
|
124
|
+
};
|
|
125
|
+
dialect: 'sqlite';
|
|
126
|
+
}>;
|
|
127
|
+
/** A drizzle-backed SelfMountStorage against any table with the standard
|
|
128
|
+
* shape (scope primary key + mounted JSON text column). Works with the
|
|
129
|
+
* tables every product creates via {@link selfMountTable}. */
|
|
130
|
+
export declare function createDrizzleSelfMountStorage(db: DrizzleLike, table: ReturnType<typeof selfMountTable>, baseline: string): SelfMountStorage;
|
|
131
|
+
/** A KV-backed SelfMountStorage (Cloudflare KV, any namespace). */
|
|
132
|
+
export declare function createKVSelfMountStorage(kv: {
|
|
133
|
+
get(key: string): Promise<string | null>;
|
|
134
|
+
put(key: string, value: string): Promise<void>;
|
|
135
|
+
}, prefix: string, baseline: string): SelfMountStorage;
|
|
136
|
+
/** The one-call product wiring: catalog + storage + baseline + cap. */
|
|
137
|
+
export interface ProductSelfMountConfig {
|
|
138
|
+
/** The product's skill catalog (id + description per skill). */
|
|
139
|
+
skills: ReadonlyArray<{
|
|
140
|
+
id: string;
|
|
141
|
+
description: string;
|
|
142
|
+
}>;
|
|
143
|
+
/** A drizzle/D1 database (uses a self-mount table) or a KV namespace. */
|
|
144
|
+
db?: DrizzleLike;
|
|
145
|
+
kv?: {
|
|
146
|
+
get(key: string): Promise<string | null>;
|
|
147
|
+
put(key: string, value: string): Promise<void>;
|
|
148
|
+
};
|
|
149
|
+
/** The table name for drizzle storage (default: 'agent_self_mounts'). */
|
|
150
|
+
tableName?: string;
|
|
151
|
+
/** KV prefix (default: 'self-mount'). */
|
|
152
|
+
kvPrefix?: string;
|
|
153
|
+
/** The skill id that can never be removed. */
|
|
154
|
+
baseline: string;
|
|
155
|
+
/** Max simultaneous mounts (default: 12). */
|
|
156
|
+
maxMounted?: number;
|
|
157
|
+
}
|
|
158
|
+
export declare function createProductSelfMount(config: ProductSelfMountConfig): AppToolDefinition<Record<string, unknown>>;
|
|
159
|
+
export {};
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
|
|
21
21
|
// src/agent-profiles/self-management.ts
|
|
22
|
+
import { eq } from "drizzle-orm";
|
|
23
|
+
import { sqliteTable, text } from "drizzle-orm/sqlite-core";
|
|
22
24
|
var PERMITTED_SELF_MOUNT_DIMENSIONS = ["skills"];
|
|
23
25
|
function createInMemorySelfMountStorage() {
|
|
24
26
|
const state = /* @__PURE__ */ new Map();
|
|
@@ -125,6 +127,57 @@ function createMountProfileChangeTool(deps) {
|
|
|
125
127
|
}
|
|
126
128
|
});
|
|
127
129
|
}
|
|
130
|
+
function selfMountTable(tableName) {
|
|
131
|
+
return sqliteTable(tableName, {
|
|
132
|
+
scope: text("scope").primaryKey(),
|
|
133
|
+
mounted: text("mounted").notNull()
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function createDrizzleSelfMountStorage(db, table, baseline) {
|
|
137
|
+
return {
|
|
138
|
+
async get(scope) {
|
|
139
|
+
const rows = await db.select({ mounted: table.mounted }).from(table).where(eq(table.scope, scope)).limit(1);
|
|
140
|
+
try {
|
|
141
|
+
return rows[0] ? JSON.parse(rows[0].mounted) : [baseline];
|
|
142
|
+
} catch {
|
|
143
|
+
return [baseline];
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
async set(scope, ids) {
|
|
147
|
+
await db.insert(table).values({ scope, mounted: JSON.stringify(ids) }).onConflictDoUpdate({
|
|
148
|
+
target: table.scope,
|
|
149
|
+
set: { mounted: JSON.stringify(ids) }
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function createKVSelfMountStorage(kv, prefix, baseline) {
|
|
155
|
+
const key = (scope) => `${prefix}:${scope}`;
|
|
156
|
+
return {
|
|
157
|
+
async get(scope) {
|
|
158
|
+
const raw = await kv.get(key(scope));
|
|
159
|
+
try {
|
|
160
|
+
return raw ? JSON.parse(raw) : [baseline];
|
|
161
|
+
} catch {
|
|
162
|
+
return [baseline];
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
async set(scope, ids) {
|
|
166
|
+
await kv.put(key(scope), JSON.stringify(ids));
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function createProductSelfMount(config) {
|
|
171
|
+
const storage = config.db ? createDrizzleSelfMountStorage(config.db, selfMountTable(config.tableName ?? "agent_self_mounts"), config.baseline) : config.kv ? createKVSelfMountStorage(config.kv, config.kvPrefix ?? "self-mount", config.baseline) : void 0;
|
|
172
|
+
if (!storage) throw new Error("createProductSelfMount needs db or kv");
|
|
173
|
+
return createMountProfileChangeTool({
|
|
174
|
+
skills: config.skills,
|
|
175
|
+
storage,
|
|
176
|
+
scopeKey: (ctx) => ctx.workspaceId ?? ctx.threadId ?? "",
|
|
177
|
+
baseline: config.baseline,
|
|
178
|
+
maxMounted: config.maxMounted ?? 12
|
|
179
|
+
});
|
|
180
|
+
}
|
|
128
181
|
|
|
129
182
|
// src/agent-profiles/index.ts
|
|
130
183
|
var PROFILE_CHANGE_POLICY = {
|
|
@@ -621,9 +674,9 @@ function profileTools(context) {
|
|
|
621
674
|
const turn = await context.activeTurn();
|
|
622
675
|
if (turn.role !== "owner" && turn.role !== "manager") throw new ProfileAccessError("Profile management is required");
|
|
623
676
|
if (context.memory) {
|
|
624
|
-
const
|
|
625
|
-
const known = (await context.memory.list(turn.workspaceId, PROFILE_MEMORY_PREFIX)).find((entry) => entry.content?.trim() ===
|
|
626
|
-
if (known) return { memoryId: known.id, saved: true, alreadyKnown: true, line: `- ${
|
|
677
|
+
const text2 = fact.replace(/\s+/g, " ");
|
|
678
|
+
const known = (await context.memory.list(turn.workspaceId, PROFILE_MEMORY_PREFIX)).find((entry) => entry.content?.trim() === text2);
|
|
679
|
+
if (known) return { memoryId: known.id, saved: true, alreadyKnown: true, line: `- ${text2}`, appliesTo: "next_message" };
|
|
627
680
|
const id = crypto.randomUUID();
|
|
628
681
|
const saved = await context.memory.put({
|
|
629
682
|
workspaceId: turn.workspaceId,
|
|
@@ -631,10 +684,10 @@ function profileTools(context) {
|
|
|
631
684
|
kind: "fact",
|
|
632
685
|
ifRevision: null,
|
|
633
686
|
actor: turn.memberId,
|
|
634
|
-
content:
|
|
687
|
+
content: text2,
|
|
635
688
|
id
|
|
636
689
|
});
|
|
637
|
-
return { memoryId: saved.id, saved: true, alreadyKnown: false, line: `- ${
|
|
690
|
+
return { memoryId: saved.id, saved: true, alreadyKnown: false, line: `- ${text2}`, appliesTo: "next_message" };
|
|
638
691
|
}
|
|
639
692
|
const line = `- ${fact.replace(/\s+/g, " ")}`;
|
|
640
693
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -689,6 +742,10 @@ export {
|
|
|
689
742
|
PERMITTED_SELF_MOUNT_DIMENSIONS,
|
|
690
743
|
createInMemorySelfMountStorage,
|
|
691
744
|
createMountProfileChangeTool,
|
|
745
|
+
selfMountTable,
|
|
746
|
+
createDrizzleSelfMountStorage,
|
|
747
|
+
createKVSelfMountStorage,
|
|
748
|
+
createProductSelfMount,
|
|
692
749
|
PROFILE_CHANGE_POLICY,
|
|
693
750
|
ProfileConflictError,
|
|
694
751
|
ProfileAccessError,
|
|
@@ -715,4 +772,4 @@ export {
|
|
|
715
772
|
PROFILE_MEMORY_PREFIX,
|
|
716
773
|
profileTools
|
|
717
774
|
};
|
|
718
|
-
//# sourceMappingURL=chunk-
|
|
775
|
+
//# sourceMappingURL=chunk-ARBBJWZA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent-profiles/index.ts","../src/agent-profiles/self-management.ts"],"sourcesContent":["/** Chat-owned profile revisions and member/channel bindings. Execution stays in the substrate. */\nimport {\n canonicalAgentProfileDigest,\n diffAgentProfiles,\n snapshotAgentProfile,\n sha256Utf8,\n type AgentProfile,\n type AgentProfileDiff,\n} from '@tangle-network/agent-interface'\nimport { z } from 'zod'\nimport { normalizeProfileName, parseProfileSwitch } from './switch'\nexport { normalizeProfileName, parseProfileSwitch }\nimport type { McpToolDefinition } from '../tools'\n\nexport type ProfileAuthorKind = 'person' | 'agent' | 'optimizer'\nexport type ProfileRevisionState = 'active' | 'candidate' | 'pending-consent'\n\n/** The decision table used by every write path; products may narrow access, never widen it. */\nexport const PROFILE_CHANGE_POLICY = {\n textEdit: { admission: 'automatic', conversation: 'same', destructive: false },\n sameAuthoritySwitch: { admission: 'prepare-then-flip', conversation: 'same', destructive: false },\n differentAuthoritySwitch: { admission: 'prepare-then-flip', conversation: 'same', destructive: false },\n authorityEdit: { admission: 'editor-consent', conversation: 'same', destructive: false },\n optimizerRevision: { admission: 'eval-promotion', conversation: 'same', destructive: false },\n destructiveAction: { admission: 'reaper-only', conversation: 'none', destructive: true },\n} as const\n\nexport interface ProfileRevision {\n id: string\n workspaceId: string\n profileId: string\n parentId: string | null\n profile: AgentProfile\n knowledgeText: string\n author: { kind: ProfileAuthorKind; id: string }\n reason: string\n /** `null` means an older stored revision did not record the knowledge delta. */\n knowledgeTextChanged?: boolean | null\n diff: AgentProfileDiff[]\n authorityDigest: string\n /** ADC hash of the public profile plan, without per-turn product attachments. */\n planDigest: string\n state: ProfileRevisionState\n createdAt: number\n}\n\nexport interface ProfileBindingKey {\n workspaceId: string\n memberId: string\n /** `chat`, or a product-scoped phone line and sender key. */\n channel: string\n}\n\nexport interface ProfileBinding extends ProfileBindingKey {\n profileId: string\n pinnedRevisionId: string | null\n authorityDigest: string\n planDigest: string\n version: number\n}\n\nexport interface ProfileTurnPin {\n workspaceId: string\n memberId: string\n channel: string\n messageId: string\n inputHash: string\n profileId: string\n revisionId: string\n authorityDigest: string\n /** Effective ADC plan selected by the executor, including allowed turn attachments. */\n planDigest: string\n}\n\n/** Remove events name only adds they observed; a concurrent add survives. */\nexport interface ProfileKnowledgeEvent {\n id: string\n workspaceId: string\n profileId: string\n documentId: string\n kind: 'add' | 'remove'\n content: string | null\n observedAddIds: string[]\n createdAt: number\n}\n\nexport interface ProfileKnowledgeDocument {\n documentId: string\n content: string\n addEventId: string\n}\n\nexport interface ProfileSwitchReceipt {\n key: ProfileBindingKey\n messageId: string\n inputHash: string\n /** Visible conversation that should render this switch marker on reload. */\n conversationId?: string | null\n createdAt?: number\n profileId: string | null\n revisionId: string | null\n /** A rollback binds the previous immutable revision, not the current head. */\n pinnedRevisionId: string | null\n authorityDigest: string | null\n planDigest: string | null\n outcome: 'switched' | 'refused'\n message: string\n /** Workspace resource collisions retain the original and place the profile copy beside it. */\n conflicts: string[]\n}\n\nexport interface ProfileRevisionStore {\n getActiveRevision(workspaceId: string, profileId: string): Promise<ProfileRevision | null>\n getRevision(workspaceId: string, profileId: string, revisionId: string): Promise<ProfileRevision | null>\n /** Append the immutable row and optionally an activation event in one guarded transaction. */\n appendRevision(revision: ProfileRevision, expectedActiveId: string | null, activate: boolean): Promise<boolean>\n /** Promotion appends an activation event; the historical revision remains immutable. */\n promoteRevision(workspaceId: string, profileId: string, revisionId: string, expectedActiveId: string | null): Promise<boolean>\n getBinding(key: ProfileBindingKey): Promise<ProfileBinding | null>\n getSwitchReceipt(key: ProfileBindingKey, messageId: string, inputHash: string): Promise<ProfileSwitchReceipt | null>\n /** Receipt and binding event append atomically; a refusal leaves the binding untouched. */\n recordSwitch(receipt: ProfileSwitchReceipt, expectedVersion: number): Promise<ProfileSwitchReceipt>\n /** Persist one immutable pin under a message id; retries must return the same pin. */\n pinTurn(pin: ProfileTurnPin, expectedBindingVersion: number): Promise<ProfileTurnPin>\n getTurnPin(key: ProfileBindingKey, messageId: string, inputHash: string): Promise<ProfileTurnPin | null>\n listKnowledgeEvents(workspaceId: string, profileId: string): Promise<ProfileKnowledgeEvent[]>\n appendKnowledgeEvent(event: ProfileKnowledgeEvent): Promise<void>\n}\n\nexport class ProfileConflictError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ProfileConflictError'\n }\n}\n\nexport class ProfileAccessError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ProfileAccessError'\n }\n}\n\n/** Keep the existing diff column readable while adding the separate knowledge text axis. */\nexport function parseProfileRevisionDiff(value: string): {\n diff: AgentProfileDiff[]; knowledgeTextChanged: boolean | null\n} {\n const parsed: unknown = JSON.parse(value)\n if (Array.isArray(parsed)) return { diff: parsed as AgentProfileDiff[], knowledgeTextChanged: null }\n if (!parsed || typeof parsed !== 'object' || !('profile' in parsed) ||\n !Array.isArray(parsed.profile) || !('knowledgeTextChanged' in parsed) ||\n (parsed.knowledgeTextChanged !== null && typeof parsed.knowledgeTextChanged !== 'boolean')) {\n throw new TypeError('Stored profile revision diff is invalid')\n }\n return { diff: parsed.profile as AgentProfileDiff[],\n knowledgeTextChanged: parsed.knowledgeTextChanged }\n}\n\nexport function serializeProfileRevisionDiff(revision: Pick<ProfileRevision, 'diff' | 'knowledgeTextChanged'>): string {\n return JSON.stringify({ profile: revision.diff, knowledgeTextChanged: revision.knowledgeTextChanged ?? null })\n}\n\n/** Remove exactly the declared text axes. Unknown future fields remain authority. */\nexport function profileAuthority(profile: AgentProfile): AgentProfile {\n const { name: _name, description: _description, prompt, ...authority } = profile\n const { systemPrompt: _systemPrompt, instructions: _instructions, ...promptAuthority } = prompt ?? {}\n return { ...authority, ...(Object.keys(promptAuthority).length ? { prompt: promptAuthority } : {}) }\n}\n\nexport function profileAuthorityDigest(profile: AgentProfile): string {\n return canonicalAgentProfileDigest(profileAuthority(snapshotAgentProfile(profile)))\n}\n\nexport function projectKnowledgeDocuments(events: readonly ProfileKnowledgeEvent[]): ProfileKnowledgeDocument[] {\n const removed = new Set(events.filter(event => event.kind === 'remove').flatMap(event => event.observedAddIds))\n const visible = events.filter(event => event.kind === 'add' && !removed.has(event.id))\n const latest = new Map<string, ProfileKnowledgeEvent>()\n for (const event of visible) {\n const prior = latest.get(event.documentId)\n if (!prior || event.createdAt > prior.createdAt ||\n (event.createdAt === prior.createdAt && event.id > prior.id)) latest.set(event.documentId, event)\n }\n return [...latest.values()].sort((a, b) => a.documentId.localeCompare(b.documentId))\n .map(event => ({ documentId: event.documentId, content: event.content!, addEventId: event.id }))\n}\n\nexport async function addProfileKnowledgeDocument(input: {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n documentId: string\n content: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n id?: string\n now?: number\n}): Promise<ProfileKnowledgeEvent> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Profile management is required')\n }\n if (!input.documentId || !input.content) throw new TypeError('A knowledge document needs an id and content')\n const event: ProfileKnowledgeEvent = { id: input.id ?? crypto.randomUUID(),\n workspaceId: input.workspaceId, profileId: input.profileId, documentId: input.documentId,\n kind: 'add', content: input.content, observedAddIds: [], createdAt: input.now ?? Date.now() }\n await input.store.appendKnowledgeEvent(event)\n return event\n}\n\nexport async function removeProfileKnowledgeDocument(input: {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n documentId: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n id?: string\n now?: number\n}): Promise<ProfileKnowledgeEvent> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Profile management is required')\n }\n const events = await input.store.listKnowledgeEvents(input.workspaceId, input.profileId)\n const removed = new Set(events.filter(event => event.kind === 'remove').flatMap(event => event.observedAddIds))\n const observedAddIds = events.filter(event => event.kind === 'add' &&\n event.documentId === input.documentId && !removed.has(event.id)).map(event => event.id)\n const event: ProfileKnowledgeEvent = { id: input.id ?? crypto.randomUUID(),\n workspaceId: input.workspaceId, profileId: input.profileId, documentId: input.documentId,\n kind: 'remove', content: null, observedAddIds, createdAt: input.now ?? Date.now() }\n await input.store.appendKnowledgeEvent(event)\n return event\n}\n\n/** The per-turn text overlay is validated without admitting tools, model, MCP or resources. */\nexport function bindProfileText(consentedBaseline: AgentProfile, selected: AgentProfile): AgentProfile {\n if (profileAuthorityDigest(consentedBaseline) !== profileAuthorityDigest(selected)) {\n throw new ProfileAccessError('Profile authority differs; prepare its managed plan before the next turn')\n }\n // Profiles are digested as RFC 8785 JSON, which has no `undefined`: an\n // absent selected field removes the baseline's value instead of storing it.\n const result: AgentProfile = { ...consentedBaseline, name: selected.name }\n if (selected.description === undefined) delete result.description\n else result.description = selected.description\n const prompt: NonNullable<AgentProfile['prompt']> = { ...consentedBaseline.prompt }\n const { systemPrompt, instructions } = selected.prompt ?? {}\n if (systemPrompt === undefined) delete prompt.systemPrompt\n else prompt.systemPrompt = systemPrompt\n if (instructions === undefined) delete prompt.instructions\n else prompt.instructions = instructions\n if (Object.values(prompt).some(value => value !== undefined)) result.prompt = prompt\n else delete result.prompt\n return snapshotAgentProfile(result)\n}\n\nexport interface ProposeRevisionInput {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n expectedRevisionId: string | null\n profile: AgentProfile\n knowledgeText: string\n /** The exact ADC `hashWorkspacePlan` for this authored snapshot. */\n planDigest: string\n author: ProfileRevision['author']\n /** Trusted role from the authenticated session, never model arguments. */\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n reason: string\n id?: string\n now?: number\n}\n\n/** All authors use one immutable write path. Optimizer and authority edits cannot self-activate. */\nexport async function proposeRevision(input: ProposeRevisionInput): Promise<ProfileRevision> {\n if (input.author.kind !== 'optimizer' && input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can change a profile')\n }\n if (!input.workspaceId || !input.profileId || !input.author.id || !input.reason.trim() ||\n !/^sha256:[a-f0-9]{64}$/.test(input.planDigest)) {\n throw new TypeError('A profile revision needs workspace, profile, author, reason and plan digest')\n }\n const previous = await input.store.getActiveRevision(input.workspaceId, input.profileId)\n if ((previous?.id ?? null) !== input.expectedRevisionId) {\n throw new ProfileConflictError('The profile changed; read its latest revision before saving')\n }\n const profile = snapshotAgentProfile(input.profile)\n const diff = previous ? diffAgentProfiles(previous.profile, profile) : []\n const authorityDigest = profileAuthorityDigest(profile)\n const authorityChanged = !!previous && previous.authorityDigest !== authorityDigest\n const admission = input.author.kind === 'optimizer'\n ? PROFILE_CHANGE_POLICY.optimizerRevision.admission\n : authorityChanged\n ? PROFILE_CHANGE_POLICY.authorityEdit.admission\n : PROFILE_CHANGE_POLICY.textEdit.admission\n const state: ProfileRevisionState = admission === 'eval-promotion' ? 'candidate'\n : admission === 'editor-consent' ? 'pending-consent' : 'active'\n const revision: ProfileRevision = {\n id: input.id ?? crypto.randomUUID(), workspaceId: input.workspaceId, profileId: input.profileId,\n parentId: previous?.id ?? null, profile, knowledgeText: input.knowledgeText,\n author: input.author, reason: input.reason.trim(), diff,\n knowledgeTextChanged: previous ? previous.knowledgeText !== input.knowledgeText : input.knowledgeText.length > 0,\n authorityDigest,\n planDigest: input.planDigest, state, createdAt: input.now ?? Date.now(),\n }\n if (!await input.store.appendRevision(revision, input.expectedRevisionId, state === 'active')) {\n throw new ProfileConflictError('The profile changed while saving')\n }\n return revision\n}\n\nexport interface CreateTextProfileInput {\n store: ProfileRevisionStore\n workspaceId: string\n /** An active profile whose authority the new profile inherits exactly. */\n baselineProfileId: string\n /** Include builtins and user profiles from the authenticated workspace catalog. */\n existingProfiles: readonly { name: string }[]\n name: string\n instructions: string\n authorId: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n /** Product computes ADC's hashWorkspacePlan for the complete authored snapshot. */\n planDigest: (profile: AgentProfile) => string | Promise<string>\n now?: number\n}\n\n/** Create a distinct text persona without granting new model, tool, MCP or secret authority. */\nexport async function createTextProfile(input: CreateTextProfileInput): Promise<ProfileRevision> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can create a profile')\n }\n const name = input.name.trim().replace(/\\s+/g, ' ')\n const normalizedName = normalizeProfileName(name)\n if (!normalizedName) throw new TypeError('A profile needs a name')\n if (input.existingProfiles.some(profile => normalizeProfileName(profile.name) === normalizedName)) {\n throw new ProfileConflictError('A profile with that name already exists')\n }\n const baseline = await input.store.getActiveRevision(input.workspaceId, input.baselineProfileId)\n if (!baseline) throw new ProfileConflictError('The baseline profile is not active')\n // Equal names map to one id, so two concurrent creates cannot create an\n // ambiguous text command even when both read the catalog before either writes.\n const profileId = `custom-${sha256Utf8(`${input.workspaceId}\\0${normalizedName}`).slice(7, 39)}`\n const addedInstruction = input.instructions.trim()\n const profile = bindProfileText(baseline.profile, {\n ...baseline.profile, name,\n prompt: {\n ...baseline.profile.prompt,\n instructions: [...(baseline.profile.prompt?.instructions ?? []),\n ...(addedInstruction ? [addedInstruction] : [])],\n },\n })\n return proposeRevision({\n store: input.store, workspaceId: input.workspaceId, profileId,\n expectedRevisionId: null, profile, knowledgeText: '',\n planDigest: await input.planDigest(profile),\n author: { kind: 'person', id: input.authorId }, actorRole: input.actorRole,\n reason: 'Created a text profile from an approved baseline', now: input.now,\n })\n}\n\nexport async function promoteRevision(input: {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n revisionId: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n /** Verified by the product's consent route; required when authority changes. */\n verifyConsent?: (revision: ProfileRevision) => Promise<boolean>\n}): Promise<ProfileRevision> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can promote a profile')\n }\n const [revision, head] = await Promise.all([\n input.store.getRevision(input.workspaceId, input.profileId, input.revisionId),\n input.store.getActiveRevision(input.workspaceId, input.profileId),\n ])\n if (!revision || revision.parentId !== (head?.id ?? null)) throw new ProfileConflictError('Profile parent changed')\n if (revision.authorityDigest !== head?.authorityDigest &&\n (input.actorRole !== 'owner' || !input.verifyConsent || !await input.verifyConsent(revision))) {\n throw new ProfileAccessError('Authority changes require owner consent')\n }\n if (!await input.store.promoteRevision(input.workspaceId, input.profileId, revision.id, head?.id ?? null)) {\n throw new ProfileConflictError('The profile changed while promoting')\n }\n return revision\n}\n\n/** A source identity joins the command hash without entering the receipt row. */\nexport function profileSwitchInputHashFromContentHash(contentHash: string,\n identityContext?: string): string {\n return identityContext === undefined ? contentHash\n : sha256Utf8(JSON.stringify([identityContext, contentHash]))\n}\n\nexport function profileSwitchInputHash(content: string, identityContext?: string): string {\n return profileSwitchInputHashFromContentHash(sha256Utf8(content), identityContext)\n}\n\nexport interface SwitchableProfile {\n id: string\n name: string\n status: 'active' | 'draft' | 'paused'\n}\n\nexport interface SwitchProfileInput {\n store: ProfileRevisionStore\n key: ProfileBindingKey\n messageId: string\n content: string\n /** Trusted source identity, such as a phone sender; replay must preserve it. */\n identityContext?: string\n conversationId?: string\n choice: { name: string } | { profileId: string }\n profiles: readonly SwitchableProfile[]\n /** Product's role/phone allowlist decision for the authenticated member. */\n canSelect: (profileId: string) => Promise<boolean>\n /** Stage a complete managed plan for the same conversation; never mutate live workspace files. */\n prepareAuthority: (revision: ProfileRevision, key: ProfileBindingKey) => Promise<{\n planDigest: string; healthy: true; conflicts: string[]\n }>\n /** Receives the reason preparation failed; the person sees only a generic refusal.\n * Defaults to one structured `console.error` line so the reason reaches the host's logs. */\n onPrepareFailure?: (error: unknown, profileId: string) => void\n}\n\n/** The picker and deterministic text command converge here. Models cannot call it. */\nfunction logPrepareFailure(error: unknown, profileId: string): void {\n console.error(JSON.stringify({ event: 'profile-switch-prepare-failed', profileId,\n error: error instanceof Error ? `${error.name}: ${error.message}` : String(error) }))\n}\n\nexport async function switchProfile(input: SwitchProfileInput): Promise<ProfileSwitchReceipt> {\n const inputHash = profileSwitchInputHash(input.content, input.identityContext)\n const previousReceipt = await input.store.getSwitchReceipt(input.key, input.messageId, inputHash)\n if (previousReceipt) return previousReceipt\n const binding = await input.store.getBinding(input.key)\n const choice = input.choice\n const matches = 'name' in choice\n ? input.profiles.filter(profile => normalizeProfileName(profile.name) === normalizeProfileName(choice.name))\n : input.profiles.filter(profile => profile.id === choice.profileId)\n const target = matches.length === 1 ? matches[0] : undefined\n let revision: ProfileRevision | null = null\n if (target?.status === 'active' && await input.canSelect(target.id)) {\n revision = await input.store.getActiveRevision(input.key.workspaceId, target.id)\n if (revision && 'name' in choice &&\n normalizeProfileName(revision.profile.name ?? '') !== normalizeProfileName(choice.name)) {\n revision = null\n }\n }\n let outcome: ProfileSwitchReceipt['outcome'] = 'refused'\n let message = matches.length > 1 ? 'That profile name is ambiguous.'\n : target?.status !== 'active' && target ? `${target.name} is not active.`\n : 'That profile is not available for this member.'\n let planDigest: string | null = null\n let conflicts: string[] = []\n if (revision && target) {\n try {\n const prepared = await input.prepareAuthority(revision, input.key)\n if (!prepared.healthy || prepared.planDigest !== revision.planDigest) {\n throw new ProfileConflictError('The managed plan was not prepared for this revision')\n }\n planDigest = prepared.planDigest\n conflicts = prepared.conflicts\n } catch (error) {\n revision = null\n message = `Could not prepare ${target.name}; your current agent is unchanged.`\n ;(input.onPrepareFailure ?? logPrepareFailure)(error, target.id)\n }\n if (revision && planDigest) {\n outcome = 'switched'\n message = `Now talking to ${target.name}`\n }\n }\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: revision?.profileId ?? null, revisionId: revision?.id ?? null,\n pinnedRevisionId: null, authorityDigest: revision?.authorityDigest ?? null,\n planDigest, outcome, message, conflicts }, binding?.version ?? 0)\n}\n\n/** Call before dispatching a chat message; a recognized command is never sent to the model. */\nexport async function handleProfileSwitchText(\n input: Omit<SwitchProfileInput, 'choice'>,\n): Promise<ProfileSwitchReceipt | null> {\n const parsed = parseProfileSwitch(input.content)\n if (!parsed) return null\n if ('name' in parsed) return switchProfile({ ...input, choice: parsed })\n const inputHash = profileSwitchInputHash(input.content, input.identityContext)\n const previous = await input.store.getSwitchReceipt(input.key, input.messageId, inputHash)\n if (previous) return previous\n const binding = await input.store.getBinding(input.key)\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: null, revisionId: null, pinnedRevisionId: null, outcome: 'refused',\n authorityDigest: null, planDigest: null, conflicts: [],\n message: 'Send only “Switch to [agent name]” to change agents.' },\n binding?.version ?? 0)\n}\n\n/** One-step rollback moves this member/channel to its previous immutable revision. */\nexport async function rollbackProfileBinding(input: {\n store: ProfileRevisionStore\n key: ProfileBindingKey\n messageId: string\n conversationId?: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n canSelect: (profileId: string) => Promise<boolean>\n prepareAuthority: SwitchProfileInput['prepareAuthority']\n}): Promise<ProfileSwitchReceipt> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can roll back a profile')\n }\n const inputHash = sha256Utf8(`rollback:${input.messageId}`)\n const prior = await input.store.getSwitchReceipt(input.key, input.messageId, inputHash)\n if (prior) return prior\n const binding = await input.store.getBinding(input.key)\n if (!binding || !await input.canSelect(binding.profileId)) throw new ProfileAccessError('Profile is unavailable')\n const current = binding.pinnedRevisionId\n ? await input.store.getRevision(input.key.workspaceId, binding.profileId, binding.pinnedRevisionId)\n : await input.store.getActiveRevision(input.key.workspaceId, binding.profileId)\n if (!current?.parentId) throw new ProfileConflictError('The bound profile has no previous revision')\n const parent = await input.store.getRevision(input.key.workspaceId, binding.profileId, current.parentId)\n if (!parent) throw new ProfileConflictError('The previous revision is unavailable')\n let planDigest = binding.planDigest\n let conflicts: string[] = []\n if (binding.authorityDigest !== parent.authorityDigest || binding.planDigest !== parent.planDigest) {\n try {\n const prepared = await input.prepareAuthority(parent, input.key)\n if (!prepared.healthy || prepared.planDigest !== parent.planDigest) {\n throw new ProfileConflictError('The prior managed plan was not prepared')\n }\n planDigest = prepared.planDigest\n conflicts = prepared.conflicts\n } catch {\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: null, revisionId: null, pinnedRevisionId: null, outcome: 'refused',\n authorityDigest: null, planDigest: null, conflicts: [],\n message: 'Could not prepare the previous profile; your current agent is unchanged.' },\n binding.version)\n }\n }\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: parent.profileId, revisionId: parent.id, pinnedRevisionId: parent.id,\n authorityDigest: parent.authorityDigest, planDigest, outcome: 'switched', conflicts,\n message: `Now talking to ${parent.profile.name ?? 'this profile'}` }, binding.version)\n}\n\n/**\n * An opaque token for what `readProfileAdmission` read for one message. It carries no data: the values\n * live in this module, cloned when read, so a caller can neither build a token nor change what it stands\n * for. `admitProfileTurn` accepts each token once. The active-revision pointer is never part of it;\n * admission reads that live.\n */\nexport interface ProfileAdmissionRead { readonly [admissionReadBrand]: true }\ndeclare const admissionReadBrand: unique symbol\n\n/** The values a token stands for, as the caller may inspect them. */\nexport interface ProfileAdmissionValues {\n key: ProfileBindingKey\n messageId: string\n inputHash: string\n /** The message's existing pin, when it was already admitted. */\n prior: ProfileTurnPin | null\n binding: ProfileBinding | null\n /** The pinned revision by id (immutable), when the binding pins one. */\n pinnedRevision: ProfileRevision | null\n}\nconst admissionReads = new WeakMap<ProfileAdmissionRead, ProfileAdmissionValues>()\n/** Tokens already presented, so a second use is told apart from one this module never issued. */\nconst spentAdmissionReads = new WeakSet<ProfileAdmissionRead>()\n\n/**\n * Read what admitting a message needs: its prior pin and the binding together, then a pinned revision.\n * Read it where the caller holds its conversation lock (after any switch it records), check the values\n * with `profileAdmissionValues`, and pass the token to `admitProfileTurn`, which then skips re-reading\n * the pin and binding. The pin is still written as a compare-and-set on the binding version, so a\n * binding that moved after this read is refused.\n */\nexport async function readProfileAdmission(store: ProfileRevisionStore, key: ProfileBindingKey,\n messageId: string, content: string): Promise<ProfileAdmissionRead> {\n const inputHash = sha256Utf8(content)\n const [prior, binding] = await Promise.all([store.getTurnPin(key, messageId, inputHash), store.getBinding(key)])\n const pinnedRevision = !prior && binding?.pinnedRevisionId\n ? await store.getRevision(key.workspaceId, binding.profileId, binding.pinnedRevisionId) : null\n const read = Object.freeze(Object.create(null)) as ProfileAdmissionRead\n admissionReads.set(read, structuredClone({ key: { workspaceId: key.workspaceId, memberId: key.memberId, channel: key.channel },\n messageId, inputHash, prior, binding, pinnedRevision }))\n return read\n}\n\n/** A deep copy of what a token stands for; changing the copy changes nothing the token admits. */\nexport function profileAdmissionValues(read: ProfileAdmissionRead): ProfileAdmissionValues {\n const values = admissionReads.get(read)\n if (!values) throw new ProfileAccessError('Unknown or used profile admission read')\n return structuredClone(values)\n}\n\nexport async function admitProfileTurn(input: {\n store: ProfileRevisionStore\n key: ProfileBindingKey\n messageId: string\n content: string\n /** Effective ADC plan digest selected by the executor for this revision and turn. */\n observedManagedPlanDigest: string\n /** Required if trusted per-turn attachments change the public profile plan. */\n verifyEffectivePlan?: (revision: ProfileRevision, effectivePlanDigest: string,\n key: ProfileBindingKey) => Promise<boolean>\n /** A token from `readProfileAdmission` for this message; its pin and binding are not read again.\n * Each token admits once: after a failed admit, read again before retrying. */\n read?: ProfileAdmissionRead\n}): Promise<ProfileTurnPin> {\n const inputHash = sha256Utf8(input.content)\n // A token is spent when presented, so it admits at most one turn even if this call fails;\n // a retry reads again with `readProfileAdmission`.\n const read = input.read ? admissionReads.get(input.read) : undefined\n if (input.read && !read && spentAdmissionReads.has(input.read)) {\n throw new ProfileConflictError('The admission read was already used; read again')\n }\n if (input.read) { admissionReads.delete(input.read); spentAdmissionReads.add(input.read) }\n if (input.read && (!read || read.messageId !== input.messageId || read.inputHash !== inputHash ||\n read.key.workspaceId !== input.key.workspaceId || read.key.memberId !== input.key.memberId ||\n read.key.channel !== input.key.channel)) {\n throw new ProfileAccessError('The admission read does not belong to this message')\n }\n const prior = read ? read.prior : await input.store.getTurnPin(input.key, input.messageId, inputHash)\n if (prior) return prior\n const binding = read ? read.binding : await input.store.getBinding(input.key)\n if (!binding) throw new ProfileAccessError('Choose a profile before sending a message')\n // The active pointer can move without the binding version changing, so it is always read live.\n const revision = binding.pinnedRevisionId\n ? read?.pinnedRevision ?? await input.store.getRevision(input.key.workspaceId, binding.profileId, binding.pinnedRevisionId)\n : await input.store.getActiveRevision(input.key.workspaceId, binding.profileId)\n if (!revision) throw new ProfileConflictError('The bound profile revision is unavailable')\n if (revision.authorityDigest !== binding.authorityDigest ||\n !/^sha256:[a-f0-9]{64}$/.test(input.observedManagedPlanDigest)) {\n throw new ProfileAccessError('The selected managed plan is not active for this turn')\n }\n const planMatches = revision.planDigest === input.observedManagedPlanDigest ||\n (input.verifyEffectivePlan !== undefined &&\n await input.verifyEffectivePlan(revision, input.observedManagedPlanDigest, input.key))\n if (!planMatches) {\n throw new ProfileAccessError('The selected managed plan is not active for this turn')\n }\n return input.store.pinTurn({ ...input.key, messageId: input.messageId, inputHash,\n profileId: revision.profileId, revisionId: revision.id,\n authorityDigest: revision.authorityDigest, planDigest: input.observedManagedPlanDigest }, binding.version)\n}\n\nconst KNOWLEDGE_TEXT_MAX = 32000\nconst textChangeSchema = z.object({\n name: z.string().trim().min(1).max(160).optional(),\n description: z.string().max(2000).nullable().optional(),\n systemPrompt: z.string().max(32000).nullable().optional(),\n instructions: z.array(z.string().max(32000)).max(40).optional(),\n knowledgeText: z.string().max(KNOWLEDGE_TEXT_MAX).optional(),\n}).strict().refine(changes => Object.keys(changes).length > 0)\nconst updateToolSchema = z.object({ expectedRevisionId: z.string().min(1), changes: textChangeSchema }).strict()\nconst rememberToolSchema = z.object({ fact: z.string().trim().min(1).max(1000) }).strict()\n\nexport function profileTextChange(revision: ProfileRevision, changes: z.infer<typeof textChangeSchema>): {\n profile: AgentProfile; knowledgeText: string\n} {\n const profile = structuredClone(revision.profile)\n if (changes.name !== undefined) profile.name = changes.name\n if (changes.description !== undefined) profile.description = changes.description ?? undefined\n if (changes.systemPrompt !== undefined || changes.instructions !== undefined) {\n profile.prompt = { ...profile.prompt,\n ...(changes.systemPrompt !== undefined ? { systemPrompt: changes.systemPrompt ?? undefined } : {}),\n ...(changes.instructions !== undefined ? { instructions: changes.instructions } : {}) }\n }\n return { profile: snapshotAgentProfile(profile), knowledgeText: changes.knowledgeText ?? revision.knowledgeText }\n}\n\nexport interface ProfileToolTurn {\n workspaceId: string; profileId: string; revisionId: string\n memberId: string; role: 'owner' | 'manager' | 'member' | 'viewer'\n}\n\nexport interface ProfileToolContext<TTurn extends ProfileToolTurn = ProfileToolTurn> {\n /** Resolve the running turn from the trusted server session; never from tool arguments. */\n activeTurn(): Promise<TTurn>\n /** Product computes the plan with ADC, returning `hashWorkspacePlan(plan)`. */\n planDigest(profile: AgentProfile, knowledgeText: string): Promise<string>\n store: ProfileRevisionStore\n /** Return a store whose revision append atomically rechecks product turn authority. */\n storeForTurn?(turn: TTurn): ProfileRevisionStore\n /**\n * When set, `profile.remember` writes to this workspace memory store instead\n * of appending a profile revision, so remembered facts never change the\n * hashed profile (or anything that pins its version, such as a phone line).\n * Structurally matches agent-runtime's `WorkspaceStore`.\n */\n memory?: ProfileMemoryStore\n}\n\n/** The subset of agent-runtime's `WorkspaceStore` that `profile.remember` uses. */\nexport interface ProfileMemoryStore {\n list(workspaceId: string, prefix: string): Promise<Array<{ id: string; content?: string }>>\n put(input: { workspaceId: string; path: string; kind: 'fact'; ifRevision: null; actor: string;\n content: string; id?: string }): Promise<{ id: string; revision: number }>\n}\n\n/** Workspace-shared memories live under this prefix in the workspace store. */\nexport const PROFILE_MEMORY_PREFIX = '/memories/workspace/'\n\n/** Shared self-edit tools; only the authenticated active turn can name the profile. */\nexport function profileTools<TTurn extends ProfileToolTurn>(\n context: ProfileToolContext<TTurn>): McpToolDefinition<Record<string, never>>[] {\n return [{\n name: 'profile.read',\n description: 'Read the active agent profile text and revision. Saved text applies on the next message.',\n inputSchema: z.toJSONSchema(z.object({}).strict(), { io: 'input' }) as Record<string, unknown>,\n async run(args) {\n z.object({}).strict().parse(args)\n const turn = await context.activeTurn()\n if (turn.role !== 'owner' && turn.role !== 'manager') throw new ProfileAccessError('Profile management is required')\n const revision = await context.store.getActiveRevision(turn.workspaceId, turn.profileId)\n if (!revision) throw new ProfileConflictError('Profile revision is unavailable')\n return { profileId: turn.profileId, revisionId: revision.id, currentTurnRevisionId: turn.revisionId,\n name: revision.profile.name, description: revision.profile.description ?? null,\n systemPrompt: revision.profile.prompt?.systemPrompt ?? null,\n instructions: revision.profile.prompt?.instructions ?? [], knowledgeText: revision.knowledgeText }\n },\n }, {\n name: 'profile.update',\n description: 'Save a requested owner or manager text change with the revision from profile.read. Applies on the next message.',\n inputSchema: z.toJSONSchema(updateToolSchema, { io: 'input' }) as Record<string, unknown>,\n async run(args) {\n const { expectedRevisionId, changes } = updateToolSchema.parse(args)\n const turn = await context.activeTurn()\n if (turn.role !== 'owner' && turn.role !== 'manager') throw new ProfileAccessError('Profile management is required')\n const current = await context.store.getActiveRevision(turn.workspaceId, turn.profileId)\n if (!current || current.id !== expectedRevisionId) throw new ProfileConflictError('The profile changed; read it again')\n const next = profileTextChange(current, changes)\n const revision = await proposeRevision({ store: context.storeForTurn?.(turn) ?? context.store,\n workspaceId: turn.workspaceId,\n profileId: turn.profileId, expectedRevisionId, ...next,\n planDigest: await context.planDigest(next.profile, next.knowledgeText),\n author: { kind: 'agent', id: turn.memberId }, actorRole: turn.role,\n reason: 'Owner or manager requested a text change during chat' })\n return { profileId: turn.profileId, revisionId: revision.id, state: revision.state,\n canonicalSaved: revision.state === 'active', appliesTo: 'next_message', currentTurn: 'unchanged' }\n },\n }, {\n name: 'profile.remember',\n description: 'Save one durable fact or standing instruction an owner or manager tells you to keep '\n + '(\"remember\", \"note that\", \"from now on\", \"always\", \"never\"). Appends it as one line of the agent\\'s '\n + 'knowledge, which every later conversation reads. Applies on the next message.',\n inputSchema: z.toJSONSchema(rememberToolSchema, { io: 'input' }) as Record<string, unknown>,\n async run(args) {\n const { fact } = rememberToolSchema.parse(args)\n const turn = await context.activeTurn()\n if (turn.role !== 'owner' && turn.role !== 'manager') throw new ProfileAccessError('Profile management is required')\n if (context.memory) {\n const text = fact.replace(/\\s+/g, ' ')\n const known = (await context.memory.list(turn.workspaceId, PROFILE_MEMORY_PREFIX))\n .find(entry => entry.content?.trim() === text)\n if (known) return { memoryId: known.id, saved: true, alreadyKnown: true, line: `- ${text}`, appliesTo: 'next_message' }\n const id = crypto.randomUUID()\n const saved = await context.memory.put({ workspaceId: turn.workspaceId, path: `${PROFILE_MEMORY_PREFIX}${id}`,\n kind: 'fact', ifRevision: null, actor: turn.memberId, content: text, id })\n return { memoryId: saved.id, saved: true, alreadyKnown: false, line: `- ${text}`, appliesTo: 'next_message' }\n }\n const line = `- ${fact.replace(/\\s+/g, ' ')}`\n // One retry covers a concurrent save between the read and the append; the\n // revision chain keeps every earlier line.\n for (let attempt = 0; ; attempt++) {\n const current = await context.store.getActiveRevision(turn.workspaceId, turn.profileId)\n if (!current) throw new ProfileConflictError('Profile revision is unavailable')\n if (current.knowledgeText.split('\\n').some(existing => existing.trim() === line)) {\n return { profileId: turn.profileId, revisionId: current.id, saved: true, alreadyKnown: true,\n line, appliesTo: 'next_message' }\n }\n const knowledgeText = current.knowledgeText.trim() ? `${current.knowledgeText.trimEnd()}\\n${line}` : line\n if (knowledgeText.length > KNOWLEDGE_TEXT_MAX) {\n throw new ProfileConflictError('Knowledge is full; ask the owner to edit it before saving more')\n }\n try {\n const revision = await proposeRevision({ store: context.storeForTurn?.(turn) ?? context.store,\n workspaceId: turn.workspaceId, profileId: turn.profileId, expectedRevisionId: current.id,\n profile: current.profile, knowledgeText,\n planDigest: await context.planDigest(current.profile, knowledgeText),\n author: { kind: 'agent', id: turn.memberId }, actorRole: turn.role,\n reason: 'Owner or manager asked the agent to remember a fact during chat' })\n return { profileId: turn.profileId, revisionId: revision.id, saved: revision.state === 'active',\n state: revision.state, alreadyKnown: false, line, appliesTo: 'next_message' }\n } catch (error) {\n if (!(error instanceof ProfileConflictError) || attempt > 0) throw error\n }\n }\n },\n }]\n}\n\nexport * from './self-management'\n","/**\n * Live profile self-mounting — the safe, immediate subset of agent\n * self-improvement.\n *\n * The revision system ({@link ProfileRevision}, `PROFILE_CHANGE_POLICY`) owns\n * durable profile evolution: authority edits need editor consent, optimizer\n * revisions promote through eval. Self-mounting is the complementary\n * LIVE dimension — the sandboxed agent adjusts its own mounted context\n * (skills today) within a permitted, idempotent, catalog-validated delta.\n * Nothing here touches authority: model, permissions, tools denials and\n * billing identity are not agent-changeable dimensions, and every refusal\n * names the permitted set.\n *\n * One audited verb, not a family: `mount_profile_change` applies a validated\n * delta against a permitted-dimensions allowlist; re-applying the same delta\n * is a no-op; the baseline skill cannot be removed; the mount count is capped\n * because context is a budget.\n *\n * Products wire their own catalog and persistence:\n *\n * ```ts\n * import { createMountProfileChangeTool, createInMemorySelfMountStorage } from '@tangle-network/agent-app/agent-profiles'\n *\n * const mountProfileChange = createMountProfileChangeTool({\n * skills: mySkillRegistry, // { id, description }[]\n * storage: createD1SelfMountStorage(env.DB), // or any { get, set }\n * scopeKey: (ctx) => ctx.threadId ?? ctx.userId, // product's persistence scope\n * baseline: 'cad',\n * })\n * ```\n */\nimport { defineAppTool, type AppToolDefinition } from '../tools/registry'\nimport { ToolInputError } from '../tools/errors'\nimport type { AppToolContext } from '../tools/types'\n\n/** The only profile dimensions an agent may change on its own mounted state.\n * Anything else in a delta is refused with this list — the boundary is the\n * schema, not the verb count. */\nexport const PERMITTED_SELF_MOUNT_DIMENSIONS = ['skills'] as const\n\nexport interface SelfMountSkillEntry {\n /** Registry-unique skill id. */\n id: string\n /** One-line description, surfaced in the tool's catalog. */\n description: string\n}\n\n/** Durable mounted-skill state, keyed by the product's scope. */\nexport interface SelfMountStorage {\n get(scope: string): Promise<readonly string[]>\n set(scope: string, ids: readonly string[]): Promise<void>\n}\n\n/** Non-durable default for tests and single-instance products. */\nexport function createInMemorySelfMountStorage(): SelfMountStorage {\n const state = new Map<string, string[]>()\n return {\n async get(scope) {\n return state.get(scope) ?? []\n },\n async set(scope, ids) {\n state.set(scope, [...new Set(ids)].sort())\n },\n }\n}\n\nexport interface MountProfileChangeDeps {\n /** The product's skill catalog — the only mountable ids. */\n skills: readonly SelfMountSkillEntry[]\n /** Where mounted ids persist, keyed by the product's scope. */\n storage: SelfMountStorage\n /** The persistence scope for a call (project id, thread id, …). */\n scopeKey: (ctx: AppToolContext) => string\n /** Always-mounted skill id that cannot be removed. Default: none. */\n baseline?: string\n /** Upper bound on total mounted skills. Default 12; context is a budget. */\n maxMounted?: number\n /** Tool name override when a product needs a distinct verb. */\n name?: string\n}\n\ninterface SkillsDelta {\n add?: string[]\n remove?: string[]\n}\n\nexport interface MountProfileChangeResult {\n ok: true\n mounted: string[]\n removed: string[]\n effective: string[]\n note: string\n}\n\nfunction catalogLine(skills: readonly SelfMountSkillEntry[]): string {\n return skills.map((s) => `${s.id} (${s.description})`).join('; ')\n}\n\n/**\n * The permitted, idempotent self-mount verb as an app tool. Register it with\n * the product's tool set; the sandboxed agent calls it through the per-turn\n * MCP surface like any other app tool.\n */\nexport function createMountProfileChangeTool(deps: MountProfileChangeDeps): AppToolDefinition<Record<string, unknown>> {\n const { skills, storage, scopeKey } = deps\n const baseline = deps.baseline?.trim() || undefined\n const maxMounted = deps.maxMounted ?? 12\n const known = new Set(skills.map((s) => s.id))\n if (known.size !== skills.length) throw new Error('createMountProfileChangeTool: duplicate skill ids in the catalog')\n if (baseline && !known.has(baseline)) throw new Error(`createMountProfileChangeTool: baseline \"${baseline}\" is not in the catalog`)\n\n return defineAppTool({\n name: deps.name ?? 'mount_profile_change',\n description:\n `Apply a permitted, idempotent change to the mounted skills on this profile. ` +\n `Permitted dimension: skills ({ add: [ids], remove: [ids] }) — anything else is refused. ` +\n `Re-applying the same change is a no-op. Takes effect the next time the profile renders. ` +\n `Catalog: ${catalogLine(skills)}.`,\n parameters: {\n type: 'object',\n properties: {\n changes: {\n type: 'object',\n description: `The profile delta. Permitted dimensions: ${PERMITTED_SELF_MOUNT_DIMENSIONS.join(', ')}.`,\n properties: {\n skills: {\n type: 'object',\n description: 'Skill mounts: catalog ids to add or remove.',\n properties: {\n add: { type: 'array', items: { type: 'string' }, description: 'Catalog skill ids to mount.' },\n remove: { type: 'array', items: { type: 'string' }, description: 'Mounted skill ids to unmount.' },\n },\n additionalProperties: false,\n },\n },\n additionalProperties: false,\n },\n },\n required: ['changes'],\n additionalProperties: false,\n },\n async execute(args: unknown, ctx: AppToolContext): Promise<MountProfileChangeResult | { ok: false; error: string }> {\n const changes = (args as { changes?: Record<string, unknown> }).changes ?? {}\n const unknownDimensions = Object.keys(changes).filter(\n (d) => !(PERMITTED_SELF_MOUNT_DIMENSIONS as readonly string[]).includes(d),\n )\n if (unknownDimensions.length > 0) {\n throw new ToolInputError(\n 'mount_profile_change',\n `dimensions [${unknownDimensions.join(', ')}] are not agent-changeable. Permitted dimensions: ${PERMITTED_SELF_MOUNT_DIMENSIONS.join(', ')}.`,\n )\n }\n const delta = (changes.skills ?? {}) as SkillsDelta\n const add = [...new Set((delta.add ?? []).map((s) => s.trim()).filter(Boolean))]\n const remove = [...new Set((delta.remove ?? []).map((s) => s.trim()).filter(Boolean))]\n if (add.length === 0 && remove.length === 0) {\n throw new ToolInputError('mount_profile_change', 'empty delta: provide skills.add and/or skills.remove')\n }\n const invalid = [...add, ...remove].filter((id) => !known.has(id))\n if (invalid.length > 0) {\n throw new ToolInputError(\n 'mount_profile_change',\n `unknown skill ids: ${invalid.join(', ')}. Catalog: ${[...known].sort().join(', ')}.`)\n }\n if (baseline && remove.includes(baseline)) {\n throw new ToolInputError(\n 'mount_profile_change',\n `refused: \"${baseline}\" is the always-on baseline and cannot be removed`)\n }\n\n const scope = scopeKey(ctx)\n const stored = await storage.get(scope)\n const before = [...new Set([...stored, ...(baseline ? [baseline] : [])])].sort()\n const mounted = new Set(before)\n for (const id of add) mounted.add(id)\n for (const id of remove) mounted.delete(id)\n if (baseline) mounted.add(baseline)\n const effective = [...mounted].sort()\n if (effective.length > maxMounted) {\n throw new ToolInputError(\n 'mount_profile_change',\n `refused: ${effective.length} skills exceeds the ${maxMounted}-skill mount limit`)\n }\n if (JSON.stringify(before) === JSON.stringify(effective)) {\n return { ok: true, mounted: [], removed: [], effective, note: 'no change (already in that state) — idempotent no-op' }\n }\n await storage.set(scope, effective)\n return {\n ok: true,\n mounted: effective.filter((id) => !before.includes(id)),\n removed: before.filter((id) => !effective.includes(id)),\n effective,\n note: 'applied — takes effect the next time the profile renders',\n }\n },\n })\n}\n"],"mappings":"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","names":["event","profile"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent-profiles/index.ts","../src/agent-profiles/self-management.ts"],"sourcesContent":["/** Chat-owned profile revisions and member/channel bindings. Execution stays in the substrate. */\nimport {\n canonicalAgentProfileDigest,\n diffAgentProfiles,\n snapshotAgentProfile,\n sha256Utf8,\n type AgentProfile,\n type AgentProfileDiff,\n} from '@tangle-network/agent-interface'\nimport { z } from 'zod'\nimport { normalizeProfileName, parseProfileSwitch } from './switch'\nexport { normalizeProfileName, parseProfileSwitch }\nimport type { McpToolDefinition } from '../tools'\n\nexport type ProfileAuthorKind = 'person' | 'agent' | 'optimizer'\nexport type ProfileRevisionState = 'active' | 'candidate' | 'pending-consent'\n\n/** The decision table used by every write path; products may narrow access, never widen it. */\nexport const PROFILE_CHANGE_POLICY = {\n textEdit: { admission: 'automatic', conversation: 'same', destructive: false },\n sameAuthoritySwitch: { admission: 'prepare-then-flip', conversation: 'same', destructive: false },\n differentAuthoritySwitch: { admission: 'prepare-then-flip', conversation: 'same', destructive: false },\n authorityEdit: { admission: 'editor-consent', conversation: 'same', destructive: false },\n optimizerRevision: { admission: 'eval-promotion', conversation: 'same', destructive: false },\n destructiveAction: { admission: 'reaper-only', conversation: 'none', destructive: true },\n} as const\n\nexport interface ProfileRevision {\n id: string\n workspaceId: string\n profileId: string\n parentId: string | null\n profile: AgentProfile\n knowledgeText: string\n author: { kind: ProfileAuthorKind; id: string }\n reason: string\n /** `null` means an older stored revision did not record the knowledge delta. */\n knowledgeTextChanged?: boolean | null\n diff: AgentProfileDiff[]\n authorityDigest: string\n /** ADC hash of the public profile plan, without per-turn product attachments. */\n planDigest: string\n state: ProfileRevisionState\n createdAt: number\n}\n\nexport interface ProfileBindingKey {\n workspaceId: string\n memberId: string\n /** `chat`, or a product-scoped phone line and sender key. */\n channel: string\n}\n\nexport interface ProfileBinding extends ProfileBindingKey {\n profileId: string\n pinnedRevisionId: string | null\n authorityDigest: string\n planDigest: string\n version: number\n}\n\nexport interface ProfileTurnPin {\n workspaceId: string\n memberId: string\n channel: string\n messageId: string\n inputHash: string\n profileId: string\n revisionId: string\n authorityDigest: string\n /** Effective ADC plan selected by the executor, including allowed turn attachments. */\n planDigest: string\n}\n\n/** Remove events name only adds they observed; a concurrent add survives. */\nexport interface ProfileKnowledgeEvent {\n id: string\n workspaceId: string\n profileId: string\n documentId: string\n kind: 'add' | 'remove'\n content: string | null\n observedAddIds: string[]\n createdAt: number\n}\n\nexport interface ProfileKnowledgeDocument {\n documentId: string\n content: string\n addEventId: string\n}\n\nexport interface ProfileSwitchReceipt {\n key: ProfileBindingKey\n messageId: string\n inputHash: string\n /** Visible conversation that should render this switch marker on reload. */\n conversationId?: string | null\n createdAt?: number\n profileId: string | null\n revisionId: string | null\n /** A rollback binds the previous immutable revision, not the current head. */\n pinnedRevisionId: string | null\n authorityDigest: string | null\n planDigest: string | null\n outcome: 'switched' | 'refused'\n message: string\n /** Workspace resource collisions retain the original and place the profile copy beside it. */\n conflicts: string[]\n}\n\nexport interface ProfileRevisionStore {\n getActiveRevision(workspaceId: string, profileId: string): Promise<ProfileRevision | null>\n getRevision(workspaceId: string, profileId: string, revisionId: string): Promise<ProfileRevision | null>\n /** Append the immutable row and optionally an activation event in one guarded transaction. */\n appendRevision(revision: ProfileRevision, expectedActiveId: string | null, activate: boolean): Promise<boolean>\n /** Promotion appends an activation event; the historical revision remains immutable. */\n promoteRevision(workspaceId: string, profileId: string, revisionId: string, expectedActiveId: string | null): Promise<boolean>\n getBinding(key: ProfileBindingKey): Promise<ProfileBinding | null>\n getSwitchReceipt(key: ProfileBindingKey, messageId: string, inputHash: string): Promise<ProfileSwitchReceipt | null>\n /** Receipt and binding event append atomically; a refusal leaves the binding untouched. */\n recordSwitch(receipt: ProfileSwitchReceipt, expectedVersion: number): Promise<ProfileSwitchReceipt>\n /** Persist one immutable pin under a message id; retries must return the same pin. */\n pinTurn(pin: ProfileTurnPin, expectedBindingVersion: number): Promise<ProfileTurnPin>\n getTurnPin(key: ProfileBindingKey, messageId: string, inputHash: string): Promise<ProfileTurnPin | null>\n listKnowledgeEvents(workspaceId: string, profileId: string): Promise<ProfileKnowledgeEvent[]>\n appendKnowledgeEvent(event: ProfileKnowledgeEvent): Promise<void>\n}\n\nexport class ProfileConflictError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ProfileConflictError'\n }\n}\n\nexport class ProfileAccessError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ProfileAccessError'\n }\n}\n\n/** Keep the existing diff column readable while adding the separate knowledge text axis. */\nexport function parseProfileRevisionDiff(value: string): {\n diff: AgentProfileDiff[]; knowledgeTextChanged: boolean | null\n} {\n const parsed: unknown = JSON.parse(value)\n if (Array.isArray(parsed)) return { diff: parsed as AgentProfileDiff[], knowledgeTextChanged: null }\n if (!parsed || typeof parsed !== 'object' || !('profile' in parsed) ||\n !Array.isArray(parsed.profile) || !('knowledgeTextChanged' in parsed) ||\n (parsed.knowledgeTextChanged !== null && typeof parsed.knowledgeTextChanged !== 'boolean')) {\n throw new TypeError('Stored profile revision diff is invalid')\n }\n return { diff: parsed.profile as AgentProfileDiff[],\n knowledgeTextChanged: parsed.knowledgeTextChanged }\n}\n\nexport function serializeProfileRevisionDiff(revision: Pick<ProfileRevision, 'diff' | 'knowledgeTextChanged'>): string {\n return JSON.stringify({ profile: revision.diff, knowledgeTextChanged: revision.knowledgeTextChanged ?? null })\n}\n\n/** Remove exactly the declared text axes. Unknown future fields remain authority. */\nexport function profileAuthority(profile: AgentProfile): AgentProfile {\n const { name: _name, description: _description, prompt, ...authority } = profile\n const { systemPrompt: _systemPrompt, instructions: _instructions, ...promptAuthority } = prompt ?? {}\n return { ...authority, ...(Object.keys(promptAuthority).length ? { prompt: promptAuthority } : {}) }\n}\n\nexport function profileAuthorityDigest(profile: AgentProfile): string {\n return canonicalAgentProfileDigest(profileAuthority(snapshotAgentProfile(profile)))\n}\n\nexport function projectKnowledgeDocuments(events: readonly ProfileKnowledgeEvent[]): ProfileKnowledgeDocument[] {\n const removed = new Set(events.filter(event => event.kind === 'remove').flatMap(event => event.observedAddIds))\n const visible = events.filter(event => event.kind === 'add' && !removed.has(event.id))\n const latest = new Map<string, ProfileKnowledgeEvent>()\n for (const event of visible) {\n const prior = latest.get(event.documentId)\n if (!prior || event.createdAt > prior.createdAt ||\n (event.createdAt === prior.createdAt && event.id > prior.id)) latest.set(event.documentId, event)\n }\n return [...latest.values()].sort((a, b) => a.documentId.localeCompare(b.documentId))\n .map(event => ({ documentId: event.documentId, content: event.content!, addEventId: event.id }))\n}\n\nexport async function addProfileKnowledgeDocument(input: {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n documentId: string\n content: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n id?: string\n now?: number\n}): Promise<ProfileKnowledgeEvent> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Profile management is required')\n }\n if (!input.documentId || !input.content) throw new TypeError('A knowledge document needs an id and content')\n const event: ProfileKnowledgeEvent = { id: input.id ?? crypto.randomUUID(),\n workspaceId: input.workspaceId, profileId: input.profileId, documentId: input.documentId,\n kind: 'add', content: input.content, observedAddIds: [], createdAt: input.now ?? Date.now() }\n await input.store.appendKnowledgeEvent(event)\n return event\n}\n\nexport async function removeProfileKnowledgeDocument(input: {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n documentId: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n id?: string\n now?: number\n}): Promise<ProfileKnowledgeEvent> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Profile management is required')\n }\n const events = await input.store.listKnowledgeEvents(input.workspaceId, input.profileId)\n const removed = new Set(events.filter(event => event.kind === 'remove').flatMap(event => event.observedAddIds))\n const observedAddIds = events.filter(event => event.kind === 'add' &&\n event.documentId === input.documentId && !removed.has(event.id)).map(event => event.id)\n const event: ProfileKnowledgeEvent = { id: input.id ?? crypto.randomUUID(),\n workspaceId: input.workspaceId, profileId: input.profileId, documentId: input.documentId,\n kind: 'remove', content: null, observedAddIds, createdAt: input.now ?? Date.now() }\n await input.store.appendKnowledgeEvent(event)\n return event\n}\n\n/** The per-turn text overlay is validated without admitting tools, model, MCP or resources. */\nexport function bindProfileText(consentedBaseline: AgentProfile, selected: AgentProfile): AgentProfile {\n if (profileAuthorityDigest(consentedBaseline) !== profileAuthorityDigest(selected)) {\n throw new ProfileAccessError('Profile authority differs; prepare its managed plan before the next turn')\n }\n // Profiles are digested as RFC 8785 JSON, which has no `undefined`: an\n // absent selected field removes the baseline's value instead of storing it.\n const result: AgentProfile = { ...consentedBaseline, name: selected.name }\n if (selected.description === undefined) delete result.description\n else result.description = selected.description\n const prompt: NonNullable<AgentProfile['prompt']> = { ...consentedBaseline.prompt }\n const { systemPrompt, instructions } = selected.prompt ?? {}\n if (systemPrompt === undefined) delete prompt.systemPrompt\n else prompt.systemPrompt = systemPrompt\n if (instructions === undefined) delete prompt.instructions\n else prompt.instructions = instructions\n if (Object.values(prompt).some(value => value !== undefined)) result.prompt = prompt\n else delete result.prompt\n return snapshotAgentProfile(result)\n}\n\nexport interface ProposeRevisionInput {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n expectedRevisionId: string | null\n profile: AgentProfile\n knowledgeText: string\n /** The exact ADC `hashWorkspacePlan` for this authored snapshot. */\n planDigest: string\n author: ProfileRevision['author']\n /** Trusted role from the authenticated session, never model arguments. */\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n reason: string\n id?: string\n now?: number\n}\n\n/** All authors use one immutable write path. Optimizer and authority edits cannot self-activate. */\nexport async function proposeRevision(input: ProposeRevisionInput): Promise<ProfileRevision> {\n if (input.author.kind !== 'optimizer' && input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can change a profile')\n }\n if (!input.workspaceId || !input.profileId || !input.author.id || !input.reason.trim() ||\n !/^sha256:[a-f0-9]{64}$/.test(input.planDigest)) {\n throw new TypeError('A profile revision needs workspace, profile, author, reason and plan digest')\n }\n const previous = await input.store.getActiveRevision(input.workspaceId, input.profileId)\n if ((previous?.id ?? null) !== input.expectedRevisionId) {\n throw new ProfileConflictError('The profile changed; read its latest revision before saving')\n }\n const profile = snapshotAgentProfile(input.profile)\n const diff = previous ? diffAgentProfiles(previous.profile, profile) : []\n const authorityDigest = profileAuthorityDigest(profile)\n const authorityChanged = !!previous && previous.authorityDigest !== authorityDigest\n const admission = input.author.kind === 'optimizer'\n ? PROFILE_CHANGE_POLICY.optimizerRevision.admission\n : authorityChanged\n ? PROFILE_CHANGE_POLICY.authorityEdit.admission\n : PROFILE_CHANGE_POLICY.textEdit.admission\n const state: ProfileRevisionState = admission === 'eval-promotion' ? 'candidate'\n : admission === 'editor-consent' ? 'pending-consent' : 'active'\n const revision: ProfileRevision = {\n id: input.id ?? crypto.randomUUID(), workspaceId: input.workspaceId, profileId: input.profileId,\n parentId: previous?.id ?? null, profile, knowledgeText: input.knowledgeText,\n author: input.author, reason: input.reason.trim(), diff,\n knowledgeTextChanged: previous ? previous.knowledgeText !== input.knowledgeText : input.knowledgeText.length > 0,\n authorityDigest,\n planDigest: input.planDigest, state, createdAt: input.now ?? Date.now(),\n }\n if (!await input.store.appendRevision(revision, input.expectedRevisionId, state === 'active')) {\n throw new ProfileConflictError('The profile changed while saving')\n }\n return revision\n}\n\nexport interface CreateTextProfileInput {\n store: ProfileRevisionStore\n workspaceId: string\n /** An active profile whose authority the new profile inherits exactly. */\n baselineProfileId: string\n /** Include builtins and user profiles from the authenticated workspace catalog. */\n existingProfiles: readonly { name: string }[]\n name: string\n instructions: string\n authorId: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n /** Product computes ADC's hashWorkspacePlan for the complete authored snapshot. */\n planDigest: (profile: AgentProfile) => string | Promise<string>\n now?: number\n}\n\n/** Create a distinct text persona without granting new model, tool, MCP or secret authority. */\nexport async function createTextProfile(input: CreateTextProfileInput): Promise<ProfileRevision> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can create a profile')\n }\n const name = input.name.trim().replace(/\\s+/g, ' ')\n const normalizedName = normalizeProfileName(name)\n if (!normalizedName) throw new TypeError('A profile needs a name')\n if (input.existingProfiles.some(profile => normalizeProfileName(profile.name) === normalizedName)) {\n throw new ProfileConflictError('A profile with that name already exists')\n }\n const baseline = await input.store.getActiveRevision(input.workspaceId, input.baselineProfileId)\n if (!baseline) throw new ProfileConflictError('The baseline profile is not active')\n // Equal names map to one id, so two concurrent creates cannot create an\n // ambiguous text command even when both read the catalog before either writes.\n const profileId = `custom-${sha256Utf8(`${input.workspaceId}\\0${normalizedName}`).slice(7, 39)}`\n const addedInstruction = input.instructions.trim()\n const profile = bindProfileText(baseline.profile, {\n ...baseline.profile, name,\n prompt: {\n ...baseline.profile.prompt,\n instructions: [...(baseline.profile.prompt?.instructions ?? []),\n ...(addedInstruction ? [addedInstruction] : [])],\n },\n })\n return proposeRevision({\n store: input.store, workspaceId: input.workspaceId, profileId,\n expectedRevisionId: null, profile, knowledgeText: '',\n planDigest: await input.planDigest(profile),\n author: { kind: 'person', id: input.authorId }, actorRole: input.actorRole,\n reason: 'Created a text profile from an approved baseline', now: input.now,\n })\n}\n\nexport async function promoteRevision(input: {\n store: ProfileRevisionStore\n workspaceId: string\n profileId: string\n revisionId: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n /** Verified by the product's consent route; required when authority changes. */\n verifyConsent?: (revision: ProfileRevision) => Promise<boolean>\n}): Promise<ProfileRevision> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can promote a profile')\n }\n const [revision, head] = await Promise.all([\n input.store.getRevision(input.workspaceId, input.profileId, input.revisionId),\n input.store.getActiveRevision(input.workspaceId, input.profileId),\n ])\n if (!revision || revision.parentId !== (head?.id ?? null)) throw new ProfileConflictError('Profile parent changed')\n if (revision.authorityDigest !== head?.authorityDigest &&\n (input.actorRole !== 'owner' || !input.verifyConsent || !await input.verifyConsent(revision))) {\n throw new ProfileAccessError('Authority changes require owner consent')\n }\n if (!await input.store.promoteRevision(input.workspaceId, input.profileId, revision.id, head?.id ?? null)) {\n throw new ProfileConflictError('The profile changed while promoting')\n }\n return revision\n}\n\n/** A source identity joins the command hash without entering the receipt row. */\nexport function profileSwitchInputHashFromContentHash(contentHash: string,\n identityContext?: string): string {\n return identityContext === undefined ? contentHash\n : sha256Utf8(JSON.stringify([identityContext, contentHash]))\n}\n\nexport function profileSwitchInputHash(content: string, identityContext?: string): string {\n return profileSwitchInputHashFromContentHash(sha256Utf8(content), identityContext)\n}\n\nexport interface SwitchableProfile {\n id: string\n name: string\n status: 'active' | 'draft' | 'paused'\n}\n\nexport interface SwitchProfileInput {\n store: ProfileRevisionStore\n key: ProfileBindingKey\n messageId: string\n content: string\n /** Trusted source identity, such as a phone sender; replay must preserve it. */\n identityContext?: string\n conversationId?: string\n choice: { name: string } | { profileId: string }\n profiles: readonly SwitchableProfile[]\n /** Product's role/phone allowlist decision for the authenticated member. */\n canSelect: (profileId: string) => Promise<boolean>\n /** Stage a complete managed plan for the same conversation; never mutate live workspace files. */\n prepareAuthority: (revision: ProfileRevision, key: ProfileBindingKey) => Promise<{\n planDigest: string; healthy: true; conflicts: string[]\n }>\n /** Receives the reason preparation failed; the person sees only a generic refusal.\n * Defaults to one structured `console.error` line so the reason reaches the host's logs. */\n onPrepareFailure?: (error: unknown, profileId: string) => void\n}\n\n/** The picker and deterministic text command converge here. Models cannot call it. */\nfunction logPrepareFailure(error: unknown, profileId: string): void {\n console.error(JSON.stringify({ event: 'profile-switch-prepare-failed', profileId,\n error: error instanceof Error ? `${error.name}: ${error.message}` : String(error) }))\n}\n\nexport async function switchProfile(input: SwitchProfileInput): Promise<ProfileSwitchReceipt> {\n const inputHash = profileSwitchInputHash(input.content, input.identityContext)\n const previousReceipt = await input.store.getSwitchReceipt(input.key, input.messageId, inputHash)\n if (previousReceipt) return previousReceipt\n const binding = await input.store.getBinding(input.key)\n const choice = input.choice\n const matches = 'name' in choice\n ? input.profiles.filter(profile => normalizeProfileName(profile.name) === normalizeProfileName(choice.name))\n : input.profiles.filter(profile => profile.id === choice.profileId)\n const target = matches.length === 1 ? matches[0] : undefined\n let revision: ProfileRevision | null = null\n if (target?.status === 'active' && await input.canSelect(target.id)) {\n revision = await input.store.getActiveRevision(input.key.workspaceId, target.id)\n if (revision && 'name' in choice &&\n normalizeProfileName(revision.profile.name ?? '') !== normalizeProfileName(choice.name)) {\n revision = null\n }\n }\n let outcome: ProfileSwitchReceipt['outcome'] = 'refused'\n let message = matches.length > 1 ? 'That profile name is ambiguous.'\n : target?.status !== 'active' && target ? `${target.name} is not active.`\n : 'That profile is not available for this member.'\n let planDigest: string | null = null\n let conflicts: string[] = []\n if (revision && target) {\n try {\n const prepared = await input.prepareAuthority(revision, input.key)\n if (!prepared.healthy || prepared.planDigest !== revision.planDigest) {\n throw new ProfileConflictError('The managed plan was not prepared for this revision')\n }\n planDigest = prepared.planDigest\n conflicts = prepared.conflicts\n } catch (error) {\n revision = null\n message = `Could not prepare ${target.name}; your current agent is unchanged.`\n ;(input.onPrepareFailure ?? logPrepareFailure)(error, target.id)\n }\n if (revision && planDigest) {\n outcome = 'switched'\n message = `Now talking to ${target.name}`\n }\n }\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: revision?.profileId ?? null, revisionId: revision?.id ?? null,\n pinnedRevisionId: null, authorityDigest: revision?.authorityDigest ?? null,\n planDigest, outcome, message, conflicts }, binding?.version ?? 0)\n}\n\n/** Call before dispatching a chat message; a recognized command is never sent to the model. */\nexport async function handleProfileSwitchText(\n input: Omit<SwitchProfileInput, 'choice'>,\n): Promise<ProfileSwitchReceipt | null> {\n const parsed = parseProfileSwitch(input.content)\n if (!parsed) return null\n if ('name' in parsed) return switchProfile({ ...input, choice: parsed })\n const inputHash = profileSwitchInputHash(input.content, input.identityContext)\n const previous = await input.store.getSwitchReceipt(input.key, input.messageId, inputHash)\n if (previous) return previous\n const binding = await input.store.getBinding(input.key)\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: null, revisionId: null, pinnedRevisionId: null, outcome: 'refused',\n authorityDigest: null, planDigest: null, conflicts: [],\n message: 'Send only “Switch to [agent name]” to change agents.' },\n binding?.version ?? 0)\n}\n\n/** One-step rollback moves this member/channel to its previous immutable revision. */\nexport async function rollbackProfileBinding(input: {\n store: ProfileRevisionStore\n key: ProfileBindingKey\n messageId: string\n conversationId?: string\n actorRole: 'owner' | 'manager' | 'member' | 'viewer'\n canSelect: (profileId: string) => Promise<boolean>\n prepareAuthority: SwitchProfileInput['prepareAuthority']\n}): Promise<ProfileSwitchReceipt> {\n if (input.actorRole !== 'owner' && input.actorRole !== 'manager') {\n throw new ProfileAccessError('Only an owner or manager can roll back a profile')\n }\n const inputHash = sha256Utf8(`rollback:${input.messageId}`)\n const prior = await input.store.getSwitchReceipt(input.key, input.messageId, inputHash)\n if (prior) return prior\n const binding = await input.store.getBinding(input.key)\n if (!binding || !await input.canSelect(binding.profileId)) throw new ProfileAccessError('Profile is unavailable')\n const current = binding.pinnedRevisionId\n ? await input.store.getRevision(input.key.workspaceId, binding.profileId, binding.pinnedRevisionId)\n : await input.store.getActiveRevision(input.key.workspaceId, binding.profileId)\n if (!current?.parentId) throw new ProfileConflictError('The bound profile has no previous revision')\n const parent = await input.store.getRevision(input.key.workspaceId, binding.profileId, current.parentId)\n if (!parent) throw new ProfileConflictError('The previous revision is unavailable')\n let planDigest = binding.planDigest\n let conflicts: string[] = []\n if (binding.authorityDigest !== parent.authorityDigest || binding.planDigest !== parent.planDigest) {\n try {\n const prepared = await input.prepareAuthority(parent, input.key)\n if (!prepared.healthy || prepared.planDigest !== parent.planDigest) {\n throw new ProfileConflictError('The prior managed plan was not prepared')\n }\n planDigest = prepared.planDigest\n conflicts = prepared.conflicts\n } catch {\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: null, revisionId: null, pinnedRevisionId: null, outcome: 'refused',\n authorityDigest: null, planDigest: null, conflicts: [],\n message: 'Could not prepare the previous profile; your current agent is unchanged.' },\n binding.version)\n }\n }\n return input.store.recordSwitch({ key: input.key, messageId: input.messageId, inputHash,\n conversationId: input.conversationId,\n profileId: parent.profileId, revisionId: parent.id, pinnedRevisionId: parent.id,\n authorityDigest: parent.authorityDigest, planDigest, outcome: 'switched', conflicts,\n message: `Now talking to ${parent.profile.name ?? 'this profile'}` }, binding.version)\n}\n\n/**\n * An opaque token for what `readProfileAdmission` read for one message. It carries no data: the values\n * live in this module, cloned when read, so a caller can neither build a token nor change what it stands\n * for. `admitProfileTurn` accepts each token once. The active-revision pointer is never part of it;\n * admission reads that live.\n */\nexport interface ProfileAdmissionRead { readonly [admissionReadBrand]: true }\ndeclare const admissionReadBrand: unique symbol\n\n/** The values a token stands for, as the caller may inspect them. */\nexport interface ProfileAdmissionValues {\n key: ProfileBindingKey\n messageId: string\n inputHash: string\n /** The message's existing pin, when it was already admitted. */\n prior: ProfileTurnPin | null\n binding: ProfileBinding | null\n /** The pinned revision by id (immutable), when the binding pins one. */\n pinnedRevision: ProfileRevision | null\n}\nconst admissionReads = new WeakMap<ProfileAdmissionRead, ProfileAdmissionValues>()\n/** Tokens already presented, so a second use is told apart from one this module never issued. */\nconst spentAdmissionReads = new WeakSet<ProfileAdmissionRead>()\n\n/**\n * Read what admitting a message needs: its prior pin and the binding together, then a pinned revision.\n * Read it where the caller holds its conversation lock (after any switch it records), check the values\n * with `profileAdmissionValues`, and pass the token to `admitProfileTurn`, which then skips re-reading\n * the pin and binding. The pin is still written as a compare-and-set on the binding version, so a\n * binding that moved after this read is refused.\n */\nexport async function readProfileAdmission(store: ProfileRevisionStore, key: ProfileBindingKey,\n messageId: string, content: string): Promise<ProfileAdmissionRead> {\n const inputHash = sha256Utf8(content)\n const [prior, binding] = await Promise.all([store.getTurnPin(key, messageId, inputHash), store.getBinding(key)])\n const pinnedRevision = !prior && binding?.pinnedRevisionId\n ? await store.getRevision(key.workspaceId, binding.profileId, binding.pinnedRevisionId) : null\n const read = Object.freeze(Object.create(null)) as ProfileAdmissionRead\n admissionReads.set(read, structuredClone({ key: { workspaceId: key.workspaceId, memberId: key.memberId, channel: key.channel },\n messageId, inputHash, prior, binding, pinnedRevision }))\n return read\n}\n\n/** A deep copy of what a token stands for; changing the copy changes nothing the token admits. */\nexport function profileAdmissionValues(read: ProfileAdmissionRead): ProfileAdmissionValues {\n const values = admissionReads.get(read)\n if (!values) throw new ProfileAccessError('Unknown or used profile admission read')\n return structuredClone(values)\n}\n\nexport async function admitProfileTurn(input: {\n store: ProfileRevisionStore\n key: ProfileBindingKey\n messageId: string\n content: string\n /** Effective ADC plan digest selected by the executor for this revision and turn. */\n observedManagedPlanDigest: string\n /** Required if trusted per-turn attachments change the public profile plan. */\n verifyEffectivePlan?: (revision: ProfileRevision, effectivePlanDigest: string,\n key: ProfileBindingKey) => Promise<boolean>\n /** A token from `readProfileAdmission` for this message; its pin and binding are not read again.\n * Each token admits once: after a failed admit, read again before retrying. */\n read?: ProfileAdmissionRead\n}): Promise<ProfileTurnPin> {\n const inputHash = sha256Utf8(input.content)\n // A token is spent when presented, so it admits at most one turn even if this call fails;\n // a retry reads again with `readProfileAdmission`.\n const read = input.read ? admissionReads.get(input.read) : undefined\n if (input.read && !read && spentAdmissionReads.has(input.read)) {\n throw new ProfileConflictError('The admission read was already used; read again')\n }\n if (input.read) { admissionReads.delete(input.read); spentAdmissionReads.add(input.read) }\n if (input.read && (!read || read.messageId !== input.messageId || read.inputHash !== inputHash ||\n read.key.workspaceId !== input.key.workspaceId || read.key.memberId !== input.key.memberId ||\n read.key.channel !== input.key.channel)) {\n throw new ProfileAccessError('The admission read does not belong to this message')\n }\n const prior = read ? read.prior : await input.store.getTurnPin(input.key, input.messageId, inputHash)\n if (prior) return prior\n const binding = read ? read.binding : await input.store.getBinding(input.key)\n if (!binding) throw new ProfileAccessError('Choose a profile before sending a message')\n // The active pointer can move without the binding version changing, so it is always read live.\n const revision = binding.pinnedRevisionId\n ? read?.pinnedRevision ?? await input.store.getRevision(input.key.workspaceId, binding.profileId, binding.pinnedRevisionId)\n : await input.store.getActiveRevision(input.key.workspaceId, binding.profileId)\n if (!revision) throw new ProfileConflictError('The bound profile revision is unavailable')\n if (revision.authorityDigest !== binding.authorityDigest ||\n !/^sha256:[a-f0-9]{64}$/.test(input.observedManagedPlanDigest)) {\n throw new ProfileAccessError('The selected managed plan is not active for this turn')\n }\n const planMatches = revision.planDigest === input.observedManagedPlanDigest ||\n (input.verifyEffectivePlan !== undefined &&\n await input.verifyEffectivePlan(revision, input.observedManagedPlanDigest, input.key))\n if (!planMatches) {\n throw new ProfileAccessError('The selected managed plan is not active for this turn')\n }\n return input.store.pinTurn({ ...input.key, messageId: input.messageId, inputHash,\n profileId: revision.profileId, revisionId: revision.id,\n authorityDigest: revision.authorityDigest, planDigest: input.observedManagedPlanDigest }, binding.version)\n}\n\nconst KNOWLEDGE_TEXT_MAX = 32000\nconst textChangeSchema = z.object({\n name: z.string().trim().min(1).max(160).optional(),\n description: z.string().max(2000).nullable().optional(),\n systemPrompt: z.string().max(32000).nullable().optional(),\n instructions: z.array(z.string().max(32000)).max(40).optional(),\n knowledgeText: z.string().max(KNOWLEDGE_TEXT_MAX).optional(),\n}).strict().refine(changes => Object.keys(changes).length > 0)\nconst updateToolSchema = z.object({ expectedRevisionId: z.string().min(1), changes: textChangeSchema }).strict()\nconst rememberToolSchema = z.object({ fact: z.string().trim().min(1).max(1000) }).strict()\n\nexport function profileTextChange(revision: ProfileRevision, changes: z.infer<typeof textChangeSchema>): {\n profile: AgentProfile; knowledgeText: string\n} {\n const profile = structuredClone(revision.profile)\n if (changes.name !== undefined) profile.name = changes.name\n if (changes.description !== undefined) profile.description = changes.description ?? undefined\n if (changes.systemPrompt !== undefined || changes.instructions !== undefined) {\n profile.prompt = { ...profile.prompt,\n ...(changes.systemPrompt !== undefined ? { systemPrompt: changes.systemPrompt ?? undefined } : {}),\n ...(changes.instructions !== undefined ? { instructions: changes.instructions } : {}) }\n }\n return { profile: snapshotAgentProfile(profile), knowledgeText: changes.knowledgeText ?? revision.knowledgeText }\n}\n\nexport interface ProfileToolTurn {\n workspaceId: string; profileId: string; revisionId: string\n memberId: string; role: 'owner' | 'manager' | 'member' | 'viewer'\n}\n\nexport interface ProfileToolContext<TTurn extends ProfileToolTurn = ProfileToolTurn> {\n /** Resolve the running turn from the trusted server session; never from tool arguments. */\n activeTurn(): Promise<TTurn>\n /** Product computes the plan with ADC, returning `hashWorkspacePlan(plan)`. */\n planDigest(profile: AgentProfile, knowledgeText: string): Promise<string>\n store: ProfileRevisionStore\n /** Return a store whose revision append atomically rechecks product turn authority. */\n storeForTurn?(turn: TTurn): ProfileRevisionStore\n /**\n * When set, `profile.remember` writes to this workspace memory store instead\n * of appending a profile revision, so remembered facts never change the\n * hashed profile (or anything that pins its version, such as a phone line).\n * Structurally matches agent-runtime's `WorkspaceStore`.\n */\n memory?: ProfileMemoryStore\n}\n\n/** The subset of agent-runtime's `WorkspaceStore` that `profile.remember` uses. */\nexport interface ProfileMemoryStore {\n list(workspaceId: string, prefix: string): Promise<Array<{ id: string; content?: string }>>\n put(input: { workspaceId: string; path: string; kind: 'fact'; ifRevision: null; actor: string;\n content: string; id?: string }): Promise<{ id: string; revision: number }>\n}\n\n/** Workspace-shared memories live under this prefix in the workspace store. */\nexport const PROFILE_MEMORY_PREFIX = '/memories/workspace/'\n\n/** Shared self-edit tools; only the authenticated active turn can name the profile. */\nexport function profileTools<TTurn extends ProfileToolTurn>(\n context: ProfileToolContext<TTurn>): McpToolDefinition<Record<string, never>>[] {\n return [{\n name: 'profile.read',\n description: 'Read the active agent profile text and revision. Saved text applies on the next message.',\n inputSchema: z.toJSONSchema(z.object({}).strict(), { io: 'input' }) as Record<string, unknown>,\n async run(args) {\n z.object({}).strict().parse(args)\n const turn = await context.activeTurn()\n if (turn.role !== 'owner' && turn.role !== 'manager') throw new ProfileAccessError('Profile management is required')\n const revision = await context.store.getActiveRevision(turn.workspaceId, turn.profileId)\n if (!revision) throw new ProfileConflictError('Profile revision is unavailable')\n return { profileId: turn.profileId, revisionId: revision.id, currentTurnRevisionId: turn.revisionId,\n name: revision.profile.name, description: revision.profile.description ?? null,\n systemPrompt: revision.profile.prompt?.systemPrompt ?? null,\n instructions: revision.profile.prompt?.instructions ?? [], knowledgeText: revision.knowledgeText }\n },\n }, {\n name: 'profile.update',\n description: 'Save a requested owner or manager text change with the revision from profile.read. Applies on the next message.',\n inputSchema: z.toJSONSchema(updateToolSchema, { io: 'input' }) as Record<string, unknown>,\n async run(args) {\n const { expectedRevisionId, changes } = updateToolSchema.parse(args)\n const turn = await context.activeTurn()\n if (turn.role !== 'owner' && turn.role !== 'manager') throw new ProfileAccessError('Profile management is required')\n const current = await context.store.getActiveRevision(turn.workspaceId, turn.profileId)\n if (!current || current.id !== expectedRevisionId) throw new ProfileConflictError('The profile changed; read it again')\n const next = profileTextChange(current, changes)\n const revision = await proposeRevision({ store: context.storeForTurn?.(turn) ?? context.store,\n workspaceId: turn.workspaceId,\n profileId: turn.profileId, expectedRevisionId, ...next,\n planDigest: await context.planDigest(next.profile, next.knowledgeText),\n author: { kind: 'agent', id: turn.memberId }, actorRole: turn.role,\n reason: 'Owner or manager requested a text change during chat' })\n return { profileId: turn.profileId, revisionId: revision.id, state: revision.state,\n canonicalSaved: revision.state === 'active', appliesTo: 'next_message', currentTurn: 'unchanged' }\n },\n }, {\n name: 'profile.remember',\n description: 'Save one durable fact or standing instruction an owner or manager tells you to keep '\n + '(\"remember\", \"note that\", \"from now on\", \"always\", \"never\"). Appends it as one line of the agent\\'s '\n + 'knowledge, which every later conversation reads. Applies on the next message.',\n inputSchema: z.toJSONSchema(rememberToolSchema, { io: 'input' }) as Record<string, unknown>,\n async run(args) {\n const { fact } = rememberToolSchema.parse(args)\n const turn = await context.activeTurn()\n if (turn.role !== 'owner' && turn.role !== 'manager') throw new ProfileAccessError('Profile management is required')\n if (context.memory) {\n const text = fact.replace(/\\s+/g, ' ')\n const known = (await context.memory.list(turn.workspaceId, PROFILE_MEMORY_PREFIX))\n .find(entry => entry.content?.trim() === text)\n if (known) return { memoryId: known.id, saved: true, alreadyKnown: true, line: `- ${text}`, appliesTo: 'next_message' }\n const id = crypto.randomUUID()\n const saved = await context.memory.put({ workspaceId: turn.workspaceId, path: `${PROFILE_MEMORY_PREFIX}${id}`,\n kind: 'fact', ifRevision: null, actor: turn.memberId, content: text, id })\n return { memoryId: saved.id, saved: true, alreadyKnown: false, line: `- ${text}`, appliesTo: 'next_message' }\n }\n const line = `- ${fact.replace(/\\s+/g, ' ')}`\n // One retry covers a concurrent save between the read and the append; the\n // revision chain keeps every earlier line.\n for (let attempt = 0; ; attempt++) {\n const current = await context.store.getActiveRevision(turn.workspaceId, turn.profileId)\n if (!current) throw new ProfileConflictError('Profile revision is unavailable')\n if (current.knowledgeText.split('\\n').some(existing => existing.trim() === line)) {\n return { profileId: turn.profileId, revisionId: current.id, saved: true, alreadyKnown: true,\n line, appliesTo: 'next_message' }\n }\n const knowledgeText = current.knowledgeText.trim() ? `${current.knowledgeText.trimEnd()}\\n${line}` : line\n if (knowledgeText.length > KNOWLEDGE_TEXT_MAX) {\n throw new ProfileConflictError('Knowledge is full; ask the owner to edit it before saving more')\n }\n try {\n const revision = await proposeRevision({ store: context.storeForTurn?.(turn) ?? context.store,\n workspaceId: turn.workspaceId, profileId: turn.profileId, expectedRevisionId: current.id,\n profile: current.profile, knowledgeText,\n planDigest: await context.planDigest(current.profile, knowledgeText),\n author: { kind: 'agent', id: turn.memberId }, actorRole: turn.role,\n reason: 'Owner or manager asked the agent to remember a fact during chat' })\n return { profileId: turn.profileId, revisionId: revision.id, saved: revision.state === 'active',\n state: revision.state, alreadyKnown: false, line, appliesTo: 'next_message' }\n } catch (error) {\n if (!(error instanceof ProfileConflictError) || attempt > 0) throw error\n }\n }\n },\n }]\n}\n\nexport * from './self-management'\n","/**\n * Live profile self-mounting — the safe, immediate subset of agent\n * self-improvement.\n *\n * The revision system ({@link ProfileRevision}, `PROFILE_CHANGE_POLICY`) owns\n * durable profile evolution: authority edits need editor consent, optimizer\n * revisions promote through eval. Self-mounting is the complementary\n * LIVE dimension — the sandboxed agent adjusts its own mounted context\n * (skills today) within a permitted, idempotent, catalog-validated delta.\n * Nothing here touches authority: model, permissions, tools denials and\n * billing identity are not agent-changeable dimensions, and every refusal\n * names the permitted set.\n *\n * One audited verb, not a family: `mount_profile_change` applies a validated\n * delta against a permitted-dimensions allowlist; re-applying the same delta\n * is a no-op; the baseline skill cannot be removed; the mount count is capped\n * because context is a budget.\n *\n * Products wire their own catalog and persistence:\n *\n * ```ts\n * import { createMountProfileChangeTool, createInMemorySelfMountStorage } from '@tangle-network/agent-app/agent-profiles'\n *\n * const mountProfileChange = createMountProfileChangeTool({\n * skills: mySkillRegistry, // { id, description }[]\n * storage: createD1SelfMountStorage(env.DB), // or any { get, set }\n * scopeKey: (ctx) => ctx.threadId ?? ctx.userId, // product's persistence scope\n * baseline: 'cad',\n * })\n * ```\n */\nimport { defineAppTool, type AppToolDefinition } from '../tools/registry'\nimport { ToolInputError } from '../tools/errors'\nimport type { AppToolContext } from '../tools/types'\n\n/** The only profile dimensions an agent may change on its own mounted state.\n * Anything else in a delta is refused with this list — the boundary is the\n * schema, not the verb count. */\nexport const PERMITTED_SELF_MOUNT_DIMENSIONS = ['skills'] as const\n\nexport interface SelfMountSkillEntry {\n /** Registry-unique skill id. */\n id: string\n /** One-line description, surfaced in the tool's catalog. */\n description: string\n}\n\n/** Durable mounted-skill state, keyed by the product's scope. */\nexport interface SelfMountStorage {\n get(scope: string): Promise<readonly string[]>\n set(scope: string, ids: readonly string[]): Promise<void>\n}\n\n/** Non-durable default for tests and single-instance products. */\nexport function createInMemorySelfMountStorage(): SelfMountStorage {\n const state = new Map<string, string[]>()\n return {\n async get(scope) {\n return state.get(scope) ?? []\n },\n async set(scope, ids) {\n state.set(scope, [...new Set(ids)].sort())\n },\n }\n}\n\nexport interface MountProfileChangeDeps {\n /** The product's skill catalog — the only mountable ids. */\n skills: readonly SelfMountSkillEntry[]\n /** Where mounted ids persist, keyed by the product's scope. */\n storage: SelfMountStorage\n /** The persistence scope for a call (project id, thread id, …). */\n scopeKey: (ctx: AppToolContext) => string\n /** Always-mounted skill id that cannot be removed. Default: none. */\n baseline?: string\n /** Upper bound on total mounted skills. Default 12; context is a budget. */\n maxMounted?: number\n /** Tool name override when a product needs a distinct verb. */\n name?: string\n}\n\ninterface SkillsDelta {\n add?: string[]\n remove?: string[]\n}\n\nexport interface MountProfileChangeResult {\n ok: true\n mounted: string[]\n removed: string[]\n effective: string[]\n note: string\n}\n\nfunction catalogLine(skills: readonly SelfMountSkillEntry[]): string {\n return skills.map((s) => `${s.id} (${s.description})`).join('; ')\n}\n\n/**\n * The permitted, idempotent self-mount verb as an app tool. Register it with\n * the product's tool set; the sandboxed agent calls it through the per-turn\n * MCP surface like any other app tool.\n */\nexport function createMountProfileChangeTool(deps: MountProfileChangeDeps): AppToolDefinition<Record<string, unknown>> {\n const { skills, storage, scopeKey } = deps\n const baseline = deps.baseline?.trim() || undefined\n const maxMounted = deps.maxMounted ?? 12\n const known = new Set(skills.map((s) => s.id))\n if (known.size !== skills.length) throw new Error('createMountProfileChangeTool: duplicate skill ids in the catalog')\n if (baseline && !known.has(baseline)) throw new Error(`createMountProfileChangeTool: baseline \"${baseline}\" is not in the catalog`)\n\n return defineAppTool({\n name: deps.name ?? 'mount_profile_change',\n description:\n `Apply a permitted, idempotent change to the mounted skills on this profile. ` +\n `Permitted dimension: skills ({ add: [ids], remove: [ids] }) — anything else is refused. ` +\n `Re-applying the same change is a no-op. Takes effect the next time the profile renders. ` +\n `Catalog: ${catalogLine(skills)}.`,\n parameters: {\n type: 'object',\n properties: {\n changes: {\n type: 'object',\n description: `The profile delta. Permitted dimensions: ${PERMITTED_SELF_MOUNT_DIMENSIONS.join(', ')}.`,\n properties: {\n skills: {\n type: 'object',\n description: 'Skill mounts: catalog ids to add or remove.',\n properties: {\n add: { type: 'array', items: { type: 'string' }, description: 'Catalog skill ids to mount.' },\n remove: { type: 'array', items: { type: 'string' }, description: 'Mounted skill ids to unmount.' },\n },\n additionalProperties: false,\n },\n },\n additionalProperties: false,\n },\n },\n required: ['changes'],\n additionalProperties: false,\n },\n async execute(args: unknown, ctx: AppToolContext): Promise<MountProfileChangeResult | { ok: false; error: string }> {\n const changes = (args as { changes?: Record<string, unknown> }).changes ?? {}\n const unknownDimensions = Object.keys(changes).filter(\n (d) => !(PERMITTED_SELF_MOUNT_DIMENSIONS as readonly string[]).includes(d),\n )\n if (unknownDimensions.length > 0) {\n throw new ToolInputError(\n 'mount_profile_change',\n `dimensions [${unknownDimensions.join(', ')}] are not agent-changeable. Permitted dimensions: ${PERMITTED_SELF_MOUNT_DIMENSIONS.join(', ')}.`,\n )\n }\n const delta = (changes.skills ?? {}) as SkillsDelta\n const add = [...new Set((delta.add ?? []).map((s) => s.trim()).filter(Boolean))]\n const remove = [...new Set((delta.remove ?? []).map((s) => s.trim()).filter(Boolean))]\n if (add.length === 0 && remove.length === 0) {\n throw new ToolInputError('mount_profile_change', 'empty delta: provide skills.add and/or skills.remove')\n }\n const invalid = [...add, ...remove].filter((id) => !known.has(id))\n if (invalid.length > 0) {\n throw new ToolInputError(\n 'mount_profile_change',\n `unknown skill ids: ${invalid.join(', ')}. Catalog: ${[...known].sort().join(', ')}.`)\n }\n if (baseline && remove.includes(baseline)) {\n throw new ToolInputError(\n 'mount_profile_change',\n `refused: \"${baseline}\" is the always-on baseline and cannot be removed`)\n }\n\n const scope = scopeKey(ctx)\n const stored = await storage.get(scope)\n const before = [...new Set([...stored, ...(baseline ? [baseline] : [])])].sort()\n const mounted = new Set(before)\n for (const id of add) mounted.add(id)\n for (const id of remove) mounted.delete(id)\n if (baseline) mounted.add(baseline)\n const effective = [...mounted].sort()\n if (effective.length > maxMounted) {\n throw new ToolInputError(\n 'mount_profile_change',\n `refused: ${effective.length} skills exceeds the ${maxMounted}-skill mount limit`)\n }\n if (JSON.stringify(before) === JSON.stringify(effective)) {\n return { ok: true, mounted: [], removed: [], effective, note: 'no change (already in that state) — idempotent no-op' }\n }\n await storage.set(scope, effective)\n return {\n ok: true,\n mounted: effective.filter((id) => !before.includes(id)),\n removed: before.filter((id) => !effective.includes(id)),\n effective,\n note: 'applied — takes effect the next time the profile renders',\n }\n },\n })\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/** Any drizzle database instance (structural — the adapters only use\n * select/insert with the standard builder chain). */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleLike = any\n\n// ── Shared storage adapters ────────────────────────────────────────────────\n//\n// Every product's self-mount storage is the same shape: a scope key and a\n// JSON list of mounted skill ids. These adapters mean each product wires\n// the verb in 3 lines instead of hand-writing a drizzle query.\n\nimport type { drizzle as drizzleD1 } from 'drizzle-orm/d1'\nimport { eq } from 'drizzle-orm'\nimport { sqliteTable, text } from 'drizzle-orm/sqlite-core'\n\n/** Create (or use) the standard self-mount table in a drizzle/D1 database. */\nexport function selfMountTable(tableName: string) {\n return sqliteTable(tableName, {\n scope: text('scope').primaryKey(),\n mounted: text('mounted').notNull(),\n })\n}\n\n/** A drizzle-backed SelfMountStorage against any table with the standard\n * shape (scope primary key + mounted JSON text column). Works with the\n * tables every product creates via {@link selfMountTable}. */\nexport function createDrizzleSelfMountStorage(\n db: DrizzleLike,\n table: ReturnType<typeof selfMountTable>,\n baseline: string,\n): SelfMountStorage {\n return {\n async get(scope: string): Promise<readonly string[]> {\n const rows = await db\n .select({ mounted: table.mounted })\n .from(table)\n .where(eq(table.scope, scope))\n .limit(1)\n try {\n return rows[0] ? (JSON.parse(rows[0].mounted) as string[]) : [baseline]\n } catch {\n return [baseline]\n }\n },\n async set(scope: string, ids: readonly string[]): Promise<void> {\n await db\n .insert(table)\n .values({ scope, mounted: JSON.stringify(ids) })\n .onConflictDoUpdate({\n target: table.scope,\n set: { mounted: JSON.stringify(ids) },\n })\n },\n }\n}\n\n/** A KV-backed SelfMountStorage (Cloudflare KV, any namespace). */\nexport function createKVSelfMountStorage(\n kv: { get(key: string): Promise<string | null>; put(key: string, value: string): Promise<void> },\n prefix: string,\n baseline: string,\n): SelfMountStorage {\n const key = (scope: string) => `${prefix}:${scope}`\n return {\n async get(scope: string): Promise<readonly string[]> {\n const raw = await kv.get(key(scope))\n try { return raw ? (JSON.parse(raw) as string[]) : [baseline] } catch { return [baseline] }\n },\n async set(scope: string, ids: readonly string[]): Promise<void> {\n await kv.put(key(scope), JSON.stringify(ids))\n },\n }\n}\n\n/** The one-call product wiring: catalog + storage + baseline + cap. */\nexport interface ProductSelfMountConfig {\n /** The product's skill catalog (id + description per skill). */\n skills: ReadonlyArray<{ id: string; description: string }>\n /** A drizzle/D1 database (uses a self-mount table) or a KV namespace. */\n db?: DrizzleLike\n kv?: { get(key: string): Promise<string | null>; put(key: string, value: string): Promise<void> }\n /** The table name for drizzle storage (default: 'agent_self_mounts'). */\n tableName?: string\n /** KV prefix (default: 'self-mount'). */\n kvPrefix?: string\n /** The skill id that can never be removed. */\n baseline: string\n /** Max simultaneous mounts (default: 12). */\n maxMounted?: number\n}\n\nexport function createProductSelfMount(config: ProductSelfMountConfig) {\n const storage = config.db\n ? createDrizzleSelfMountStorage(config.db, selfMountTable(config.tableName ?? 'agent_self_mounts'), config.baseline)\n : config.kv\n ? createKVSelfMountStorage(config.kv, config.kvPrefix ?? 'self-mount', config.baseline)\n : undefined\n if (!storage) throw new Error('createProductSelfMount needs db or kv')\n return createMountProfileChangeTool({\n skills: config.skills,\n storage,\n scopeKey: (ctx) => ctx.workspaceId ?? ctx.threadId ?? '',\n baseline: config.baseline,\n maxMounted: config.maxMounted ?? 12,\n })\n}\n"],"mappings":"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","names":["event","profile","text"]}
|