Skip to content

feat(agent): add artifact probe and inspection - #25

Open
ThomAub wants to merge 5 commits into
mainfrom
agent/artifact-probe-inspect
Open

feat(agent): add artifact probe and inspection#25
ThomAub wants to merge 5 commits into
mainfrom
agent/artifact-probe-inspect

Conversation

@ThomAub

@ThomAub ThomAub commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the agentic artifact lifecycle foundation for OfficeMD:

  • introduces officemd_agent with artifact identity, fingerprints, capability reports, locators, bounded inspection reports, typed apply reports, render reports, and verification reports
  • introduces officemd_renderer with system renderer discovery, Poppler PDF rasterization, and LibreOffice DOCX/XLSX/PPTX-to-PDF conversion followed by Poppler rasterization
  • adds CLI entry points for officemd probe, officemd inspect --agent-query, officemd apply, officemd render-artifact, and officemd verify
  • supports agent patch preconditions, atomic output writes, DOCX/PPTX text replacement through existing patch APIs, XLSX sheet rename/text replacement, and explicit unsupported-operation reports for narrower XLSX cell writes
  • adds structural verification, stored formula-reference checks, and renderer-backed visual verification when --render-output-dir is provided
  • keeps the existing terminal render and metadata inspect behavior intact

CLI smoke coverage

  • rendered examples/data/OpenXML_WhitePaper.pdf with Poppler into 14 PNG files
  • rendered examples/data/showcase.docx, showcase.xlsx, and showcase.pptx through LibreOffice plus Poppler
  • verified PDF and DOCX with structure,visual-render, producing rendered evidence
  • applied and verified DOCX text replacement and XLSX sheet rename flows

Validation

  • cargo fmt --all
  • cargo test --workspace --quiet - passed
  • pre-commit hook cargo clippy

@ThomAub
ThomAub marked this pull request as ready for review July 9, 2026 21:56

@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: 599ff7ce47

ℹ️ 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 crates/officemd_agent/src/apply.rs Outdated
) =>
{
patch.scoped_replacements.push(ScopedDocxReplace {
scope: DocxTextScope::AllText,

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 Limit DOCX replacements to the requested locator

When a patch targets a specific DocxParagraph or DocxTableCell, this queues the replacement with DocxTextScope::AllText, so any matching expected_text elsewhere in the document is rewritten too. For common strings such as a status label or table value, an agent patch intended for one located cell/paragraph can silently change unrelated content while reporting the targeted operation as applied.

Useful? React with 👍 / 👎.

Comment thread crates/officemd_agent/src/inspect.rs Outdated
Comment on lines +340 to +344
let value = table
.rows
.get(row_idx)
.and_then(|row| row.get(col_idx))
.map(cell_text)

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 Fix XLSX range indexing for sparse sheets

The row/column indexes parsed from the A1 range are absolute sheet coordinates, but the table returned by the XLSX extractor is rebased to the first populated row/column. On sheets whose data does not start at A1, querying the real address (for example C5) looks past the rebased table and returns no value, while querying A1 can return the C5 value under the wrong locator, causing incorrect inspection results for sparse spreadsheets.

Useful? React with 👍 / 👎.

Comment on lines +72 to +75
AgentDocumentFormat::Xlsx => vec![
MutationKind::SetXlsxCellValue,
MutationKind::SetXlsxCellFormula,
MutationKind::RenameXlsxSheet,

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 Report only XLSX mutations that apply supports

The capability report advertises SetXlsxCellValue and SetXlsxCellFormula, but apply_xlsx returns those operations as unsupported, and it omits ReplaceText even though the XLSX apply path accepts that operation. Agents that rely on probe will be steered toward patch plans that are immediately rejected and away from a supported XLSX text replacement path.

Useful? React with 👍 / 👎.

@ThomAub
ThomAub marked this pull request as draft July 9, 2026 23:01
@ThomAub
ThomAub marked this pull request as ready for review July 10, 2026 01:27

@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: 52a6910ff7

ℹ️ 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 crates/officemd_agent/src/apply.rs Outdated
Comment on lines +434 to +436
patch.scoped_replacements.push(ScopedXlsxReplace {
scope: XlsxTextScope::AllText,
replace: TextReplace::all(expected_text, replacement),

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 Limit XLSX replacements to the requested locator

When an agent patch targets a specific XlsxCell, this maps the operation to XlsxTextScope::AllText, so a request to change one inspected cell rewrites every matching string in the workbook, including other sheets, comments, metadata, and sheet names. For common values such as Status or Yes, the report says the targeted operation was applied while unrelated workbook content is silently mutated.

Useful? React with 👍 / 👎.

Comment thread crates/officemd_agent/src/apply.rs Outdated
Comment on lines +473 to +475
patch.scoped_replacements.push(ScopedPptxReplace {
scope: PptxTextScope::AllText,
replace: TextReplace::all(expected_text, replacement),

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 Limit PPTX shape edits to the target shape

For ReplacePptxShapeText, the supplied PptxShape locator is ignored and the replacement is queued with PptxTextScope::AllText. If the same label or phrase appears in another slide/shape/notes/comments, a patch intended for one shape will mutate those unrelated occurrences while reporting the targeted shape operation as applied.

Useful? React with 👍 / 👎.

Comment thread crates/officemd_agent/src/apply.rs Outdated
if count == 0 {
output.push_str(text.as_str());
} else {
output.push_str(&text.as_str().replace(expected_text, replacement));

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 Escape DOCX text replacements before writing XML

This writes the replacement string directly inside a <w:t> node without XML escaping. When the replacement contains common characters such as & or <, the generated DOCX XML becomes invalid; the same raw-text matching also prevents replacing inspected text that is stored escaped in the source, such as AT&amp;T being reported to the agent as AT&T.

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant