bunnia

MoonBit mini-app UI framework with Rabbita-style authoring and modular platform adapters.

miniapp
wechat
alipay
tiktok
ui
moon add vectie/bunnia@0.1.0
Download zip
Author
Version
0.1.0
License
Apache-2.0
Last updated
14 days ago
Downloads
1
README

#vectie/bunnia

Bunnia is a MoonBit mini-app UI framework experiment with Rabbita-style authoring and modular platform adapters.

The main goal is fast, high-quality rendering for large mini-apps. Translation from Rabbita/Moontown should be easier, but rendering speed, visual quality, and predictable generated output size are the priorities.

Bunnia is also intended for agentic mini-apps. Agent chat, action traces, streaming status, and reviewable tool results should be first-class UI patterns, not bolted-on product widgets.

Agent interaction and communication should also be first-class: agent-to-human, agent-to-agent, handoff, review, and broadcast patterns should have reusable framework support inspired by Moontown, without importing Moontown concepts into core APIs.

Bunnia should also support stylised map-style surfaces for large stateful apps: scene layers, positioned actors, status overlays, and asset-budgeted rendering should be framework patterns rather than one-off product code.

Bunnia should keep a few MoonSuite lessons in mind without becoming a heavy suite platform: stable ids, small deltas, visible loading/error status, reviewable risky actions, artifact links, and generated-output diagnostics.

The first target is WeChat Mini Program, but the core tree model is platform neutral so Alipay and TikTok adapters can be added without rewriting product views.

Bunnia is a dedicated framework. Moontown/Wenyu can be used as a reference app and stress test, but Moontown product concepts must not be mixed into Bunnia's core framework APIs.

See docs/ROADMAP.md for the phase-by-phase implementation plan.

See docs/MOONTOWN_MINIAPP_PLAN.md for the Moontown product/backend dogfood plan, including user login, building ownership, publication, search, books, and agent interaction.

See docs/MOONTOWN_REALM_MIGRATION_PLAN.md for the focused migration plan where Realm is the existing tile map and the remaining work is the mature mini-app functionality around it.

#Package Shape

  • core: platform-neutral tree, events, adapters, render planning, and generic surface-status badges/overlays for loading, stale, error, retry, cancelled, and degraded states.
  • program: pure Program[Model, Msg] update/view boundary with pending effects and patch plans.
  • agent: lightweight message, review, artifact-link, run-status, and communication planning primitives, plus generic communication threads and traces.
  • scene: static stylised map model with layers, selectable regions, markers, asset manifests, hit targets, thread-link plans, and bounded updates.
  • effects: typed frontend effect descriptions, platform support planning, snapshot-delta planning, cancel/retry helpers, and backend contract paths.
  • adapters/wechat: WeChat Mini Program output generation.
  • tooling: build-profile diagnostics that aggregate render, WeChat, patch, backend, snapshot-delta, agent-delta, asset, and scene budget signals.
  • examples/agent_map: small downstream example combining agentic UI, review controls, patches, and a static map surface.
  • examples/wenyu_overview: product-shaped proof slice that keeps Wenyu projection/view code outside the framework core.
  • examples/moontown_miniapp: product-shaped Moontown mini-app vertical slice with full-screen map, building search/place flows, agent chat, mock local backend contracts, and create-building/create-agent controls outside core.
  • root package: small @bunnia facade for app authors.

#Generate The Demo

Print the CLI command map without writing generated output:

moon run cmd/main -- help

Unknown positional commands fail before the generator writes files, so command typos do not accidentally produce stale output.

moon run cmd/main

This writes a WeChat Mini Program file set to _build/bunnia/wechat/agent_map. The default demo includes initial page data plus event-to-patch dispatch for review buttons, map regions, and map markers. The command also prints render, file-size, initial-data, event-patch byte/operation, patch, agent-delta, and build-profile budget summaries. Use --out to choose another directory:

moon run cmd/main -- --out /tmp/bunnia-agent-map

The Moontown mini-app slice uses the same build path:

moon run cmd/main -- build --target wechat --example moontown_miniapp --strict --budget large --render-budget large moon run cmd/main -- inspect --target wechat --example moontown_miniapp --budget large --render-budget large sh scripts/validate_moontown_ordinary_copy.sh

For WeChat DevTools backend calls, start the local Moontown example backend on this Mac:

node examples/moontown_miniapp/backend/local_backend.mjs --reset-state node examples/moontown_miniapp/backend/local_backend.mjs --smoke

The same generator also accepts explicit build-style arguments:

moon run cmd/main -- build --target wechat --strict

--strict fails the command when render, generated-file, patch, effect, build-profile, or inspection-gate diagnostics are present. Use --budget tight for a stricter generated-output gate, or --budget tiny when testing that CI fails on size and route-pressure regressions:

moon run cmd/main -- build --target wechat --strict --budget tight

The render planner uses the same named profile by default. Use --render-budget tiny to exercise render-budget failures without shrinking generated-output byte budgets. Named budget profiles are exposed through @bunnia.render_budget_for_profile(...) and @bunnia.wechat_build_budget_for_profile(...); route-risk and update-payload gates are exposed through @bunnia.inspection_budget_for_profile(...), and aggregate large-app profile gates are exposed through @bunnia.build_profile_budget_for_profile(...), including generated-route diagnostic, repeated-list identity, unresolved-review, tool-result acknowledgment, and scene asset deployability limits, so contributors can use the same gates outside the CLI.

For local iteration, watch generated output with:

moon run cmd/main -- watch --target wechat --example agent_map --strict

Use --once with watch to run the same generation path once in CI or smoke tests without starting a long-running file watcher.

For deterministic generator review in CI, write a compact generated-output snapshot without writing the full generated mini-program directory:

moon run cmd/main -- snapshot --target wechat --example agent_map --strict

Snapshot output records the selected --budget profile, so CI diffs include the same generated-output report and diagnostic lines that strict builds evaluate. If --render-budget is set separately, snapshots record that profile too. Snapshots also include route-scoped manifest diagnostics, so a CI diff can point directly at the generated page that owns a render, payload, or interaction issue. The same snapshot records route diagnostic counts, making route pressure visible even before reading the diagnostic lines. Snapshots also record the profile-gate and inspection-gate summaries and diagnostics, highest-risk route, and per-route inspection lines, so CI diffs can show which page should be optimized first and which strict route/profile-pressure gate fired.

The snapshot records route, budget profile, size budgets, profile summary, profile-gate summary, per-route risk, route-scoped scene asset references, estimated scene asset bytes, and per-file byte/checksum lines without committing the full generated mini-program.

To inspect route and file pressure without writing generated files:

moon run cmd/main -- inspect --target wechat --example agent_map --budget tight --render-budget tight

inspect prints the same render, manifest, report, patch, profile, and snapshot summaries as the build path, then adds a project inspection summary, the highest-risk route, max scene marker/asset/package pressure, one route-inspection line per generated page, one route=... manifest line per generated page, route-scoped scene_asset=... lines, and one file=... line per generated artifact. This is intended for quick checks of first-screen bytes, update payloads, update operation fanout, scene marker and asset pressure, packaged scene bytes, diagnostic counts, file kinds, file bytes, and checksums before opening WeChat DevTools.

To inspect component mapping and platform capability limits:

moon run cmd/main -- limits --target wechat

limits prints the active platform adapter's component mappings, tap-event mapping, lifecycle names, request API, canvas/cloud/stream capabilities, and explicit generator status. The status is available for WeChat plus the generic Alipay/TikTok generators, and unknown for unsupported target ids. The same target-support model is reused by ci-plan and build-style commands, so unknown targets fail before artifacts are generated. Alipay and TikTok can write generic mini-app projects through build, including a deterministic bunnia.manifest.json route/file inventory plus named budget gates for cross-platform diagnostics. They also support no-write inspect, deterministic snapshot, and local watch regeneration paths. Generic build, inspect, snapshot, and watch flows print a target-neutral release-readiness report, and strict mode treats its diagnostics as blocking.

