Skip to content

Let a host ask whether a toolkit has a sync pipeline - #106

Merged
YellowSnnowmann merged 1 commit into
tinyhumansai:mainfrom
YellowSnnowmann:feat/5560-syncable-toolkits
Aug 25, 2026
Merged

Let a host ask whether a toolkit has a sync pipeline#106
YellowSnnowmann merged 1 commit into
tinyhumansai:mainfrom
YellowSnnowmann:feat/5560-syncable-toolkits

Conversation

@YellowSnnowmann

Copy link
Copy Markdown
Contributor

What

One member: IsToolkitSyncable(toolkit) -> bool, on MemorySourceSync.

Why

is_composio_toolkit_syncable decides whether a Composio connection can become a memory source, and it is engine-internal. A host that cannot ask it has three options, all bad:

  • keep its own copy of the list, and drift from the driver's;
  • infer the answer from a failed sync — by which point it has already registered the source it should not have;
  • reach past the contract into the engine crate.

OpenHuman does the third. It is now the last thing keeping the engine's provider re-export alive there (tinyhumansai/openhuman#5560), and that re-export is one of the shims holding tinymemory-core in the shipped dependency graph.

The gate matters because of what getting it wrong looks like. From the host's own comment on the code this replaces:

a source that reports ACTIVE and then fails every sync with "tinycortex sync does not support toolkit" is a silent lie to the user (#4957)

Design notes

A predicate, not the list. The answer depends on a normalisation the driver owns — it trims and lower-cases before matching. A caller handed ["clickup", "github", "gmail", "linear", "notion", "slack"] would have to reimplement that rule, and would be correct right up until the rule changed, then silently wrong. Asking the question keeps the rule on the side that owns it. The cost is one round-trip per connection authorisation, not per sync.

Unsupported, not Ok(false), from a driver that cannot enumerate its pipelines. "I have no pipeline for this" and "I cannot tell you" are different facts. A caller that conflated them would quietly stop registering every memory source while still looking healthy — the same failure mode the member exists to prevent, one level up.

Defaulted on the trait, so this is additive for any other implementor; the null driver takes the default and answers Unsupported.

The doc also states what false means, since that is where the original bug came from: not "refuse the connection". A toolkit with no pipeline is still a perfectly good agent-tool integration. What it cannot be is a memory source.

Tests

Null-driver Unsupported coverage, and the member joins the manifest, METHODS and the loader E2E's expected list, so the four registration sites stay in agreement.

Root workspace and the module's own workspace both build clean with --all-targets; 985 + 113 + 62 + 163 + 134 + 24 tests pass.

After this

Releases, then OpenHuman re-pins and memory/sync/composio/bus.rs loses its last engine call — which lets the providers re-export shim be deleted along with it.

Stacked conceptually on #105 (BootstrapConnection), already merged and released in v1.11.0: that one moved the connection-created hook behind the bus, this one moves the gate that decides whether to run it.

`is_composio_toolkit_syncable` is the gate that decides whether a Composio
connection can become a memory source, and it is engine-internal. A host
that cannot ask it has three bad options: keep its own copy of the list
and drift, infer the answer from a failed sync — by which point it has
already registered the source it should not have — or reach past the
contract into the engine crate. OpenHuman does the third today, and it is
the last thing keeping the engine's provider re-export alive there
(openhuman#5560).
`IsToolkitSyncable(toolkit) -> bool` closes it.
A predicate rather than the list, because the answer depends on a
normalisation the driver owns: it trims and lower-cases before matching. A
caller handed the list would have to reimplement that rule, and would be
right until the day the rule changed and silently wrong after. The
question keeps the rule on the side that owns it, and the cost is one
round-trip per connection authorisation rather than per sync.
`Unsupported` rather than `Ok(false)` from a driver that cannot enumerate
its pipelines: "I have no pipeline for this" and "I cannot tell you" are
different answers, and a caller that conflated them would quietly stop
registering every memory source while still looking healthy.
Defaulted on the trait, so this is additive for any other implementor; the
null driver takes the default and answers `Unsupported`.
985 + 113 + 62 + 163 + 134 + 24 tests pass in the root workspace and the
module's own; both build clean with --all-targets.
@coderabbitai

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ff168c9f-8b9f-4fd8-8d47-42b9a20d8edb

Warning

Your free Security trial is over. An organization admin can activate billing to continue.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tinysweepertinysweeperBot 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.

tinysweeper found nothing blocking. Approving.

$0.0000 · 0 in / 0 out

@tinysweeper

Copy link
Copy Markdown

How this change flows

2 changed behaviours across 11 relationships. 6 surrounding behaviours are shown (60 graph nodes walked). 27 further behaviours left out to keep the diagram readable.

flowchart LR
n0["...hod_fails_with_its_advertised_family_name<br/>changed"]:::changed
n1["TinycortexProvider<br/>changed"]:::changed
n2["block_on"]:::impacted
n3["assert"]:::impacted
n4["EngineRuntimeConfig"]:::impacted
n5["assert_unsupported"]:::impacted
n6["...eturn_unsupported_naming_their_capability"]:::impacted
n7["Result"]:::impacted
n0 -->|calls| n2
n0 -->|tests| n2
n0 -->|calls| n3
n0 -->|calls| n5
n0 -->|tests| n5
n1 -->|uses| n4
n5 -->|uses| n7
n6 -->|calls| n2
n6 -->|tests| n2
n6 -->|calls| n5
n6 -->|tests| n5
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
Loading

Green: changed behaviour. Grey: surrounding behaviour. Arrows name the call, use, implementation, or test relationship. Orange: has findings. Red: has a finding that blocks the merge.

tinysweeper 0.1.0

@tinysweepertinysweeperBot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Aug 25, 2026
@YellowSnnowmann
YellowSnnowmann merged commit 974b28c into tinyhumansai:mainAug 25, 2026
27 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@YellowSnnowmann