@agent-native/creative-context 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -9
- package/agent-native.package.json +4 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +8 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-context-memberships.d.ts +11 -0
- package/dist/actions/list-context-memberships.d.ts.map +1 -0
- package/dist/actions/list-context-memberships.js +47 -0
- package/dist/actions/list-context-memberships.js.map +1 -0
- package/dist/actions/list-creative-contexts.d.ts +12 -0
- package/dist/actions/list-creative-contexts.d.ts.map +1 -0
- package/dist/actions/list-creative-contexts.js +28 -0
- package/dist/actions/list-creative-contexts.js.map +1 -0
- package/dist/actions/manage-context-membership.d.ts +64 -0
- package/dist/actions/manage-context-membership.d.ts.map +1 -0
- package/dist/actions/manage-context-membership.js +70 -0
- package/dist/actions/manage-context-membership.js.map +1 -0
- package/dist/actions/manage-context-pack.d.ts +3 -0
- package/dist/actions/manage-context-pack.js +6 -0
- package/dist/actions/manage-context-pack.js.map +1 -1
- package/dist/actions/manage-context-source.js +4 -11
- package/dist/actions/manage-context-source.js.map +1 -1
- package/dist/actions/manage-creative-context.d.ts +28 -0
- package/dist/actions/manage-creative-context.d.ts.map +1 -0
- package/dist/actions/manage-creative-context.js +65 -0
- package/dist/actions/manage-creative-context.js.map +1 -0
- package/dist/actions/process-context-purge.d.ts +16 -1
- package/dist/actions/process-context-purge.js +2 -1
- package/dist/actions/process-context-purge.js.map +1 -1
- package/dist/actions/search-creative-context.d.ts +1 -0
- package/dist/actions/search-creative-context.js +2 -1
- package/dist/actions/search-creative-context.js.map +1 -1
- package/dist/client/CreativeContextChip.d.ts +5 -1
- package/dist/client/CreativeContextChip.d.ts.map +1 -1
- package/dist/client/CreativeContextChip.js +36 -7
- package/dist/client/CreativeContextChip.js.map +1 -1
- package/dist/client/CreativeContextPanel.d.ts.map +1 -1
- package/dist/client/CreativeContextPanel.js +406 -89
- package/dist/client/CreativeContextPanel.js.map +1 -1
- package/dist/client/CreativeContextShareTab.d.ts +56 -0
- package/dist/client/CreativeContextShareTab.d.ts.map +1 -0
- package/dist/client/CreativeContextShareTab.js +213 -0
- package/dist/client/CreativeContextShareTab.js.map +1 -0
- package/dist/client/actions.d.ts +210 -0
- package/dist/client/actions.d.ts.map +1 -1
- package/dist/client/actions.js +318 -0
- package/dist/client/actions.js.map +1 -1
- package/dist/client/application-state.d.ts +2 -0
- package/dist/client/application-state.d.ts.map +1 -1
- package/dist/client/application-state.js +25 -2
- package/dist/client/application-state.js.map +1 -1
- package/dist/client/index.d.ts +4 -3
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +4 -3
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +1 -1
- package/dist/client/messages.d.ts.map +1 -1
- package/dist/client/messages.js +77 -0
- package/dist/client/messages.js.map +1 -1
- package/dist/connectors/types.d.ts +2 -2
- package/dist/connectors/types.d.ts.map +1 -1
- package/dist/schema/index.d.ts +1592 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +95 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/migrations.d.ts.map +1 -1
- package/dist/schema/migrations.js +80 -0
- package/dist/schema/migrations.js.map +1 -1
- package/dist/server/generation-artifact-access.js +2 -0
- package/dist/server/generation-artifact-access.js.map +1 -1
- package/dist/server/generation-context.d.ts +12 -4
- package/dist/server/generation-context.d.ts.map +1 -1
- package/dist/server/generation-context.js +129 -7
- package/dist/server/generation-context.js.map +1 -1
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +16 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/isolated-a2a.d.ts +3 -0
- package/dist/server/isolated-a2a.d.ts.map +1 -1
- package/dist/server/isolated-a2a.js +3 -1
- package/dist/server/isolated-a2a.js.map +1 -1
- package/dist/server/media.d.ts +1 -1
- package/dist/server/media.d.ts.map +1 -1
- package/dist/server/media.js +24 -9
- package/dist/server/media.js.map +1 -1
- package/dist/server/native-resource-capture.d.ts +78 -0
- package/dist/server/native-resource-capture.d.ts.map +1 -0
- package/dist/server/native-resource-capture.js +94 -0
- package/dist/server/native-resource-capture.js.map +1 -0
- package/dist/server/public-serialization.js +1 -1
- package/dist/server/public-serialization.js.map +1 -1
- package/dist/server/retrieval.d.ts +1 -0
- package/dist/server/retrieval.d.ts.map +1 -1
- package/dist/server/retrieval.js +2 -0
- package/dist/server/retrieval.js.map +1 -1
- package/dist/server/safe-native-preview.d.ts +15 -0
- package/dist/server/safe-native-preview.d.ts.map +1 -0
- package/dist/server/safe-native-preview.js +149 -0
- package/dist/server/safe-native-preview.js.map +1 -0
- package/dist/store/brand.d.ts.map +1 -1
- package/dist/store/brand.js +2 -16
- package/dist/store/brand.js.map +1 -1
- package/dist/store/content.d.ts +1 -0
- package/dist/store/content.d.ts.map +1 -1
- package/dist/store/content.js +84 -20
- package/dist/store/content.js.map +1 -1
- package/dist/store/contexts.d.ts +216 -0
- package/dist/store/contexts.d.ts.map +1 -0
- package/dist/store/contexts.js +1341 -0
- package/dist/store/contexts.js.map +1 -0
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +1 -0
- package/dist/store/index.js.map +1 -1
- package/dist/store/packs.d.ts +3 -0
- package/dist/store/packs.d.ts.map +1 -1
- package/dist/store/packs.js +126 -9
- package/dist/store/packs.js.map +1 -1
- package/dist/store/purge.d.ts.map +1 -1
- package/dist/store/purge.js +103 -6
- package/dist/store/purge.js.map +1 -1
- package/dist/store/sources.d.ts.map +1 -1
- package/dist/store/sources.js +2 -15
- package/dist/store/sources.js.map +1 -1
- package/dist/store/suggestions.d.ts.map +1 -1
- package/dist/store/suggestions.js +3 -1
- package/dist/store/suggestions.js.map +1 -1
- package/dist/types.d.ts +77 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -1
- package/dist/types.js.map +1 -1
- package/docs/skills/creative-context/SKILL.md +13 -5
- package/package.json +3 -3
- package/src/actions/index.ts +8 -0
- package/src/actions/job-public-serialization.spec.ts +21 -0
- package/src/actions/list-context-memberships.ts +56 -0
- package/src/actions/list-creative-contexts.spec.ts +38 -0
- package/src/actions/list-creative-contexts.ts +32 -0
- package/src/actions/manage-context-membership.ts +80 -0
- package/src/actions/manage-context-pack.ts +6 -0
- package/src/actions/manage-context-source.ts +8 -11
- package/src/actions/manage-creative-context.ts +73 -0
- package/src/actions/process-context-purge.ts +4 -1
- package/src/actions/search-creative-context.ts +2 -1
- package/src/client/CreativeContextChip.spec.ts +32 -0
- package/src/client/CreativeContextChip.tsx +83 -14
- package/src/client/CreativeContextPanel.tsx +1947 -885
- package/src/client/CreativeContextShareTab.spec.ts +70 -0
- package/src/client/CreativeContextShareTab.tsx +657 -0
- package/src/client/actions.spec.ts +177 -0
- package/src/client/actions.ts +566 -0
- package/src/client/application-state.spec.ts +5 -0
- package/src/client/application-state.ts +30 -2
- package/src/client/index.ts +33 -0
- package/src/client/messages.ts +95 -0
- package/src/connectors/types.ts +6 -8
- package/src/eval/library-flow.acceptance.spec.tsx +1 -0
- package/src/schema/index.ts +116 -0
- package/src/schema/migrations.ts +80 -0
- package/src/server/generation-artifact-access.ts +1 -0
- package/src/server/generation-context-a2a.spec.ts +133 -0
- package/src/server/generation-context.ts +153 -7
- package/src/server/index.spec.ts +15 -0
- package/src/server/index.ts +16 -0
- package/src/server/isolated-a2a.ts +4 -1
- package/src/server/media.spec.ts +30 -2
- package/src/server/media.ts +31 -12
- package/src/server/native-resource-capture.spec.ts +121 -0
- package/src/server/native-resource-capture.ts +198 -0
- package/src/server/public-serialization.spec.ts +1 -0
- package/src/server/public-serialization.ts +1 -1
- package/src/server/retrieval.ts +3 -0
- package/src/server/safe-native-preview.spec.ts +29 -0
- package/src/server/safe-native-preview.ts +200 -0
- package/src/store/access.integration.spec.ts +1116 -0
- package/src/store/brand.ts +2 -21
- package/src/store/content.ts +217 -17
- package/src/store/contexts.ts +1826 -0
- package/src/store/index.ts +1 -0
- package/src/store/packs.ts +279 -24
- package/src/store/purge.ts +139 -6
- package/src/store/sources.ts +2 -18
- package/src/store/suggestions.ts +3 -1
- package/src/types.ts +95 -0
package/src/store/index.ts
CHANGED
package/src/store/packs.ts
CHANGED
|
@@ -3,9 +3,20 @@ import {
|
|
|
3
3
|
assertAccess,
|
|
4
4
|
resolveAccess,
|
|
5
5
|
} from "@agent-native/core/sharing";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
and,
|
|
8
|
+
asc,
|
|
9
|
+
eq,
|
|
10
|
+
gt,
|
|
11
|
+
inArray,
|
|
12
|
+
isNotNull,
|
|
13
|
+
isNull,
|
|
14
|
+
ne,
|
|
15
|
+
or,
|
|
16
|
+
} from "drizzle-orm";
|
|
7
17
|
|
|
8
18
|
import { getCreativeContext } from "../server/context.js";
|
|
19
|
+
import { sanitizePublicMetadata } from "../server/public-serialization.js";
|
|
9
20
|
import type {
|
|
10
21
|
ContextPackDetail,
|
|
11
22
|
ContextPackMember,
|
|
@@ -20,6 +31,16 @@ import {
|
|
|
20
31
|
stringifyJson,
|
|
21
32
|
} from "./helpers.js";
|
|
22
33
|
|
|
34
|
+
type ResolvedPackMember = {
|
|
35
|
+
itemId: string;
|
|
36
|
+
itemVersionId: string;
|
|
37
|
+
reason?: string;
|
|
38
|
+
score?: number;
|
|
39
|
+
scoreMetadata?: Record<string, unknown>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const MAX_NATIVE_PACK_DEPENDENCIES = 256;
|
|
43
|
+
|
|
23
44
|
export function assertImmutablePackMembership(operation: string): never {
|
|
24
45
|
throw new Error(
|
|
25
46
|
`Context-pack membership is append-only; ${operation} must derive a new pack snapshot`,
|
|
@@ -48,15 +69,9 @@ async function resolveBrandDnaVersion(
|
|
|
48
69
|
return dnaVersionId;
|
|
49
70
|
}
|
|
50
71
|
|
|
51
|
-
async function resolveMembers(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
itemVersionId: string;
|
|
55
|
-
reason?: string;
|
|
56
|
-
score?: number;
|
|
57
|
-
scoreMetadata?: Record<string, unknown>;
|
|
58
|
-
}>
|
|
59
|
-
> {
|
|
72
|
+
async function resolveMembers(
|
|
73
|
+
members: ContextPackMemberInput[],
|
|
74
|
+
): Promise<ResolvedPackMember[]> {
|
|
60
75
|
const { getDb, schema } = getCreativeContext();
|
|
61
76
|
const itemIds = members.map((member) => member.itemId);
|
|
62
77
|
if (new Set(itemIds).size !== itemIds.length) {
|
|
@@ -73,12 +88,34 @@ async function resolveMembers(members: ContextPackMemberInput[]): Promise<
|
|
|
73
88
|
schema.contextSources,
|
|
74
89
|
eq(schema.contextSources.id, schema.contextItems.sourceId),
|
|
75
90
|
)
|
|
91
|
+
.leftJoin(
|
|
92
|
+
schema.creativeContextMemberships,
|
|
93
|
+
and(
|
|
94
|
+
eq(
|
|
95
|
+
schema.creativeContextMemberships.publishedItemId,
|
|
96
|
+
schema.contextItems.id,
|
|
97
|
+
),
|
|
98
|
+
eq(schema.creativeContextMemberships.status, "active"),
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
.leftJoin(
|
|
102
|
+
schema.creativeContexts,
|
|
103
|
+
eq(
|
|
104
|
+
schema.creativeContexts.id,
|
|
105
|
+
schema.creativeContextMemberships.contextId,
|
|
106
|
+
),
|
|
107
|
+
)
|
|
76
108
|
.where(
|
|
77
109
|
and(
|
|
78
110
|
inArray(schema.contextItems.id, itemIds),
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
111
|
+
or(
|
|
112
|
+
and(
|
|
113
|
+
accessFilter(schema.contextSources, schema.contextSourceShares),
|
|
114
|
+
ne(schema.contextSources.upstreamAccess, "restricted"),
|
|
115
|
+
ne(schema.contextSources.status, "archived"),
|
|
116
|
+
),
|
|
117
|
+
accessFilter(schema.creativeContexts, schema.creativeContextShares),
|
|
118
|
+
),
|
|
82
119
|
eq(schema.contextItems.curationStatus, "included"),
|
|
83
120
|
ne(schema.contextItems.curationRank, "ignored"),
|
|
84
121
|
eq(schema.contextItems.status, "active"),
|
|
@@ -130,12 +167,140 @@ async function resolveMembers(members: ContextPackMemberInput[]): Promise<
|
|
|
130
167
|
});
|
|
131
168
|
}
|
|
132
169
|
|
|
170
|
+
async function includeNativeArtifactDependencies(
|
|
171
|
+
explicitMembers: ResolvedPackMember[],
|
|
172
|
+
): Promise<ResolvedPackMember[]> {
|
|
173
|
+
if (!explicitMembers.length) return explicitMembers;
|
|
174
|
+
const { getDb, schema } = getCreativeContext();
|
|
175
|
+
const members = [...explicitMembers];
|
|
176
|
+
const byItemId = new Map(members.map((member) => [member.itemId, member]));
|
|
177
|
+
const sourceByVersion = new Map<string, string>();
|
|
178
|
+
const initialItems = await getDb()
|
|
179
|
+
.select({
|
|
180
|
+
itemId: schema.contextItems.id,
|
|
181
|
+
itemVersionId: schema.contextItemVersions.id,
|
|
182
|
+
sourceId: schema.contextItems.sourceId,
|
|
183
|
+
})
|
|
184
|
+
.from(schema.contextItemVersions)
|
|
185
|
+
.innerJoin(
|
|
186
|
+
schema.contextItems,
|
|
187
|
+
eq(schema.contextItems.id, schema.contextItemVersions.itemId),
|
|
188
|
+
)
|
|
189
|
+
.where(
|
|
190
|
+
inArray(
|
|
191
|
+
schema.contextItemVersions.id,
|
|
192
|
+
explicitMembers.map((member) => member.itemVersionId),
|
|
193
|
+
),
|
|
194
|
+
);
|
|
195
|
+
for (const item of initialItems as Array<{
|
|
196
|
+
itemId: string;
|
|
197
|
+
itemVersionId: string;
|
|
198
|
+
sourceId: string;
|
|
199
|
+
}>) {
|
|
200
|
+
sourceByVersion.set(item.itemVersionId, item.sourceId);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let frontier = explicitMembers.map((member) => member.itemVersionId);
|
|
204
|
+
let dependencyCount = 0;
|
|
205
|
+
while (frontier.length) {
|
|
206
|
+
const edges = await getDb()
|
|
207
|
+
.select({
|
|
208
|
+
fromItemVersionId: schema.contextEdges.fromItemVersionId,
|
|
209
|
+
toItemId: schema.contextEdges.toItemId,
|
|
210
|
+
toItemVersionId: schema.contextEdges.toItemVersionId,
|
|
211
|
+
toExternalId: schema.contextEdges.toExternalId,
|
|
212
|
+
childSourceId: schema.contextItems.sourceId,
|
|
213
|
+
childVersionId: schema.contextItemVersions.id,
|
|
214
|
+
})
|
|
215
|
+
.from(schema.contextEdges)
|
|
216
|
+
.leftJoin(
|
|
217
|
+
schema.contextItems,
|
|
218
|
+
eq(schema.contextItems.id, schema.contextEdges.toItemId),
|
|
219
|
+
)
|
|
220
|
+
.leftJoin(
|
|
221
|
+
schema.contextItemVersions,
|
|
222
|
+
and(
|
|
223
|
+
eq(
|
|
224
|
+
schema.contextItemVersions.id,
|
|
225
|
+
schema.contextEdges.toItemVersionId,
|
|
226
|
+
),
|
|
227
|
+
eq(schema.contextItemVersions.itemId, schema.contextEdges.toItemId),
|
|
228
|
+
),
|
|
229
|
+
)
|
|
230
|
+
.where(
|
|
231
|
+
and(
|
|
232
|
+
inArray(schema.contextEdges.fromItemVersionId, frontier),
|
|
233
|
+
eq(schema.contextEdges.relation, "contains-native-child"),
|
|
234
|
+
),
|
|
235
|
+
)
|
|
236
|
+
.orderBy(
|
|
237
|
+
asc(schema.contextEdges.fromItemVersionId),
|
|
238
|
+
asc(schema.contextEdges.toExternalId),
|
|
239
|
+
);
|
|
240
|
+
const next: string[] = [];
|
|
241
|
+
for (const edge of edges as Array<{
|
|
242
|
+
fromItemVersionId: string;
|
|
243
|
+
toItemId: string | null;
|
|
244
|
+
toItemVersionId: string | null;
|
|
245
|
+
toExternalId: string | null;
|
|
246
|
+
childSourceId: string | null;
|
|
247
|
+
childVersionId: string | null;
|
|
248
|
+
}>) {
|
|
249
|
+
if (
|
|
250
|
+
!edge.toItemId ||
|
|
251
|
+
!edge.toItemVersionId ||
|
|
252
|
+
!edge.childSourceId ||
|
|
253
|
+
!edge.childVersionId
|
|
254
|
+
) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
`Native artifact child ${edge.toExternalId ?? "(unknown)"} has no immutable version reference`,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
const parentSourceId = sourceByVersion.get(edge.fromItemVersionId);
|
|
260
|
+
if (!parentSourceId || parentSourceId !== edge.childSourceId) {
|
|
261
|
+
throw new Error(
|
|
262
|
+
"Native artifact dependencies must stay within the pinned source snapshot",
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
const existing = byItemId.get(edge.toItemId);
|
|
266
|
+
if (existing) {
|
|
267
|
+
if (existing.itemVersionId !== edge.toItemVersionId) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
"A native artifact dependency conflicts with an explicitly pinned item version",
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
dependencyCount += 1;
|
|
275
|
+
if (dependencyCount > MAX_NATIVE_PACK_DEPENDENCIES) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
"Native artifact pack dependencies exceed the safe limit",
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
const dependency: ResolvedPackMember = {
|
|
281
|
+
itemId: edge.toItemId,
|
|
282
|
+
itemVersionId: edge.toItemVersionId,
|
|
283
|
+
reason: "Native artifact dependency",
|
|
284
|
+
};
|
|
285
|
+
members.push(dependency);
|
|
286
|
+
byItemId.set(dependency.itemId, dependency);
|
|
287
|
+
sourceByVersion.set(dependency.itemVersionId, edge.childSourceId);
|
|
288
|
+
next.push(dependency.itemVersionId);
|
|
289
|
+
}
|
|
290
|
+
frontier = [...new Set(next)];
|
|
291
|
+
}
|
|
292
|
+
return members;
|
|
293
|
+
}
|
|
294
|
+
|
|
133
295
|
export async function createContextPack(input: {
|
|
134
296
|
name: string;
|
|
135
297
|
description?: string | null;
|
|
136
298
|
derivedFromPackId?: string;
|
|
137
299
|
brandDnaVersionId?: string | null;
|
|
138
300
|
contextMode?: string;
|
|
301
|
+
baseContextId?: string | null;
|
|
302
|
+
specialtyContextId?: string | null;
|
|
303
|
+
selectionReason?: string | null;
|
|
139
304
|
request?: Record<string, unknown>;
|
|
140
305
|
members: ContextPackMemberInput[];
|
|
141
306
|
pinned?: boolean;
|
|
@@ -144,10 +309,12 @@ export async function createContextPack(input: {
|
|
|
144
309
|
const actor = requireActor();
|
|
145
310
|
const timestamp = nowIso();
|
|
146
311
|
const id = newId("ccp");
|
|
147
|
-
const [
|
|
312
|
+
const [explicitMembers, brandDnaVersionId] = await Promise.all([
|
|
148
313
|
resolveMembers(input.members),
|
|
149
314
|
resolveBrandDnaVersion(input.brandDnaVersionId),
|
|
150
315
|
]);
|
|
316
|
+
const resolvedMembers =
|
|
317
|
+
await includeNativeArtifactDependencies(explicitMembers);
|
|
151
318
|
if (input.derivedFromPackId) {
|
|
152
319
|
await assertAccess(
|
|
153
320
|
"creative-context-pack",
|
|
@@ -157,6 +324,18 @@ export async function createContextPack(input: {
|
|
|
157
324
|
{ skipResourceBody: true },
|
|
158
325
|
);
|
|
159
326
|
}
|
|
327
|
+
const contextAccess = input.baseContextId
|
|
328
|
+
? await resolveAccess("creative-context", input.baseContextId)
|
|
329
|
+
: null;
|
|
330
|
+
if (input.baseContextId && !contextAccess) {
|
|
331
|
+
throw new Error("Base Creative Context not found or not accessible");
|
|
332
|
+
}
|
|
333
|
+
const inheritedShares = input.baseContextId
|
|
334
|
+
? await getDb()
|
|
335
|
+
.select()
|
|
336
|
+
.from(schema.creativeContextShares)
|
|
337
|
+
.where(eq(schema.creativeContextShares.resourceId, input.baseContextId))
|
|
338
|
+
: [];
|
|
160
339
|
await getDb().transaction(async (tx: any) => {
|
|
161
340
|
await tx.insert(schema.contextPacks).values({
|
|
162
341
|
id,
|
|
@@ -165,11 +344,14 @@ export async function createContextPack(input: {
|
|
|
165
344
|
derivedFromPackId: input.derivedFromPackId ?? null,
|
|
166
345
|
brandDnaVersionId,
|
|
167
346
|
contextMode: input.contextMode ?? "manual",
|
|
347
|
+
baseContextId: input.baseContextId ?? null,
|
|
348
|
+
specialtyContextId: input.specialtyContextId ?? null,
|
|
349
|
+
selectionReason: input.selectionReason ?? null,
|
|
168
350
|
request: stringifyJson(input.request),
|
|
169
351
|
archivedAt: null,
|
|
170
352
|
ownerEmail: actor.ownerEmail,
|
|
171
353
|
orgId: actor.orgId,
|
|
172
|
-
visibility: "private",
|
|
354
|
+
visibility: contextAccess?.resource.visibility ?? "private",
|
|
173
355
|
createdAt: timestamp,
|
|
174
356
|
});
|
|
175
357
|
if (resolvedMembers.length) {
|
|
@@ -189,6 +371,19 @@ export async function createContextPack(input: {
|
|
|
189
371
|
})),
|
|
190
372
|
);
|
|
191
373
|
}
|
|
374
|
+
if (inheritedShares.length) {
|
|
375
|
+
await tx.insert(schema.contextPackShares).values(
|
|
376
|
+
(inheritedShares as any[]).map((share) => ({
|
|
377
|
+
id: newId("ccpsh"),
|
|
378
|
+
resourceId: id,
|
|
379
|
+
principalType: share.principalType,
|
|
380
|
+
principalId: share.principalId,
|
|
381
|
+
role: share.role,
|
|
382
|
+
createdBy: actor.ownerEmail,
|
|
383
|
+
createdAt: timestamp,
|
|
384
|
+
})),
|
|
385
|
+
);
|
|
386
|
+
}
|
|
192
387
|
if (input.pinned) {
|
|
193
388
|
await tx.insert(schema.contextPackPins).values({
|
|
194
389
|
id: newId("ccpp"),
|
|
@@ -241,6 +436,9 @@ export async function deriveContextPack(input: {
|
|
|
241
436
|
? base.brandDnaVersionId
|
|
242
437
|
: input.brandDnaVersionId,
|
|
243
438
|
contextMode: base.contextMode,
|
|
439
|
+
baseContextId: base.baseContextId,
|
|
440
|
+
specialtyContextId: base.specialtyContextId,
|
|
441
|
+
selectionReason: base.selectionReason,
|
|
244
442
|
request: base.request,
|
|
245
443
|
members: Array.from(members.values()),
|
|
246
444
|
pinned: input.pinned,
|
|
@@ -338,12 +536,37 @@ export async function listContextPacks(input: {
|
|
|
338
536
|
schema.contextSources,
|
|
339
537
|
eq(schema.contextSources.id, schema.contextItems.sourceId),
|
|
340
538
|
)
|
|
539
|
+
.leftJoin(
|
|
540
|
+
schema.creativeContextPublishedSnapshots,
|
|
541
|
+
and(
|
|
542
|
+
eq(
|
|
543
|
+
schema.creativeContextPublishedSnapshots.itemId,
|
|
544
|
+
schema.contextPackMembers.itemId,
|
|
545
|
+
),
|
|
546
|
+
eq(
|
|
547
|
+
schema.creativeContextPublishedSnapshots.itemVersionId,
|
|
548
|
+
schema.contextPackMembers.itemVersionId,
|
|
549
|
+
),
|
|
550
|
+
eq(
|
|
551
|
+
schema.creativeContextPublishedSnapshots.sourceId,
|
|
552
|
+
schema.contextItems.sourceId,
|
|
553
|
+
),
|
|
554
|
+
),
|
|
555
|
+
)
|
|
341
556
|
.where(
|
|
342
557
|
and(
|
|
343
558
|
inArray(schema.contextPackMembers.packId, ids),
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
559
|
+
or(
|
|
560
|
+
and(
|
|
561
|
+
accessFilter(
|
|
562
|
+
schema.contextSources,
|
|
563
|
+
schema.contextSourceShares,
|
|
564
|
+
),
|
|
565
|
+
ne(schema.contextSources.upstreamAccess, "restricted"),
|
|
566
|
+
ne(schema.contextSources.status, "archived"),
|
|
567
|
+
),
|
|
568
|
+
isNotNull(schema.creativeContextPublishedSnapshots.id),
|
|
569
|
+
),
|
|
347
570
|
eq(schema.contextItems.curationStatus, "included"),
|
|
348
571
|
ne(schema.contextItems.curationRank, "ignored"),
|
|
349
572
|
eq(schema.contextItems.status, "active"),
|
|
@@ -375,7 +598,11 @@ export async function listContextPacks(input: {
|
|
|
375
598
|
derivedFromPackId: row.derivedFromPackId ?? null,
|
|
376
599
|
brandDnaVersionId: row.brandDnaVersionId ?? null,
|
|
377
600
|
contextMode: row.contextMode,
|
|
378
|
-
|
|
601
|
+
baseContextId: row.baseContextId ?? null,
|
|
602
|
+
specialtyContextId: row.specialtyContextId ?? null,
|
|
603
|
+
selectionReason: row.selectionReason ?? null,
|
|
604
|
+
request: (sanitizePublicMetadata(parseJson(row.request, {})) ??
|
|
605
|
+
{}) as Record<string, unknown>,
|
|
379
606
|
memberCount: memberCount.get(row.id) ?? 0,
|
|
380
607
|
pinned: pinned.has(row.id),
|
|
381
608
|
archivedAt: row.archivedAt ?? null,
|
|
@@ -414,12 +641,34 @@ export async function getContextPack(
|
|
|
414
641
|
schema.contextSources,
|
|
415
642
|
eq(schema.contextSources.id, schema.contextItems.sourceId),
|
|
416
643
|
)
|
|
644
|
+
.leftJoin(
|
|
645
|
+
schema.creativeContextPublishedSnapshots,
|
|
646
|
+
and(
|
|
647
|
+
eq(
|
|
648
|
+
schema.creativeContextPublishedSnapshots.itemId,
|
|
649
|
+
schema.contextPackMembers.itemId,
|
|
650
|
+
),
|
|
651
|
+
eq(
|
|
652
|
+
schema.creativeContextPublishedSnapshots.itemVersionId,
|
|
653
|
+
schema.contextPackMembers.itemVersionId,
|
|
654
|
+
),
|
|
655
|
+
eq(
|
|
656
|
+
schema.creativeContextPublishedSnapshots.sourceId,
|
|
657
|
+
schema.contextItems.sourceId,
|
|
658
|
+
),
|
|
659
|
+
),
|
|
660
|
+
)
|
|
417
661
|
.where(
|
|
418
662
|
and(
|
|
419
663
|
eq(schema.contextPackMembers.packId, packId),
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
664
|
+
or(
|
|
665
|
+
and(
|
|
666
|
+
accessFilter(schema.contextSources, schema.contextSourceShares),
|
|
667
|
+
ne(schema.contextSources.upstreamAccess, "restricted"),
|
|
668
|
+
ne(schema.contextSources.status, "archived"),
|
|
669
|
+
),
|
|
670
|
+
isNotNull(schema.creativeContextPublishedSnapshots.id),
|
|
671
|
+
),
|
|
423
672
|
eq(schema.contextItems.curationStatus, "included"),
|
|
424
673
|
ne(schema.contextItems.curationRank, "ignored"),
|
|
425
674
|
eq(schema.contextItems.status, "active"),
|
|
@@ -446,7 +695,9 @@ export async function getContextPack(
|
|
|
446
695
|
ordinal: member.ordinal,
|
|
447
696
|
reason: member.reason ?? null,
|
|
448
697
|
score: member.score ?? null,
|
|
449
|
-
scoreMetadata:
|
|
698
|
+
scoreMetadata: (sanitizePublicMetadata(
|
|
699
|
+
parseJson(member.scoreMetadata, {}),
|
|
700
|
+
) ?? {}) as Record<string, unknown>,
|
|
450
701
|
}));
|
|
451
702
|
return {
|
|
452
703
|
id: row.id,
|
|
@@ -455,7 +706,11 @@ export async function getContextPack(
|
|
|
455
706
|
derivedFromPackId: row.derivedFromPackId ?? null,
|
|
456
707
|
brandDnaVersionId: row.brandDnaVersionId ?? null,
|
|
457
708
|
contextMode: row.contextMode,
|
|
458
|
-
|
|
709
|
+
baseContextId: row.baseContextId ?? null,
|
|
710
|
+
specialtyContextId: row.specialtyContextId ?? null,
|
|
711
|
+
selectionReason: row.selectionReason ?? null,
|
|
712
|
+
request: (sanitizePublicMetadata(parseJson(row.request, {})) ??
|
|
713
|
+
{}) as Record<string, unknown>,
|
|
459
714
|
memberCount: members.length,
|
|
460
715
|
pinned: Boolean(pinRows[0]),
|
|
461
716
|
archivedAt: row.archivedAt ?? null,
|
package/src/store/purge.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
sharedResourceOwner,
|
|
6
6
|
} from "@agent-native/core/resources/store";
|
|
7
7
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
8
|
-
import { and, eq, inArray, or } from "drizzle-orm";
|
|
8
|
+
import { and, eq, inArray, like, or } from "drizzle-orm";
|
|
9
9
|
|
|
10
10
|
import { parsePrivateBlobHandle } from "../connectors/private-artifacts.js";
|
|
11
11
|
import { deletePostgresFtsDocuments } from "../search/postgres-fts.js";
|
|
@@ -29,12 +29,75 @@ export async function purgeContextSourceArtifacts(sourceId: string) {
|
|
|
29
29
|
.limit(1);
|
|
30
30
|
const source = sourceRows[0];
|
|
31
31
|
if (!source) throw new Error("Creative context source not found");
|
|
32
|
-
const
|
|
32
|
+
const originalItems = await getDb()
|
|
33
33
|
.select({ id: schema.contextItems.id })
|
|
34
34
|
.from(schema.contextItems)
|
|
35
35
|
.where(eq(schema.contextItems.sourceId, sourceId));
|
|
36
|
+
const derivedSubmissions = await getDb()
|
|
37
|
+
.select({
|
|
38
|
+
id: schema.creativeContextSubmissions.id,
|
|
39
|
+
membershipId: schema.creativeContextSubmissions.membershipId,
|
|
40
|
+
stagingItemId: schema.creativeContextSubmissions.stagingItemId,
|
|
41
|
+
publishedItemId: schema.creativeContextSubmissions.publishedItemId,
|
|
42
|
+
privateMetadata: schema.creativeContextSubmissions.privateMetadata,
|
|
43
|
+
})
|
|
44
|
+
.from(schema.creativeContextSubmissions)
|
|
45
|
+
.where(
|
|
46
|
+
like(schema.creativeContextSubmissions.artifactKey, `${sourceId}:%`),
|
|
47
|
+
);
|
|
48
|
+
const derivedSubmissionIds = derivedSubmissions.map((row: any) =>
|
|
49
|
+
String(row.id),
|
|
50
|
+
);
|
|
51
|
+
const publishedCopies = derivedSubmissionIds.length
|
|
52
|
+
? await getDb()
|
|
53
|
+
.select({ itemId: schema.creativeContextPublishedSnapshots.itemId })
|
|
54
|
+
.from(schema.creativeContextPublishedSnapshots)
|
|
55
|
+
.where(
|
|
56
|
+
inArray(
|
|
57
|
+
schema.creativeContextPublishedSnapshots.submissionId,
|
|
58
|
+
derivedSubmissionIds,
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
: [];
|
|
62
|
+
const stagedChildIds = derivedSubmissions.flatMap((row: any) => {
|
|
63
|
+
const metadata = parseJson<Record<string, unknown>>(
|
|
64
|
+
row.privateMetadata,
|
|
65
|
+
{},
|
|
66
|
+
);
|
|
67
|
+
return Array.isArray(metadata.stagedChildren)
|
|
68
|
+
? metadata.stagedChildren.flatMap((child) =>
|
|
69
|
+
child &&
|
|
70
|
+
typeof child === "object" &&
|
|
71
|
+
typeof (child as { itemId?: unknown }).itemId === "string"
|
|
72
|
+
? [(child as { itemId: string }).itemId]
|
|
73
|
+
: [],
|
|
74
|
+
)
|
|
75
|
+
: [];
|
|
76
|
+
});
|
|
77
|
+
const candidateItemIds = [
|
|
78
|
+
...originalItems.map((item: any) => String(item.id)),
|
|
79
|
+
...derivedSubmissions.flatMap((row: any) =>
|
|
80
|
+
[row.stagingItemId, row.publishedItemId].filter(
|
|
81
|
+
(value): value is string => typeof value === "string",
|
|
82
|
+
),
|
|
83
|
+
),
|
|
84
|
+
...publishedCopies.map((row: any) => String(row.itemId)),
|
|
85
|
+
...stagedChildIds,
|
|
86
|
+
];
|
|
87
|
+
const items = candidateItemIds.length
|
|
88
|
+
? await getDb()
|
|
89
|
+
.select({
|
|
90
|
+
id: schema.contextItems.id,
|
|
91
|
+
sourceId: schema.contextItems.sourceId,
|
|
92
|
+
})
|
|
93
|
+
.from(schema.contextItems)
|
|
94
|
+
.where(inArray(schema.contextItems.id, [...new Set(candidateItemIds)]))
|
|
95
|
+
: [];
|
|
36
96
|
const itemIds = items.map((item: any) => item.id as string);
|
|
37
97
|
if (!itemIds.length) return { sourceId, purgedItems: 0, purgedBlobs: 0 };
|
|
98
|
+
const affectedSourceIds = [
|
|
99
|
+
...new Set([sourceId, ...items.map((item: any) => String(item.sourceId))]),
|
|
100
|
+
];
|
|
38
101
|
const versions = await getDb()
|
|
39
102
|
.select({
|
|
40
103
|
id: schema.contextItemVersions.id,
|
|
@@ -43,6 +106,16 @@ export async function purgeContextSourceArtifacts(sourceId: string) {
|
|
|
43
106
|
.from(schema.contextItemVersions)
|
|
44
107
|
.where(inArray(schema.contextItemVersions.itemId, itemIds));
|
|
45
108
|
const versionIds = versions.map((version: any) => version.id as string);
|
|
109
|
+
const referencedMemberships = await getDb()
|
|
110
|
+
.select({ id: schema.creativeContextMemberships.id })
|
|
111
|
+
.from(schema.creativeContextMemberships)
|
|
112
|
+
.where(inArray(schema.creativeContextMemberships.publishedItemId, itemIds));
|
|
113
|
+
const affectedMembershipIds = [
|
|
114
|
+
...new Set([
|
|
115
|
+
...referencedMemberships.map((row: any) => String(row.id)),
|
|
116
|
+
...derivedSubmissions.map((row: any) => String(row.membershipId)),
|
|
117
|
+
]),
|
|
118
|
+
];
|
|
46
119
|
const [
|
|
47
120
|
chunks,
|
|
48
121
|
media,
|
|
@@ -140,10 +213,24 @@ export async function purgeContextSourceArtifacts(sourceId: string) {
|
|
|
140
213
|
for (const layout of promotedLayouts) {
|
|
141
214
|
await projections?.layoutTemplate?.demote(layout);
|
|
142
215
|
}
|
|
216
|
+
const cloneBlobRefs = derivedSubmissions.flatMap((row: any) => {
|
|
217
|
+
const metadata = parseJson<Record<string, unknown>>(
|
|
218
|
+
row.privateMetadata,
|
|
219
|
+
{},
|
|
220
|
+
);
|
|
221
|
+
const clone =
|
|
222
|
+
metadata.clone &&
|
|
223
|
+
typeof metadata.clone === "object" &&
|
|
224
|
+
!Array.isArray(metadata.clone)
|
|
225
|
+
? (metadata.clone as Record<string, unknown>)
|
|
226
|
+
: null;
|
|
227
|
+
return clone?.handle ? [clone.handle] : [];
|
|
228
|
+
});
|
|
143
229
|
let purgedBlobs = 0;
|
|
144
230
|
for (const reference of [
|
|
145
231
|
...versions.map((version: any) => version.rawSnapshotBlobRef),
|
|
146
232
|
...media.map((entry: any) => entry.storageKey),
|
|
233
|
+
...cloneBlobRefs,
|
|
147
234
|
]) {
|
|
148
235
|
const handle = parsePrivateBlobHandle(reference);
|
|
149
236
|
if (!handle) continue;
|
|
@@ -161,6 +248,40 @@ export async function purgeContextSourceArtifacts(sourceId: string) {
|
|
|
161
248
|
chunks.map((chunk: any) => chunk.id),
|
|
162
249
|
).catch(() => 0);
|
|
163
250
|
await getDb().transaction(async (tx: any) => {
|
|
251
|
+
if (affectedMembershipIds.length) {
|
|
252
|
+
await tx
|
|
253
|
+
.update(schema.creativeContextMemberships)
|
|
254
|
+
.set({
|
|
255
|
+
publishedItemId: null,
|
|
256
|
+
publishedItemVersionId: null,
|
|
257
|
+
pendingSubmissionId: null,
|
|
258
|
+
status: "removed",
|
|
259
|
+
updatedAt: nowIso(),
|
|
260
|
+
})
|
|
261
|
+
.where(
|
|
262
|
+
inArray(schema.creativeContextMemberships.id, affectedMembershipIds),
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
await tx
|
|
266
|
+
.delete(schema.creativeContextPublishedSnapshots)
|
|
267
|
+
.where(
|
|
268
|
+
derivedSubmissionIds.length
|
|
269
|
+
? or(
|
|
270
|
+
inArray(schema.creativeContextPublishedSnapshots.itemId, itemIds),
|
|
271
|
+
inArray(
|
|
272
|
+
schema.creativeContextPublishedSnapshots.submissionId,
|
|
273
|
+
derivedSubmissionIds,
|
|
274
|
+
),
|
|
275
|
+
)
|
|
276
|
+
: inArray(schema.creativeContextPublishedSnapshots.itemId, itemIds),
|
|
277
|
+
);
|
|
278
|
+
if (derivedSubmissionIds.length) {
|
|
279
|
+
await tx
|
|
280
|
+
.delete(schema.creativeContextSubmissions)
|
|
281
|
+
.where(
|
|
282
|
+
inArray(schema.creativeContextSubmissions.id, derivedSubmissionIds),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
164
285
|
if (derivedEdges.length) {
|
|
165
286
|
await tx
|
|
166
287
|
.update(schema.contextItems)
|
|
@@ -266,11 +387,23 @@ export async function purgeContextSourceArtifacts(sourceId: string) {
|
|
|
266
387
|
await tx
|
|
267
388
|
.delete(schema.contextItems)
|
|
268
389
|
.where(inArray(schema.contextItems.id, itemIds));
|
|
269
|
-
await tx
|
|
270
|
-
.update(schema.contextSources)
|
|
271
|
-
.set({ itemCount: 0, restrictedItemCount: 0, updatedAt: nowIso() })
|
|
272
|
-
.where(eq(schema.contextSources.id, sourceId));
|
|
273
390
|
});
|
|
391
|
+
for (const affectedSourceId of affectedSourceIds) {
|
|
392
|
+
const remaining = await getDb()
|
|
393
|
+
.select({ upstreamAccess: schema.contextItems.upstreamAccess })
|
|
394
|
+
.from(schema.contextItems)
|
|
395
|
+
.where(eq(schema.contextItems.sourceId, affectedSourceId));
|
|
396
|
+
await getDb()
|
|
397
|
+
.update(schema.contextSources)
|
|
398
|
+
.set({
|
|
399
|
+
itemCount: remaining.length,
|
|
400
|
+
restrictedItemCount: remaining.filter(
|
|
401
|
+
(item: any) => item.upstreamAccess !== "available",
|
|
402
|
+
).length,
|
|
403
|
+
updatedAt: nowIso(),
|
|
404
|
+
})
|
|
405
|
+
.where(eq(schema.contextSources.id, affectedSourceId));
|
|
406
|
+
}
|
|
274
407
|
const profileIds = [
|
|
275
408
|
...new Set(affectedProfiles.map((row: any) => row.profileId as string)),
|
|
276
409
|
];
|
package/src/store/sources.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { currentRequestUserIsOrgAdmin } from "@agent-native/core/server";
|
|
2
2
|
import {
|
|
3
3
|
accessFilter,
|
|
4
4
|
assertAccess,
|
|
@@ -580,22 +580,6 @@ export async function contextSourceBoundary(input: {
|
|
|
580
580
|
};
|
|
581
581
|
}
|
|
582
582
|
|
|
583
|
-
async function currentUserIsOrgAdmin(
|
|
584
|
-
orgId: string,
|
|
585
|
-
ownerEmail: string,
|
|
586
|
-
): Promise<boolean> {
|
|
587
|
-
try {
|
|
588
|
-
const result = await getDbExec().execute({
|
|
589
|
-
sql: "SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1",
|
|
590
|
-
args: [orgId, ownerEmail.toLowerCase()],
|
|
591
|
-
});
|
|
592
|
-
const role = String(result.rows[0]?.role ?? "").toLowerCase();
|
|
593
|
-
return role === "owner" || role === "admin";
|
|
594
|
-
} catch {
|
|
595
|
-
return false;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
|
|
599
583
|
export async function previewContextSourcePromotion(
|
|
600
584
|
sourceId: string,
|
|
601
585
|
): Promise<ContextSourcePromotionPreview> {
|
|
@@ -608,7 +592,7 @@ export async function previewContextSourcePromotion(
|
|
|
608
592
|
if (!actor.orgId) {
|
|
609
593
|
throw new Error("Select an organization before promoting a context source");
|
|
610
594
|
}
|
|
611
|
-
const orgAdmin = await
|
|
595
|
+
const orgAdmin = await currentRequestUserIsOrgAdmin(actor.orgId);
|
|
612
596
|
const verifiedOwner =
|
|
613
597
|
access.role === "owner" &&
|
|
614
598
|
Boolean(access.resource.containerOwnerVerifiedAt);
|
package/src/store/suggestions.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { assertContextItemSqlTextLimits } from "../connectors/normalize.js";
|
|
|
5
5
|
import { reassembleNativeCreativeArtifact } from "../native-artifact-reassembly.js";
|
|
6
6
|
import { nativeCreativeArtifactFromMetadata } from "../native-artifact.js";
|
|
7
7
|
import { getCreativeContext } from "../server/context.js";
|
|
8
|
+
import { sanitizePublicMetadata } from "../server/public-serialization.js";
|
|
8
9
|
import type { CreativeContextSuggestion } from "../types.js";
|
|
9
10
|
import {
|
|
10
11
|
getCreativeContextItem,
|
|
@@ -30,7 +31,8 @@ function mapSuggestion(row: any): CreativeContextSuggestion {
|
|
|
30
31
|
itemId: row.itemId,
|
|
31
32
|
itemVersionId: row.itemVersionId,
|
|
32
33
|
reason: row.reason ?? null,
|
|
33
|
-
payload: parseJson(row.payload, {})
|
|
34
|
+
payload: (sanitizePublicMetadata(parseJson(row.payload, {})) ??
|
|
35
|
+
{}) as Record<string, unknown>,
|
|
34
36
|
createdAt: row.createdAt,
|
|
35
37
|
updatedAt: row.updatedAt,
|
|
36
38
|
};
|