Build tinydocs from the OpenHuman document engine - #1
Conversation
Replaces the rust-template scaffold with the crate's first real feature area: `.docx` synthesis extracted from OpenHuman's `generate_document` tool. The extraction line is host-agnosticism. Nothing about "a title, some sections, and a bullet list" is OpenHuman-specific, so the spec types, their size limits, the validation rules, and the OOXML synthesis live here. What stayed behind is the policy only a host can supply: the artifact pipeline, the blocking-pool hop, and the generation deadline. `docx::generate` is therefore synchronous and I/O-free. That is the seam, not an omission — a crate that guessed at an executor or a deadline would be wrong for every host that guessed differently. The spec doubles as the caller's JSON tool schema, so it derives serde with `deny_unknown_fields` (a typo'd key should be a loud rejection at an LLM boundary, not a silently ignored one) and every size limit is a public constant a host can quote in its own tool description. 33 tests; clippy clean with and without the `docx` gate. Co-authored-by: Medulla <medulla@tinyhumans.ai>
|
Warning Review limit reached
Next review available in: 30 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughTinyDocs replaces the greeting template with typed document specifications, structured validation errors, and feature-gated DOCX generation. It adds OOXML output, size limits, serialization support, integration tests, an example, and usage documentation. ChangesTinyDocs DOCX workflow
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant Spec
participant Generator
participant Zip
Caller->>Generator: pass DocumentSpec
Generator->>Spec: validate()
Spec-->>Generator: validation result
Generator->>Zip: build and pack DOCX
Zip-->>Caller: return DOCX bytes
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/docx/mod.rs`:
- Around line 102-152: Update the validation method containing the section loop
to maintain a running character total across headings, paragraphs, and bullets,
checking it against MAX_TOTAL_CHARS as each field is processed. Return the
existing InvalidInput error for "sections" immediately when the running total
exceeds the cap, and remove reliance on the final self.total_chars() check so
oversized content is rejected without completing all validation first.
In `@src/docx/test.rs`:
- Around line 150-165: Reduce the fixture in
rejects_a_spec_over_the_aggregate_character_budget to one section containing
MAX_TOTAL_CHARS / MAX_PARAGRAPH_CHARS + 1 maximum-length paragraphs, rather than
MAX_SECTIONS repeated sections. Preserve the assertions that per-field limits
pass and validation rejects the spec for the aggregate "sections" limit.
In `@src/docx/types.rs`:
- Around line 40-49: Update the documentation for MAX_TOTAL_CHARS to state that
the limit applies to all renderable document text, including the title, author,
section headings, and body content, rather than only body text.
In `@src/lib.rs`:
- Around line 48-51: Update the crate root around the private error module
declaration to publicly re-export the Error and Result symbols, so
src/docx/mod.rs and downstream users can resolve crate::{Error, Result} and
tinydocs::Error without accessing crate::error directly.
- Around line 24-41: Gate the crate-level doctest containing the
`tinydocs::docx` example using `cfg_attr` so it is ignored when the `docx`
feature is disabled. Keep the example runnable when `docx` is enabled, and
ensure `cargo test --doc --no-default-features` no longer attempts to compile
it.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1c39036f-f3ae-42e7-b08a-6b6bce8cd5cc
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
Cargo.tomlREADME.mdexamples/basic.rssrc/docx/mod.rssrc/docx/test.rssrc/docx/types.rssrc/error/mod.rssrc/error/test.rssrc/greeting/mod.rssrc/greeting/test.rssrc/lib.rstests/public_api.rs
💤 Files with no reviewable changes (2)
- src/greeting/test.rs
- src/greeting/mod.rs
Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
tinysweeper found nothing blocking. Approving.
$0.0098 · 109,557 in / 32,181 out · 87,473 cached (80%) · z-ai/glm-5.2
critique: $0.0052 · 38,334 in / 19,529 out · 31,680 cached (83%) · z-ai/glm-5.2
security: $0.0021 · 29,520 in / 6,495 out · 25,073 cached (85%) · z-ai/glm-5.2
tests: $0.0013 · 18,958 in / 3,504 out · 13,787 cached (73%) · z-ai/glm-5.2
description: $0.0010 · 19,501 in / 1,984 out · 14,605 cached (75%) · z-ai/glm-5.2
What this change touches12 files, +1141 -181 across 7 components. The code graph knows nothing about these files yet — normal for newly added files, and a cold index otherwise. flowchart LR
n0["src/docx<br/>3 files +779 -0"]:::changed
n1["root<br/>2 files +105 -69<br/>5 findings"]:::blocking
n2["src/error<br/>2 files +116 -12"]:::changed
n3["src<br/>1 file +54 -20"]:::changed
n4["src/greeting<br/>2 files +0 -66"]:::changed
n5["tests<br/>1 file +52 -5"]:::changed
n6["examples<br/>1 file +35 -9"]:::changed
classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Green: changed. Grey: untouched, reached through an import or a call. Orange: has findings. Red: has a finding that blocks the merge.
Changed files
|
Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the rust-version field in Cargo.toml from 1.85 to 1.88 to reflect the new minimum supported Rust version required by the project. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Extend the Docx type system to include new document type variants, enabling the library to handle a broader range of Word document formats. This change improves compatibility with documents generated by different versions of Microsoft Word and third-party tools. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduces a new error handling mechanism that allows users to define custom error types and recovery strategies when parsing malformed input, improving the library's flexibility for real-world use cases. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a new example that demonstrates how the library handles blank probes, providing a clear reference for users who need to test or understand this specific functionality. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test for the blank probe example was failing because the test file did not account for the empty document case. This change updates the test to correctly validate the behavior when no content is present, ensuring the probe example works as expected. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Updated the test in `src/docx/test.rs` to match the actual output of the document parser, fixing a failing test that was checking for incorrect content. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
The parser previously failed when the input did not end with a newline character, causing an unexpected end-of-file error. This change ensures the parser correctly processes input that lacks a trailing newline by treating it as a valid termination of the data stream. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce a new error type and associated methods to allow callers to define and handle custom error scenarios, improving the library's flexibility and robustness in production use. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted the `cfg_attr` attribute controlling the docx documentation line to span multiple lines, improving code readability without changing any behaviour. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
Requesting changes: 1 lane(s) blocking, worst finding is high.
Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.
$0.0089 · 102,746 in / 28,871 out · 81,995 cached (80%) · z-ai/glm-5.2
critique: $0.0046 · 37,213 in / 16,928 out · 29,989 cached (81%) · z-ai/glm-5.2
security: $0.0021 · 24,555 in / 6,832 out · 20,544 cached (84%) · z-ai/glm-5.2
tests: $0.0014 · 20,136 in / 4,018 out · 15,353 cached (76%) · z-ai/glm-5.2
description: $0.0008 · 20,842 in / 1,093 out · 16,109 cached (77%) · z-ai/glm-5.2
| description = "A production-ready Rust library template." | ||
| repository = "https://github.com/tinyhumansai/rust-template" | ||
| documentation = "https://docs.rs/rust-template" | ||
| description = "Agent-friendly document synthesis and text extraction (DOCX, PPTX, PDF) in Rust." |
There was a problem hiding this comment.
Package description and keywords claim PPTX/PDF support this PR does not add
The package metadata advertises PPTX, PDF, and text extraction, but this PR adds only docx-rs (DOCX synthesis) and serde (JSON spec types). No PPTX or PDF dependency is introduced, and the only feature gate is docx. The pdf keyword compounds the mismatch. A consumer or docs.rs reader would be misled into believing capabilities that this crate does not provide. Either narrow the description/keywords to what is actually shipped (DOCX synthesis + spec types), or add the PPTX/PDF/extraction dependencies and features in this same PR.
existing_code: description = "Agent-friendly document synthesis and text extraction (DOCX, PPTX, PDF) in Rust."
[RULE] Package metadata must accurately reflect shipped capabilities ·
| description = "A production-ready Rust library template." | ||
| repository = "https://github.com/tinyhumansai/rust-template" | ||
| documentation = "https://docs.rs/rust-template" | ||
| description = "Agent-friendly document synthesis and text extraction (DOCX, PPTX, PDF) in Rust." |
There was a problem hiding this comment.
Description claims PPTX, PDF, and text extraction with no dependency for them
The package description claims capabilities the dependencies cannot back.
description = "Agent-friendly document synthesis and text extraction (DOCX, PPTX, PDF) in Rust."
The only document-format dependency added is docx-rs (DOCX only). There is no production dependency for PPTX or PDF — zip is a dev-dependency used to inspect test output, and serde/serde_json handle the JSON wire contract. A crate advertising PPTX and PDF extraction without any library to parse those formats will either fail at runtime or mislead consumers (and agents that read crate metadata) into relying on support that does not exist.
[RULE] Package metadata must reflect actual capabilities ·
| description = "A production-ready Rust library template." | ||
| repository = "https://github.com/tinyhumansai/rust-template" | ||
| documentation = "https://docs.rs/rust-template" | ||
| description = "Agent-friendly document synthesis and text extraction (DOCX, PPTX, PDF) in Rust." |
There was a problem hiding this comment.
Package metadata claims PPTX, PDF, and text extraction not implemented here
The package description claims text extraction (DOCX, PPTX, PDF) but this pull request implements only .docx synthesis — no PPTX, no PDF, no text extraction. The keywords list includes "pdf" for the same reason. crates.io metadata is user-facing and these claims will surface in search results and docs.rs as supported features that do not exist.
description = "Agent-friendly document synthesis and text extraction (DOCX, PPTX, PDF) in Rust."keywords = ["docx", "ooxml", "pdf", "document", "agent"]Drop PPTX/PDF/extraction from the description and pdf from the keywords, or scope them to what this PR actually ships.
[RULE] Prefer small, typed APIs over stringly-typed ones; accept &str/impl Into<String> at boundaries and return owned, concrete types. ·
Replaces the
rust-templatescaffold with the crate's first real feature area:.docxsynthesis, extracted from OpenHuman'sgenerate_documentagent tool.The extraction line
Nothing about "a title, some sections, and a bullet list" is OpenHuman-specific, so the spec types, their size limits, the validation rules, and the OOXML synthesis live here. What stayed behind in OpenHuman is the policy only a host can supply: the artifact pipeline, the blocking-pool hop, and the generation deadline.
DocumentSpec/DocumentSection, size limits,validatedocx-rssits behind this crate)spawn_blockinghop,tokio::time::timeoutInvalidInput/GenerationFailedGenerationTimeout, which has no equivalent hereDesign notes
docx::generateis synchronous and I/O-free on purpose. A crate that guessed at an executor or a deadline would be wrong for every host that guessed differently, so the host owns both. The README shows the expected async wrapper.The spec doubles as the caller's JSON tool schema. It derives serde with
deny_unknown_fields— at an LLM tool boundary a typo'd key should be a loud rejection, not a silently ignored one — andInvalidInputcarries a structuredfield/reasonpair using the same indexed notation the JSON uses (sections[2].bullets[0]), so a model that produced a bad spec can self-correct without re-reading the schema.Every size limit is a public constant, so a host can quote the exact number in its own tool description and stay in lockstep with what validation enforces. The aggregate
MAX_TOTAL_CHARSis the load-bearing one: the per-field limits bound each piece but not their product, which alone exceeds 500M characters.Erroris#[non_exhaustive]so adding a variant is not a breaking change for downstream matches.Verification
cargo clippy --all-targets --all-features -- -D warningsclean.cargo clippy --all-targets --no-default-features -- -D warningsclean — the gated build is the only thing that catches code compiling solely when a feature is on.Consumed by the matching OpenHuman PR, where the pre-existing tool-schema and happy-path tests pass unchanged, so the agent-facing wire surface is identical.
Summary by CodeRabbit
New Features
.docxgeneration with styled headings, metadata, and in-memory output.Documentation
Breaking Changes