@engenty/wizards-runtime 0.0.0-stage → 0.7.5
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/LICENSE +110 -0
- package/README.md +214 -2
- package/apps/runtime/dist/agents/architect.js +444 -0
- package/apps/runtime/dist/agents/studio-assistant.js +883 -0
- package/apps/runtime/dist/agents/subscription.js +207 -0
- package/apps/runtime/dist/agents/thought.js +21 -0
- package/apps/runtime/dist/agents/website.js +480 -0
- package/apps/runtime/dist/app.js +359 -0
- package/apps/runtime/dist/apple/wizards-apple +0 -0
- package/apps/runtime/dist/assistant/browser.js +26 -0
- package/apps/runtime/dist/assistant/docs.js +158 -0
- package/apps/runtime/dist/assistant/knows.js +353 -0
- package/apps/runtime/dist/assistant/primer.js +26 -0
- package/apps/runtime/dist/assistant/runs.js +24 -0
- package/apps/runtime/dist/auth/account.js +175 -0
- package/apps/runtime/dist/auth/device.js +112 -0
- package/apps/runtime/dist/auth/index.js +358 -0
- package/apps/runtime/dist/auth/keys.js +55 -0
- package/apps/runtime/dist/auth/local-ticket.js +26 -0
- package/apps/runtime/dist/authoring/example.js +74 -0
- package/apps/runtime/dist/authoring/guide.js +433 -0
- package/apps/runtime/dist/authoring/ops.js +117 -0
- package/apps/runtime/dist/browser/fast/action-space.js +160 -0
- package/apps/runtime/dist/browser/fast/classifier.js +91 -0
- package/apps/runtime/dist/browser/fast/decide.js +171 -0
- package/apps/runtime/dist/browser/fast/driver.js +141 -0
- package/apps/runtime/dist/browser/fast/instructions.js +33 -0
- package/apps/runtime/dist/browser/fast/run.js +249 -0
- package/apps/runtime/dist/browser/fast/span-picker.js +153 -0
- package/apps/runtime/dist/browser/fast/text-helper.js +178 -0
- package/apps/runtime/dist/browser/snapshot.js +335 -0
- package/apps/runtime/dist/cli/account.js +385 -0
- package/apps/runtime/dist/cli/autostart.js +182 -0
- package/apps/runtime/dist/cli/autoupdate.js +221 -0
- package/apps/runtime/dist/cli/clients.js +44 -0
- package/apps/runtime/dist/cli/connect.js +540 -0
- package/apps/runtime/dist/cli/environment.js +93 -0
- package/apps/runtime/dist/cli/exec.js +45 -0
- package/apps/runtime/dist/cli/features.js +50 -0
- package/apps/runtime/dist/cli/home.js +88 -0
- package/apps/runtime/dist/cli/install-env.js +33 -0
- package/apps/runtime/dist/cli/machine.js +107 -0
- package/apps/runtime/dist/cli/main.js +222 -0
- package/apps/runtime/dist/cli/mcp.js +136 -0
- package/apps/runtime/dist/cli/menu.js +202 -0
- package/apps/runtime/dist/cli/processes.js +72 -0
- package/apps/runtime/dist/cli/report.js +66 -0
- package/apps/runtime/dist/cli/setup.js +335 -0
- package/apps/runtime/dist/cli/start.js +276 -0
- package/apps/runtime/dist/cli/status.js +203 -0
- package/apps/runtime/dist/cli/ui.js +59 -0
- package/apps/runtime/dist/cli/uninstall-main.js +20 -0
- package/apps/runtime/dist/cli/uninstall.js +231 -0
- package/apps/runtime/dist/cli/update.js +86 -0
- package/apps/runtime/dist/cli/validate.js +75 -0
- package/apps/runtime/dist/cli/versions.js +123 -0
- package/apps/runtime/dist/connectors/builtin.js +86 -0
- package/apps/runtime/dist/connectors/external.js +409 -0
- package/apps/runtime/dist/connectors/gmail.js +107 -0
- package/apps/runtime/dist/connectors/imap.js +261 -0
- package/apps/runtime/dist/connectors/index.js +325 -0
- package/apps/runtime/dist/connectors/mail.js +72 -0
- package/apps/runtime/dist/connectors/outlook.js +90 -0
- package/apps/runtime/dist/connectors/plugin-connections.js +343 -0
- package/apps/runtime/dist/connectors/via-account.js +65 -0
- package/apps/runtime/dist/credits/credits.js +100 -0
- package/apps/runtime/dist/credits/estimate.js +152 -0
- package/apps/runtime/dist/db/adopt.js +149 -0
- package/apps/runtime/dist/db/client.js +173 -0
- package/apps/runtime/dist/db/control-schema.js +133 -0
- package/apps/runtime/dist/db/migrations/control/0000_last_absorbing_man.sql +47 -0
- package/apps/runtime/dist/db/migrations/control/0001_gorgeous_nicolaos.sql +41 -0
- package/apps/runtime/dist/db/migrations/control/0002_secret_penance.sql +1 -0
- package/apps/runtime/dist/db/migrations/control/0003_nasty_mordo.sql +3 -0
- package/apps/runtime/dist/db/migrations/control/0004_breezy_eddie_brock.sql +6 -0
- package/apps/runtime/dist/db/migrations/control/0005_chilly_oracle.sql +1 -0
- package/apps/runtime/dist/db/migrations/control/0006_sleepy_mojo.sql +1 -0
- package/apps/runtime/dist/db/migrations/control/0007_common_the_hand.sql +15 -0
- package/apps/runtime/dist/db/migrations/control/0008_runner.sql +8 -0
- package/apps/runtime/dist/db/migrations/control/0009_plugin_claim.sql +9 -0
- package/apps/runtime/dist/db/migrations/control/0010_tan_snowbird.sql +6 -0
- package/apps/runtime/dist/db/migrations/control/meta/0000_snapshot.json +311 -0
- package/apps/runtime/dist/db/migrations/control/meta/0001_snapshot.json +599 -0
- package/apps/runtime/dist/db/migrations/control/meta/0002_snapshot.json +607 -0
- package/apps/runtime/dist/db/migrations/control/meta/0003_snapshot.json +311 -0
- package/apps/runtime/dist/db/migrations/control/meta/0004_snapshot.json +350 -0
- package/apps/runtime/dist/db/migrations/control/meta/0005_snapshot.json +358 -0
- package/apps/runtime/dist/db/migrations/control/meta/0006_snapshot.json +365 -0
- package/apps/runtime/dist/db/migrations/control/meta/0007_snapshot.json +460 -0
- package/apps/runtime/dist/db/migrations/control/meta/0008_snapshot.json +505 -0
- package/apps/runtime/dist/db/migrations/control/meta/0009_snapshot.json +561 -0
- package/apps/runtime/dist/db/migrations/control/meta/0010_snapshot.json +600 -0
- package/apps/runtime/dist/db/migrations/control/meta/_journal.json +83 -0
- package/apps/runtime/dist/db/migrations/tenant/0000_eminent_freak.sql +188 -0
- package/apps/runtime/dist/db/migrations/tenant/0001_salty_master_chief.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0002_cloudy_firebird.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0003_brown_warbound.sql +52 -0
- package/apps/runtime/dist/db/migrations/tenant/0004_romantic_nocturne.sql +6 -0
- package/apps/runtime/dist/db/migrations/tenant/0005_reflective_forgotten_one.sql +2 -0
- package/apps/runtime/dist/db/migrations/tenant/0006_hard_war_machine.sql +30 -0
- package/apps/runtime/dist/db/migrations/tenant/0007_space_data.sql +43 -0
- package/apps/runtime/dist/db/migrations/tenant/0008_run_event_note.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0009_knowledge.sql +104 -0
- package/apps/runtime/dist/db/migrations/tenant/0010_plugin_connection.sql +15 -0
- package/apps/runtime/dist/db/migrations/tenant/0011_runners.sql +2 -0
- package/apps/runtime/dist/db/migrations/tenant/0012_assistant_chat.sql +40 -0
- package/apps/runtime/dist/db/migrations/tenant/0013_run_origin.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0014_run_answer.sql +2 -0
- package/apps/runtime/dist/db/migrations/tenant/0015_device_calls.sql +13 -0
- package/apps/runtime/dist/db/migrations/tenant/0016_even_trish_tilby.sql +12 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0000_snapshot.json +1323 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0001_snapshot.json +1330 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0002_snapshot.json +1337 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0003_snapshot.json +1605 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0004_snapshot.json +1645 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0005_snapshot.json +1659 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0006_snapshot.json +1696 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0007_snapshot.json +2012 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0008_snapshot.json +2019 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0009_snapshot.json +2837 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0010_snapshot.json +2942 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0011_snapshot.json +2956 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0012_snapshot.json +3132 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0013_snapshot.json +3139 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0014_snapshot.json +3154 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0015_snapshot.json +3243 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0016_snapshot.json +3326 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +125 -0
- package/apps/runtime/dist/db/schema.js +602 -0
- package/apps/runtime/dist/debug.js +196 -0
- package/apps/runtime/dist/docs/dev/index.md +41 -0
- package/apps/runtime/dist/docs/dev/meta.json +7 -0
- package/apps/runtime/dist/docs/dev/plugins/connections.md +74 -0
- package/apps/runtime/dist/docs/dev/plugins/events.md +89 -0
- package/apps/runtime/dist/docs/dev/plugins/examples.md +101 -0
- package/apps/runtime/dist/docs/dev/plugins/index.md +78 -0
- package/apps/runtime/dist/docs/dev/plugins/layout.md +90 -0
- package/apps/runtime/dist/docs/dev/plugins/meta.json +28 -0
- package/apps/runtime/dist/docs/dev/plugins/quick-start.md +94 -0
- package/apps/runtime/dist/docs/dev/plugins/reference.md +348 -0
- package/apps/runtime/dist/docs/dev/plugins/reloading.md +76 -0
- package/apps/runtime/dist/docs/dev/plugins/routes.md +185 -0
- package/apps/runtime/dist/docs/dev/plugins/runners.md +230 -0
- package/apps/runtime/dist/docs/dev/plugins/server.md +281 -0
- package/apps/runtime/dist/docs/dev/plugins/shipping.md +79 -0
- package/apps/runtime/dist/docs/dev/plugins/space.md +297 -0
- package/apps/runtime/dist/docs/dev/plugins/starters.md +70 -0
- package/apps/runtime/dist/docs/dev/plugins/studio.md +363 -0
- package/apps/runtime/dist/docs/dev/plugins/styling.md +129 -0
- package/apps/runtime/dist/docs/dev/plugins/tables.md +104 -0
- package/apps/runtime/dist/docs/dev/plugins/tools.md +139 -0
- package/apps/runtime/dist/docs/dev/wizard-format.md +125 -0
- package/apps/runtime/dist/docs/meta.json +3 -0
- package/apps/runtime/dist/docs/user/ai-apps.md +112 -0
- package/apps/runtime/dist/docs/user/assistant.md +77 -0
- package/apps/runtime/dist/docs/user/build-a-wizard.md +116 -0
- package/apps/runtime/dist/docs/user/command-line.md +83 -0
- package/apps/runtime/dist/docs/user/connectors.md +90 -0
- package/apps/runtime/dist/docs/user/create-account.md +52 -0
- package/apps/runtime/dist/docs/user/data.md +66 -0
- package/apps/runtime/dist/docs/user/first-start.md +60 -0
- package/apps/runtime/dist/docs/user/index.md +49 -0
- package/apps/runtime/dist/docs/user/install.md +123 -0
- package/apps/runtime/dist/docs/user/local-only.md +42 -0
- package/apps/runtime/dist/docs/user/meta.json +32 -0
- package/apps/runtime/dist/docs/user/models.md +156 -0
- package/apps/runtime/dist/docs/user/plugins.md +71 -0
- package/apps/runtime/dist/docs/user/run.md +98 -0
- package/apps/runtime/dist/docs/user/server.md +52 -0
- package/apps/runtime/dist/docs/user/space.md +126 -0
- package/apps/runtime/dist/docs/user/steps.md +220 -0
- package/apps/runtime/dist/docs/user/test-and-share.md +224 -0
- package/apps/runtime/dist/docs/user/troubleshooting.md +67 -0
- package/apps/runtime/dist/docs/user/wordpress.md +121 -0
- package/apps/runtime/dist/documents/parse.js +246 -0
- package/apps/runtime/dist/engenty/connections-external/build-connector.js +193 -0
- package/apps/runtime/dist/engenty/connections-external/errors.js +11 -0
- package/apps/runtime/dist/engenty/connections-external/import-service.js +270 -0
- package/apps/runtime/dist/engenty/connections-external/importer/classify.js +34 -0
- package/apps/runtime/dist/engenty/connections-external/importer/map-auth.js +185 -0
- package/apps/runtime/dist/engenty/connections-external/importer/normalize-mcp.js +63 -0
- package/apps/runtime/dist/engenty/connections-external/importer/normalize-openapi.js +130 -0
- package/apps/runtime/dist/engenty/connections-external/invoke/http-invoker.js +143 -0
- package/apps/runtime/dist/engenty/connections-external/invoke/mcp-client.js +143 -0
- package/apps/runtime/dist/engenty/connections-external/net/guarded-fetch.js +119 -0
- package/apps/runtime/dist/engenty/connections-external/oauth-dcr.js +88 -0
- package/apps/runtime/dist/engenty/connections-external/registry-client.js +336 -0
- package/apps/runtime/dist/engenty/connections-external/registry-source.js +82 -0
- package/apps/runtime/dist/engenty/connections-external/types.js +7 -0
- package/apps/runtime/dist/engenty/connections-github/connector.js +209 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/calendar.js +381 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/contacts.js +94 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/drive.js +290 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/gmail.js +567 -0
- package/apps/runtime/dist/engenty/connections-google/definitions.js +11 -0
- package/apps/runtime/dist/engenty/connections-google/shared.js +73 -0
- package/apps/runtime/dist/engenty/connections-hubspot/connector.js +140 -0
- package/apps/runtime/dist/engenty/connections-microsoft/action.js +17 -0
- package/apps/runtime/dist/engenty/connections-microsoft/graph.js +114 -0
- package/apps/runtime/dist/engenty/connections-microsoft/onedrive.js +286 -0
- package/apps/runtime/dist/engenty/connections-microsoft/outlook.js +492 -0
- package/apps/runtime/dist/engenty/connections-s3/s3.js +328 -0
- package/apps/runtime/dist/engenty/connections-sdk/files-capability.js +86 -0
- package/apps/runtime/dist/engenty/connections-sdk/oauth2.js +150 -0
- package/apps/runtime/dist/engenty/connections-sdk/registry.js +89 -0
- package/apps/runtime/dist/engenty/connections-sdk/storage-capability.js +84 -0
- package/apps/runtime/dist/engenty/connections-sdk/types.js +30 -0
- package/apps/runtime/dist/engenty/connections-slack/connector.js +360 -0
- package/apps/runtime/dist/engenty/csv-import/csv-matrix.js +178 -0
- package/apps/runtime/dist/engenty/csv-import/import-sources.js +87 -0
- package/apps/runtime/dist/engenty/csv-import/parse-csv.js +129 -0
- package/apps/runtime/dist/engenty/csv-import/serialize-csv.js +20 -0
- package/apps/runtime/dist/engenty/csv-import/types.js +1 -0
- package/apps/runtime/dist/engenty/csv-import/xlsx-workbook.js +159 -0
- package/apps/runtime/dist/engenty/doc-converter/interface.js +9 -0
- package/apps/runtime/dist/engenty/doc-converter/page-break.js +92 -0
- package/apps/runtime/dist/engenty/doc-converter/providers/local/index.js +72 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/classifier.js +30 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/index.js +4 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/invoice.js +73 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/receipt.js +63 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/shared.js +40 -0
- package/apps/runtime/dist/engenty/search-index/chunks.js +164 -0
- package/apps/runtime/dist/engenty/search-index/contracts.js +9 -0
- package/apps/runtime/dist/engenty/shims/connections-sdk.js +39 -0
- package/apps/runtime/dist/engenty/shims/plugin-sdk.js +1 -0
- package/apps/runtime/dist/engenty/shims/web-ingest.js +19 -0
- package/apps/runtime/dist/engenty/web-ingest/ssrf.js +277 -0
- package/apps/runtime/dist/engine/asks.js +82 -0
- package/apps/runtime/dist/engine/decide.js +82 -0
- package/apps/runtime/dist/engine/device.js +194 -0
- package/apps/runtime/dist/engine/events.js +128 -0
- package/apps/runtime/dist/engine/input.js +208 -0
- package/apps/runtime/dist/engine/owner.js +32 -0
- package/apps/runtime/dist/engine/prepare.js +90 -0
- package/apps/runtime/dist/engine/push.js +58 -0
- package/apps/runtime/dist/engine/requirements.js +355 -0
- package/apps/runtime/dist/engine/resources.js +198 -0
- package/apps/runtime/dist/engine/runner.js +970 -0
- package/apps/runtime/dist/engine/steps.js +1000 -0
- package/apps/runtime/dist/engine/surface.js +91 -0
- package/apps/runtime/dist/engine/template.js +240 -0
- package/apps/runtime/dist/engine/types.js +4 -0
- package/apps/runtime/dist/env.js +295 -0
- package/apps/runtime/dist/features.js +123 -0
- package/apps/runtime/dist/files/blobs.js +22 -0
- package/apps/runtime/dist/files/objects.js +86 -0
- package/apps/runtime/dist/files/storage.js +120 -0
- package/apps/runtime/dist/files/web-images.js +101 -0
- package/apps/runtime/dist/film/project.js +257 -0
- package/apps/runtime/dist/film/skills.js +91 -0
- package/apps/runtime/dist/film/sounds.js +122 -0
- package/apps/runtime/dist/film/step.js +289 -0
- package/apps/runtime/dist/film/tools.js +99 -0
- package/apps/runtime/dist/geocode.js +58 -0
- package/apps/runtime/dist/harness/antigravity.js +129 -0
- package/apps/runtime/dist/harness/apple.js +270 -0
- package/apps/runtime/dist/harness/claude.js +147 -0
- package/apps/runtime/dist/harness/codex.js +229 -0
- package/apps/runtime/dist/harness/cursor.js +93 -0
- package/apps/runtime/dist/harness/env.js +124 -0
- package/apps/runtime/dist/harness/index.js +95 -0
- package/apps/runtime/dist/harness/model.js +279 -0
- package/apps/runtime/dist/harness/prompt.js +121 -0
- package/apps/runtime/dist/harness/terminal.js +194 -0
- package/apps/runtime/dist/harness/types.js +7 -0
- package/apps/runtime/dist/index.js +113 -0
- package/apps/runtime/dist/limits.js +81 -0
- package/apps/runtime/dist/link-preview.js +60 -0
- package/apps/runtime/dist/log.js +106 -0
- package/apps/runtime/dist/manage.js +249 -0
- package/apps/runtime/dist/mcp/auth.js +161 -0
- package/apps/runtime/dist/mcp/bridge.js +59 -0
- package/apps/runtime/dist/mcp/flow-app.js +97 -0
- package/apps/runtime/dist/mcp/handler.js +54 -0
- package/apps/runtime/dist/mcp/scopes.js +14 -0
- package/apps/runtime/dist/mcp/seen.js +65 -0
- package/apps/runtime/dist/mcp/tools.js +572 -0
- package/apps/runtime/dist/media/conversation.js +167 -0
- package/apps/runtime/dist/media/ffmpeg.js +121 -0
- package/apps/runtime/dist/media/generate.js +120 -0
- package/apps/runtime/dist/media/marking.js +121 -0
- package/apps/runtime/dist/media/transcribe.js +198 -0
- package/apps/runtime/dist/model-errors.js +42 -0
- package/apps/runtime/dist/models.js +1164 -0
- package/apps/runtime/dist/plugin.js +61 -0
- package/apps/runtime/dist/plugins/channels.js +78 -0
- package/apps/runtime/dist/plugins/claims.js +56 -0
- package/apps/runtime/dist/plugins/discovery.js +155 -0
- package/apps/runtime/dist/plugins/events.js +63 -0
- package/apps/runtime/dist/plugins/jobs.js +64 -0
- package/apps/runtime/dist/plugins/loader.js +508 -0
- package/apps/runtime/dist/plugins/migrations.js +69 -0
- package/apps/runtime/dist/plugins/pro-keys.js +34 -0
- package/apps/runtime/dist/plugins/pro-state.js +83 -0
- package/apps/runtime/dist/plugins/pro.js +310 -0
- package/apps/runtime/dist/plugins/public.js +44 -0
- package/apps/runtime/dist/plugins/registry.js +122 -0
- package/apps/runtime/dist/plugins/runs.js +210 -0
- package/apps/runtime/dist/render/browser-path.js +54 -0
- package/apps/runtime/dist/render/chromium.js +98 -0
- package/apps/runtime/dist/render/convert.js +158 -0
- package/apps/runtime/dist/render/downloads.js +299 -0
- package/apps/runtime/dist/render/guard.js +25 -0
- package/apps/runtime/dist/render/shaped.js +137 -0
- package/apps/runtime/dist/routes/api.js +440 -0
- package/apps/runtime/dist/routes/debug.js +42 -0
- package/apps/runtime/dist/routes/delivery.js +90 -0
- package/apps/runtime/dist/routes/internal.js +81 -0
- package/apps/runtime/dist/routes/lang.js +25 -0
- package/apps/runtime/dist/routes/marketplace.js +43 -0
- package/apps/runtime/dist/routes/plugin-public.js +113 -0
- package/apps/runtime/dist/routes/plugins.js +212 -0
- package/apps/runtime/dist/routes/runs.js +1422 -0
- package/apps/runtime/dist/routes/studio.js +1629 -0
- package/apps/runtime/dist/routes/wizard-stream.js +30 -0
- package/apps/runtime/dist/running.js +39 -0
- package/apps/runtime/dist/sandbox/docker.js +75 -0
- package/apps/runtime/dist/sandbox/index.js +23 -0
- package/apps/runtime/dist/sandbox/types.js +1 -0
- package/apps/runtime/dist/secrets/crypto.js +28 -0
- package/apps/runtime/dist/secrets/signing.js +52 -0
- package/apps/runtime/dist/secrets/vault.js +59 -0
- package/apps/runtime/dist/services/access.js +88 -0
- package/apps/runtime/dist/services/api.js +248 -0
- package/apps/runtime/dist/services/architect.js +95 -0
- package/apps/runtime/dist/services/assistant-chats.js +311 -0
- package/apps/runtime/dist/services/brand.js +85 -0
- package/apps/runtime/dist/services/cloud.js +456 -0
- package/apps/runtime/dist/services/draft-events.js +27 -0
- package/apps/runtime/dist/services/engenty-shapes.js +71 -0
- package/apps/runtime/dist/services/errors.js +29 -0
- package/apps/runtime/dist/services/files.js +178 -0
- package/apps/runtime/dist/services/knowledge-model.js +559 -0
- package/apps/runtime/dist/services/knowledge.js +721 -0
- package/apps/runtime/dist/services/links.js +16 -0
- package/apps/runtime/dist/services/marketplace.js +492 -0
- package/apps/runtime/dist/services/onboarding.js +152 -0
- package/apps/runtime/dist/services/package-file.js +82 -0
- package/apps/runtime/dist/services/package.js +170 -0
- package/apps/runtime/dist/services/profile.js +51 -0
- package/apps/runtime/dist/services/project-files.js +439 -0
- package/apps/runtime/dist/services/project-index.js +707 -0
- package/apps/runtime/dist/services/projects.js +387 -0
- package/apps/runtime/dist/services/relevance.js +58 -0
- package/apps/runtime/dist/services/runners.js +178 -0
- package/apps/runtime/dist/services/runs.js +524 -0
- package/apps/runtime/dist/services/shares.js +130 -0
- package/apps/runtime/dist/services/site.js +270 -0
- package/apps/runtime/dist/services/space-categories.js +861 -0
- package/apps/runtime/dist/services/space-data.js +792 -0
- package/apps/runtime/dist/services/space-origin.js +207 -0
- package/apps/runtime/dist/services/spaces.js +656 -0
- package/apps/runtime/dist/services/translations.js +306 -0
- package/apps/runtime/dist/services/widgets.js +34 -0
- package/apps/runtime/dist/services/wizard-icon.js +157 -0
- package/apps/runtime/dist/services/wizards.js +420 -0
- package/apps/runtime/dist/settings.js +16 -0
- package/apps/runtime/dist/store/errors.js +4 -0
- package/apps/runtime/dist/store/index.js +299 -0
- package/apps/runtime/dist/store/shared-lists.js +123 -0
- package/apps/runtime/dist/tenants/control.js +238 -0
- package/apps/runtime/dist/tenants/tenant.js +26 -0
- package/apps/runtime/dist/texts.js +207 -0
- package/apps/runtime/dist/tools/browser.js +703 -0
- package/apps/runtime/dist/tools/connector.js +204 -0
- package/apps/runtime/dist/tools/index.js +291 -0
- package/apps/runtime/dist/tools/mail.js +104 -0
- package/apps/runtime/dist/tools/net-guard.js +170 -0
- package/apps/runtime/dist/tools/pages.js +81 -0
- package/apps/runtime/dist/tools/plugin.js +180 -0
- package/apps/runtime/dist/tools/project.js +154 -0
- package/apps/runtime/dist/tools/shared.js +69 -0
- package/apps/runtime/dist/tools/store.js +238 -0
- package/apps/runtime/dist/update.js +113 -0
- package/apps/runtime/dist/widgets/bundle.js +99 -0
- package/apps/runtime/dist/widgets/render.js +329 -0
- package/apps/runtime/dist/widgets/runtime.js +108 -0
- package/apps/runtime/dist/widgets/script.js +30 -0
- package/apps/runtime/dist/widgets/step.js +223 -0
- package/apps/web/dist/ai-labels/ai-black.svg +20 -0
- package/apps/web/dist/ai-labels/ai-generated-black.svg +31 -0
- package/apps/web/dist/ai-labels/ai-generated-white.svg +32 -0
- package/apps/web/dist/ai-labels/ai-modified-black.svg +30 -0
- package/apps/web/dist/ai-labels/ai-modified-white.svg +31 -0
- package/apps/web/dist/ai-labels/ai-white.svg +21 -0
- package/apps/web/dist/assets/AboutDialog-D4mvc-zu.js +1 -0
- package/apps/web/dist/assets/ChangelogDialog-DLqpJsF6.js +1 -0
- package/apps/web/dist/assets/ChatView-3laypRcE.js +10 -0
- package/apps/web/dist/assets/EditorPage-BalA5U2Y.js +3 -0
- package/apps/web/dist/assets/FlowPreview-CusP7ci9.js +1 -0
- package/apps/web/dist/assets/Harness-BrP-ENHg.css +1 -0
- package/apps/web/dist/assets/Harness-iYLtOLaK.js +16 -0
- package/apps/web/dist/assets/NewWizardChannels-CbwJ9A56.js +1 -0
- package/apps/web/dist/assets/NewWizardPage-BOBYiB9i.js +7 -0
- package/apps/web/dist/assets/OnboardingPage-CUwCiVIr.js +1 -0
- package/apps/web/dist/assets/ProjectPage-Bb16MdYG.js +1 -0
- package/apps/web/dist/assets/PublicRunner-BCt7Q6C-.js +1 -0
- package/apps/web/dist/assets/ReadOnly-kIHX2TEy.js +1 -0
- package/apps/web/dist/assets/RunDrawer-hZ9oeSXu.js +4 -0
- package/apps/web/dist/assets/RunnerView-DUS9fPmx.js +1 -0
- package/apps/web/dist/assets/SettingsPage-BzwR50fi.js +1 -0
- package/apps/web/dist/assets/SetupPage-gAp7rPxp.js +1 -0
- package/apps/web/dist/assets/SharePage-DqZWHva_.js +1 -0
- package/apps/web/dist/assets/changelog-DugmCNSf.js +1 -0
- package/apps/web/dist/assets/engenty-eXZ-EAwd.js +1 -0
- package/apps/web/dist/assets/esm-DXeMu8Lb.js +7 -0
- package/apps/web/dist/assets/fluffy-engenty-ClRou7yu.js +456 -0
- package/apps/web/dist/assets/index-AfUa8xKD.css +1 -0
- package/apps/web/dist/assets/index-C5Sm7tTR.js +14 -0
- package/apps/web/dist/assets/jsx-runtime-BNakU3Ej.js +1 -0
- package/apps/web/dist/assets/lock-R_CfU0Xo.js +1 -0
- package/apps/web/dist/assets/oss-credits-cZ9NUaLZ.js +1 -0
- package/apps/web/dist/assets/pdfmake-Cx9scTbD.js +228 -0
- package/apps/web/dist/assets/phone-CgrIS4_-.js +1 -0
- package/apps/web/dist/assets/preload-helper-CNEI7N0N.js +1 -0
- package/apps/web/dist/assets/qr-scanner-worker.min-CJaXo3yu.js +98 -0
- package/apps/web/dist/assets/qr-scanner.min-C_UI0gH-.js +1 -0
- package/apps/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/apps/web/dist/assets/settings-menu-2IMOOlLl.js +1 -0
- package/apps/web/dist/assets/ui-dzGvc3xk.js +137 -0
- package/apps/web/dist/assets/upload-BSuTilFF.js +1 -0
- package/apps/web/dist/assets/vfs_fonts-DllDSYt1.js +1 -0
- package/apps/web/dist/embed.js +266 -0
- package/apps/web/dist/favicon.svg +1 -0
- package/apps/web/dist/icons/apple-touch-icon.png +0 -0
- package/apps/web/dist/icons/icon-192.png +0 -0
- package/apps/web/dist/icons/icon-512.png +0 -0
- package/apps/web/dist/icons/icon-maskable-512.png +0 -0
- package/apps/web/dist/index.html +48 -0
- package/apps/web/dist/install.sh +577 -0
- package/apps/web/dist/manifest.webmanifest +21 -0
- package/apps/web/dist/mcp/flow.html +980 -0
- package/apps/web/dist/sw.js +15 -0
- package/bin/wizards.mjs +288 -0
- package/modules/README.md +15 -0
- package/node_modules/@engenty/wizards/dist/plugin/index.d.ts +1150 -0
- package/node_modules/@engenty/wizards/dist/plugin/index.js +4 -0
- package/node_modules/@engenty/wizards/dist/plugin/studio.d.ts +322 -0
- package/node_modules/@engenty/wizards/dist/plugin/studio.js +4 -0
- package/node_modules/@engenty/wizards/dist/plugin/thread.d.ts +174 -0
- package/node_modules/@engenty/wizards/dist/plugin/thread.js +821 -0
- package/node_modules/@engenty/wizards/package.json +11 -0
- package/node_modules/@engenty-wizards/shared/dist/assistant.d.ts +174 -0
- package/node_modules/@engenty-wizards/shared/dist/assistant.js +65 -0
- package/node_modules/@engenty-wizards/shared/dist/changes.d.ts +22 -0
- package/node_modules/@engenty-wizards/shared/dist/changes.js +61 -0
- package/node_modules/@engenty-wizards/shared/dist/connectors.d.ts +77 -0
- package/node_modules/@engenty-wizards/shared/dist/connectors.js +2 -0
- package/node_modules/@engenty-wizards/shared/dist/decision.d.ts +76 -0
- package/node_modules/@engenty-wizards/shared/dist/decision.js +147 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +2922 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.js +1920 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.d.ts +5 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.js +132 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.d.ts +11 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.js +209 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.d.ts +532 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.js +217 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.d.ts +3 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.js +3 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.d.ts +14 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.js +166 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.d.ts +33 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.js +99 -0
- package/node_modules/@engenty-wizards/shared/dist/feature-flags.d.ts +78 -0
- package/node_modules/@engenty-wizards/shared/dist/feature-flags.js +70 -0
- package/node_modules/@engenty-wizards/shared/dist/features.d.ts +41 -0
- package/node_modules/@engenty-wizards/shared/dist/features.js +89 -0
- package/node_modules/@engenty-wizards/shared/dist/fit.d.ts +71 -0
- package/node_modules/@engenty-wizards/shared/dist/fit.js +382 -0
- package/node_modules/@engenty-wizards/shared/dist/json-schema.d.ts +14 -0
- package/node_modules/@engenty-wizards/shared/dist/json-schema.js +66 -0
- package/node_modules/@engenty-wizards/shared/dist/knowledge.d.ts +199 -0
- package/node_modules/@engenty-wizards/shared/dist/knowledge.js +68 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +35 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +107 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.d.ts +20 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +136 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +227 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.js +354 -0
- package/node_modules/@engenty-wizards/shared/dist/merge.d.ts +7 -0
- package/node_modules/@engenty-wizards/shared/dist/merge.js +40 -0
- package/node_modules/@engenty-wizards/shared/dist/numbers.d.ts +24 -0
- package/node_modules/@engenty-wizards/shared/dist/numbers.js +54 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +224 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.js +319 -0
- package/node_modules/@engenty-wizards/shared/dist/providers.d.ts +101 -0
- package/node_modules/@engenty-wizards/shared/dist/providers.js +390 -0
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +680 -0
- package/node_modules/@engenty-wizards/shared/dist/run.js +620 -0
- package/node_modules/@engenty-wizards/shared/dist/runner-texts.d.ts +546 -0
- package/node_modules/@engenty-wizards/shared/dist/runner-texts.js +523 -0
- package/node_modules/@engenty-wizards/shared/dist/runners.d.ts +93 -0
- package/node_modules/@engenty-wizards/shared/dist/runners.js +146 -0
- package/node_modules/@engenty-wizards/shared/dist/shape.d.ts +102 -0
- package/node_modules/@engenty-wizards/shared/dist/shape.js +318 -0
- package/node_modules/@engenty-wizards/shared/dist/space-data.d.ts +89 -0
- package/node_modules/@engenty-wizards/shared/dist/space-data.js +47 -0
- package/node_modules/@engenty-wizards/shared/dist/store.d.ts +117 -0
- package/node_modules/@engenty-wizards/shared/dist/store.js +81 -0
- package/node_modules/@engenty-wizards/shared/dist/surface.d.ts +115 -0
- package/node_modules/@engenty-wizards/shared/dist/surface.js +442 -0
- package/node_modules/@engenty-wizards/shared/dist/texts.d.ts +45 -0
- package/node_modules/@engenty-wizards/shared/dist/texts.js +54 -0
- package/node_modules/@engenty-wizards/shared/dist/translation.d.ts +23 -0
- package/node_modules/@engenty-wizards/shared/dist/translation.js +154 -0
- package/node_modules/@engenty-wizards/shared/dist/wizard-package.d.ts +48 -0
- package/node_modules/@engenty-wizards/shared/dist/wizard-package.js +49 -0
- package/node_modules/@engenty-wizards/shared/dist/workspace.d.ts +16 -0
- package/node_modules/@engenty-wizards/shared/dist/workspace.js +51 -0
- package/node_modules/@engenty-wizards/shared/package.json +10 -0
- package/package.json +77 -4
- package/plugin/.claude-plugin/plugin.json +9 -0
- package/plugin/.mcp.json +8 -0
- package/plugin/commands/wizard.md +8 -0
- package/plugin/skills/build-wizard/SKILL.md +27 -0
- package/plugin/skills/use-wizard/SKILL.md +18 -0
|
@@ -0,0 +1,883 @@
|
|
|
1
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
2
|
+
import { cleanAssetSections, cleanLogoSections, FACT_TYPES, FONT_USES, factKey, gradientCss, PROJECT_FILE_KINDS, PROJECT_LIMITS, parseGradient, RULE_MARKS, textStyleLine, } from "@engenty-wizards/shared/projects";
|
|
3
|
+
import { Agent } from "@mastra/core/agent";
|
|
4
|
+
import { createTool } from "@mastra/core/tools";
|
|
5
|
+
import { nanoid } from "nanoid";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { knowsTools } from "../assistant/knows.js";
|
|
8
|
+
import { PRIMER } from "../assistant/primer.js";
|
|
9
|
+
import { currentFeatures } from "../features.js";
|
|
10
|
+
import { agentModel, attachTools, contextWindowOf, costOf, gatewayTools, textModel, totalUsage, usageOf, } from "../models.js";
|
|
11
|
+
import { knowledgeCounts } from "../services/knowledge.js";
|
|
12
|
+
import { addProjectFileFromUrl, projectFileContent, projectFiles, updateProjectFile, } from "../services/project-files.js";
|
|
13
|
+
import { documentText } from "../services/project-index.js";
|
|
14
|
+
import { ownedProject, updateProject } from "../services/projects.js";
|
|
15
|
+
import { categoryRows } from "../services/space-categories.js";
|
|
16
|
+
import { currentTenant } from "../tenants/tenant.js";
|
|
17
|
+
import { serverText } from "../texts.js";
|
|
18
|
+
import { assistantPageOf, assistantToolsOf } from "../tools/plugin.js";
|
|
19
|
+
import { attempt as attemptTool, imageOutput } from "../tools/shared.js";
|
|
20
|
+
import { readWebsite } from "./website.js";
|
|
21
|
+
/** How a message written meanwhile reaches the model. */
|
|
22
|
+
export function signalText(taken) {
|
|
23
|
+
return `The person wrote this while you were working. What they asked before still stands unless this changes it:\n\n${taken.map((s) => s.message).join("\n\n")}`;
|
|
24
|
+
}
|
|
25
|
+
const MAX_STEPS = 24;
|
|
26
|
+
const SYSTEM = `You are Goose, the assistant of the engenty wizards studio. You stand on every page of the studio except the wizard editor, which has a chat of its own: the space's pages, the settings, the plugins' pages. You help the person who works here understand the app, set it up and find their way.
|
|
27
|
+
|
|
28
|
+
You talk to the person. Answer in their language, briefly and warmly: a few sentences, a short list where it helps. Never mention JSON, ids, keys or tool names. Call it a space, never a project: the tools say project, the app says space. Name the studio's parts and pages as the studio shows them in the person's language.
|
|
29
|
+
|
|
30
|
+
${PRIMER}
|
|
31
|
+
|
|
32
|
+
WHAT YOU KNOW
|
|
33
|
+
- How the app works: from the guides of this installed version. Before you explain how something works, docs_search (and docs_read a page); link the page you used (engenty.ai/docs/…). How wizards are written: authoring_guide. Never guess at a menu, a button or a feature.
|
|
34
|
+
- Live data only from tools, never from memory: gallery_search / gallery_detail for templates, plans for plans and prices, account for the person, team, plan and credits, usage for what was spent, wizards and runs for the space, models for what thinks and makes here.
|
|
35
|
+
- Templates you recommend or talk about: show_templates them, in your order, with your answer. The cards show title, pitch, time, cost and formats: your text says in a line why each fits, never repeats what the card shows.
|
|
36
|
+
- You never buy, upgrade, top up or change a plan or a setting that costs money. Explain it, then open the page where the person does it (navigate, or give the billing page's link).
|
|
37
|
+
- Earlier chats: their summaries come with every message. chats_search and chat_read find more when the person refers to something said before.
|
|
38
|
+
|
|
39
|
+
THE PAGE
|
|
40
|
+
- Every message comes with the page the person writes from: its address, title, the section in view, an open item, what is selected, a line on what it holds and its fields. Answer about what they see; "this" and "here" mean that page.
|
|
41
|
+
- In the browser you may: navigate (open a studio page), highlight (dim the page except one element, or ring it, with a short card), look_at_page (what is visible: headings, buttons, fields with their values), read_section (one area in full), fill_field (put a value into a field, not saved), scroll_to. A page may add tools of its own (filter its list, show a week): use them to show what you talk about. A page you open during an answer brings its tools too: navigate and look_at_page list them, page_tool runs them. Targets are what look_at_page lists.
|
|
42
|
+
- Show rather than describe: open the page and highlight the place when the person asks where or how. look_at_page first when you are not sure what is there.
|
|
43
|
+
- fill_field never saves: say that the person checks and saves. You never press buttons for the person.
|
|
44
|
+
|
|
45
|
+
THE SPACE
|
|
46
|
+
- Where a space's tools are there, you also fill the space in: what every wizard of the space draws on — who they are (title, about), the brand (logos, colours), assets (images, graphics, videos), documents, and facts (label → value: address, VAT ID, phone, opening hours — anything). The space as it is now comes with every message then; you change it ONLY through tools.
|
|
47
|
+
- A website: read_website it first. You get the page's text, colours from its stylesheet, logo candidates and the links to imprint / contact / about. Read those pages too (at most four more) for address, VAT ID, register number, phone, email, bank details, who runs it.
|
|
48
|
+
- Facts: one fact per thing, a short label in the person's language ("Adresse", "USt-IdNr.", "Telefon"), the value on one line where it fits. Only what a source or the person states — never guess, never invent. Keep the facts that are there; a fact with a known label is updated.
|
|
49
|
+
- About: two to five sentences — what they do, for whom, what sets them apart, the tone they write in. Rewrite it only when you learned something new or the person asks.
|
|
50
|
+
- Colours: two to six, the main one first, each with a name that says what it is for ("Primär", "Hintergrund", "Text"). Take them from the stylesheet's variables or its most used colours, never from photos. set_colors replaces the list: pass all colours that should remain. Colours in no section are the standard ones; the first of them is the accent. Colour sections are optional like logo sections: only for a further palette a brand guide or the person names for its own use ("Illustration – drawings and charts"), never for the standard colours. A brand's gradients (set_gradients, as CSS) only where a brand guide or the site's stylesheet has them; patterns and background fills are pictures the person uploads.
|
|
51
|
+
- Logos: save the best candidate (an SVG or a large PNG rather than a favicon); a second one only if it truly differs (for dark ground, a signet). A few images that show the business (header, team, products) may be saved as assets — a handful, never everything.
|
|
52
|
+
- Logo sections and rules are optional, and most spaces need neither. Logos in no section are the standard ones; the first of them is the main logo. Add a section (set_logo_sections) only for further variants that a brand guide, a brand or press page or the person says are used elsewhere: the title names the variant ("Logomark", "Wordmark"), the description says when to use it ("Small spaces: app icons, favicons"). The standard logos never go into a section; one logo, or a light and a dark one whose descriptions already tell them apart, get no sections. Rules (set_rules, for the logos, the colours or the type) are short rows, one rule each, with a sign: do ("Keep clear space of the mark's height on all sides"), dont ("Place it on photos"), important, question (something to check with the person), number (steps in order), or none for a plain note (minimum size, file formats). Only what such a source or the person states; never invent rules and never write general advice a brand guide did not say.
|
|
53
|
+
- Typography: the brand's fonts (set_typography), each with what it is for ("Headings", "Body text") and the weights it uses — from the website's stylesheet (read_website lists its fonts) or a brand guide; system and generic faces are no brand fonts. A font's licence and what it may be used for (web, documents, print, images, video) only where a brand guide, the font's own page or the person says so; the wizards keep to it. A type scale (text styles: name, size, weight, line height, letter spacing) only when a brand guide gives one.
|
|
54
|
+
- Asset sections are optional too: tabs of one kind each ("Icons", "Background images"), made with set_asset_sections only when the space holds enough assets of clearly different kinds or the person asks; a handful of pictures stay in the general tab.
|
|
55
|
+
- Files the person attached are stored already; the message names them. look_at_file shows you a picture or a document's text. Give a file a description with describe_file when it has none or the person says what it is. Take facts from a document when asked.
|
|
56
|
+
- Knowledge is what the wizards' steps look things up in: pages, tables and files, kept apart by typed categories. Documents the person attaches are read into Knowledge by themselves: say so; do not copy their text into facts unless asked. A website, a sitemap or a folder whose entries should go into Knowledge is a source: where a tool proposes sources, use it (the person takes the proposal on its card); where there is none, say that sources need the Sources plugin.
|
|
57
|
+
- Talking from another page than Info & brand, change title, about, logos, colours and facts only when the person asks.
|
|
58
|
+
- A space that is read-only (synced from a local install, or a team that builds elsewhere) has no tools: say where it is changed.
|
|
59
|
+
|
|
60
|
+
HOW YOU WORK
|
|
61
|
+
- Call independent tools together. Work in few steps.
|
|
62
|
+
- Finish with one to three sentences: what you did or found, what is still open, and at most one question.`;
|
|
63
|
+
const LABELS = {
|
|
64
|
+
save_logo: "doingSaveLogo",
|
|
65
|
+
save_file: "doingSaveFile",
|
|
66
|
+
set_logo_sections: "doingSetLogoSections",
|
|
67
|
+
set_asset_sections: "doingSetAssetSections",
|
|
68
|
+
set_typography: "doingSetTypography",
|
|
69
|
+
set_gradients: "doingSetGradients",
|
|
70
|
+
set_rules: "doingSetRules",
|
|
71
|
+
set_profile: "doingSetProfile",
|
|
72
|
+
set_facts: "doingSetFacts",
|
|
73
|
+
set_colors: "doingSetColors",
|
|
74
|
+
look_at_file: "doingLookAtFile",
|
|
75
|
+
describe_file: "doingDescribeFile",
|
|
76
|
+
web_search: "doingWebSearch",
|
|
77
|
+
};
|
|
78
|
+
function activity(tool, args, lang) {
|
|
79
|
+
const host = (u) => {
|
|
80
|
+
try {
|
|
81
|
+
return new URL(/^https?:/i.test(String(u)) ? String(u) : `https://${u}`).hostname;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return "";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
if (tool === "read_website") {
|
|
88
|
+
const at = args.url ? host(args.url) : "";
|
|
89
|
+
return at
|
|
90
|
+
? serverText(lang, "doingReadSite", { host: at })
|
|
91
|
+
: serverText(lang, "doingReadWebsite");
|
|
92
|
+
}
|
|
93
|
+
const key = tool === "save_file" && args.kind === "logo"
|
|
94
|
+
? "save_logo"
|
|
95
|
+
: tool === "remove_facts"
|
|
96
|
+
? "set_facts"
|
|
97
|
+
: tool;
|
|
98
|
+
return LABELS[key] ? serverText(lang, LABELS[key]) : null;
|
|
99
|
+
}
|
|
100
|
+
/** A tool failure the model can read and fix, instead of a crashed turn: the whole message. */
|
|
101
|
+
const attempt = (run) => attemptTool(run, { limit: Number.POSITIVE_INFINITY });
|
|
102
|
+
async function projectState(userId, projectId) {
|
|
103
|
+
const p = await ownedProject(userId, projectId);
|
|
104
|
+
const files = await projectFiles(projectId);
|
|
105
|
+
const categories = await categoryRows(projectId);
|
|
106
|
+
return {
|
|
107
|
+
knowledge: {
|
|
108
|
+
...(await knowledgeCounts(projectId)),
|
|
109
|
+
categories: categories.map((c) => `${c.name} (${c.type}${c.proposed ? ", proposed" : ""})`),
|
|
110
|
+
},
|
|
111
|
+
title: p.brand.name ?? "",
|
|
112
|
+
about: p.brand.about ?? "",
|
|
113
|
+
colors: (p.brand.colors ?? []).map(({ name, value, section }) => {
|
|
114
|
+
const s = p.brand.colorSections?.find((x) => x.id === section);
|
|
115
|
+
return { name, value, ...(s ? { section: s.title } : {}) };
|
|
116
|
+
}),
|
|
117
|
+
// Optional parts are only there when the space has them.
|
|
118
|
+
...(p.brand.colorSections?.length
|
|
119
|
+
? {
|
|
120
|
+
colorSections: p.brand.colorSections.map(({ title, kind }) => ({
|
|
121
|
+
title,
|
|
122
|
+
kind: kind ?? "colors",
|
|
123
|
+
})),
|
|
124
|
+
}
|
|
125
|
+
: {}),
|
|
126
|
+
...(p.brand.gradients?.length
|
|
127
|
+
? {
|
|
128
|
+
gradients: p.brand.gradients.map((g) => ({
|
|
129
|
+
name: g.name,
|
|
130
|
+
...(g.description ? { description: g.description } : {}),
|
|
131
|
+
section: p.brand.colorSections?.find((s) => s.id === g.section)?.title,
|
|
132
|
+
css: gradientCss(g),
|
|
133
|
+
})),
|
|
134
|
+
}
|
|
135
|
+
: {}),
|
|
136
|
+
...(p.brand.patterns?.length
|
|
137
|
+
? {
|
|
138
|
+
patterns: p.brand.patterns.map((x) => ({
|
|
139
|
+
name: x.name,
|
|
140
|
+
...(x.description ? { description: x.description } : {}),
|
|
141
|
+
section: p.brand.colorSections?.find((s) => s.id === x.section)?.title,
|
|
142
|
+
tile: Boolean(x.tile),
|
|
143
|
+
})),
|
|
144
|
+
}
|
|
145
|
+
: {}),
|
|
146
|
+
...(p.brand.logoSections?.length
|
|
147
|
+
? {
|
|
148
|
+
logoSections: p.brand.logoSections.map(({ title, description, logos }) => ({
|
|
149
|
+
title,
|
|
150
|
+
description,
|
|
151
|
+
logos,
|
|
152
|
+
})),
|
|
153
|
+
}
|
|
154
|
+
: {}),
|
|
155
|
+
...(p.brand.assetSections?.length
|
|
156
|
+
? {
|
|
157
|
+
assetSections: p.brand.assetSections.map(({ title, assets }) => ({ title, assets })),
|
|
158
|
+
}
|
|
159
|
+
: {}),
|
|
160
|
+
...(p.brand.fonts?.length
|
|
161
|
+
? {
|
|
162
|
+
fonts: p.brand.fonts.map(({ family, role, weights, license, uses }) => ({
|
|
163
|
+
family,
|
|
164
|
+
role,
|
|
165
|
+
weights,
|
|
166
|
+
...(license ? { license } : {}),
|
|
167
|
+
...(uses?.length ? { uses } : {}),
|
|
168
|
+
})),
|
|
169
|
+
}
|
|
170
|
+
: {}),
|
|
171
|
+
...(p.brand.textStyles?.length
|
|
172
|
+
? {
|
|
173
|
+
textStyles: p.brand.textStyles.map((s) => ({
|
|
174
|
+
name: s.name,
|
|
175
|
+
style: textStyleLine(s, p.brand.fonts ?? []),
|
|
176
|
+
})),
|
|
177
|
+
}
|
|
178
|
+
: {}),
|
|
179
|
+
...(p.brand.logoRules ? { logoRules: p.brand.logoRules } : {}),
|
|
180
|
+
...(p.brand.colorRules ? { colorRules: p.brand.colorRules } : {}),
|
|
181
|
+
...(p.brand.typeRules ? { typeRules: p.brand.typeRules } : {}),
|
|
182
|
+
facts: p.facts.map(({ label, value }) => ({ label, value })),
|
|
183
|
+
files: files.map((f) => ({
|
|
184
|
+
id: f.id,
|
|
185
|
+
kind: f.kind,
|
|
186
|
+
name: f.name,
|
|
187
|
+
description: f.description,
|
|
188
|
+
...(f.status === "ready" ? {} : { status: f.status }),
|
|
189
|
+
})),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function spaceTools(input, project, wrote, on) {
|
|
193
|
+
const { signal } = input;
|
|
194
|
+
const userId = input.user.id;
|
|
195
|
+
const projectId = project.id;
|
|
196
|
+
// Said from inside the tool: an installed AI client runs tools without the stream showing it.
|
|
197
|
+
const doing = (tool, args = {}) => {
|
|
198
|
+
const label = activity(tool, args, input.lang);
|
|
199
|
+
if (label) {
|
|
200
|
+
input.onActivity?.(label);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
// Tools of one step run together; writes to the project's row take turns.
|
|
204
|
+
let turn = Promise.resolve();
|
|
205
|
+
const inTurn = (run) => {
|
|
206
|
+
const next = turn.then(run, run);
|
|
207
|
+
turn = next.catch(() => undefined);
|
|
208
|
+
return next;
|
|
209
|
+
};
|
|
210
|
+
const tools = {
|
|
211
|
+
read_website: createTool({
|
|
212
|
+
id: "read_website",
|
|
213
|
+
description: "Read a public web page: its text as Markdown, the colours of its stylesheet (named variables and the most used ones), logo candidates and images with their addresses, and the links to imprint, contact and about pages.",
|
|
214
|
+
inputSchema: z.object({ url: z.string().describe("The page's address") }),
|
|
215
|
+
execute: ({ url }) => {
|
|
216
|
+
doing("read_website", { url });
|
|
217
|
+
return attempt(() => readWebsite(url, signal));
|
|
218
|
+
},
|
|
219
|
+
}),
|
|
220
|
+
set_profile: createTool({
|
|
221
|
+
id: "set_profile",
|
|
222
|
+
description: "Set the project's title (the company, brand or undertaking) and/or its about text.",
|
|
223
|
+
inputSchema: z.object({
|
|
224
|
+
title: z.string().max(120).optional(),
|
|
225
|
+
about: z.string().max(8000).optional(),
|
|
226
|
+
}),
|
|
227
|
+
execute: ({ title, about }) => attempt(() => inTurn(async () => {
|
|
228
|
+
doing("set_profile");
|
|
229
|
+
await updateProject(userId, projectId, {
|
|
230
|
+
brand: {
|
|
231
|
+
...(title !== undefined ? { name: title } : {}),
|
|
232
|
+
...(about !== undefined ? { about } : {}),
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
wrote();
|
|
236
|
+
return { ok: true };
|
|
237
|
+
})),
|
|
238
|
+
}),
|
|
239
|
+
set_facts: createTool({
|
|
240
|
+
id: "set_facts",
|
|
241
|
+
description: "Add facts to the project, or update the ones whose label is already there. A fact is a label and a value.",
|
|
242
|
+
inputSchema: z.object({
|
|
243
|
+
facts: z
|
|
244
|
+
.array(z.object({
|
|
245
|
+
label: z.string().min(1).max(80),
|
|
246
|
+
value: z.string().min(1).max(4000),
|
|
247
|
+
type: z.enum(FACT_TYPES).optional().describe("Only when the value's look misleads"),
|
|
248
|
+
}))
|
|
249
|
+
.min(1),
|
|
250
|
+
}),
|
|
251
|
+
execute: ({ facts }) => attempt(() => inTurn(async () => {
|
|
252
|
+
doing("set_facts");
|
|
253
|
+
const p = await ownedProject(userId, projectId);
|
|
254
|
+
const next = [...p.facts];
|
|
255
|
+
for (const f of facts) {
|
|
256
|
+
const label = f.label.trim();
|
|
257
|
+
const at = next.findIndex((x) => x.label.toLowerCase() === label.toLowerCase());
|
|
258
|
+
if (at >= 0) {
|
|
259
|
+
next[at] = { ...next[at], value: f.value.trim(), type: f.type ?? next[at].type };
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
const key = factKey(label, next.map((x) => x.key));
|
|
263
|
+
next.push({
|
|
264
|
+
key,
|
|
265
|
+
label,
|
|
266
|
+
value: f.value.trim(),
|
|
267
|
+
...(f.type ? { type: f.type } : {}),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (next.length > PROJECT_LIMITS.facts) {
|
|
272
|
+
throw new Error(`A project holds at most ${PROJECT_LIMITS.facts} facts.`);
|
|
273
|
+
}
|
|
274
|
+
await updateProject(userId, projectId, { facts: next });
|
|
275
|
+
wrote();
|
|
276
|
+
return { ok: true, facts: next.length };
|
|
277
|
+
})),
|
|
278
|
+
}),
|
|
279
|
+
remove_facts: createTool({
|
|
280
|
+
id: "remove_facts",
|
|
281
|
+
description: "Remove facts by their labels. Only when the admin asks or a fact is wrong.",
|
|
282
|
+
inputSchema: z.object({ labels: z.array(z.string()).min(1) }),
|
|
283
|
+
execute: ({ labels }) => attempt(() => inTurn(async () => {
|
|
284
|
+
doing("remove_facts");
|
|
285
|
+
const p = await ownedProject(userId, projectId);
|
|
286
|
+
const gone = new Set(labels.map((l) => l.trim().toLowerCase()));
|
|
287
|
+
const next = p.facts.filter((f) => !gone.has(f.label.toLowerCase()));
|
|
288
|
+
await updateProject(userId, projectId, { facts: next });
|
|
289
|
+
wrote();
|
|
290
|
+
return { ok: true, removed: p.facts.length - next.length };
|
|
291
|
+
})),
|
|
292
|
+
}),
|
|
293
|
+
set_colors: createTool({
|
|
294
|
+
id: "set_colors",
|
|
295
|
+
description: "Set the brand's colours — the whole list, the main colour first. Values as #rrggbb. Optional: `sections` for a further palette of its own use (its title), and on a colour the `section` title it belongs to; colours without one are the standard ones. Without `sections` the space keeps its sections.",
|
|
296
|
+
inputSchema: z.object({
|
|
297
|
+
colors: z
|
|
298
|
+
.array(z.object({
|
|
299
|
+
name: z.string().max(120),
|
|
300
|
+
value: z.string().regex(/^#[0-9a-fA-F]{6}$/),
|
|
301
|
+
section: z.string().max(80).optional().describe("A section's title"),
|
|
302
|
+
}))
|
|
303
|
+
.max(PROJECT_LIMITS.colors),
|
|
304
|
+
sections: z
|
|
305
|
+
.array(z.object({ title: z.string().min(1).max(80) }))
|
|
306
|
+
.max(PROJECT_LIMITS.logoSections)
|
|
307
|
+
.optional(),
|
|
308
|
+
}),
|
|
309
|
+
execute: ({ colors, sections }) => attempt(() => inTurn(async () => {
|
|
310
|
+
doing("set_colors");
|
|
311
|
+
if (!on.brandSections && (sections || colors.some((c) => c.section))) {
|
|
312
|
+
throw new Error("Colour sections are not available in this studio: pass the colours without them.");
|
|
313
|
+
}
|
|
314
|
+
const p = await ownedProject(userId, projectId);
|
|
315
|
+
const groups = sections
|
|
316
|
+
? sections.map((s) => ({
|
|
317
|
+
id: p.brand.colorSections?.find((x) => x.title === s.title)?.id ?? nanoid(10),
|
|
318
|
+
...s,
|
|
319
|
+
}))
|
|
320
|
+
: (p.brand.colorSections ?? []);
|
|
321
|
+
const unknown = colors.filter((c) => c.section && !groups.some((s) => s.title === c.section));
|
|
322
|
+
if (unknown.length) {
|
|
323
|
+
throw new Error(`No colour section named: ${unknown.map((c) => c.section).join(", ")}`);
|
|
324
|
+
}
|
|
325
|
+
await updateProject(userId, projectId, {
|
|
326
|
+
brand: {
|
|
327
|
+
colors: colors.map(({ section, ...c }) => {
|
|
328
|
+
const id = groups.find((s) => s.title === section)?.id;
|
|
329
|
+
return { ...c, value: c.value.toLowerCase(), ...(id ? { section: id } : {}) };
|
|
330
|
+
}),
|
|
331
|
+
colorSections: groups,
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
wrote();
|
|
335
|
+
return { ok: true };
|
|
336
|
+
})),
|
|
337
|
+
}),
|
|
338
|
+
set_logo_sections: createTool({
|
|
339
|
+
id: "set_logo_sections",
|
|
340
|
+
description: "Optional. Put further logo variants into sections, each with a title and when to use it (Logomark, Wordmark, Monochrome). Logos in no section are the standard ones and come first — never put those into a section. Use it only when a brand guide, a brand page or the person says a variant is used elsewhere — one logo or two plain variants need none. Replaces all sections: pass every section that should remain, an empty list removes them.",
|
|
341
|
+
inputSchema: z.object({
|
|
342
|
+
sections: z
|
|
343
|
+
.array(z.object({
|
|
344
|
+
title: z.string().min(1).max(80).describe("The variant: Logomark, Wordmark, …"),
|
|
345
|
+
description: z
|
|
346
|
+
.string()
|
|
347
|
+
.max(400)
|
|
348
|
+
.describe("When to use these logos, in the person's language"),
|
|
349
|
+
logos: z.array(z.string()).describe("Ids of the space's logo files, in order"),
|
|
350
|
+
}))
|
|
351
|
+
.max(PROJECT_LIMITS.logoSections),
|
|
352
|
+
}),
|
|
353
|
+
execute: ({ sections }) => attempt(() => inTurn(async () => {
|
|
354
|
+
doing("set_logo_sections");
|
|
355
|
+
const logos = (await projectFiles(projectId, "logo")).map((f) => f.id);
|
|
356
|
+
const unknown = sections.flatMap((s) => s.logos).filter((id) => !logos.includes(id));
|
|
357
|
+
if (unknown.length) {
|
|
358
|
+
throw new Error(`Not a logo of this space: ${unknown.join(", ")}`);
|
|
359
|
+
}
|
|
360
|
+
await updateProject(userId, projectId, {
|
|
361
|
+
brand: {
|
|
362
|
+
logoSections: cleanLogoSections(sections.map((s) => ({ ...s, id: nanoid(10) })), logos),
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
wrote();
|
|
366
|
+
return { ok: true };
|
|
367
|
+
})),
|
|
368
|
+
}),
|
|
369
|
+
set_asset_sections: createTool({
|
|
370
|
+
id: "set_asset_sections",
|
|
371
|
+
description: "Optional. Sort the space's assets into sections, each shown as a tab named by its title (Icons, Background images, Team photos). Assets in no section stay in the general tab. Use it only when there are enough assets of clearly different kinds, or the person asks. Replaces all sections: pass every section that should remain, an empty list removes them.",
|
|
372
|
+
inputSchema: z.object({
|
|
373
|
+
sections: z
|
|
374
|
+
.array(z.object({
|
|
375
|
+
title: z.string().min(1).max(80),
|
|
376
|
+
assets: z.array(z.string()).describe("Ids of the space's asset files, in order"),
|
|
377
|
+
}))
|
|
378
|
+
.max(PROJECT_LIMITS.logoSections),
|
|
379
|
+
}),
|
|
380
|
+
execute: ({ sections }) => attempt(() => inTurn(async () => {
|
|
381
|
+
doing("set_asset_sections");
|
|
382
|
+
const assets = (await projectFiles(projectId, "asset")).map((f) => f.id);
|
|
383
|
+
const unknown = sections.flatMap((s) => s.assets).filter((id) => !assets.includes(id));
|
|
384
|
+
if (unknown.length) {
|
|
385
|
+
throw new Error(`Not an asset of this space: ${unknown.join(", ")}`);
|
|
386
|
+
}
|
|
387
|
+
await updateProject(userId, projectId, {
|
|
388
|
+
brand: {
|
|
389
|
+
assetSections: cleanAssetSections(sections.map((s) => ({ ...s, id: nanoid(10) })), assets),
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
wrote();
|
|
393
|
+
return { ok: true };
|
|
394
|
+
})),
|
|
395
|
+
}),
|
|
396
|
+
set_typography: createTool({
|
|
397
|
+
id: "set_typography",
|
|
398
|
+
description: "Set the brand's fonts — the whole list, the main one first — each with what it is for, its weights and, where a source says so, its licence and what it may be used for. Optional: `textStyles`, the type scale a brand guide gives (name, font family, size px, weight, line height %, letter spacing %); without it the space keeps its text styles.",
|
|
399
|
+
inputSchema: z.object({
|
|
400
|
+
fonts: z
|
|
401
|
+
.array(z.object({
|
|
402
|
+
family: z.string().min(1).max(80),
|
|
403
|
+
role: z.string().max(200).describe("What it is for, in the person's language"),
|
|
404
|
+
weights: z.array(z.number().int().min(100).max(900)).max(9),
|
|
405
|
+
license: z
|
|
406
|
+
.string()
|
|
407
|
+
.max(200)
|
|
408
|
+
.optional()
|
|
409
|
+
.describe("The licence, only where a source names it: 'SIL Open Font License'"),
|
|
410
|
+
uses: z
|
|
411
|
+
.array(z.enum(FONT_USES))
|
|
412
|
+
.optional()
|
|
413
|
+
.describe("All the licence allows it for, only where a source says so"),
|
|
414
|
+
}))
|
|
415
|
+
.max(PROJECT_LIMITS.fonts),
|
|
416
|
+
textStyles: z
|
|
417
|
+
.array(z.object({
|
|
418
|
+
name: z.string().min(1).max(60),
|
|
419
|
+
family: z.string().max(80).optional().describe("One of the fonts; none: the first"),
|
|
420
|
+
size: z.number().min(6).max(400),
|
|
421
|
+
weight: z.number().int().min(100).max(900),
|
|
422
|
+
lineHeight: z.number().min(50).max(300).describe("% of the size"),
|
|
423
|
+
tracking: z.number().min(-20).max(50).describe("Letter spacing, % of the size"),
|
|
424
|
+
uppercase: z.boolean().optional(),
|
|
425
|
+
}))
|
|
426
|
+
.max(PROJECT_LIMITS.textStyles)
|
|
427
|
+
.optional(),
|
|
428
|
+
}),
|
|
429
|
+
execute: ({ fonts, textStyles }) => attempt(() => inTurn(async () => {
|
|
430
|
+
doing("set_typography");
|
|
431
|
+
const p = await ownedProject(userId, projectId);
|
|
432
|
+
const faces = fonts.map((f) => ({
|
|
433
|
+
...f,
|
|
434
|
+
id: p.brand.fonts?.find((x) => x.family === f.family)?.id ?? nanoid(10),
|
|
435
|
+
}));
|
|
436
|
+
await updateProject(userId, projectId, {
|
|
437
|
+
brand: {
|
|
438
|
+
fonts: faces,
|
|
439
|
+
...(textStyles
|
|
440
|
+
? {
|
|
441
|
+
textStyles: textStyles.map(({ family, ...s }) => ({
|
|
442
|
+
...s,
|
|
443
|
+
id: nanoid(10),
|
|
444
|
+
font: faces.find((f) => f.family === family)?.id,
|
|
445
|
+
})),
|
|
446
|
+
}
|
|
447
|
+
: {}),
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
wrote();
|
|
451
|
+
return { ok: true };
|
|
452
|
+
})),
|
|
453
|
+
}),
|
|
454
|
+
set_gradients: createTool({
|
|
455
|
+
id: "set_gradients",
|
|
456
|
+
description: "Optional. Set the brand's gradients, as a brand guide or the site's stylesheet gives them: each with a name, when to use it where the source says so, and its CSS (linear-, radial- or conic-gradient with hex stops). They go into a gradients section, made when there is none with that title. Replaces the gradients of that section.",
|
|
457
|
+
inputSchema: z.object({
|
|
458
|
+
section: z.string().min(1).max(80).describe("The gradients section's title"),
|
|
459
|
+
gradients: z
|
|
460
|
+
.array(z.object({
|
|
461
|
+
name: z.string().min(1).max(80),
|
|
462
|
+
description: z.string().max(400).optional().describe("When to use it"),
|
|
463
|
+
css: z.string().max(1000),
|
|
464
|
+
}))
|
|
465
|
+
.max(PROJECT_LIMITS.gradients),
|
|
466
|
+
}),
|
|
467
|
+
execute: ({ section, gradients }) => attempt(() => inTurn(async () => {
|
|
468
|
+
doing("set_gradients");
|
|
469
|
+
const p = await ownedProject(userId, projectId);
|
|
470
|
+
const sections = p.brand.colorSections ?? [];
|
|
471
|
+
const found = sections.find((s) => s.title === section && s.kind === "gradients");
|
|
472
|
+
const id = found?.id ?? nanoid(10);
|
|
473
|
+
const parsed = gradients.map((g) => ({ g, read: parseGradient(g.css) }));
|
|
474
|
+
const bad = parsed.filter((x) => !x.read).map((x) => x.g.name);
|
|
475
|
+
if (bad.length) {
|
|
476
|
+
throw new Error(`Not a gradient with hex stops: ${bad.join(", ")}`);
|
|
477
|
+
}
|
|
478
|
+
await updateProject(userId, projectId, {
|
|
479
|
+
brand: {
|
|
480
|
+
colorSections: found
|
|
481
|
+
? sections
|
|
482
|
+
: [...sections, { id, title: section, kind: "gradients" }],
|
|
483
|
+
gradients: [
|
|
484
|
+
...(p.brand.gradients ?? []).filter((g) => g.section !== id),
|
|
485
|
+
...parsed.map(({ g, read }) => ({
|
|
486
|
+
id: nanoid(10),
|
|
487
|
+
name: g.name,
|
|
488
|
+
...(g.description ? { description: g.description } : {}),
|
|
489
|
+
section: id,
|
|
490
|
+
...read,
|
|
491
|
+
})),
|
|
492
|
+
],
|
|
493
|
+
},
|
|
494
|
+
});
|
|
495
|
+
wrote();
|
|
496
|
+
return { ok: true };
|
|
497
|
+
})),
|
|
498
|
+
}),
|
|
499
|
+
set_rules: createTool({
|
|
500
|
+
id: "set_rules",
|
|
501
|
+
description: "Optional. Set how the logos, the colours or the type may be used: one short rule per row, with its sign (do, dont, important, question, number; none for a plain note). Only rules a brand guide, the website or the person states — never invented ones, never general advice. Replaces that list; an empty list removes it.",
|
|
502
|
+
inputSchema: z.object({
|
|
503
|
+
of: z.enum(["logos", "colors", "type"]),
|
|
504
|
+
rules: z
|
|
505
|
+
.array(z.object({
|
|
506
|
+
text: z.string().min(1).max(200),
|
|
507
|
+
mark: z
|
|
508
|
+
.enum(RULE_MARKS)
|
|
509
|
+
.optional()
|
|
510
|
+
.describe("do, dont, important, question, number; none for a plain note"),
|
|
511
|
+
}))
|
|
512
|
+
.max(PROJECT_LIMITS.logoRules),
|
|
513
|
+
}),
|
|
514
|
+
execute: ({ of, rules }) => attempt(() => inTurn(async () => {
|
|
515
|
+
doing("set_rules");
|
|
516
|
+
await updateProject(userId, projectId, {
|
|
517
|
+
brand: of === "logos"
|
|
518
|
+
? { logoRules: rules }
|
|
519
|
+
: of === "colors"
|
|
520
|
+
? { colorRules: rules }
|
|
521
|
+
: { typeRules: rules },
|
|
522
|
+
});
|
|
523
|
+
wrote();
|
|
524
|
+
return { ok: true };
|
|
525
|
+
})),
|
|
526
|
+
}),
|
|
527
|
+
save_file: createTool({
|
|
528
|
+
id: "save_file",
|
|
529
|
+
description: "Fetch a file from a public address into the project: a logo, an asset (image, graphic, video) or a document (PDF, Word, Excel, CSV, text). Documents are read and indexed afterwards.",
|
|
530
|
+
inputSchema: z.object({
|
|
531
|
+
url: z.string(),
|
|
532
|
+
kind: z.enum(PROJECT_FILE_KINDS),
|
|
533
|
+
description: z
|
|
534
|
+
.string()
|
|
535
|
+
.max(600)
|
|
536
|
+
.optional()
|
|
537
|
+
.describe("One sentence: what it shows or holds, and what it suits"),
|
|
538
|
+
}),
|
|
539
|
+
execute: ({ url, kind, description }) => attempt(async () => {
|
|
540
|
+
doing("save_file", { kind });
|
|
541
|
+
const row = await addProjectFileFromUrl(projectId, { url, kind, description, signal });
|
|
542
|
+
wrote();
|
|
543
|
+
return { ok: true, id: row.id, name: row.name, mime: row.mime, size: row.size };
|
|
544
|
+
}),
|
|
545
|
+
}),
|
|
546
|
+
describe_file: createTool({
|
|
547
|
+
id: "describe_file",
|
|
548
|
+
description: "Set the description of one of the project's files.",
|
|
549
|
+
inputSchema: z.object({ id: z.string(), description: z.string().max(600) }),
|
|
550
|
+
execute: ({ id, description }) => attempt(async () => {
|
|
551
|
+
doing("describe_file");
|
|
552
|
+
await updateProjectFile(projectId, id, { description });
|
|
553
|
+
wrote();
|
|
554
|
+
return { ok: true };
|
|
555
|
+
}),
|
|
556
|
+
}),
|
|
557
|
+
look_at_file: createTool({
|
|
558
|
+
id: "look_at_file",
|
|
559
|
+
description: "Look at one of the project's files: a picture is shown to you, a document comes as text.",
|
|
560
|
+
inputSchema: z.object({
|
|
561
|
+
id: z.string(),
|
|
562
|
+
from: z.number().int().min(0).optional().describe("Documents: character to start at"),
|
|
563
|
+
}),
|
|
564
|
+
execute: ({ id, from }) => attempt(async () => {
|
|
565
|
+
doing("look_at_file");
|
|
566
|
+
const { row, data } = await projectFileContent(projectId, id);
|
|
567
|
+
if (row.kind === "document") {
|
|
568
|
+
const text = await documentText(row);
|
|
569
|
+
if (!text) {
|
|
570
|
+
return { name: row.name, note: `The document is not read yet (${row.status}).` };
|
|
571
|
+
}
|
|
572
|
+
const start = Math.min(from ?? 0, text.length);
|
|
573
|
+
return {
|
|
574
|
+
name: row.name,
|
|
575
|
+
text: text.slice(start, start + 12_000),
|
|
576
|
+
next: start + 12_000 < text.length ? start + 12_000 : null,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
if (!/^image\/(png|jpeg|webp|gif)$/.test(row.mime) || data.byteLength > 5_000_000) {
|
|
580
|
+
return { name: row.name, mime: row.mime, note: "This file cannot be shown to you." };
|
|
581
|
+
}
|
|
582
|
+
return { name: row.name, image: data.toString("base64"), mime: row.mime };
|
|
583
|
+
}),
|
|
584
|
+
toModelOutput: imageOutput("image", (rest) => String(rest.name)),
|
|
585
|
+
}),
|
|
586
|
+
};
|
|
587
|
+
if (!on.brandSections) {
|
|
588
|
+
delete tools.set_logo_sections;
|
|
589
|
+
delete tools.set_gradients;
|
|
590
|
+
}
|
|
591
|
+
if (!on.brandRules) {
|
|
592
|
+
delete tools.set_rules;
|
|
593
|
+
}
|
|
594
|
+
if (!on.typography) {
|
|
595
|
+
delete tools.set_typography;
|
|
596
|
+
}
|
|
597
|
+
return tools;
|
|
598
|
+
}
|
|
599
|
+
/** A browser tool as the model calls it: sent to the page, its answer awaited. */
|
|
600
|
+
function browserTool(input, spec) {
|
|
601
|
+
let inputSchema;
|
|
602
|
+
try {
|
|
603
|
+
inputSchema = z.fromJSONSchema(spec.parameters);
|
|
604
|
+
}
|
|
605
|
+
catch {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
return createTool({
|
|
609
|
+
id: spec.name,
|
|
610
|
+
description: spec.description,
|
|
611
|
+
inputSchema,
|
|
612
|
+
// The id is the one `traced` gave the call: the browser answers to it.
|
|
613
|
+
execute: async (args, ctx) => input.callBrowser({
|
|
614
|
+
toolCallId: ctx?.toolCallId ?? nanoid(10),
|
|
615
|
+
toolCallName: spec.name,
|
|
616
|
+
args,
|
|
617
|
+
}),
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
/** Text of a tool's result for the chat's record, cut short. */
|
|
621
|
+
function resultText(out) {
|
|
622
|
+
if (typeof out === "string") {
|
|
623
|
+
return out.slice(0, 1200);
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
return (JSON.stringify(out, (key, value) => (key === "image" ? "(picture)" : value))?.slice(0, 1200) ?? "");
|
|
627
|
+
}
|
|
628
|
+
catch {
|
|
629
|
+
return "";
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Every tool says when it is called and what it gave back (AG-UI's tool call), from inside: an
|
|
634
|
+
* installed AI client runs tools without the stream showing it. A browser tool's call carries the
|
|
635
|
+
* same id to the page.
|
|
636
|
+
*/
|
|
637
|
+
function traced(tools, input, record) {
|
|
638
|
+
for (const [name, tool] of Object.entries(tools)) {
|
|
639
|
+
const run = tool?.execute;
|
|
640
|
+
if (typeof run !== "function") {
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
tool.execute = async (args, ctx = {}) => {
|
|
644
|
+
const toolCallId = nanoid(10);
|
|
645
|
+
const call = { toolCallId, toolCallName: name, args };
|
|
646
|
+
input.onToolCall?.(call);
|
|
647
|
+
const out = await run(args, { ...ctx, toolCallId });
|
|
648
|
+
const content = resultText(out);
|
|
649
|
+
record.push({ ...call, result: content });
|
|
650
|
+
input.onToolResult?.({ toolCallId, content });
|
|
651
|
+
return out;
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
/** The part of the space page a route stands on. */
|
|
656
|
+
function partOf(route) {
|
|
657
|
+
const m = route.match(/^\/space\/(info|knowledge|data|results)/);
|
|
658
|
+
return m ? m[1] : route === "/space" ? "info" : null;
|
|
659
|
+
}
|
|
660
|
+
/** How large each tool is in the prompt: its description and its schema, in characters. */
|
|
661
|
+
function toolSizes(tools) {
|
|
662
|
+
return Object.entries(tools)
|
|
663
|
+
.map(([name, tool]) => {
|
|
664
|
+
let schema = "";
|
|
665
|
+
try {
|
|
666
|
+
schema = JSON.stringify(tool?.inputSchema ? z.toJSONSchema(tool.inputSchema, { unrepresentable: "any" }) : {});
|
|
667
|
+
}
|
|
668
|
+
catch {
|
|
669
|
+
// A provider's own tool (web search) has no schema of ours.
|
|
670
|
+
}
|
|
671
|
+
return { name, chars: String(tool?.description ?? "").length + schema.length };
|
|
672
|
+
})
|
|
673
|
+
.sort((a, b) => b.chars - a.chars);
|
|
674
|
+
}
|
|
675
|
+
/** One turn of the studio assistant. */
|
|
676
|
+
export async function runStudioAssistant(input) {
|
|
677
|
+
// How often the space or a plugin's data changed: a part of the answer changed something when
|
|
678
|
+
// this grew during it.
|
|
679
|
+
let changes = 0;
|
|
680
|
+
const resolved = await textModel("high");
|
|
681
|
+
const wrote = () => {
|
|
682
|
+
changes++;
|
|
683
|
+
input.onChanged?.();
|
|
684
|
+
};
|
|
685
|
+
const cards = [];
|
|
686
|
+
const { project } = input;
|
|
687
|
+
const space = project && input.writable ? project : null;
|
|
688
|
+
const switches = await currentFeatures();
|
|
689
|
+
const brandOn = {
|
|
690
|
+
brandSections: switches.brandSections === true,
|
|
691
|
+
brandRules: switches.brandRules === true,
|
|
692
|
+
typography: switches.typography === true,
|
|
693
|
+
};
|
|
694
|
+
const tools = {
|
|
695
|
+
...knowsTools({
|
|
696
|
+
user: input.user,
|
|
697
|
+
project: project
|
|
698
|
+
? { id: project.id, name: project.name, mcpServers: project.mcpServers }
|
|
699
|
+
: null,
|
|
700
|
+
lang: input.lang,
|
|
701
|
+
chatId: input.chat.id,
|
|
702
|
+
doing: (label) => input.onActivity?.(label),
|
|
703
|
+
card: (card) => {
|
|
704
|
+
cards.push(card);
|
|
705
|
+
input.onCard?.(card);
|
|
706
|
+
},
|
|
707
|
+
}),
|
|
708
|
+
...(space ? spaceTools(input, space, wrote, brandOn) : {}),
|
|
709
|
+
};
|
|
710
|
+
// What the tenant's plugins let the assistant do besides: a source of knowledge, say.
|
|
711
|
+
if (space) {
|
|
712
|
+
Object.assign(tools, await assistantToolsOf({
|
|
713
|
+
tenantId: currentTenant(),
|
|
714
|
+
space: { id: space.id, name: space.name },
|
|
715
|
+
userId: input.user.id,
|
|
716
|
+
signal: input.signal ?? new AbortController().signal,
|
|
717
|
+
emit: (message) => input.onActivity?.(message),
|
|
718
|
+
changed: wrote,
|
|
719
|
+
card: (card) => {
|
|
720
|
+
cards.push(card);
|
|
721
|
+
input.onCard?.(card);
|
|
722
|
+
},
|
|
723
|
+
}));
|
|
724
|
+
}
|
|
725
|
+
for (const spec of input.browserTools) {
|
|
726
|
+
if (tools[spec.name]) {
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
const tool = browserTool(input, spec);
|
|
730
|
+
if (tool) {
|
|
731
|
+
tools[spec.name] = tool;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const toolCalls = [];
|
|
735
|
+
traced(tools, input, toolCalls);
|
|
736
|
+
if (resolved.vendor === "anthropic") {
|
|
737
|
+
tools.web_search = anthropic.tools.webSearch_20250305({ maxUses: 5 });
|
|
738
|
+
}
|
|
739
|
+
else if (resolved.gateway) {
|
|
740
|
+
tools.web_search = gatewayTools.perplexitySearch({ maxResults: 6 });
|
|
741
|
+
}
|
|
742
|
+
attachTools(resolved, tools);
|
|
743
|
+
const agent = new Agent({
|
|
744
|
+
id: "studio-assistant",
|
|
745
|
+
name: "Studio assistant",
|
|
746
|
+
instructions: {
|
|
747
|
+
role: "system",
|
|
748
|
+
content: SYSTEM,
|
|
749
|
+
providerOptions: { anthropic: { cacheControl: { type: "ephemeral" } } },
|
|
750
|
+
},
|
|
751
|
+
model: agentModel(resolved),
|
|
752
|
+
tools,
|
|
753
|
+
});
|
|
754
|
+
const page = input.page;
|
|
755
|
+
const pluginPage = page?.plugin && project
|
|
756
|
+
? await assistantPageOf(currentTenant(), page.plugin, { id: project.id, name: project.name })
|
|
757
|
+
: null;
|
|
758
|
+
const part = page ? partOf(page.route) : null;
|
|
759
|
+
const { history } = input;
|
|
760
|
+
const context = [
|
|
761
|
+
history.earlier.length
|
|
762
|
+
? `Earlier chats with this person, newest first (chats_search finds more):\n${history.earlier
|
|
763
|
+
.map((c) => `- ${c.closedAt.slice(0, 10)} "${c.title}": ${c.summary.replace(/\n+/g, " ")}`)
|
|
764
|
+
.join("\n")}`
|
|
765
|
+
: "",
|
|
766
|
+
history.running ? `What this chat said before the messages above:\n${history.running}` : "",
|
|
767
|
+
page
|
|
768
|
+
? `Current page:\n\`\`\`json\n${JSON.stringify(page)}\n\`\`\``
|
|
769
|
+
: "The person writes from a page that tells nothing about itself.",
|
|
770
|
+
pluginPage
|
|
771
|
+
? [
|
|
772
|
+
`The page is the plugin "${pluginPage.name}"'s${pluginPage.description ? `: ${pluginPage.description}` : "."} They most likely mean what that page holds: use its tools first (their names begin with "${page?.plugin?.replace(/-/g, "_")}_"). Space settings stay possible when they ask for them.`,
|
|
773
|
+
...pluginPage.blocks,
|
|
774
|
+
].join("\n\n")
|
|
775
|
+
: "",
|
|
776
|
+
space
|
|
777
|
+
? `The space now:\n\`\`\`json\n${JSON.stringify(await projectState(input.user.id, space.id))}\n\`\`\``
|
|
778
|
+
: project
|
|
779
|
+
? `The space "${project.name}" is read-only here: nothing of it can be changed in this studio.`
|
|
780
|
+
: "No space is open.",
|
|
781
|
+
part === "knowledge"
|
|
782
|
+
? "The person talks to you from Knowledge: they want the wizards to know something."
|
|
783
|
+
: "",
|
|
784
|
+
space && !(brandOn.brandSections && brandOn.brandRules && brandOn.typography)
|
|
785
|
+
? `Not in this studio (no tools for it; never offer it): ${[
|
|
786
|
+
brandOn.brandSections ? "" : "sections of logos and colours, gradients and patterns",
|
|
787
|
+
brandOn.brandRules ? "" : "rules for logos, colours and type",
|
|
788
|
+
brandOn.typography ? "" : "typography (fonts, type scale)",
|
|
789
|
+
]
|
|
790
|
+
.filter(Boolean)
|
|
791
|
+
.join("; ")}.`
|
|
792
|
+
: "",
|
|
793
|
+
input.message,
|
|
794
|
+
]
|
|
795
|
+
.filter(Boolean)
|
|
796
|
+
.join("\n\n");
|
|
797
|
+
input.onPrompt?.({
|
|
798
|
+
model: resolved.ref,
|
|
799
|
+
system: SYSTEM,
|
|
800
|
+
context,
|
|
801
|
+
history: history.messages.map((m) => ({ role: m.role, chars: m.content.length })),
|
|
802
|
+
tools: toolSizes(tools),
|
|
803
|
+
});
|
|
804
|
+
let reply = "";
|
|
805
|
+
// Where the part the result holds begins: a message written meanwhile cuts the answer there.
|
|
806
|
+
const from = { reply: 0, cards: 0, toolCalls: 0, changes: 0 };
|
|
807
|
+
const cut = () => {
|
|
808
|
+
const part = {
|
|
809
|
+
reply: reply.slice(from.reply).trim(),
|
|
810
|
+
changed: changes > from.changes,
|
|
811
|
+
cards: cards.slice(from.cards),
|
|
812
|
+
toolCalls: toolCalls.slice(from.toolCalls),
|
|
813
|
+
};
|
|
814
|
+
Object.assign(from, {
|
|
815
|
+
reply: reply.length,
|
|
816
|
+
cards: cards.length,
|
|
817
|
+
toolCalls: toolCalls.length,
|
|
818
|
+
changes,
|
|
819
|
+
});
|
|
820
|
+
return part;
|
|
821
|
+
};
|
|
822
|
+
const stream = await agent.stream([
|
|
823
|
+
...history.messages.map((m) => m.role === "user"
|
|
824
|
+
? { role: "user", content: m.content }
|
|
825
|
+
: { role: "assistant", content: m.content }),
|
|
826
|
+
{ role: "user", content: context },
|
|
827
|
+
], {
|
|
828
|
+
maxSteps: MAX_STEPS,
|
|
829
|
+
abortSignal: input.signal,
|
|
830
|
+
modelSettings: { maxOutputTokens: 8000 },
|
|
831
|
+
// What the person wrote meanwhile comes before the next step, after the tools' results.
|
|
832
|
+
prepareStep: async ({ stepNumber, messageList }) => {
|
|
833
|
+
const taken = stepNumber > 0 ? (input.takeSignals?.() ?? []) : [];
|
|
834
|
+
if (!taken.length) {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
await input.onSignal?.(taken, cut());
|
|
838
|
+
messageList.add({ role: "user", content: signalText(taken) }, "input");
|
|
839
|
+
return { messageList };
|
|
840
|
+
},
|
|
841
|
+
});
|
|
842
|
+
const window = contextWindowOf(resolved.ref);
|
|
843
|
+
// A step lasts from the end of the one before – its tools' work included – to its own end.
|
|
844
|
+
let stepStarted = Date.now();
|
|
845
|
+
for await (const chunk of stream.fullStream) {
|
|
846
|
+
const payload = chunk.payload ?? chunk;
|
|
847
|
+
if (chunk.type === "step-finish" && input.onStep) {
|
|
848
|
+
const usage = usageOf(payload.output?.usage);
|
|
849
|
+
input.onStep({
|
|
850
|
+
model: resolved.ref,
|
|
851
|
+
inputTokens: usage.inputTokens ?? 0,
|
|
852
|
+
outputTokens: usage.outputTokens ?? 0,
|
|
853
|
+
cachedInputTokens: usage.cachedInputTokens ?? 0,
|
|
854
|
+
ms: Date.now() - stepStarted,
|
|
855
|
+
costUsd: costOf(resolved, payload.output?.usage),
|
|
856
|
+
tools: (payload.output?.toolCalls ?? []).map((c) => c.payload?.toolName ?? c.toolName ?? ""),
|
|
857
|
+
window,
|
|
858
|
+
});
|
|
859
|
+
stepStarted = Date.now();
|
|
860
|
+
}
|
|
861
|
+
else if (chunk.type === "text-delta") {
|
|
862
|
+
const text = payload.text ?? payload.delta ?? "";
|
|
863
|
+
reply += text;
|
|
864
|
+
input.onText?.(text);
|
|
865
|
+
}
|
|
866
|
+
else if (chunk.type === "tool-call") {
|
|
867
|
+
// The model's own search has no tool of ours that could say so.
|
|
868
|
+
if (payload.toolName === "web_search") {
|
|
869
|
+
input.onActivity?.(serverText(input.lang, LABELS.web_search));
|
|
870
|
+
}
|
|
871
|
+
// Keep what it says before and after a tool call apart.
|
|
872
|
+
if (reply.trim() && !reply.endsWith("\n\n")) {
|
|
873
|
+
input.onText?.("\n\n");
|
|
874
|
+
reply += "\n\n";
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
else if (chunk.type === "error") {
|
|
878
|
+
throw payload.error ?? new Error("assistant stream error");
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
const usage = await totalUsage(stream);
|
|
882
|
+
return { ...cut(), costUsd: costOf(resolved, usage) };
|
|
883
|
+
}
|