To print the canonical local/CI workflow for the tight proof examples:

moon run cmd/main -- ci-plan moon run cmd/main -- ci-plan --script sh scripts/scaffold_smoke.sh sh scripts/ci.sh

For the product-shaped Moontown route, use the explicit large-app lane:

moon run cmd/main -- ci-plan --example moontown_miniapp --budget large --render-budget large

The repository GitHub Actions workflow in .github/workflows/ci.yml generates the same CI plan through scripts/ci.sh, so local and hosted CI use the same command list. To run that same gate before each commit, configure the included hook once with git config core.hooksPath .githooks.

ci-plan defaults to the tight generated-output and render budgets and lists the check, test, interface, format, framework-boundary, platform-limits, route inspection, strict build, one-shot watch generation, snapshot, and scaffold-smoke commands that contributors should run before review. The public @bunnia.ci_plan() default stays product-neutral; the root CLI explicitly includes the Wenyu proof slice as an example stress test. Pass --render-budget to make render pressure stricter or looser than generated file-size gates. Unknown budget profile names and unsupported targets are printed as CI-plan diagnostics before contributors copy the generated commands. Use --target alipay or --target tiktok to print the same inspect, strict build, watch-once, and snapshot workflow for the generic mini-app adapters. The CI plan also prints the inspection-gate and profile-gate thresholds derived from the selected budget profile, including route-risk, update-operation ceilings, backend pressure, scene-asset ceilings, packaged scene-byte ceilings, duplicate stream chunks, full snapshot replacements, scene thread orphans, clamped cameras, surface fallbacks, visual-quality issues, and degraded scenes. That makes strict map-heavy and agent-heavy checks reviewable before the commands run. Build, inspect, and snapshot output also include a release-readiness line that aggregates manifest coverage, frontend secret checks, backend audit hooks, remote scene-asset policy, and the profile/inspection gates into a pilot preflight status. Add --script to emit a deterministic sh script from the same plan; invalid plans print diagnostics and exit before running generated commands.

The WeChat generator also supports multi-page projects through @bunnia.wechat_project_page(...) and @bunnia.generate_wechat_project_from_pages(...). Build reports include page count, generated file sizes, initial data bytes, event patch bytes, event patch operation count, and route-level first-screen/update payload and update operation budgets so large apps can catch growth early.

Generated WeChat projects include bunnia.manifest.json, a deterministic route and file manifest with per-page node/event counts, runtime data bytes, patch bytes, update operation counts, generated file sizes, first-screen/update byte estimates, and route-scoped render diagnostics. Generic Alipay/TikTok projects also include bunnia.manifest.json with platform id, route/file inventory, page node/event counts, scene counts, diagnostics, and generated byte totals. Generated manifests also include route-scoped scene asset references, estimated packaged scene bytes, remote scene asset counts, and an app-level sceneAssets list derived from neutral data-asset-* attributes, so map-heavy pages can review packaged and remote asset usage without importing scene-specific code in the WeChat adapter. Generated projects also include shared bunnia.runtime.js and app.wxss files plus route-local *.data.js payload modules, so page files keep only route structure and runtime glue instead of duplicating helpers, default styles, initial data, and event-patch tables per route. Generated event-patch tables include only messages reachable from that route's rendered events; orphan handlers stay visible as diagnostics instead of being serialized into page payloads. The manifest records missing and orphan event-patch counts per route, so large apps can locate broken interaction wiring without scanning aggregate logs. Route manifests also include a diagnostics array for render, payload, and interaction issues attributable to that page, plus per-route and app-level diagnostic counts/status fields so large apps can rank problematic routes without parsing every diagnostic string. @bunnia.inspect_wechat_project(...) and the inspect command use those signals to identify the top route by diagnostic and payload/render pressure. Backend-aware manifests also record reachable backend, stream, and review endpoint counts per route, making agentic request pressure attributable before opening the mini-app IDE. Projects generated with a backend contract also include bunnia.backend.js, a contract-derived wx.request adapter that keeps base URLs in page data and does not generate app secrets. Backend-aware pages call that adapter when a handled event message matches a backend endpoint id, and each page only carries the endpoint ids reachable from its own rendered events. Pages with no matching endpoint events keep the normal lightweight page runtime even inside a backend-aware project.

For large repeated surfaces, use @bunnia.windowed_list(...) with the visible rows and the full total_count. Render plans and generated manifests report windowed_lists plus visible/total item counts, which keeps first output bounded while preserving scale diagnostics. Render plans also report unwindowed_list_children and can diagnose unwindowed-list-children-over-budget when a keyed list, feed, or trace grows too large without windowing.

For large agentic traces, use @bunnia.plan_communications(...) or @bunnia.plan_filtered_communications(...) before rendering. Communication plans report visible/total rows, unresolved review pressure, artifact-bearing rows, and budget diagnostics; build profiles aggregate those signals in the normal CLI summary. Build profiles also carry route diagnostic route/count fields from the generated manifest so large apps can rank problematic routes from tooling output.

For long agent conversations, use @bunnia.windowed_message_feed(...) and @bunnia.windowed_communication_trace(...) so chat rows and action traces keep the same visible/total diagnostics as other large surfaces. For tool outputs, use @bunnia.tool_result_card(...) with @bunnia.tool_result_card_view(...) or @bunnia.windowed_tool_result_card_list(...) so artifact references, run-status, open actions, and acknowledgments remain typed UI state. Use @bunnia.plan_tool_result_cards(...) before profiling large agentic surfaces so visible result cards, pending acknowledgments, missing acknowledgments, and artifact references show up in build-profile diagnostics. For streaming output, append completed chunks with @bunnia.append_stream_chunk_delta(...) and update the current in-flight chunk with @bunnia.set_stream_chunk_delta(...); agent delta plans flag duplicate appended stream chunks.

Render plans also report unkeyed_list_children and duplicate_list_keys. Keep repeated rows uniquely keyed so large lists, feeds, and traces can update predictably. Render plans also count canvas nodes and can be planned against a custom PlatformAdapter, so unsupported canvas capability is visible before choosing a generator. Effect plans can also be checked against a custom PlatformAdapter, so streaming agent operations fail as explicit diagnostics when a target runtime cannot support them. Generic mini-app pages can be lowered for Alipay and TikTok from the same platform-neutral view while the CLI target gate remains conservative:

moon run cmd/main -- build --target alipay --example agent_map --strict moon run cmd/main -- build --target tiktok --example agent_map --strict

///|
test {
let root = @bunnia.page([@bunnia.button("Open", "open-detail")])
let alipay = @bunnia.generate_alipay_project(name="Adapter", root~)
let tiktok = @bunnia.generate_tiktok_project(name="Adapter", root~)
assert_true(alipay.files[2].path.has_suffix(".axml"))
assert_true(tiktok.files[2].path.has_suffix(".ttml"))
assert_eq(alipay.page.plan.node_count, tiktok.page.plan.node_count)
}
Use @bunnia.platform_limits(...) or @bunnia.platform_limits_for_adapter(...) to inspect component mapping, tap-event mapping, lifecycle mapping, request API mapping, and target capabilities from the same adapter boundary before choosing a generator.

///|
test {
let limits = @bunnia.platform_limits(target="wechat")
assert_eq(limits.generator_status_id, "available")
assert_eq(limits.generator_available, true)
assert_eq(limits.event_mappings[0].platform_event, "bindtap")
assert_eq(limits.request_mappings[0].platform_api, "wx.request")
assert_true(limits.summary.contains("components=9"))
let alipay = @bunnia.platform_limits(target="alipay")
assert_eq(alipay.generator_status_id, "available")
assert_eq(alipay.event_mappings[0].platform_event, "onTap")
assert_eq(alipay.request_mappings[0].platform_api, "my.request")
}

For map-heavy surfaces, use @bunnia.static_scene_view_with_viewport(...) and @bunnia.plan_scene_render_viewport(...). Scene plans and build profiles report visible/total marker and region counts so large maps can stay spatially bounded. Viewported scene views keep full scene dimensions as data while rendering a viewport-sized surface with viewport-local marker, region, and overlay coordinates, so first-screen layout does not inherit the whole map size. Generic render plans and generated route manifests also report scene count, visible/total marker count, visible/total region count, scene asset count, and degraded scene count, so map pressure is visible even before product-specific profiling is wired in. Route manifests include the render-budget limits used for generation, which keeps budget failures explainable from generated output alone. @bunnia.render_budget(...) can gate visible scene marker count, visible scene region count, scene asset reference count, and degraded scene count directly, which lets strict builds catch oversized first-screen map routes without penalizing offscreen world size. WeChat generation APIs also accept explicit render budgets, so route manifests and build reports carry those render diagnostics into normal build output. For agentic pages, route initial-data bytes are also checked against the page render budget. Use @bunnia.scene_camera(...) with @bunnia.static_scene_view_with_camera(...) when pan/zoom state should be explicit, clamped to scene bounds, and updated through small camera patches.

For agentic map surfaces, use @bunnia.scene_marker_thread_link(...), @bunnia.scene_region_thread_link(...), or the generic @bunnia.scene_thread_link(...) plus @bunnia.plan_scene_threads(...) to keep scene-subject badges measurable. Scene thread plans report visible/total links, unread pressure, orphan marker/region links, and missing open actions before the mini-app output grows. Scene-aware overlays derive badge anchors from marker centers or region centers, so agent communication stays attached to the map without product-specific positioning code. Use the viewport-aware anchored overlay and planner helpers when a large map is cameraed or clipped; they keep total thread counts visible while budgeting and rendering only badges inside the active viewport. Use @bunnia.plan_scene_surface_for_platform(...) to make the intended static/canvas/lightweight surface mode and any fallback explicit in build profiles before adding platform-specific rendering. Use @bunnia.plan_scene_visual_quality(...) for a checklist covering scene size, marker status, tap targets, asset references, unresolved assets, and degraded output. Use @bunnia.plan_scene_visual_quality_viewport(...) for cameraed or clipped maps; it checks the viewport-sized rendered surface and visible objects while the embedded render plan still reports total/visible world geometry. Use @bunnia.plan_scene_assets_with_budget(...) to identify bundled scene assets that should be deferred or moved remote when package-byte budgets are tight. Use @bunnia.plan_scene_assets_with_budget_and_policy(...) when remote assets must stay on approved domains; build profiles report remote, unapproved-remote, insecure-remote, and deferred asset counts. Build profiles also report generated scene asset counts derived from the WeChat manifest, so strict builds can compare planned package pressure with the actual route asset references emitted by the mini-app generator.

#WeChat package policy

Bunnia's WeChat release profile treats 2 MiB as the hard main-package limit and 1.5 MiB as the recommended operating ceiling. A build above 1.5 MiB receives the split-recommended advisory so there is room for future iteration; a build above 2 MiB fails the strict release budget. The report and generated manifest count the materialized bytes of copied assets, not the length of their copy-file: marker.

Follow the platform packaging model supplied for MoonSuite deployments:

  • keep the main package at or below 1.5 MiB whenever practical;
  • keep every subpackage at or below 2 MiB and all subpackages at or below 30 MiB in total;
  • reserve the main package for startup routes and truly boot-critical assets;
  • move non-TabBar pages and large optional components into subpackages;
  • serve image, audio, and video libraries from approved CDN or object-storage domains, while keeping a compact local fallback for the first screen;
  • import third-party libraries by used function or module instead of bundling an entire library.

Remote assets still require an explicit approved-domain policy, rights metadata, and a usable failure state. Subpackaging is an architectural release step rather than a way to hide oversized startup code.

Markers carry stable data-hit-width and data-hit-height attributes, and visual quality plans flag tappable markers with hit targets below the configured minimum so map interactions stay usable on mobile.

Use @bunnia.surface_status_badge(...) and @bunnia.surface_status_overlay(...) for loading, stale, error, retry, cancelled, or degraded state that should be visible without replacing the underlying list, dashboard, feed, or scene model.

For backend refreshes, use @bunnia.plan_snapshot_deltas(...) to turn section updates, append-only items, and removals into bounded patches. Full snapshot replacement is still representable for bootstrap paths, but plans flag it. Build profiles report snapshot delta counts, section updates, append pressure, and full replacements so large mini-apps do not accidentally refresh whole pages. WeChat build reports, manifests, inspections, and snapshots also report update operation counts separately from update payload bytes, so many small setData keys stay visible as a speed risk even when the JSON payload is compact. Project inspections also rank and gate route-level repeated-list pressure from generated manifests, including unwindowed rows, unkeyed rows, and duplicate keys. Snapshots include first-class list, agent workflow, snapshot replacement, and map-quality pressure counters, so CI diffs can track huge-app render and interaction risk without parsing the long profile summary.

Generate a standalone starter project with:

moon run cmd/main -- init --name my_miniapp --module local/my_miniapp --out /tmp/my-miniapp

The generated starter keeps agent chat and map-heavy surfaces first-class while splitting app view, agent feed, scene model, bounded updates, budget checks, backend contract, inspection/profile gates, release readiness, and WeChat generation into separate files, plus a local cmd/main build command that writes the starter's WeChat files and supports --strict diagnostic gating. The same command has an inspect mode for no-write route, backend, map, file pressure, and release-readiness checks and a snapshot mode for deterministic generated-output artifacts, plus a no-write limits mode for platform capabilities and generator status. WeChat build, inspect, snapshot, and CI-plan paths reuse Bunnia's target-support gate; Alipay/TikTok currently use generic build, inspect, snapshot, and watch paths with release-readiness preflight, while unknown targets report diagnostics before artifacts are generated. It also prints a local ci-plan with check, test, interface, format, product-neutral boundary, platform-limits, inspect, snapshot, strict build, one-shot watch commands, and the active inspection/profile/release thresholds. Its summary reports the current generated-output and gate diagnostic count. Starter tests check render budgets, scene output, bounded patches, backend visibility, release readiness, profile gates, and clean WeChat event wiring. The command also writes a local moon.work that includes the starter app and the current Bunnia checkout for pre-registry development.

Generate the Wenyu proof slice with:

moon run cmd/main -- --example wenyu_overview

///|
test {
let page = @bunnia.page([
@bunnia.view([
@bunnia.text("Demo Dashboard"),
@bunnia.button("Open Detail", "open-detail"),
]),
])
let plan = @bunnia.plan(page, @bunnia.wechat())
assert_eq(plan.node_count, 5)
}

///|
test {
let plan = @bunnia.plan_scene_assets_with_budget_and_policy(
[
@bunnia.remote_image_asset(
"remote-ok", "https://cdn.example.test/tile.png",
),
@bunnia.remote_image_asset(
"remote-bad", "https://assets.example.test/tile.png",
),
],
@bunnia.default_scene_asset_budget(),
@bunnia.scene_asset_policy(approved_remote_domains=["cdn.example.test"]),
)
assert_eq(plan.remote_assets, 2)
assert_eq(plan.unapproved_remote_asset_count, 1)
}

