Security (from a dynamic security audit of the branch):
- H1: UnityWebRequestTransport disables auto-redirect on auth-bearing
requests (redirectLimit=0) so a provider 3xx can't re-send the API key
to a redirect host.
- H2/P8: per-kind result-extension allowlist in AssetGenJobManager.WriteFile
(+ defense-in-depth in the audio/image import pipelines) — a provider
can no longer land a .cs/.asmdef/.meta/.asset under Assets/ (Editor RCE).
- H3: ProviderHttp.RequireHost pins the submit URL and the provider-supplied
response_url to https://queue.fal.run before the fal key is attached
(both fal image + audio adapters).
Correctness (from code review):
- C1: Tripo image->3D now sends model_version.
- C2/C3/C6/C10: FalAudioAdapter.BuildBody is catalog-driven — duration-
required models (CassetteAI SFX/Music, Stable Audio) send a default
duration when the caller passes 0 (fixes the default-input 422),
fractional durations floor to >=1, Lyria stays prompt-only and its GUI
no longer advertises a duration it ignores, and the clamp ceilings come
from the catalog (no more duplicated 190/30/180).
- C4: an unmapped fal poll status now fails fast instead of polling to the
600s timeout (both fal adapters).
- C5: a stale/invalid selected-model pref is cleared on dropdown fallback.
- C7: the audio fal-key status refreshes when the shared 2D fal key changes.
Cleanup: extract AssetGenModelCatalog.ResolveModel (dedupes the model-
resolution chain across the three generate tools) + DefaultModelId no-alloc.
Verified: full EditMode suite 1166 tests, 0 failures (+19 new regression
tests); 34 Python asset-gen tests pass.
Claude-Session: https://claude.ai/code/session_015KYy51gwBuhDuLZXXoqc98
Wraps each category (3D Models / 2D Images / Sound) in its own darker rounded panel
so they read as distinct blocks, and moves the per-provider key status (saved/not set)
up into the header row to the right of the provider name — reclaiming a line per
provider. Verified live: 3 panels (bg alpha 0.20), status inline in each header.
Claude-Session: https://claude.ai/code/session_01GCxmdd4qo7MG6J4M6WcT9Y
The provider row is a vertical (column) container, so the setting-dropdown-inline
class's flex-grow:1 stretched the DropdownField vertically. Wrap the Model dropdown
in a horizontal .setting-row with a .setting-label (matching the Format row) and use
a label-less DropdownField. Verified live: all 5 model dropdowns now render at 18px
inside setting-row containers instead of ~400px boxes.
Claude-Session: https://claude.ai/code/session_01GCxmdd4qo7MG6J4M6WcT9Y
Phases 4-5. Extends the existing Asset Gen tab (no new window): per-provider
'Model' dropdowns on the image + 3D rows with price/duration/use-case metadata, a
fal audio row (no key field — reuses the shared fal key) with a model dropdown and
the Stable Audio license caveat, and a Refresh button that re-validates key
presence + the curated catalog. Selecting a model writes the per-(kind,provider)
pref that generate_* reads as its default. fal has no public list-models API, so
Refresh is a curated re-validate (the plan's gated fallback), never a network fetch.
Characterization tests assert the new builders + three-phase lifecycle.
Claude-Session: https://claude.ai/code/session_01GCxmdd4qo7MG6J4M6WcT9Y
Informational row (not a keyed provider) with a best-effort "Blender app detected"
status and a pointer to the blender-to-unity workflow / import_model_file. BlenderMCP
runs in the AI client and isn't detectable from Unity, so this reports only the
locally installed Blender app.
- BlenderDetection helper: checks well-known install paths + PATH per platform; the
pure DetectIn(candidates, exists) core is unit-tested with a fake predicate.
- McpAssetGenSection: AddBlenderHandoffRow() appended after the provider rows.
- README: note the tab's best-effort detection + that BlenderMCP lives in the AI client.
Verified: package compiles clean; EditMode 972/1018 pass, 0 failures (4 new
BlenderDetection tests) via tools/local_harness.py.
Claude-Session: https://claude.ai/code/session_015DAUrMR5UaSEzEn2wNPrEP
Security review + code review of the asset-gen feature surfaced concrete issues;
this fixes them and adds regression tests (request-shaping layer, FakeHttpTransport).
Security
- SafeZipExtractor enforces an extension allowlist; ModelImportPipeline passes an
inert model/texture allowlist so a provider archive can't drop a .cs/.dll under
Assets/ and have the Editor compile/load it (code execution on import).
- AssetGenJobManager refuses non-http(s) download URLs before fetching
(file:// SSRF / local-file read into the project).
Provider correctness
- Meshy image->3D polls /openapi/v1/image-to-3d/{id} (was the v2 text URL).
- Meshy text->3D honors texture=true via the preview->refine two-phase flow.
- OpenRouter image->image attaches the reference image (content image_url part).
- fal image->image uses the /edit endpoint + image_urls array; width/height
forwarded as image_size.
- Sketchfab search forwards categories/count/cursor/downloadable; preview doc
corrected (returns metadata, not a base64 thumbnail).
- Job import calls AssetDatabase.Refresh() before importing a freshly written file.
Local image input (image_path)
- New LocalImage helper; image_path is read and sent inline as a base64 data URI
for Meshy / fal / OpenRouter. Tripo rejects local images with a clear error
(needs a hosted image_url; its upload flow is not wired).
Cleanup (no behavior change)
- Shared AssetGenPaths + ProviderHttp helpers, HttpResult.Ok, MissingKeyMessage,
cached glTFast probe, dead-field / per-frame-alloc removal, CLI _emit.
Docs: README + manual-verification updated (image_path support; transparency is
import-flag-only; width/height fal-only).
Verified: package compiles clean; Python 1306 passed / 3 skipped. Meshy refine,
fal /edit, and image_path data-URI paths are unit-tested at the request layer
only -- live smoke per provider (real keys) still pending.
Claude-Session: https://claude.ai/code/session_015DAUrMR5UaSEzEn2wNPrEP
Drop Hunyuan (Tencent TC3-HMAC) — high effort and not testable by the maintainer:
delete HunyuanAdapter + TencentCloud3Signer (+tests), unwire from AssetGenProviders,
SecureKeyStoreConstants, the GUI provider list, and Python/CLI/README/manual-verify docs.
Refresh model defaults to current (2026) SOTA, verified against provider docs:
- fal: fal-ai/flux/dev -> fal-ai/flux-2 (FLUX.2 dev; cheaper and higher quality)
- Tripo: v2.5-20250123 -> v3.1-20260211 (current recommended model)
- Meshy: drop deprecated art_style (errors on Meshy-6); pin ai_model=meshy-6
- OpenRouter: gemini-2.5-flash-image-preview (delisted) -> gemini-2.5-flash-image
Fix two tests that asserted the now-implemented 'meshy' provider throws (repointed to the
now-removed 'hunyuan'). They were silently wrong: the headless --full runs never executed
EditMode tests (Unity -quit exits before -runTests; compile-only). A real -runTests run
now passes 62/62 AssetGen EditMode tests; Python suite 1299 passed.
Claude-Session: https://claude.ai/code/session_01Tjpb5gYgUe2AUJuRdXr7Lv
New 'Asset Gen' tab in MCPForUnityEditorWindow: per-provider API-key entry backed by
SecureKeyStore (never EditorPrefs/project — field never reads the stored key back),
enable toggles, Test presence-check, Clear; non-secret prefs (default format, output
root, auto-normalize); glTFast-missing notice pointing to the Dependencies tab. No
Generate button / prompt — generation is MCP/CLI only. Wired exactly like the Advanced
tab. Compiles clean on Unity 2021.3.45f2.
Claude-Session: https://claude.ai/code/session_01Tjpb5gYgUe2AUJuRdXr7Lv