Repository navigation
Move the pure tool-UI rules into tinymcp-bus - #105
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Comment |
Tiny Sweeper reviewTiny Sweeper reviewed this change across 5 lane(s) and found 0 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below. State: Incomplete Review snapshot
Completeness: Incomplete FeaturesNone identified with supported citations. TestsNo supported feature-to-test mapping was produced. Test execution is not inferred. FindingsNo active actionable findings. Could not review: README.md, crates/tinymcp-bus/src/ui/links.rs, crates/tinymcp-bus/src/ui/links_scan_tests.rs, crates/tinymcp-bus/src/version/mod.rs, crates/tinymcp-bus/src/version/mod_tests.rs, crates/tinymcp/Cargo.toml Before merge
How this fits togetherflowchart LR
n0["classify_link<br/>changed"]:::changed
n1["extract_links<br/>changed"]:::changed
n2["image_path<br/>changed"]:::changed
n3["link_kind<br/>changed"]:::changed
n4["trim_trailing<br/>changed"]:::changed
n5["resolve_presentation<br/>changed"]:::changed
n6["json"]:::impacted
n7["view"]:::impacted
n8["...ocument_the_result_embedded_is_prefetched"]:::impacted
n9["...uctured_content_is_dropped_but_links_kept"]:::impacted
n10["resource_from_contents"]:::impacted
n11["drops_image_assets"]:::impacted
n0 -->|calls| n2
n1 -->|calls| n0
n1 -->|calls| n3
n1 -->|calls| n4
n5 -->|calls| n1
n5 -->|calls| n10
n7 -->|calls| n6
n8 -->|calls| n5
n8 -->|tests| n5
n8 -->|calls| n6
n8 -->|tests| n6
n8 -->|calls| n7
n8 -->|tests| n7
n9 -->|calls| n5
n9 -->|tests| n5
n9 -->|calls| n6
n9 -->|tests| n6
n9 -->|calls| n7
n9 -->|tests| n7
n11 -->|calls| n1
n11 -->|tests| n1
n11 -->|calls| n6
n11 -->|tests| n6
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
Agent review detailscritique
security
tests
commits
description
Evidence and run details
|
There was a problem hiding this comment.
tinysweeper found nothing blocking, but could not review everything, so this is not an approval: crates/tinymcp-bus/Cargo.toml, crates/tinymcp-bus/src/ui/links.rs, crates/tinymcp-bus/src/ui/web_url.rs, crates/tinymcp-bus/src/ui/web_url_tests.rs, crates/tinymcp/Cargo.toml.
$0.0100 · 614,764 in / 37,392 out · 13,440 cached (2%) · ladder/vectors-oai3, glm-5.3-flash · 871 embedded
critique: $0.0065 · 272,018 in / 23,670 out · 4,480 cached (2%) · glm-5.3-flash
security: $0.0027 · 283,136 in / 8,564 out · 8,960 cached (3%) · glm-5.3-flash
tests: $0.0002 · 24,531 in / 129 out · 0 cached (0%) · glm-5.3-flash
description: $0.0002 · 18,399 in / 1,669 out · 0 cached (0%) · glm-5.3-flash
Template resolution, widget document checks, link classification and extraction, and the widget tool-call and rendering policy are pure functions of a tool call's JSON. Living in tinymcp::ui made every host that renders tool UI link the whole module crate (reqwest, tokio, the storage drivers) for them. Move them into tinymcp_bus::ui and keep tinymcp::ui as a re-export. The contract may depend only on serialization utilities, so: - the URL scanner is hand-written instead of a regex, with a differential test against the old pattern; - http(s) links are split by a fail-closed host and path splitter instead of the url crate, with a differential test against url that every Web or Image verdict parses there with the same host; - the debug logs are gone. Contract 1.25; no member was added or removed.
c3afdee to
81d9980
Compare
There was a problem hiding this comment.
tinysweeper found nothing blocking, but could not review everything, so this is not an approval: README.md, crates/tinymcp-bus/src/ui/links.rs, crates/tinymcp-bus/src/ui/links_scan_tests.rs, crates/tinymcp-bus/src/version/mod.rs, crates/tinymcp-bus/src/version/mod_tests.rs, crates/tinymcp/Cargo.toml.
$0.0056 · 522,784 in / 24,960 out · 0 cached (0%) · ladder/vectors-oai3, glm-5.3-flash, · 871 embedded
critique: $0.0024 · 226,066 in / 12,446 out · 0 cached (0%) · glm-5.3-flash,
security: $0.0023 · 234,782 in / 4,687 out · 0 cached (0%) · glm-5.3-flash,
tests: $0.0003 · 24,986 in / 3,383 out · 0 cached (0%) · glm-5.3-flash
description: $0.0002 · 18,399 in / 11 out · 0 cached (0%) · glm-5.3-flash
Ships tinyhumansai#105 (the pure tool-UI rules move into tinymcp-bus, contract 1.25) and tinyhumansai#107. Workspace version and the two lockfile entries only, as in the 0.18.5 release. Part of tinyhumansai/openhuman#7868
Behaviour change (fail-closed): http(s) links with userinfo, IDN/punycode or %-encoded hosts, IPv6, non-canonical IPv4, bad ports or dot segments are now Blocked (previously Web).
Summary
The pure tool-UI rules move from
tinymcp::uiinto the contract crate, astinymcp_bus::ui:tinymcp::uistays as apub use tinymcp_bus::ui::*re-export, behind the sameuifeature.The rules are pure functions of a tool call's JSON. Until now, though, a host that renders tool UI had to link the whole module crate (reqwest, tokio, the storage drivers) to get them. OpenHuman's module-boundaries audit therefore flags
openhuman-coreandopenhuman-appfor their directtinymcpdependency. With this change they can taketinymcp-busalone.The contract may depend only on serialization utilities (
serde,serde_json,schemars, andbase64, which OpenHuman's contract audit allows). The old rules used three crates outside that set, so:regex→ a hand-written scanner (links.rs,url_spans). It finds the same spans as the old pattern,(?i)\b[a-z][a-z0-9+.\-]{1,31}://[^\s"'<>{}|\^[]]+, andlinks_scan_tests.rschecks it against that regex on hand-picked and generated text. The scheme scan is bounded at 33 bytes, so text with a word boundary every other byte (a.a.a.…`) stays linear.url→ a fail-closedhttp(s)splitter (web_url.rs). It accepts:--), or canonical dotted-decimal IPv4;Everything else is
Blocked.tracing→ removed. Five debug lines.Contract 1.25. No member was added or removed.
Related issue
Refs tinyhumansai/openhuman#7868, which tracks moving these rules to the bus, then the host import switch and removing the temporary
hosts:tinymcpboundary exception (tinyhumansai/openhuman#7869). This PR is the first step and does not finish that issue.API or behavior changes
tinymcp_bus::uinow exports the rule functions and constants thattinymcp::uiexported (same names and signatures).tinymcp::uire-exports them unchanged, so existing callers compile as before.CONTRACT_VERSION1.24 → 1.25, a minor bump with no member added or removed, following the precedent of 1.23's pure helpers.tinymcp-busgainsbase64, plusurlandregexas dev-dependencies (test oracles only).tinymcpdropsregex; itsuifeature no longer enables a dependency.classify_link,extract_linksandis_image_urlare stricter, and only in the fail-closed direction.http(s)URLs, previouslyWeborImage, are nowBlocked:xn--) hosts, and any label containing--127.1,0x7f.0.0.1,010.0.0.1)_.,..,%2e)is_image_urlnow answersfalsefor non-http(s)schemes. It previously ranurl::Url::parseon any scheme. Its doc already said "anhttp(s)URL".BlockedbecomesWeb,ImageorHandoff.Handoffclassification is unchanged.Validation
Not run locally: clippy, build and the test suite. By our fleet's policy, CI is the gate for those, and this PR relies on
module-cito run them. Commands actually run:cargo fmt --all. Ran it and committed the result;--checkwas not run separately.cargo metadata --locked --offline. Exit 0, andCargo.lockwas unchanged afterwards, which confirms the hand-edited lockfile resolves (only thetinymcpandtinymcp-busdependency lists changed).cargo clippy --all-targets --all-features -- -D warnings(CI)cargo build --all-targets --all-features(CI)cargo test --all-features(CI)Tests
links_tests.rs,policy_tests.rsandresolve_tests.rs(byte-for-byte;links_tests.rswas not modified).web_url_tests.rs: the differential property. For every input thatclassify_linkcallsWeborImage,url::Url::parsemust succeed with anhttp(s)scheme, the samehost_str(), and the same image verdict on itspath(). Inputs:https://a@b,https://b.com@evil.com/)javascript:,data:,file:andftp:url.links_scan_tests.rs: the scanner against the old regex, on hand-picked haystacks covering terminators, word boundaries (including non-ASCII letters and digits), the 32-byte scheme limit and Unicode whitespace, plus 17³ generated three-piece strings.char::is_alphanumeric() || '_', while the regex's\walso includes combining marks, other connector punctuation and join controls, and excludes non-decimal numerics. In those cases the two can disagree on whether a candidate is found right after such a character. Every candidate still goes throughclassify_link, so this cannot widen what is accepted.Documentation
README.md: the UI section now points attinymcp_bus::uiand lists whatclassify_linkblocks.crates/tinymcp-bus/README.md: a contract 1.25 paragraph; the dependency closure now namesbase64.crates/tinymcp-bus/src/ui/mod.rsandweb_url.rsmodule docs;tinymcp::uishim docs; the feature comment incrates/tinymcp/Cargo.toml; the version history inversion/mod.rs.Checklist
#[allow(...)],#[ignore], or relaxed lints. The two new test files carry the same#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]header as every existing test file; library code has none..envcontents in the diff or the description