Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//
// Server-only, on purpose: each `buildJson` closure pulls in its
// workflow package (e.g. `@corbits/granola-call-workflow`) and with it
// `@intx/agent`/`@intx/workflow`. Only `./template-block-routes.ts`
// `@intx/agent`/`@intx/workflow`. Only `./catalog-block-routes.ts`
// (mounted in `apps/hub`) imports this; it is deliberately not
// re-exported from the package root.
import { deployableCatalogBlock } from "./catalog-blocks";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Exercises `createTemplateBlockRoutes`' HTTP surface through the real
// Exercises `createCatalogBlockRoutes`' HTTP surface through the real
// `buildBlockWorkflowSource` builder, mounted the same way
// `./connect-github-routes.test.ts` mounts its routes: a bare `Hono`
// with a tenant-injecting middleware, every port a plain fake.
Expand All @@ -20,9 +20,9 @@ import type { RequireGrant, TenantEnv } from "@intx/hub-api";
import { makeErrorEnvelope } from "@corbits/error-sink";

import {
createTemplateBlockRoutes,
type TemplateBlockRoutesDeps,
} from "./template-block-routes";
createCatalogBlockRoutes,
type CatalogBlockRoutesDeps,
} from "./catalog-block-routes";

const TENANT = {
id: "tnt_1",
Expand Down Expand Up @@ -62,12 +62,12 @@ function mountAs(routes: Hono<TenantEnv>): Hono<TenantEnv> {
}

type DeployedSource = Parameters<
TemplateBlockRoutesDeps["deployWorkflowSource"]
CatalogBlockRoutesDeps["deployWorkflowSource"]
>[0];

function buildApp(overrides: Partial<TemplateBlockRoutesDeps> = {}) {
function buildApp(overrides: Partial<CatalogBlockRoutesDeps> = {}) {
const deployed: DeployedSource[] = [];
const deps: TemplateBlockRoutesDeps = {
const deps: CatalogBlockRoutesDeps = {
requireGrant: allowAll,
log: () => {},
inferencePreferences: async () => [
Expand All @@ -79,7 +79,7 @@ function buildApp(overrides: Partial<TemplateBlockRoutesDeps> = {}) {
},
...overrides,
};
return { app: mountAs(createTemplateBlockRoutes(deps)), deployed };
return { app: mountAs(createCatalogBlockRoutes(deps)), deployed };
}

describe("POST /:assetName/deploy", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// The instantiate path's block-workflow deploy surface (CL-6405):
// `instantiateWorkbenchTemplate`'s `deployBlockWorkflow` port binds to
// `POST /:assetName/deploy` here, the way its `createParticipantAgent`
// port binds to `POST /agent-definitions`. Mounted per-tenant inside
// the platform's native tenant middleware, mirroring
// `./connect-github-routes.ts`: every side effect a host needs — the
// tenant's default inference preferences, and the actual source-form
// asset write + `workflow_definition` projection — arrives as an
// injected port, so `apps/hub` is the only place drizzle and the
// The on-demand catalog-workflow deploy surface (CL-6405, generalized by
// CL-7073 to any catalog entry — CL-8156 dropped the "template" naming
// once workbench template picking was deleted): `POST /:assetName/deploy`
// deploys a `workflows/<name>` package's block as a real `workflow`-kind
// asset on the requesting tenant, the same surface the "Available"
// catalog-workflows section (`apps/web`'s routines page) drives.
// Mounted per-tenant inside the platform's native tenant middleware,
// mirroring `./connect-github-routes.ts`: every side effect a host needs
// — the tenant's default inference preferences, and the actual
// source-form asset write + `workflow_definition` projection — arrives
// as an injected port, so `apps/hub` is the only place drizzle and the
// `AssetService` are touched and this stays testable with plain fakes.
import { Hono } from "hono";
import type { RequireGrant, TenantEnv } from "@intx/hub-api";
Expand All @@ -18,9 +20,9 @@ import {
} from "./block-workflows";

const DEPLOY_FAILED_MESSAGE =
"Couldn't set up this template's workflow. Try again in a moment.";
"Couldn't set up this workflow. Try again in a moment.";

export type TemplateBlockRoutesDeps = {
export type CatalogBlockRoutesDeps = {
requireGrant: RequireGrant;
/** Where a failure's real cause goes — the same CL-6360 idiom
* `./connect-github-routes.ts` documents: the client sees one honest
Expand Down Expand Up @@ -48,8 +50,8 @@ export type TemplateBlockRoutesDeps = {
}): Promise<{ readonly id: string; readonly created: boolean }>;
};

export function createTemplateBlockRoutes(
deps: TemplateBlockRoutesDeps,
export function createCatalogBlockRoutes(
deps: CatalogBlockRoutesDeps,
): Hono<TenantEnv> {
const app = new Hono<TenantEnv>();

Expand All @@ -69,7 +71,7 @@ export function createTemplateBlockRoutes(
return c.json(
makeErrorEnvelope({
code: "not_found",
userMessage: `"${assetName}" isn't a deployable template workflow.`,
userMessage: `"${assetName}" isn't a deployable catalog workflow.`,
}),
404,
);
Expand All @@ -88,9 +90,12 @@ export function createTemplateBlockRoutes(
result.created ? 201 : 200,
);
} catch (cause) {
// report-error-ignore: the client sees one honest userMessage
// below; the real cause goes to deps.log, the same CL-6360 idiom
// `./connect-github-routes.ts` documents.
const message = cause instanceof Error ? cause.message : String(cause);
deps.log(
`template-blocks: deploying "${assetName}" failed for tenant ${tenant.id}: ${message}`,
`catalog-blocks: deploying "${assetName}" failed for tenant ${tenant.id}: ${message}`,
);
return c.json(
makeErrorEnvelope({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Pins the hub's native catalog-block adapter (`./catalog-blocks`): the
// deployable set served by `POST /template-blocks/:assetName/deploy`,
// deployable set served by `POST /catalog-blocks/:assetName/deploy`,
// rendered from the `workflows/*` builder packages against
// `@corbits/workflows` catalog metadata — with zero import from
// `@workbench/onboarding`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// The hub's native catalog-block adapter (CL-8113, hub-zero T2): the
// deployable set `POST /template-blocks/:assetName/deploy` serves,
// deployable set `POST /catalog-blocks/:assetName/deploy` serves,
// composed directly from the `workflows/*` builder packages against
// `@corbits/workflows` catalog metadata — the same composition
// `@workbench/onboarding`'s `CATALOG_WORKFLOWS` table wraps, with zero
Expand All @@ -9,18 +9,16 @@
// same as any name outside the catalog entirely.
//
// Display names come from the native `WORKFLOW_CATALOG` entry
// (`@corbits/workflows`, which the legacy template package re-exports its
// own catalog mirror from), so the labels served here
// and the catalog's can never drift apart silently. Turn timeouts match
// the seed table's per-workflow budgets one-for-one: a research turn
// fans out and writes long-form, a call-transcript pass runs past the
// shortest catalog steps, everything else runs the conversational
// default.
// (`@corbits/workflows`), so the labels served here and the catalog's
// can never drift apart silently. Turn timeouts match the seed table's
// per-workflow budgets one-for-one: a research turn fans out and writes
// long-form, a call-transcript pass runs past the shortest catalog
// steps, everything else runs the conversational default.
//
// Server-only, on purpose: each `buildJson` closure pulls in its
// workflow package (e.g. `@corbits/granola-call-workflow`) and with it
// `@intx/agent`/`@intx/workflow`. Only `./block-workflows.ts`
// (mounted in `apps/hub` through `./template-block-routes.ts`) imports
// (mounted in `apps/hub` through `./catalog-block-routes.ts`) imports
// this; it is deliberately not re-exported from the package root.
import { workflowCatalogEntry } from "@corbits/workflows";
import {
Expand Down Expand Up @@ -103,7 +101,7 @@ export type CatalogBlock = {
/**
* Renders the definition's JSON given the tenant's mail domain and the
* ordered provider/model preferences to deploy against. Takes the bare
* preference list so this same function serves the template-block
* preference list so this same function serves the catalog-block
* route's in-process deploy path, which only ever has the tenant's
* real inference preferences on hand.
*/
Expand All @@ -118,7 +116,7 @@ function catalogDisplayName(assetName: string): string {
}

/**
* Workflows a tenant can deploy on demand through the template-block
* Workflows a tenant can deploy on demand through the catalog-block
* route: every native catalog entry with a source package under
* `workflows/<name>`, minus `assistant` (seeded already) and
* `heartbeat` (test-only). Nothing here reaches a bench until
Expand Down Expand Up @@ -293,7 +291,7 @@ export const CATALOG_BLOCK_ASSET_NAMES: readonly string[] = CATALOG_BLOCKS.map(
);

/**
* The deployable-through-the-template-block-route entry for one asset
* The deployable-through-the-catalog-block-route entry for one asset
* name, or `undefined` if none exists. `CATALOG_BLOCKS` is the one
* source of truth for "has a source package under `workflows/<name>`
* and can be deployed on demand".
Expand Down
31 changes: 14 additions & 17 deletions apps/hub/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,6 @@ import {
isWorkbenchHostDefinitionName,
listConnectedProviders,
listDefaultInferencePreferences,
localPartOf,
parseParticipants,
postRoomMessage,
startWorkflowCommand,
settleConnectedService,
createCryptoProviderCache,
Expand Down Expand Up @@ -150,7 +147,6 @@ import {
createWebhookTriggerRoutes,
launchWebhookTrigger,
} from "@corbits/webhook-triggers";
import { createTemplateBlockRoutes } from "./templates/template-block-routes";
import {
createWorkflowDetailRoute,
createScheduledWorkflowRoutes,
Expand Down Expand Up @@ -225,6 +221,7 @@ import {
DEFAULT_RETURN_PATH_ALLOWLIST,
listMcpServerConnections,
} from "@corbits/connections";
import { createCatalogBlockRoutes } from "./catalog-blocks/catalog-block-routes";
import type { ServiceConnectedHook } from "@corbits/connections";
import { CONNECTOR_REGISTRY, MCP_PRESETS } from "./native-connector-registry";
import {
Expand Down Expand Up @@ -2128,16 +2125,16 @@ export async function createHub(config: HubConfig) {
providerHealth: providerHealthStore,
}),
);
// Template block workflows (CL-6405, cut over to native deploy in
// CL-7364): the instantiate path's `deployBlockWorkflow` port lands
// here — the same source-form materialization pattern (asset +
// `@corbits/workflows`'s `./source` tree) applied to a template's referenced
// block definition (`code-review` today), now deployed through the
// same `workflowDeployer` the agent-authored deploy path above uses
// rather than a hub-local inert freeze.
// On-demand catalog workflow deploy (CL-6405, generalized by CL-7073):
// the "Available" catalog-workflows section (`apps/web`'s routines
// page) drives this to add any `workflows/*` package on demand, the
// same source-form materialization pattern (asset +
// `@corbits/workflows`'s `./source` tree) applied through the same
// `workflowDeployer` the agent-authored deploy path above uses rather
// than a hub-local inert freeze.
app.route(
`${TENANT_PREFIX}/template-blocks`,
createTemplateBlockRoutes({
`${TENANT_PREFIX}/catalog-blocks`,
createCatalogBlockRoutes({
requireGrant: createRequireGrant({
grantStore: chatGrantStore,
conditionRegistry: chatConditionRegistry,
Expand Down Expand Up @@ -2196,16 +2193,16 @@ export async function createHub(config: HubConfig) {
principal: { kind: "hub" },
tree: {
files: renderWorkflowSourceTree({
packageName: `@workbench-template/${assetName}`,
packageName: `@workbench-catalog-block/${assetName}`,
workflowJson,
}),
message: `Deploy template block ${assetName}`,
message: `Deploy catalog block ${assetName}`,
},
});

// Native deploy, not a hub-local inert freeze (CL-7364): the same
// Native deploy, not a hub-local inert freeze: the same
// `workflowDeployer` the agent-authored deploy path above drives,
// so a template block's definition goes through the real
// so a catalog block's definition goes through the real
// bundle → sidecar probe → capability walk → gate → freeze
// pipeline instead of a hub-side shortcut.
const result = await workflowDeployer.deploy({
Expand Down
1 change: 0 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
"@radix-ui/react-slot": "^1.2.3",
"@tanstack/react-query": "catalog:",
"@corbits/connections": "workspace:*",
"@workbench/templates": "workspace:*",
"arktype": "catalog:",
"react": "^19.2.0",
"react-dom": "^19.2.0",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/client-bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// config — this module never guesses them. When stock Interchange lacks a
// capability the result carries the typed gap instead of throwing.

import { WORKFLOW_CATALOG } from "@workbench/templates";
import { WORKFLOW_CATALOG } from "@corbits/workflows/catalog";

import type { ClientLogger } from "@corbits/client-log";

Expand Down
7 changes: 2 additions & 5 deletions apps/web/src/connect-service-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,8 @@ import {
listMcpPresets,
McpServersApiError,
} from "@corbits/plugins-ui";
import { mcpPresetBySlug } from "@corbits/connections/mcp-presets";
import {
CONNECTOR_REGISTRY,
MCP_PRESETS,
} from "@workbench/templates/connectors";
import { mcpPresetBySlug, MCP_PRESETS } from "@corbits/connections/mcp-presets";
import { CONNECTOR_REGISTRY } from "@corbits/connections/registry";

function bareConnectorId(connectorId: string): string {
return connectorId.startsWith("mcp:")
Expand Down
Loading
Loading