///|
test {
let app = @bunnia.program(
id="counter",
model=0,
view=fn(count) {
@bunnia.page([
@bunnia.text("Count \{count}"),
@bunnia.button("Increment", "inc"),
])
},
update=fn(count, msg) {
if msg == "inc" {
@bunnia.step(model=count + 1)
} else {
@bunnia.step(model=count)
}
},
)
let next = @bunnia.apply(app, "inc")
let output = @bunnia.generate_wechat_page(
"Counter",
@bunnia.current_view(next),
)
assert_true(output.wxml.contains("Count 1"))
}

///|
test {
let trace = @bunnia.communication_trace([
@bunnia.handoff(
id="handoff-1",
thread_id="thread-a",
from_actor_id="agent-a",
to_actor_id="operator",
text="Please review this result.",
open_message="open-review",
),
])
let output = @bunnia.generate_wechat_page("Trace", @bunnia.page([trace]))
assert_true(output.wxml.contains("bunnia-communication-handoff"))
assert_true(output.wxml.contains("open-review"))
}

///|
test {
let runtime = @bunnia.wechat_runtime(initial_data_json="{\"counter\":0}", event_patches=[
@bunnia.wechat_event_patch("open-detail", [@bunnia.set_json("counter", "1")]),
])
let project = @bunnia.generate_wechat_project_with_runtime(
name="Budgeted",
root=@bunnia.page([@bunnia.button("Open", "open-detail")]),
runtime~,
)
let report = @bunnia.report_wechat_project(project, runtime)
assert_eq(report.file_count, 10)
assert_true(project.manifest.summary.contains("app_files=9"))
assert_true(report.initial_data_bytes > 0)
assert_true(report.event_patch_bytes > 0)
}

///|
test {
let contract = @bunnia.backend_contract(id="agent-backend", endpoints=[
@bunnia.agent_message_endpoint(
"send-agent-message", "/agent/message", "message", "messageResult",
),
@bunnia.review_decision_endpoint(
"review-decision", "/review/decision", "review", "reviewResult",
),
])
let plan = @bunnia.plan_backend_contract(contract)
let effects = @bunnia.plan_backend_effects_for_platform(
contract,
@bunnia.wechat(),
)
let js = @bunnia.generate_wechat_request_adapter(contract)
assert_eq(plan.endpoint_count, 2)
assert_eq(effects.effect_count, 2)
assert_true(js.contains("wx.request"))
assert_true(!js.contains("secret"))
}

///|
test {
let plan = @bunnia.plan_snapshot_deltas([
@bunnia.set_snapshot_section_delta(
"home", "buildings", "[{\"id\":\"hall\"}]",
),
@bunnia.append_snapshot_item_delta(
"home", "messages", "msg-1", "{\"id\":\"msg-1\"}",
),
])
assert_eq(plan.section_update_count, 1)
assert_eq(plan.append_item_count, 1)
assert_eq(plan.full_snapshot_count, 0)
assert_true(plan.patch_plan.total_estimated_bytes < 128)
}

///|
test {
let assets = [@bunnia.sprite_asset("agent", "/assets/agent.png", 2048)]
let map = @bunnia.static_scene_view(
@bunnia.scene(
"overview",
@bunnia.scene_size(640, 480),
[
@bunnia.layer("districts", 1, [], regions=[
@bunnia.region(
id="district-a",
label="District A",
x=48,
y=64,
width=240,
height=160,
status="review",
tap_message="select-district-a",
),
]),
@bunnia.layer("actors", 10, [
@bunnia.marker(
id="actor-a",
label="Agent A",
x=120,
y=180,
status="running",
asset_ref="agent",
tap_message="select-actor-a",
),
]),
],
assets~,
),
)
let patches = @bunnia.plan_patches([
@bunnia.select_scene_region("overview", "district-a"),
@bunnia.set_scene_marker_status("overview", "actor-a", "selected"),
])
let output = @bunnia.generate_wechat_page("Map", @bunnia.page([map]))
assert_true(output.wxml.contains("data-region-id=\"district-a\""))
assert_true(output.wxml.contains("bunnia-scene-sprite"))
assert_true(patches.total_estimated_bytes < 96)
}

///|
test {
let map = @bunnia.scene(
"ops-map",
@bunnia.scene_size(640, 420),
[
@bunnia.layer("markers", 1, [
@bunnia.marker(
id="agent",
label="Agent",
x=120,
y=140,
status="running",
tap_message="select-agent",
asset_ref="agent",
),
]),
],
assets=[@bunnia.sprite_asset("agent", "/assets/agent.png", 2048)],
)
let quality = @bunnia.plan_scene_visual_quality(map)
assert_eq(quality.degraded, false)
assert_eq(quality.diagnostics.length(), 0)
}

///|
test {
let feed = @bunnia.message_feed([
@bunnia.message(
id="msg-1",
actor_id="agent-a",
thread_id="thread-a",
text="Working",
artifact_ref="artifact://result-a",
),
])
let map = @bunnia.static_scene_view(
@bunnia.scene("overview", @bunnia.scene_size(640, 480), [
@bunnia.layer("actors", 10, [
@bunnia.marker(
id="actor-a",
label="Agent A",
x=120,
y=180,
status="running",
tap_message="select-actor-a",
),
]),
]),
)
let output = @bunnia.generate_wechat_page("Demo", @bunnia.page([feed, map]))
assert_true(output.wxml.contains("select-actor-a"))
assert_true(output.js.contains("__bunnia.lastMessage"))
}

#
Actor

#
ActorKind

#
AgentDelta

#
AgentDeltaKind

#
AgentDeltaPlan

#
Attr

using @vectie/bunnia/core { type Attr }

#
BackendBudget

#
BackendContract

#
BackendEndpoint

#
BackendEndpointKind

#
BackendPlan

#
BackendRequest

#
BackendResult

#
BackendResultKind

#
BackendState

#
BuildProfile

#
BuildProfileBudget

#
BuildProfileGate

#
CiPlan

#
CiPlanStep

#
Communication

#
CommunicationBudget

#
CommunicationFilter

#
CommunicationKind

#
CommunicationPlan

#
Effect

#
EffectKind

#
EffectPlan

#
EventBinding

#
GeneratedSnapshot

#
GeneratedSnapshotFile

#
HttpMethod

#
Message

#
MiniappInspection

#
MiniappInspectionBudget

#
MiniappInspectionGate

#
MiniappReleaseReadinessReport

using @vectie/bunnia/tooling { type ReleaseReadinessReport as MiniappReleaseReadinessReport }

#
Node

using @vectie/bunnia/core { type Node }

#
Patch

using @vectie/bunnia/core { type Patch }

#
PatchBudget

#
PatchKind

#
PatchPlan

#
Platform

#
PlatformAdapter

#
PlatformComponentMapping

#
PlatformEventMapping

#
PlatformGeneratorStatus

#
PlatformLifecycleMapping

#
PlatformLimitsReport

#
PlatformRequestMapping

#
PlatformTargetSupport

#
Program

#
ProjectInspection

#
ProjectInspectionBudget

#
ProjectInspectionGate

#
ReleaseReadinessReport

#
RenderBudget

#
RenderPlan

#
ReviewAction

#
ReviewState

#
RouteInspection

#
RunStatus

#
ScaffoldFile

#
ScaffoldPlan

#
Scene

#
SceneAsset

#
SceneAssetBudget

#
SceneAssetKind

#
SceneAssetPlan

#
SceneAssetPolicy

#
SceneCamera

#
SceneCameraBudget

#
SceneCameraPlan

#
SceneLayer

#
SceneMarker

#
SceneQualityLevel

#
SceneRegion

#
SceneRenderBudget

#
SceneRenderMode

#
SceneRenderPlan

#
SceneSize

#
SceneSurfacePlan

#
SceneSurfacePreference

#
SceneThreadBudget

