Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a12a6a2
chore(ui): delete @object-ui/plugin-ai and its release-group entries …
claude Oct 26, 2026
133f219
chore(i18n): delete the ai.* block plugin-ai owned in all ten packs (…
claude Oct 26, 2026
61bf86d
refactor(types): tombstone the plugin-ai node mirrors (WIP)
claude Oct 26, 2026
22dc89f
test: follow the plugin-ai retirement in the cli ratchet, markdown in…
claude Oct 26, 2026
ae61439
test,docs: follow the plugin-ai retirement in census pins, docs and t…
claude Oct 26, 2026
2a9feba
chore(changeset): retire @object-ui/plugin-ai, minor with the breakin…
claude Oct 26, 2026
a138a39
chore(changeset): name each retired export on its own FROM line (WIP)
claude Oct 26, 2026
bc1e8c1
chore(sdui): re-record the i18n and types registry records (WIP)
claude Oct 26, 2026
b97d2d9
test: settle the mirror-parity, handler-key census and markdown-input…
claude Oct 26, 2026
4bef30f
docs: lockstep package count 111 -> 110 after plugin-ai leaves the fi…
claude Oct 26, 2026
aaab8ac
Merge origin/main into claude/project-thread-vl2c07
claude Oct 26, 2026
db6ddb4
test,docs: published-package count and license-text floor follow the …
claude Oct 27, 2026
0ae3bda
Merge origin/main into claude/project-thread-vl2c07
claude Oct 27, 2026
20d75f1
chore(sdui): re-record the types registry record on top of main
claude Oct 27, 2026
8a72b41
Merge origin/main into claude/project-thread-vl2c07
claude Oct 27, 2026
bde1e72
test: the files-entry floor follows the plugin-ai retirement
claude Oct 27, 2026
d81562e
Merge origin/main into claude/project-thread-vl2c07
claude Oct 28, 2026
e0535a3
Merge origin/main into claude/project-thread-vl2c07
claude Oct 28, 2026
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
22 changes: 22 additions & 0 deletions .changeset/25921-retire-plugin-ai.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"@object-ui/types": minor
"@object-ui/i18n": minor
"@object-ui/cli": minor
---

refactor(ui)!: retire `@object-ui/plugin-ai` and its three node types

Clause-②: no (narrowing)
Metadata-protocol: narrowed

<!-- adr-0087: not-required (runtime-export-retired @object-ui/plugin-ai#*) the package is deleted whole: a published ui package of React components that nothing in the workspace loaded; no packages/spec schema, no ADR-0087 conversion surface and no stored shape names them, so there is nothing for `objectstack migrate meta` to rewrite, and the three node literals are refused by name on the zod face -->

**BREAKING.** `@object-ui/plugin-ai` is retired: `18.2.0` is its last published version, and it gets no further release. The console registered it neither eagerly nor lazily and no workspace package imported it, so the `ai-form-assist`, `ai-recommendations` and `nl-query` node types it registered rendered nowhere in the product.

What leaves, and what to do:

- FROM `@object-ui/plugin-ai` TO nothing: drop the import and the dependency (its exports `AIFormAssist`, `AIRecommendations` and `NLQueryInput` leave with it). A host that still wants a component keeps its own copy and registers it under its own type key.
- Page nodes of type `ai-form-assist`, `ai-recommendations` or `nl-query`: remove them from the page. `safeValidateSchema` and `objectui validate` now refuse each of the three literals by name at `type`, with that remedy; before, the page rendered the "Unknown component type" panel in their place whenever the package was not loaded.
- `@object-ui/types`: `AIFormAssistSchema`, `AIRecommendationsSchema`, `NLQuerySchema`, `AIConfig`, `AIFieldSuggestion`, `AIRecommendationItem`, `NLQueryResult`, `AIProvider` and `AIModelType` are `@deprecated` and now `never`, and `AnySchema` has no member for the three literals. The zod names (`AIFormAssistSchema` and the rest under `@object-ui/types/zod`, `AIComponentSchema` included) are `@deprecated` `z.never()` schemas that accept nothing. Remove every reference. The names stay importable until the tombstone sunset rule decides when they leave the published face.
- `@object-ui/i18n`: the `ai.*` message block (`ai.nlQuery.*`, `ai.formAssist.*`, `ai.recommendations.*`) is gone from all ten packs. A host that registered overrides for those keys can delete them.
- `@object-ui/cli`: `objectui check` no longer lists the three literals as known component types.
1 change: 0 additions & 1 deletion .changeset/26080-readme-contributing-links.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
'@object-ui/auth': patch
'@object-ui/collaboration': patch
Expand All @@ -11,7 +11,6 @@
'@object-ui/layout': patch
'@object-ui/mobile': patch
'@object-ui/permissions': patch
'@object-ui/plugin-ai': patch
'@object-ui/plugin-calendar': patch
'@object-ui/plugin-charts': patch
'@object-ui/plugin-chatbot': patch
Expand Down
1 change: 0 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@
"@object-ui/layout",
"@object-ui/mobile",
"@object-ui/permissions",
"@object-ui/plugin-ai",
"@object-ui/plugin-calendar",
"@object-ui/plugin-charts",
"@object-ui/plugin-chatbot",
Expand Down
1 change: 0 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,6 @@ Atoms and fields stay light; heavy widgets live in lazy-loaded plugins.
| [`@object-ui/plugin-editor`](ui/packages/plugin-editor) | Rich text editor powered by Monaco |
| [`@object-ui/plugin-markdown`](ui/packages/plugin-markdown) | Markdown rendering |
| [`@object-ui/plugin-chatbot`](ui/packages/plugin-chatbot) | Chatbot interface |
| [`@object-ui/plugin-ai`](ui/packages/plugin-ai) | Schema generation and conversational assistants (Vercel AI SDK) |

#### Tooling

Expand Down
49 changes: 0 additions & 49 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion ui/content/docs/plugins/meta.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins",
"pages": [
"plugin-ai",
"plugin-calendar",
"plugin-calendar-view",
"plugin-charts",
Expand Down
26 changes: 0 additions & 26 deletions ui/content/docs/plugins/plugin-ai.mdx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* (`validateAuthoredDocument`, objectui#5250), whose root is the strict twin of
* `AnyComponentSchema` — a union discriminated on `type`. A registered type
* with no arm in that union is refused with one `invalid_union` issue at
* `['type']`, whatever else the document says: `ai-form-assist`, which
* `packages/plugin-ai/README.md` teaches, was one of them. The mirror-parity
* `['type']`, whatever else the document says: `ai-form-assist`, which the
* since-retired `@object-ui/plugin-ai` README taught, was one of them. The mirror-parity
* ratchet in `@object-ui/types` counts declaration↔mirror PAIRS and the keys
* inside them; a registered type with no mirror at all is in neither, so
* nothing counted this family until this file.
Expand Down Expand Up @@ -379,7 +379,7 @@ describe('registered component types refused at `type` — a ratchet (objectui#1
// was 200 until objectui#10859 batch 8 unregistered thirty bare keys.)
expect(BARE_KEYS.length).toBeGreaterThan(150);
expect(BARE_KEYS).toContain('timeline');
expect(BARE_KEYS).toContain('ai-form-assist');
expect(BARE_KEYS).toContain('pivot');
});

it('tells a claimed type from an unclaimed one — both instrument controls fire', () => {
Expand All @@ -392,11 +392,24 @@ describe('registered component types refused at `type` — a ratchet (objectui#1
expect(refusedAtType('no-such-component-10859')).toBe(true);
});

it('counts the three plugin-ai keys as armed (objectui#10859 batch 1)', () => {
it('refuses the three plugin-ai keys BY NAME at `type` — the package retired and their arms became refusals (objectstack#25921)', () => {
// objectui#10859 batch 1 armed them; the registrations left with
// `@object-ui/plugin-ai`, so registration and arm leaving in one change move
// neither count. Each arm stays as `retiredNodeType()`'s refusal, the
// `cloud:plan-status` shape below.
for (const key of ['ai-form-assist', 'ai-recommendations', 'nl-query']) {
expect(BARE_KEYS, key).toContain(key);
expect(BARE_KEYS, key).not.toContain(key);
const result = validateAuthoredDocument({ type: key });
expect(result.success, key).toBe(false);
const named = (result.success ? [] : result.error.issues).filter(
(issue) => issue.code === 'custom' && issue.path.length === 1 && issue.path[0] === 'type',
);
expect(named, key).toHaveLength(1);
expect(named[0]?.message, key).toContain('@object-ui/plugin-ai');
expect(refusedAtType(key), key).toBe(false);
}
// Control: an unknown bare literal still takes the generic path.
expect(refusedAtType('ai-no-such-node-25921')).toBe(true);
});

it('counts the three keys batch 2 armed (objectui#10859 batch 2)', () => {
Expand Down Expand Up @@ -712,7 +725,6 @@ describe('registered NAMESPACED component types refused at `type` — a ratchet

/** Rooted on this file, never on `process.cwd()`. */
const HERE = dirname(fileURLToPath(import.meta.url));
const PLUGIN_AI_README = join(HERE, '..', '..', '..', 'plugin-ai', 'README.md');
const QUICK_START = join(HERE, '..', '..', '..', '..', 'content', 'docs', 'guide', 'quick-start.md');

/** See `validate-root-path-line.test.ts` — the escape byte is never spelled. */
Expand Down Expand Up @@ -750,26 +762,6 @@ afterEach(() => {
rmSync(dir, { recursive: true, force: true });
});

describe('objectui validate — the plugin-ai README document (objectui#10859)', () => {
it('validates the "Schema-Driven Usage" `ai-form-assist` document', async () => {
const readme = readFileSync(PLUGIN_AI_README, 'utf8');
const section = readme.slice(readme.indexOf('## Schema-Driven Usage'));
const fence = /```json\n([\s\S]*?)\n```/.exec(section);
expect(fence, 'no ```json fence under "## Schema-Driven Usage"').not.toBeNull();
const file = join(dir, 'ai-form-assist.json');
writeFileSync(file, (fence as RegExpExecArray)[1], 'utf-8');
// Lit control on the extraction: it is the taught node.
expect(JSON.parse((fence as RegExpExecArray)[1]).type).toBe('ai-form-assist');

await validate(file);

const text = out.join('\n').replace(ANSI, '');
expect(text).not.toContain('Schema validation failed');
expect(text).toContain('Schema is valid');
expect(exitCodes).toEqual([0]);
});
});

/* ── End to end: a page of public blocks through `objectui validate` ─────── */

describe('objectui validate — a page built from ADR-0080 public blocks (objectui#10872)', () => {
Expand Down
3 changes: 0 additions & 3 deletions ui/packages/cli/src/utils/known-schema-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ export const KNOWN_SCHEMA_TYPES: readonly string[] = [
'action:icon',
'action:menu',
'address',
'ai-form-assist',
'ai-recommendations',
'ai:feedback',
'ai:input',
'ai:suggestion',
Expand Down Expand Up @@ -222,7 +220,6 @@ export const KNOWN_SCHEMA_TYPES: readonly string[] = [
'nav:breadcrumb',
'nav:menu',
'navigation-menu',
'nl-query',
'object-calendar',
'object-chart',
'object-data-table',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ const NOT_CONTROLS: Array<[file: string, key: string, reason: string]> = [
const BACKLOG: Array<[file: string, key: string]> = [
// The data form preview selects a field by a click delegated from its frame.
['packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx', 'div · closest,getAttribute,some,readFields,setFieldSel'],
['packages/plugin-ai/src/AIRecommendations.tsx', 'div · handleSelect'],
['packages/plugin-designer/src/DashboardEditor.tsx', 'div · onSelect'],
['packages/plugin-designer/src/DataModelDesigner.tsx', 'span · stopPropagation,handleStartFieldEdit'],
['packages/plugin-designer/src/PageDesigner.tsx', 'div · stopPropagation,toggle'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,6 @@ const unnamed: Judged[] = iconOnly.filter((j) => !j.named);
* that card's fix.
*/
const BACKLOG: Array<[file: string, icons: string[]]> = [
['packages/plugin-ai/src/AIFormAssist.tsx', ['RefreshCw', 'X', 'Check', 'X']],
['packages/plugin-ai/src/AIRecommendations.tsx', ['ExternalLink', 'X', 'ThumbsUp', 'ThumbsDown']],
['packages/plugin-detail/src/DetailView.tsx', ['ArrowLeft', 'ChevronLeft', 'ChevronRight']],
['packages/plugin-detail/src/RecordComments.tsx', ['Send']],
['packages/plugin-list/src/ListView.tsx', ['X']],
Expand Down
35 changes: 0 additions & 35 deletions ui/packages/i18n/src/locales/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3786,41 +3786,6 @@ const ar = {
cloudWorkspaceTimezoneNotice: {
seeded: "تم تعيين المنطقة الزمنية للبيئة إلى {{zone}} وفقًا لمتصفحك عند إنشائها. يمكنك تغييرها من الإعدادات → التوطين.",
},
ai: {
nlQuery: {
placeholder: "اطرح سؤالًا حول بياناتك…",
ask: "اسأل",
results: "النتائج",
match: "نسبة التطابق: {{percent}}",
simulatedSummary: "نتائج: {{query}}",
noResults: "لم يتم العثور على سجلات مطابقة",
recentQueries: "الاستعلامات الأخيرة",
},
formAssist: {
title: "اقتراحات الذكاء الاصطناعي",
suggestionCount: "عدد الاقتراحات: {{count}}",
suggestionCount_zero: "{{count}} اقتراح",
suggestionCount_one: "{{count}} اقتراح",
suggestionCount_two: "اقتراحان ({{count}})",
suggestionCount_few: "{{count}} اقتراحات",
suggestionCount_many: "{{count}} اقتراحًا",
suggestionCount_other: "{{count}} اقتراح",
applyAll: "تطبيق الكل",
confidence: "الثقة: {{percent}}",
appliedCount: "عدد الاقتراحات المطبّقة: {{count}}",
appliedCount_zero: "تم تطبيق {{count}} اقتراح",
appliedCount_one: "تم تطبيق {{count}} اقتراح",
appliedCount_two: "تم تطبيق اقتراحين ({{count}})",
appliedCount_few: "تم تطبيق {{count}} اقتراحات",
appliedCount_many: "تم تطبيق {{count}} اقتراحًا",
appliedCount_other: "تم تطبيق {{count}} اقتراح",
},
recommendations: {
title: "التوصيات",
generating: "جارٍ إنشاء التوصيات…",
empty: "لا توجد توصيات متاحة",
},
},
aiApprovals: {
title: "موافقات الذكاء الاصطناعي",
description: "إجراءات اقترحها وكيل ذكاء اصطناعي وتحتاج إلى مراجعة بشرية قبل تنفيذها.",
Expand Down
27 changes: 0 additions & 27 deletions ui/packages/i18n/src/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3517,33 +3517,6 @@ const de = {
cloudWorkspaceTimezoneNotice: {
seeded: "Die Zeitzone der Umgebung wurde beim Erstellen anhand Ihres Browsers auf {{zone}} festgelegt. Sie können sie unter Einstellungen → Lokalisierung ändern.",
},
ai: {
nlQuery: {
placeholder: "Stellen Sie eine Frage zu Ihren Daten…",
ask: "Fragen",
results: "Ergebnisse",
match: "{{percent}} Übereinstimmung",
simulatedSummary: "Ergebnisse für: {{query}}",
noResults: "Keine passenden Datensätze gefunden",
recentQueries: "Letzte Abfragen",
},
formAssist: {
title: "KI-Vorschläge",
suggestionCount: "{{count}} Vorschläge",
suggestionCount_one: "{{count}} Vorschlag",
suggestionCount_other: "{{count}} Vorschläge",
applyAll: "Alle übernehmen",
confidence: "{{percent}} Konfidenz",
appliedCount: "{{count}} Vorschläge übernommen",
appliedCount_one: "{{count}} Vorschlag übernommen",
appliedCount_other: "{{count}} Vorschläge übernommen",
},
recommendations: {
title: "Empfehlungen",
generating: "Empfehlungen werden generiert…",
empty: "Keine Empfehlungen verfügbar",
},
},
aiApprovals: {
title: "KI-Genehmigungen",
description: "Von einem KI-Agenten vorgeschlagene Aktionen, die vor der Ausführung eine menschliche Prüfung benötigen.",
Expand Down
31 changes: 0 additions & 31 deletions ui/packages/i18n/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4252,37 +4252,6 @@ const en = {
cloudWorkspaceTimezoneNotice: {
seeded: 'The environment timezone was set to {{zone}} from your browser when the environment was created. You can change it in Settings → Localization.',
},
// `@object-ui/plugin-ai` — the `nl-query`, `ai-form-assist` and
// `ai-recommendations` components (objectui#10232). The two count labels are
// i18next count families (objectui#11445): the component passes `count` and
// each pack carries every CLDR category its language selects.
ai: {
nlQuery: {
placeholder: 'Ask a question about your data…',
ask: 'Ask',
results: 'Results',
match: '{{percent}} match',
simulatedSummary: 'Results for: {{query}}',
noResults: 'No matching records found',
recentQueries: 'Recent Queries',
},
formAssist: {
title: 'AI Suggestions',
suggestionCount: '{{count}} suggestions',
suggestionCount_one: '{{count}} suggestion',
suggestionCount_other: '{{count}} suggestions',
applyAll: 'Apply All',
confidence: '{{percent}} confidence',
appliedCount: '{{count}} suggestions applied',
appliedCount_one: '{{count}} suggestion applied',
appliedCount_other: '{{count}} suggestions applied',
},
recommendations: {
title: 'Recommendations',
generating: 'Generating recommendations…',
empty: 'No recommendations available',
},
},
// The AI HITL approval inbox (`@object-ui/plugin-chatbot`'s
// `AiPendingActionsInbox`) — objectui#7173. Its four relative-time phrases
// are NOT here: it borrows `detail.justNow` / `minutesAgo` / `hoursAgo` /
Expand Down
Loading
Loading