Skip to content

Add IBackendsTransport interface for provider packages#526

Open
sroussey wants to merge 68 commits into
mainfrom
claude/elegant-knuth-0SiYx
Open

Add IBackendsTransport interface for provider packages#526
sroussey wants to merge 68 commits into
mainfrom
claude/elegant-knuth-0SiYx

Conversation

@sroussey
Copy link
Copy Markdown
Collaborator

Summary

Introduces IBackendsTransport, a renderer-side abstraction interface for the backends broker that provider packages can consume without importing Electron or builder dependencies. This enables a clean separation of concerns where provider packages depend only on the abstract interface, while the concrete implementation lives in the builder package.

Changes

  • New file: packages/ai/src/transport/IBackendsTransport.ts

    • IEnsureRunningRequest — request payload for acquiring a running backend
    • IRunningHandle — handle returned by ensureRunning() with refcount-based lifecycle
    • IBackendStatus — status snapshot mirroring the electron-side type
    • IBackendsTransport — main interface with three methods:
      • ensureRunning() — acquire or share a running backend process
      • subscribeStatus() — subscribe to backend status updates with unsubscribe callback
      • install() — install a backend with optional progress reporting
  • Updated: packages/ai/package.json

    • Added "./backends-transport" export path pointing to the new interface file

Implementation Details

  • The interface uses plain string for backend identifiers (not a closed union) so provider packages don't need to know the full set of backend names; the transport implementation in builder coerces to BackendName
  • IRunningHandle.release() is fire-and-forget to avoid blocking on broker acks
  • Status subscriptions persist across port reconnects (utility crash + restart)
  • Follows repository conventions: Apache 2.0 license header, readonly properties, I prefix for public interfaces, no Electron imports in the interface definition

https://claude.ai/code/session_01Avr2i3ryqAUJUFRRZZ3Mf3

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 22, 2026

Open in StackBlitz

@workglow/cli

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/cli@526

@workglow/ai

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/ai@526

@workglow/browser-control

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/browser-control@526

@workglow/indexeddb

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/indexeddb@526

@workglow/javascript

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/javascript@526

@workglow/job-queue

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/job-queue@526

@workglow/knowledge-base

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/knowledge-base@526

@workglow/mcp

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/mcp@526

@workglow/storage

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/storage@526

@workglow/task-graph

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/task-graph@526

@workglow/tasks

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/tasks@526

@workglow/util

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/util@526

workglow

npm i https://pkg.pr.new/workglow-dev/libs/workglow@526

@workglow/anthropic

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/anthropic@526

@workglow/bun-webview

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/bun-webview@526

@workglow/cactus

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/cactus@526

@workglow/chrome-ai

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/chrome-ai@526

@workglow/electron

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/electron@526

@workglow/google-gemini

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/google-gemini@526

@workglow/huggingface-inference

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/huggingface-inference@526

@workglow/huggingface-transformers

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/huggingface-transformers@526

@workglow/llamacpp-server

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/llamacpp-server@526

@workglow/mlx

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/mlx@526

@workglow/node-llama-cpp

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/node-llama-cpp@526

@workglow/ollama

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/ollama@526

@workglow/openai

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/openai@526

@workglow/playwright

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/playwright@526

@workglow/postgres

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/postgres@526

@workglow/sqlite

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/sqlite@526

@workglow/stable-diffusion-server

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/stable-diffusion-server@526

@workglow/supabase

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/supabase@526

@workglow/tf-mediapipe

npm i https://pkg.pr.new/workglow-dev/libs/@workglow/tf-mediapipe@526

commit: 2cc8663

sroussey added a commit that referenced this pull request May 22, 2026
…s, tighten JSDoc (PR #526 follow-up) (#527)

* feat(ai): finalize IBackendsTransport — add list/uninstall, widen opts, tighten JSDoc

Adds list() and uninstall(backend) to IBackendsTransport so the libs interface
matches what builder's MessagePortBackendsTransport already implements and the
renderer UI requires.

Widens IEnsureRunningRequest.opts from { ctx: number } to
Readonly<Record<string, unknown>> so non-llamacpp backends (sd-cpp, future
MLX/whisper) don't have to lie with ctx: 0. Updates StableDiffusionCppProvider
to pass opts: {} accordingly.

Tightens JSDoc on release() (resolves on post, not broker-ack) and
subscribeStatus() (idempotent unsubscribe, dedup of double-subscribe).

* docs(IBackendsTransport): clarify opts JSDoc for sd-cpp

* test(IBackendsTransport): move type test under packages/test for CI discovery

The repo's test runner (scripts/test.ts) only collects Vitest files from
packages/test/src/test, so this file was never executed in CI. Removing
the old location; the file is recreated under packages/test/src/test/ai
in the following commit (also strengthens the structural conformance
assertion with explicit parameter signatures).

* test(IBackendsTransport): strengthen conformance with explicit signatures

Recreates the type-conformance test at packages/test/src/test/ai/ (the
location scripts/test.ts discovers) and replaces the zero-arg dummy
implementations with explicit parameter signatures drawn from the
interface. TypeScript happily assigns `() => X` to `(arg) => X`, so the
previous form did not catch parameter-list drift; the new form fails
typecheck on any rename, type change, or return-type change to a method
of `IBackendsTransport`.

Imports come from `@workglow/ai/provider-utils` (the public subpath
export) instead of the previous relative path into packages/ai/src.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 22, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 61.9% 24323 / 39291
🔵 Statements 61.76% 25169 / 40750
🔵 Functions 62.82% 4613 / 7343
🔵 Branches 50.44% 11854 / 23500
File CoverageNo changed files found.
Generated in workflow #2418 for commit 3830106 by the Vitest Coverage Report Action

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Introduces a renderer-side IBackendsTransport abstraction in @workglow/ai/provider-utils so provider packages can acquire/install local backends without depending on any desktop/builder/Electron implementation details. The PR also adds three new provider packages (llamacpp-server, stable-diffusion-cpp, and an mlx stub) that consume this transport interface.

Changes:

  • Added IBackendsTransport (+ related request/handle/status types) and exported it via @workglow/ai/provider-utils.
  • Added compile-time conformance tests for the IBackendsTransport surface.
  • Added new provider packages for local backends (llama-server, stable-diffusion.cpp HTTP) and an MLX stub, plus workspace lockfile updates.

Reviewed changes

Copilot reviewed 30 out of 31 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
providers/stable-diffusion-cpp/tsconfig.json New TS project config for the stable-diffusion.cpp provider package.
providers/stable-diffusion-cpp/src/ai/StableDiffusionCppProvider.ts Implements a text-to-image provider that uses IBackendsTransport.ensureRunning() or an external URL.
providers/stable-diffusion-cpp/src/ai/runtime.ts Runtime entry re-export for registration.
providers/stable-diffusion-cpp/src/ai/registerStableDiffusionCpp.ts Provider registration helper (injects transport/external URL).
providers/stable-diffusion-cpp/src/ai/index.ts Public AI entry exports for the provider.
providers/stable-diffusion-cpp/src/ai/common/StableDiffusionCpp_Constants.ts Defines the provider name constant.
providers/stable-diffusion-cpp/src/ai.ts Package ./ai entrypoint barrel.
providers/stable-diffusion-cpp/src/ai-runtime.ts Package ./ai-runtime entrypoint barrel.
providers/stable-diffusion-cpp/package.json New provider package manifest/exports/scripts.
providers/mlx/tsconfig.json New TS project config for the MLX provider stub package.
providers/mlx/src/ai/runtime.ts Runtime entry re-export for registration.
providers/mlx/src/ai/registerMlx.ts Provider registration helper for the stub provider.
providers/mlx/src/ai/MlxProvider.ts Stub provider that registers but throws on inference (v1 limitation).
providers/mlx/src/ai/index.ts Public AI entry exports for the provider.
providers/mlx/src/ai/common/Mlx_Constants.ts Defines the provider name constant.
providers/mlx/src/ai.ts Package ./ai entrypoint barrel.
providers/mlx/src/ai-runtime.ts Package ./ai-runtime entrypoint barrel.
providers/mlx/package.json New provider package manifest/exports/scripts.
providers/llamacpp-server/tsconfig.json New TS project config for the llama-server provider package.
providers/llamacpp-server/src/ai/runtime.ts Runtime entry re-export for registration.
providers/llamacpp-server/src/ai/registerLlamaCppServer.ts Provider registration helper (injects transport/external URL).
providers/llamacpp-server/src/ai/LlamaCppServerProvider.ts OpenAI-compatible streaming chat-completions client for llama-server using IBackendsTransport.
providers/llamacpp-server/src/ai/index.ts Public AI entry exports for the provider.
providers/llamacpp-server/src/ai/common/LlamaCppServer_Constants.ts Defines the provider name constant.
providers/llamacpp-server/src/ai.ts Package ./ai entrypoint barrel.
providers/llamacpp-server/src/ai-runtime.ts Package ./ai-runtime entrypoint barrel.
providers/llamacpp-server/package.json New provider package manifest/exports/scripts.
packages/test/src/test/ai/IBackendsTransport.types.test.ts Adds compile-time conformance checks for IBackendsTransport.
packages/ai/src/provider-utils/IBackendsTransport.ts Defines the new transport interface/types for provider packages.
packages/ai/src/provider-utils.ts Re-exports IBackendsTransport from the provider-utils entrypoint.
bun.lock Adds the new provider workspaces and adjusts trustedDependencies ordering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"png"
);

emit({ type: "finish", data: { image } });
Comment on lines +171 to +176
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed.startsWith("data:")) continue;
const data = trimmed.slice(5).trim();
if (data === "[DONE]") break;
if (!data) continue;
Comment on lines +58 to +59
* Mirrors `IBackendStatus` from `packages/electron/src/backends-util/types.ts`
* without importing from the builder package.
Comment on lines +70 to +72
* The concrete implementation (`MessagePortBackendsTransport`, in builder) uses
* `window.desktop.backends.openChannel()` to obtain a `MessagePort` and speaks
* the protocol defined in `packages/electron/src/backends-util/protocol.ts`.
Comment on lines 23 to +26
export * from "./provider-utils/BaseCloudProvider";
export * from "./provider-utils/CloudProviderClient";
export * from "./provider-utils/OpenAIShapedChat";
export * from "./provider-utils/IBackendsTransport";
Comment on lines +34 to +45
"peerDependencies": {
"@workglow/ai": "workspace:*",
"@workglow/util": "workspace:*"
},
"peerDependenciesMeta": {
"@workglow/ai": {
"optional": false
},
"@workglow/util": {
"optional": false
}
},
Comment on lines +34 to +45
"peerDependencies": {
"@workglow/ai": "workspace:*",
"@workglow/util": "workspace:*"
},
"peerDependenciesMeta": {
"@workglow/ai": {
"optional": false
},
"@workglow/util": {
"optional": false
}
},
Comment on lines +35 to +47
"@workglow/ai": "workspace:*",
"@workglow/util": "workspace:*"
},
"peerDependenciesMeta": {
"@workglow/ai": {
"optional": false
},
"@workglow/util": {
"optional": false
}
},
"devDependencies": {
"@workglow/ai": "workspace:*",
sroussey added a commit that referenced this pull request May 22, 2026
…s, tighten JSDoc (PR #526 follow-up) (#527)

* feat(ai): finalize IBackendsTransport — add list/uninstall, widen opts, tighten JSDoc

Adds list() and uninstall(backend) to IBackendsTransport so the libs interface
matches what builder's MessagePortBackendsTransport already implements and the
renderer UI requires.

Widens IEnsureRunningRequest.opts from { ctx: number } to
Readonly<Record<string, unknown>> so non-llamacpp backends (sd-cpp, future
MLX/whisper) don't have to lie with ctx: 0. Updates StableDiffusionCppProvider
to pass opts: {} accordingly.

Tightens JSDoc on release() (resolves on post, not broker-ack) and
subscribeStatus() (idempotent unsubscribe, dedup of double-subscribe).

* docs(IBackendsTransport): clarify opts JSDoc for sd-cpp

* test(IBackendsTransport): move type test under packages/test for CI discovery

The repo's test runner (scripts/test.ts) only collects Vitest files from
packages/test/src/test, so this file was never executed in CI. Removing
the old location; the file is recreated under packages/test/src/test/ai
in the following commit (also strengthens the structural conformance
assertion with explicit parameter signatures).

* test(IBackendsTransport): strengthen conformance with explicit signatures

Recreates the type-conformance test at packages/test/src/test/ai/ (the
location scripts/test.ts discovers) and replaces the zero-arg dummy
implementations with explicit parameter signatures drawn from the
interface. TypeScript happily assigns `() => X` to `(arg) => X`, so the
previous form did not catch parameter-list drift; the new form fails
typecheck on any rename, type change, or return-type change to a method
of `IBackendsTransport`.

Imports come from `@workglow/ai/provider-utils` (the public subpath
export) instead of the previous relative path into packages/ai/src.
@sroussey sroussey force-pushed the claude/elegant-knuth-0SiYx branch from 54cbafd to 60723b7 Compare May 22, 2026 23:02
Copy link
Copy Markdown
Collaborator Author

Review notes (process, not blocking)

Thanks for the work here! Two process-level suggestions before merge — both about keeping the historical record clean, not about the code itself.

H1 — Unrelated deletion of .github/dependabot.yml

The diff removes .github/dependabot.yml (+0/-14), but nothing in the title/description explains why. Silently dropping it turns off weekly Bun dependency updates plus the @types/node / @typescript/native-preview ignores. Could we revert it on this branch (git checkout main -- .github/dependabot.yml) and ship the removal as its own PR if it's intentional?

H2 — PR description doesn't match the diff

A few mismatches worth tidying up:

  • Path is packages/ai/src/provider-utils/IBackendsTransport.ts, not packages/ai/src/transport/IBackendsTransport.ts.
  • packages/ai/package.json is unchanged — no new ./backends-transport export; the interface is re-exported via the existing ./provider-utils subpath (packages/ai/src/provider-utils.ts:21).
  • Description omits the three new provider packages (llamacpp-server, mlx, stable-diffusion-server), the 197-line contract test, and the 75-line type-conformance test.

Could we rewrite the description before merge so the squash commit reflects what actually landed? Thanks!


Generated by Claude Code

claude and others added 9 commits May 23, 2026 19:13
…sports

Adds a renderer-side abstraction at packages/ai/src/transport/IBackendsTransport.ts
that provider packages (in libs) consume to talk to electron's backends-util
utility process without importing electron. The concrete MessagePort-based
implementation lives in builder; this is the public surface.

Exposed via the @workglow/ai/backends-transport subpath export. Used by the
upcoming llamacpp-server and stable-diffusion-cpp provider packages.
… (v1 chat-completion)

Adds the minimum-viable `libs/providers/llamacpp-server` package that
POSTs to an OpenAI-compatible `/v1/chat/completions` endpoint. Acquires
a backend URL via `IBackendsTransport.ensureRunning` (with proper
`release()` in finally) or bypasses transport when `externalUrl` is set.
Exports `registerLlamaCppServer` from both `./ai` and `./ai-runtime`
subpaths.

https://claude.ai/code/session_01Avr2i3ryqAUJUFRRZZ3Mf3
The previous \`./backends-transport\` subpath export had only a
\`types\` field pointing at a raw \`.ts\` source file and no \`import\`
field, which is non-idiomatic and likely the cause of the
\`test-vitest-ai-provider-api\` job failing on this PR (the bad
export disrupts the @workglow/ai package build/types pipeline that
the api-provider tests indirectly depend on).

Moving the interface alongside the other shared provider helpers
(\`packages/ai/src/provider-utils/IBackendsTransport.ts\`) lets it
ride the existing barrel: consumers now \`import type { ... } from
\"@workglow/ai/provider-utils\"\` just like every other vendor
package, and the bespoke subpath export is gone.

The three downstream providers (\`@workglow/llamacpp-server\`,
\`@workglow/stable-diffusion-cpp\`, \`@workglow/mlx\`) are updated to
the new import path.

https://claude.ai/code/session_01Avr2i3ryqAUJUFRRZZ3Mf3
LlamaCppServerProvider and StableDiffusionCppProvider stored
\`options.transport\` and \`options.externalUrl\` on the instance via
\`#transport\` / \`#externalUrl\` but never read them — the run-fn
closures capture them directly from \`options\`. With strict
\`noUnusedLocals\` these unused private fields broke
\`bun run build\` in libs CI (build-types step).

Also typed the local \`handle\` variable as \`IRunningHandle\` instead
of the partial \`{ release }\` shape — the run-fn reads \`handle.url\`,
which is part of \`IRunningHandle\`.

\`bun run build\` now succeeds for all 71 turbo tasks locally.

https://claude.ai/code/session_01Avr2i3ryqAUJUFRRZZ3Mf3
…s, tighten JSDoc (PR #526 follow-up) (#527)

* feat(ai): finalize IBackendsTransport — add list/uninstall, widen opts, tighten JSDoc

Adds list() and uninstall(backend) to IBackendsTransport so the libs interface
matches what builder's MessagePortBackendsTransport already implements and the
renderer UI requires.

Widens IEnsureRunningRequest.opts from { ctx: number } to
Readonly<Record<string, unknown>> so non-llamacpp backends (sd-cpp, future
MLX/whisper) don't have to lie with ctx: 0. Updates StableDiffusionCppProvider
to pass opts: {} accordingly.

Tightens JSDoc on release() (resolves on post, not broker-ack) and
subscribeStatus() (idempotent unsubscribe, dedup of double-subscribe).

* docs(IBackendsTransport): clarify opts JSDoc for sd-cpp

* test(IBackendsTransport): move type test under packages/test for CI discovery

The repo's test runner (scripts/test.ts) only collects Vitest files from
packages/test/src/test, so this file was never executed in CI. Removing
the old location; the file is recreated under packages/test/src/test/ai
in the following commit (also strengthens the structural conformance
assertion with explicit parameter signatures).

* test(IBackendsTransport): strengthen conformance with explicit signatures

Recreates the type-conformance test at packages/test/src/test/ai/ (the
location scripts/test.ts discovers) and replaces the zero-arg dummy
implementations with explicit parameter signatures drawn from the
interface. TypeScript happily assigns `() => X` to `(arg) => X`, so the
previous form did not catch parameter-list drift; the new form fails
typecheck on any rename, type change, or return-type change to a method
of `IBackendsTransport`.

Imports come from `@workglow/ai/provider-utils` (the public subpath
export) instead of the previous relative path into packages/ai/src.
Introduces the `@workglow/stable-diffusion-server` package, which serves as a local HTTP client for stable-diffusion.cpp servers. This package includes the `StableDiffusionCppProvider` for image generation tasks and provides registration functionality through `registerStableDiffusionCpp`. Additionally, updates to the `bun.lock` and `package.json` files reflect the new dependencies and workspace configurations for the added provider.

- Added `StableDiffusionCppProvider` for handling image generation requests.
- Implemented `registerStableDiffusionCpp` for provider registration.
- Updated `bun.lock` and `package.json` to include new dependencies and workspace references.
@sroussey sroussey force-pushed the claude/elegant-knuth-0SiYx branch from 2cc8663 to 231f21f Compare May 23, 2026 19:13
sroussey added 29 commits May 23, 2026 21:56
…uery filter

Also fix description text so it does not pollute case-insensitive query
filtering (every loaded model previously matched 'llama' because the
static description was 'llama-server loaded model').
}

function stripTrailingSlash(url: string): string {
return url.replace(/\/+$/, "");
try {
const { baseUrl, release } = await acquire(model, opts);
try {
const res = await fetch(`${baseUrl}/props`, { signal });
try {
const { baseUrl, release } = await acquire(model, opts);
try {
const res = await fetch(`${baseUrl}/v1/models`, { signal });
emit({ type: "finish", data: { results: [] } });
return;
}
const baseUrl = opts.externalUrl.replace(/\/+$/, "");
}
const baseUrl = opts.externalUrl.replace(/\/+$/, "");
try {
const res = await fetch(`${baseUrl}/v1/models`, { signal });
Comment on lines +80 to +85
const response = await fetch(`${baseUrl}/v1/chat/completions`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
signal,
});
}

function stripTrailingSlash(url: string): string {
return url.replace(/\/+$/, "");
Comment on lines +52 to +57
const response = await fetch(`${baseUrl}${endpoint}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
signal,
});
emit({ type: "finish", data: { results: [] } });
return;
}
const baseUrl = opts.externalUrl.replace(/\/+$/, "");
}
const baseUrl = opts.externalUrl.replace(/\/+$/, "");
try {
const res = await fetch(`${baseUrl}/v1/models`, { signal });
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.

5 participants