Skip to content

feat(connector): warm action schema cache from search results#289

Merged
BlackHole1 merged 2 commits into
mainfrom
feat/connector-search-schema-warming
Jul 2, 2026
Merged

feat(connector): warm action schema cache from search results#289
BlackHole1 merged 2 commits into
mainfrom
feat/connector-search-schema-warming

Conversation

@BlackHole1

Copy link
Copy Markdown
Member

Since /v1/actions/search (#288) returns inputSchema and outputSchema for every match, connector search now seeds the local action schema cache with those payloads. A follow-up oo connector schema (or the input validation in oo connector run) for a returned action is then answered locally instead of issuing a fresh metadata request. Warming is best-effort: results without schema payloads are skipped, cache write failures only log a warning, and the search output contract is unchanged. This effectively restores the search-time warming removed in #193 — safe again now that search is served by the connector service itself rather than a separate index that could return stale schemas.

One correctness guard comes with it: search payloads never carry an asyncLifecycle, so the --wait / --wait-result run modes must not trust a search-seeded cache entry — they would misreport async actions as unsupported. loadConnectorActionSchema gains a requireAsyncLifecycle option that treats lifecycle-less cache entries as misses and falls back to the metadata API once, re-caching the full metadata. The observable side effect is that rejecting --wait on a genuinely non-async action now performs one metadata request before erroring.

Docs for oo search, oo connector search, and oo connector schema note the new caching behavior (en + zh-CN).

The /v1/actions/search endpoint now returns `inputSchema` and
`outputSchema` for every match, so search can seed the local action
schema cache that `oo connector schema` and `oo connector run` read.
A follow-up schema lookup for a returned action is then answered
locally instead of issuing a fresh metadata request. Warming is
best-effort: results without schema payloads are skipped and cache
write failures only log a warning.

Search payloads never carry an `asyncLifecycle`, so a search-seeded
entry must not be trusted by the `--wait` / `--wait-result` run
modes: they would misreport async actions as unsupported. The loader
gains a `requireAsyncLifecycle` option that treats lifecycle-less
cache entries as misses and falls back to the metadata API once,
re-caching the full metadata.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6714747f-f7a2-4548-b2ed-178d3cd138b2

📥 Commits

Reviewing files that changed from the base of the PR and between e9028ad and 303dbb6.

📒 Files selected for processing (2)
  • docs/commands.md
  • docs/commands.zh-CN.md
✅ Files skipped from review due to trivial changes (2)
  • docs/commands.md
  • docs/commands.zh-CN.md

Summary by CodeRabbit

  • New Features
    • Connector search now warms the local action schema cache, so follow-up schema lookups return faster and often avoid an extra metadata request.
  • Bug Fixes
    • Schema cache reuse is now more accurate for actions that require async lifecycle details, with fallback to fresh metadata when missing.
    • Wait-related behavior for lifecycle-less cached entries now performs a metadata check before rejecting unsupported options.
    • Actions that don’t include schema payloads continue to work correctly.
  • Documentation
    • Updated command docs (including refresh/caching behavior) for connector search and schema lookups.

Walkthrough

This pull request adds schema-cache warming for connector search results, introduces a requireAsyncLifecycle option to loadConnectorActionSchema that refetches metadata when cached entries lack asyncLifecycle, adjusts requireAsyncLifecycle computation in run.ts for wait-related payloads, extends connector action search results with inputSchema and outputSchema, adds a shared createMemoryCache test helper, updates related tests, and revises English and Chinese documentation for connector schema caching behavior.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required type(scope): subject format and clearly matches the connector cache-warming change.
Description check ✅ Passed The description directly explains the cache-warming, lifecycle guard, and docs updates in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/connector-search-schema-warming

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

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/application/commands/connector/schema-cache.ts (1)

84-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the repeated log-context object.

The same { accountId, actionName, endpoint, serviceName } literal is now built three times in this function (Lines 85-90, 97-102, 120-125). Compute it once and reuse across the logger.debug calls.

As per coding guidelines, "Compute an expression once, store in a variable, and reuse."

♻️ Proposed refactor
     const cache = openConnectorActionSchemaCache(context);
     const cacheKey = createConnectorActionSchemaCacheKey({
         accountId: options.account.id,
         actionName: options.actionName,
         endpoint: options.account.endpoint,
         serviceName: options.serviceName,
     });
+    const logContext = {
+        accountId: options.account.id,
+        actionName: options.actionName,
+        endpoint: options.account.endpoint,
+        serviceName: options.serviceName,
+    };

     if (options.refresh !== true) {
         const cached = tryReadConnectorActionSchemaCache(cache, cacheKey, context);

         if (cached !== undefined) {
             if (options.requireAsyncLifecycle !== true
                 || cached.asyncLifecycle !== undefined) {
                 return cached;
             }

             context.logger.debug(
-                {
-                    accountId: options.account.id,
-                    actionName: options.actionName,
-                    endpoint: options.account.endpoint,
-                    serviceName: options.serviceName,
-                },
+                logContext,
                 "Connector action schema cache entry lacks an async lifecycle; fetching metadata.",
             );
         }
     }
     else {
         context.logger.debug(
-            {
-                accountId: options.account.id,
-                actionName: options.actionName,
-                endpoint: options.account.endpoint,
-                serviceName: options.serviceName,
-            },
+            logContext,
             "Connector action schema cache bypassed for refresh.",
         );
     }

Also applies to: 119-127

🤖 Prompt for 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.

In `@src/application/commands/connector/schema-cache.ts` around lines 84 - 104,
The connector schema cache logic in the function that emits the repeated
logger.debug calls is rebuilding the same log-context object multiple times.
Extract the shared { accountId, actionName, endpoint, serviceName } payload into
a single local variable in this function and reuse it for each debug invocation,
including the branches that log the async lifecycle fetch and the bypass
message, so the repeated context construction is centralized and consistent.

Source: Coding guidelines

src/application/commands/connector/index.cli.test.ts (1)

2628-2637: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract duplicated fetcher setup into a shared factory.

The GET-confirmation fetcher (capture request, return fixture on GET) is duplicated almost verbatim between the --wait and --wait-result tests.

♻️ Suggested factory extraction
+function createMetadataConfirmationFetcher(requests: Request[]) {
+    return async (input: RequestInfo | URL, init?: RequestInit) => {
+        const request = toRequest(input, init);
+        requests.push(request);
+        if (request.method === "GET") {
+            return new Response(JSON.stringify({
+                data: createConnectorActionFixture(),
+            }));
+        }
+        return new Response(JSON.stringify({
+            data: {
+                // ...existing non-GET payload
+            },
+        }));
+    };
+}

Then reuse fetcher: createMetadataConfirmationFetcher(requests) in both tests.

As per path instructions, "In test files, extract repeated setup (mock, stub, or setup objects) into a local factory function at the bottom of the file."

Also applies to: 2738-2747

🤖 Prompt for 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.

In `@src/application/commands/connector/index.cli.test.ts` around lines 2628 -
2637, The GET-confirmation fetcher setup is duplicated across the --wait and
--wait-result tests, so extract it into a shared local factory in the test file
and reuse it in both cases. Create a helper like
createMetadataConfirmationFetcher(requests) that captures requests and returns
the fixture on GET, then pass fetcher:
createMetadataConfirmationFetcher(requests) in each test to keep the setup
consistent and reduce duplication.

Source: Path instructions

🤖 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 `@docs/commands.md`:
- Around line 570-572: Update the cache note in the search command docs so it
only describes schema-bearing search results, since the implementation in the
relevant search flow only warms cache entries when both inputSchema and
outputSchema are present and writes are best-effort. Adjust the wording near the
search documentation sections so it does not imply every search result seeds the
cache, and keep the description aligned with the behavior in the search/cache
path.

---

Nitpick comments:
In `@src/application/commands/connector/index.cli.test.ts`:
- Around line 2628-2637: The GET-confirmation fetcher setup is duplicated across
the --wait and --wait-result tests, so extract it into a shared local factory in
the test file and reuse it in both cases. Create a helper like
createMetadataConfirmationFetcher(requests) that captures requests and returns
the fixture on GET, then pass fetcher:
createMetadataConfirmationFetcher(requests) in each test to keep the setup
consistent and reduce duplication.

In `@src/application/commands/connector/schema-cache.ts`:
- Around line 84-104: The connector schema cache logic in the function that
emits the repeated logger.debug calls is rebuilding the same log-context object
multiple times. Extract the shared { accountId, actionName, endpoint,
serviceName } payload into a single local variable in this function and reuse it
for each debug invocation, including the branches that log the async lifecycle
fetch and the bypass message, so the repeated context construction is
centralized and consistent.
🪄 Autofix (Beta)

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

Run ID: dc1275d2-c213-4415-939b-6d11a034cb6b

📥 Commits

Reviewing files that changed from the base of the PR and between 86b8df0 and e9028ad.

⛔ Files ignored due to path filters (1)
  • src/application/commands/connector/__snapshots__/index.cli.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (12)
  • __tests__/helpers.ts
  • docs/commands.md
  • docs/commands.zh-CN.md
  • src/application/commands/connector/index.cli.test.ts
  • src/application/commands/connector/run.ts
  • src/application/commands/connector/schema-cache.test.ts
  • src/application/commands/connector/schema-cache.ts
  • src/application/commands/connector/search-provider.test.ts
  • src/application/commands/connector/search-provider.ts
  • src/application/commands/connector/shared.test.ts
  • src/application/commands/connector/shared.ts
  • src/application/commands/search.cli.test.ts

Comment thread docs/commands.md Outdated
Cache warming only happens when the search response carries schema
data, so the unconditional wording overstated the behavior. Phrase the
note as conditional without leaking wire-level field names into the
user-facing CLI contract docs.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@BlackHole1 BlackHole1 merged commit f872ecc into main Jul 2, 2026
6 checks passed
@BlackHole1 BlackHole1 deleted the feat/connector-search-schema-warming branch July 2, 2026 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant