Skip to content

Commit 7ee4884

Browse files
Copilothotlong
andauthored
feat: align AI chat protocol with Vercel AI SDK, remove custom types and schemas
- Re-export ModelMessage, ToolCallPart, ToolResultPart, TextStreamPart from 'ai' - Remove AiChatRequestSchema/AiChatResponseSchema (use Vercel wire protocol) - Update IAIService/LLMAdapter to use Vercel types - Deprecate AIMessage, AIToolCall, AIToolResult, AIStreamEvent as aliases - Remove aiChat from IObjectStackAPI, client SDK, and DEFAULT_AI_ROUTES - Keep NLQ/Suggest/Insights protocols (ObjectStack-specific) - Update all tests (6772 pass) - Update CHANGELOG.md and ROADMAP.md Agent-Logs-Url: https://github.com/objectstack-ai/spec/sessions/2515d700-01d1-4303-8678-41f0ce9674da Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 6bda8e8 commit 7ee4884

11 files changed

Lines changed: 244 additions & 275 deletions

File tree

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
- **AI Chat Protocol Aligned with Vercel AI SDK** — Removed custom AI chat protocol
12+
types and Zod schemas (`AIMessage`, `AIToolCall`, `AIStreamEvent`,
13+
`AiChatRequestSchema`, `AiChatResponseSchema`) from `@objectstack/spec`. The
14+
canonical message, tool-call, and streaming types are now re-exported from the
15+
Vercel AI SDK (`ai` v6):
16+
- `ModelMessage` replaces `AIMessage`
17+
- `ToolCallPart` replaces `AIToolCall`
18+
- `ToolResultPart` replaces `AIToolResult`
19+
- `TextStreamPart<ToolSet>` replaces `AIStreamEvent`
20+
- `IAIService` and `LLMAdapter` method signatures now accept `ModelMessage[]`
21+
and return `TextStreamPart<ToolSet>` for streaming
22+
- Deprecated type aliases preserved for migration convenience
23+
- NLQ, Suggest, and Insights protocols (ObjectStack-specific) are retained
24+
25+
### Removed
26+
- `AiChatRequestSchema` / `AiChatResponseSchema` Zod schemas from
27+
`@objectstack/spec/api` — the AI chat wire protocol now uses Vercel AI SDK's
28+
data stream format (`toDataStreamResponse()`)
29+
- `aiChat` method from `IObjectStackAPI` and client SDK — consumers should use
30+
`@ai-sdk/react/useChat` directly
31+
- AI `/chat` endpoint from `DEFAULT_AI_ROUTES` plugin REST API definition
32+
33+
### Added
34+
- `ai` v6 as a dependency of `@objectstack/spec` for type re-exports
35+
1036
## [4.0.1] — 2026-03-31
1137

1238
### Fixed

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ObjectStack Protocol — Road Map
22

3-
> **Last Updated:** 2026-03-31
3+
> **Last Updated:** 2026-04-01
44
> **Current Version:** v4.0.1
55
> **Status:** Protocol Specification Complete · Runtime Implementation In Progress
66

packages/client/src/index.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ import {
6262
MarkAllNotificationsReadResponse,
6363
AiNlqRequest,
6464
AiNlqResponse,
65-
AiChatRequest,
66-
AiChatResponse,
6765
AiSuggestRequest,
6866
AiSuggestResponse,
6967
AiInsightsRequest,
@@ -1209,17 +1207,7 @@ export class ObjectStackClient {
12091207
return this.unwrapResponse<AiNlqResponse>(res);
12101208
},
12111209

1212-
/**
1213-
* Multi-turn AI chat
1214-
*/
1215-
chat: async (request: AiChatRequest): Promise<AiChatResponse> => {
1216-
const route = this.getRoute('ai');
1217-
const res = await this.fetch(`${this.baseUrl}${route}/chat`, {
1218-
method: 'POST',
1219-
body: JSON.stringify(request)
1220-
});
1221-
return this.unwrapResponse<AiChatResponse>(res);
1222-
},
1210+
// AI chat method removed — use Vercel AI SDK `useChat()` / `@ai-sdk/react` directly.
12231211

12241212
/**
12251213
* AI-powered field value suggestions
@@ -1826,8 +1814,6 @@ export type {
18261814
ListNotificationsResponse,
18271815
AiNlqRequest,
18281816
AiNlqResponse,
1829-
AiChatRequest,
1830-
AiChatResponse,
18311817
AiSuggestRequest,
18321818
AiSuggestResponse,
18331819
AiInsightsRequest,

packages/spec/src/api/plugin-rest-api.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,13 +571,10 @@ describe('plugin-rest-api.zod', () => {
571571
expect(DEFAULT_AI_ROUTES.service).toBe('ai');
572572
expect(DEFAULT_AI_ROUTES.category).toBe('ai');
573573
expect(DEFAULT_AI_ROUTES.methods).toContain('aiNlq');
574-
expect(DEFAULT_AI_ROUTES.methods).toContain('aiChat');
574+
// aiChat removed — wire protocol aligned with Vercel AI SDK
575575
expect(DEFAULT_AI_ROUTES.methods).toContain('aiSuggest');
576576
expect(DEFAULT_AI_ROUTES.methods).toContain('aiInsights');
577-
expect(DEFAULT_AI_ROUTES.endpoints).toHaveLength(4);
578-
// AI endpoints should have extended timeouts
579-
const chatEndpoint = DEFAULT_AI_ROUTES.endpoints?.find(e => e.handler === 'aiChat');
580-
expect(chatEndpoint?.timeout).toBe(60000);
577+
expect(DEFAULT_AI_ROUTES.endpoints).toHaveLength(3);
581578
});
582579

583580
it('should validate DEFAULT_I18N_ROUTES', () => {

packages/spec/src/api/plugin-rest-api.zod.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,7 @@ export const DEFAULT_AI_ROUTES: RestApiRouteRegistration = {
13981398
prefix: '/api/v1/ai',
13991399
service: 'ai',
14001400
category: 'ai',
1401-
methods: ['aiNlq', 'aiChat', 'aiSuggest', 'aiInsights'],
1401+
methods: ['aiNlq', 'aiSuggest', 'aiInsights'],
14021402
authRequired: true,
14031403
endpoints: [
14041404
{
@@ -1415,20 +1415,8 @@ export const DEFAULT_AI_ROUTES: RestApiRouteRegistration = {
14151415
timeout: 30000,
14161416
cacheable: false,
14171417
},
1418-
{
1419-
method: 'POST',
1420-
path: '/chat',
1421-
handler: 'aiChat',
1422-
category: 'ai',
1423-
public: false,
1424-
summary: 'AI chat interaction',
1425-
description: 'Sends a message to the AI assistant and receives a response',
1426-
tags: ['AI'],
1427-
requestSchema: 'AiChatRequestSchema',
1428-
responseSchema: 'AiChatResponseSchema',
1429-
timeout: 60000,
1430-
cacheable: false,
1431-
},
1418+
// AI chat route removed — wire protocol aligned with Vercel AI SDK.
1419+
// The chat endpoint should use Vercel's `toDataStreamResponse()` directly.
14321420
{
14331421
method: 'POST',
14341422
path: '/suggest',

packages/spec/src/api/protocol.test.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ import {
5454
// AI
5555
AiNlqRequestSchema,
5656
AiNlqResponseSchema,
57-
AiChatRequestSchema,
58-
AiChatResponseSchema,
5957
AiSuggestRequestSchema,
6058
AiSuggestResponseSchema,
6159
AiInsightsRequestSchema,
@@ -285,11 +283,7 @@ describe('ObjectStack Protocol', () => {
285283
query: { object: 'task', where: { status: 'open' } },
286284
explanation: 'Find all tasks with open status', confidence: 0.92,
287285
}).success).toBe(true);
288-
expect(AiChatRequestSchema.safeParse({ message: 'How many tasks are overdue?', conversationId: 'c1' }).success).toBe(true);
289-
expect(AiChatResponseSchema.safeParse({
290-
message: 'There are 5 overdue tasks.', conversationId: 'c1',
291-
actions: [{ type: 'navigate', label: 'View overdue tasks' }],
292-
}).success).toBe(true);
286+
// AiChatRequestSchema/AiChatResponseSchema removed — chat protocol aligned with Vercel AI SDK
293287
expect(AiSuggestRequestSchema.safeParse({ object: 'task', field: 'priority', partial: 'hi' }).success).toBe(true);
294288
expect(AiSuggestResponseSchema.safeParse({
295289
suggestions: [{ value: 'high', label: 'High', confidence: 0.95, reason: 'Matches partial input' }],

packages/spec/src/api/protocol.zod.ts

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -851,21 +851,10 @@ export const AiNlqResponseSchema = z.object({
851851
suggestions: z.array(z.string()).optional().describe('Suggested follow-up queries'),
852852
});
853853

854-
export const AiChatRequestSchema = z.object({
855-
message: z.string().describe('User message'),
856-
conversationId: z.string().optional().describe('Conversation ID for context'),
857-
context: z.record(z.string(), z.unknown()).optional().describe('Additional context data'),
858-
});
859-
860-
export const AiChatResponseSchema = z.object({
861-
message: z.string().describe('Assistant response message'),
862-
conversationId: z.string().describe('Conversation ID'),
863-
actions: z.array(z.object({
864-
type: z.string().describe('Action type'),
865-
label: z.string().describe('Action display label'),
866-
data: z.record(z.string(), z.unknown()).optional().describe('Action data'),
867-
})).optional().describe('Suggested actions'),
868-
});
854+
// AiChatRequestSchema and AiChatResponseSchema have been removed.
855+
// The AI chat wire protocol is now fully aligned with the Vercel AI SDK (`ai`).
856+
// Frontend consumers should use `@ai-sdk/react/useChat` directly.
857+
// See: https://ai-sdk.dev/docs
869858

870859
export const AiSuggestRequestSchema = z.object({
871860
object: z.string().describe('Object name for context'),
@@ -1264,8 +1253,6 @@ export type MarkAllNotificationsReadResponse = z.infer<typeof MarkAllNotificatio
12641253
// AI Types
12651254
export type AiNlqRequest = z.input<typeof AiNlqRequestSchema>;
12661255
export type AiNlqResponse = z.infer<typeof AiNlqResponseSchema>;
1267-
export type AiChatRequest = z.input<typeof AiChatRequestSchema>;
1268-
export type AiChatResponse = z.infer<typeof AiChatResponseSchema>;
12691256
export type AiSuggestRequest = z.input<typeof AiSuggestRequestSchema>;
12701257
export type AiSuggestResponse = z.infer<typeof AiSuggestResponseSchema>;
12711258
export type AiInsightsRequest = z.input<typeof AiInsightsRequestSchema>;
@@ -1416,9 +1403,8 @@ export interface ObjectStackProtocol {
14161403
markNotificationsRead?(request: MarkNotificationsReadRequest): Promise<MarkNotificationsReadResponse>;
14171404
markAllNotificationsRead?(request: MarkAllNotificationsReadRequest): Promise<MarkAllNotificationsReadResponse>;
14181405

1419-
// AI (optional)
1406+
// AI (optional — chat is now handled by Vercel AI SDK wire protocol)
14201407
aiNlq?(request: AiNlqRequest): Promise<AiNlqResponse>;
1421-
aiChat?(request: AiChatRequest): Promise<AiChatResponse>;
14221408
aiSuggest?(request: AiSuggestRequest): Promise<AiSuggestResponse>;
14231409
aiInsights?(request: AiInsightsRequest): Promise<AiInsightsResponse>;
14241410

0 commit comments

Comments
 (0)