Skip to content

feat: add four editorial-grade output skills#460

Open
martinma51 wants to merge 2 commits into
xorbitsai:mainfrom
martinma51:editorial-skills-and-file-registration
Open

feat: add four editorial-grade output skills#460
martinma51 wants to merge 2 commits into
xorbitsai:mainfrom
martinma51:editorial-skills-and-file-registration

Conversation

@martinma51
Copy link
Copy Markdown
Collaborator

Summary

Adds four magazine-grade editorial output skills (HTML deck / PPTX / XLSX / PDF) and fixes two related file-registration bugs that broke chat chip links for any agent-generated workspace file.

What's in this PR

Two commits, can be reviewed independently:

  1. fix(tools): register raw-write files + expose file_id from get_file_info — backend file-registration bugfix
  2. feat(skills): add four editorial-grade output skills — four new SKILL.md files under src/xagent/skills/builtin/

The bugfix (commit 1)

Bug A — python_executor / javascript_executor adapters miss raw-fs-IO files

workspace.auto_register_files() scans workspace.workspace_dir. The executor's actual working_directory (resolved via workspace.resolve_path("")) can be a sibling tree — e.g. workspace id "67" → workspace_dir is user_1/67, but the executor cwd lands in user_1/web_task_67/output. Files written by openpyxl, pptxgenjs.writeFile, fs.writeFileSync, etc. land in the latter; the scan misses them entirely; they never reach uploaded_files; the frontend has no UUID for chip links.

Fix: in both adapters, snapshot the executor's actual working_directory before and after execute_code(), diff the file sets, and explicitly call workspace.register_file() on the deltas. register_file() already dedupes via the path → file_id DB lookup, so this is a no-op when the dirs coincide.

Bug B — get_file_info doesn't return file_id

WorkspaceFileOperations.get_file_info() returned name / size / mtime but never the registered file_id. When an LLM asks "what's the UUID for foo.pptx so I can build a chip link" the tool gave it no way to answer — the agent guessed a UUID, the chip 404'd, the user saw a dead link. Same failure mode that PR #432's Rule #10 partially addresses, but here the agent has no real value to fall back on.

Fix: add file_id: Optional[str] to FileInfo and populate it from workspace.get_file_id_from_path() inside get_file_info().

Combined effect

openpyxl-written .xlsx, pptxgenjs-written .pptx, and other raw-fs-IO files now auto-register, and the agent can retrieve the real UUID to render a clickable chip in its final answer.

Relationship to other PRs

This sits at a different layer than the recent pptxgenjs-error-handling PRs:

PR Layer Failure mode it fixes
#432 (merged) prompt LLM emits link on success: false
#442 (open) core JS executor pptxgenjs warn-only failures → broken .pptx exits 0
This PR adapter + file-info tool file is written successfully but isn't registered

These are independent. No file-level conflict with #442 (this PR touches core/tools/adapters/vibe/*_executor.py and core/tools/core/workspace_file_tool.py; #442 touches core/tools/core/javascript_executor.py).

The skills (commit 2)

Four builtin skills focused on "face-of-the-product" deliverables:

Skill Output Stack
html-deck-editorial single-file HTML slide deck inline CSS / SVG, Google Fonts only, no JS deps
pptx-editorial native .pptx pptxgenjs via execute_javascript_code
xlsx-financial-report native .xlsx openpyxl via execute_python_code
pdf-report-editorial editorial .pdf HTML → Chrome headless via browser tool

Zero new dependencies. pptxgenjs is already in _get_deps. openpyxl is already in the backend .venv. Each skill is a single SKILL.md file (markdown + YAML frontmatter), no helper code modules.

What each skill enforces

  • One palette per output, no hex mixing (5 named palettes per skill: Monocle / Indigo Porcelain / Forest Ink / Kraft Paper / Dune for deck-style; Bloomberg Mono / Indigo Sheet / Forest Ledger / Crimson Quarterly / Slate Audit for xlsx)
  • Two fonts max (display + body), all system-available (Georgia + Calibri for pptx/xlsx; Playfair Display + Inter for html/pdf via Google Fonts)
  • Forbidden visual junk: drop-shadow, 3D, gradients, rounded corners > 2px, emoji decoration, clipart
  • No fabricated data — drop the slot rather than invent team names / financial metrics
  • Language matches user prompt — Chinese prompt → fully Chinese output, no English template phrases leaking through
  • CJK text uses charSpacing: 0 to avoid the per-glyph gap artifact
  • Final answer leads with bare [name](file:UUID) chip link so the output is clickable in chat
  • Pre-write output checklist for the agent to self-verify before declaring success

Why these instead of extending presentation-generator

presentation-generator is a defensive general-purpose generator (4 fixed themes, allows placeholder text, no language matching). These four skills take an opinionated editorial-design stance — closer to Monocle / Economist / NYT style guides — for cases where visual quality matters more than flexibility. They coexist with presentation-generator; the skill selector picks based on description and triggers.

Verification

End-to-end run of all 4 skills with Chinese prompts (Xagent fundraising deck, community growth dashboard, enterprise whitepaper, dev-community pitch):

Task Skill Tool failures Auto-registered Chip clickable
80 (html) html-deck-editorial 0
81 (pptx) pptx-editorial 0
82 (xlsx) xlsx-financial-report 1 (auto-recovered)
83 (pdf) pdf-report-editorial 0

All chips resolve to real files in uploaded_files. Zero manual backfill required.

Test plan

  • Run a "create a pitch deck" task with a Chinese prompt → confirm pptx-editorial is selected, output is in Chinese, chip is clickable
  • Run a "make an xlsx KPI dashboard" task → confirm xlsx-financial-report is selected, file auto-registers, chip is clickable
  • Verify the existing presentation-generator skill still selects for generic "make slides" prompts (i.e. the new skill doesn't over-trigger)
  • Confirm pip install-style new deps: none (only existing openpyxl + pptxgenjs)

🤖 Generated with Claude Code

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request implements a manual file registration mechanism in the Python and JavaScript executors to ensure files created outside the standard workspace are tracked. It also adds a file_id field to the FileInfo model and introduces several new editorial skills for generating styled HTML, PDF, PPTX, and XLSX reports. Feedback identifies code duplication and performance inefficiencies in the file scanning logic, suggesting a shared utility using optimized directory traversal. Additionally, a redundant error handling block in the workspace file tool was noted for simplification.

Comment thread src/xagent/core/tools/adapters/vibe/javascript_executor.py Outdated
Comment thread src/xagent/core/tools/adapters/vibe/python_executor.py Outdated
Comment thread src/xagent/core/tools/core/workspace_file_tool.py Outdated
@martinma51
Copy link
Copy Markdown
Collaborator Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a suite of 'editorial' skills for generating high-quality HTML decks, PDF reports, PowerPoint presentations, and Excel financial reports. It also enhances the JavaScript and Python executors with a 'belt-and-braces' file registration mechanism to capture files created in working directories that diverge from the main workspace root. Additionally, the FileInfo model now includes a file_id to support clickable file links in chat. Feedback focused on optimizing the new file registration logic in the executors, specifically recommending that manual scans be skipped when the working directory is already within the workspace tree to avoid redundant filesystem operations and expensive path resolutions.

Comment thread src/xagent/core/tools/adapters/vibe/javascript_executor.py Outdated
Comment thread src/xagent/core/tools/adapters/vibe/python_executor.py Outdated
martinma51 pushed a commit to martinma51/xagent that referenced this pull request May 20, 2026
Addresses all five Gemini-code-assist review points on PR xorbitsai#460.

Centralise the manual file-registration backfill that python_executor
and javascript_executor were each doing inline. Both adapters now
just call ``workspace.backfill_files_from_cwd(working_directory)``
around the existing ``auto_register_files()`` block.

Key changes from the duplicated inline implementations:

1. **Skip-when-redundant fast path.** When the executor's cwd is
   already inside ``workspace_dir`` (the common case in tests and
   for tasks whose workspace id matches the executor's working
   directory), ``auto_register_files`` already covers those files
   on its own scan. The new helper detects this with
   ``wd.is_relative_to(workspace_dir)`` and yields immediately
   without doing any second walk — avoiding the double-scan Gemini
   called out.

2. **``os.walk`` with in-place dir pruning** replaces ``rglob("*")``
   + post-filter. Hidden subdirs, ``__pycache__`` and ``node_modules``
   are pruned from ``dirnames`` so the walk never descends into
   them — significantly faster on trees that contain large
   ``node_modules`` directories (which is exactly the case for the
   pptxgenjs-using JS executor).

3. **No more ``p.resolve()`` inside the snapshot loop.** ``os.walk``
   already yields absolute paths when given an absolute root, so we
   resolve the root once outside the walk and reuse it. Each entry
   in the resulting set is already absolute and comparable across
   the before/after snapshots without further normalisation.

4. **Module-level logger.** The inline helpers were creating a
   per-call ``_log`` shadow of the module logger; both adapters
   now use the module-level ``logger`` they already declared at
   import time.

5. **No per-call function redefinition.** The inline ``_scan_cwd``
   was being defined fresh on every executor invocation; the
   extracted ``_scan_user_files`` is a module-level function.

Also drop the redundant ``try/except`` around
``self.workspace.get_file_id_from_path(...)`` in
``workspace_file_tool.py``: that method already swallows internal
exceptions and returns ``None``, so the outer guard was dead code.

Tests: 60 tests across javascript_executor / python_executor /
workspace / file_analysis suites pass; ruff check + format clean.
@martinma51
Copy link
Copy Markdown
Collaborator Author

Thanks @gemini-code-assist — all five points addressed in 44f13e0.

Code duplication (comments 1, 2, 4, 5): Extracted into TaskWorkspace.backfill_files_from_cwd(working_directory) and a module-level _scan_user_files(root) helper in workspace.py. Both python_executor and javascript_executor now wrap their auto_register_files() call in this single helper instead of inlining their own scan loops.

Redundant manual scans: The helper checks wd.is_relative_to(workspace_dir) up front and yields immediately without doing any walk when the executor's cwd is already inside the workspace tree — auto_register_files() covers that case on its own. The manual snapshot only runs when the two trees actually diverge.

rglobos.walk with pruning: _scan_user_files walks with os.walk(root) and prunes hidden subdirs / __pycache__ / node_modules from dirnames in-place, so the traversal never descends into them. Especially noticeable for the JS executor where node_modules is large.

p.resolve() in the loop: dropped. The root is resolved once outside the walk; os.walk yields absolute paths when handed an absolute root, so the before/after sets are directly diffable without per-entry resolution.

Per-call function definitions / redundant logger: _scan_user_files is module-level, and both adapters now use the module-level logger they already declared at import time.

workspace_file_tool.py redundant try/except (comment 3): Dropped. get_file_id_from_path already returns None on internal failure, so the outer guard was dead code; collapsed to a single assignment.

60 tests across the touched + adjacent suites pass; ruff check + format clean.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

The changes in 44f13e0 correctly address the identified issues. Centralizing the file backfill logic into TaskWorkspace.backfill_files_from_cwd and utilizing os.walk with in-place pruning of node_modules and __pycache__ significantly improves both maintainability and performance compared to the previous rglob approach. The removal of redundant p.resolve() calls and the simplification of the workspace_file_tool logic align with the discussed improvements.

martinma51 pushed a commit to martinma51/xagent that referenced this pull request May 21, 2026
Addresses all five Gemini-code-assist review points on PR xorbitsai#460.

Centralise the manual file-registration backfill that python_executor
and javascript_executor were each doing inline. Both adapters now
just call ``workspace.backfill_files_from_cwd(working_directory)``
around the existing ``auto_register_files()`` block.

Key changes from the duplicated inline implementations:

1. **Skip-when-redundant fast path.** When the executor's cwd is
   already inside ``workspace_dir`` (the common case in tests and
   for tasks whose workspace id matches the executor's working
   directory), ``auto_register_files`` already covers those files
   on its own scan. The new helper detects this with
   ``wd.is_relative_to(workspace_dir)`` and yields immediately
   without doing any second walk — avoiding the double-scan Gemini
   called out.

2. **``os.walk`` with in-place dir pruning** replaces ``rglob("*")``
   + post-filter. Hidden subdirs, ``__pycache__`` and ``node_modules``
   are pruned from ``dirnames`` so the walk never descends into
   them — significantly faster on trees that contain large
   ``node_modules`` directories (which is exactly the case for the
   pptxgenjs-using JS executor).

3. **No more ``p.resolve()`` inside the snapshot loop.** ``os.walk``
   already yields absolute paths when given an absolute root, so we
   resolve the root once outside the walk and reuse it. Each entry
   in the resulting set is already absolute and comparable across
   the before/after snapshots without further normalisation.

4. **Module-level logger.** The inline helpers were creating a
   per-call ``_log`` shadow of the module logger; both adapters
   now use the module-level ``logger`` they already declared at
   import time.

5. **No per-call function redefinition.** The inline ``_scan_cwd``
   was being defined fresh on every executor invocation; the
   extracted ``_scan_user_files`` is a module-level function.

Also drop the redundant ``try/except`` around
``self.workspace.get_file_id_from_path(...)`` in
``workspace_file_tool.py``: that method already swallows internal
exceptions and returns ``None``, so the outer guard was dead code.

Tests: 60 tests across javascript_executor / python_executor /
workspace / file_analysis suites pass; ruff check + format clean.
@martinma51 martinma51 force-pushed the editorial-skills-and-file-registration branch from 44f13e0 to 7566374 Compare May 21, 2026 04:16
@martinma51
Copy link
Copy Markdown
Collaborator Author

Rebased onto current upstream/main — was -8 behind, including #383 (durable file storage layer) which touches core/workspace.py and the uploaded_files schema. Zero conflictscore/workspace.py auto-merged cleanly because #383 extends TaskWorkspace orthogonally to this PR's _scan_user_files + backfill_files_from_cwd helpers.

Preserved the original 3-commit history (fix(tools) / feat(skills) / refactor(tools)) via cherry-pick rather than squashing, since the reviewer feedback so far has been per-commit. Diff vs upstream/main is identical to before the rebase: 8 files / +1123 / −7.

Local checks (against the rebased branch):

  • pytest tests/core/test_workspace_*.py tests/core/tools/test_workspace_*.py tests/core/tools/test_python_executor.py tests/core/tools/test_javascript_executor.py: 116 passed
  • ruff check + ruff format --check: clean

Ready for review.

martinma51 pushed a commit to martinma51/xagent that referenced this pull request May 21, 2026
Addresses all five Gemini-code-assist review points on PR xorbitsai#460.

Centralise the manual file-registration backfill that python_executor
and javascript_executor were each doing inline. Both adapters now
just call ``workspace.backfill_files_from_cwd(working_directory)``
around the existing ``auto_register_files()`` block.

Key changes from the duplicated inline implementations:

1. **Skip-when-redundant fast path.** When the executor's cwd is
   already inside ``workspace_dir`` (the common case in tests and
   for tasks whose workspace id matches the executor's working
   directory), ``auto_register_files`` already covers those files
   on its own scan. The new helper detects this with
   ``wd.is_relative_to(workspace_dir)`` and yields immediately
   without doing any second walk — avoiding the double-scan Gemini
   called out.

2. **``os.walk`` with in-place dir pruning** replaces ``rglob("*")``
   + post-filter. Hidden subdirs, ``__pycache__`` and ``node_modules``
   are pruned from ``dirnames`` so the walk never descends into
   them — significantly faster on trees that contain large
   ``node_modules`` directories (which is exactly the case for the
   pptxgenjs-using JS executor).

3. **No more ``p.resolve()`` inside the snapshot loop.** ``os.walk``
   already yields absolute paths when given an absolute root, so we
   resolve the root once outside the walk and reuse it. Each entry
   in the resulting set is already absolute and comparable across
   the before/after snapshots without further normalisation.

4. **Module-level logger.** The inline helpers were creating a
   per-call ``_log`` shadow of the module logger; both adapters
   now use the module-level ``logger`` they already declared at
   import time.

5. **No per-call function redefinition.** The inline ``_scan_cwd``
   was being defined fresh on every executor invocation; the
   extracted ``_scan_user_files`` is a module-level function.

Also drop the redundant ``try/except`` around
``self.workspace.get_file_id_from_path(...)`` in
``workspace_file_tool.py``: that method already swallows internal
exceptions and returns ``None``, so the outer guard was dead code.

Tests: 60 tests across javascript_executor / python_executor /
workspace / file_analysis suites pass; ruff check + format clean.
@martinma51 martinma51 force-pushed the editorial-skills-and-file-registration branch from 7566374 to 2df5151 Compare May 21, 2026 07:34
martinma51 pushed a commit to martinma51/xagent that referenced this pull request May 21, 2026
Addresses all five Gemini-code-assist review points on PR xorbitsai#460.

Centralise the manual file-registration backfill that python_executor
and javascript_executor were each doing inline. Both adapters now
just call ``workspace.backfill_files_from_cwd(working_directory)``
around the existing ``auto_register_files()`` block.

Key changes from the duplicated inline implementations:

1. **Skip-when-redundant fast path.** When the executor's cwd is
   already inside ``workspace_dir`` (the common case in tests and
   for tasks whose workspace id matches the executor's working
   directory), ``auto_register_files`` already covers those files
   on its own scan. The new helper detects this with
   ``wd.is_relative_to(workspace_dir)`` and yields immediately
   without doing any second walk — avoiding the double-scan Gemini
   called out.

2. **``os.walk`` with in-place dir pruning** replaces ``rglob("*")``
   + post-filter. Hidden subdirs, ``__pycache__`` and ``node_modules``
   are pruned from ``dirnames`` so the walk never descends into
   them — significantly faster on trees that contain large
   ``node_modules`` directories (which is exactly the case for the
   pptxgenjs-using JS executor).

3. **No more ``p.resolve()`` inside the snapshot loop.** ``os.walk``
   already yields absolute paths when given an absolute root, so we
   resolve the root once outside the walk and reuse it. Each entry
   in the resulting set is already absolute and comparable across
   the before/after snapshots without further normalisation.

4. **Module-level logger.** The inline helpers were creating a
   per-call ``_log`` shadow of the module logger; both adapters
   now use the module-level ``logger`` they already declared at
   import time.

5. **No per-call function redefinition.** The inline ``_scan_cwd``
   was being defined fresh on every executor invocation; the
   extracted ``_scan_user_files`` is a module-level function.

Also drop the redundant ``try/except`` around
``self.workspace.get_file_id_from_path(...)`` in
``workspace_file_tool.py``: that method already swallows internal
exceptions and returns ``None``, so the outer guard was dead code.

Tests: 60 tests across javascript_executor / python_executor /
workspace / file_analysis suites pass; ruff check + format clean.
@martinma51 martinma51 force-pushed the editorial-skills-and-file-registration branch 2 times, most recently from a006318 to 9bd5f1a Compare May 21, 2026 09:07
@martinma51 martinma51 changed the title feat: editorial output skills + fix file registration for raw-write tools feat: add four editorial-grade output skills May 21, 2026
Copy link
Copy Markdown
Collaborator

@rogercloud rogercloud left a comment

Choose a reason for hiding this comment

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

Leaving the validated review findings inline. I grouped related symptoms together so each thread points at one underlying contract issue.

Comment thread src/xagent/skills/builtin/html-deck-editorial/SKILL.md Outdated
Comment thread src/xagent/skills/builtin/html-deck-editorial/SKILL.md Outdated
Comment thread src/xagent/skills/builtin/pdf-report-editorial/SKILL.md Outdated
Comment thread src/xagent/skills/builtin/html-deck-editorial/SKILL.md Outdated
Comment thread src/xagent/skills/builtin/xlsx-financial-report/SKILL.md
Comment thread src/xagent/skills/builtin/xlsx-financial-report/SKILL.md
Comment thread src/xagent/skills/builtin/pdf-report-editorial/SKILL.md Outdated
Comment thread src/xagent/skills/builtin/pptx-editorial/SKILL.md Outdated
Add four new builtin skills focused on magazine-grade visual output for
"face-of-the-product" deliverables (investor pitch decks, board reviews,
executive whitepapers, customer-facing dashboards).

- `html-deck-editorial` — single-file HTML slide deck with inline CSS,
  keyboard navigation, hash sync, top progress bar; 5 palettes; 10
  numbered layouts (L01 cover → L10 closing). Zero JS dependencies.

- `pptx-editorial` — native .pptx via pptxgenjs (npm), same 5 palettes
  and 10 layouts as html-deck. Generates async-IIFE-wrapped JS through
  `execute_javascript_code` to avoid the Node top-level-await /
  CommonJS require conflict.

- `xlsx-financial-report` — native .xlsx via openpyxl (already in
  backend .venv). Five financial-report palettes (Bloomberg Mono /
  Indigo Sheet / Forest Ledger / Crimson Quarterly / Slate Audit),
  freeze panes, alternating row bands, conditional formatting,
  monochrome data bars. Currency defaults to USD with explicit guidance
  on when to switch to CNY / EUR / GBP. Ships copy-pasteable openpyxl
  3.x chart snippets to avoid the common kwarg-name footguns
  (`ln=` not `line=`, `w=` not `width=`, `ChartLines(spPr=...)` wrap).

- `pdf-report-editorial` — editorial PDF (whitepaper / brief / memo) via
  HTML → Chrome headless. Same 5 palettes, A4 + print-aware CSS, drop
  caps, pull quotes, callout boxes, paginated footer.

Each skill enforces:
- One palette per output, no hex mixing
- Two fonts max (display + body), all system-available
- Forbidden visual junk (drop-shadow, 3D, gradients, rounded > 2px)
- No fabricated data — drop the slot rather than invent
- Language matches user prompt (Chinese prompt → fully Chinese output,
  no English template phrases leaking through)
- CJK text uses `charSpacing: 0` to avoid the per-glyph gap artifact
- Final answer leads with bare `[name](file:UUID)` chip link so the
  output is clickable in chat
- Each skill includes a pre-write output checklist for the agent to
  self-verify before declaring success
@martinma51 martinma51 force-pushed the editorial-skills-and-file-registration branch from 9bd5f1a to 9f83f8a Compare May 25, 2026 01:57
…tsai#460

[#1] Replace `triggers:` frontmatter with `tags:` + `when_to_use:`.
``SkillParser.parse()`` only reads ``description`` / ``when_to_use`` /
``tags`` / ``files`` / ``content``, so the trigger phrases were
silently ignored while the keyword-tag fallback could attach
unrelated tags. The trigger phrases that aren't already in the
``description`` are folded in there; explicit ``tags:`` now declare
the selection vocabulary the runtime actually consumes.

[xorbitsai#2] Drop the ``get_file_info(...)`` → ``file_id`` instruction in all
four skills. ``FileInfo`` does not include a ``file_id`` field, so
following the previous wording yielded fabricated UUIDs and dead
chips. Each skill now tells the model to read ``markdown_link`` /
``file_refs[].markdown_link`` from the producing tool's own response
(the contract upstream xorbitsai#439 ships) and copy it verbatim. Calling
``get_file_info`` for chips is now an explicit anti-pattern.

[xorbitsai#3] pdf-report-editorial: rewrite the PDF export step from the
nonexistent ``browser_use`` dispatcher with ``navigate``/``pdf``
sub-actions to the actually-callable tools: ``browser_navigate``
(workspace path or ``file://`` URL) followed by
``browser_pdf(output_filename=..., format="A4", print_background=True)``.
``browser_pdf`` does not accept a ``margin`` object; page margins are
set in CSS ``@page`` rules inside the HTML. The base64 fallback hint
is dropped — the tool writes the file directly and returns
``markdown_link``.

[xorbitsai#4] html-deck-editorial: resolve the "no external ``<link>``" vs
"load Playfair Display + Inter from Google Fonts" contradiction by
relaxing Hard Rule 1 to allow exactly one Google Fonts stylesheet
``<link>``. All other external scripts/images/CDNs remain forbidden.

[xorbitsai#5] xlsx-financial-report: align the palette contract on 4 colors
(``ink`` / ``paper`` / ``paper_tint`` / ``accent``) — ``paper_tint``
is required by the alternating-row band, so claiming "only 3 usable
colors" while consuming the 4th was internally contradictory. All
chart snippets now reference a single ``palette = {…}`` dict instead
of hard-coding hex literals (including the stray ``E5E7EB`` that
wasn't in any palette).

[xorbitsai#6] xlsx-financial-report: document that ``execute_python_code`` 's
sandbox ships only ``pandas`` / ``numpy`` / ``matplotlib`` — openpyxl
is NOT preinstalled. The skill now instructs the model to pass
``packages=["openpyxl>=3.1.0"]`` on every invocation so the very
first ``import openpyxl`` doesn't ModuleNotFoundError.

[xorbitsai#7] pdf-report-editorial: pick one heading hierarchy. The output
checklist already said "H1 only on cover; H2 for section dividers",
so the typography table now labels H1 as cover-only and the
``page-break-before`` rule applies to ``section.chapter`` wrappers or
the H2 section-divider rule instead of conflicting with the checklist.

[xorbitsai#8] pptx-editorial: remove the contradictory "Node env has pptxgenjs
preinstalled" claim. The executor only has pptxgenjs when it's
supplied through ``packages``; the skill now states that explicitly
and tells the model to pass it on every run.

Also switch any remaining internal-name references
(``python_executor`` / ``javascript_executor``) to the public tool
names (``execute_python_code`` / ``execute_javascript_code``) the
agent actually sees.
@martinma51
Copy link
Copy Markdown
Collaborator Author

Thanks @rogercloud — all 8 issues addressed in 481c84b. The threads were marked resolved on GitHub but the SKILL.md content hadn't been updated; this commit closes them at the file level. Quick map:

[1] triggers: ignored by parser — Replaced with tags: + when_to_use: in all four skills. The trigger phrases that weren't already in description are folded in there so they survive selector scoring. Verified the parser only reads description / when_to_use / tags / files / content.

[2] get_file_info → file_id contract — Dropped in all four skills. Confirmed FileInfo doesn't expose file_id, so following the old wording would either fabricate UUIDs (dead chips) or stall the model. Each skill now reads markdown_link / file_refs[].markdown_link straight off the producing tool's response (the contract upstream #439 ships) and copies it verbatim. Calling get_file_info for chips is now explicitly flagged as an anti-pattern in each skill.

[3] PDF skill browser_usebrowser_navigate + browser_pdf — Rewrote the export step. The tools are individually callable; browser_pdf(output_filename=..., format="A4", print_background=True), no margin object — margins go in CSS @page inside the HTML. Dropped the "decode base64" fallback since browser_pdf writes to the workspace and returns markdown_link directly.

[4] HTML deck Google Fonts vs no-<link> conflict — Relaxed Hard Rule 1 to allow exactly one Google Fonts stylesheet <link> (matching the typography section which requires Playfair Display + Inter). All other external scripts/images/CDNs are still forbidden.

[5] XLSX palette 3 vs 4 colors — Aligned everything on 4 colors (ink / paper / paper_tint / accent). All chart snippets now reference a single palette = {…} dict instead of hard-coding hex literals (including the stray E5E7EB you flagged that wasn't in any palette).

[6] openpyxl not in sandbox — Added an explicit "Required runtime packages" section: openpyxl is NOT preinstalled, the model must pass packages=["openpyxl>=3.1.0"] to execute_python_code on every invocation. Verified the python_executor's @sandbox_config only declares pandas / numpy / matplotlib by default.

[7] PDF skill H1 vs H2 / page-break conflict — Picked the hierarchy the output checklist already enforced (H1 cover-only, H2 chapter dividers). Updated the typography table to label H1 as cover-only and moved page-break-before onto section.chapter wrappers / the H2 rule.

[8] pptxgenjs "preinstalled" claim — Removed. Replaced with explicit "not preinstalled in the sandbox — supplying it via packages is what makes it available" wording so the contract is consistent with the executor's actual behavior. Also switched a few internal-module references (python_executor, javascript_executor) to the public tool names (execute_python_code, execute_javascript_code) the agent actually sees.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants