Skip to content
Closed
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
33 changes: 32 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Newest first. `Unreleased` is what is on `main` and not yet tagged.

## Unreleased

**Before upgrading.** Nine things change for an existing deployment:
**Before upgrading.** Eleven things change for an existing deployment:
- A hosted computer's browser is now headed by default. It uses a little more memory than headless
did; set `COMPUTER_BROWSER_MODE=headless` (Helm: `computers.browserMode: headless`) to keep the old
behaviour.
Expand Down Expand Up @@ -42,6 +42,37 @@ Newest first. `Unreleased` is what is on `main` and not yet tagged.
- On Helm's `shared` computer and the docker-compose `agent-computer`, each Bot's files now live in
`computers/<Bot id>` on the workspace volume (below). Files saved before the upgrade stay at the
root of the volume, where no Bot sees them; move them into a Bot's folder to give them back.
- With `OPENAI_BASE_URL` set to a host that is not OpenAI or Azure, `openai/...` models now use the
Chat Completions API rather than the Responses API (below). Set `COPILOTKIT_OPENAI_API=responses`
to keep the old behaviour.
- Interfaces a Bot drew before the upgrade (A2UI 0.9 surfaces) no longer draw when a conversation is
reopened; the messages around them stay. New ones use the standard catalog (below).

### Bots draw from CopilotKit's standard components

With generative UI on, a Bot builds an interface from CopilotKit's standard catalog: 68 components
for layout, text, inputs, tables, charts, media and composites such as link and entity cards,
including the A2UI 1.0 basic components under their A2UI names. They take OpenBot's colours, radii
and font, in light and dark. Map is left out, because it needs a map library OpenBot does not ship.
The gallery components a Bot is granted are unchanged. `OPENBOT_GENERATIVE_UI=false` still switches
it all off, on the server as well as in the browser.

They are governed like the gallery. Each family (a component and the parts that only work with it,
such as Table with its rows and cells) is listed under Admin → UI components, grouped and with a
preview, and an administrator publishes it, words it and withholds it per Bot. The components gallery
lists the published ones. Layout, text and input families arrive published; data, media, overlay and composite families
arrive unpublished and wait for an administrator. The server builds every run's catalog from its own
copy and those rows, so a Bot is told only what it holds, in the published words, and is refused any
other component whatever the browser sends. Conversations still draw what they drew before a family
was withdrawn.

### CopilotKit 1.83

OpenBot now runs on CopilotKit 1.83.0 (`@copilotkit/runtime` and `react-core`, from 1.77.0) and
AG-UI 1.0.2 (`@ag-ui/core` and `@ag-ui/client`, from 1.0.1). A managed Intelligence project needs
nothing changed. A deployment whose `OPENAI_BASE_URL` points at an OpenAI-compatible gateway rather
than OpenAI or Azure now reaches `openai/...` models through Chat Completions; a gateway that only
speaks the Responses API needs `COPILOTKIT_OPENAI_API=responses`.

### The audit log reads like a log

Expand Down
8 changes: 4 additions & 4 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
"prebuild": "bun run --cwd .. generate:app-config",
"predev": "bun run --cwd .. generate:app-config",
"pretypecheck": "bun run --cwd .. generate:app-config",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"export:standard-ui": "bun scripts/export-standard-ui-catalog.ts"
},
"dependencies": {
"@ag-ui/core": "1.0.1",
"@ag-ui/core": "1.0.2",
"@base-ui/react": "^1.6.0",
"@better-auth/sso": "^1.7.1",
"@copilotkit/a2ui-renderer": "1.77.0",
"@copilotkit/react-core": "1.77.0",
"@copilotkit/react-core": "1.83.0",
"@fontsource-variable/inter": "^5.3.0",
"@openbot/shared": "workspace:*",
"@shadcn/react": "^0.3.0",
Expand Down
25 changes: 25 additions & 0 deletions app/scripts/export-standard-ui-catalog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Write the server's copy of the standard catalog: what the model is told about each component, as
* the browser would send it. The server builds every run's catalog from this file, so a Bot is told
* only what its administrator allowed, in the administrator's words.
*
* Run it after an SDK upgrade: `bun run --cwd app export:standard-ui`. app/tests/standard-ui.test.ts
* fails until the committed file matches the SDK again.
*/
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { OPENBOT_UI } from "../src/lib/copilot/a2ui";

export const STANDARD_UI_CATALOG_PATH = join(
import.meta.dir,
"../../shared/standard-ui-catalog.json",
);

export function standardUiCatalogFile() {
return `${JSON.stringify({ catalogId: OPENBOT_UI.id, components: OPENBOT_UI.manifestComponents }, null, 2)}\n`;
}

if (import.meta.main) {
await writeFile(STANDARD_UI_CATALOG_PATH, standardUiCatalogFile());
console.log(`Wrote ${STANDARD_UI_CATALOG_PATH}`);
}
76 changes: 76 additions & 0 deletions app/src/components/building-block-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { CopilotKitProvider } from "@copilotkit/react-core/v2";
import {
type GenerativeUIErrorInfo,
GenerativeUISurface,
useGenerativeUIRuntime,
} from "@copilotkit/react-core/v2/generative-ui";
import { standardUiFamily } from "@openbot/shared/standard-ui";
import { useEffect } from "react";
import { OPENBOT_UI, OPENBOT_UI_THEME } from "@/lib/copilot/a2ui";
import { BUILDING_BLOCK_SAMPLES } from "./building-block-samples";

const THREAD = "building-block-preview";
const TARGET = "preview";

/** Commits the sample as the runtime would commit a Bot's render_ui call. */
function Sample({ head }: { head: string }) {
const runtime = useGenerativeUIRuntime();
useEffect(() => {
const sample = BUILDING_BLOCK_SAMPLES[head];
if (!runtime || !sample) return;
runtime.manager.setActiveThread(THREAD);
runtime.manager.ingest(THREAD, undefined, {
surfaceId: head,
target: TARGET,
catalogId: OPENBOT_UI.id,
status: "ready",
rejected: [],
operations: [
{
version: "v1.0",
createSurface: {
surfaceId: head,
catalogId: OPENBOT_UI.id,
...(sample.dataModel ? { dataModel: sample.dataModel } : {}),
},
},
{
version: "v1.0",
updateComponents: { surfaceId: head, components: sample.components },
},
],
});
}, [runtime, head]);
return null;
}

/**
* A family of the standard catalog, drawn by the SDK from its sample.
*
* In a provider of its own, with no runtime: the preview is a surface on a thread nobody talks on,
* so it can neither reach a conversation nor be mistaken for one.
*/
export function BuildingBlockPreview({
name,
onError,
}: {
name: string;
/** For tests: every operation, prop or render failure of the sample. */
onError?: (info: GenerativeUIErrorInfo) => void;
}) {
const family = standardUiFamily(name);
if (!family || !BUILDING_BLOCK_SAMPLES[family.head]) return null;
return (
<CopilotKitProvider
enableInspector={false}
generativeUI={{
ui: OPENBOT_UI,
theme: OPENBOT_UI_THEME,
...(onError ? { errorBoundary: { onError } } : {}),
}}
>
<Sample head={family.head} />
<GenerativeUISurface autoScroll={false} id={TARGET} />
</CopilotKitProvider>
);
}
Loading
Loading