@womp/spark-agent 6.5.0 → 8.0.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/CHANGELOG.md +86 -0
- package/README.md +7 -4
- package/dist/agent.d.ts +3 -6
- package/dist/agent.js +41 -23
- package/dist/capabilities/geometry.d.ts +17 -5
- package/dist/capabilities/geometry.js +11 -12
- package/dist/compaction.d.ts +41 -8
- package/dist/compaction.js +241 -77
- package/dist/context-window.d.ts +23 -0
- package/dist/context-window.js +141 -0
- package/dist/generated/geometry-declarations.d.ts +1 -1
- package/dist/generated/geometry-declarations.js +1 -1
- package/dist/geometry/backendRegistry.d.ts +1 -0
- package/dist/geometry/common.d.ts +5 -2
- package/dist/geometry/common.js +18 -3
- package/dist/geometry/compiler.js +2 -2
- package/dist/geometry/diagnostics.d.ts +2 -7
- package/dist/geometry/diagnostics.js +3 -51
- package/dist/geometry/graph.d.ts +1 -1
- package/dist/geometry/graph.js +1 -0
- package/dist/geometry/index.d.ts +0 -1
- package/dist/geometry/index.js +0 -3
- package/dist/geometry/lift.js +105 -113
- package/dist/geometry/lower.js +29 -49
- package/dist/geometry/schemas/flowir-dialect.json +117 -117
- package/dist/geometry/writeParamData.js +4 -4
- package/dist/geometry.d.ts +2 -5
- package/dist/geometry.js +7 -11
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/intent-bench.js +1 -1
- package/dist/sdk-geometry-host.d.ts +1 -1
- package/dist/sdk-geometry-host.js +253 -251
- package/dist/ui.d.ts +7 -0
- package/dist/ui.js +1 -0
- package/dist/womp-scene-api.d.ts +9 -1
- package/dist/womp-scene-api.js +41 -32
- package/package.json +2 -2
- package/dist/context-budget.d.ts +0 -65
- package/dist/context-budget.js +0 -364
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { runSparkAgent, } from "./agent.js";
|
|
2
2
|
export { createSparkTools } from "./agent-tools.js";
|
|
3
3
|
export { convertSparkMessages } from "./model-history.js";
|
|
4
|
-
export
|
|
4
|
+
export { applyCompaction, latestCompaction } from "./compaction.js";
|
|
5
|
+
export * from "./context-window.js";
|
|
5
6
|
export * from "./capabilities.js";
|
|
6
7
|
export { createSdkSceneEditor, createSdkSceneHost, } from "./sdk-scene-host.js";
|
|
7
8
|
export { recoverSceneOperation } from "./scene-operations.js";
|
package/dist/intent-bench.js
CHANGED
|
@@ -342,7 +342,7 @@ async function intentFixtures(testCase, controller) {
|
|
|
342
342
|
if (objectId !== 0)
|
|
343
343
|
return refuse("geometry.read", `Object ${objectId} has no Geometry Nodes graph.`);
|
|
344
344
|
note("geometry.read");
|
|
345
|
-
return { kind: "container", objectId: 0, title: "Scene", source: null, instances: [], diagnostics: [] };
|
|
345
|
+
return { kind: "container", objectId: 0, title: "Scene", source: null, transform: null, bounds: null, instances: [], diagnostics: [] };
|
|
346
346
|
},
|
|
347
347
|
write: async (options) => decide("geometry-nodes", "geometry.write", options),
|
|
348
348
|
}, geometryReference()),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SdkSceneEditor } from "./sdk-scene-host.js";
|
|
2
1
|
import type { GeometryHost } from "./capabilities.js";
|
|
2
|
+
import { type SdkSceneEditor } from "./sdk-scene-host.js";
|
|
3
3
|
import { readSdkSceneHealth } from "./scene-health.js";
|
|
4
4
|
import { type RepairStateStore } from "./repair-state.js";
|
|
5
5
|
export type SdkGeometryHostOptions = {
|
|
@@ -1,293 +1,295 @@
|
|
|
1
|
+
import { KakapoError, } from "@womp/kakapo-sdk";
|
|
1
2
|
import { SceneOperationError } from "./sdk-scene-host.js";
|
|
2
|
-
import { compileGeometry, migrateGraphExt, readEditableGeometry
|
|
3
|
-
import { graphExtSchema } from "./geometry/graph.js";
|
|
3
|
+
import { compileGeometry, migrateGraphExt, readEditableGeometry } from "./geometry/compiler.js";
|
|
4
4
|
import { boundedDiagnostics } from "./geometry/diagnostics.js";
|
|
5
|
-
import {
|
|
5
|
+
import { graphExtSchema } from "./geometry/graph.js";
|
|
6
|
+
import { migrateParameterOverrides, readParameterOverrides } from "./geometry/parameters.js";
|
|
7
|
+
import { convertAABB, sceneNodePosition, sceneNodeRotation, sceneNodeSize } from "./womp-scene-api.js";
|
|
8
|
+
import { sceneUnitMultiplier } from "./coordinates.js";
|
|
6
9
|
import { unverifiedSceneHealth } from "./scene-health.js";
|
|
7
|
-
import { createGeometryRepairTracker
|
|
10
|
+
import { createGeometryRepairTracker } from "./repair-state.js";
|
|
11
|
+
const MEMORY_LIMIT = "Scene memory limits prevent applying this graph.";
|
|
8
12
|
function errorMessage(error) {
|
|
9
13
|
return error instanceof Error ? error.message : String(error);
|
|
10
14
|
}
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
11
18
|
function unusedId(entries) {
|
|
12
19
|
let id = 0;
|
|
13
20
|
while (id in entries)
|
|
14
21
|
id++;
|
|
15
22
|
return id;
|
|
16
23
|
}
|
|
17
|
-
function
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
return { graphs: {}, instances: {} };
|
|
21
|
-
const value = scripts;
|
|
24
|
+
function readScripts(scene) {
|
|
25
|
+
const stored = scene.getSceneStorage().scripts;
|
|
26
|
+
const scripts = isRecord(stored) ? stored : {};
|
|
22
27
|
return {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
instances: value.instances && typeof value.instances === "object"
|
|
27
|
-
? value.instances
|
|
28
|
-
: {},
|
|
28
|
+
...scripts,
|
|
29
|
+
graphs: isRecord(scripts.graphs) ? scripts.graphs : {},
|
|
30
|
+
instances: isRecord(scripts.instances) ? scripts.instances : {},
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
function readGraphExts(scene) {
|
|
34
|
+
const graphExts = scene.getSceneExt(["graphsExt"]).graphsExt;
|
|
35
|
+
return isRecord(graphExts) ? graphExts : {};
|
|
36
|
+
}
|
|
37
|
+
function graphExtOf(graphExts, graphId) {
|
|
38
|
+
return graphExtSchema.parse(graphExts[graphId] ?? {});
|
|
36
39
|
}
|
|
37
|
-
function
|
|
38
|
-
|
|
40
|
+
function graphInstances(scripts, graphId) {
|
|
41
|
+
return Object.entries(scripts.instances).filter(([, instance]) => instance.graph_id === graphId);
|
|
42
|
+
}
|
|
43
|
+
function objectIdsByInstance(scene) {
|
|
44
|
+
const objectIds = new Map();
|
|
45
|
+
for (const node of scene.listNodes({ kind: "union" })) {
|
|
46
|
+
if (node.kind !== "union" || node.scriptInstanceId === undefined)
|
|
47
|
+
continue;
|
|
48
|
+
const ids = objectIds.get(node.scriptInstanceId);
|
|
49
|
+
if (ids)
|
|
50
|
+
ids.push(node.id);
|
|
51
|
+
else
|
|
52
|
+
objectIds.set(node.scriptInstanceId, [node.id]);
|
|
53
|
+
}
|
|
54
|
+
return objectIds;
|
|
55
|
+
}
|
|
56
|
+
function resolveTarget(scene, objectId) {
|
|
57
|
+
const node = scene.getNode(objectId);
|
|
39
58
|
if (objectId !== 0 && node.kind !== "union" && node.kind !== "group")
|
|
40
59
|
throw new Error("Geometry Nodes requires an Area, Group, or scene root target.");
|
|
60
|
+
const scripts = readScripts(scene);
|
|
41
61
|
const instanceId = node.kind === "union" ? node.scriptInstanceId : undefined;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
62
|
+
if (instanceId === undefined)
|
|
63
|
+
return { node, scripts };
|
|
64
|
+
const instance = scripts.instances[instanceId];
|
|
65
|
+
if (!instance)
|
|
45
66
|
throw new Error("The target's Geometry Nodes instance is missing. Inspect it before editing.");
|
|
46
|
-
const graphId = instance
|
|
47
|
-
const graph =
|
|
48
|
-
if (
|
|
67
|
+
const graphId = instance.graph_id;
|
|
68
|
+
const graph = scripts.graphs[graphId];
|
|
69
|
+
if (graph === undefined || !Number.isInteger(graphId))
|
|
49
70
|
throw new Error("The target's Geometry Nodes graph is missing. Inspect it before editing.");
|
|
50
|
-
return { node,
|
|
71
|
+
return { node, scripts, graphId, instanceId, graph };
|
|
51
72
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
objectId,
|
|
56
|
-
title: target.node.name,
|
|
57
|
-
graphId: target.graphId,
|
|
58
|
-
instanceId: target.instanceId,
|
|
59
|
-
source: null,
|
|
60
|
-
instances: [],
|
|
61
|
-
diagnostics: [],
|
|
62
|
-
};
|
|
63
|
-
if (target.graphId === undefined || target.graph === undefined)
|
|
64
|
-
return result;
|
|
73
|
+
function describeGraph(api, target) {
|
|
74
|
+
if (target.graph === undefined)
|
|
75
|
+
return { source: null, instances: [], diagnostics: [] };
|
|
65
76
|
try {
|
|
66
|
-
const ext =
|
|
77
|
+
const ext = graphExtOf(readGraphExts(api), target.graphId);
|
|
67
78
|
const editable = readEditableGeometry(target.graph, ext);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const { params } = readParameterOverrides(editable.graph, ext, instance.data ?? {});
|
|
73
|
-
result.instances.push({
|
|
79
|
+
const objectIds = objectIdsByInstance(api);
|
|
80
|
+
return {
|
|
81
|
+
source: editable.source,
|
|
82
|
+
instances: graphInstances(target.scripts, target.graphId).map(([id, instance]) => ({
|
|
74
83
|
instanceId: Number(id),
|
|
75
|
-
objectIds:
|
|
76
|
-
params,
|
|
77
|
-
})
|
|
78
|
-
|
|
84
|
+
objectIds: objectIds.get(Number(id)) ?? [],
|
|
85
|
+
params: readParameterOverrides(editable.graph, ext, instance.data ?? {}).params,
|
|
86
|
+
})),
|
|
87
|
+
diagnostics: [],
|
|
88
|
+
};
|
|
79
89
|
}
|
|
80
90
|
catch (error) {
|
|
81
|
-
|
|
82
|
-
// Bounded: a compiler diagnostic is unbounded text (./geometry/diagnostics.ts).
|
|
83
|
-
result.diagnostics.push(...boundedDiagnostics([errorMessage(error)]));
|
|
91
|
+
return { source: null, instances: [], diagnostics: boundedDiagnostics([errorMessage(error)]) };
|
|
84
92
|
}
|
|
85
|
-
return structuredClone(result);
|
|
86
93
|
}
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
async function readPlacement(api, objectId, target) {
|
|
95
|
+
if (objectId === 0)
|
|
96
|
+
return { transform: null, bounds: null, diagnostics: [] };
|
|
97
|
+
const reader = { requireNode: (id) => api.getNode(id), getNode: (id) => api.getNode(id) };
|
|
98
|
+
const unitMultiplier = sceneUnitMultiplier(api.getSceneProperties().unit_multiplier);
|
|
99
|
+
const transform = {
|
|
100
|
+
position: sceneNodePosition(reader, 0, unitMultiplier, objectId),
|
|
101
|
+
rotation: sceneNodeRotation(reader, objectId),
|
|
102
|
+
size: sceneNodeSize(reader, 0, unitMultiplier, objectId),
|
|
103
|
+
};
|
|
104
|
+
if (target.graph === undefined || target.node.parentId !== 0)
|
|
105
|
+
return { transform, bounds: null, diagnostics: [] };
|
|
106
|
+
try {
|
|
107
|
+
return { transform, bounds: convertAABB(await api.getNodeBoundingBox(objectId), unitMultiplier), diagnostics: [] };
|
|
97
108
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
additions.push({
|
|
103
|
-
op: "add",
|
|
104
|
-
path: "/scripts/graphs",
|
|
105
|
-
value: {},
|
|
106
|
-
});
|
|
107
|
-
if (!record.instances)
|
|
108
|
-
additions.push({
|
|
109
|
-
op: "add",
|
|
110
|
-
path: "/scripts/instances",
|
|
111
|
-
value: {},
|
|
112
|
-
});
|
|
113
|
-
if (additions.length)
|
|
114
|
-
draft.patchSceneStorage(additions, { returnScene: false });
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error instanceof KakapoError && error.code === "EMPTY_BOUNDING_BOX")
|
|
111
|
+
return { transform, bounds: null, diagnostics: [] };
|
|
112
|
+
return { transform, bounds: null, diagnostics: [`Bounds are unavailable: ${errorMessage(error)}`] };
|
|
115
113
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
114
|
+
}
|
|
115
|
+
async function readTarget(api, objectId) {
|
|
116
|
+
const target = resolveTarget(api, objectId);
|
|
117
|
+
const graph = describeGraph(api, target);
|
|
118
|
+
const placement = await readPlacement(api, objectId, target);
|
|
119
|
+
return {
|
|
120
|
+
kind: target.graph === undefined ? "container" : "graph",
|
|
121
|
+
objectId,
|
|
122
|
+
title: target.node.name,
|
|
123
|
+
graphId: target.graphId,
|
|
124
|
+
instanceId: target.instanceId,
|
|
125
|
+
source: graph.source,
|
|
126
|
+
transform: placement.transform,
|
|
127
|
+
bounds: placement.bounds,
|
|
128
|
+
instances: graph.instances,
|
|
129
|
+
diagnostics: boundedDiagnostics([...graph.diagnostics, ...placement.diagnostics]),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function planUpdate(target, graphExts, compiled) {
|
|
133
|
+
const ext = graphExtOf(graphExts, target.graphId);
|
|
134
|
+
const previous = readEditableGeometry(target.graph, ext);
|
|
135
|
+
const nextExt = migrateGraphExt(ext, previous.nodeIds, compiled);
|
|
136
|
+
const instances = {};
|
|
137
|
+
const diagnostics = [];
|
|
138
|
+
for (const [id, instance] of graphInstances(target.scripts, target.graphId)) {
|
|
139
|
+
const migrated = migrateParameterOverrides(previous.graph, ext, compiled.graph, nextExt, instance.data ?? {});
|
|
140
|
+
instances[id] = { graph_id: target.graphId, data: migrated.data };
|
|
141
|
+
if (migrated.removed.length)
|
|
142
|
+
diagnostics.push(`Instance ${id}: removed or type-changed overrides ${migrated.removed.join(", ")} now use graph defaults where present.`);
|
|
143
|
+
}
|
|
144
|
+
return { graphId: target.graphId, instanceId: target.instanceId, graph: compiled.graph, ext: nextExt, instances, diagnostics };
|
|
145
|
+
}
|
|
146
|
+
function planCreation(target, compiled) {
|
|
147
|
+
const graphId = unusedId(target.scripts.graphs);
|
|
148
|
+
const instanceId = unusedId(target.scripts.instances);
|
|
149
|
+
return {
|
|
150
|
+
graphId,
|
|
151
|
+
instanceId,
|
|
152
|
+
graph: compiled.graph,
|
|
153
|
+
ext: migrateGraphExt({ nodes: {} }, {}, compiled),
|
|
154
|
+
instances: { [instanceId]: { graph_id: graphId, data: {} } },
|
|
155
|
+
diagnostics: [],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function attachArea(draft, objectId, node, instanceId) {
|
|
159
|
+
const areaId = objectId !== 0 && node.kind === "union"
|
|
160
|
+
? objectId
|
|
161
|
+
: draft.createNode({ kind: "union", parentId: objectId, name: "Area" }).id;
|
|
162
|
+
draft.updateNode(areaId, { scriptInstanceId: instanceId });
|
|
163
|
+
return areaId;
|
|
164
|
+
}
|
|
165
|
+
function writeGraph(draft, scripts, graphExts, change) {
|
|
166
|
+
const nextScripts = {
|
|
167
|
+
...scripts,
|
|
168
|
+
graphs: { ...scripts.graphs, [change.graphId]: change.graph },
|
|
169
|
+
instances: { ...scripts.instances, ...change.instances },
|
|
170
|
+
};
|
|
171
|
+
draft.patchSceneStorage([{ op: "add", path: "/scripts", value: nextScripts }], { returnScene: false });
|
|
172
|
+
draft.patchSceneExt([{ op: "add", path: "/graphsExt", value: { ...graphExts, [change.graphId]: change.ext } }], { returnScene: false });
|
|
128
173
|
}
|
|
129
174
|
export function createSdkGeometryHost(options) {
|
|
130
|
-
const editor = options
|
|
175
|
+
const { editor } = options;
|
|
131
176
|
const repairs = createGeometryRepairTracker(options.repairs, "geometry");
|
|
132
177
|
const pendingTargets = new Set();
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
178
|
+
const write = async (input, invocation) => {
|
|
179
|
+
const target = await editor.read(invocation, (api) => resolveTarget(api, input.objectId));
|
|
180
|
+
const rejected = (diagnostics) => ({
|
|
181
|
+
status: "rejected",
|
|
182
|
+
objectId: input.objectId,
|
|
183
|
+
graphId: target.graphId,
|
|
184
|
+
instanceId: target.instanceId,
|
|
185
|
+
affectedObjectIds: [],
|
|
186
|
+
diagnostics: boundedDiagnostics(diagnostics),
|
|
187
|
+
});
|
|
188
|
+
const pendingKey = target.graphId === undefined ? `object:${input.objectId}` : `graph:${target.graphId}`;
|
|
189
|
+
if (pendingTargets.has(pendingKey))
|
|
190
|
+
throw new Error("This Geometry Nodes target is still being updated. Await its current update first.");
|
|
191
|
+
pendingTargets.add(pendingKey);
|
|
192
|
+
try {
|
|
193
|
+
const repairKey = target.graphId === undefined ? undefined : String(target.graphId);
|
|
194
|
+
const repairing = repairKey !== undefined && (await repairs.isPending(repairKey));
|
|
195
|
+
if (repairKey !== undefined)
|
|
196
|
+
await repairs.assertCanWrite(repairKey);
|
|
197
|
+
let compiled;
|
|
144
198
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
objectId: input.objectId,
|
|
170
|
-
};
|
|
171
|
-
let operationId;
|
|
172
|
-
let applied;
|
|
173
|
-
try {
|
|
174
|
-
applied = await editor.access({
|
|
175
|
-
capability: "geometry",
|
|
176
|
-
operation: "write",
|
|
177
|
-
target: () => receiptTarget,
|
|
178
|
-
}, async (_api, draft, id) => {
|
|
179
|
-
operationId = id;
|
|
180
|
-
const current = resolveTarget(draft, input.objectId);
|
|
181
|
-
if (repairingGeometry === false && options.canGrow?.() === false)
|
|
182
|
-
throw new Error("Scene memory limits prevent applying this graph.");
|
|
183
|
-
if (current.graphId !== target.graphId)
|
|
184
|
-
throw new Error("The Geometry Nodes target changed. Read it again.");
|
|
185
|
-
let nextExt;
|
|
186
|
-
const updates = new Map();
|
|
187
|
-
try {
|
|
188
|
-
if (target.graphId === undefined) {
|
|
189
|
-
nextExt = migrateGraphExt({ nodes: {} }, {}, compiled);
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
if (current.graph === undefined)
|
|
193
|
-
throw new Error("The Geometry Nodes graph is missing.");
|
|
194
|
-
const graphExt = draft.getSceneExt(["graphsExt"]).graphsExt;
|
|
195
|
-
const ext = graphExtSchema.parse(graphExt?.[target.graphId] ?? {});
|
|
196
|
-
const previous = readEditableGeometry(current.graph, ext);
|
|
197
|
-
nextExt = migrateGraphExt(ext, previous.nodeIds, compiled);
|
|
198
|
-
for (const [id, instance] of Object.entries(current.scripts.instances)) {
|
|
199
|
-
if (instance.graph_id !== target.graphId)
|
|
200
|
-
continue;
|
|
201
|
-
const old = readParameterOverrides(previous.graph, ext, instance.data ?? {});
|
|
202
|
-
const migrated = migrateParameterOverrides(previous.graph, ext, compiled.graph, nextExt, old.data);
|
|
203
|
-
updates.set(id, {
|
|
204
|
-
graph_id: target.graphId,
|
|
205
|
-
data: migrated.data,
|
|
206
|
-
});
|
|
207
|
-
if (migrated.removed.length)
|
|
208
|
-
diagnostics.push(`Instance ${id}: removed or type-changed overrides ${migrated.removed.join(", ")} now use graph defaults where present.`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
catch (error) {
|
|
213
|
-
return { rejected: [errorMessage(error)] };
|
|
214
|
-
}
|
|
215
|
-
if (current.graphId !== undefined)
|
|
216
|
-
await repairs.reserve(String(current.graphId), id);
|
|
217
|
-
let objectId = input.objectId;
|
|
218
|
-
let graphId = current.graphId;
|
|
219
|
-
let instanceId = current.instanceId;
|
|
220
|
-
const nextInstances = new Map(updates);
|
|
221
|
-
if (graphId === undefined) {
|
|
222
|
-
graphId = unusedId(current.scripts.graphs);
|
|
223
|
-
instanceId = unusedId(current.scripts.instances);
|
|
224
|
-
if (objectId === 0 || current.node.kind !== "union") {
|
|
225
|
-
objectId = draft.createNode({
|
|
226
|
-
kind: "union",
|
|
227
|
-
parentId: objectId,
|
|
228
|
-
name: "Area",
|
|
229
|
-
}).id;
|
|
230
|
-
}
|
|
231
|
-
draft.updateNode(objectId, { scriptInstanceId: instanceId });
|
|
232
|
-
nextInstances.set(String(instanceId), {
|
|
233
|
-
graph_id: graphId,
|
|
234
|
-
data: {},
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
writeGraphStorage(draft, graphId, compiled.graph, nextInstances);
|
|
238
|
-
const ext = draft.getSceneExt();
|
|
239
|
-
if (!ext.graphsExt)
|
|
240
|
-
draft.patchSceneExt([
|
|
241
|
-
{ op: "add", path: "/graphsExt", value: {} },
|
|
242
|
-
], { returnScene: false });
|
|
243
|
-
draft.patchSceneExt([
|
|
244
|
-
{
|
|
245
|
-
op: "add",
|
|
246
|
-
path: `/graphsExt/${graphId}`,
|
|
247
|
-
value: nextExt,
|
|
248
|
-
},
|
|
249
|
-
], { returnScene: false });
|
|
250
|
-
const affectedObjectIds = Object.entries(scriptStorage(draft).instances)
|
|
251
|
-
.filter(([, instance]) => instance.graph_id === graphId)
|
|
252
|
-
.flatMap(([id]) => objectIdsFor(draft, Number(id)));
|
|
253
|
-
Object.assign(receiptTarget, { objectId, graphId, instanceId });
|
|
254
|
-
return { objectId, graphId, instanceId, affectedObjectIds };
|
|
255
|
-
}, invocation, async (operation) => {
|
|
256
|
-
const graphId = receiptTarget.graphId;
|
|
257
|
-
if (graphId === undefined)
|
|
258
|
-
return;
|
|
259
|
-
const recorded = await repairs.record(String(graphId), operation.id, unverifiedSceneHealth([], "Health was not requested."));
|
|
260
|
-
return {
|
|
261
|
-
geometryRepairAttempts: recorded.repairAttempts,
|
|
262
|
-
geometryRepairLimit: recorded.repairLimit,
|
|
263
|
-
};
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
catch (error) {
|
|
267
|
-
if (operationId !== undefined && target.graphId !== undefined) {
|
|
268
|
-
const operation = error instanceof SceneOperationError
|
|
269
|
-
? error.operation : await editor.getOperation(operationId);
|
|
270
|
-
if (operation?.status === "rolled_back")
|
|
271
|
-
await repairs.refund(String(target.graphId), operationId);
|
|
199
|
+
compiled = compileGeometry(input.source);
|
|
200
|
+
readEditableGeometry(compiled.graph, compiled.graphExt);
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
return rejected([errorMessage(error)]);
|
|
204
|
+
}
|
|
205
|
+
const memoryBlocked = () => repairing === false && options.canGrow?.() === false;
|
|
206
|
+
if (memoryBlocked())
|
|
207
|
+
return rejected([MEMORY_LIMIT]);
|
|
208
|
+
const receipt = { objectId: input.objectId };
|
|
209
|
+
let operationId;
|
|
210
|
+
let applied;
|
|
211
|
+
try {
|
|
212
|
+
applied = await editor.access({ capability: "geometry", operation: "write", target: () => receipt }, async (_api, draft, id) => {
|
|
213
|
+
operationId = id;
|
|
214
|
+
const current = resolveTarget(draft, input.objectId);
|
|
215
|
+
if (memoryBlocked())
|
|
216
|
+
throw new Error(MEMORY_LIMIT);
|
|
217
|
+
if (current.graphId !== target.graphId)
|
|
218
|
+
throw new Error("The Geometry Nodes target changed. Read it again.");
|
|
219
|
+
const graphExts = readGraphExts(draft);
|
|
220
|
+
let change;
|
|
221
|
+
try {
|
|
222
|
+
change = current.graph === undefined ? planCreation(current, compiled) : planUpdate(current, graphExts, compiled);
|
|
272
223
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
224
|
+
catch (error) {
|
|
225
|
+
return { rejected: [errorMessage(error)] };
|
|
226
|
+
}
|
|
227
|
+
if (current.graph !== undefined)
|
|
228
|
+
await repairs.reserve(String(current.graphId), id);
|
|
229
|
+
const objectId = current.graph === undefined ? attachArea(draft, input.objectId, current.node, change.instanceId) : input.objectId;
|
|
230
|
+
writeGraph(draft, current.scripts, graphExts, change);
|
|
231
|
+
const objectIds = objectIdsByInstance(draft);
|
|
232
|
+
Object.assign(receipt, { objectId, graphId: change.graphId, instanceId: change.instanceId });
|
|
233
|
+
return {
|
|
234
|
+
objectId,
|
|
235
|
+
graphId: change.graphId,
|
|
236
|
+
instanceId: change.instanceId,
|
|
237
|
+
affectedObjectIds: Object.keys(change.instances).flatMap((instanceId) => objectIds.get(Number(instanceId)) ?? []),
|
|
238
|
+
diagnostics: change.diagnostics,
|
|
239
|
+
};
|
|
240
|
+
}, invocation, async (operation) => {
|
|
241
|
+
if (receipt.graphId === undefined)
|
|
242
|
+
return;
|
|
243
|
+
const recorded = await repairs.record(String(receipt.graphId), operation.id, unverifiedSceneHealth([], "Health was not requested."));
|
|
244
|
+
return { geometryRepairAttempts: recorded.repairAttempts, geometryRepairLimit: recorded.repairLimit };
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
if (operationId !== undefined && repairKey !== undefined) {
|
|
249
|
+
const operation = error instanceof SceneOperationError ? error.operation : await editor.getOperation(operationId);
|
|
250
|
+
if (operation?.status === "rolled_back")
|
|
251
|
+
await repairs.refund(repairKey, operationId);
|
|
280
252
|
}
|
|
281
|
-
|
|
282
|
-
return {
|
|
283
|
-
status: "applied",
|
|
284
|
-
...applied.value,
|
|
285
|
-
diagnostics: boundedDiagnostics(diagnostics),
|
|
286
|
-
};
|
|
253
|
+
throw error;
|
|
287
254
|
}
|
|
288
|
-
|
|
289
|
-
|
|
255
|
+
const result = applied.value;
|
|
256
|
+
if (result.rejected)
|
|
257
|
+
return rejected(result.rejected);
|
|
258
|
+
invocation.signal.throwIfAborted();
|
|
259
|
+
try {
|
|
260
|
+
await options.onSelect?.(result.objectId);
|
|
261
|
+
}
|
|
262
|
+
catch { }
|
|
263
|
+
let committed;
|
|
264
|
+
try {
|
|
265
|
+
committed = await editor.read(invocation, (api) => readTarget(api, result.objectId));
|
|
290
266
|
}
|
|
291
|
-
|
|
267
|
+
catch (error) {
|
|
268
|
+
committed = {
|
|
269
|
+
source: null,
|
|
270
|
+
transform: null,
|
|
271
|
+
bounds: null,
|
|
272
|
+
diagnostics: [`The write was applied, but reading it back failed: ${errorMessage(error)} Read the target before editing it again.`],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
status: "applied",
|
|
277
|
+
objectId: result.objectId,
|
|
278
|
+
graphId: result.graphId,
|
|
279
|
+
instanceId: result.instanceId,
|
|
280
|
+
affectedObjectIds: result.affectedObjectIds,
|
|
281
|
+
source: committed.source ?? undefined,
|
|
282
|
+
transform: committed.transform,
|
|
283
|
+
bounds: committed.bounds,
|
|
284
|
+
diagnostics: boundedDiagnostics([...result.diagnostics, ...committed.diagnostics]),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
finally {
|
|
288
|
+
pendingTargets.delete(pendingKey);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
return {
|
|
292
|
+
read: (objectId, invocation) => editor.read(invocation, (api) => readTarget(api, objectId)),
|
|
293
|
+
write,
|
|
292
294
|
};
|
|
293
295
|
}
|
package/dist/ui.d.ts
CHANGED
|
@@ -106,6 +106,12 @@ export type SparkSelectionData = {
|
|
|
106
106
|
export type SparkCompaction = {
|
|
107
107
|
/** The user message the model reads verbatim from; everything before it is summarized. */
|
|
108
108
|
firstKeptMessageId: string;
|
|
109
|
+
/**
|
|
110
|
+
* Set when the summary was written during its turn: the first step of the
|
|
111
|
+
* recording message the model still reads, counted from 0. Its earlier steps
|
|
112
|
+
* are summarized too.
|
|
113
|
+
*/
|
|
114
|
+
firstKeptStep?: number;
|
|
109
115
|
summary: string;
|
|
110
116
|
/** Skills read in the summarized messages; their current text is sent after the summary. */
|
|
111
117
|
skills: string[];
|
|
@@ -363,6 +369,7 @@ export declare const sparkDataPartSchemas: {
|
|
|
363
369
|
}, z.core.$strip>;
|
|
364
370
|
readonly compaction: z.ZodObject<{
|
|
365
371
|
firstKeptMessageId: z.ZodString;
|
|
372
|
+
firstKeptStep: z.ZodOptional<z.ZodNumber>;
|
|
366
373
|
summary: z.ZodString;
|
|
367
374
|
skills: z.ZodArray<z.ZodString>;
|
|
368
375
|
modelId: z.ZodString;
|
package/dist/ui.js
CHANGED
|
@@ -88,6 +88,7 @@ export const sparkDataPartSchemas = {
|
|
|
88
88
|
selection: z.object({ nodeIds: z.array(z.string().min(1).max(64)).min(1).max(8192) }),
|
|
89
89
|
compaction: z.object({
|
|
90
90
|
firstKeptMessageId: z.string().min(1),
|
|
91
|
+
firstKeptStep: z.number().int().positive().optional(),
|
|
91
92
|
summary: z.string().min(1),
|
|
92
93
|
skills: z.array(z.string().min(1)),
|
|
93
94
|
modelId: z.string(),
|
package/dist/womp-scene-api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FontFamily, KakapoAPI, KakapoNode, NodeKind, SceneEdit, Vec2, Vec3 } from "@womp/kakapo-sdk";
|
|
1
|
+
import type { BoundingBox, FontFamily, KakapoAPI, KakapoNode, NodeKind, SceneEdit, Vec2, Vec3 } from "@womp/kakapo-sdk";
|
|
2
2
|
import { type SceneHdr } from "./scene-environment.js";
|
|
3
3
|
import { type MirrorAxis } from "./coordinates.js";
|
|
4
4
|
export declare const NodeType: {
|
|
@@ -81,6 +81,14 @@ export type WompSceneApiContext = {
|
|
|
81
81
|
};
|
|
82
82
|
export type WompSceneApi = ReturnType<typeof createWompSceneApi>;
|
|
83
83
|
export declare function sceneNodeType(kind: NodeKind): number;
|
|
84
|
+
export declare function convertAABB(box: BoundingBox, unitMultiplier: number): AABB;
|
|
85
|
+
export type SceneNodeReader = {
|
|
86
|
+
requireNode(id: number): KakapoNode;
|
|
87
|
+
getNode(id: number): KakapoNode;
|
|
88
|
+
};
|
|
89
|
+
export declare function sceneNodePosition(reader: SceneNodeReader, rootId: number, unitMultiplier: number, id: number): Vec3;
|
|
90
|
+
export declare function sceneNodeRotation(reader: SceneNodeReader, id: number): Vec3;
|
|
91
|
+
export declare function sceneNodeSize(reader: SceneNodeReader, rootId: number, unitMultiplier: number, id: number): Vec3;
|
|
84
92
|
/** Align local +Z toward target. Both points are in the same parent-local coordinates. */
|
|
85
93
|
declare function lookAt(origin: Vec3, target: Vec3): Vec3;
|
|
86
94
|
/** XYZ degrees aligning the selected positive local axis to a parent-local direction. */
|