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

coderabbitai Bot commented Aug 25, 2026

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.

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

tinysweeper found nothing blocking. Approving.

$0.0000 · 0 in / 0 out

@tinysweeper

tinysweeper Bot commented Aug 25, 2026

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

@tinysweeper tinysweeper Bot 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:main Aug 25, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. 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