@positronic/core 0.0.77 → 0.0.78
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/src/dsl/brain-runner.js +37 -182
- package/dist/src/dsl/brain-state-machine.js +58 -112
- package/dist/src/dsl/brain.js +1 -0
- package/dist/src/dsl/builder/brain.js +250 -412
- package/dist/src/dsl/builder/continuation.js +67 -0
- package/dist/src/dsl/constants.js +16 -17
- package/dist/src/dsl/create-brain.js +29 -45
- package/dist/src/dsl/example-webhook.js +1 -1
- package/dist/src/dsl/execution/constants.js +0 -4
- package/dist/src/dsl/execution/event-channel.js +77 -0
- package/dist/src/dsl/execution/event-stream.js +1625 -1474
- package/dist/src/dsl/signal-validation.js +0 -1
- package/dist/src/dsl/webhook.js +4 -1
- package/dist/src/files/event-wrapper.js +268 -0
- package/dist/src/files/index.js +1 -0
- package/dist/src/files/mime.js +31 -0
- package/dist/src/files/types.js +13 -0
- package/dist/src/index.js +10 -3
- package/dist/src/jsx-runtime.js +49 -0
- package/dist/src/memory/{scoped-memory.js → create-memory.js} +5 -5
- package/dist/src/plugins/collect-webhooks.js +49 -0
- package/dist/src/plugins/define-plugin.js +15 -0
- package/dist/src/plugins/index.js +1 -0
- package/dist/src/plugins/types.js +4 -0
- package/dist/src/store/types.js +2 -3
- package/dist/src/template/render-html.js +282 -0
- package/dist/src/template/render.js +357 -0
- package/dist/src/tools/index.js +88 -27
- package/dist/src/ui/generate-page-html.js +6 -6
- package/dist/src/ui/{generate-ui.js → generate-page.js} +24 -12
- package/dist/src/ui/parse-form-data.js +1 -11
- package/dist/src/ui/types.js +0 -123
- package/dist/src/yaml/data-validator.js +0 -27
- package/dist/src/yaml/type-inference.js +10 -9
- package/dist/types/clients/types.d.ts +15 -5
- package/dist/types/clients/types.d.ts.map +1 -1
- package/dist/types/dsl/brain-runner.d.ts +9 -14
- package/dist/types/dsl/brain-runner.d.ts.map +1 -1
- package/dist/types/dsl/brain-state-machine.d.ts +18 -28
- package/dist/types/dsl/brain-state-machine.d.ts.map +1 -1
- package/dist/types/dsl/brain.d.ts +3 -2
- package/dist/types/dsl/brain.d.ts.map +1 -1
- package/dist/types/dsl/builder/brain.d.ts +85 -228
- package/dist/types/dsl/builder/brain.d.ts.map +1 -1
- package/dist/types/dsl/builder/continuation.d.ts +16 -0
- package/dist/types/dsl/builder/continuation.d.ts.map +1 -0
- package/dist/types/dsl/constants.d.ts +12 -12
- package/dist/types/dsl/constants.d.ts.map +1 -1
- package/dist/types/dsl/create-brain.d.ts +17 -57
- package/dist/types/dsl/create-brain.d.ts.map +1 -1
- package/dist/types/dsl/definitions/blocks.d.ts +67 -66
- package/dist/types/dsl/definitions/blocks.d.ts.map +1 -1
- package/dist/types/dsl/definitions/brain-types.d.ts +8 -11
- package/dist/types/dsl/definitions/brain-types.d.ts.map +1 -1
- package/dist/types/dsl/definitions/events.d.ts +61 -56
- package/dist/types/dsl/definitions/events.d.ts.map +1 -1
- package/dist/types/dsl/definitions/run-params.d.ts +20 -21
- package/dist/types/dsl/definitions/run-params.d.ts.map +1 -1
- package/dist/types/dsl/definitions/steps.d.ts +1 -1
- package/dist/types/dsl/definitions/steps.d.ts.map +1 -1
- package/dist/types/dsl/example-webhook.d.ts +3 -3
- package/dist/types/dsl/example-webhook.d.ts.map +1 -1
- package/dist/types/dsl/execution/constants.d.ts +0 -5
- package/dist/types/dsl/execution/constants.d.ts.map +1 -1
- package/dist/types/dsl/execution/event-channel.d.ts +16 -0
- package/dist/types/dsl/execution/event-channel.d.ts.map +1 -0
- package/dist/types/dsl/execution/event-stream.d.ts +46 -34
- package/dist/types/dsl/execution/event-stream.d.ts.map +1 -1
- package/dist/types/dsl/signal-validation.d.ts.map +1 -1
- package/dist/types/dsl/types.d.ts +21 -83
- package/dist/types/dsl/types.d.ts.map +1 -1
- package/dist/types/dsl/webhook.d.ts +12 -2
- package/dist/types/dsl/webhook.d.ts.map +1 -1
- package/dist/types/files/event-wrapper.d.ts +20 -0
- package/dist/types/files/event-wrapper.d.ts.map +1 -0
- package/dist/types/files/index.d.ts +2 -0
- package/dist/types/files/index.d.ts.map +1 -0
- package/dist/types/files/mime.d.ts +2 -0
- package/dist/types/files/mime.d.ts.map +1 -0
- package/dist/types/files/types.d.ts +88 -0
- package/dist/types/files/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +22 -13
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/jsx-runtime.d.ts +35 -0
- package/dist/types/jsx-runtime.d.ts.map +1 -0
- package/dist/types/memory/{scoped-memory.d.ts → create-memory.d.ts} +7 -7
- package/dist/types/memory/create-memory.d.ts.map +1 -0
- package/dist/types/memory/types.d.ts +4 -4
- package/dist/types/memory/types.d.ts.map +1 -1
- package/dist/types/plugins/collect-webhooks.d.ts +8 -0
- package/dist/types/plugins/collect-webhooks.d.ts.map +1 -0
- package/dist/types/plugins/define-plugin.d.ts +25 -0
- package/dist/types/plugins/define-plugin.d.ts.map +1 -0
- package/dist/types/plugins/index.d.ts +3 -0
- package/dist/types/plugins/index.d.ts.map +1 -0
- package/dist/types/plugins/types.d.ts +83 -0
- package/dist/types/plugins/types.d.ts.map +1 -0
- package/dist/types/store/index.d.ts +1 -1
- package/dist/types/store/index.d.ts.map +1 -1
- package/dist/types/store/types.d.ts +0 -8
- package/dist/types/store/types.d.ts.map +1 -1
- package/dist/types/template/render-html.d.ts +9 -0
- package/dist/types/template/render-html.d.ts.map +1 -0
- package/dist/types/template/render.d.ts +15 -0
- package/dist/types/template/render.d.ts.map +1 -0
- package/dist/types/tools/index.d.ts +39 -27
- package/dist/types/tools/index.d.ts.map +1 -1
- package/dist/types/ui/generate-page-html.d.ts +4 -6
- package/dist/types/ui/generate-page-html.d.ts.map +1 -1
- package/dist/types/ui/{generate-ui.d.ts → generate-page.d.ts} +6 -6
- package/dist/types/ui/generate-page.d.ts.map +1 -0
- package/dist/types/ui/parse-form-data.d.ts +1 -5
- package/dist/types/ui/parse-form-data.d.ts.map +1 -1
- package/dist/types/ui/types.d.ts +0 -49
- package/dist/types/ui/types.d.ts.map +1 -1
- package/dist/types/yaml/data-validator.d.ts +0 -5
- package/dist/types/yaml/data-validator.d.ts.map +1 -1
- package/dist/types/yaml/type-inference.d.ts +4 -2
- package/dist/types/yaml/type-inference.d.ts.map +1 -1
- package/dist/types/yaml/types.d.ts +0 -1
- package/dist/types/yaml/types.d.ts.map +1 -1
- package/package.json +5 -1
- package/dist/src/dsl/agent-messages.js +0 -5
- package/dist/src/ui/validate-form.js +0 -428
- package/dist/types/dsl/agent-messages.d.ts +0 -12
- package/dist/types/dsl/agent-messages.d.ts.map +0 -1
- package/dist/types/memory/scoped-memory.d.ts.map +0 -1
- package/dist/types/ui/generate-ui.d.ts.map +0 -1
- package/dist/types/ui/validate-form.d.ts +0 -45
- package/dist/types/ui/validate-form.d.ts.map +0 -1
package/dist/src/tools/index.js
CHANGED
|
@@ -119,7 +119,7 @@ function _ts_generator(thisArg, body) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
import { z } from 'zod';
|
|
122
|
-
import {
|
|
122
|
+
import { generatePage as generatePageCore } from '../ui/generate-page.js';
|
|
123
123
|
import { generatePageHtml } from '../ui/generate-page-html.js';
|
|
124
124
|
import { parseDuration } from '../dsl/duration.js';
|
|
125
125
|
/**
|
|
@@ -145,7 +145,7 @@ import { parseDuration } from '../dsl/duration.js';
|
|
|
145
145
|
*/ export function createTool(config) {
|
|
146
146
|
return config;
|
|
147
147
|
}
|
|
148
|
-
var
|
|
148
|
+
var generatePageInputSchema = z.object({
|
|
149
149
|
prompt: z.string().describe('Natural language instructions describing the UI to generate. ' + 'Include: (1) the purpose of the page, (2) what information to display from the data parameter, ' + '(3) what input fields are needed if collecting data, (4) labels and placeholders for fields, ' + '(5) any specific layout preferences. Example: "Create a form to collect user feedback with ' + 'fields for rating (1-5 scale), comments (text area), and email. Show the product name at the top."'),
|
|
150
150
|
hasForm: z.boolean().optional().describe('Whether to include a form that can be submitted. Defaults to true. ' + 'Set to true when: collecting user input, approval workflows, any interactive data entry. ' + 'Set to false when: displaying read-only information, confirmation pages, dashboards. ' + 'When true, the tool returns webhook info that must be used with waitForWebhook to receive the submission.'),
|
|
151
151
|
persist: z.boolean().optional().describe('Whether to keep the page after the brain run completes. Defaults to false. ' + 'Set to false (default): Page is automatically cleaned up when the brain run finishes. Use for one-time forms, approvals, or temporary displays. ' + 'Set to true: Page survives brain completion and remains accessible. Use for shared dashboards, permanent reference pages, or pages that need to outlive the workflow.'),
|
|
@@ -166,9 +166,9 @@ var generateUIInputSchema = z.object({
|
|
|
166
166
|
* Requires components and pages to be configured via createBrain or withComponents().
|
|
167
167
|
*
|
|
168
168
|
* The description is enriched at runtime with available component information.
|
|
169
|
-
*/ export var
|
|
170
|
-
description: "Generate a web page for displaying rich content or collecting user input.\n\nSometimes you need more than simple notifications to communicate with users. This tool creates web pages that can display formatted content, dashboards, or forms to collect information.\n\nPass structured data via the 'data' parameter to populate the page with dynamic content. The
|
|
171
|
-
inputSchema:
|
|
169
|
+
*/ export var generatePage = {
|
|
170
|
+
description: "Generate a web page for displaying rich content or collecting user input.\n\nSometimes you need more than simple notifications to communicate with users. This tool creates web pages that can display formatted content, dashboards, or forms to collect information.\n\nPass structured data via the 'data' parameter to populate the page with dynamic content. The page generator uses {{path.to.value}} template bindings to render your data.\n\nRETURNS: { url: string, webhook: { slug: string, identifier: string, token: string } | null }\n- url: The page URL\n- webhook: For forms (hasForm=true), contains slug, identifier, and token that must be passed to waitForWebhook to pause execution until the user submits the form\n\nIMPORTANT: Users have no way to discover the page URL on their own. After generating a page, you must tell them the URL using whatever communication tools are available.",
|
|
171
|
+
inputSchema: generatePageInputSchema,
|
|
172
172
|
execute: function execute(input, context) {
|
|
173
173
|
return _async_to_generator(function() {
|
|
174
174
|
var components, pages, client, state, env, brainRunId, stepId, _input_hasForm, hasForm, _input_data, uiResult, placementCount, webhookInfo, formAction, formToken, webhookIdentifier, _input_data1, html, page;
|
|
@@ -178,11 +178,11 @@ var generateUIInputSchema = z.object({
|
|
|
178
178
|
components = context.components, pages = context.pages, client = context.client, state = context.state, env = context.env, brainRunId = context.brainRunId, stepId = context.stepId;
|
|
179
179
|
hasForm = (_input_hasForm = input.hasForm) !== null && _input_hasForm !== void 0 ? _input_hasForm : true;
|
|
180
180
|
if (!components || Object.keys(components).length === 0) {
|
|
181
|
-
throw new Error('
|
|
181
|
+
throw new Error('generatePage requires components to be configured. ' + 'Use createBrain({ components }) or brain.withComponents() to register UI components.');
|
|
182
182
|
}
|
|
183
183
|
return [
|
|
184
184
|
4,
|
|
185
|
-
|
|
185
|
+
generatePageCore({
|
|
186
186
|
client: client,
|
|
187
187
|
prompt: input.prompt,
|
|
188
188
|
components: components,
|
|
@@ -194,19 +194,19 @@ var generateUIInputSchema = z.object({
|
|
|
194
194
|
if (!uiResult.rootId) {
|
|
195
195
|
placementCount = uiResult.placements.length;
|
|
196
196
|
if (placementCount === 0) {
|
|
197
|
-
throw new Error("
|
|
197
|
+
throw new Error("Page generation failed - no components were generated. " + "The LLM may not have understood the prompt. Try being more specific.");
|
|
198
198
|
} else {
|
|
199
|
-
throw new Error("
|
|
199
|
+
throw new Error("Page generation failed - no root component found. " + "".concat(placementCount, " component(s) were placed but all have a parentId."));
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
// Create webhook info only if hasForm is true
|
|
203
203
|
webhookInfo = null;
|
|
204
204
|
if (hasForm) {
|
|
205
|
-
webhookIdentifier = "".concat(brainRunId, "-").concat(stepId, "-
|
|
205
|
+
webhookIdentifier = "".concat(brainRunId, "-").concat(stepId, "-generatepage-").concat(Date.now());
|
|
206
206
|
formToken = crypto.randomUUID();
|
|
207
|
-
formAction = "".concat(env.origin, "/webhooks/system/
|
|
207
|
+
formAction = "".concat(env.origin, "/webhooks/system/page-form?identifier=").concat(encodeURIComponent(webhookIdentifier), "&token=").concat(encodeURIComponent(formToken));
|
|
208
208
|
webhookInfo = {
|
|
209
|
-
slug: '
|
|
209
|
+
slug: 'page-form',
|
|
210
210
|
identifier: webhookIdentifier,
|
|
211
211
|
token: formToken
|
|
212
212
|
};
|
|
@@ -217,8 +217,7 @@ var generateUIInputSchema = z.object({
|
|
|
217
217
|
rootId: uiResult.rootId,
|
|
218
218
|
data: (_input_data1 = input.data) !== null && _input_data1 !== void 0 ? _input_data1 : {},
|
|
219
219
|
title: hasForm ? 'Generated Form' : 'Generated Page',
|
|
220
|
-
formAction: formAction
|
|
221
|
-
formToken: formToken
|
|
220
|
+
formAction: formAction
|
|
222
221
|
});
|
|
223
222
|
return [
|
|
224
223
|
4,
|
|
@@ -242,21 +241,21 @@ var generateUIInputSchema = z.object({
|
|
|
242
241
|
}
|
|
243
242
|
};
|
|
244
243
|
var waitForWebhookInputSchema = z.object({
|
|
245
|
-
slug: z.string().describe('The webhook slug that identifies the type of webhook. ' + 'For
|
|
246
|
-
identifier: z.string().describe('The unique identifier for this specific webhook instance. ' + 'This is returned by
|
|
247
|
-
token: z.string().optional().describe('The CSRF token for form submission validation. ' + 'This is returned by
|
|
244
|
+
slug: z.string().describe('The webhook slug that identifies the type of webhook. ' + 'For generatePage forms, this is always "page-form". ' + 'Use the exact slug value returned by the tool that created the webhook.'),
|
|
245
|
+
identifier: z.string().describe('The unique identifier for this specific webhook instance. ' + 'This is returned by generatePage in webhook.identifier. ' + 'Each generatePage call creates a unique identifier - use the one from the specific page you want to wait for.'),
|
|
246
|
+
token: z.string().optional().describe('The CSRF token for form submission validation. ' + 'This is returned by generatePage in webhook.token. ' + 'Pass it through to ensure only submissions from the actual page are accepted.'),
|
|
248
247
|
timeout: z.string().optional().describe('How long to wait before timing out. Defaults to "1h". ' + 'Accepts durations like "30m", "1h", "24h", "7d". ' + 'If the timeout elapses without a response, the brain is cancelled.')
|
|
249
248
|
});
|
|
250
249
|
/**
|
|
251
250
|
* Wait for webhook tool - pauses execution until a webhook receives a response.
|
|
252
251
|
*
|
|
253
|
-
* Use this after generating a
|
|
252
|
+
* Use this after generating a page with a form to wait for the user's submission.
|
|
254
253
|
* The form data will be returned as the tool result when the webhook fires.
|
|
255
254
|
*
|
|
256
255
|
* IMPORTANT: Before calling this tool, ensure the user knows the page URL
|
|
257
256
|
* so they can access and submit the form.
|
|
258
257
|
*/ export var waitForWebhook = {
|
|
259
|
-
description: 'Pause agent execution and wait for an external event (webhook response).\n\nPURPOSE: Suspend the agent until a user action occurs, such as submitting a form generated by
|
|
258
|
+
description: 'Pause agent execution and wait for an external event (webhook response).\n\nPURPOSE: Suspend the agent until a user action occurs, such as submitting a form generated by generatePage.\n\n⚠️ CRITICAL - BEFORE CALLING THIS TOOL:\nYou MUST have already communicated the page URL to the user in your response. The user has no other way to discover the URL. If you call this tool without first telling the user where to go, the job will freeze with no easy recovery.\n\nCORRECT SEQUENCE:\n1. Call generatePage to create the page\n2. In your response text, tell the user the URL (e.g., "Please complete the form at: {url}")\n3. THEN call waitForWebhook\n\nBEHAVIOR:\n- Calling this tool immediately pauses execution\n- The agent will NOT continue until the webhook receives data or the timeout elapses\n- Default timeout is 1 hour. Use the timeout parameter to customize (e.g., "30m", "24h", "7d")\n- If the timeout elapses without a response, the brain is cancelled\n- When the webhook fires, execution resumes with the webhook payload as this tool\'s result\n- The form data will be available as key-value pairs (e.g., { name: "John", email: "john@example.com" })\n\nWHEN TO USE:\n- After generatePage with hasForm=true, to wait for form submission\n- Any workflow requiring human input or approval before continuing\n\nFAILURE MODE: If the user doesn\'t know the URL, they cannot submit the form, and the agent waits until timeout. The only recovery is to kill the job or manually inspect the event stream for the URL.\n\nRETURNS: The webhook payload when triggered. For UI forms, this contains all form field values as an object.',
|
|
260
259
|
inputSchema: waitForWebhookInputSchema,
|
|
261
260
|
execute: function execute(input) {
|
|
262
261
|
var webhook = {
|
|
@@ -312,10 +311,73 @@ var waitForWebhookInputSchema = z.object({
|
|
|
312
311
|
}
|
|
313
312
|
});
|
|
314
313
|
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*/ export var
|
|
318
|
-
|
|
314
|
+
* Read a file by name. The agent decides which files to read.
|
|
315
|
+
* Returns the file content as text.
|
|
316
|
+
*/ export var readFile = createTool({
|
|
317
|
+
description: 'Read the contents of a file by name. Returns the file content as text.',
|
|
318
|
+
inputSchema: z.object({
|
|
319
|
+
name: z.string().describe('The file name to read')
|
|
320
|
+
}),
|
|
321
|
+
execute: function execute(_0, _1) {
|
|
322
|
+
return _async_to_generator(function(param, context) {
|
|
323
|
+
var name, _tmp;
|
|
324
|
+
return _ts_generator(this, function(_state) {
|
|
325
|
+
switch(_state.label){
|
|
326
|
+
case 0:
|
|
327
|
+
name = param.name;
|
|
328
|
+
if (!context.files) {
|
|
329
|
+
throw new Error('readFile tool requires a files service to be configured');
|
|
330
|
+
}
|
|
331
|
+
_tmp = {};
|
|
332
|
+
return [
|
|
333
|
+
4,
|
|
334
|
+
context.files.open(name).read()
|
|
335
|
+
];
|
|
336
|
+
case 1:
|
|
337
|
+
return [
|
|
338
|
+
2,
|
|
339
|
+
(_tmp.content = _state.sent(), _tmp)
|
|
340
|
+
];
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}).apply(this, arguments);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
/**
|
|
347
|
+
* Write text content to a file. The agent decides what to write and where.
|
|
348
|
+
*/ export var writeFile = createTool({
|
|
349
|
+
description: 'Write text content to a file. Creates or overwrites the file.',
|
|
350
|
+
inputSchema: z.object({
|
|
351
|
+
name: z.string().describe('The file name to write'),
|
|
352
|
+
content: z.string().describe('The text content to write')
|
|
353
|
+
}),
|
|
354
|
+
execute: function execute(_0, _1) {
|
|
355
|
+
return _async_to_generator(function(param, context) {
|
|
356
|
+
var name, content;
|
|
357
|
+
return _ts_generator(this, function(_state) {
|
|
358
|
+
switch(_state.label){
|
|
359
|
+
case 0:
|
|
360
|
+
name = param.name, content = param.content;
|
|
361
|
+
if (!context.files) {
|
|
362
|
+
throw new Error('writeFile tool requires a files service to be configured');
|
|
363
|
+
}
|
|
364
|
+
return [
|
|
365
|
+
4,
|
|
366
|
+
context.files.write(name, content)
|
|
367
|
+
];
|
|
368
|
+
case 1:
|
|
369
|
+
_state.sent();
|
|
370
|
+
return [
|
|
371
|
+
2,
|
|
372
|
+
{
|
|
373
|
+
written: true,
|
|
374
|
+
name: name
|
|
375
|
+
}
|
|
376
|
+
];
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}).apply(this, arguments);
|
|
380
|
+
}
|
|
319
381
|
});
|
|
320
382
|
/**
|
|
321
383
|
* Default tools bundle.
|
|
@@ -324,9 +386,8 @@ var waitForWebhookInputSchema = z.object({
|
|
|
324
386
|
* standard tools in your brain. Tools can be extended or overridden in
|
|
325
387
|
* individual agent steps.
|
|
326
388
|
*
|
|
327
|
-
* Note: A 'done' terminal tool is automatically generated for every agent
|
|
328
|
-
*
|
|
329
|
-
* it uses a default schema expecting { result: string }.
|
|
389
|
+
* Note: A 'done' terminal tool is automatically generated for every agent
|
|
390
|
+
* using the required outputSchema.
|
|
330
391
|
*
|
|
331
392
|
* @example
|
|
332
393
|
* ```typescript
|
|
@@ -347,7 +408,7 @@ var waitForWebhookInputSchema = z.object({
|
|
|
347
408
|
* }));
|
|
348
409
|
* ```
|
|
349
410
|
*/ export var defaultTools = {
|
|
350
|
-
|
|
411
|
+
generatePage: generatePage,
|
|
351
412
|
waitForWebhook: waitForWebhook,
|
|
352
413
|
print: print,
|
|
353
414
|
consoleLog: consoleLog
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Generate a CSRF token for form submissions.
|
|
3
3
|
* Use this when building custom HTML pages with forms that submit to webhook endpoints.
|
|
4
4
|
*
|
|
5
|
-
* Include the returned token as a
|
|
6
|
-
* ```
|
|
7
|
-
*
|
|
5
|
+
* Include the returned token as a query parameter in the form action URL:
|
|
6
|
+
* ```
|
|
7
|
+
* /webhooks/system/ui-form?identifier=...&token=${token}
|
|
8
8
|
* ```
|
|
9
9
|
* And include it in the WebhookRegistration's `token` field.
|
|
10
10
|
*/ export function generateFormToken() {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
/**
|
|
14
14
|
* Bootstrap runtime that builds and renders the React tree from placements.
|
|
15
15
|
* This is inlined into the generated page.
|
|
16
|
-
*/ var bootstrapRuntime = "\n(function() {\n const components = window.PositronicComponents;\n const data = window.__POSITRONIC_DATA__;\n const tree = window.__POSITRONIC_TREE__;\n const rootId = window.__POSITRONIC_ROOT__;\n const formAction = window.__POSITRONIC_FORM_ACTION__;\n
|
|
16
|
+
*/ var bootstrapRuntime = "\n(function() {\n const components = window.PositronicComponents;\n const data = window.__POSITRONIC_DATA__;\n const tree = window.__POSITRONIC_TREE__;\n const rootId = window.__POSITRONIC_ROOT__;\n const formAction = window.__POSITRONIC_FORM_ACTION__;\n\n if (!components) {\n console.error('PositronicComponents not loaded');\n return;\n }\n\n /**\n * Resolve a binding path against a data context.\n * e.g., \"email.subject\" against { email: { subject: \"Hello\" } } -> \"Hello\"\n */\n function resolveBinding(path, ctx) {\n return path.split('.').reduce(function(obj, key) {\n return obj && obj[key];\n }, ctx);\n }\n\n /**\n * Resolve a prop value - handle both full bindings and embedded bindings.\n * - \"{{path}}\" -> resolved value (preserves type - arrays, objects, etc.)\n * - \"Hello {{name}}, score: {{score}}\" -> \"Hello John, score: 42\"\n */\n function resolveProp(value, ctx) {\n if (typeof value !== 'string') {\n return value;\n }\n // Check if the entire value is a single binding - return the actual value (preserves arrays/objects)\n var fullBindingMatch = value.match(/^{{([^}]+)}}$/);\n if (fullBindingMatch) {\n var resolved = resolveBinding(fullBindingMatch[1].trim(), ctx);\n return resolved !== undefined ? resolved : value;\n }\n // Otherwise replace embedded bindings as strings\n return value.replace(/{{([^}]+)}}/g, function(match, path) {\n var resolved = resolveBinding(path.trim(), ctx);\n return resolved !== undefined ? String(resolved) : match;\n });\n }\n\n /**\n * Build a React element from a placement.\n */\n function buildElement(placementId, ctx) {\n var placement = tree.find(function(p) { return p.id === placementId; });\n if (!placement) {\n console.error('Placement not found:', placementId);\n return null;\n }\n\n // Resolve props first (needed for List handling)\n var props = {};\n for (var key in placement.props) {\n props[key] = resolveProp(placement.props[key], ctx);\n }\n\n // Handle List component specially - it's a virtual component that creates a loop context\n if (placement.component === 'List') {\n var items = Array.isArray(props.items) ? props.items : [];\n var itemVarName = props.as || 'item';\n\n // Find direct children of this List\n var childIds = tree\n .filter(function(p) { return p.parentId === placementId; })\n .map(function(p) { return p.id; });\n\n var listItems = items.map(function(item, index) {\n // Create new context with loop variable\n var itemCtx = Object.assign({}, ctx);\n itemCtx[itemVarName] = item;\n itemCtx[itemVarName + 'Index'] = index;\n\n var children = childIds.map(function(childId) {\n return buildElement(childId, itemCtx);\n });\n\n return React.createElement('div', { key: index, className: 'p-4 bg-white border border-gray-200 rounded-lg' }, children);\n });\n\n return React.createElement('div', { className: 'flex flex-col gap-4' }, listItems);\n }\n\n // Look up the component (after handling virtual components like List)\n var Component = components[placement.component];\n if (!Component) {\n console.error('Component not found:', placement.component);\n return null;\n }\n\n // Handle Form component - inject action URL and CSRF token\n if (placement.component === 'Form' && formAction) {\n props.action = formAction;\n }\n\n // Find direct children\n var childIds = tree\n .filter(function(p) { return p.parentId === placementId; })\n .map(function(p) { return p.id; });\n\n var children = childIds.map(function(childId) {\n return buildElement(childId, ctx);\n });\n\n return React.createElement(Component, props, children.length > 0 ? children : undefined);\n }\n\n // Render the tree\n var root = document.getElementById('root');\n if (root && rootId) {\n var element = buildElement(rootId, data);\n ReactDOM.render(element, root);\n }\n})();\n";
|
|
17
17
|
/**
|
|
18
18
|
* Generate a complete HTML page from placements.
|
|
19
19
|
*
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* });
|
|
36
36
|
* ```
|
|
37
37
|
*/ export function generatePageHtml(options) {
|
|
38
|
-
var placements = options.placements, rootId = options.rootId, data = options.data, _options_title = options.title, title = _options_title === void 0 ? 'Generated Page' : _options_title, formAction = options.formAction
|
|
38
|
+
var placements = options.placements, rootId = options.rootId, data = options.data, _options_title = options.title, title = _options_title === void 0 ? 'Generated Page' : _options_title, formAction = options.formAction;
|
|
39
39
|
// Escape for embedding in HTML
|
|
40
40
|
var escapeHtml = function(str) {
|
|
41
41
|
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
var safeJsonStringify = function(obj) {
|
|
45
45
|
return JSON.stringify(obj).replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/&/g, '\\u0026');
|
|
46
46
|
};
|
|
47
|
-
return '<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>'.concat(escapeHtml(title), '</title>\n <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>\n <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>\n <script src="https://cdn.tailwindcss.com"></script>\n</head>\n<body class="bg-gray-50 min-h-screen">\n <div id="root" class="max-w-4xl mx-auto p-6"></div>\n\n <!-- Pre-bundled components -->\n <script src="/bundle/components.js"></script>\n\n <!-- Data and placements -->\n <script>\n window.__POSITRONIC_DATA__ = ').concat(safeJsonStringify(data), ";\n window.__POSITRONIC_TREE__ = ").concat(safeJsonStringify(placements), ";\n window.__POSITRONIC_ROOT__ = ").concat(safeJsonStringify(rootId), ";\n window.__POSITRONIC_FORM_ACTION__ = ").concat(formAction ? safeJsonStringify(formAction) : 'null', ";\n
|
|
47
|
+
return '<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>'.concat(escapeHtml(title), '</title>\n <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>\n <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>\n <script src="https://cdn.tailwindcss.com"></script>\n</head>\n<body class="bg-gray-50 min-h-screen">\n <div id="root" class="max-w-4xl mx-auto p-6"></div>\n\n <!-- Pre-bundled components -->\n <script src="/bundle/components.js"></script>\n\n <!-- Data and placements -->\n <script>\n window.__POSITRONIC_DATA__ = ').concat(safeJsonStringify(data), ";\n window.__POSITRONIC_TREE__ = ").concat(safeJsonStringify(placements), ";\n window.__POSITRONIC_ROOT__ = ").concat(safeJsonStringify(rootId), ";\n window.__POSITRONIC_FORM_ACTION__ = ").concat(formAction ? safeJsonStringify(formAction) : 'null', ";\n </script>\n\n <!-- Bootstrap runtime -->\n <script>\n").concat(bootstrapRuntime, "\n </script>\n</body>\n</html>");
|
|
48
48
|
}
|
|
@@ -185,6 +185,7 @@ function _ts_generator(thisArg, body) {
|
|
|
185
185
|
}
|
|
186
186
|
import { v4 as uuidv4 } from 'uuid';
|
|
187
187
|
import { z } from 'zod';
|
|
188
|
+
import { IterateResult } from '../dsl/iterate-result.js';
|
|
188
189
|
import { parseTemplate } from '../yaml/parser.js';
|
|
189
190
|
import { inferDataType, resolveBindings, validateDataBindings } from '../yaml/data-validator.js';
|
|
190
191
|
import { extractFormSchema, validateAgainstZod } from '../yaml/schema-extractor.js';
|
|
@@ -319,7 +320,7 @@ import { describeDataShape } from '../yaml/type-inference.js';
|
|
|
319
320
|
*/ function createValidateTemplateTool(components, schema, data) {
|
|
320
321
|
var dataType = inferDataType(data);
|
|
321
322
|
return {
|
|
322
|
-
description: "Validate a YAML template. Checks that:\n1. The YAML is valid and can be parsed\n2. All component names are valid\n3. All data bindings (like {{email.subject}}) reference valid paths in the provided data\n4. Form components have a Button for submission\n5. The form fields will produce data matching the expected schema (if schema provided)\n\nReturns resolvedBindings showing
|
|
323
|
+
description: "Validate a YAML template. Checks that:\n1. The YAML is valid and can be parsed\n2. All component names are valid\n3. All data bindings (like {{email.subject}}) reference valid paths in the provided data\n4. Form components have a Button for submission\n5. The form fields will produce data matching the expected schema (if schema provided)\n\nReturns resolvedBindings showing whether each binding path is valid. Use this to verify bindings reference valid data paths.\n\nCall this after generating your YAML template to verify it's correct before finalizing.",
|
|
323
324
|
inputSchema: z.object({
|
|
324
325
|
yaml: z.string().describe('The complete YAML template to validate')
|
|
325
326
|
}),
|
|
@@ -499,18 +500,21 @@ import { describeDataShape } from '../yaml/type-inference.js';
|
|
|
499
500
|
/**
|
|
500
501
|
* Build the user prompt with data shape and instructions.
|
|
501
502
|
*/ function buildUserPrompt(prompt, data, schema) {
|
|
502
|
-
var
|
|
503
|
-
var userPrompt =
|
|
503
|
+
var hasData = Object.keys(data).length > 0;
|
|
504
|
+
var userPrompt = '';
|
|
505
|
+
if (hasData) {
|
|
506
|
+
var dataShape = describeDataShape(data, {
|
|
507
|
+
includeExamples: false
|
|
508
|
+
});
|
|
509
|
+
userPrompt += "## Available Data\n```typescript\n".concat(dataShape, "\n```\n\n");
|
|
510
|
+
}
|
|
511
|
+
userPrompt += "## Instructions\n".concat(prompt);
|
|
504
512
|
if (schema) {
|
|
505
513
|
var schemaFields = Object.entries(schema.shape).map(function(param) {
|
|
506
514
|
var _param = _sliced_to_array(param, 2), name = _param[0], field = _param[1];
|
|
507
515
|
var isOptional = _instanceof(field, z.ZodOptional);
|
|
508
516
|
var baseType = isOptional ? field.unwrap() : field;
|
|
509
|
-
var typeName =
|
|
510
|
-
if (_instanceof(baseType, z.ZodString)) typeName = 'string';
|
|
511
|
-
else if (_instanceof(baseType, z.ZodNumber)) typeName = 'number';
|
|
512
|
-
else if (_instanceof(baseType, z.ZodBoolean)) typeName = 'boolean';
|
|
513
|
-
else if (_instanceof(baseType, z.ZodArray)) typeName = "".concat(typeName, "[]");
|
|
517
|
+
var typeName = getZodTypeName(baseType);
|
|
514
518
|
return "- ".concat(name, ": ").concat(typeName).concat(isOptional ? ' (optional)' : '');
|
|
515
519
|
}).join('\n');
|
|
516
520
|
userPrompt += "\n\n## Expected Form Output\nThe form must collect these fields:\n".concat(schemaFields, "\n\nCall validate_template after generating your YAML to verify correctness.");
|
|
@@ -527,7 +531,7 @@ import { describeDataShape } from '../yaml/type-inference.js';
|
|
|
527
531
|
* ```typescript
|
|
528
532
|
* import { components } from '@positronic/gen-ui-components';
|
|
529
533
|
*
|
|
530
|
-
* const result = await
|
|
534
|
+
* const result = await generatePage({
|
|
531
535
|
* client,
|
|
532
536
|
* prompt: 'Create a form to collect user name and email',
|
|
533
537
|
* components,
|
|
@@ -539,13 +543,21 @@ import { describeDataShape } from '../yaml/type-inference.js';
|
|
|
539
543
|
* // result.rootId is the ID of the root component
|
|
540
544
|
* // result.yaml is the generated YAML template
|
|
541
545
|
* ```
|
|
542
|
-
*/ export function
|
|
546
|
+
*/ export function generatePage(params) {
|
|
543
547
|
return _async_to_generator(function() {
|
|
544
|
-
var client, prompt, components, schema,
|
|
548
|
+
var client, prompt, components, schema, tmp, rawData, _params_maxSteps, maxSteps, data, _params_system, systemPrompt, userPrompt, validateTool, result, _result_text, yamlContent, yamlMatch, placements, rootId, _placements_find, template;
|
|
545
549
|
return _ts_generator(this, function(_state) {
|
|
546
550
|
switch(_state.label){
|
|
547
551
|
case 0:
|
|
548
|
-
client = params.client, prompt = params.prompt, components = params.components, schema = params.schema,
|
|
552
|
+
client = params.client, prompt = params.prompt, components = params.components, schema = params.schema, tmp = params.data, rawData = tmp === void 0 ? {} : tmp, _params_maxSteps = params.maxSteps, maxSteps = _params_maxSteps === void 0 ? 10 : _params_maxSteps;
|
|
553
|
+
// Unwrap IterateResult values to plain arrays so the LLM sees a clean data shape
|
|
554
|
+
data = Object.fromEntries(Object.entries(rawData).map(function(param) {
|
|
555
|
+
var _param = _sliced_to_array(param, 2), k = _param[0], v = _param[1];
|
|
556
|
+
return [
|
|
557
|
+
k,
|
|
558
|
+
_instanceof(v, IterateResult) ? v.values : v
|
|
559
|
+
];
|
|
560
|
+
}));
|
|
549
561
|
systemPrompt = (_params_system = params.system) !== null && _params_system !== void 0 ? _params_system : buildSystemPrompt(components, !!schema);
|
|
550
562
|
userPrompt = buildUserPrompt(prompt, data, schema);
|
|
551
563
|
// Create the validate_template tool
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Parse form data into a plain object, handling array fields.
|
|
3
|
-
* Extracts and strips the __positronic_token CSRF field.
|
|
4
3
|
* Supports:
|
|
5
4
|
* - name[] syntax for explicit arrays
|
|
6
5
|
* - Multiple values with same key (converted to array)
|
|
@@ -52,16 +51,10 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
52
51
|
}
|
|
53
52
|
export function parseFormData(formData) {
|
|
54
53
|
var result = {};
|
|
55
|
-
var token = null;
|
|
56
54
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
57
55
|
try {
|
|
58
56
|
for(var _iterator = formData.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
59
57
|
var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], value = _step_value[1];
|
|
60
|
-
// Extract CSRF token and exclude from response data
|
|
61
|
-
if (key === '__positronic_token') {
|
|
62
|
-
token = value;
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
58
|
// Handle array fields (e.g., name[] for multi-select)
|
|
66
59
|
if (key.endsWith('[]')) {
|
|
67
60
|
var baseKey = key.slice(0, -2);
|
|
@@ -95,8 +88,5 @@ export function parseFormData(formData) {
|
|
|
95
88
|
}
|
|
96
89
|
}
|
|
97
90
|
}
|
|
98
|
-
return
|
|
99
|
-
data: result,
|
|
100
|
-
token: token
|
|
101
|
-
};
|
|
91
|
+
return result;
|
|
102
92
|
}
|
package/dist/src/ui/types.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
function _array_like_to_array(arr, len) {
|
|
2
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
3
|
-
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
4
|
-
return arr2;
|
|
5
|
-
}
|
|
6
|
-
function _array_with_holes(arr) {
|
|
7
|
-
if (Array.isArray(arr)) return arr;
|
|
8
|
-
}
|
|
9
1
|
function _instanceof(left, right) {
|
|
10
2
|
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
11
3
|
return !!right[Symbol.hasInstance](left);
|
|
@@ -13,122 +5,7 @@ function _instanceof(left, right) {
|
|
|
13
5
|
return left instanceof right;
|
|
14
6
|
}
|
|
15
7
|
}
|
|
16
|
-
function _iterable_to_array_limit(arr, i) {
|
|
17
|
-
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
18
|
-
if (_i == null) return;
|
|
19
|
-
var _arr = [];
|
|
20
|
-
var _n = true;
|
|
21
|
-
var _d = false;
|
|
22
|
-
var _s, _e;
|
|
23
|
-
try {
|
|
24
|
-
for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
|
|
25
|
-
_arr.push(_s.value);
|
|
26
|
-
if (i && _arr.length === i) break;
|
|
27
|
-
}
|
|
28
|
-
} catch (err) {
|
|
29
|
-
_d = true;
|
|
30
|
-
_e = err;
|
|
31
|
-
} finally{
|
|
32
|
-
try {
|
|
33
|
-
if (!_n && _i["return"] != null) _i["return"]();
|
|
34
|
-
} finally{
|
|
35
|
-
if (_d) throw _e;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return _arr;
|
|
39
|
-
}
|
|
40
|
-
function _non_iterable_rest() {
|
|
41
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
42
|
-
}
|
|
43
|
-
function _sliced_to_array(arr, i) {
|
|
44
|
-
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
45
|
-
}
|
|
46
|
-
function _type_of(obj) {
|
|
47
|
-
"@swc/helpers - typeof";
|
|
48
|
-
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
49
|
-
}
|
|
50
|
-
function _unsupported_iterable_to_array(o, minLen) {
|
|
51
|
-
if (!o) return;
|
|
52
|
-
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
53
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
54
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
55
|
-
if (n === "Map" || n === "Set") return Array.from(n);
|
|
56
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
57
|
-
}
|
|
58
8
|
import { z } from 'zod';
|
|
59
|
-
/**
|
|
60
|
-
* Infer the DataType from a sample value.
|
|
61
|
-
*/ export function inferDataType(value) {
|
|
62
|
-
if (value === null) {
|
|
63
|
-
return {
|
|
64
|
-
kind: 'primitive',
|
|
65
|
-
type: 'null'
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
if (typeof value === 'string') {
|
|
69
|
-
return {
|
|
70
|
-
kind: 'primitive',
|
|
71
|
-
type: 'string'
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
if (typeof value === 'number') {
|
|
75
|
-
return {
|
|
76
|
-
kind: 'primitive',
|
|
77
|
-
type: 'number'
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
if (typeof value === 'boolean') {
|
|
81
|
-
return {
|
|
82
|
-
kind: 'primitive',
|
|
83
|
-
type: 'boolean'
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
if (Array.isArray(value)) {
|
|
87
|
-
if (value.length === 0) {
|
|
88
|
-
return {
|
|
89
|
-
kind: 'array',
|
|
90
|
-
elementType: {
|
|
91
|
-
kind: 'unknown'
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
// Infer from first element
|
|
96
|
-
return {
|
|
97
|
-
kind: 'array',
|
|
98
|
-
elementType: inferDataType(value[0])
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
if ((typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object') {
|
|
102
|
-
var properties = {};
|
|
103
|
-
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
104
|
-
try {
|
|
105
|
-
for(var _iterator = Object.entries(value)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
106
|
-
var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], val = _step_value[1];
|
|
107
|
-
properties[key] = inferDataType(val);
|
|
108
|
-
}
|
|
109
|
-
} catch (err) {
|
|
110
|
-
_didIteratorError = true;
|
|
111
|
-
_iteratorError = err;
|
|
112
|
-
} finally{
|
|
113
|
-
try {
|
|
114
|
-
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
115
|
-
_iterator.return();
|
|
116
|
-
}
|
|
117
|
-
} finally{
|
|
118
|
-
if (_didIteratorError) {
|
|
119
|
-
throw _iteratorError;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
kind: 'object',
|
|
125
|
-
properties: properties
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
kind: 'unknown'
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
9
|
/**
|
|
133
10
|
* Type guard to check if a schema is form-compatible at runtime.
|
|
134
11
|
* Used as a backup validation when TypeScript inference isn't sufficient.
|
|
@@ -366,32 +366,6 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
366
366
|
}
|
|
367
367
|
return current;
|
|
368
368
|
}
|
|
369
|
-
/**
|
|
370
|
-
* Summarize a value for LLM consumption.
|
|
371
|
-
* Keeps output compact — no full data dumps.
|
|
372
|
-
*/ export function summarizeValue(value) {
|
|
373
|
-
if (value === undefined) return 'undefined';
|
|
374
|
-
if (value === null) return 'null';
|
|
375
|
-
if (typeof value === 'string') {
|
|
376
|
-
if (value.length <= 60) return JSON.stringify(value);
|
|
377
|
-
return JSON.stringify(value.slice(0, 57) + '...');
|
|
378
|
-
}
|
|
379
|
-
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
380
|
-
return String(value);
|
|
381
|
-
}
|
|
382
|
-
if (Array.isArray(value)) {
|
|
383
|
-
if (value.length === 0) return 'Array(0) []';
|
|
384
|
-
var firstPreview = summarizeValue(value[0]);
|
|
385
|
-
return "Array(".concat(value.length, ") [").concat(firstPreview, ", ...]");
|
|
386
|
-
}
|
|
387
|
-
if ((typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object') {
|
|
388
|
-
var keys = Object.keys(value);
|
|
389
|
-
var keyPreview = keys.slice(0, 5).join(', ');
|
|
390
|
-
var suffix = keys.length > 5 ? ', ...' : '';
|
|
391
|
-
return "{ ".concat(keyPreview).concat(suffix, " } (").concat(keys.length, " keys)");
|
|
392
|
-
}
|
|
393
|
-
return String(value);
|
|
394
|
-
}
|
|
395
369
|
/**
|
|
396
370
|
* Walk the ComponentNode tree and resolve every binding against real data.
|
|
397
371
|
*
|
|
@@ -412,7 +386,6 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
412
386
|
path: propValue.path,
|
|
413
387
|
component: node.component,
|
|
414
388
|
prop: propName,
|
|
415
|
-
value: summarizeValue(value),
|
|
416
389
|
resolved: value !== undefined
|
|
417
390
|
});
|
|
418
391
|
}
|
|
@@ -114,7 +114,7 @@ export function inferTypeDescription(value) {
|
|
|
114
114
|
* @param indent - Current indentation level
|
|
115
115
|
* @returns Multi-line string describing the type with examples
|
|
116
116
|
*/ export function inferTypeWithExamples(value) {
|
|
117
|
-
var indent = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0;
|
|
117
|
+
var indent = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0, includeExamples = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : true;
|
|
118
118
|
var spaces = ' '.repeat(indent);
|
|
119
119
|
if (value === null) {
|
|
120
120
|
return 'null';
|
|
@@ -123,23 +123,23 @@ export function inferTypeDescription(value) {
|
|
|
123
123
|
return 'undefined';
|
|
124
124
|
}
|
|
125
125
|
if (typeof value === 'string') {
|
|
126
|
-
return "string // e.g., ".concat(formatExample(value));
|
|
126
|
+
return includeExamples ? "string // e.g., ".concat(formatExample(value)) : 'string';
|
|
127
127
|
}
|
|
128
128
|
if (typeof value === 'number') {
|
|
129
|
-
return "number // e.g., ".concat(value);
|
|
129
|
+
return includeExamples ? "number // e.g., ".concat(value) : 'number';
|
|
130
130
|
}
|
|
131
131
|
if (typeof value === 'boolean') {
|
|
132
|
-
return "boolean // e.g., ".concat(value);
|
|
132
|
+
return includeExamples ? "boolean // e.g., ".concat(value) : 'boolean';
|
|
133
133
|
}
|
|
134
134
|
if (Array.isArray(value)) {
|
|
135
135
|
if (value.length === 0) {
|
|
136
136
|
return 'unknown[] // empty array';
|
|
137
137
|
}
|
|
138
138
|
var firstElement = value[0];
|
|
139
|
-
var elementType = inferTypeWithExamples(firstElement, indent + 1);
|
|
139
|
+
var elementType = inferTypeWithExamples(firstElement, indent + 1, includeExamples);
|
|
140
140
|
// For primitive arrays, keep it compact
|
|
141
141
|
if (typeof firstElement === 'string' || typeof firstElement === 'number' || typeof firstElement === 'boolean') {
|
|
142
|
-
return "Array<".concat(inferTypeDescription(firstElement), "> // ").concat(value.length, " items, e.g., ").concat(formatExample(firstElement));
|
|
142
|
+
return includeExamples ? "Array<".concat(inferTypeDescription(firstElement), "> // ").concat(value.length, " items, e.g., ").concat(formatExample(firstElement)) : "Array<".concat(inferTypeDescription(firstElement), "> // ").concat(value.length, " items");
|
|
143
143
|
}
|
|
144
144
|
// For object arrays, show the structure
|
|
145
145
|
return "Array<".concat(elementType, "> // ").concat(value.length, " items");
|
|
@@ -156,7 +156,7 @@ export function inferTypeDescription(value) {
|
|
|
156
156
|
try {
|
|
157
157
|
for(var _iterator = entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
158
158
|
var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], val = _step_value[1];
|
|
159
|
-
var valType = inferTypeWithExamples(val, indent + 1);
|
|
159
|
+
var valType = inferTypeWithExamples(val, indent + 1, includeExamples);
|
|
160
160
|
lines.push("".concat(spaces, " ").concat(key, ": ").concat(valType));
|
|
161
161
|
}
|
|
162
162
|
} catch (err) {
|
|
@@ -205,6 +205,7 @@ export function inferTypeDescription(value) {
|
|
|
205
205
|
* // sessionId: string // e.g., "abc123"
|
|
206
206
|
* // }
|
|
207
207
|
* ```
|
|
208
|
-
*/ export function describeDataShape(data) {
|
|
209
|
-
|
|
208
|
+
*/ export function describeDataShape(data, options) {
|
|
209
|
+
var _options_includeExamples;
|
|
210
|
+
return inferTypeWithExamples(data, 0, (_options_includeExamples = options === null || options === void 0 ? void 0 : options.includeExamples) !== null && _options_includeExamples !== void 0 ? _options_includeExamples : true);
|
|
210
211
|
}
|