diff --git a/.agents/skills/infographic-agent/README.md b/.agents/skills/infographic-agent/README.md index 2c1167c..f9e4ad9 100644 --- a/.agents/skills/infographic-agent/README.md +++ b/.agents/skills/infographic-agent/README.md @@ -24,7 +24,7 @@ npx infographic-agent "Top 5 programming languages in 2026" ## 📋 Prerequisites -- **Python 3.8+** +- **Python 3.9+** - **Gemini API Key**: Get a free key at [Google AI Studio](https://aistudio.google.com/apikey). Set it as: ```bash export GEMINI_API_KEY="your-key" diff --git a/.agents/skills/infographic-agent/SKILL.md b/.agents/skills/infographic-agent/SKILL.md index a6051fb..665e0d0 100644 --- a/.agents/skills/infographic-agent/SKILL.md +++ b/.agents/skills/infographic-agent/SKILL.md @@ -6,7 +6,7 @@ description: > then gemini-3.1-flash-lite-image renders it into a PNG. No browser, Playwright, or Chromium dependencies — the only requirement is Google's GenAI SDK. Fully portable to any agent CLI environment. metadata: - version: "3.2.0" + version: "3.2.2" author: "Infographic Agent contributors" --- diff --git a/.agents/skills/infographic-agent/bin/infographic-agent.js b/.agents/skills/infographic-agent/bin/infographic-agent.js index 95bf0ce..a43f0ac 100755 --- a/.agents/skills/infographic-agent/bin/infographic-agent.js +++ b/.agents/skills/infographic-agent/bin/infographic-agent.js @@ -51,7 +51,7 @@ function findPython() { if (match) { const major = parseInt(match[1], 10); const minor = parseInt(match[2], 10); - if (major >= 3 && minor >= 8) return candidate; + if (major >= 3 && minor >= 9) return candidate; } } } @@ -120,7 +120,7 @@ Examples: if (!python) { err( - "Python 3.8+ is required but was not found on your PATH.\n\n" + + "Python 3.9+ is required but was not found on your PATH.\n\n" + " Install Python from https://www.python.org/downloads/ and make sure\n" + " it is on your PATH, then re-run:\n\n" + " npx infographic-agent ..." @@ -132,7 +132,7 @@ if (!python) { if (doInstall) { print("Installing Python dependencies (google-genai, pillow)..."); - const result = run(python, ["-m", "pip", "install", "--upgrade", "google-genai", "pillow"]); + const result = run(python, ["-m", "pip", "install", "--upgrade", "google-genai>=1.47.0", "pillow"]); if (result.status !== 0) process.exit(result.status); print(` diff --git a/.agents/skills/infographic-agent/package.json b/.agents/skills/infographic-agent/package.json index 8a1fb50..ff587c1 100644 --- a/.agents/skills/infographic-agent/package.json +++ b/.agents/skills/infographic-agent/package.json @@ -1,6 +1,6 @@ { "name": "infographic-agent", - "version": "3.2.0", + "version": "3.2.2", "description": "Generate professional infographic PNGs from text with Gemini — a research agent (gemini-3.5-flash) prepares and validates the prompt, then gemini-3.1-flash-lite-image renders it. No browser/Playwright deps.", "license": "MIT", "author": "Ryan Baumann", diff --git a/.agents/skills/infographic-agent/portable_infographic.py b/.agents/skills/infographic-agent/portable_infographic.py index bc33b6f..2b67230 100755 --- a/.agents/skills/infographic-agent/portable_infographic.py +++ b/.agents/skills/infographic-agent/portable_infographic.py @@ -637,9 +637,14 @@ def _normalize_to_png(data: bytes, mime: str): return data, m +def _config_fields(config_type): + """Return the declared fields across supported Pydantic SDK versions.""" + return getattr(config_type, "model_fields", None) or getattr(config_type, "__fields__", {}) + + def _image_config(aspect: str, resolution: str): - """Use newer quality controls only when the installed SDK supports them.""" - fields = getattr(types.ImageConfig, "model_fields", {}) + """Request image size only when the installed SDK exposes that field.""" + fields = _config_fields(types.ImageConfig) kwargs = {"aspect_ratio": aspect} if "image_size" in fields: kwargs["image_size"] = resolution @@ -649,7 +654,8 @@ def _image_config(aspect: str, resolution: str): def _thinking_config(): - fields = getattr(types.ThinkingConfig, "model_fields", {}) + """Use high thinking on current SDKs and dynamic thinking on older SDKs.""" + fields = _config_fields(types.ThinkingConfig) if "thinking_level" in fields: return types.ThinkingConfig(thinking_level="HIGH", include_thoughts=True) return types.ThinkingConfig(thinking_budget=-1, include_thoughts=True) diff --git a/.agents/skills/infographic-agent/requirements.txt b/.agents/skills/infographic-agent/requirements.txt index bb94f99..704b837 100644 --- a/.agents/skills/infographic-agent/requirements.txt +++ b/.agents/skills/infographic-agent/requirements.txt @@ -1,4 +1,4 @@ # Runtime dependencies. Install with: pip install -r requirements.txt # (or: pip install google-genai pillow) -google-genai>=1.0.0 # Gemini SDK — the two-agent research + image pipeline +google-genai>=1.47.0 # Gemini SDK — includes the typed image/thinking config surface tested here pillow>=10.0.0 # transcodes the model's output to lossless PNG (crisp text) diff --git a/.agents/skills/infographic-agent/test_portable_infographic.py b/.agents/skills/infographic-agent/test_portable_infographic.py new file mode 100644 index 0000000..464ccb9 --- /dev/null +++ b/.agents/skills/infographic-agent/test_portable_infographic.py @@ -0,0 +1,62 @@ +import importlib.util +import unittest +from pathlib import Path +from types import SimpleNamespace +from unittest.mock import patch + + +SCRIPT_PATH = Path(__file__).with_name("portable_infographic.py") +SPEC = importlib.util.spec_from_file_location("portable_infographic", SCRIPT_PATH) +portable = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(portable) + + +def config_type(*field_names): + class Config: + model_fields = {name: object() for name in field_names} + + def __init__(self, **kwargs): + self.kwargs = kwargs + + return Config + + +class SDKConfigCompatibilityTest(unittest.TestCase): + def test_current_sdk_requests_resolution_and_high_thinking(self): + fake_types = SimpleNamespace( + ImageConfig=config_type("aspect_ratio", "image_size"), + ThinkingConfig=config_type("thinking_level", "include_thoughts"), + ) + + with patch.object(portable, "types", fake_types): + image = portable._image_config("16:9", "1K") + thinking = portable._thinking_config() + + self.assertEqual(image.kwargs, {"aspect_ratio": "16:9", "image_size": "1K"}) + self.assertEqual( + thinking.kwargs, + {"thinking_level": "HIGH", "include_thoughts": True}, + ) + + def test_sdk_1_47_falls_back_to_supported_fields(self): + fake_types = SimpleNamespace( + ImageConfig=config_type("aspect_ratio"), + ThinkingConfig=config_type("thinking_budget", "include_thoughts"), + ) + + with patch.object(portable, "types", fake_types), patch.object(portable, "warn") as warn: + image = portable._image_config("16:9", "1K") + thinking = portable._thinking_config() + + self.assertEqual(image.kwargs, {"aspect_ratio": "16:9"}) + self.assertEqual( + thinking.kwargs, + {"thinking_budget": -1, "include_thoughts": True}, + ) + warn.assert_called_once_with( + "Installed google-genai does not expose image_size; using the model's native resolution." + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/CHANGELOG.md b/CHANGELOG.md index b945ee1..cefc5bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - Replaced the oversized text-heavy hero with a 16:9 growth-loop diagram, added a separate 1200×627 social card, and embedded a purpose-built agent-evaluation loop in the article. - Added reusable front-matter aliases for future detail-page renames and documented the workflow in the portfolio content skill. - Hardened aliases against slashless duplicates, canonical-page collisions, private-route disclosure, stale canonicals, external targets, and bodyless entries. -- Installed Infographic Agent 3.2.0 and documented the required three-asset visual standard for every future hosted essay. +- Updated the vendored Infographic Agent skill to the merged 3.2.1 source, including Python 3.9 / `google-genai 1.47.0` compatibility and matching lock metadata, and documented the required three-asset visual standard for every future hosted essay. - Archived the exact final image prompts and settings, including Gemini 3.1 Flash Image at 1K with high thinking, so all three visuals can be reproduced. - Added a mandatory portfolio review workflow for every publishable content change: deterministic copy, claim, link, URL, image, metadata, and browser checks plus a bounded independent maker/checker loop. diff --git a/skills-lock.json b/skills-lock.json index 92a60c6..562373b 100644 --- a/skills-lock.json +++ b/skills-lock.json @@ -5,7 +5,7 @@ "source": "ryanbaumann/infographic-agent", "sourceType": "github", "skillPath": "skill/infographic-agent/SKILL.md", - "computedHash": "ec4962103a11264951bc9d431af6a9f6721e1df8f84e4df1c98bb6a2e0a2a416" + "computedHash": "9f2d5eb57d968332ef3d0fecb1b7c320967c4c820cb786ef86c3d8442681d3c6" } } }