@sveda-ai/protocol 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sveda AI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @sveda-ai/protocol
2
+
3
+ Sveda Wire Protocol — stream event schemas and constants used by the JS client packages.
4
+
5
+ ```bash
6
+ npm install @sveda-ai/protocol
7
+ ```
@@ -0,0 +1,88 @@
1
+ {
2
+ "version": "1.0",
3
+ "prefix": "/sveda",
4
+ "accept": {
5
+ "svedaStream": "application/vnd.sveda.stream+json",
6
+ "sse": "text/event-stream"
7
+ },
8
+ "headers": {
9
+ "inbound": [
10
+ "Accept",
11
+ "Authorization",
12
+ "Content-Type",
13
+ "X-Sveda-Admin-Key",
14
+ "X-Sveda-Embed-Token",
15
+ "X-Sveda-Host-Key",
16
+ "X-Sveda-Protocol"
17
+ ],
18
+ "streamResponse": {
19
+ "Content-Type": "text/event-stream",
20
+ "Cache-Control": "no-cache",
21
+ "X-Accel-Buffering": "no",
22
+ "X-Sveda-Protocol-Version": "1.0"
23
+ },
24
+ "mcpOutbound": [
25
+ "X-Sveda-Page-Context",
26
+ "X-Sveda-Chat-Id"
27
+ ]
28
+ },
29
+ "cors": {
30
+ "allowedHeaders": [
31
+ "Accept",
32
+ "Authorization",
33
+ "Content-Type",
34
+ "X-Requested-With",
35
+ "X-Sveda-Embed-Token",
36
+ "X-Sveda-Host-Key",
37
+ "X-Sveda-Admin-Key",
38
+ "X-Sveda-Protocol"
39
+ ],
40
+ "allowedMethods": ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
41
+ },
42
+ "routes": [
43
+ { "method": "POST", "path": "/sveda/stream", "mode": "sse" },
44
+ { "method": "POST", "path": "/sveda/message", "mode": "json" },
45
+ { "method": "GET", "path": "/sveda/chat-histories", "mode": "json" },
46
+ { "method": "GET", "path": "/sveda/chat-histories/{chatId}", "mode": "json" },
47
+ { "method": "PATCH", "path": "/sveda/chat-histories/{chatId}", "mode": "json" },
48
+ { "method": "DELETE", "path": "/sveda/chat-histories/{chatId}", "mode": "json" },
49
+ { "method": "POST", "path": "/sveda/documents/extract", "mode": "json" },
50
+ { "method": "GET", "path": "/sveda/embed/config", "mode": "json" },
51
+ { "method": "POST", "path": "/sveda/embed/token", "mode": "json" }
52
+ ],
53
+ "streamEvents": [
54
+ "message.start",
55
+ "text.delta",
56
+ "reasoning.delta",
57
+ "tool.call",
58
+ "tool.result",
59
+ "tool.progress",
60
+ "context.usage",
61
+ "chat.title",
62
+ "max_steps",
63
+ "message.end",
64
+ "error"
65
+ ],
66
+ "sseDoneLine": "data: [DONE]",
67
+ "embedToken": {
68
+ "request": ["visitor_id", "host_mcp_url", "host_mcp_token"],
69
+ "responseRequired": ["token", "visitor_id", "expires_in"],
70
+ "responseOptional": ["appearance"]
71
+ },
72
+ "message": {
73
+ "responseRequired": ["explanation", "tokens_used", "chat_id"]
74
+ },
75
+ "histories": {
76
+ "listKey": "histories",
77
+ "detailKey": "history",
78
+ "summaryRequired": ["id", "chatId", "title", "preview", "tokensUsed", "version", "createdAt", "updatedAt"],
79
+ "detailRequired": ["id", "chatId", "title", "messages", "conversationHistory", "tokensUsed", "version", "createdAt", "updatedAt"],
80
+ "patchRequest": ["title"],
81
+ "mutationResponseRequired": ["success"]
82
+ },
83
+ "documentsExtract": {
84
+ "requestField": "files",
85
+ "responseKey": "items",
86
+ "itemRequired": ["filename", "ok"]
87
+ }
88
+ }
@@ -0,0 +1,102 @@
1
+ export declare const SVEDA_PROTOCOL_VERSION: "1.0";
2
+ export declare const SVEDA_STREAM_EVENTS: readonly ["message.start", "text.delta", "reasoning.delta", "tool.call", "tool.result", "tool.progress", "context.usage", "chat.title", "max_steps", "message.end", "error"];
3
+ export type SvedaStreamEventType = (typeof SVEDA_STREAM_EVENTS)[number];
4
+ export type SvedaToolTarget = 'backend' | 'frontend';
5
+ export type SvedaRenderHint = 'confirm_dialog' | 'resource_links' | 'plain' | 'custom';
6
+ export interface SvedaStreamEventBase {
7
+ type: SvedaStreamEventType;
8
+ chatId?: string;
9
+ messageId?: string;
10
+ timestamp?: string;
11
+ }
12
+ export interface SvedaMessageStartEvent extends SvedaStreamEventBase {
13
+ type: 'message.start';
14
+ }
15
+ export interface SvedaTextDeltaEvent extends SvedaStreamEventBase {
16
+ type: 'text.delta';
17
+ delta: string;
18
+ }
19
+ export interface SvedaReasoningDeltaEvent extends SvedaStreamEventBase {
20
+ type: 'reasoning.delta';
21
+ delta: string;
22
+ }
23
+ export interface SvedaToolCallEvent extends SvedaStreamEventBase {
24
+ type: 'tool.call';
25
+ toolCallId: string;
26
+ toolName: string;
27
+ target: SvedaToolTarget;
28
+ input: Record<string, unknown>;
29
+ }
30
+ export interface SvedaToolResultEvent extends SvedaStreamEventBase {
31
+ type: 'tool.result';
32
+ toolCallId: string;
33
+ toolName: string;
34
+ output: unknown;
35
+ renderHint?: SvedaRenderHint;
36
+ renderData?: Record<string, unknown>;
37
+ }
38
+ export interface SvedaToolProgressTask {
39
+ id: string;
40
+ label: string;
41
+ status: 'pending' | 'running' | 'completed' | 'failed';
42
+ detail?: string;
43
+ }
44
+ export interface SvedaToolProgressEvent extends SvedaStreamEventBase {
45
+ type: 'tool.progress';
46
+ phase?: string;
47
+ tasks: SvedaToolProgressTask[];
48
+ }
49
+ export interface SvedaContextUsageEvent extends SvedaStreamEventBase {
50
+ type: 'context.usage';
51
+ usedTokens: number;
52
+ maxTokens: number;
53
+ percent: number;
54
+ }
55
+ export interface SvedaChatTitleEvent extends SvedaStreamEventBase {
56
+ type: 'chat.title';
57
+ title: string;
58
+ }
59
+ export interface SvedaMaxStepsEvent extends SvedaStreamEventBase {
60
+ type: 'max_steps';
61
+ maxSteps: number;
62
+ canContinue: boolean;
63
+ }
64
+ export interface SvedaMessageEndEvent extends SvedaStreamEventBase {
65
+ type: 'message.end';
66
+ finishReason?: string;
67
+ usage?: {
68
+ promptTokens?: number;
69
+ completionTokens?: number;
70
+ totalTokens?: number;
71
+ };
72
+ }
73
+ export interface SvedaErrorEvent extends SvedaStreamEventBase {
74
+ type: 'error';
75
+ code: string;
76
+ message: string;
77
+ }
78
+ export type SvedaStreamEvent = SvedaMessageStartEvent | SvedaTextDeltaEvent | SvedaReasoningDeltaEvent | SvedaToolCallEvent | SvedaToolResultEvent | SvedaToolProgressEvent | SvedaContextUsageEvent | SvedaChatTitleEvent | SvedaMaxStepsEvent | SvedaMessageEndEvent | SvedaErrorEvent;
79
+ export interface SvedaClientToolDefinition {
80
+ name: string;
81
+ description: string;
82
+ parameters: Record<string, unknown>;
83
+ }
84
+ export interface SvedaChatMessage {
85
+ id?: string;
86
+ role: 'user' | 'assistant' | 'system' | 'tool';
87
+ content?: string;
88
+ parts?: Array<Record<string, unknown>>;
89
+ }
90
+ export interface SvedaStreamRequest {
91
+ messages: SvedaChatMessage[];
92
+ prompt?: string;
93
+ chatId?: string;
94
+ context?: Record<string, unknown>;
95
+ clientTools?: SvedaClientToolDefinition[];
96
+ model?: string;
97
+ provider?: string;
98
+ options?: Record<string, unknown>;
99
+ }
100
+ export declare function isSvedaStreamEvent(value: unknown): value is SvedaStreamEvent;
101
+ export declare function parseSvedaStreamLine(line: string): SvedaStreamEvent | null;
102
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
package/dist/events.js ADDED
@@ -0,0 +1,42 @@
1
+ export const SVEDA_PROTOCOL_VERSION = '1.0';
2
+ export const SVEDA_STREAM_EVENTS = [
3
+ 'message.start',
4
+ 'text.delta',
5
+ 'reasoning.delta',
6
+ 'tool.call',
7
+ 'tool.result',
8
+ 'tool.progress',
9
+ 'context.usage',
10
+ 'chat.title',
11
+ 'max_steps',
12
+ 'message.end',
13
+ 'error',
14
+ ];
15
+ export function isSvedaStreamEvent(value) {
16
+ if (!value || typeof value !== 'object') {
17
+ return false;
18
+ }
19
+ const type = value.type;
20
+ return typeof type === 'string' && SVEDA_STREAM_EVENTS.includes(type);
21
+ }
22
+ export function parseSvedaStreamLine(line) {
23
+ const trimmed = line.trim();
24
+ if (!trimmed.startsWith('data:')) {
25
+ return null;
26
+ }
27
+ const payload = trimmed.slice(5).trim();
28
+ if (!payload || payload === '[DONE]') {
29
+ return null;
30
+ }
31
+ try {
32
+ const parsed = JSON.parse(payload);
33
+ if (isSvedaStreamEvent(parsed)) {
34
+ return parsed;
35
+ }
36
+ return null;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAc,CAAC;AAErD,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,eAAe;IACf,YAAY;IACZ,iBAAiB;IACjB,WAAW;IACX,aAAa;IACb,eAAe;IACf,eAAe;IACf,YAAY;IACZ,WAAW;IACX,aAAa;IACb,OAAO;CACC,CAAC;AAsIX,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,GAAI,KAA4B,CAAC,IAAI,CAAC;IAChD,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAK,mBAAyC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC;QAC9C,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './events.js';
2
+ export * from './vercelAdapter.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './events.js';
2
+ export * from './vercelAdapter.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { SvedaStreamEvent } from './events.js';
2
+ export type VercelDataPart = {
3
+ type: string;
4
+ [key: string]: unknown;
5
+ };
6
+ export declare function svedaEventToVercelDataPart(event: SvedaStreamEvent): VercelDataPart | null;
7
+ export declare function vercelDataPartToSvedaEvent(part: VercelDataPart): SvedaStreamEvent | null;
8
+ export declare function encodeSvedaStreamEvent(event: SvedaStreamEvent): string;
9
+ //# sourceMappingURL=vercelAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercelAdapter.d.ts","sourceRoot":"","sources":["../src/vercelAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAErE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,gBAAgB,GAAG,cAAc,GAAG,IAAI,CAuDzF;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,cAAc,GAAG,gBAAgB,GAAG,IAAI,CAsExF;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAEtE"}
@@ -0,0 +1,125 @@
1
+ export function svedaEventToVercelDataPart(event) {
2
+ switch (event.type) {
3
+ case 'text.delta':
4
+ return { type: 'text-delta', textDelta: event.delta };
5
+ case 'reasoning.delta':
6
+ return { type: 'reasoning-delta', reasoningDelta: event.delta };
7
+ case 'tool.call':
8
+ return {
9
+ type: 'tool-call',
10
+ toolCallId: event.toolCallId,
11
+ toolName: event.toolName,
12
+ args: event.input,
13
+ target: event.target,
14
+ };
15
+ case 'tool.result':
16
+ return {
17
+ type: 'tool-result',
18
+ toolCallId: event.toolCallId,
19
+ toolName: event.toolName,
20
+ result: event.output,
21
+ renderHint: event.renderHint,
22
+ renderData: event.renderData,
23
+ };
24
+ case 'tool.progress':
25
+ return {
26
+ type: 'data-toolProgress',
27
+ data: { phase: event.phase, tasks: event.tasks },
28
+ };
29
+ case 'context.usage':
30
+ return {
31
+ type: 'data-contextUsage',
32
+ data: {
33
+ usedTokens: event.usedTokens,
34
+ maxTokens: event.maxTokens,
35
+ percent: event.percent,
36
+ },
37
+ };
38
+ case 'chat.title':
39
+ return { type: 'data-chatTitle', data: { title: event.title } };
40
+ case 'max_steps':
41
+ return {
42
+ type: 'data-maxStepsReached',
43
+ data: { maxSteps: event.maxSteps, canContinue: event.canContinue },
44
+ };
45
+ case 'message.end':
46
+ return {
47
+ type: 'finish',
48
+ finishReason: event.finishReason ?? 'stop',
49
+ usage: event.usage,
50
+ };
51
+ case 'error':
52
+ return { type: 'error', error: { code: event.code, message: event.message } };
53
+ default:
54
+ return null;
55
+ }
56
+ }
57
+ export function vercelDataPartToSvedaEvent(part) {
58
+ const data = (part.data ?? {});
59
+ switch (part.type) {
60
+ case 'text-delta':
61
+ return { type: 'text.delta', delta: String(part.textDelta ?? '') };
62
+ case 'reasoning-delta':
63
+ return { type: 'reasoning.delta', delta: String(part.reasoningDelta ?? '') };
64
+ case 'tool-call':
65
+ return {
66
+ type: 'tool.call',
67
+ toolCallId: String(part.toolCallId ?? ''),
68
+ toolName: String(part.toolName ?? ''),
69
+ target: part.target === 'frontend' ? 'frontend' : 'backend',
70
+ input: part.args ?? {},
71
+ };
72
+ case 'tool-result':
73
+ return {
74
+ type: 'tool.result',
75
+ toolCallId: String(part.toolCallId ?? ''),
76
+ toolName: String(part.toolName ?? ''),
77
+ output: part.result,
78
+ renderHint: part.renderHint,
79
+ renderData: part.renderData,
80
+ };
81
+ case 'data-toolProgress': {
82
+ const tasks = Array.isArray(data.tasks) ? data.tasks : [];
83
+ return {
84
+ type: 'tool.progress',
85
+ phase: typeof data.phase === 'string' ? data.phase : undefined,
86
+ tasks: tasks,
87
+ };
88
+ }
89
+ case 'data-contextUsage':
90
+ return {
91
+ type: 'context.usage',
92
+ usedTokens: Number(data.usedTokens ?? 0),
93
+ maxTokens: Number(data.maxTokens ?? 0),
94
+ percent: Number(data.percent ?? 0),
95
+ };
96
+ case 'data-chatTitle':
97
+ return { type: 'chat.title', title: String(data.title ?? '') };
98
+ case 'data-maxStepsReached':
99
+ return {
100
+ type: 'max_steps',
101
+ maxSteps: Number(data.maxSteps ?? 0),
102
+ canContinue: Boolean(data.canContinue ?? true),
103
+ };
104
+ case 'finish':
105
+ return {
106
+ type: 'message.end',
107
+ finishReason: String(part.finishReason ?? 'stop'),
108
+ usage: part.usage,
109
+ };
110
+ case 'error': {
111
+ const error = (part.error ?? {});
112
+ return {
113
+ type: 'error',
114
+ code: String(error.code ?? 'unknown'),
115
+ message: String(error.message ?? 'Unknown error'),
116
+ };
117
+ }
118
+ default:
119
+ return null;
120
+ }
121
+ }
122
+ export function encodeSvedaStreamEvent(event) {
123
+ return `data: ${JSON.stringify(event)}\n\n`;
124
+ }
125
+ //# sourceMappingURL=vercelAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercelAdapter.js","sourceRoot":"","sources":["../src/vercelAdapter.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@sveda-ai/protocol",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "description": "Sveda Wire Protocol — stream event schemas and constants.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/neresson/sveda.git",
10
+ "directory": "packages/protocol"
11
+ },
12
+ "homepage": "https://github.com/neresson/sveda/tree/main/packages/protocol",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ },
20
+ "./schemas/*": "./schemas/*",
21
+ "./contracts/*": "./contracts/*"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "src",
29
+ "schemas",
30
+ "contracts"
31
+ ],
32
+ "devDependencies": {
33
+ "typescript": "^5.8.2",
34
+ "vitest": "^4.1.4"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.json",
38
+ "test": "vitest run",
39
+ "typecheck": "tsc -p tsconfig.json --noEmit",
40
+ "lint": "echo 'no lint configured'"
41
+ }
42
+ }
@@ -0,0 +1,189 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://sveda-ai.dev/schemas/v1/stream-event.schema.json",
4
+ "title": "Sveda Wire Protocol v1 — Stream Event",
5
+ "description": "Server-to-client SSE event envelope. Every event is a JSON object sent as one SSE `data:` frame.",
6
+ "oneOf": [
7
+ { "$ref": "#/$defs/messageStart" },
8
+ { "$ref": "#/$defs/textDelta" },
9
+ { "$ref": "#/$defs/reasoningDelta" },
10
+ { "$ref": "#/$defs/toolCall" },
11
+ { "$ref": "#/$defs/toolResult" },
12
+ { "$ref": "#/$defs/toolProgress" },
13
+ { "$ref": "#/$defs/contextUsage" },
14
+ { "$ref": "#/$defs/chatTitle" },
15
+ { "$ref": "#/$defs/maxSteps" },
16
+ { "$ref": "#/$defs/messageEnd" },
17
+ { "$ref": "#/$defs/error" }
18
+ ],
19
+ "$defs": {
20
+ "base": {
21
+ "type": "object",
22
+ "required": ["type"],
23
+ "properties": {
24
+ "type": { "type": "string" },
25
+ "chatId": { "type": "string" },
26
+ "messageId": { "type": "string" },
27
+ "timestamp": { "type": "string", "format": "date-time" }
28
+ }
29
+ },
30
+ "messageStart": {
31
+ "allOf": [
32
+ { "$ref": "#/$defs/base" },
33
+ { "type": "object", "properties": { "type": { "const": "message.start" } } }
34
+ ]
35
+ },
36
+ "textDelta": {
37
+ "allOf": [
38
+ { "$ref": "#/$defs/base" },
39
+ {
40
+ "type": "object",
41
+ "required": ["delta"],
42
+ "properties": { "type": { "const": "text.delta" }, "delta": { "type": "string" } }
43
+ }
44
+ ]
45
+ },
46
+ "reasoningDelta": {
47
+ "allOf": [
48
+ { "$ref": "#/$defs/base" },
49
+ {
50
+ "type": "object",
51
+ "required": ["delta"],
52
+ "properties": { "type": { "const": "reasoning.delta" }, "delta": { "type": "string" } }
53
+ }
54
+ ]
55
+ },
56
+ "toolCall": {
57
+ "allOf": [
58
+ { "$ref": "#/$defs/base" },
59
+ {
60
+ "type": "object",
61
+ "required": ["toolCallId", "toolName", "target", "input"],
62
+ "properties": {
63
+ "type": { "const": "tool.call" },
64
+ "toolCallId": { "type": "string" },
65
+ "toolName": { "type": "string" },
66
+ "target": { "enum": ["backend", "frontend"] },
67
+ "input": { "type": "object" }
68
+ }
69
+ }
70
+ ]
71
+ },
72
+ "toolResult": {
73
+ "allOf": [
74
+ { "$ref": "#/$defs/base" },
75
+ {
76
+ "type": "object",
77
+ "required": ["toolCallId", "toolName", "output"],
78
+ "properties": {
79
+ "type": { "const": "tool.result" },
80
+ "toolCallId": { "type": "string" },
81
+ "toolName": { "type": "string" },
82
+ "output": true,
83
+ "renderHint": { "enum": ["confirm_dialog", "resource_links", "plain", "custom"] },
84
+ "renderData": { "type": "object" }
85
+ }
86
+ }
87
+ ]
88
+ },
89
+ "toolProgress": {
90
+ "allOf": [
91
+ { "$ref": "#/$defs/base" },
92
+ {
93
+ "type": "object",
94
+ "required": ["tasks"],
95
+ "properties": {
96
+ "type": { "const": "tool.progress" },
97
+ "phase": { "type": "string" },
98
+ "tasks": {
99
+ "type": "array",
100
+ "items": {
101
+ "type": "object",
102
+ "required": ["id", "label", "status"],
103
+ "properties": {
104
+ "id": { "type": "string" },
105
+ "label": { "type": "string" },
106
+ "status": { "enum": ["pending", "running", "completed", "failed"] },
107
+ "detail": { "type": "string" }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ ]
114
+ },
115
+ "contextUsage": {
116
+ "allOf": [
117
+ { "$ref": "#/$defs/base" },
118
+ {
119
+ "type": "object",
120
+ "required": ["usedTokens", "maxTokens", "percent"],
121
+ "properties": {
122
+ "type": { "const": "context.usage" },
123
+ "usedTokens": { "type": "integer", "minimum": 0 },
124
+ "maxTokens": { "type": "integer", "minimum": 0 },
125
+ "percent": { "type": "number", "minimum": 0, "maximum": 100 }
126
+ }
127
+ }
128
+ ]
129
+ },
130
+ "chatTitle": {
131
+ "allOf": [
132
+ { "$ref": "#/$defs/base" },
133
+ {
134
+ "type": "object",
135
+ "required": ["title"],
136
+ "properties": { "type": { "const": "chat.title" }, "title": { "type": "string" } }
137
+ }
138
+ ]
139
+ },
140
+ "maxSteps": {
141
+ "allOf": [
142
+ { "$ref": "#/$defs/base" },
143
+ {
144
+ "type": "object",
145
+ "required": ["maxSteps", "canContinue"],
146
+ "properties": {
147
+ "type": { "const": "max_steps" },
148
+ "maxSteps": { "type": "integer", "minimum": 1 },
149
+ "canContinue": { "type": "boolean" }
150
+ }
151
+ }
152
+ ]
153
+ },
154
+ "messageEnd": {
155
+ "allOf": [
156
+ { "$ref": "#/$defs/base" },
157
+ {
158
+ "type": "object",
159
+ "properties": {
160
+ "type": { "const": "message.end" },
161
+ "finishReason": { "type": "string" },
162
+ "usage": {
163
+ "type": "object",
164
+ "properties": {
165
+ "promptTokens": { "type": "integer" },
166
+ "completionTokens": { "type": "integer" },
167
+ "totalTokens": { "type": "integer" }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ ]
173
+ },
174
+ "error": {
175
+ "allOf": [
176
+ { "$ref": "#/$defs/base" },
177
+ {
178
+ "type": "object",
179
+ "required": ["code", "message"],
180
+ "properties": {
181
+ "type": { "const": "error" },
182
+ "code": { "type": "string" },
183
+ "message": { "type": "string" }
184
+ }
185
+ }
186
+ ]
187
+ }
188
+ }
189
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://sveda-ai.dev/schemas/v1/stream-request.schema.json",
4
+ "title": "Sveda Wire Protocol v1 — Stream Request",
5
+ "description": "Client-to-server POST body for /sveda/stream.",
6
+ "type": "object",
7
+ "required": ["messages"],
8
+ "properties": {
9
+ "messages": {
10
+ "type": "array",
11
+ "minItems": 1,
12
+ "items": {
13
+ "type": "object",
14
+ "required": ["role"],
15
+ "properties": {
16
+ "id": { "type": "string" },
17
+ "role": { "enum": ["user", "assistant", "system", "tool"] },
18
+ "content": { "type": "string" },
19
+ "parts": { "type": "array", "items": { "type": "object" } }
20
+ }
21
+ }
22
+ },
23
+ "chatId": { "type": "string" },
24
+ "context": {
25
+ "type": "object",
26
+ "description": "Host-provided context: page, host page, global readables."
27
+ },
28
+ "clientTools": {
29
+ "type": "array",
30
+ "items": {
31
+ "type": "object",
32
+ "required": ["name", "description", "parameters"],
33
+ "properties": {
34
+ "name": { "type": "string" },
35
+ "description": { "type": "string" },
36
+ "parameters": { "type": "object", "description": "JSON Schema of tool input" }
37
+ }
38
+ }
39
+ },
40
+ "model": { "type": "string" },
41
+ "provider": { "type": "string" },
42
+ "options": { "type": "object" }
43
+ }
44
+ }
package/src/events.ts ADDED
@@ -0,0 +1,179 @@
1
+ export const SVEDA_PROTOCOL_VERSION = '1.0' as const;
2
+
3
+ export const SVEDA_STREAM_EVENTS = [
4
+ 'message.start',
5
+ 'text.delta',
6
+ 'reasoning.delta',
7
+ 'tool.call',
8
+ 'tool.result',
9
+ 'tool.progress',
10
+ 'context.usage',
11
+ 'chat.title',
12
+ 'max_steps',
13
+ 'message.end',
14
+ 'error',
15
+ ] as const;
16
+
17
+ export type SvedaStreamEventType = (typeof SVEDA_STREAM_EVENTS)[number];
18
+
19
+ export type SvedaToolTarget = 'backend' | 'frontend';
20
+
21
+ export type SvedaRenderHint =
22
+ | 'confirm_dialog'
23
+ | 'resource_links'
24
+ | 'plain'
25
+ | 'custom';
26
+
27
+ export interface SvedaStreamEventBase {
28
+ type: SvedaStreamEventType;
29
+ chatId?: string;
30
+ messageId?: string;
31
+ timestamp?: string;
32
+ }
33
+
34
+ export interface SvedaMessageStartEvent extends SvedaStreamEventBase {
35
+ type: 'message.start';
36
+ }
37
+
38
+ export interface SvedaTextDeltaEvent extends SvedaStreamEventBase {
39
+ type: 'text.delta';
40
+ delta: string;
41
+ }
42
+
43
+ export interface SvedaReasoningDeltaEvent extends SvedaStreamEventBase {
44
+ type: 'reasoning.delta';
45
+ delta: string;
46
+ }
47
+
48
+ export interface SvedaToolCallEvent extends SvedaStreamEventBase {
49
+ type: 'tool.call';
50
+ toolCallId: string;
51
+ toolName: string;
52
+ target: SvedaToolTarget;
53
+ input: Record<string, unknown>;
54
+ }
55
+
56
+ export interface SvedaToolResultEvent extends SvedaStreamEventBase {
57
+ type: 'tool.result';
58
+ toolCallId: string;
59
+ toolName: string;
60
+ output: unknown;
61
+ renderHint?: SvedaRenderHint;
62
+ renderData?: Record<string, unknown>;
63
+ }
64
+
65
+ export interface SvedaToolProgressTask {
66
+ id: string;
67
+ label: string;
68
+ status: 'pending' | 'running' | 'completed' | 'failed';
69
+ detail?: string;
70
+ }
71
+
72
+ export interface SvedaToolProgressEvent extends SvedaStreamEventBase {
73
+ type: 'tool.progress';
74
+ phase?: string;
75
+ tasks: SvedaToolProgressTask[];
76
+ }
77
+
78
+ export interface SvedaContextUsageEvent extends SvedaStreamEventBase {
79
+ type: 'context.usage';
80
+ usedTokens: number;
81
+ maxTokens: number;
82
+ percent: number;
83
+ }
84
+
85
+ export interface SvedaChatTitleEvent extends SvedaStreamEventBase {
86
+ type: 'chat.title';
87
+ title: string;
88
+ }
89
+
90
+ export interface SvedaMaxStepsEvent extends SvedaStreamEventBase {
91
+ type: 'max_steps';
92
+ maxSteps: number;
93
+ canContinue: boolean;
94
+ }
95
+
96
+ export interface SvedaMessageEndEvent extends SvedaStreamEventBase {
97
+ type: 'message.end';
98
+ finishReason?: string;
99
+ usage?: {
100
+ promptTokens?: number;
101
+ completionTokens?: number;
102
+ totalTokens?: number;
103
+ };
104
+ }
105
+
106
+ export interface SvedaErrorEvent extends SvedaStreamEventBase {
107
+ type: 'error';
108
+ code: string;
109
+ message: string;
110
+ }
111
+
112
+ export type SvedaStreamEvent =
113
+ | SvedaMessageStartEvent
114
+ | SvedaTextDeltaEvent
115
+ | SvedaReasoningDeltaEvent
116
+ | SvedaToolCallEvent
117
+ | SvedaToolResultEvent
118
+ | SvedaToolProgressEvent
119
+ | SvedaContextUsageEvent
120
+ | SvedaChatTitleEvent
121
+ | SvedaMaxStepsEvent
122
+ | SvedaMessageEndEvent
123
+ | SvedaErrorEvent;
124
+
125
+ export interface SvedaClientToolDefinition {
126
+ name: string;
127
+ description: string;
128
+ parameters: Record<string, unknown>;
129
+ }
130
+
131
+ export interface SvedaChatMessage {
132
+ id?: string;
133
+ role: 'user' | 'assistant' | 'system' | 'tool';
134
+ content?: string;
135
+ parts?: Array<Record<string, unknown>>;
136
+ }
137
+
138
+ export interface SvedaStreamRequest {
139
+ messages: SvedaChatMessage[];
140
+ prompt?: string;
141
+ chatId?: string;
142
+ context?: Record<string, unknown>;
143
+ clientTools?: SvedaClientToolDefinition[];
144
+ model?: string;
145
+ provider?: string;
146
+ options?: Record<string, unknown>;
147
+ }
148
+
149
+ export function isSvedaStreamEvent(value: unknown): value is SvedaStreamEvent {
150
+ if (!value || typeof value !== 'object') {
151
+ return false;
152
+ }
153
+
154
+ const type = (value as { type?: unknown }).type;
155
+ return typeof type === 'string' && (SVEDA_STREAM_EVENTS as readonly string[]).includes(type);
156
+ }
157
+
158
+ export function parseSvedaStreamLine(line: string): SvedaStreamEvent | null {
159
+ const trimmed = line.trim();
160
+ if (!trimmed.startsWith('data:')) {
161
+ return null;
162
+ }
163
+
164
+ const payload = trimmed.slice(5).trim();
165
+ if (!payload || payload === '[DONE]') {
166
+ return null;
167
+ }
168
+
169
+ try {
170
+ const parsed = JSON.parse(payload) as unknown;
171
+ if (isSvedaStreamEvent(parsed)) {
172
+ return parsed;
173
+ }
174
+
175
+ return null;
176
+ } catch {
177
+ return null;
178
+ }
179
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './events.js';
2
+ export * from './vercelAdapter.js';
@@ -0,0 +1,139 @@
1
+ import type { SvedaRenderHint, SvedaStreamEvent } from './events.js';
2
+
3
+ export type VercelDataPart = {
4
+ type: string;
5
+ [key: string]: unknown;
6
+ };
7
+
8
+ export function svedaEventToVercelDataPart(event: SvedaStreamEvent): VercelDataPart | null {
9
+ switch (event.type) {
10
+ case 'text.delta':
11
+ return { type: 'text-delta', textDelta: event.delta };
12
+ case 'reasoning.delta':
13
+ return { type: 'reasoning-delta', reasoningDelta: event.delta };
14
+ case 'tool.call':
15
+ return {
16
+ type: 'tool-call',
17
+ toolCallId: event.toolCallId,
18
+ toolName: event.toolName,
19
+ args: event.input,
20
+ target: event.target,
21
+ };
22
+ case 'tool.result':
23
+ return {
24
+ type: 'tool-result',
25
+ toolCallId: event.toolCallId,
26
+ toolName: event.toolName,
27
+ result: event.output,
28
+ renderHint: event.renderHint,
29
+ renderData: event.renderData,
30
+ };
31
+ case 'tool.progress':
32
+ return {
33
+ type: 'data-toolProgress',
34
+ data: { phase: event.phase, tasks: event.tasks },
35
+ };
36
+ case 'context.usage':
37
+ return {
38
+ type: 'data-contextUsage',
39
+ data: {
40
+ usedTokens: event.usedTokens,
41
+ maxTokens: event.maxTokens,
42
+ percent: event.percent,
43
+ },
44
+ };
45
+ case 'chat.title':
46
+ return { type: 'data-chatTitle', data: { title: event.title } };
47
+ case 'max_steps':
48
+ return {
49
+ type: 'data-maxStepsReached',
50
+ data: { maxSteps: event.maxSteps, canContinue: event.canContinue },
51
+ };
52
+ case 'message.end':
53
+ return {
54
+ type: 'finish',
55
+ finishReason: event.finishReason ?? 'stop',
56
+ usage: event.usage,
57
+ };
58
+ case 'error':
59
+ return { type: 'error', error: { code: event.code, message: event.message } };
60
+ default:
61
+ return null;
62
+ }
63
+ }
64
+
65
+ export function vercelDataPartToSvedaEvent(part: VercelDataPart): SvedaStreamEvent | null {
66
+ const data = (part.data ?? {}) as Record<string, unknown>;
67
+
68
+ switch (part.type) {
69
+ case 'text-delta':
70
+ return { type: 'text.delta', delta: String(part.textDelta ?? '') };
71
+ case 'reasoning-delta':
72
+ return { type: 'reasoning.delta', delta: String(part.reasoningDelta ?? '') };
73
+ case 'tool-call':
74
+ return {
75
+ type: 'tool.call',
76
+ toolCallId: String(part.toolCallId ?? ''),
77
+ toolName: String(part.toolName ?? ''),
78
+ target: part.target === 'frontend' ? 'frontend' : 'backend',
79
+ input: (part.args as Record<string, unknown>) ?? {},
80
+ };
81
+ case 'tool-result':
82
+ return {
83
+ type: 'tool.result',
84
+ toolCallId: String(part.toolCallId ?? ''),
85
+ toolName: String(part.toolName ?? ''),
86
+ output: part.result,
87
+ renderHint: part.renderHint as SvedaRenderHint | undefined,
88
+ renderData: part.renderData as Record<string, unknown> | undefined,
89
+ };
90
+ case 'data-toolProgress': {
91
+ const tasks = Array.isArray(data.tasks) ? data.tasks : [];
92
+ return {
93
+ type: 'tool.progress',
94
+ phase: typeof data.phase === 'string' ? data.phase : undefined,
95
+ tasks: tasks as Array<{
96
+ id: string;
97
+ label: string;
98
+ status: 'pending' | 'running' | 'completed' | 'failed';
99
+ detail?: string;
100
+ }>,
101
+ };
102
+ }
103
+ case 'data-contextUsage':
104
+ return {
105
+ type: 'context.usage',
106
+ usedTokens: Number(data.usedTokens ?? 0),
107
+ maxTokens: Number(data.maxTokens ?? 0),
108
+ percent: Number(data.percent ?? 0),
109
+ };
110
+ case 'data-chatTitle':
111
+ return { type: 'chat.title', title: String(data.title ?? '') };
112
+ case 'data-maxStepsReached':
113
+ return {
114
+ type: 'max_steps',
115
+ maxSteps: Number(data.maxSteps ?? 0),
116
+ canContinue: Boolean(data.canContinue ?? true),
117
+ };
118
+ case 'finish':
119
+ return {
120
+ type: 'message.end',
121
+ finishReason: String(part.finishReason ?? 'stop'),
122
+ usage: part.usage as { promptTokens?: number; completionTokens?: number; totalTokens?: number } | undefined,
123
+ };
124
+ case 'error': {
125
+ const error = (part.error ?? {}) as Record<string, unknown>;
126
+ return {
127
+ type: 'error',
128
+ code: String(error.code ?? 'unknown'),
129
+ message: String(error.message ?? 'Unknown error'),
130
+ };
131
+ }
132
+ default:
133
+ return null;
134
+ }
135
+ }
136
+
137
+ export function encodeSvedaStreamEvent(event: SvedaStreamEvent): string {
138
+ return `data: ${JSON.stringify(event)}\n\n`;
139
+ }