web-nuxt exposes a complete AI workspace instead of routing every workflow into one playground:
/dashboard/ai-chatis the persistent conversational product surface, including history and multi-turn continuation./dashboard/ai-playgroundis AI Studio for image, video, audio, and other structured generation workflows./dashboard/image-agentis a conversational image editing workspace with saved chats, reference images, generation history, a library, and version previews./dashboard/usagecombines Chat and provider generation usage, including image, video, audio, requests, tokens, credits, daily activity, and model breakdown.
Why it matters
These surfaces share the same session lifecycle, so they already understand:
- auth state
- guest sessions
- available credits
- API key lifecycle
- conversation and generation history
- provider-specific inputs
- user-scoped usage and billing data
Site owners can keep the native Workers AI binding or configure any HTTPS OpenAI-compatible Base URL and API Key in the admin AI upstream settings. The credential remains server-side in node10-ai-service; users only see enabled models, never the upstream key.
Recommended user path
- Start from
/guest-demoor/dashboard - Open
/dashboard/ai-chatfor conversational work or/dashboard/ai-playgroundfor generation - Continue previous conversations or create the first result
- Review
/dashboard/usagebefore upgrading to a full account or a higher plan
Image Agent setup
Image Agent is currently included only in the Nuxt template. Its navigation is enabled by imageAgent.enabled in app/app.config.ts. The page and API live in apps/web-nuxt; other frontend templates are not connected.
Reopening a conversation restores its most recent image model and generation settings. If that model is no longer available, select an available model before sending the next message. Background progress updates preserve the current model selection.
The composer attachment panel supports file selection, drag and drop, clipboard images, HTTPS image links, and library selection. Each message accepts up to 16 images, with numbered previews, removal, and clear actions. Conversation images remain available for analysis even when the selected image model cannot edit images or accepts fewer source images. Image tools still enforce that model's capabilities and source count. File uploads reuse the platform CDN component with progress, cancellation, and retry, accepting PNG, JPEG, WebP, GIF, and AVIF files up to 10 MB each. Mock mode uses the same controls and validation while retaining files only in the browser, without contacting the CDN.
You can discuss ideas before uploading an image or completing generation settings. The selected image model and settings apply when the Agent generates or edits an image; they do not prevent text discussion or visual analysis. Uploaded images are conversation context, and the Agent selects the permitted sources for each image operation.
Assistant replies and activity messages support Markdown headings, emphasis, lists, tables and code blocks. Wide tables and code blocks scroll within the message on small screens. Model-supplied HTML stays plain text; replies do not load Markdown image URLs. Generated images and references are displayed from the saved task records. HTTP(S) links open separately.
Annotate image opens an editor from reference thumbnails or image previews. It supports pen, arrows, rectangles, ellipses, text, colors, line width, movement, undo/redo, and modification notes. Each message accepts up to four annotated sources, with 64 marks and a 1,000-character note per source. The flattened PNG guide is uploaded through the shared CDN transport; the clean source, guide, normalized editable marks, and note are saved with the message. The Agent receives both images, while image editing tools receive only the clean source. Saved marks can be reopened for another edit. Live sources are imported into reference storage and read through an authenticated same-origin endpoint, so the editor does not require third-party browser CORS. Sources must be allowed by the import policy and remain accessible until their first successful copy. Inaccessible or oversized files show a retry state. Exported guides have a longest side of at most 2,048 pixels.
The existing node10 Worker exports an Image Agent Cloudflare Workflow. Apply Node1 migrations through 0040_credit_debit_cancellation.sql, enterprise billing through 0004_usage_reservation_fences.sql, Provider1 through 0034_task_recovery_legacy_visibility.sql, and node10 through 0016_image_agent_workflow_control.sql. Release Node1 and enterprise billing, then Provider1, node10, and the Nuxt app. Use each service's db:migrate:local script for local development. Node10 needs IMAGE_AGENT_WORKFLOW, PROVIDER1_SERVICE, and a dedicated IMAGE_AGENT_CREDENTIAL_KEY secret containing 32 random bytes encoded as 64 hexadecimal characters. The frontend uses its existing AI_SERVICE, PROVIDER1_SERVICE, and CDN service connections. Configure an image provider with public model metadata, a prompt field, and an image reference field for editing. The model's validation schema supplies image settings and tool source limits. Provider Turnstile, access checks, moderation, credits, refunds, and task status handling still apply.
In Cloudflare, the Admin AI proxy requires both AUTH_SERVICE for administrator verification and AI_SERVICE for Agent operations. The Nuxt Image Agent proxy requires AI_SERVICE; legacy image submissions also require PROVIDER1_SERVICE. Missing or failed bindings return an error without retrying through an HTTP URL, including when a write may already have committed. Local development outside Cloudflare continues to use the configured HTTP services. Run pnpm --filter @zship/node10-ai-service test:admin-pages:local to verify the compiled Admin API with actual local service bindings and pnpm --filter @zship/web-nuxt test:server for the Nuxt proxy regressions. These checks do not call models or replace hosted deployment verification.
The shared Nuxt authentication and CDN upload proxies also require their configured bindings in Cloudflare. Password/refresh, Google and GitHub login requests are not resent through HTTP after a binding response is lost. Authentication outages preserve existing session cookies; a lost response may still mean the upstream already rotated the refresh credential. pnpm --filter @zship/node10-ai-service test:nuxt-pages:local builds and tests the Nuxt API with actual local platform services, including generation, editing, cold recovery, login, refresh, uploads and authenticated media. Inference uses controlled responses and the test stores are temporary. Add --pages-browser to serve the compiled page and its static assets after these checks; see the Node10 README for the fixture account, media routing and cleanup. Live OAuth providers, public media domains and hosted deployment still require separate verification.
The template bundles literal Lucide and Simple Icons used by its active Nuxt layers, app manifest and UI icon defaults. Shared upload controls, model selection and navigation therefore render these icons from the client bundle in the production build. Custom runtime icon names need their own explicit bundle configuration.
Open AI Gateway > Image Agent in Admin, or /ai?tab=image-agent, to choose the conversation model, enable new work, and set global limits. Choose an enabled model with valid token pricing that supports vision and tool calls; the model list does not certify its vision or tool quality. This conversation model is separate from the image model selected in the composer and uses the existing Workers AI or OpenAI-compatible gateway. Saving writes IMAGE_AGENT_ENABLED, IMAGE_AGENT_MODEL, and IMAGE_AGENT_LIMITS atomically through /api/ai/image-agent/config. Invalid stored policies disable new work and can be repaired from this tab. Without a configured conversation model, live submissions show the assistant as unavailable; local mock mode remains usable.
The Admin tab lists runs by application, exact email, and status. Needs attention includes failed runs, waiting for credits, unpaid model calls, and unknown image operations. Detail shows frozen budgets, model usage, image operations, and event types without exposing prompts, credentials, image URLs, or raw provider payloads. admin.provider.read permits diagnostics; admin.provider.write permits configuration, stop, and resume. Initial verification must be completed by the user. Resume currently requires an active run with retained, unexpired credentials. Disabling new work preserves settlement for already accepted operations.
Response token limit and Reasoning effort configure the conversation model, separately from image generation settings. The default is 1600 output tokens per call with provider-default reasoning. The output limit accepts 256–8192 tokens and includes reasoning tokens where the upstream counts them. Only select an explicit reasoning level when the upstream supports it. Saving also writes IMAGE_AGENT_INFERENCE in the same policy transaction. Each new run freezes these settings; changing them does not alter accepted runs. Higher limits can increase usage and latency.
Test model in the Admin Image Agent tab checks image recognition, a structured tool call and adoption of its returned result through the same model adapter used by the Agent. It tests the selected model and current inference settings without saving the policy. The check makes at most two model calls, disables retries and uses the same 120-second upstream request timeout as live Agent calls. It can incur upstream model usage but creates no images and deducts no customer credits. Only administrators with provider write permission can start it. Configuration indicators mean Configured, not verified connectivity. Test results apply to the current screen and clear after changing the model or inference settings or refreshing; they are a basic connectivity/capability check, not a quality benchmark or a persistent release approval. A local Workers AI binding still needs authenticated remote inference to pass.
Test media separately checks the reference-image storage path. It writes a unique tiny PNG to the configured R2 bucket, verifies the exact bytes through the public base URL, and removes the test object. It shows storage, public-read and cleanup results separately, with guidance for failures. This requires provider write permission and performs a few R2 operations without invoking a model, generating images, charging customer credits or adding user media records. A passed result verifies reference-media access from the Worker at that moment; image-provider delivery, model-side access and visual quality still require separate checks. Refreshing clears the result. Node6 honors the object's cache policy, so diagnostic files use no-store. A short R2 lifecycle rule for image-agent/diagnostics/ can clean up files left by an interrupted check.
If an Agent response reaches its output limit, the run stops before executing tool calls from that truncated response. Measured model usage is retained and settled, and any images created by earlier steps remain available. The workspace shows the response-limit reason and lets the user continue in a new message. Try this state locally with ?mock=1&case=workflow-output-limit.
The AI SDK agent can answer or clarify with text, inspect conversation images, and execute generate_image or edit_image. The Workflow waits for Provider results and supplies the resulting images back to the model, which can finish or perform a bounded revision. Image tools retain the selected provider, model and settings; source IDs resolve only to the conversation's images and current attachments. The activity timeline exposes persisted progress and intermediate images. Text-only replies do not create an image task or show an empty-image error.
The Agent can focus its next visual inspection on one image or compare several selected images in order. Other image versions remain in the conversation and can be viewed again; they are excluded from the focused preview. Associated annotation guides accompany the selected sources. This helps isolate a detail when versions are confusing, but does not guarantee that the model's visual judgment is correct. Inspection uses model steps and tokens without creating an image operation.
New tasks review newly returned images first. Results produced together are reviewed together; source images and earlier versions remain available for explicit comparison. A subsequent edit starts a fresh review of its outputs. Accepted tasks keep their original review policy during recovery.
Conversation usage is charged separately at the configured model's token rates. New calls round positive usage up to whole credits, matching Node1's ledger: a calculated 0.14 credits costs 1 credit, while a free model remains free. Each response and exact billable amount are frozen before debit, using image-agent:run:<run-id>:model:<step> as Node1's operation key. New paid runs require at least 1 credit in both balance and budget; D1 prevents a further model call with less than 1 credit remaining. Billing retries reuse the same amount and never repeat a completed inference; unpaid responses stay hidden. Settled calls create one platform usage record per run and step, including token counts and charged credits. Image Agent messages are excluded from ordinary AI Chat history. Defaults are six model steps, two image operations, 100 credits, and 30 minutes. Absolute server ceilings are eight steps, three operations, 1,000 credits, and 30 minutes. Admin can lower these caps for new runs; accepted runs keep their frozen limits. The composer clamps credit and operation inputs to the configured caps. Image-generation failures follow Provider's refund policy and do not refund completed conversation usage.
New snapshots freeze billing version 1. Earlier accepted snapshots and saved legacy replies retain their original amounts and are never repriced during retries. Historical fractional debits cannot settle against the current integer-only Node1 ledger; they require explicit accounting reconciliation before a rollout containing such records. The local platform check (pnpm --filter @zship/node10-ai-service test:platform:local) runs the actual node10, Provider1 and Node1 Workers with disposable D1/R2 data and controlled external model responses.
For persisted image tasks, Provider freezes the failure outcome and generation refund before contacting Node1. Failed refunds and lost refund responses remain pending and retry through status, authenticated callbacks, or the five-minute Provider recovery schedule. Refunds reuse provider1:failure-refund:<task-id> and preserve moderation charges. The Agent shows Returning image credits and waits for settlement before its final reply; it does not repeat the failed image operation. A failed image operation leaves the run failed while preserving the assistant's explanation and any earlier successful images. Already completed dialogue usage is still billed. Historical failures without a frozen refund record require separate reconciliation.
New Provider tasks and their frozen generation prices are persisted before generation billing. Unconfirmed payments cannot submit images. Payment uncertainty or a two-minute admission timeout cancels the original debit identity and refunds only its confirmed amount; Node1 blocks any delayed new debit with that key. Recovery retains the task ID and never submits a replacement image. Enterprise reservations use their original identity for cancellation. Moderation billing still precedes task creation, and acceptance uncertainty after the submission claim remains distinct from an unsubmitted billing failure.
Content review persists its result and frozen price before charging, including reviews that stop before image task creation. If billing confirmation is lost, the Agent shows Confirming content review charges until Provider's scheduled recovery settles the original operation and its audit. Completed review fees are retained; no generation charge or refund is invented. Expired admission cannot generate an image even when the original caller returns late. Admin displays pending review charges as pending rather than zero. In local development, ?mock=1&case=workflow-review previews this state and the final explanation while retaining the first image and draft.
For enterprise Provider requests, image acceptance reserves usage; only final upstream success commits it. Provider saves the successful result before committing, then publishes task success after ledger confirmation. Lost responses recover the original operation through status, callbacks or the schedule, without generating again. Competing failure callbacks cannot cancel a saved success. Durable image delivery may still be pending after billing. Enterprise prices must use whole credits. Historical committed failures, orphan/fractional charges, permanent reservation denial and ambiguous upstream acceptance require separate reconciliation; existing committed invoices are not automatically cancelled.
Each message freezes its parameters, ordered references, dialogue model rates, and run limits. Provider operations use image-agent:run:<run-id>:image:<sequence>; transport retries and status reconciliation retain the original identity and API key. The browser reads durable progress through node10. Stop task revokes permission for further image work and retains results already accepted upstream; Resume task wakes the same run after reconnecting or adding credits. Scoped execution credentials are encrypted outside Workflow checkpoints, retained for at most one hour to settle accepted work, and cleared at terminal states. Rotated API keys cannot mutate an old run. Earlier messages retain their legacy execution path and identities.
For terminal runs or expired execution credentials, Reconcile existing results uses the authenticated original API key to query existing Provider operations, settle saved model responses, and restore missing activity records. It never starts inference, submits images, changes accepted limits, or restarts the run. Pending image counts and frozen unpaid credits remain visible until resolved. Failed runs retain their terminal status; recovered images appear in the conversation and library. Uncertain submissions remain unresolved without authoritative Provider evidence, and lost model responses cannot be reconstructed by this action. Concurrent settlement and response-loss tests verify one ledger operation and one usage record per saved model call.
Model quality determines how well edits preserve identity. Context uses the latest 24 messages and a bounded image catalog with visual references. Uploads and outputs use existing CDN/R2 delivery policy; authenticated history does not make public CDN URLs private. Chats with active Workflow messages cannot be archived. Archiving completed chats hides their history and library entries without deleting files. Recent chats, conversation history, and library reads are bounded at 100 records. Local authenticated start/events/resume/reconcile and Workerd restart tests use controlled model, Provider, and ledger substitutes. Admin browser tests cover desktop/mobile light/dark layouts, policy saves, permissions, filtering, and run controls with controlled Agent responses. Recovery browser tests cover pending results, partial settlement followed by an error, retry, and desktop/mobile light/dark layouts. Annotation tests cover editing, source/guide separation, save/reopen, touch input, cancellation, and transport retries. Real provider validation, complete source lineage, durable-media guarantees, and the release audit remain required before production release.
New Workflow runs also require Provider migration 0027_required_image_delivery.sql. Configure file transfer with an enabled R2 destination, a public base URL that serves that actual bucket, allowed upstream HTTPS origins, and rules selecting images from the mapped response. Provider currently binds the zship-provider1 bucket; an unrelated CDN bucket cannot serve its objects. Missing storage configuration blocks authorization before model inference. When generation finishes but copying is pending, the timeline shows Saving generated images. Only fully saved results are delivered to the Agent. Storage retries retain the original task and fees, without generating again; terminal runs can continue delivery through reconciliation. Old accepted runs preserve their previous delivery policy. Complete historical source lineage, real configured inference, and release verification remain separate production requirements.
Reference media
Live image links are copied before entering the reference list. Node10's IMAGE_AGENT_MEDIA R2 binding uses the existing zship-cdn bucket, under image-agent/references/. Set IMAGE_AGENT_MEDIA_PUBLIC_URL to a public address that serves this bucket. For Node6's Worker file route, include /file in the base; a direct R2 custom domain uses its root. Both Workers must bind the same bucket. Set IMAGE_AGENT_MEDIA_ALLOWED_ORIGINS to a JSON array of trusted HTTPS origins, such as ["https://images.example.com"]; the public media origin is also allowed. Up to 32 explicit origins are supported. The importer checks every redirect, never forwards user credentials, and limits downloads to 20 seconds, 10 MB and 32 million pixels. Supported formats are PNG, JPEG, WebP, GIF and AVIF. Model input support still depends on the selected upstream model.
POST /ai/image-agent/media/import and GET /ai/image-agent/media/:id/content use normal Node1 API-key authentication and app/account ownership. D1 freezes each imported source identity and manifest. Conditional R2 writes let a retry recover already copied bytes after a lost checkpoint or an expired upstream URL. Original signed URLs are represented by hashes in the manifest storage and object metadata. Limits are 30 new import records per hour, 500 records per account/application, and two simultaneous transfers; failed records count toward the limits. A repeated source reuses its existing snapshot. Public result URLs still follow the platform's public CDN policy.
The link panel retains the URL on failure, supports cancellation, and continues an import when closed. The editor reads stored bytes through Nuxt's authenticated same-origin proxy. New Workflow runs also copy every image in their bounded catalog and its associated annotation guides before model inference. This covers the latest 48 catalog entries plus current attachments, using the latest 24 messages. The activity timeline shows reference preparation. Each import has a recoverable checkpoint; a separate immutable D1 context freezes managed URLs, catalog IDs and attachment order. Storage failure or cancellation prevents new inference and image submission. The same import quotas and source allowlist apply to background imports, including legacy images that have never been copied.
Historical guides become visible when the Agent inspects their clean source, labeled as past context. Guides never enter the editing tool's source catalog. Existing accepted runs retain their original replay behavior, and original message records are not rewritten. History, library and task reads project known references, guides and outputs to their saved URLs. Files that expired before any successful import cannot be recovered from a URL alone. Local checks cover actual Nuxt, node10, Node1, D1 and R2 using a public ZShip image. Controlled Workerd checks additionally verify reference/guide storage and frozen context across runtime restart, without paid inference.
Image Versions
Workflow results retain their run, operation and image IDs across later edits. Optional ordered reference_ids bind each selected version to its URL and owner when accepting a message; the field is immutable. New contexts assign stable media IDs to uploaded references, while generated versions retain their operation IDs. GET /ai/image-agent/versions/:id returns a version and its ordered sources using existing immutable operation records. The Nuxt preview exposes Source images and supports following parents, including compositions with multiple sources. The composition mock demonstrates this without uploading or generating images.
Archiving hides conversations and library entries; owned image provenance remains readable for existing references. Older Workflow source IDs are resolved through their accepted catalog where possible. Legacy client-synchronized tasks lack authoritative operation records, and are not presented as verified Workflow provenance. Real configured model/provider validation and the release audit remain required.
Local mock cases
In nuxt dev, open /dashboard/image-agent?mock=1. The case menu includes single-image success, multi-turn edits (the default), multiple outputs, pending generation, failed generation, interrupted submission, an empty result, insufficient credits, and a new conversation. A case can also be linked directly, for example ?mock=1&case=failed.
Mock conversations, models, credits, uploads, and task responses stay in the page instance. Generation, billing, Turnstile, and CDN upload APIs are not called; ordinary app authentication checks may still run. Uploaded references use browser object URLs. Sending creates a pending task that completes on the next poll; Resume task resolves the seeded pending case, and Try again restores a failed request for resubmission. Rename, archive, library, preview, and download work with the sample records. Reloading or switching cases resets the sample data. The images are bundled demo fixtures, not responses from an AI model. Production builds ignore mock=1 and retain normal authentication and generation.
Case values: success, edits, annotated, multiple, pending, failed, prepared, no-output, insufficient, empty, clarify, discussion, planning, agent-error.
annotated includes an original portrait, a background guide with editable rectangle/arrow marks, notes, and a sample warmer result. Selecting the original as a reference restores the saved guide for further annotation. The editing tool retains the clean original as its reference.
Workflow cases: workflow, workflow-delivery, workflow-credits, workflow-completed, and workflow-cancelled. They show the shared activity timeline, intermediate results, saving generated images, stop controls, and waiting for credits. Resume task completes the running fixture; the credit-waiting fixture requires Add demo credits first. Cancelling preserves the first image. These cases simulate task states locally and do not start Cloudflare Workflows.
workflow-recovery starts with an interrupted run, one retained image, one unresolved image, and one unpaid demo credit. Reconcile existing results restores the second image and activity record, settles the demo credit once, and leaves the original run failed. It does not start another generation.
workflow-refund shows a failed revision waiting for its image refund. Resume task confirms the simulated refund, retains the first image, and finishes the run as failed with an explanatory reply. It returns 4 demo image credits and charges 1 demo credit for that final reply exactly once.
The clarify case shows a follow-up question; the next message proceeds to a demo image task. The discussion case answers with text and does not generate another image. planning and agent-error can be resumed through the reply controls. These are deterministic fixtures, not local LLM inference. A new mock conversation response uses 1 demo credit, in addition to any demo image charge.
Open ?mock=1&case=insufficient to see the balance warning above the composer. It shows a balance of 0 and the selected model's estimated cost. Add demo credits adds 240 local credits, preserves the draft, and lets generation continue without a payment request. In live mode, the warning links to pricing in a new tab and offers a balance refresh; rejected submissions retain the draft.
What product teams should avoid
- Do not ask first-time users to paste a manual API key before they understand the product.
- Do not collapse Chat and structured generation into competing interfaces; keep each entry point tied to a distinct job.
- Do not separate credits, AI generation, and account state into unrelated pages without a guided default path.
