Skip to content

The SDK's entire ai namespace is dead, and the entire real AI surface is unreachable from the SDK — the two sets are disjoint #3718

Closed

Description

@os-zhuang

Found by enumerating the /ai/** family for #3708 — the last dynamic family of the #3563 audit, and the one the capstone's wildcard row had been covering for.

The two sets

client.ai methods exactly 3: nlq, suggest, insights
URLs they build /api/v1/ai/{nlq,suggest,insights}
Places any repo mounts those paths zero
Routes buildAIRoutes() really mounts 12: chat, chat/stream, complete, models, status, effective-model, conversations ×6
Of those 12, expressed by the SDK zero

They do not overlap at any point. The SDK's AI namespace is entirely dead; the AI service that was actually built is entirely unreachable through the SDK.

Evidence

  • service-ai / buildAIRoutes() live in the cloud repo (Cloud/EE package). Its returned table is the 12 routes above; nlq, suggest, insights are not among them — the strings do not appear in packages/service-ai/ at all.
  • In this repo, /nlq /suggest /insights appear in exactly three places: client/src/index.ts (the calls), client/src/client.test.ts (which asserts expect(url).toContain('/api/v1/ai/nlq') — the URL the client builds, not whether anything answers it), and spec/src/api/plugin-rest-api.zod.ts (DEFAULT_AI_ROUTES).
  • DEFAULT_AI_ROUTES has no runtime consumer. The only references outside its own definition are in plugin-rest-api.test.ts, which validates its shape. Nothing mounts from it.
  • aiNlq / aiSuggest / aiInsights are declared as optional protocol methods (protocol.zod.ts:1259, aiNlq?(…)). No service in either repo implements them.

Declared in the spec, expressed by the client, mounted by nothing. Instances 7–9 of the the method exists ≠ the method can be called class, after analytics.explain / analytics.meta (#3584), meta.getView (#3611), i18n.getTranslations / getFieldLabels (#3636), projects.listTemplates (#3702).

Why the guard missed it until now

The capstone (#3642) matched these three against the * /ai/** wildcard row. A wildcard asserts the family is claimed, not that the URL resolves — so all three counted as matched, and the wildcard-only ratchet (3) read as "weak evidence pending enumeration".

It was not weak evidence. It was wrong evidence. The row's note even asserted the client "expresses nlq/suggest/insights against the REST AI routes" — never verified, and false.

#3708 replaces it with a bounded prefix exemption plus a real ledger in cloud, and drops the ratchet to 0: every remaining matched call now rests on an exact enumerated route.

Also user-visible

The console's developer API-discovery panel (objectui apps/console/src/pages/developer/hooks/useApiDiscovery.ts) lists /nlq, /suggest and /insights alongside the real endpoints with "try it" bodies. It is advertising three endpoints that always 404 — Prime Directive #10 in the literal sense. Worth fixing with whichever option below is chosen.

What needs deciding

This is a product decision, not a cleanup, which is why it is filed rather than fixed:

  1. Implement the three endpoints in service-ai. NLQ (natural language → query AST), field suggestions and record insights are genuine capabilities with a declared request/response contract already in spec, and an LLM adapter already wired. If they are on the roadmap, the SDK surface and the spec are already written.
  2. Remove the namespace — delete client.ai.*, DEFAULT_AI_ROUTES, and the three optional protocol methods, and drop the three entries from the console's discovery panel. Correct if these were an early design that the chat / conversations surface superseded (which the shape of what was actually built suggests).
  3. Express the real surface instead — give the SDK ai.chat / ai.conversations.* / ai.models, which is where the 10 gap rows in cloud's new ai-route-ledger.ts point. This is a superset of option 2 and the only one that makes the SDK useful for AI at all.

Recommendation: 2 + 3 — retire the three unbuilt methods and express what exists. Option 1 only if NLQ/suggest/insights are genuinely planned; shipping three endpoints to satisfy methods nobody can be calling (they 404 today) is the wrong order.

Either way the guard is already in place: cloud's UNMOUNTED_AI_CLIENT_METHODS asserts all three still match nothing, so implementing any of them fails the test and forces an sdk ledger row.

Refs: #3708 (the enumeration), #3642 (the capstone whose wildcard hid this), #3563 (the audit family), objectstack-ai/cloud packages/service-ai/src/ai-route-ledger.ts.

Activity

  1. self-assigned this
    on Jul 28, 2026
  2. os-zhuang commented on Jul 28, 2026

    @os-zhuang
    ContributorAuthor

    Resolved as 2 + 3 — the recommendation in the issue. Three PRs, one per repo that held a piece of the disjointness:

    Repo PR What it did State
    framework #3840 retired client.ai.{nlq,suggest,insights}, DEFAULT_AI_ROUTES, AiProtocol, and the six dead Ai{Nlq,Suggest,Insights}* spec schemas; gave the SDK the 10 methods the real routes answer merged (8b9d71e)
    cloud objectstack-ai/cloud#902 the ledger's SDK half became a reachability check — drives every ai.* method against the table buildAIRoutes() returns; gap 10 → 1, UNMOUNTED_AI_CLIENT_METHODS 3 → 0 merged (b98d601)
    objectui objectstack-ai/objectui#2921 the console panel stops offering /nlq /suggest /insights with "try it" bodies; its AI group now mirrors all twelve mounted routes open (draft)

    The two sets are no longer disjoint: client.ai went from 3 methods that nothing answered to 10 that mounted routes do, and the AI surface went from 0/12 expressed to 10/12.

    The two routes still unexpressed are recorded rather than forgotten. GET /status and GET /effective-model are server-only (operator diagnostics — and they now appear in the console panel, which is the audience they were written for). POST /chat/stream is the single remaining gap: the generic-SSE twin of /chat without the tool loop or persistence, left unexpressed deliberately because ai.chatStream already covers streaming against the fuller route. Express it if a caller ever needs raw model parts without the tool loop.

    On the guard: /api/v1/ai/ is now a bounded prefix exemption in the capstone (#3642) — bounded from both ends, only ai.* may use it and the reachability check lives in the repo that mounts the routes, next to them. The wildcard-only ratchet stays 0; these URLs are matched before matches() is consulted, so they never touch the * /ai/** row that certified three dead methods for years. Mutation-checked: repointing ai.models at /modelz fails two tests in cloud, naming the method and the URL it built.

    Closing on the strength of the two merged PRs and the decision being fully executed. objectstack-ai/objectui#2921 is the last mechanical step and is open with CI running — if it does not land, reopen this rather than filing fresh, since the panel is the one place a user can still click a 404.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions