Repository navigation
feat(policy): let a tool declare that it polls - #105
YellowSnnowmann wants to merge 1 commit into
Conversation
A wait or a status poll answers the same text until whatever it waits on moves. A host's loop guards count an identical call that returns an identical result as a repeat, so a run that waits after each step gets stopped while it is making progress: TinyAgents' repeat-progress guard halted an OpenIntents shopping run on its sixth identical browser_wait, one press before checkout. ToolRuntime gains `repeat: ToolRepeat`: Counted by default, Polling when the tool waits or polls. ToolPolicy::polling() sets it and leaves `classified` alone, since polling says how a tool is called, not what it may touch. Payloads written before the field existed decode as Counted.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
Tiny Sweeper reviewReviewed head: Verdict: Ready for maintainer review · Priority: none Diagnostics and supporting detailsFull summaryPull request purpose (title): feat(policy): let a tool declare that it polls. This pull request, titled "feat(policy): let a tool declare that it polls," adds a `ToolRepeat` enum (`Counted` default, `Polling`) and a `ToolRuntime::repeat` field so a tool can declare that an identical call returning an identical result is expected rather than a sign the caller is stuck. It also adds a `ToolPolicy::polling()` builder that sets `Polling` without touching `classified`, re-exports the new type from the policy module and crate root, pins the new wire shape in tests, and documents the extension in the vocabulary spec. The latest-push delta is unavailable, so no push-only comparison can be described. Review snapshot
Completeness: Complete What changedAdds the `ToolRepeat` enum with `Counted` as the serde/default value and `Polling` for wait or status-poll tools, and a `#[serde(default)] repeat` field on `ToolRuntime` so payloads written before the field existed decode as `Counted`. A new `ToolPolicy::polling()` builder sets `Polling` while deliberately leaving the `classified` flag unchanged. The type is re-exported through `policy` and the crate root. The pinned JSON wire shape tests on both sides now include the `repeat` key, new tests cover defaulting, round-tripping, the builder's preservation of other declarations, and legacy payload decoding, and the vocabulary spec gains an "Extension: repeat classification" section that notes the additive-on-wire but source-breaking nature of the new field for exhaustive `ToolRuntime` literals. Features
Tests
FindingsNo active actionable findings. Before mergeNone. Agent review detailscritique
security
tests
commits
description
Evidence and run details
|
Summary
A wait or a status poll answers the same text until whatever it waits on moves. A host's loop guards count an
identical call that returns an identical result as a repeat, so a run that waits after each step gets stopped while it
is making progress. TinyAgents' repeat-progress guard did this to an OpenIntents shopping run: it halted the run on its
sixth identical
browser_wait(same page, same "Done. Now on (<title>)" answer), one press before checkout. Todaythe only exemption is a hard-coded tool name in TinyAgents (
wait_subagent), so a host's own wait tools can't opt out.This PR lets a tool declare the contract itself, on the declarative policy surface, the same way
replayworks:ToolRuntime::repeat: ToolRepeat, eitherCounted(the default) orPolling.ToolPolicy::polling()sets it.The TinyAgents side, which builds the exemption from these declarations, follows in a separate PR that moves the
vendor/tinytoolsgitlink to this commit.Related issue
None.
API or behavior changes
ToolRepeatenum (Counteddefault,Polling), exported from the crate root.ToolRuntime::repeatfield, with#[serde(default)]and always serialized, likereplay.ToolPolicy::polling()builder. Unlike the other builders it leavesclassifiedunchanged: polling describeshow a tool is called, not what it may touch.
runtimegains a"repeat"key ("counted"/"polling"). A payload written before the field existeddecodes as
counted.ToolRuntime { … }literal (one without..Default::default()) no longercompiles, as happened when
replaywas added. Per the versioning rule this belongs in the next minor release; thisPR does not bump the workspace version.
Validation
Commands actually run, with their outcome:
cargo fmt --all -- --check: cleancargo clippy --all-targets --all-features -- -D warnings: cleancargo build --all-targets --all-features: cleancargo test --all-features: 739 passed, 0 failedRUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features: cleanTests
In
crates/tinytools/src/policy/mod_tests.rs:repeat(countedby default,pollingwhen fully populated).repeats_are_counted_unless_a_tool_says_it_polls: the default and the read-only baseline areCounted.repeat_round_trips_through_jsonthe_polling_builder_marks_the_runtime_and_classifies_nothing: setsPolling, keepsclassifiedand every otherdeclaration.
legacy_runtime_json_without_repeat_counts_repeatsDocumentation
docs/specs/tinytools-vocabulary.mdhas a new "Extension: repeat classification" section. Rustdoc covers the enum,the field and the builder.
Checklist
#[allow(...)],#[ignore], or relaxed lints. A fourthboolonToolRuntimewould have trippedclippy::struct_excessive_bools, which is one more reason this is an enum..envcontents in the diff or the description