@vellumai/assistant 0.11.1 → 0.11.2-staging.2
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/Dockerfile +1 -3
- package/README.md +1 -1
- package/eslint.config.mjs +28 -8
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +48 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +25 -6
- package/openapi.yaml +292 -5
- package/package.json +1 -1
- package/src/__tests__/agent-loop-resume-interrupted.test.ts +223 -0
- package/src/__tests__/byok-default-profile-ensure.test.ts +43 -0
- package/src/__tests__/cli-logger-boundary-guard.test.ts +87 -0
- package/src/__tests__/compaction-events.test.ts +139 -2
- package/src/__tests__/config-loader-backfill.test.ts +35 -3
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +30 -0
- package/src/__tests__/conversation-agent-loop.test.ts +180 -7
- package/src/__tests__/conversation-error.test.ts +211 -4
- package/src/__tests__/conversation-options-turn-scoped-transport.test.ts +64 -0
- package/src/__tests__/conversation-queue.test.ts +126 -0
- package/src/__tests__/conversation-retry-route.test.ts +46 -7
- package/src/__tests__/conversation-slash.test.ts +4 -2
- package/src/__tests__/conversation-summarize-route.test.ts +7 -1
- package/src/__tests__/conversation-summarize-up-to.test.ts +71 -5
- package/src/__tests__/document-create-dedupe.test.ts +2 -1
- package/src/__tests__/document-find-replace.test.ts +2 -1
- package/src/__tests__/document-tool-security.test.ts +2 -1
- package/src/__tests__/document-update-default-surface.test.ts +2 -1
- package/src/__tests__/document-workspace-file.test.ts +467 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +290 -49
- package/src/__tests__/guardian-card-withdrawal.test.ts +91 -3
- package/src/__tests__/http-user-message-parity.test.ts +66 -0
- package/src/__tests__/list-messages-attachments.test.ts +87 -0
- package/src/__tests__/list-messages-provider-error.test.ts +143 -0
- package/src/__tests__/list-messages-system-card.test.ts +100 -0
- package/src/__tests__/llm-resolver.test.ts +19 -9
- package/src/__tests__/managed-profile-guard.test.ts +23 -0
- package/src/__tests__/notification-platform-adapter.test.ts +130 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +6 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +45 -0
- package/src/__tests__/plugin-api-model-profiles.test.ts +10 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +3 -0
- package/src/__tests__/provider-error-scenarios.test.ts +140 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +95 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +66 -3
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +209 -0
- package/src/__tests__/skills.test.ts +27 -0
- package/src/__tests__/slack-channels-routes.test.ts +0 -2
- package/src/__tests__/slack-share-routes.test.ts +0 -3
- package/src/__tests__/slack-users-routes.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +11 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +58 -0
- package/src/__tests__/tool-result-spool.test.ts +5 -4
- package/src/__tests__/turn-boundary-resolution.test.ts +53 -0
- package/src/__tests__/turn-events-store.test.ts +26 -0
- package/src/__tests__/ui-visual-surface.test.ts +695 -0
- package/src/__tests__/unified-turn-context-visible-app.test.ts +99 -0
- package/src/__tests__/visible-app-context.test.ts +189 -0
- package/src/__tests__/workspace-git-service.test.ts +173 -33
- package/src/__tests__/workspace-migration-137-repair-retired-fireworks-minimax-model-id.test.ts +157 -0
- package/src/__tests__/workspace-migration-138-backfill-home-feed-titles.test.ts +373 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +137 -0
- package/src/agent/loop.ts +36 -7
- package/src/api/events/context-window-usage.ts +31 -0
- package/src/api/events/notification-intent.ts +8 -0
- package/src/api/events/ui-surface-pending.ts +35 -0
- package/src/api/index.ts +14 -0
- package/src/api/responses/conversation-message.ts +25 -4
- package/src/api/surfaces.ts +90 -1
- package/src/approvals/guardian-card-withdrawal.ts +66 -31
- package/src/approvals/guardian-decision-primitive.ts +4 -0
- package/src/calls/__tests__/call-setup-router.test.ts +156 -26
- package/src/calls/__tests__/voice-session-bridge.test.ts +201 -12
- package/src/calls/call-setup-router.ts +80 -36
- package/src/calls/voice-session-bridge.ts +173 -26
- package/src/cli/commands/inference.help.ts +3 -3
- package/src/cli/commands/notifications.help.ts +3 -2
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +42 -128
- package/src/cli/commands/platform/__tests__/credits.test.ts +9 -78
- package/src/cli/commands/platform/__tests__/helpers.ts +90 -0
- package/src/cli/commands/platform/__tests__/invoices.test.ts +238 -0
- package/src/cli/commands/platform/__tests__/plans.test.ts +9 -88
- package/src/cli/commands/platform/__tests__/status.test.ts +12 -87
- package/src/cli/commands/platform/__tests__/subscription.test.ts +9 -86
- package/src/cli/commands/platform/index.help.ts +92 -0
- package/src/cli/commands/platform/index.ts +7 -0
- package/src/cli/commands/platform/invoices.ts +132 -0
- package/src/cli/commands/usage.help.ts +1 -1
- package/src/cli/lib/list-installed-plugins.ts +2 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +7 -10
- package/src/config/__tests__/deployment-context-defaults.test.ts +27 -5
- package/src/config/assistant-feature-flags.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -2
- package/src/config/bundled-skills/subagent/SKILL.md +3 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +3 -3
- package/src/config/bundled-skills/visualize/SKILL.md +163 -0
- package/src/config/call-site-defaults.ts +3 -2
- package/src/config/default-profile-catalog.ts +75 -70
- package/src/config/default-profile-names.ts +13 -28
- package/src/config/env-registry.ts +1 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/llm-resolver.ts +21 -5
- package/src/config/loader.ts +18 -11
- package/src/config/schemas/llm.ts +1 -9
- package/src/config/schemas/memory-retrospective.ts +9 -0
- package/src/config/schemas/monitoring.ts +28 -2
- package/src/config/schemas/workspace-git.ts +15 -0
- package/src/config/seed-inference-profiles.ts +19 -5
- package/src/context/post-turn-tool-result-truncation.ts +2 -2
- package/src/conversations/__tests__/message-consolidation.test.ts +54 -0
- package/src/conversations/message-consolidation.ts +17 -15
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +182 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +181 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +90 -7
- package/src/daemon/conversation-agent-loop.ts +107 -22
- package/src/daemon/conversation-error.ts +169 -48
- package/src/daemon/conversation-messaging.ts +87 -4
- package/src/daemon/conversation-process.ts +57 -45
- package/src/daemon/conversation-runtime-assembly.ts +57 -0
- package/src/daemon/conversation-store.ts +36 -1
- package/src/daemon/conversation-surfaces.ts +68 -6
- package/src/daemon/conversation-turn-finalize.ts +76 -18
- package/src/daemon/conversation.ts +122 -27
- package/src/daemon/lifecycle.ts +9 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/surfaces.ts +3 -0
- package/src/documents/document-store.ts +247 -10
- package/src/home/__tests__/feed-types.test.ts +43 -8
- package/src/home/__tests__/feed-writer.test.ts +59 -0
- package/src/home/feed-types.ts +34 -7
- package/src/home/feed-writer.ts +15 -6
- package/src/live-voice/__tests__/activity-label.test.ts +95 -0
- package/src/live-voice/__tests__/live-activity-reporter.test.ts +86 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +310 -25
- package/src/live-voice/__tests__/live-voice-events.test.ts +4 -4
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +8 -4
- package/src/live-voice/__tests__/live-voice-vad.test.ts +9 -1
- package/src/live-voice/activity-label.ts +169 -0
- package/src/live-voice/live-activity-reporter.ts +35 -6
- package/src/live-voice/live-voice-session.ts +282 -41
- package/src/live-voice/protocol.ts +35 -0
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +84 -2
- package/src/messaging/providers/slack/adapter.ts +86 -19
- package/src/messaging/providers/slack/api.test.ts +85 -1
- package/src/messaging/providers/slack/api.ts +121 -288
- package/src/messaging/providers/slack/client.ts +20 -251
- package/src/messaging/providers/slack/send.test.ts +4 -9
- package/src/messaging/providers/slack/send.ts +1 -1
- package/src/messaging/providers/slack/types.ts +5 -0
- package/src/messaging/providers/slack/web-api-transport.test.ts +181 -0
- package/src/messaging/providers/slack/web-api-transport.ts +367 -0
- package/src/messaging/providers/slack/withdraw.ts +6 -14
- package/src/messaging/providers/telegram-bot/send.test.ts +31 -1
- package/src/messaging/providers/telegram-bot/send.ts +23 -2
- package/src/messaging/providers/telegram-bot/withdraw.test.ts +152 -0
- package/src/messaging/providers/telegram-bot/withdraw.ts +166 -0
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +18 -4
- package/src/monitoring/__tests__/file-descriptors.test.ts +144 -0
- package/src/monitoring/file-descriptors.ts +262 -0
- package/src/monitoring/process-memory.ts +4 -11
- package/src/monitoring/resource-sampler.ts +5 -0
- package/src/monitoring/worker.ts +12 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +740 -0
- package/src/notifications/__tests__/broadcaster.test.ts +347 -7
- package/src/notifications/__tests__/copy-composer.test.ts +53 -3
- package/src/notifications/__tests__/decision-engine.test.ts +349 -29
- package/src/notifications/__tests__/deterministic-checks.test.ts +21 -0
- package/src/notifications/__tests__/edit-notification.test.ts +330 -0
- package/src/notifications/__tests__/guardian-delivery-recorder.test.ts +71 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +170 -12
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/adapters/platform.ts +90 -14
- package/src/notifications/adapters/telegram.ts +6 -4
- package/src/notifications/assistant-reply-producer.ts +219 -0
- package/src/notifications/broadcaster.ts +523 -317
- package/src/notifications/copy-composer.ts +27 -6
- package/src/notifications/decision-engine.ts +154 -77
- package/src/notifications/deterministic-checks.ts +6 -7
- package/src/notifications/edit-notification.ts +8 -4
- package/src/notifications/emit-signal.ts +49 -16
- package/src/notifications/guardian-delivery-recorder.ts +8 -2
- package/src/notifications/home-feed-side-effect.ts +43 -6
- package/src/notifications/notification-utils.ts +39 -4
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +17 -0
- package/src/persistence/bookmark-crud.ts +18 -9
- package/src/persistence/conversation-attention-store.ts +26 -0
- package/src/persistence/conversation-crud.ts +79 -32
- package/src/persistence/conversation-queries.ts +30 -15
- package/src/persistence/conversation-title-service.ts +5 -170
- package/src/persistence/conversation-types.ts +192 -1
- package/src/persistence/db-init.ts +14 -1
- package/src/persistence/db-maintenance.ts +5 -4
- package/src/persistence/embeddings/__tests__/plugin-index-qdrant-init.test.ts +219 -0
- package/src/persistence/embeddings/__tests__/plugin-index.test.ts +22 -0
- package/src/persistence/embeddings/__tests__/worker-script-version.test.ts +76 -0
- package/src/persistence/embeddings/embedding-local.ts +2 -1
- package/src/persistence/embeddings/embedding-runtime-manager.ts +29 -5
- package/src/persistence/embeddings/plugin-index.ts +84 -12
- package/src/persistence/migrations/360-add-document-workspace-path.test.ts +110 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +39 -0
- package/src/persistence/planner-statistics.ts +14 -0
- package/src/persistence/schema/documents.ts +26 -11
- package/src/persistence/steps.ts +2 -0
- package/src/platform/client.test.ts +172 -2
- package/src/platform/client.ts +178 -55
- package/src/plugin-api/conversation-turn.ts +13 -0
- package/src/plugin-api/model-profiles.test.ts +6 -2
- package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +34 -0
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +22 -0
- package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +11 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +199 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +98 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +105 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +24 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +524 -0
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +9 -4
- package/src/plugins/defaults/memory/host-utils.ts +5 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +105 -1
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +64 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +36 -1
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +12 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +1 -0
- package/src/plugins/defaults/memory/substrate/__tests__/skill-store.test.ts +195 -1
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +1 -1
- package/src/plugins/defaults/memory/substrate/skill-store.ts +167 -29
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +131 -0
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1 -0
- package/src/plugins/defaults/memory/v2/activation-log-store.ts +4 -0
- package/src/plugins/defaults/memory/v2/injection.ts +48 -3
- package/src/plugins/defaults/memory/v2/rerank-local.ts +6 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -1
- package/src/plugins/defaults/platform-hosted/routes/reengage.ts +1 -1
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +26 -0
- package/src/plugins/types.ts +17 -0
- package/src/prompts/templates/system-sections.ts +2 -2
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +43 -2
- package/src/providers/__tests__/vellum-mismatch-routing.test.ts +8 -0
- package/src/providers/call-site-routing.ts +77 -14
- package/src/providers/connection-resolution.ts +42 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +127 -1
- package/src/providers/inference/adapter-factory.ts +70 -12
- package/src/providers/model-catalog.ts +0 -11
- package/src/providers/model-intents.ts +11 -0
- package/src/providers/registry.ts +8 -0
- package/src/providers/retry.ts +85 -17
- package/src/providers/types.ts +8 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/agent-wake.ts +132 -9
- package/src/runtime/channel-approval-types.ts +25 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +2 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +11 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +121 -9
- package/src/runtime/routes/__tests__/platform-invoice-routes.test.ts +392 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +7 -0
- package/src/runtime/routes/__tests__/workspace-commit-routes.test.ts +63 -0
- package/src/runtime/routes/consolidation-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +18 -6
- package/src/runtime/routes/conversation-query-routes.ts +14 -23
- package/src/runtime/routes/conversation-routes.ts +113 -8
- package/src/runtime/routes/credential-routes.ts +1 -5
- package/src/runtime/routes/documents-routes.ts +207 -12
- package/src/runtime/routes/identity-routes.ts +3 -93
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +31 -1
- package/src/runtime/routes/inbound-stages/admission-policy.ts +18 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +52 -3
- package/src/runtime/routes/notification-routes.ts +4 -1
- package/src/runtime/routes/platform-routes.ts +238 -3
- package/src/runtime/routes/playground/guard.ts +1 -2
- package/src/runtime/routes/slack-channel-routes.ts +2 -4
- package/src/runtime/routes/workspace-commit-routes.ts +49 -2
- package/src/runtime/routes/workspace-routes.ts +11 -12
- package/src/runtime/routes/workspace-utils.ts +49 -2
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/subagent/__tests__/consult-context-gating.test.ts +98 -0
- package/src/subagent/__tests__/consult-context-skills.test.ts +82 -0
- package/src/subagent/__tests__/consult-context.test.ts +84 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +36 -0
- package/src/subagent/consult-context.ts +410 -0
- package/src/subagent/consult-prompt.ts +38 -5
- package/src/subagent/manager.ts +9 -4
- package/src/subagent/types.ts +8 -0
- package/src/telemetry/telemetry-event-sources.ts +7 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +1 -0
- package/src/telemetry/turn-events-store.ts +30 -1
- package/src/telemetry/types.ts +24 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/tools/browser/pinned-tabs.ts +3 -1
- package/src/tools/subagent/spawn.ts +23 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/ui-surface/definitions.ts +39 -1
- package/src/tools/ui-surface/surface-shape-docs.ts +38 -4
- package/src/tools/ui-surface/visual-validation.ts +787 -0
- package/src/tools/workflows/run-workflow.test.ts +1 -0
- package/src/util/__tests__/short-title.test.ts +229 -0
- package/src/util/__tests__/worker-compute.test.ts +65 -0
- package/src/util/cgroup-cpu.ts +93 -0
- package/src/util/errors.ts +27 -0
- package/src/util/process-tree.ts +19 -0
- package/src/util/short-title.ts +189 -0
- package/src/util/worker-compute.ts +83 -0
- package/src/workspace/byok-default-profile-ensure.ts +25 -15
- package/src/workspace/git-service.ts +79 -30
- package/src/workspace/migrations/137-repair-retired-fireworks-minimax-model-id.ts +131 -0
- package/src/workspace/migrations/138-backfill-home-feed-titles.ts +179 -0
- package/src/workspace/migrations/139-clear-renamed-cost-profile-label.ts +92 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/plugins/defaults/memory/substrate/constants.ts +0 -8
|
@@ -228,12 +228,10 @@ describe("resolver integration", () => {
|
|
|
228
228
|
expect(resolved.model).not.toBe("claude-sonnet-4-6");
|
|
229
229
|
});
|
|
230
230
|
|
|
231
|
-
test("a
|
|
232
|
-
// `latency-optimized`
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
// name they were never able to select: the voice front model would
|
|
236
|
-
// silently run on an arbitrary user model.
|
|
231
|
+
test("a user profile cannot shadow latency-optimized", () => {
|
|
232
|
+
// `latency-optimized` is code-owned: it fronts every live-voice turn, so
|
|
233
|
+
// a same-named workspace entry never governs what it resolves to. The
|
|
234
|
+
// entry stays on disk and stays a valid `activeProfile` reference.
|
|
237
235
|
const llm = LLMSchema.parse({
|
|
238
236
|
profiles: {
|
|
239
237
|
"latency-optimized": {
|
|
@@ -246,17 +244,16 @@ describe("resolver integration", () => {
|
|
|
246
244
|
},
|
|
247
245
|
},
|
|
248
246
|
});
|
|
249
|
-
const body = CODE_DEFAULT_PROFILE_ENTRIES["latency-optimized"]
|
|
247
|
+
const body = CODE_DEFAULT_PROFILE_ENTRIES["latency-optimized"]!;
|
|
250
248
|
for (const callSite of ["voiceFrontDoor", "voiceFrontDecision"] as const) {
|
|
251
249
|
const resolved = resolveCallSiteConfig(callSite, llm);
|
|
252
250
|
expect(resolved.model).toBe(body.model as string);
|
|
253
251
|
expect(resolved.model).not.toBe("claude-opus-4-6");
|
|
254
252
|
expect(String(resolved.provider)).toBe("vellum");
|
|
255
253
|
}
|
|
256
|
-
//
|
|
257
|
-
// a valid `activeProfile` reference for the user who created it.
|
|
254
|
+
// Listing follows resolution: the catalog body is what surfaces.
|
|
258
255
|
expect(getEffectiveProfiles(llm.profiles)["latency-optimized"]?.model).toBe(
|
|
259
|
-
|
|
256
|
+
body.model,
|
|
260
257
|
);
|
|
261
258
|
expect(() =>
|
|
262
259
|
LLMSchema.parse({
|
|
@@ -52,6 +52,7 @@ afterAll(() => {
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
import { setStorePathForTesting } from "../../__tests__/encrypted-store-test-helpers.js";
|
|
55
|
+
import { enableMemoryV3LiveForNewWorkspacesMigration } from "../../workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.js";
|
|
55
56
|
import { invalidateConfigCache, loadConfig } from "../loader.js";
|
|
56
57
|
|
|
57
58
|
// ---------------------------------------------------------------------------
|
|
@@ -221,7 +222,7 @@ describe("deployment-context embedding-provider default (via loadConfig)", () =>
|
|
|
221
222
|
expect(config.memory.qdrant.vectorSize).toBe(384);
|
|
222
223
|
});
|
|
223
224
|
|
|
224
|
-
test("first launch
|
|
225
|
+
test("first launch persists nothing under memory.v3, not even `live`", () => {
|
|
225
226
|
if (existsSync(CONFIG_PATH)) {
|
|
226
227
|
rmSync(CONFIG_PATH, { force: true });
|
|
227
228
|
}
|
|
@@ -233,16 +234,37 @@ describe("deployment-context embedding-provider default (via loadConfig)", () =>
|
|
|
233
234
|
expect(config.memory.v3.gate.denseThreshold).toBe(0.66);
|
|
234
235
|
expect(config.memory.v3.needleK).toBe(100);
|
|
235
236
|
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
237
|
+
// Nothing under memory.v3 is frozen to disk. Tuning knobs stay absent so a
|
|
238
|
+
// shipped schema-default change reaches this assistant on its next load
|
|
239
|
+
// (mirrors the embedding-provider strip above), and `live` stays absent so
|
|
240
|
+
// migration 105 can record the initial choice: 105 bails on any value
|
|
241
|
+
// already present, and this seed runs before workspace migrations.
|
|
239
242
|
const raw = readConfig();
|
|
240
243
|
const v3Raw = ((raw.memory as Record<string, unknown>).v3 ?? {}) as Record<
|
|
241
244
|
string,
|
|
242
245
|
unknown
|
|
243
246
|
>;
|
|
244
|
-
expect(Object.keys(v3Raw)).toEqual([
|
|
247
|
+
expect(Object.keys(v3Raw)).toEqual([]);
|
|
245
248
|
expect(v3Raw.gate).toBeUndefined();
|
|
246
249
|
expect(v3Raw.needleK).toBeUndefined();
|
|
247
250
|
});
|
|
251
|
+
|
|
252
|
+
test("migration 105 turns v3 on for a workspace this seed just created", () => {
|
|
253
|
+
if (existsSync(CONFIG_PATH)) {
|
|
254
|
+
rmSync(CONFIG_PATH, { force: true });
|
|
255
|
+
}
|
|
256
|
+
delete process.env.IS_PLATFORM;
|
|
257
|
+
|
|
258
|
+
loadConfig();
|
|
259
|
+
enableMemoryV3LiveForNewWorkspacesMigration.run(WORKSPACE_DIR, {
|
|
260
|
+
isNewWorkspace: true,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const raw = readConfig();
|
|
264
|
+
const v3Raw = ((raw.memory as Record<string, unknown>).v3 ?? {}) as Record<
|
|
265
|
+
string,
|
|
266
|
+
unknown
|
|
267
|
+
>;
|
|
268
|
+
expect(v3Raw.live).toBe(true);
|
|
269
|
+
});
|
|
248
270
|
});
|
|
@@ -313,10 +313,15 @@ export async function refreshOverridesFromGateway(): Promise<boolean> {
|
|
|
313
313
|
* registry)
|
|
314
314
|
* 2. Registry `defaultEnabled` (for declared assistant-scope keys)
|
|
315
315
|
* 3. `false` (for undeclared keys with no override)
|
|
316
|
+
*
|
|
317
|
+
* Resolution reads only the override and registry caches, so `_config` is
|
|
318
|
+
* accepted for the convenience of call sites that already hold one and never
|
|
319
|
+
* consulted. Callers without a config in hand should omit it rather than load
|
|
320
|
+
* one for this.
|
|
316
321
|
*/
|
|
317
322
|
export function getAssistantFeatureFlagValue(
|
|
318
323
|
key: string,
|
|
319
|
-
_config
|
|
324
|
+
_config?: AssistantConfig,
|
|
320
325
|
): boolean | string {
|
|
321
326
|
const defaults = loadDefaultsRegistry();
|
|
322
327
|
const declared = defaults[key];
|
|
@@ -343,7 +348,7 @@ export function getAssistantFeatureFlagValue(
|
|
|
343
348
|
*/
|
|
344
349
|
export function isAssistantFeatureFlagEnabled(
|
|
345
350
|
key: string,
|
|
346
|
-
config
|
|
351
|
+
config?: AssistantConfig,
|
|
347
352
|
): boolean {
|
|
348
353
|
return !!getAssistantFeatureFlagValue(key, config);
|
|
349
354
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: app-builder
|
|
3
|
-
description: Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES. This is the right skill whenever the user asks to "visualize this," "make a chart," or "build an artifact" for their own use, or to edit an app they already built here. Do NOT reach for a ui_show dynamic_page to fake an artifact — build a real persistent app here. NOT for complex, multi-user, or shippable products — those go to a real project folder with a coding agent (see Scope below).
|
|
3
|
+
description: Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES. This is the right skill whenever the user asks to "visualize this," "make a chart," or "build an artifact" for their own use, or to edit an app they already built here. Do NOT reach for a ui_show dynamic_page to fake an artifact — build a real persistent app here. A one-off diagram, chart, or explainer that just accompanies an answer belongs to the visualize skill (ui_show visual), not an app. NOT for complex, multi-user, or shippable products — those go to a real project folder with a coding agent (see Scope below).
|
|
4
4
|
metadata:
|
|
5
5
|
emoji: "🛠️"
|
|
6
6
|
vellum:
|
|
@@ -9,10 +9,11 @@ metadata:
|
|
|
9
9
|
includes: ["frontend-design"]
|
|
10
10
|
activation-hints:
|
|
11
11
|
- "User asks to build a dashboard, tracker, calculator, data visualization, chart, simple landing page, or slide deck for their own use"
|
|
12
|
-
- "User asks to
|
|
12
|
+
- "User asks to build an artifact, tool, or app they will keep using — build a real persistent app here, never a ui_show dynamic_page"
|
|
13
13
|
- "User asks to change, fix, restyle, or extend an app they already built in the sandbox — open it and iterate"
|
|
14
14
|
- "User asks to open, show, or pull up an app they already built — this skill provides app_list + app_open even when nothing needs editing"
|
|
15
15
|
avoid-when:
|
|
16
|
+
- "An inline diagram, chart, or explainer that accompanies an answer and will not be reopened — use the visualize skill"
|
|
16
17
|
- "User wants a complex app, a multi-user app, or something to publish, deploy, or hand off to others — route to a local project folder + coding agent instead (see Scope)"
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -56,7 +56,9 @@ Orient yourself first (read the relevant files, understand the task), then consu
|
|
|
56
56
|
- **When you get stuck or are weighing a change in direction.**
|
|
57
57
|
- **Once before you declare the task done.**
|
|
58
58
|
|
|
59
|
-
The consult is synchronous and read-only: spawning an `advisor` subagent BLOCKS until it returns guidance. It runs on a stronger model and inherits your full context, so it sees the task, your tool calls, and their results without you re-explaining. Give its guidance serious weight; only override it when primary-source evidence contradicts a specific claim
|
|
59
|
+
The consult is synchronous and read-only: spawning an `advisor` subagent BLOCKS until it returns guidance. It runs on a stronger model and inherits your full context, so it sees the task, your tool calls, and their results without you re-explaining. It also receives a snapshot of your environment (the tools available to you this turn, the full skill catalog, and your workspace) so its guidance can point you at existing platform capabilities by name. Give its guidance serious weight; only override it when primary-source evidence contradicts a specific claim, and say so when you do.
|
|
60
|
+
|
|
61
|
+
Beyond that snapshot, the advisor sees only what is in this conversation. It cannot read files, other conversations, or external systems on its own. If you want it to weigh specific evidence (a file's contents, a command's output, results gathered elsewhere), surface that evidence in the conversation or the spawn objective before consulting.
|
|
60
62
|
|
|
61
63
|
Spawn the advisor **alone** — do NOT batch the consult in the same turn as other tool calls (especially file edits, shell commands, or anything destructive or expensive). Tool calls you issue in the same turn run concurrently with the consult, so they would execute before you see its guidance. Consult the advisor by itself, read its guidance, then act.
|
|
62
64
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "subagent_spawn",
|
|
6
|
-
"description": "Spawn an independent subagent to work on a task in parallel. The subagent runs autonomously and its results are reported back when complete.\n\nTwo modes:\n- **Regular sub-agent** (fork: false or omitted): Gets only the objective + context fields. Use for self-contained tasks with clear objectives. Can use scoped roles (researcher, coder, planner).\n- **Fork** (fork: true): Inherits full parent context (messages, system prompt, memory). Shares KV cache for near-free context inheritance. Use when the task benefits from knowing what you've been discussing. Defaults to general role (the 'advisor' role is the exception
|
|
6
|
+
"description": "Spawn an independent subagent to work on a task in parallel. The subagent runs autonomously and its results are reported back when complete.\n\nTwo modes:\n- **Regular sub-agent** (fork: false or omitted): Gets only the objective + context fields. Use for self-contained tasks with clear objectives. Can use scoped roles (researcher, coder, planner).\n- **Fork** (fork: true): Inherits full parent context (messages, system prompt, memory). Shares KV cache for near-free context inheritance. Use when the task benefits from knowing what you've been discussing. Defaults to general role (the 'advisor' role is the exception: it is honored as a fork). Results are internal by default (send_result_to_user: false). Read with last_n: 1 to get only the final synthesis.\n\nDecision heuristic: Does the task need to know what we've been talking about? Fork. Is it self-contained? Regular sub-agent.\n\nThe 'advisor' role is a synchronous, read-only \"consult a stronger advisor\" mode: it inherits your full context plus a snapshot of your environment (available tools, skill catalog, workspace), has no tools of its own, and BLOCKS until it returns focused strategic guidance in a single response.",
|
|
7
7
|
"category": "orchestration",
|
|
8
8
|
"risk": "low",
|
|
9
9
|
"input_schema": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"context": {
|
|
21
21
|
"type": "string",
|
|
22
|
-
"description": "Optional additional context to pass to the subagent. Ignored when fork is true
|
|
22
|
+
"description": "Optional additional context to pass to the subagent. Ignored when fork is true; forks inherit the parent's full context."
|
|
23
23
|
},
|
|
24
24
|
"fork": {
|
|
25
25
|
"type": "boolean",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"investigator",
|
|
40
40
|
"advisor"
|
|
41
41
|
],
|
|
42
|
-
"description": "Agent specialization that controls tool access. 'researcher': read-only (web, files, memory). 'coder': file and bash access. 'planner': read-only analysis. 'investigator': root-cause analysis
|
|
42
|
+
"description": "Agent specialization that controls tool access. 'researcher': read-only (web, files, memory). 'coder': file and bash access. 'planner': read-only analysis. 'investigator': root-cause analysis: debugging, log forensics, tracing behavior across many files; uses read-only search/read tools (code_search, file_read, file_list) with no shell access and returns a compact root-cause report. 'advisor': synchronous, read-only \"consult a stronger advisor\": inherits full context plus a snapshot of your environment (available tools, skill catalog, workspace), has no tools of its own, and blocks until it returns focused strategic guidance. 'general': full access (default). The read-only roles (researcher, planner, investigator, advisor) cannot persist output; use 'coder' or 'general' for any objective that must write files or run commands, or a read-only subagent will finish without producing anything. Non-advisor roles are ignored when fork: true (forks default to general); the advisor role is honored even as a fork."
|
|
43
43
|
},
|
|
44
44
|
"inference_profile": {
|
|
45
45
|
"type": "string",
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: visualize
|
|
3
|
+
description: Render a polished visual inline in the chat as part of your answer — a diagram, a chart, an interactive explainer, or a UI mockup. Load it proactively whenever an explanation would land better as a picture than as prose. Do not wait to be asked.
|
|
4
|
+
metadata:
|
|
5
|
+
emoji: "📊"
|
|
6
|
+
vellum:
|
|
7
|
+
display-name: "Visualize"
|
|
8
|
+
category: "content"
|
|
9
|
+
always-candidate: true
|
|
10
|
+
activation-hints:
|
|
11
|
+
- "Explaining how something works, or how the parts of a system relate to each other"
|
|
12
|
+
- "Comparing options, tradeoffs, or before and after states side by side"
|
|
13
|
+
- "Walking through numbers, rates, growth, or a distribution the user should see"
|
|
14
|
+
- "Teaching a concept step by step, where the user should be able to move through it"
|
|
15
|
+
- "Answering how would you explain this, or helping the user teach or onboard someone else"
|
|
16
|
+
avoid-when:
|
|
17
|
+
- "Simple factual answers where a sentence or a markdown list already says it"
|
|
18
|
+
- "Durable apps or tools the user will reopen and keep using — use the app-builder skill"
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
You are authoring a self-contained HTML fragment that renders inline in the chat transcript, directly beneath the paragraph you are writing. It renders in a sandboxed frame sized to your content, with the host's design tokens injected, so it looks native in light and dark mode.
|
|
22
|
+
|
|
23
|
+
## Invocation
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
ui_show { surface_type: "visual", data: { html: "<fragment>", height: 320 } }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- `height` is a rough pixel estimate (80 to 1400); the host measures and corrects after first paint.
|
|
30
|
+
- One visual per call. To change one already shown, `ui_dismiss` its `surface_id` and show a new one.
|
|
31
|
+
- Prose goes in your reply, the visual goes in the tool: no titles, intros, or captions inside the fragment, and never describe in prose what the visual already shows.
|
|
32
|
+
- If ui_show returns an error, read it, fix the arguments, and call again. Every rejection is fixable in the next call; never debug via shell or files, and never narrate retries.
|
|
33
|
+
|
|
34
|
+
A visual is part of one answer. Durable things the user reopens (a dashboard, a tracker, a calculator they keep) are apps: use the `app-builder` skill.
|
|
35
|
+
|
|
36
|
+
## Design instincts
|
|
37
|
+
|
|
38
|
+
- Seamless and flat: no gradients, shadows, glow, or texture. Flat fills, hairline borders.
|
|
39
|
+
- Compact and honest: show the essential, explain the rest in prose; every number on screen is one you actually have.
|
|
40
|
+
- Pick the lightest form that carries the idea, and invent freely: a bespoke drawing that fits this answer beats a stock layout. Interaction has to earn its place; steppers are for stages that genuinely follow one another, tabs are not a default. Vary layout between visuals in one conversation.
|
|
41
|
+
- Route diagrams on the verb: "walk me through" wants a flowchart; "how is it organised" wants containment boxes; "how does it actually work" wants the mechanism drawn as an intuition, not a safer flowchart.
|
|
42
|
+
|
|
43
|
+
## Sandbox constraints (hard)
|
|
44
|
+
|
|
45
|
+
- No network: no script src, stylesheets, @import, remote images, web fonts, fetch, or CDN libraries. Charts and diagrams are hand-drawn inline SVG; images are inline SVG only.
|
|
46
|
+
- Fragment only: no DOCTYPE, html, head, or body. No HTML comments, no emoji.
|
|
47
|
+
- Hard cap 24000 characters; aim well under 8000. Too big to fit is too big to render. Split rich subjects into two visuals with prose between.
|
|
48
|
+
- No position fixed or sticky, no nested scrollbars: the frame auto-sizes from in-flow content.
|
|
49
|
+
- No localStorage, sessionStorage, or cookies. Hold state in JS variables.
|
|
50
|
+
|
|
51
|
+
## Fragment structure
|
|
52
|
+
|
|
53
|
+
Order: a visually hidden `<h2 class="sr-only">` one-sentence summary, a short style block, the markup, one script element last. Always quote every attribute value (`class="row-box hit"`, never `class=row-box hit`). Include verbatim when using sr-only:
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Usable width is about 660px; the host insets content 6px vertically and 10px from the sides. Rows holding controls carry their own padding of at least 8px on the crowded sides. Keep the outer background transparent.
|
|
60
|
+
|
|
61
|
+
## Design tokens
|
|
62
|
+
|
|
63
|
+
The COMPLETE list of injected CSS variables. Any other var() name is rejected unless your own style block declares it. Never hardcode a colour: hex, rgb(), hsl(), and oklch() literals are rejected everywhere, including SVG fill and stroke; only `transparent` and `currentColor` are allowed.
|
|
64
|
+
|
|
65
|
+
Semantic tokens flip automatically between light and dark. Use them for every surface, body text, border, and status colour:
|
|
66
|
+
|
|
67
|
+
- Surfaces: --surface-base (page), --surface-lift (card), --surface-overlay, --surface-sunken (recessed tile), --surface-hover, --surface-active.
|
|
68
|
+
- Text, strongest to faintest: --content-emphasised, --content-strong, --content-default (body), --content-secondary (labels and any text under 14px), --content-tertiary (14px and up only), --content-quiet, --content-faint, --content-disabled, --content-inset (on inverted fills). Text at 11 to 13px always takes --content-secondary or stronger.
|
|
69
|
+
- Borders: --border-base (hairline), --border-subtle, --border-element (visible control edge), --border-hover, --border-active, --border-disabled.
|
|
70
|
+
- Status pairs: --system-positive-strong/-weak, --system-negative-strong/-weak (and --system-negative-hover), --system-mid-strong/-weak, --system-info-strong/-weak.
|
|
71
|
+
- Type: --font-sans (default), --font-mono (identifiers, code, tabular numbers only), --font-serif (editorial pull-quotes only).
|
|
72
|
+
- Radius: --radius-xs 2, --radius-sm 4, --radius-md 8, --radius-lg 12, --radius-xl 16, --radius-xxl 20, --radius-pill 999.
|
|
73
|
+
|
|
74
|
+
Palette ramps are for categorical encoding only, never page surfaces or body text: --color-moss-50..950 and --color-stone-50..950 (neutrals), --color-forest-100..950, --color-emerald-100..950, --color-danger-100..950, --color-amber-100..950. Stops run light (100) to dark (950). Author every ramp use against the light theme as a matched triple from ONE ramp, and the host mirrors it in dark mode as a unit:
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
background: var(--color-forest-100);
|
|
78
|
+
border-color: var(--color-forest-600);
|
|
79
|
+
color: var(--color-forest-900);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The two rules the mirror imposes: text on a tinted fill takes the same ramp's 900 (secondary 800), never a --content-* token; and text sitting on the page (SVG labels, axis ticks, anything outside a tinted fill) takes --content-*, never a bare ramp stop. A dark ramp stop used as text is only valid where its light counterpart is painted right there on the same element or enclosing group.
|
|
83
|
+
|
|
84
|
+
Colour discipline: colour encodes category, not sequence. At most two accent ramps per visual plus a neutral, one accent moment per visual, system tokens only for genuine success/failure/warning/info, and a one-line legend whenever colour carries meaning. Never distinguish categories by colour alone; pair with a label or shape.
|
|
85
|
+
|
|
86
|
+
## Typography and spacing
|
|
87
|
+
|
|
88
|
+
- Sizes: 18px section label, 15px item title, 14px body (default), 12px secondary, 11px floor. Weights 400 and 500 only. Sentence case everywhere.
|
|
89
|
+
- Line-height 1.6 for prose; vertical rhythm in rem (0.5, 1, 1.5, 2); internal gaps in px (8, 12, 16).
|
|
90
|
+
- Card: --surface-lift, 1px --border-base, --radius-lg, padding 1rem 1.25rem. Tile: --surface-sunken with a 1px --border-subtle (it dissolves into the light page without the hairline), --radius-md.
|
|
91
|
+
- Buttons and pills take --radius-pill or --radius-sm, one choice per visual. No box-shadow except a focus ring. Size height to content honestly; no empty bands.
|
|
92
|
+
- Round every displayed number (Math.round, toFixed, toLocaleString); give range inputs an explicit step so the control emits round values.
|
|
93
|
+
|
|
94
|
+
## Complexity budget (hard)
|
|
95
|
+
|
|
96
|
+
At most 4 items across one row, 5 diagram nodes, 2 ramps, 5-word subtitles. Past any of these, split into two visuals with prose between. Over roughly 8000 characters means you are building too much.
|
|
97
|
+
|
|
98
|
+
## SVG mechanics
|
|
99
|
+
|
|
100
|
+
Anything with nodes and arrows is ONE inline SVG with `width="100%"` and `viewBox="0 0 680 H"`, never a row of HTML divs (divs clip silently at the frame edge; SVG scales). Skeleton:
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<svg width="100%" viewBox="0 0 680 320" role="img">
|
|
104
|
+
<title>One sentence.</title>
|
|
105
|
+
<desc>What the boxes and arrows are.</desc>
|
|
106
|
+
<style>
|
|
107
|
+
text{font-family:var(--font-sans)}
|
|
108
|
+
.th{font-size:14px;font-weight:500;fill:var(--content-strong)}
|
|
109
|
+
.ts{font-size:12px;fill:var(--content-secondary)}
|
|
110
|
+
.box rect{fill:var(--surface-lift);stroke:var(--border-element)}
|
|
111
|
+
.arr{stroke:var(--border-element);fill:none;marker-end:url(#a)}
|
|
112
|
+
</style>
|
|
113
|
+
<defs><marker id="a" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round"/></marker></defs>
|
|
114
|
+
</svg>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- Keep viewBox width 680 (one unit = one CSS pixel). Lay nodes out on the grid below instead of computing positions: it is already sized so nothing overlaps and nothing clips, so there is no spacing arithmetic to do, and the validator checks bounds for you on submit.
|
|
118
|
+
- Node width 140, height 44 (single line, text at y + 22) or 56 (title at y + 20, subtitle at y + 38).
|
|
119
|
+
- 4 nodes across: x = 30, 200, 370, 540. 3 across: x = 60, 270, 480. 2 across: x = 120, 420.
|
|
120
|
+
- Rows at y = 20, 110, 200, 290. viewBox height = last row's y + 80.
|
|
121
|
+
- Horizontal arrows run between node edges at the node's mid height. Arrow labels fit only at 2 or 3 nodes across (12 above the arrow, centred on the gap); at 4 across the gaps are 30px, nothing fits, so leave those arrows unlabeled and carry the verbs in your prose.
|
|
122
|
+
- Containers wrap a row group with 16 of margin; free-form shapes for illustrative drawings stay inside one grid cell or one row band.
|
|
123
|
+
- Every coordinate is an absolute viewBox coordinate. Never use the transform attribute: translated groups mix local and absolute positions and labels land outside their boxes (the validator rejects transforms). A node is a rect plus its text at the rect's own position:
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<g class="n-forest">
|
|
127
|
+
<rect x="200" y="110" width="140" height="56" rx="8" />
|
|
128
|
+
<text class="th" x="270" y="130" text-anchor="middle" dominant-baseline="central">Resolver</text>
|
|
129
|
+
<text class="ts" x="270" y="148" text-anchor="middle" dominant-baseline="central">checks cache</text>
|
|
130
|
+
</g>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- Node titles fit at about 13 characters; subtitles at 5 words. Longer means shorten the words, never the spacing. SVG text never wraps; no rotated text.
|
|
134
|
+
- Background fills scope to the shape, never the group: `.note rect{fill:var(--surface-sunken)}`, not `.note{fill:...}`. fill inherits to text, so a group-level surface fill silently repaints the labels inside it in the background colour.
|
|
135
|
+
- Every text element needs `dominant-baseline="central"` with y at the centre of its slot. Two sizes only: 14px titles, 12px everything else.
|
|
136
|
+
- Any path or polyline used as a line carries `fill="none"` or it renders as a black blob. Strokes: 1px structure, 2px chart line. One arrowhead marker is the whole of defs; no filters, no gradients.
|
|
137
|
+
- A coloured node applies its matched ramp triple as one class on the group containing rect and text together.
|
|
138
|
+
- Charts: 2px lines, no dot per datum unless points are the story; bars with rx 2 and a 4px gap minimum; gridlines 1px --border-subtle; label axes directly rather than with a legend when there are two series or fewer.
|
|
139
|
+
|
|
140
|
+
## Interaction mechanics
|
|
141
|
+
|
|
142
|
+
One state object, one render() function, handlers mutate state and call render(); call render() once at the end of the script so the first paint is populated. Controls are unstyled by the sandbox; style them yourself:
|
|
143
|
+
|
|
144
|
+
```css
|
|
145
|
+
.btn{padding:6px 12px;border-radius:var(--radius-md);border:1px solid var(--border-element);background:transparent;font:400 13px var(--font-sans);color:var(--content-default);cursor:pointer}
|
|
146
|
+
.btn:hover{background:var(--surface-hover)}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- Selected state lives on aria-pressed or aria-selected and the CSS keys off that attribute. Every control is a real button or input, never a clickable div; glyph-only controls get aria-label.
|
|
150
|
+
- Range inputs: min, max, value, explicit step; recompute on `input`; put the live readout beside the control with a min-width so digits do not jitter.
|
|
151
|
+
- A static table is better as markdown in your reply; a table earns a fragment only when rows react to interaction. Use table-layout:fixed and --font-mono at 12px.
|
|
152
|
+
|
|
153
|
+
A global `sendPrompt(text)` sends text to the chat as though the user typed it, for follow-ups that need you to think ("Compare last quarter"). Give such controls a trailing arrow glyph (↗). Filtering, sorting, and recomputing happen in local JS instead, instantly. sendPrompt fires only from a real user click, never on load or a timer.
|
|
154
|
+
|
|
155
|
+
## Accessibility
|
|
156
|
+
|
|
157
|
+
HTML fragments open with the sr-only h2; a lone-SVG fragment instead carries role="img" with title and desc as its first children. Toggle state never lives on colour alone.
|
|
158
|
+
|
|
159
|
+
## Now compose
|
|
160
|
+
|
|
161
|
+
Everything you need is above, and none of it needs verifying in advance: the grid already spaces things, and the validator checks tokens, contrast, and bounds when you submit, telling you exactly what to change if anything is off. Pre-checking coordinates, estimating label widths, or reviewing markup in your head duplicates work the validator does in milliseconds.
|
|
162
|
+
|
|
163
|
+
Your next action is the ui_show call itself. Your entire reasoning budget for this visual is a few sentences: name the form, name the grid slots you will use, done. Markup written in reasoning does not render, does not count as showing the user anything, and has to be written all over again inside the call, so a draft there spends the entire budget and produces nothing on screen. Compose the fragment for the first time inside `data.html` as you write the call. If you notice yourself reasoning about the fragment's contents, stop and start the call.
|
|
@@ -123,10 +123,11 @@ export const CALL_SITE_DEFAULTS: Record<LLMCallSite, CallSiteDefaultConfig> = {
|
|
|
123
123
|
},
|
|
124
124
|
// Endpoint decisions gate live-voice turn-end latency, and `cost-optimized`'s
|
|
125
125
|
// upstream cannot fit any usable decision budget (~1s+ per forced tool call).
|
|
126
|
-
// `latency-optimized` is the
|
|
126
|
+
// `latency-optimized` is the latency-class profile (see
|
|
127
127
|
// default-profile-catalog.ts): managed installs get the pinned latency model,
|
|
128
128
|
// BYOK installs resolve their own provider's latency model through the intent
|
|
129
|
-
// table rather than a model id they may hold no credential for.
|
|
129
|
+
// table rather than a model id they may hold no credential for. The profile
|
|
130
|
+
// is user-facing ("Speed"), so a user edit to it moves this call site too.
|
|
130
131
|
voiceFrontDecision: {
|
|
131
132
|
profile: "latency-optimized",
|
|
132
133
|
effort: "low",
|