Skip to content

move extension and container endpoints to zenoh #3907

Draft
nicoschmdt wants to merge 6 commits intobluerobotics:masterfrom
nicoschmdt:add-zenoh-extension-methods
Draft

move extension and container endpoints to zenoh #3907
nicoschmdt wants to merge 6 commits intobluerobotics:masterfrom
nicoschmdt:add-zenoh-extension-methods

Conversation

@nicoschmdt
Copy link
Copy Markdown
Contributor

@nicoschmdt nicoschmdt commented Apr 28, 2026

Summary by Sourcery

Migrate Kraken extension and container management from HTTP endpoints to zenoh-based queryables with streaming support for long-running operations.

New Features:

  • Expose zenoh queryables for extension lifecycle management, upload, and listing of installed extensions.
  • Expose zenoh queryables for listing running containers, fetching container stats, and retrieving container logs.
  • Add frontend support for streaming install and upload progress over zenoh, updating UI state in real time.

Bug Fixes:

  • Correct the zenoh key used for historical extension logs to go through the new container logs handler.

Enhancements:

  • Refactor the shared zenoh helper to run handlers on a dedicated asyncio event loop, with support for async generators and optional payloads.
  • Update the Extension Manager view to poll extensions, containers, and metrics via zenoh-backed service methods instead of HTTP APIs, simplifying state updates.

@nicoschmdt nicoschmdt marked this pull request as draft April 28, 2026 13:21
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • ExtensionManagerView now calls kraken.fetchInstalledExtensions(), but fetchInstalledExtensions is not included in the default export of KrakenManager, so this will be undefined; either add fetchInstalledExtensions to the default export or adjust the call site to use the exported name.
  • The frontend installExtension helper always returns { status: 'success' } without waiting for an explicit success signal from the backend stream; consider having the backend install_handler yield a final success message and wiring the frontend to resolve only when that is received (and to fail on stream timeout/no replies).
  • Error handling for fetchRunningContainers and fetchContainersStats was simplified to silently ignore failures (other than setting flags); if user feedback on failures is still desired, consider reintroducing notifier calls or another visible error path for these operations.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- ExtensionManagerView now calls `kraken.fetchInstalledExtensions()`, but `fetchInstalledExtensions` is not included in the default export of KrakenManager, so this will be `undefined`; either add `fetchInstalledExtensions` to the default export or adjust the call site to use the exported name.
- The frontend `installExtension` helper always returns `{ status: 'success' }` without waiting for an explicit success signal from the backend stream; consider having the backend `install_handler` yield a final success message and wiring the frontend to resolve only when that is received (and to fail on stream timeout/no replies).
- Error handling for `fetchRunningContainers` and `fetchContainersStats` was simplified to silently ignore failures (other than setting flags); if user feedback on failures is still desired, consider reintroducing notifier calls or another visible error path for these operations.

## Individual Comments

### Comment 1
<location path="core/frontend/src/components/kraken/KrakenManager.ts" line_range="311-314" />
<code_context>
-    url: `${KRAKEN_API_V2_URL}/extension/upload/keep-alive?temp_tag=${tempTag}`,
-    timeout: 10000,
-  })
+export async function keepTemporaryExtensionAlive(tempTag: string): Promise<any | null> {
+  await zenoh.query(
+    `kraken/extension/upload/keep-alive?temp_tag=${tempTag}`, 
+    QueryTarget.BestMatching
+  )
 }
</code_context>
<issue_to_address>
**issue (bug_risk):** Return type of `keepTemporaryExtensionAlive` no longer matches the actual return value.

The function is typed as `Promise<any | null>`, but it only `await`s `zenoh.query` and never returns its result, so callers actually get `void`. Either return the result of `zenoh.query(...)` (e.g. `return await zenoh.query(...)`) or change the return type to `Promise<void>` to match the current behavior.
</issue_to_address>

### Comment 2
<location path="core/libs/commonwealth/src/commonwealth/utils/zenoh_helper.py" line_range="135-136" />
<code_context>
-                    if response is not None:
-                        query.reply(query.selector.key_expr, json.dumps(response, default=str))
+                    payload_args = (bytes(query.payload) if query.payload else b"",) if has_payload else ()
+                    result = func(*payload_args, **params)
+                    if inspect.isasyncgen(result):
+                        async for item in result:
+                            if item is not None:
</code_context>
<issue_to_address>
**issue (bug_risk):** `inspect.isasyncgen` usage will fail without importing `inspect`.

`inspect.isasyncgen(result)` is used here but `inspect` isn’t imported in this module, so this will raise a `NameError` at runtime for any queryable call and break all zenoh handlers registered via this router. Please ensure `inspect` is imported (e.g. `import inspect`) or otherwise made available in this scope.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +311 to +314
export async function keepTemporaryExtensionAlive(tempTag: string): Promise<any | null> {
await zenoh.query(
`kraken/extension/upload/keep-alive?temp_tag=${tempTag}`,
QueryTarget.BestMatching
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Return type of keepTemporaryExtensionAlive no longer matches the actual return value.

The function is typed as Promise<any | null>, but it only awaits zenoh.query and never returns its result, so callers actually get void. Either return the result of zenoh.query(...) (e.g. return await zenoh.query(...)) or change the return type to Promise<void> to match the current behavior.

Comment on lines +135 to +136
result = func(*payload_args, **params)
if inspect.isasyncgen(result):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): inspect.isasyncgen usage will fail without importing inspect.

inspect.isasyncgen(result) is used here but inspect isn’t imported in this module, so this will raise a NameError at runtime for any queryable call and break all zenoh handlers registered via this router. Please ensure inspect is imported (e.g. import inspect) or otherwise made available in this scope.

@nicoschmdt nicoschmdt force-pushed the add-zenoh-extension-methods branch 7 times, most recently from d5b2eba to 953b7b9 Compare April 28, 2026 19:06
@nicoschmdt nicoschmdt force-pushed the add-zenoh-extension-methods branch from 953b7b9 to 5957853 Compare April 28, 2026 19:30
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