@vgai/sdk 0.4.0 → 0.4.1-canary.20260715.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/package.json +2 -2
- package/src/project/index.ts +1 -0
- package/src/project/provenance.ts +154 -0
- package/src/types.ts +24 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/sdk",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.4.0",
|
|
5
|
+
"version": "0.4.1-canary.20260715.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"./registry": "./src/registry.ts"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@vgai/engine": "0.4.0",
|
|
23
|
+
"@vgai/engine": "0.4.1-canary.20260715.0",
|
|
24
24
|
"playwright": "^1.58.2",
|
|
25
25
|
"zod": "^4.3.6"
|
|
26
26
|
}
|
package/src/project/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from './discovery-operations.js';
|
|
|
13
13
|
export * from './entity-operations.js';
|
|
14
14
|
export * from './input-map-operations.js';
|
|
15
15
|
export * from './manifest-operations.js';
|
|
16
|
+
export * from './provenance.js';
|
|
16
17
|
export * from './scene-operations.js';
|
|
17
18
|
export {
|
|
18
19
|
BaseHashField,
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const PROJECT_PROVENANCE_PATH = '.vgai/provenance.json';
|
|
4
|
+
|
|
5
|
+
export const ProjectProvenanceOutputSchema = z.object({
|
|
6
|
+
path: z.string(),
|
|
7
|
+
bytes: z.number().int().nonnegative(),
|
|
8
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
9
|
+
mediaType: z.string().optional(),
|
|
10
|
+
role: z.enum(['asset', 'prefab', 'provenance', 'other']).optional(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const ProjectProvenanceExecutionSchema = z.object({
|
|
14
|
+
mode: z.enum(['mock', 'direct', 'managed']),
|
|
15
|
+
provider: z.string(),
|
|
16
|
+
operation: z.string().optional(),
|
|
17
|
+
model: z.string().optional(),
|
|
18
|
+
requestId: z.string().optional(),
|
|
19
|
+
taskId: z.string().optional(),
|
|
20
|
+
managedJobId: z.string().optional(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const ProjectProvenanceOperationSchema = z.object({
|
|
24
|
+
createdAt: z.string().datetime(),
|
|
25
|
+
operation: z.object({
|
|
26
|
+
name: z.string(),
|
|
27
|
+
source: z.string().optional(),
|
|
28
|
+
}),
|
|
29
|
+
execution: ProjectProvenanceExecutionSchema.optional(),
|
|
30
|
+
executions: z.array(ProjectProvenanceExecutionSchema).min(2).optional(),
|
|
31
|
+
input: z.json().optional(),
|
|
32
|
+
outputs: z.array(ProjectProvenanceOutputSchema).min(1),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const ProjectProvenanceDocumentSchema = z.object({
|
|
36
|
+
version: z.literal(1),
|
|
37
|
+
operations: z.record(z.string(), ProjectProvenanceOperationSchema),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export type ProjectProvenanceDocument = z.infer<typeof ProjectProvenanceDocumentSchema>;
|
|
41
|
+
export type ProjectProvenanceOperation = z.infer<typeof ProjectProvenanceOperationSchema>;
|
|
42
|
+
export type ProjectProvenanceExecution = z.infer<typeof ProjectProvenanceExecutionSchema>;
|
|
43
|
+
|
|
44
|
+
export const ProjectAttributionEntrySchema = z.object({
|
|
45
|
+
key: z.string(),
|
|
46
|
+
name: z.string().optional(),
|
|
47
|
+
source: z.string().optional(),
|
|
48
|
+
sourceUrl: z.string().url().optional(),
|
|
49
|
+
author: z.string(),
|
|
50
|
+
license: z.string(),
|
|
51
|
+
text: z.string(),
|
|
52
|
+
operationIds: z.array(z.string()),
|
|
53
|
+
outputPaths: z.array(z.string()),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const ProjectAttributionReportSchema = z.object({
|
|
57
|
+
version: z.literal(1),
|
|
58
|
+
entries: z.array(ProjectAttributionEntrySchema),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
export type ProjectAttributionEntry = z.infer<typeof ProjectAttributionEntrySchema>;
|
|
62
|
+
export type ProjectAttributionReport = z.infer<typeof ProjectAttributionReportSchema>;
|
|
63
|
+
|
|
64
|
+
export function emptyProjectProvenanceDocument(): ProjectProvenanceDocument {
|
|
65
|
+
return { version: 1, operations: {} };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function objectRecord(value: unknown): Record<string, unknown> | null {
|
|
69
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
70
|
+
? (value as Record<string, unknown>)
|
|
71
|
+
: null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function stringField(record: Record<string, unknown>, key: string): string | undefined {
|
|
75
|
+
const value = record[key];
|
|
76
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function attributionEntry(
|
|
80
|
+
operationId: string,
|
|
81
|
+
operation: ProjectProvenanceOperation,
|
|
82
|
+
): ProjectAttributionEntry | null {
|
|
83
|
+
const input = objectRecord(operation.input);
|
|
84
|
+
if (!input) return null;
|
|
85
|
+
const nested = objectRecord(input['attribution']) ?? {};
|
|
86
|
+
const author = stringField(nested, 'author') ?? stringField(input, 'author');
|
|
87
|
+
const license = stringField(nested, 'license') ?? stringField(input, 'license');
|
|
88
|
+
if (!author || !license) return null;
|
|
89
|
+
const name = stringField(nested, 'name') ?? stringField(input, 'name');
|
|
90
|
+
const source = stringField(nested, 'source') ?? stringField(input, 'source');
|
|
91
|
+
const sourceUrl = stringField(nested, 'sourceUrl') ?? stringField(input, 'sourceUrl');
|
|
92
|
+
const text = stringField(nested, 'text') ?? `${name ? `${name} by ` : ''}${author} (${license})`;
|
|
93
|
+
const key = JSON.stringify([sourceUrl ?? '', author, license, text]);
|
|
94
|
+
return ProjectAttributionEntrySchema.parse({
|
|
95
|
+
key,
|
|
96
|
+
...(name ? { name } : {}),
|
|
97
|
+
...(source ? { source } : {}),
|
|
98
|
+
...(sourceUrl ? { sourceUrl } : {}),
|
|
99
|
+
author,
|
|
100
|
+
license,
|
|
101
|
+
text,
|
|
102
|
+
operationIds: [operationId],
|
|
103
|
+
outputPaths: operation.outputs
|
|
104
|
+
.filter((output) => output.role !== 'provenance')
|
|
105
|
+
.map((output) => output.path),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Project credits are a projection of central provenance, never another
|
|
111
|
+
* persisted ledger or a set of per-asset files.
|
|
112
|
+
*/
|
|
113
|
+
export function deriveProjectAttributionReport(
|
|
114
|
+
document: ProjectProvenanceDocument,
|
|
115
|
+
): ProjectAttributionReport {
|
|
116
|
+
const grouped = new Map<string, ProjectAttributionEntry>();
|
|
117
|
+
for (const [operationId, operation] of Object.entries(document.operations)) {
|
|
118
|
+
const entry = attributionEntry(operationId, operation);
|
|
119
|
+
if (!entry) continue;
|
|
120
|
+
const prior = grouped.get(entry.key);
|
|
121
|
+
if (!prior) {
|
|
122
|
+
grouped.set(entry.key, entry);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
prior.operationIds.push(...entry.operationIds);
|
|
126
|
+
prior.outputPaths.push(...entry.outputPaths);
|
|
127
|
+
}
|
|
128
|
+
const entries = [...grouped.values()]
|
|
129
|
+
.map((entry) => ({
|
|
130
|
+
...entry,
|
|
131
|
+
operationIds: [...new Set(entry.operationIds)].sort(),
|
|
132
|
+
outputPaths: [...new Set(entry.outputPaths)].sort(),
|
|
133
|
+
}))
|
|
134
|
+
.sort(
|
|
135
|
+
(left, right) => left.text.localeCompare(right.text) || left.key.localeCompare(right.key),
|
|
136
|
+
);
|
|
137
|
+
return ProjectAttributionReportSchema.parse({ version: 1, entries });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Deterministic human-readable projection of the machine report. */
|
|
141
|
+
export function formatProjectAttributionMarkdown(report: ProjectAttributionReport): string {
|
|
142
|
+
const sections = report.entries.map((entry) => {
|
|
143
|
+
const heading = entry.name ?? entry.text;
|
|
144
|
+
return [
|
|
145
|
+
`## ${heading}`,
|
|
146
|
+
'',
|
|
147
|
+
entry.text,
|
|
148
|
+
'',
|
|
149
|
+
`Author: ${entry.author} `,
|
|
150
|
+
`License: ${entry.license}${entry.sourceUrl ? ` \nSource: ${entry.sourceUrl}` : ''}`,
|
|
151
|
+
].join('\n');
|
|
152
|
+
});
|
|
153
|
+
return `# Asset attribution\n${sections.length > 0 ? `\n${sections.join('\n\n')}` : '\nNo attributed project assets are currently present.'}\n`;
|
|
154
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -68,6 +68,30 @@ export interface ProjectGeneratedOutput {
|
|
|
68
68
|
files: ProjectGeneratedOutputFile[];
|
|
69
69
|
totalBytes: number;
|
|
70
70
|
dryRun: boolean;
|
|
71
|
+
/** Host-created logical record in .vgai/provenance.json; absent for dry runs. */
|
|
72
|
+
provenanceOperationId?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ProjectProviderExecution {
|
|
76
|
+
mode: 'mock' | 'direct' | 'managed';
|
|
77
|
+
provider: string;
|
|
78
|
+
operation?: string;
|
|
79
|
+
model?: string;
|
|
80
|
+
requestId?: string;
|
|
81
|
+
taskId?: string;
|
|
82
|
+
managedJobId?: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Facts the operation host already owns and stamps onto every committed batch. */
|
|
86
|
+
export interface ProjectOutputProvenanceContext {
|
|
87
|
+
operationName: string;
|
|
88
|
+
operationSource?: string;
|
|
89
|
+
/** Sanitized facts for a single provider execution. */
|
|
90
|
+
execution?: ProjectProviderExecution;
|
|
91
|
+
/** Ordered facts for a native multi-task pipeline that produced one output batch. */
|
|
92
|
+
executions?: readonly ProjectProviderExecution[];
|
|
93
|
+
/** Schema-validated, JSON-safe operation input. */
|
|
94
|
+
input?: unknown;
|
|
71
95
|
}
|
|
72
96
|
|
|
73
97
|
/**
|