#
SceneThreadPlan

#
SceneViewport

#
SceneVisualQualityBudget

#
SceneVisualQualityPlan

#
SnapshotDelta

#
SnapshotDeltaKind

#
SnapshotDeltaPlan

#
SurfaceStatus

#
SurfaceStatusKind

#
Thread

#
ToolResultBudget

#
ToolResultCard

#
ToolResultPlan

#
WechatManifestSceneAsset

#
WechatProjectManifest

#
actor

fn actor(id~ : String, label~ : String, kind? :
ActorKind
) ->
Actor

#
agent_cancel_endpoint

fn agent_cancel_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
BackendEndpoint

#
agent_delta_kind_id

fn agent_delta_kind_id(kind :
AgentDeltaKind
) -> String

#
agent_message_endpoint

fn agent_message_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
BackendEndpoint

#
agent_retry_endpoint

fn agent_retry_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
BackendEndpoint

#
agent_stream_endpoint

fn agent_stream_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
BackendEndpoint

#
all_communication_filter

#
anchored_scene_thread_overlay

#
anchored_scene_thread_overlay_with_viewport

#
append_communication_delta

fn append_communication_delta(target_path : String, item :
Communication
) ->
AgentDelta

#
append_json

fn append_json(path : String, value_json : String) ->
Patch

#
append_message_delta

fn append_message_delta(target_path : String, item :
Message
) ->
AgentDelta

fn append_scene_thread_link(target_path : String, link :
SceneThreadLink
) ->
Patch

#
append_snapshot_item_delta

fn append_snapshot_item_delta(scope : String, section : String, item_id : String, value_json : String) ->
SnapshotDelta

#
append_stream_chunk_delta

fn append_stream_chunk_delta(target_path : String, chunk_id : String, text : String, status? :
RunStatus
) ->
AgentDelta

#
apply

fn[Model, Msg] apply(input :
Program
[Model, Msg], message : Msg) ->
Program
[Model, Msg]

#
approval

fn approval(id~ : String, thread_id~ : String, from_actor_id~ : String, to_actor_id~ : String, text~ : String, artifact_ref? : String, open_message? : String) ->
Communication

#
attr

fn attr(name : String, value : String) ->
Attr

#
backend_budget

fn backend_budget(max_endpoints~ : Int, max_streaming~ : Int, max_review_required~ : Int) ->
BackendBudget

#
backend_contract

fn backend_contract(id~ : String, base_url_key? : String, session_token_key? : String, session_header_key? : String, endpoints~ : Array[
BackendEndpoint
]) ->
BackendContract

#
backend_contract_effects

#
backend_endpoint

fn backend_endpoint(id~ : String, kind~ :
BackendEndpointKind
, http_method~ :
HttpMethod
, path~ : String, payload_key? : String, response_key? : String, timeout_ms? : Int, streaming? : Bool, requires_review? : Bool) ->
BackendEndpoint

#
backend_endpoint_kind_id

fn backend_endpoint_kind_id(kind :
BackendEndpointKind
) -> String

#
backend_error_patch

fn backend_error_patch(scope : String, message : String) ->
Patch

#
backend_failure

#
backend_malformed

#
backend_request

fn backend_request(id~ : String, endpoint~ :
BackendEndpoint
, payload_json? : String, replay_key? : String) ->
BackendRequest

#
backend_request_patches

#
backend_response_patch

fn backend_response_patch(scope : String, value_json : String) ->
Patch

#
backend_result_cancelled

#
backend_result_failure

#
backend_result_kind_id

fn backend_result_kind_id(kind :
BackendResultKind
) -> String

#
backend_result_malformed

#
backend_result_patches

#
backend_result_success

#
backend_result_timeout

#
backend_state_cancelled

fn backend_state_cancelled() ->
BackendState

#
backend_state_failed

#
backend_state_id

fn backend_state_id(state :
BackendState
) -> String

#
backend_state_idle

#
backend_state_loading

#
backend_state_malformed

fn backend_state_malformed() ->
BackendState

#
backend_state_patch

fn backend_state_patch(scope : String, state :
BackendState
) ->
Patch

#
backend_state_ready

#
backend_state_stale

#
backend_state_timeout

#
backend_success

#
backend_timeout

#
broadcast

fn broadcast(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, open_message? : String) ->
Communication

#
build_profile_budget

fn build_profile_budget(max_route_diagnostic_routes~ : Int, max_route_diagnostics~ : Int, max_unwindowed_list_children~ : Int, max_unkeyed_list_children~ : Int, max_duplicate_list_keys~ : Int, max_communication_unresolved_reviews~ : Int, max_tool_result_missing_acks~ : Int, max_agent_duplicate_stream_chunks~ : Int, max_snapshot_full_replaces~ : Int, max_scene_thread_orphans~ : Int, max_scene_camera_clamped~ : Int, max_scene_surface_fallbacks~ : Int, max_scene_insecure_remote_assets~ : Int, max_scene_unapproved_remote_assets~ : Int, max_scene_deferred_assets~ : Int, max_scene_quality_issues~ : Int, max_degraded_scenes~ : Int) ->
BuildProfileBudget

#
build_profile_budget_for_profile

fn build_profile_budget_for_profile(name : String) ->
BuildProfileBudget

#
button

fn button(label : String, message : String) ->
Node

#
cancel

fn cancel(id : String, target : String) ->
Effect

#
canvas

fn canvas(canvas_id : String) ->
Node

#
ci_plan

fn ci_plan(target? : String, budget_profile? : String, render_budget_profile? : String, examples? : Array[String], snapshot_dir? : String, post_build_steps? : Array[
CiPlanStep
]) ->
CiPlan

#
ci_plan_shell_script

fn ci_plan_shell_script(plan :
CiPlan
) -> String

#
ci_plan_step

fn ci_plan_step(name : String, command : String, purpose : String) ->
CiPlanStep

#
class_name

fn class_name(value : String) ->
Attr

#
cloud_function

fn cloud_function(id : String, target : String, payload_key : String) ->
Effect

#
communication

fn communication(id~ : String, thread_id~ : String, kind~ :
CommunicationKind
, from_actor_id~ : String, to_actor_id? : String, text~ : String, artifact_ref? : String, timestamp? : String, status? :
RunStatus
, open_message? : String) ->
Communication

#
communication_approval

#
communication_broadcast

#
communication_budget

fn communication_budget(max_visible_count? : Int, max_review_request_count? : Int, max_unresolved_review_count? : Int, max_artifact_ref_count? : Int) ->
CommunicationBudget

#
communication_filter

fn communication_filter(thread_id? : String, actor_id? : String, kind_id? : String, include_resolved_reviews? : Bool) ->
CommunicationFilter

#
communication_handoff

#
communication_kind_id

fn communication_kind_id(kind :
CommunicationKind
) -> String

#
communication_message

#
communication_recovery_notice

fn communication_recovery_notice() ->
CommunicationKind

#
communication_review_request

fn communication_review_request() ->
CommunicationKind

#
communication_tool_result

#
communication_trace

#
current_view

fn[Model, Msg] current_view(input :
Program
[Model, Msg]) ->
Node

#
data

fn data(name : String, value : String) ->
Attr

#
default_backend_budget

#
default_communication_budget

#
default_patch_budget

fn default_patch_budget() ->
PatchBudget

#
default_render_budget

fn default_render_budget() ->
RenderBudget

#
default_scene_asset_budget

#
default_scene_asset_policy

#
default_scene_camera_budget

#
default_scene_render_budget

#
default_scene_thread_budget

#
default_scene_visual_quality_budget

#
default_tool_result_budget

#
default_wechat_build_budget

#
default_wechat_runtime

#
effect

fn effect(id~ : String, kind~ :
EffectKind
, target~ : String, payload_key? : String, message? : String) ->
Effect

#
effect_kind_id

fn effect_kind_id(kind :
EffectKind
) -> String

#
endpoint_agent_message_send

#
endpoint_agent_operation_cancel

#
endpoint_agent_operation_retry

#
endpoint_agent_run_status

#
endpoint_effect

#
endpoint_handoff_submit

#
endpoint_operator_submit

#
endpoint_review_decision

#
endpoint_snapshot_load

#
endpoint_status_load

#
endpoint_thread_load

#
event

fn event(event : String, message : String) ->
EventBinding

#
form

fn form(submit_message : String, children : Array[
Node
]) ->
Node

#
generate_alipay_page

#
generate_alipay_project

fn generate_alipay_project(name~ : String, route? : String, root~ :
Node
) ->
MiniappProject

#
generate_miniapp_page

#
generate_miniapp_page_with_budget

#
generate_miniapp_project

fn generate_miniapp_project(name~ : String, route? : String, root~ :
Node
, platform~ :
Platform
) ->
MiniappProject

#
generate_miniapp_project_with_budget

fn generate_miniapp_project_with_budget(name~ : String, route? : String, root~ :
Node
, platform~ :
Platform
, render_budget~ :
RenderBudget
) ->
MiniappProject

#
generate_tiktok_page

#
generate_tiktok_project

fn generate_tiktok_project(name~ : String, route? : String, root~ :
Node
) ->
MiniappProject

#
generate_wechat_page

#
generate_wechat_page_with_runtime

#
generate_wechat_page_with_runtime_and_budget

#
generate_wechat_project

fn generate_wechat_project(name~ : String, route? : String, root~ :
Node
) ->
WechatProject

#
generate_wechat_project_from_pages

#
generate_wechat_project_from_pages_with_backend

#
generate_wechat_project_with_runtime

fn generate_wechat_project_with_runtime(name~ : String, route? : String, root~ :
Node
, runtime~ :
WechatRuntime
) ->
WechatProject

#
generate_wechat_project_with_runtime_and_backend

fn generate_wechat_project_with_runtime_and_backend(name~ : String, route? : String, root~ :
Node
, runtime~ :
WechatRuntime
, backend_contract~ :
BackendContract
) ->
WechatProject

#
generate_wechat_project_with_runtime_and_budget

fn generate_wechat_project_with_runtime_and_budget(name~ : String, route? : String, root~ :
Node
, runtime~ :
WechatRuntime
, render_budget~ :
RenderBudget
) ->
WechatProject

#
generate_wechat_project_with_runtime_and_budget_and_backend

fn generate_wechat_project_with_runtime_and_budget_and_backend(name~ : String, route? : String, root~ :
Node
, runtime~ :
WechatRuntime
, render_budget~ :
RenderBudget
, backend_contract~ :
BackendContract
) ->
WechatProject

#
generate_wechat_request_adapter

fn generate_wechat_request_adapter(contract :
BackendContract
) -> String

#
generate_wechat_runtime_js

fn generate_wechat_runtime_js() -> String

#
generate_wechat_set_data_call

fn generate_wechat_set_data_call(patches : Array[
Patch
]) -> String

#
generic_endpoint

fn generic_endpoint(id : String, path : String, http_method :
HttpMethod
, payload_key? : String, response_key? : String) ->
BackendEndpoint

#
handoff

fn handoff(id~ : String, thread_id~ : String, from_actor_id~ : String, to_actor_id~ : String, text~ : String, open_message? : String) ->
Communication

#
handoff_submit_endpoint

fn handoff_submit_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
BackendEndpoint

#
http_method_id

fn http_method_id(input :
HttpMethod
) -> String

fn id(value : String) ->
Attr

#
image

fn image(src : String, alt : String) ->
Node

#
image_asset

fn image_asset(id : String, src : String, estimated_bytes : Int) ->
SceneAsset

#
input

fn input(name~ : String, value? : String, input_message? : String) ->
Node

#
inspect_miniapp_project

fn inspect_miniapp_project(target~ : String, example~ : String, project :
MiniappProject
) ->
MiniappInspection

#
inspection_budget

fn inspection_budget(max_route_risk_score~ : Int, max_update_payload_bytes~ : Int, max_update_operations~ : Int, max_unwindowed_list_children~ : Int, max_unkeyed_list_children~ : Int, max_duplicate_list_keys~ : Int, max_backend_events~ : Int, max_backend_streams~ : Int, max_backend_reviews~ : Int, max_backend_cancels~ : Int, max_backend_retries~ : Int, max_scene_assets~ : Int, max_scene_remote_assets~ : Int, max_scene_package_bytes~ : Int) ->
ProjectInspectionBudget

#
inspection_budget_for_profile

fn inspection_budget_for_profile(name : String) ->
ProjectInspectionBudget

#
is_named_budget_profile

fn is_named_budget_profile(name : String) -> Bool

#
keyed

#
list

fn[Item] list(items : Array[Item], render : (Item) ->
Node
) ->
Node

#
login

fn login(id : String, target : String) ->
Effect

#
marker

fn marker(id~ : String, label~ : String, x~ : Int, y~ : Int, status? : String, tap_message? : String, asset_ref? : String, hit_width? : Int, hit_height? : Int) ->
SceneMarker

#
max_depth

fn max_depth(root :
Node
) -> Int

#
message

fn message(id~ : String, actor_id~ : String, thread_id~ : String, text~ : String, artifact_ref? : String, status? :
RunStatus
) ->
Message

#
message_event

fn message_event(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, artifact_ref? : String, open_message? : String) ->
Communication

#
miniapp_inspection_budget

fn miniapp_inspection_budget(max_pages~ : Int, max_files~ : Int, max_total_bytes~ : Int, max_route_diagnostic_routes~ : Int, max_route_diagnostics~ : Int, max_nodes~ : Int, max_depth~ : Int, max_events~ : Int, max_scene_markers~ : Int, max_scene_regions~ : Int, max_scene_assets~ : Int) ->
MiniappInspectionBudget

#
miniapp_inspection_budget_for_profile

fn miniapp_inspection_budget_for_profile(name : String) ->
MiniappInspectionBudget

#
miniapp_release_readiness_report

fn navigate(id : String, target : String) ->
Effect

#
node

fn node(kind~ : String, key? : String, attrs? : Array[
Attr
], events? : Array[
EventBinding
], children? : Array[
Node
], text? : String) ->
Node

#
node_count

fn node_count(root :
Node
) -> Int

#
operator_submit_endpoint

fn operator_submit_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
BackendEndpoint

#
patch_budget

fn patch_budget(max_patches~ : Int, max_patch_bytes~ : Int) ->
PatchBudget

#
plan_backend_effects_for_platform

#
plan_effects_for_platform

#
plan_patches_with_budget

#
plan_scene_visual_quality

#
platform_adapter

fn platform_adapter(platform~ :
Platform
, id~ : String, page_component~ : String, tap_event~ : String, component_prefix? : String, app_launch_lifecycle? : String, page_load_lifecycle? : String, page_ready_lifecycle? : String, request_api? : String, supports_canvas? : Bool, supports_cloud? : Bool, supports_stream? : Bool) ->
PlatformAdapter

#
platform_generator_available

fn platform_generator_available(status :
PlatformGeneratorStatus
) -> Bool

#
platform_generator_status_id

fn platform_generator_status_id(status :
PlatformGeneratorStatus
) -> String

#
platform_id

fn platform_id(platform :
Platform
) -> String

#
platform_label

fn platform_label(platform :
Platform
) -> String

#
platform_limits

#
platform_limits_for_adapter

#
platform_target_support

fn platform_target_support(target? : String) ->
PlatformTargetSupport

#
platform_target_support_for_adapter

fn platform_target_support_for_adapter(adapter :
PlatformAdapter
, generator_available? : Bool) ->
PlatformTargetSupport

#
prefer_canvas_surface

#
prefer_lightweight_surface

#
prefer_static_surface

#
program

fn[Model, Msg] program(id~ : String, model~ : Model, view~ : (Model) ->
Node
, update~ : (Model, Msg) ->
Step
[Model], init_effects? : Array[
Effect
]) ->
Program
[Model, Msg]

#
recovery_notice

fn recovery_notice(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, open_message? : String) ->
Communication

#
region

fn region(id~ : String, label~ : String, x~ : Int, y~ : Int, width~ : Int, height~ : Int, status? : String, tap_message? : String) ->
SceneRegion

#
remote_image_asset

fn remote_image_asset(id : String, src : String) ->
SceneAsset

#
remove_path

fn remove_path(path : String) ->
Patch

#
remove_snapshot_section_delta

fn remove_snapshot_section_delta(scope : String, section : String) ->
SnapshotDelta

#
render_budget

fn render_budget(max_nodes~ : Int, max_depth~ : Int, max_events~ : Int, max_initial_data_bytes~ : Int, max_unwindowed_list_children? : Int, max_scene_markers? : Int, max_scene_regions? : Int, max_scene_assets? : Int, max_degraded_scenes? : Int) ->
RenderBudget

#
render_budget_for_profile

fn render_budget_for_profile(name : String) ->
RenderBudget

#
replace_snapshot_delta

fn replace_snapshot_delta(scope : String, value_json : String) ->
SnapshotDelta

#
request

fn request(id : String, target : String, payload_key : String) ->
Effect

#
retry

fn retry(id : String, target : String) ->
Effect

#
review_action

fn review_action(id~ : String, label~ : String, approve_message~ : String, reject_message~ : String, state? :
ReviewState
) ->
ReviewAction

#
review_action_enabled

fn review_action_enabled(action :
ReviewAction
) -> Bool

#
review_approved

#
review_cancelled

#
review_decision_endpoint

fn review_decision_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
BackendEndpoint

#
review_failed

#
review_not_required

#
review_pending

#
review_rejected

#
review_request

fn review_request(id~ : String, thread_id~ : String, from_actor_id~ : String, to_actor_id~ : String, text~ : String, artifact_ref? : String, open_message? : String) ->
Communication

#
review_state_id

fn review_state_id(state :
ReviewState
) -> String

#
run_cancelled

#
run_failed

#
run_running

#
run_status_id

fn run_status_id(status :
RunStatus
) -> String

#
run_waiting_review

fn run_waiting_review() ->
RunStatus

#
scaffold_project

fn scaffold_project(name~ : String, module_name? : String) ->
ScaffoldPlan

#
scene_asset

fn scene_asset(id~ : String, kind~ :
SceneAssetKind
, src~ : String, estimated_bytes? : Int, remote? : Bool) ->
SceneAsset

#
scene_asset_budget

fn scene_asset_budget(max_assets~ : Int, max_package_bytes~ : Int, max_remote_assets~ : Int) ->
SceneAssetBudget

#
scene_asset_image

#
scene_asset_kind_id

fn scene_asset_kind_id(kind :
SceneAssetKind
) -> String

#
scene_asset_policy

fn scene_asset_policy(approved_remote_domains~ : Array[String], require_https? : Bool) ->
SceneAssetPolicy

#
scene_asset_remote_image

fn scene_asset_remote_image() ->
SceneAssetKind

#
scene_asset_sprite

#
scene_asset_tile

#
scene_camera

fn scene_camera(scene_id~ : String, x~ : Int, y~ : Int, width~ : Int, height~ : Int, zoom_percent? : Int) ->
SceneCamera

#
scene_camera_budget

fn scene_camera_budget(min_zoom_percent? : Int, max_zoom_percent? : Int, min_viewport_width? : Int, min_viewport_height? : Int) ->
SceneCameraBudget

#
scene_camera_from_viewport

fn scene_camera_from_viewport(scene_id : String, viewport :
SceneViewport
, zoom_percent? : Int) ->
SceneCamera

#
scene_marker_count

fn scene_marker_count(input :
Scene
) -> Int

fn scene_marker_thread_link(id~ : String, scene_id~ : String, marker_id~ : String, thread_id~ : String, subject_ref? : String, status? : String, unread_count? : Int, open_message? : String) ->
SceneThreadLink

#
scene_mode_canvas_surface

fn scene_mode_canvas_surface() ->
SceneRenderMode

#
scene_mode_lightweight_markup

fn scene_mode_lightweight_markup() ->
SceneRenderMode

#
scene_mode_static_markup

#
scene_quality_balanced

#
scene_quality_full

#
scene_quality_id

fn scene_quality_id(quality :
SceneQualityLevel
) -> String

#
scene_quality_lightweight

#
scene_region_count

fn scene_region_count(input :
Scene
) -> Int

fn scene_region_thread_link(id~ : String, scene_id~ : String, region_id~ : String, thread_id~ : String, subject_ref? : String, status? : String, unread_count? : Int, open_message? : String) ->
SceneThreadLink

#
scene_render_budget

fn scene_render_budget(max_layers~ : Int, max_markers~ : Int, max_static_assets~ : Int, max_regions? : Int) ->
SceneRenderBudget

#
scene_render_mode_id

fn scene_render_mode_id(mode :
SceneRenderMode
) -> String

#
scene_size

fn scene_size(width : Int, height : Int) ->
SceneSize

#
scene_surface_preference_id

fn scene_surface_preference_id(preference :
SceneSurfacePreference
) -> String

#
scene_thread_budget

fn scene_thread_budget(max_visible_links? : Int, max_unread_total? : Int, max_orphan_links? : Int, max_links_without_open_message? : Int) ->
SceneThreadBudget

fn scene_thread_link(id~ : String, scene_id~ : String, subject_kind~ : String, subject_id~ : String, thread_id~ : String, subject_ref? : String, status? : String, unread_count? : Int, open_message? : String) ->
SceneThreadLink

#
scene_thread_overlay

#
scene_viewport

fn scene_viewport(x~ : Int, y~ : Int, width~ : Int, height~ : Int) ->
SceneViewport

#
scene_visible_marker_count

fn scene_visible_marker_count(input :
Scene
, viewport :
SceneViewport
) -> Int

#
scene_visible_region_count

fn scene_visible_region_count(input :
Scene
, viewport :
SceneViewport
) -> Int

#
scene_visual_quality_budget

fn scene_visual_quality_budget(min_width~ : Int, min_height~ : Int, max_markers_without_status~ : Int, max_markers_without_tap~ : Int, max_markers_without_asset_ref~ : Int, max_unresolved_asset_refs~ : Int, max_regions_without_status? : Int, max_regions_without_tap? : Int, min_hit_width? : Int, min_hit_height? : Int, max_small_hit_targets? : Int) ->
SceneVisualQualityBudget

#
scroll_view

#
select_scene_marker

fn select_scene_marker(scene_id : String, marker_id : String) ->
Patch

#
select_scene_marker_thread

fn select_scene_marker_thread(scene_id : String, marker_id : String, thread_id : String) ->
Patch

#
select_scene_region

fn select_scene_region(scene_id : String, region_id : String) ->
Patch

#
select_scene_region_thread

fn select_scene_region_thread(scene_id : String, region_id : String, thread_id : String) ->
Patch

#
select_scene_thread

fn select_scene_thread(scene_id : String, subject_kind : String, subject_id : String, thread_id : String) ->
Patch

#
set_json

fn set_json(path : String, value_json : String) ->
Patch

#
set_review_state_delta

fn set_review_state_delta(target_path : String, state :
ReviewState
) ->
AgentDelta

#
set_run_status_delta

fn set_run_status_delta(target_path : String, status :
RunStatus
) ->
AgentDelta

#
set_scene_camera

fn set_scene_camera(scene_id : String, camera :
SceneCamera
) ->
Patch

#
set_scene_camera_position

fn set_scene_camera_position(scene_id : String, x : Int, y : Int) ->
Patch

#
set_scene_camera_viewport

fn set_scene_camera_viewport(scene_id : String, viewport :
SceneViewport
) ->
Patch

#
set_scene_camera_zoom

fn set_scene_camera_zoom(scene_id : String, zoom_percent : Int) ->
Patch

#
set_scene_marker_status

fn set_scene_marker_status(scene_id : String, marker_id : String, status : String) ->
Patch

#
set_scene_region_status

fn set_scene_region_status(scene_id : String, region_id : String, status : String) ->
Patch

#
set_scene_thread_status

fn set_scene_thread_status(scene_id : String, thread_id : String, status : String) ->
Patch

#
set_scene_thread_unread

fn set_scene_thread_unread(scene_id : String, thread_id : String, unread_count : Int) ->
Patch

#
set_snapshot_section_delta

fn set_snapshot_section_delta(scope : String, section : String, value_json : String) ->
SnapshotDelta

#
set_stream_chunk_delta

fn set_stream_chunk_delta(target_path : String, chunk_id : String, text : String, status? :
RunStatus
) ->
AgentDelta

#
set_string

fn set_string(path : String, value : String) ->
Patch

#
share

fn share(id : String, target : String) ->
Effect

#
snapshot_delta_kind_id

fn snapshot_delta_kind_id(kind :
SnapshotDeltaKind
) -> String

#
snapshot_load_endpoint

fn snapshot_load_endpoint(id : String, path : String, response_key : String) ->
BackendEndpoint

#
snapshot_miniapp_project

#
snapshot_wechat_project

#
snapshot_wechat_project_with_report

fn snapshot_wechat_project_with_report(target~ : String, example~ : String, project :
WechatProject
, report :
WechatBuildReport
, profile :
BuildProfile
, budget_profile? : String, render_budget_profile? : String) ->
GeneratedSnapshot

#
sprite_asset

fn sprite_asset(id : String, src : String, estimated_bytes : Int) ->
SceneAsset

#
static_scene_view

#
static_scene_view_with_budget

#
static_scene_with_windowed_threads

fn static_scene_with_windowed_threads(input :
Scene
, links : Array[
SceneThreadLink
], total_count~ : Int, offset? : Int) ->
Node

#
status_load_endpoint

fn status_load_endpoint(id : String, path : String, response_key : String) ->
BackendEndpoint

#
step

fn[Model] step(model~ : Model, effects? : Array[
Effect
], patches? : Array[
Patch
]) ->
Step
[Model]

#
step_patches

#
storage

fn storage(id : String, target : String, payload_key : String) ->
Effect

#
stream

fn stream(id : String, target : String, payload_key : String) ->
Effect

#
supported_platforms

fn supported_platforms() -> Array[
Platform
]

#
surface_cancelled

fn surface_cancelled(label? : String, detail? : String, action_message? : String) ->
SurfaceStatus

#
surface_degraded

fn surface_degraded(label? : String, detail? : String, action_message? : String) ->
SurfaceStatus

#
surface_error

fn surface_error(label? : String, detail? : String, action_message? : String) ->
SurfaceStatus

#
surface_loading

fn surface_loading(label? : String, detail? : String) ->
SurfaceStatus

#
surface_ready

fn surface_ready(label? : String, detail? : String) ->
SurfaceStatus

#
surface_retry

fn surface_retry(label? : String, detail? : String, action_message? : String) ->
SurfaceStatus

#
surface_stale

fn surface_stale(label? : String, detail? : String, action_message? : String) ->
SurfaceStatus

#
surface_status

fn surface_status(kind~ :
SurfaceStatusKind
, label~ : String, detail? : String, action_message? : String) ->
SurfaceStatus

#
surface_status_badge

#
surface_status_cancelled

#
surface_status_degraded

#
surface_status_error

#
surface_status_kind_id

fn surface_status_kind_id(kind :
SurfaceStatusKind
) -> String

#
surface_status_loading

#
surface_status_overlay

#
surface_status_ready

#
surface_status_retry

#
surface_status_stale

#
text

fn text(value : String) ->
Node

#
thread

fn thread(id~ : String, title~ : String, owner_actor_id~ : String, subject_ref? : String, status? :
RunStatus
) ->
Thread

#
thread_load_endpoint

fn thread_load_endpoint(id : String, path : String, response_key : String) ->
BackendEndpoint

#
tile_asset

fn tile_asset(id : String, src : String, estimated_bytes : Int) ->
SceneAsset

#
tool_ack_endpoint

fn tool_ack_endpoint(id : String, path : String, payload_key : String) ->
BackendEndpoint

#
tool_result

fn tool_result(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, artifact_ref~ : String, open_message? : String) ->
Communication

#
tool_result_budget

fn tool_result_budget(max_visible_count? : Int, max_pending_ack_count? : Int, max_missing_ack_count? : Int, max_artifact_ref_count? : Int) ->
ToolResultBudget

#
tool_result_card

fn tool_result_card(id~ : String, tool_name~ : String, title~ : String, summary~ : String, artifact_ref? : String, status? :
RunStatus
, open_message? : String, acknowledge_message? : String) ->
ToolResultCard

#
tool_result_card_list

#
tool_result_card_view

#
wechat_build_budget

fn wechat_build_budget(max_pages~ : Int, max_files~ : Int, max_total_bytes~ : Int, max_wxml_bytes~ : Int, max_wxss_bytes~ : Int, max_js_bytes~ : Int, max_initial_data_bytes~ : Int, max_event_patch_bytes~ : Int, max_event_patch_operations~ : Int, max_page_first_screen_bytes~ : Int, max_page_update_payload_bytes~ : Int, max_page_update_operations~ : Int) ->
WechatBuildBudget

#
wechat_build_budget_for_profile

fn wechat_build_budget_for_profile(name : String) ->
WechatBuildBudget

#
wechat_event_patch

#
wechat_page_with_wxss

#
wechat_runtime

fn wechat_runtime(initial_data_json? : String, event_patches? : Array[
WechatEventPatch
], page_methods_js? : String) ->
WechatRuntime

#
when

fn when(condition : Bool, child :
Node
) ->
Node

#
windowed_anchored_scene_thread_overlay

fn windowed_anchored_scene_thread_overlay(input :
Scene
, links : Array[
SceneThreadLink
], total_count~ : Int, offset? : Int) ->
Node

#
windowed_anchored_scene_thread_overlay_with_viewport

fn windowed_anchored_scene_thread_overlay_with_viewport(input :
Scene
, viewport :
SceneViewport
, links : Array[
SceneThreadLink
], total_count~ : Int, offset? : Int) ->
Node

#
windowed_communication_trace

fn windowed_communication_trace(items : Array[
Communication
], total_count~ : Int, offset? : Int) ->
Node

#
windowed_list

fn[Item] windowed_list(items : Array[Item], total_count~ : Int, offset? : Int, render~ : (Item) ->
Node
) ->
Node

#
windowed_message_feed

fn windowed_message_feed(messages : Array[
Message
], total_count~ : Int, offset? : Int) ->
Node

#
windowed_scene_thread_overlay

fn windowed_scene_thread_overlay(links : Array[
SceneThreadLink
], total_count~ : Int, offset? : Int) ->
Node

#
windowed_tool_result_card_list

fn windowed_tool_result_card_list(cards : Array[
ToolResultCard
], total_count~ : Int, offset? : Int) ->
Node

Source Files