Skip to content

Add source-grounded multimodal media slots to wiki pages - #626

Merged
fishmingyu merged 4 commits into
sysevol-ai:mainfrom
MarinaMackay:codex/multimodal-codewiki-media-slots
Aug 15, 2026
Merged

Add source-grounded multimodal media slots to wiki pages#626
fishmingyu merged 4 commits into
sysevol-ai:mainfrom
MarinaMackay:codex/multimodal-codewiki-media-slots

Conversation

@MarinaMackay

@MarinaMackay MarinaMackay commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Add a source-grounded multimodal layer to CodeWiki pages. Wiki pages expose deterministic media slots, render a key-free local SVG preview out of the box, and can optionally materialize bounded PNG assets through an OpenAI-compatible image endpoint.

Changes

  • Plan deterministic media slots for directory-based and agent-generated wiki pages, including placement, purpose, citations, prompts, and editable human-prior metadata.
  • Add a local SVG renderer and an optional OpenAI-compatible PNG generator.
  • Serve repository-scoped media assets through FastAPI and render them in the CodeWiki frontend.
  • Authenticate cached assets against the complete render input and generated content.
  • Bound slot, prompt, response, decoded-image, manifest, dimension, timeout, and configuration inputs.
  • Keep generated paths inside hashed repository/page storage roots; reject traversal, links, malformed names, unsafe remote URLs, credentials, and unexpected media types.
  • Use atomic writes and process-local per-asset locking to avoid partial or duplicate materialization.
  • Add frontend URL validation, restrictive SVG response headers, source citations, responsive previews, and generation status.
  • Document local preview and optional hosted-provider setup.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring
  • Performance improvement
  • Tests

Testing

  • Tests pass locally
  • Added new tests for the changes

Commands and results:

pytest -q test/wiki test/web/test_app_runtime.py test/web/test_config.py   test/web/test_static_export.py test/web/test_static_server.py
346 passed

cd web
npm test -- --run
8 files / 28 tests passed
npx tsc --noEmit
npm run build

pre-commit run --files <changed files>
all applicable hooks passed

umask 022
pytest -q -m "not slow and not integration and not integration_serial and not integration_serial_consumer"   --deselect=test/test_release_metadata.py::test_runtime_version_comes_from_distribution_metadata
5465 passed, 71 skipped, 191 deselected

The deselected version assertion also fails on the exact clean base because this machine still has CodeNib 0.2.0 distribution metadata installed while the checkout is 0.2.1; it is unrelated to this PR.

Manual preview:

export CODENIB_WIKI_MEDIA_MODEL=local/svg
codenib wiki /path/to/repository

Open a local wiki page and look for Multimodal CodeWiki. The local renderer requires no paid model key. Optional provider configuration and its first uncached network call are documented in docs/experiments/multimodal_codewiki_preview.md.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

@github-actions github-actions Bot added type/test Test-related type/docs Documentation labels Aug 14, 2026
MarinaMackay and others added 3 commits August 15, 2026 15:45
Keep generated media within bounded repository-scoped storage, validate provider inputs and outputs, and make cache reuse content-authenticated. Harden the frontend asset URL boundary and add concurrency, traversal, resource-limit, configuration, and rendering regressions.

Verified with the focused wiki/web suites, the frontend test/typecheck/build tiers, pre-commit, and the unit tier.
@fishmingyu
fishmingyu force-pushed the codex/multimodal-codewiki-media-slots branch from cb4137b to a689eb0 Compare August 15, 2026 23:06
@fishmingyu
fishmingyu marked this pull request as ready for review August 15, 2026 23:08
@fishmingyu
fishmingyu marked this pull request as draft August 15, 2026 23:09
@fishmingyu
fishmingyu marked this pull request as ready for review August 15, 2026 23:09
Store the experiment-only SVG beside its excluded guide so the public documentation boundary does not publish an otherwise unlisted static asset.

Verified with the public-docs unit tests, a strict MkDocs build, the public boundary checker, and pre-commit.
@fishmingyu
fishmingyu merged commit 9816093 into sysevol-ai:main Aug 15, 2026
17 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a689eb03c6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web/lib/runtime.ts
if (pathname.split("/").some((segment) => segment === "." || segment === "..")) {
return null;
}
return assetUrl(value);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve local media URLs against the API origin

When __CODENIB_API_BASE__ points to a different origin, fetchWikiPage correctly loads the page through that API base, but the returned local URI (api/repos/...) is resolved here through the frontend's base path instead. Consequently, both the image preview and “Open generated asset” link request the frontend origin and return 404 even though the asset exists on the backend; backend-relative media should be resolved using the configured API base.

Useful? React with 👍 / 👎.

Comment on lines +174 to +176
elif item.get("url"):
uri = _validated_remote_asset_url(str(item["url"]))
mime_type = "image/*"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid caching temporary hosted image URLs indefinitely

When an OpenAI-compatible provider returns a signed or otherwise temporary hosted URL, this branch stores the URL in the manifest without downloading the asset or recording an expiry. _read_cached_asset subsequently treats any syntactically valid remote URL as a permanent cache hit, so after the URL expires every later page load keeps returning the broken asset and never calls the provider again; either materialize hosted responses locally or make remote cache entries expire.

Useful? React with 👍 / 👎.

page_id=str(meta.get("id") or ""),
title=str(meta.get("title") or meta.get("id") or ""),
citations=citations,
relations=[item.__dict__ for item in relations],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Serialize slotted relation items without __dict__

When a freshly generated AgentWiki page has at least one static relation, each item is a RelationItem declared with @dataclass(..., slots=True), so it has no __dict__. This comprehension raises AttributeError while constructing the response, causing the page request to fail before the page is cached; serialize with dataclasses.asdict, explicit fields, or the already-produced evidence metadata instead.

Useful? React with 👍 / 👎.

Comment on lines +370 to +372
citations = _source_citations(slot)
if citations:
parts.append("Source citations: " + ", ".join(citations))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass actual source evidence to the image provider

For every external provider generation, the constructed prompt contains only citation filenames plus generic purpose text; no source snippets, existing diagram, graph edges, or relation endpoints are sent to the standalone images endpoint. The model therefore cannot follow the slot instructions to use the cited code and graph as its technical source of truth, so potentially hallucinated visuals are presented as source-grounded; include bounded evidence content and structural facts in the generation input.

Useful? React with 👍 / 👎.

Comment on lines +500 to +504
with _ASSET_LOCKS_GUARD:
lock = _ASSET_LOCKS.get(key)
if lock is None:
lock = threading.Lock()
_ASSET_LOCKS[key] = lock

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Coordinate asset generation across server processes

When the FastAPI application runs in multiple worker processes, this threading.Lock registry exists independently in each process. Simultaneous first requests for the same uncached page can therefore all pass the cache check and invoke the billed image provider, and their independent image/manifest replacements can interleave and leave a hash mismatch that triggers another regeneration; use a filesystem or other inter-process lock around the cache-check-and-generate transaction.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/docs Documentation type/test Test-related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants