@pinepaper.studio/mcp-server 1.6.32 → 1.6.33
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 +53 -0
- package/dist/agent/types.d.ts +3 -3
- package/dist/build-info.json +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/ontology/upstream-vocabulary.d.ts +1 -1
- package/dist/ontology/upstream-vocabulary.js +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +51 -38
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-lists.d.ts +5 -3
- package/dist/tools/engine-lists.d.ts.map +1 -1
- package/dist/tools/engine-lists.js +11 -3
- package/dist/tools/engine-lists.js.map +1 -1
- package/dist/tools/engine-surface.d.ts +1 -1
- package/dist/tools/engine-surface.d.ts.map +1 -1
- package/dist/tools/engine-surface.js +10 -4
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +59 -11
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/lane.js +2 -2
- package/dist/tools/lane.js.map +1 -1
- package/dist/tools/reply-fields.d.ts +15 -0
- package/dist/tools/reply-fields.d.ts.map +1 -0
- package/dist/tools/reply-fields.js +117 -0
- package/dist/tools/reply-fields.js.map +1 -0
- package/dist/tools/scene-cache-export.d.ts.map +1 -1
- package/dist/tools/scene-cache-export.js +2 -1
- package/dist/tools/scene-cache-export.js.map +1 -1
- package/dist/tools/shape-params.d.ts +2 -2
- package/dist/tools/shape-params.d.ts.map +1 -1
- package/dist/tools/shape-params.js +4 -2
- package/dist/tools/shape-params.js.map +1 -1
- package/dist/tools/stick-vocabulary.d.ts +1 -1
- package/dist/tools/stick-vocabulary.js +1 -1
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +113 -34
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +31 -6
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +11 -3
- package/dist/types/schemas.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
package/dist/tools/handlers.js
CHANGED
|
@@ -9,6 +9,7 @@ import { dropPrivateRelationParams, normalizeBatchOperationNames, renamedArgumen
|
|
|
9
9
|
import { nestedIgnoredPaths } from './nested-ignored.js';
|
|
10
10
|
import { CRAFT_FRAME_JS, generateDrawWeave, generateDrawKnots, generateDrawSashiko, generateDrawSubdivision, generateUiKit, uiKitCallProblems, } from './craft-tools.js';
|
|
11
11
|
import { exportPerScene } from './scene-cache-export.js';
|
|
12
|
+
import { boundedStructured, reportedIgnoredPaths } from './reply-fields.js';
|
|
12
13
|
import { codeGenerator, generateQueryMutationsCode, SHEET_RUBRIC } from '../types/code-generator.js';
|
|
13
14
|
import { expandBatchMacros, BatchMacroError } from './batch-macros.js';
|
|
14
15
|
import { CreateItemInputSchema, ModifyItemInputSchema, DeleteItemInputSchema, AddRelationInputSchema, RemoveRelationInputSchema, QueryRelationsInputSchema, AnimateItemInputSchema, ImportMotionCaptureInputSchema, KeyframeAnimateInputSchema, ExecuteGeneratorInputSchema, ApplyEffectInputSchema, GetItemsInputSchema, PlayTimelineInputSchema, SetBackgroundColorInputSchema, SetCanvasSizeInputSchema, ImportSVGInputSchema, ImportMermaidInputSchema, AddFilterInputSchema, CreateGlossySphereInputSchema, CreateDiagonalStripesInputSchema, BatchCreateInputSchema, BatchModifyInputSchema, CreateGridInputSchema, GeometryInputSchema, EquationPathInputSchema, EventInputSchema, ConstructionSequenceInputSchema, ValidateSceneInputSchema, CaptureFramesInputSchema, InstantiateOntologyInputSchema, LintSceneInputSchema, MediaInputSchema, TextStyleInputSchema, TextEffectInputSchema, DesignMediumInputSchema, RelightInputSchema, ChoreographInputSchema, EmitterInputSchema, MorphSequenceInputSchema, OriginalCharacterInputSchema, LookInputSchema, RenderHookInputSchema, ShaderGraphInputSchema, ShatterImageInputSchema, ImportLayeredCharacterInputSchema, CharacterInputSchema, GameInputSchema, World3DInputSchema, BrandKitInputSchema, ComponentInputSchema, ArtboardInputSchema, CommentInputSchema, ProvenanceInputSchema, SceneDiffInputSchema, AudioBeatsInputSchema, TemplateParamsInputSchema, RenderBatchInputSchema, AccessibilityCheckInputSchema, QueryMutationsInputSchema, ComposeInputSchema, CropImageInputSchema, PathOpInputSchema, MotionInputSchema, SoundInputSchema, InterchangeInputSchema, StickInputSchema, DesignSystemInputSchema, StoryInputSchema, ChromaKeyInputSchema, RiggingInputSchema, GroupInputSchema, CameraDirectorInputSchema, DetectObjectsInputSchema, ExtractObjectInputSchema, ArrangeInputSchema, CreateSceneInputSchema, GetPerformanceMetricsInputSchema, DiagnosticReportInputSchema, SearchAssetsInputSchema, ImportAssetInputSchema, P5DrawInputSchema,
|
|
@@ -161,11 +162,11 @@ function exportGovernorTimeoutMs() {
|
|
|
161
162
|
* size cap. This reads the user's disk on their instruction, the same as the
|
|
162
163
|
* export side writes to it, and neither should be a wildcard.
|
|
163
164
|
*/
|
|
164
|
-
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.avif']);
|
|
165
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.apng', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.avif']);
|
|
165
166
|
const MAX_LOCAL_IMAGE_BYTES = 32 * 1024 * 1024;
|
|
166
167
|
const IMAGE_MIME = {
|
|
167
168
|
'.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif',
|
|
168
|
-
'.webp': 'image/webp', '.svg': 'image/svg+xml', '.bmp': 'image/bmp', '.avif': 'image/avif',
|
|
169
|
+
'.webp': 'image/webp', '.apng': 'image/apng', '.svg': 'image/svg+xml', '.bmp': 'image/bmp', '.avif': 'image/avif',
|
|
169
170
|
};
|
|
170
171
|
/**
|
|
171
172
|
* THE PAGE CANNOT FETCH A THIRD-PARTY IMAGE. THIS PROCESS CAN.
|
|
@@ -421,6 +422,7 @@ async function saveAdExport(r, input, platform) {
|
|
|
421
422
|
if (warnings.length && cleanResult.fidelity.note)
|
|
422
423
|
delete cleanResult.fidelity.note;
|
|
423
424
|
return {
|
|
425
|
+
structuredContent: boundedStructured(cleanResult),
|
|
424
426
|
content: [{
|
|
425
427
|
type: 'text',
|
|
426
428
|
text: `Ad saved:\n\n${Object.entries(files).map(([k, v]) => `${k}: ${v}`).join('\n')}\nFormat: ${r.format}\nSize: ${r.adSize.width}x${r.adSize.height}, upload ${(uploadBytes / 1024).toFixed(1)} KB\n\nResult: ${JSON.stringify(cleanResult, null, 2)}`,
|
|
@@ -1909,22 +1911,60 @@ export function batchOpIgnoredPaths(args) {
|
|
|
1909
1911
|
return out.slice(0, 50);
|
|
1910
1912
|
}
|
|
1911
1913
|
export const IGNORED_ARGUMENTS_META_KEY = 'pinepaper.studio/ignoredArguments';
|
|
1912
|
-
/**
|
|
1914
|
+
/**
|
|
1915
|
+
* Adds fields to a reply whose first block is a JSON object, and to its structuredContent when it already has one (a
|
|
1916
|
+
* saved export: prose first, data beside it). False when neither took them (or nothing to add is true).
|
|
1917
|
+
*/
|
|
1913
1918
|
function withReplyFields(result, fields) {
|
|
1914
1919
|
if (!Object.keys(fields).length)
|
|
1915
1920
|
return true;
|
|
1921
|
+
const hadStructured = !!result.structuredContent;
|
|
1922
|
+
if (result.structuredContent)
|
|
1923
|
+
result.structuredContent = { ...result.structuredContent, ...fields };
|
|
1916
1924
|
const first = result.content?.[0];
|
|
1917
1925
|
if (first?.type !== 'text')
|
|
1918
|
-
return
|
|
1926
|
+
return hadStructured;
|
|
1919
1927
|
try {
|
|
1920
1928
|
const obj = JSON.parse(first.text);
|
|
1921
1929
|
if (!obj || typeof obj !== 'object' || Array.isArray(obj))
|
|
1922
|
-
return
|
|
1930
|
+
return hadStructured;
|
|
1923
1931
|
result.content = [{ ...first, text: JSON.stringify({ ...obj, ...fields }, null, 2) }, ...result.content.slice(1)];
|
|
1924
1932
|
return true;
|
|
1925
1933
|
}
|
|
1926
1934
|
catch {
|
|
1927
|
-
return
|
|
1935
|
+
return hadStructured;
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
/** How many ops a written batch op becomes; a macro that does not expand is refused before anything runs. */
|
|
1939
|
+
function expandedOpCount(op) {
|
|
1940
|
+
try {
|
|
1941
|
+
return expandBatchMacros([op]).length;
|
|
1942
|
+
}
|
|
1943
|
+
catch {
|
|
1944
|
+
return 1;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
/**
|
|
1948
|
+
* The tools that hand back something the studio rendered. Render behaviour follows the live studio, not this package,
|
|
1949
|
+
* so a result is traced by the build that made it. agent_export's generated code says so itself; the rest are asked
|
|
1950
|
+
* here, once, after the call.
|
|
1951
|
+
*/
|
|
1952
|
+
const RENDERING_TOOLS = new Set(['pinepaper_agent_export', 'pinepaper_capture_frames', 'pinepaper_export_scene', 'pinepaper_export_svg',
|
|
1953
|
+
'pinepaper_export_training_data', 'pinepaper_export_widget', 'pinepaper_export_widget_html', 'pinepaper_render_batch', 'pinepaper_sprite_sheet']);
|
|
1954
|
+
async function renderingBuildField(toolName, args, result, options) {
|
|
1955
|
+
if (!RENDERING_TOOLS.has(toolName) || args.estimateOnly === true || result.isError || !options.executeInBrowser || result.structuredContent?.studioBuild)
|
|
1956
|
+
return {};
|
|
1957
|
+
if ((options.executionMode ?? getExecutionMode()) === 'code')
|
|
1958
|
+
return {};
|
|
1959
|
+
const controller = (options.browserController ?? peekBrowserController());
|
|
1960
|
+
if (!controller?.connected || typeof controller.executeCode !== 'function')
|
|
1961
|
+
return {};
|
|
1962
|
+
try {
|
|
1963
|
+
const r = await controller.executeCode(`(function () { return typeof app !== 'undefined' && app.buildId ? app.buildId : null; })();`, false, { bypassGovernor: true });
|
|
1964
|
+
return r?.success && typeof r.result === 'string' ? { studioBuild: r.result } : {};
|
|
1965
|
+
}
|
|
1966
|
+
catch {
|
|
1967
|
+
return {}; // the export stands
|
|
1928
1968
|
}
|
|
1929
1969
|
}
|
|
1930
1970
|
export async function handleToolCall(toolName, args, options = {}) {
|
|
@@ -1955,10 +1995,12 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
1955
1995
|
}
|
|
1956
1996
|
}
|
|
1957
1997
|
const ignored = await ignoredArgumentsNoteFor(toolName, args);
|
|
1958
|
-
if (ignored)
|
|
1998
|
+
if (ignored)
|
|
1959
1999
|
result.content = [...(result.content ?? []), { type: 'text', text: ignored.note }];
|
|
1960
|
-
|
|
1961
|
-
|
|
2000
|
+
// What only the run can tell: an option or property the op's own warning named. Its sentence is already in the reply.
|
|
2001
|
+
const ignoredPaths = [...new Set([...(ignored?.ignored ?? []), ...reportedIgnoredPaths(toolName, args, result, expandedOpCount)])];
|
|
2002
|
+
if (ignoredPaths.length)
|
|
2003
|
+
result._meta = { ...(result._meta ?? {}), [IGNORED_ARGUMENTS_META_KEY]: ignoredPaths };
|
|
1962
2004
|
if (renamed.length)
|
|
1963
2005
|
result._meta = { ...(result._meta ?? {}), [RENAMED_ARGUMENTS_META_KEY]: renamed };
|
|
1964
2006
|
// IN THE REPLY'S OWN JSON. A client that has structuredContent reads that, and it is built from the first block
|
|
@@ -1966,7 +2008,11 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
1966
2008
|
const folded = withReplyFields(result, {
|
|
1967
2009
|
...(renamed.length ? { translatedArguments: renamed } : {}),
|
|
1968
2010
|
...(dropped.length ? { droppedArguments: dropped } : {}),
|
|
1969
|
-
...(
|
|
2011
|
+
...(ignoredPaths.length ? { ignoredArguments: ignoredPaths } : {}),
|
|
2012
|
+
...await renderingBuildField(toolName, args, result, options),
|
|
2013
|
+
// The engine draws an APNG's first frame; a GIF or WebP plays. Said by name, since nothing about the reply would show it.
|
|
2014
|
+
...(toolName === 'pinepaper_import_image' && !result.isError && typeof args.url === 'string' && /\.apng([?#]|$)/i.test(args.url)
|
|
2015
|
+
? { animation: 'an APNG draws its first frame and does not play. Import a GIF or WebP to play it.' } : {}),
|
|
1970
2016
|
});
|
|
1971
2017
|
if (!folded) {
|
|
1972
2018
|
const lines = [...(renamed.length ? [renamedArgumentsNote(renamed)] : []), ...(dropped.length ? [`Not sent to the studio, as its private state: ${dropped.join(', ')}.`] : [])];
|
|
@@ -4229,6 +4275,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
4229
4275
|
const receipt = await exportFileReceiptOrReason(filePath, exportResult);
|
|
4230
4276
|
const cleanResult = { ...exportResult, data: undefined, filePath, fileSize, chunks, file: receipt };
|
|
4231
4277
|
return withEngineReport({
|
|
4278
|
+
structuredContent: boundedStructured(cleanResult),
|
|
4232
4279
|
content: [{
|
|
4233
4280
|
type: 'text',
|
|
4234
4281
|
text: `Export saved to file:\n\nFile: ${filePath}\nFormat: ${format}\nSize: ${(fileSize / 1024).toFixed(1)} KB\nPlatform: ${input.platform}\nPaged out of the studio's export store in ${chunks} chunk${chunks === 1 ? '' : 's'}\n${receiptErrorLine(receipt)}${'receiptError' in receipt ? '' : probeLines(receipt)}${lintLines(exportResult)}\nResult: ${JSON.stringify(cleanResult, null, 2)}`,
|
|
@@ -4265,7 +4312,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
4265
4312
|
const { sccCues: _c, ...rest } = exportResult;
|
|
4266
4313
|
void _c;
|
|
4267
4314
|
const cleanResult = { ...rest, filePath, fileSize, frameRate: '29.97 drop-frame', fidelity: { warnings } };
|
|
4268
|
-
return withEngineReport({ content: [{ type: 'text', text: `Export saved to file:\n\nFile: ${filePath}\nFormat: scc (CEA-608, CC1, pop-on)\nSize: ${fileSize} bytes\n\nResult: ${JSON.stringify(cleanResult, null, 2)}` }, exportFileLink(filePath, fileSize)] }, exportBrowserResult.report);
|
|
4315
|
+
return withEngineReport({ structuredContent: boundedStructured(cleanResult), content: [{ type: 'text', text: `Export saved to file:\n\nFile: ${filePath}\nFormat: scc (CEA-608, CC1, pop-on)\nSize: ${fileSize} bytes\n\nResult: ${JSON.stringify(cleanResult, null, 2)}` }, exportFileLink(filePath, fileSize)] }, exportBrowserResult.report);
|
|
4269
4316
|
}
|
|
4270
4317
|
if ((format === 'html5-ad' || format === 'playable') && typeof exportResult?.adPage === 'string') {
|
|
4271
4318
|
try {
|
|
@@ -4295,6 +4342,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
4295
4342
|
// it has to be said out loud here rather than left in the JSON.
|
|
4296
4343
|
const dropNote = exportResult.incomplete;
|
|
4297
4344
|
return withEngineReport({
|
|
4345
|
+
structuredContent: boundedStructured(cleanResult),
|
|
4298
4346
|
content: [{
|
|
4299
4347
|
type: 'text',
|
|
4300
4348
|
text: `Export saved to file:\n\nFile: ${filePath}\nFormat: ${format}\nSize: ${(fileSize / 1024).toFixed(1)} KB\nPlatform: ${input.platform}\n`
|