@amaster.ai/copilot-client 1.0.0-beta.0 → 1.0.0-beta.2

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/README.md CHANGED
@@ -1,338 +1 @@
1
1
  # @amaster.ai/copilot-client
2
-
3
- AI copilot client with full A2A Agent-to-Agent protocol support and streaming chat capabilities.
4
-
5
- ## Features
6
-
7
- - 💬 **Streaming Chat**: Real-time streaming responses with SSE
8
- - 🔄 **Task Management**: Cancel, monitor, and resubscribe to tasks
9
- - 🤖 **Multi-turn Conversations**: Support for conversation history
10
- - 🎯 **A2A Protocol**: Full JSON-RPC 2.0 implementation
11
- - 📡 **Auto Context**: Automatically extracts app context from URL
12
- - 🌳 **Tree-shakeable**: ESM/CJS builds with TypeScript support
13
-
14
- ## Installation
15
-
16
- ```bash
17
- pnpm add @amaster.ai/copilot-client @amaster.ai/http-client axios @a2a-js/sdk eventsource-parser
18
- ```
19
-
20
- ## Quick Start
21
-
22
- ```typescript
23
- import { createCopilotClient } from "@amaster.ai/copilot-client";
24
-
25
- const copilot = createCopilotClient();
26
-
27
- // Stream chat responses
28
- for await (const chunk of copilot.chat([
29
- { role: "user", content: "Hello, how are you?" }
30
- ])) {
31
- console.log(chunk.text); // Print each chunk as it arrives
32
-
33
- if (chunk.isFinal) {
34
- console.log("Chat completed with status:", chunk.status);
35
- }
36
- }
37
- ```
38
-
39
- ## Architecture
40
-
41
- This client implements the **A2A (Agent-to-Agent)** protocol for AI interactions:
42
-
43
- - **JSON-RPC 2.0**: Standard protocol for method calls
44
- - **Server-Sent Events (SSE)**: Streaming responses
45
- - **Task-based**: Each conversation is a trackable task
46
- - **Context-aware**: Automatically links to app context
47
-
48
- ## API Reference
49
-
50
- ### `chat(messages, options?)`
51
-
52
- Stream chat responses using simplified API.
53
-
54
- **Parameters:**
55
- - `messages`: Array of chat messages
56
- - `options`: Optional configuration
57
- - `taskId`: Continue an existing task (optional)
58
-
59
- **Returns:** `AsyncGenerator<ChatChunk>`
60
-
61
- ```typescript
62
- const messages = [
63
- { role: "system", content: "You are a helpful assistant" },
64
- { role: "user", content: "What is TypeScript?" },
65
- ];
66
-
67
- for await (const chunk of copilot.chat(messages)) {
68
- process.stdout.write(chunk.text); // Stream output
69
-
70
- // chunk.status: Current state (RUNNING, SUCCEEDED, FAILED, CANCELLED)
71
- // chunk.isFinal: true when chat is complete
72
- }
73
- ```
74
-
75
- ### Types
76
-
77
- ```typescript
78
- interface ChatMessage {
79
- role: "system" | "user" | "assistant";
80
- content: string;
81
- }
82
-
83
- interface ChatChunk {
84
- taskId: string; // Unique task identifier
85
- text: string; // Chunk of response text
86
- status: TaskState; // RUNNING | SUCCEEDED | FAILED | CANCELLED
87
- isFinal: boolean | undefined; // Whether this is the final chunk
88
- }
89
-
90
- interface ChatOptions {
91
- taskId?: string; // Optional: provide your own task ID to resume
92
- }
93
-
94
- type TaskState = "RUNNING" | "SUCCEEDED" | "FAILED" | "CANCELLED";
95
- ```
96
-
97
- ### `cancelChat(taskId)`
98
-
99
- Cancel an ongoing chat task.
100
-
101
- ```typescript
102
- const taskId = "task-123";
103
- const result = await copilot.cancelChat(taskId);
104
-
105
- if (result.data) {
106
- console.log("Chat cancelled successfully");
107
- }
108
- ```
109
-
110
- ### `getChatStatus(taskId)`
111
-
112
- Get current status of a chat task.
113
-
114
- ```typescript
115
- const result = await copilot.getChatStatus("task-123");
116
-
117
- if (result.data) {
118
- console.log("Task status:", result.data.result.status.state);
119
- }
120
- ```
121
-
122
- ## Usage Examples
123
-
124
- ### Multi-turn Conversation
125
-
126
- ```typescript
127
- const messages: ChatMessage[] = [];
128
-
129
- // First message
130
- messages.push({ role: "user", content: "What is React?" });
131
-
132
- let response = "";
133
- for await (const chunk of copilot.chat(messages)) {
134
- response += chunk.text;
135
- }
136
-
137
- messages.push({ role: "assistant", content: response });
138
-
139
- // Follow-up message
140
- messages.push({ role: "user", content: "Can you give me an example?" });
141
-
142
- response = "";
143
- for await (const chunk of copilot.chat(messages)) {
144
- response += chunk.text;
145
- }
146
- ```
147
-
148
- ### With System Prompt
149
-
150
- ```typescript
151
- const messages = [
152
- {
153
- role: "system",
154
- content: "You are a coding assistant specialized in TypeScript."
155
- },
156
- {
157
- role: "user",
158
- content: "How do I define an interface?"
159
- },
160
- ];
161
-
162
- for await (const chunk of copilot.chat(messages)) {
163
- console.log(chunk.text);
164
- }
165
- ```
166
-
167
- ### Resume Existing Task
168
-
169
- ```typescript
170
- // Start a chat
171
- let taskId: string;
172
- for await (const chunk of copilot.chat([
173
- { role: "user", content: "Tell me a long story" }
174
- ])) {
175
- taskId = chunk.taskId;
176
- console.log(chunk.text);
177
- }
178
-
179
- // Later, continue the same task
180
- for await (const chunk of copilot.chat([
181
- { role: "user", content: "What happened next?" }
182
- ], { taskId })) {
183
- console.log(chunk.text);
184
- }
185
- ```
186
-
187
- ### Cancel Long-running Chat
188
-
189
- ```typescript
190
- let taskId: string;
191
-
192
- const chatPromise = (async () => {
193
- for await (const chunk of copilot.chat(
194
- [{ role: "user", content: "Write a long essay" }]
195
- )) {
196
- taskId = chunk.taskId;
197
- console.log(chunk.text);
198
- }
199
- })();
200
-
201
- // Cancel after 5 seconds
202
- setTimeout(async () => {
203
- if (taskId) {
204
- await copilot.cancelChat(taskId);
205
- console.log("Chat cancelled");
206
- }
207
- }, 5000);
208
- ```
209
-
210
- ### React Integration
211
-
212
- ```typescript
213
- import { useState } from "react";
214
- import { createCopilotClient } from "@amaster.ai/copilot-client";
215
-
216
- const copilot = createCopilotClient();
217
-
218
- function ChatComponent() {
219
- const [message, setMessage] = useState("");
220
- const [response, setResponse] = useState("");
221
- const [isLoading, setIsLoading] = useState(false);
222
- const [taskId, setTaskId] = useState<string>();
223
-
224
- const handleSend = async () => {
225
- setIsLoading(true);
226
- setResponse("");
227
-
228
- try {
229
- for await (const chunk of copilot.chat([
230
- { role: "user", content: message }
231
- ])) {
232
- setTaskId(chunk.taskId);
233
- setResponse(prev => prev + chunk.text);
234
- }
235
- } finally {
236
- setIsLoading(false);
237
- }
238
- };
239
-
240
- const handleCancel = async () => {
241
- if (taskId) {
242
- await copilot.cancelChat(taskId);
243
- setIsLoading(false);
244
- }
245
- };
246
-
247
- return (
248
- <div>
249
- <input
250
- value={message}
251
- onChange={e => setMessage(e.target.value)}
252
- disabled={isLoading}
253
- />
254
- <button onClick={handleSend} disabled={isLoading}>
255
- Send
256
- </button>
257
- {isLoading && (
258
- <button onClick={handleCancel}>Cancel</button>
259
- )}
260
- <div>{response}</div>
261
- </div>
262
- );
263
- }
264
- ```
265
-
266
- ## Custom HTTP Client
267
-
268
- You can provide your own pre-configured HTTP client:
269
-
270
- ```typescript
271
- import { createHttpClient } from "@amaster.ai/http-client";
272
- import axios from "axios";
273
-
274
- // Configure axios instance
275
- const axiosInstance = axios.create({
276
- baseURL: "https://api.example.com",
277
- timeout: 30000,
278
- headers: {
279
- "X-Custom-Header": "value"
280
- }
281
- });
282
-
283
- // Create HTTP client with custom axios
284
- const httpClient = createHttpClient(axiosInstance);
285
-
286
- // Create copilot client with custom HTTP client
287
- const copilot = createCopilotClient(httpClient);
288
- ```
289
-
290
- ## Error Handling
291
-
292
- ```typescript
293
- try {
294
- for await (const chunk of copilot.chat([
295
- { role: "user", content: "Hello" }
296
- ])) {
297
- console.log(chunk.text);
298
-
299
- // Check for errors in status
300
- if (chunk.status === "FAILED" && chunk.isFinal) {
301
- console.error("Chat failed");
302
- break;
303
- }
304
- }
305
- } catch (error) {
306
- console.error("Chat error:", error);
307
- }
308
- ```
309
-
310
- ## How It Works
311
-
312
- ### A2A Protocol
313
-
314
- The client implements the A2A (Agent-to-Agent) protocol using JSON-RPC 2.0:
315
-
316
- 1. **Message Streaming**: `method: "message/stream"` - Send message and receive streaming response
317
- 2. **Task Cancellation**: `method: "tasks/cancel"` - Cancel an ongoing task
318
- 3. **Task Status**: `method: "tasks/get"` - Get task status
319
- 4. **Task Resubscription**: Reconnect to an existing task stream
320
-
321
- ### Auto Context Extraction
322
-
323
- The client automatically extracts `contextId` from:
324
- 1. URL path: `/app/{app_id}/...`
325
- 2. Domain subdomain: `{app_id}-{env}.amaster.local`
326
-
327
- This links conversations to the current app context.
328
-
329
- ### SSE Streaming
330
-
331
- Uses `eventsource-parser` for robust SSE parsing:
332
- - Handles reconnections
333
- - Parses JSON payloads
334
- - Manages stream lifecycle
335
-
336
- ## License
337
-
338
- MIT
package/dist/index.cjs CHANGED
@@ -1,237 +1,2 @@
1
- 'use strict';
2
-
3
- var sdk = require('@a2a-js/sdk');
4
- var eventsourceParser = require('eventsource-parser');
5
- var httpClient = require('@amaster.ai/http-client');
6
-
7
- // src/copilot-client.ts
8
- function generateUUID() {
9
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
10
- return crypto.randomUUID();
11
- }
12
- if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
13
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
14
- const randomValues = crypto.getRandomValues(new Uint8Array(1));
15
- const r = (randomValues[0] ?? 0) % 16;
16
- const v = c === "x" ? r : r & 3 | 8;
17
- return v.toString(16);
18
- });
19
- }
20
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
21
- const r = Math.random() * 16 | 0;
22
- const v = c === "x" ? r : r & 3 | 8;
23
- return v.toString(16);
24
- });
25
- }
26
- function extractAppIdFromUrl() {
27
- if (typeof window === "undefined") {
28
- return null;
29
- }
30
- try {
31
- const url = window.location.href;
32
- const pathMatch = /\/app\/([\da-f-]+)(?:\/|$)/.exec(url);
33
- if (pathMatch && pathMatch[1]) {
34
- return pathMatch[1];
35
- }
36
- const hostname = window.location.hostname;
37
- const domainMatch = /^([\da-f-]+)(?:-[^.]+)?\.amaster\.(?:local|ai)$/.exec(hostname);
38
- if (domainMatch && domainMatch[1]) {
39
- return domainMatch[1];
40
- }
41
- return null;
42
- } catch {
43
- return null;
44
- }
45
- }
46
- async function* streamSSEResponse(response) {
47
- if (!response.body) {
48
- return;
49
- }
50
- const reader = response.body.getReader();
51
- const decoder = new TextDecoder();
52
- const queue = [];
53
- const parser = eventsourceParser.createParser({
54
- onEvent: (event) => {
55
- try {
56
- queue.push(JSON.parse(event.data));
57
- } catch {
58
- }
59
- }
60
- });
61
- try {
62
- while (true) {
63
- const { done, value } = await reader.read();
64
- if (done) {
65
- break;
66
- }
67
- parser.feed(decoder.decode(value, { stream: true }));
68
- while (queue.length > 0) {
69
- const item = queue.shift();
70
- if (item) {
71
- yield item;
72
- }
73
- }
74
- }
75
- } finally {
76
- reader.releaseLock();
77
- }
78
- }
79
- function extractTextFromResponse(response) {
80
- if ("error" in response) {
81
- return "";
82
- }
83
- const result = response.result;
84
- if (!result) {
85
- return "";
86
- }
87
- if ("kind" in result && result.kind === "status-update") {
88
- const parts = result.status?.message?.parts;
89
- if (!parts) {
90
- return "";
91
- }
92
- return parts.filter((part) => part.kind === "text").map((part) => part.text).join("");
93
- }
94
- return "";
95
- }
96
- function parseChunk(response) {
97
- if ("error" in response) {
98
- return null;
99
- }
100
- const result = response.result;
101
- if (!result) {
102
- return null;
103
- }
104
- if ("kind" in result && result.kind === "status-update") {
105
- return {
106
- taskId: result.taskId,
107
- text: extractTextFromResponse(response),
108
- status: result.status.state,
109
- isFinal: result.final ?? false
110
- };
111
- }
112
- return null;
113
- }
114
- function createCopilotClient(http = httpClient.createHttpClient()) {
115
- const baseUrl = "/api/proxy/builtin/platform/copilot";
116
- const internal = {
117
- getAgentCard() {
118
- return http.request({
119
- url: `${baseUrl}/${sdk.AGENT_CARD_PATH}`,
120
- method: "GET"
121
- });
122
- },
123
- sendMessage(request) {
124
- return http.request({
125
- url: baseUrl,
126
- method: "POST",
127
- data: request
128
- });
129
- },
130
- async *sendMessageStream(request) {
131
- try {
132
- const response = await fetch(baseUrl, {
133
- method: "POST",
134
- headers: {
135
- "Content-Type": "application/json"
136
- },
137
- credentials: "include",
138
- body: JSON.stringify(request)
139
- });
140
- if (!response.ok) {
141
- throw new Error(`Stream request failed: ${response.statusText}`);
142
- }
143
- yield* streamSSEResponse(response);
144
- } catch {
145
- }
146
- },
147
- cancelTask(request) {
148
- return http.request({
149
- url: baseUrl,
150
- method: "POST",
151
- data: request
152
- });
153
- },
154
- getTask(request) {
155
- return http.request({
156
- url: baseUrl,
157
- method: "POST",
158
- data: request
159
- });
160
- },
161
- async *resubscribeTask(request) {
162
- try {
163
- const response = await fetch(baseUrl, {
164
- method: "POST",
165
- headers: {
166
- "Content-Type": "application/json"
167
- },
168
- credentials: "include",
169
- body: JSON.stringify(request)
170
- });
171
- if (!response.ok) {
172
- throw new Error(`Stream request failed: ${response.statusText}`);
173
- }
174
- yield* streamSSEResponse(response);
175
- } catch {
176
- }
177
- },
178
- // ============ Simplified API Implementation ============
179
- async *chat(messages, options = {}) {
180
- const { taskId } = options;
181
- const systemMsg = messages.find((m) => m.role === "system");
182
- const nonSystemMsgs = messages.filter((m) => m.role !== "system");
183
- const lastUserMsg = nonSystemMsgs[nonSystemMsgs.length - 1];
184
- const request = {
185
- jsonrpc: "2.0",
186
- id: generateUUID(),
187
- method: "message/stream",
188
- params: {
189
- message: {
190
- contextId: extractAppIdFromUrl() || generateUUID(),
191
- kind: "message",
192
- messageId: generateUUID(),
193
- role: "user",
194
- parts: [{ kind: "text", text: lastUserMsg?.content ?? "" }],
195
- ...taskId && { taskId },
196
- ...systemMsg && {
197
- metadata: { systemPrompt: systemMsg.content }
198
- }
199
- }
200
- }
201
- };
202
- for await (const response of this.sendMessageStream(request)) {
203
- const chunk = parseChunk(response);
204
- if (chunk) {
205
- yield chunk;
206
- }
207
- }
208
- },
209
- cancelChat(taskId) {
210
- const request = {
211
- jsonrpc: "2.0",
212
- id: generateUUID(),
213
- method: "tasks/cancel",
214
- params: { id: taskId }
215
- };
216
- return this.cancelTask(request);
217
- },
218
- getChatStatus(taskId) {
219
- const request = {
220
- jsonrpc: "2.0",
221
- id: generateUUID(),
222
- method: "tasks/get",
223
- params: { id: taskId }
224
- };
225
- return this.getTask(request);
226
- }
227
- };
228
- return {
229
- chat: internal.chat.bind(internal),
230
- cancelChat: internal.cancelChat.bind(internal),
231
- getChatStatus: internal.getChatStatus.bind(internal)
232
- };
233
- }
234
-
235
- exports.createCopilotClient = createCopilotClient;
236
- //# sourceMappingURL=index.cjs.map
1
+ 'use strict';var sdk=require('@a2a-js/sdk'),eventsourceParser=require('eventsource-parser'),httpClient=require('@amaster.ai/http-client');function c(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():typeof crypto<"u"&&typeof crypto.getRandomValues=="function"?"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let n=(crypto.getRandomValues(new Uint8Array(1))[0]??0)%16;return (s==="x"?n:n&3|8).toString(16)}):"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let e=Math.random()*16|0;return (s==="x"?e:e&3|8).toString(16)})}function h(){if(typeof window>"u")return null;try{let s=window.location.href,e=/\/app\/([\da-f-]+)(?:\/|$)/.exec(s);if(e&&e[1])return e[1];let n=window.location.hostname,t=/^([\da-f-]+)(?:-[^.]+)?\.amaster\.(?:local|ai)$/.exec(n);return t&&t[1]?t[1]:null}catch{return null}}async function*d(s){if(!s.body)return;let e=s.body.getReader(),n=new TextDecoder,t=[],a=eventsourceParser.createParser({onEvent:r=>{try{t.push(JSON.parse(r.data));}catch{}}});try{for(;;){let{done:r,value:u}=await e.read();if(r)break;for(a.feed(n.decode(u,{stream:!0}));t.length>0;){let o=t.shift();o&&(yield o);}}}finally{e.releaseLock();}}function f(s){if("error"in s)return "";let e=s.result;if(!e)return "";if("kind"in e&&e.kind==="status-update"){let n=e.status?.message?.parts;return n?n.filter(t=>t.kind==="text").map(t=>t.text).join(""):""}return ""}function k(s){if("error"in s)return null;let e=s.result;return e&&"kind"in e&&e.kind==="status-update"?{taskId:e.taskId,text:f(s),status:e.status.state,isFinal:e.final??false}:null}function y(s=httpClient.createHttpClient()){let e="/api/proxy/builtin/platform/copilot",n={getAgentCard(){return s.request({url:`${e}/${sdk.AGENT_CARD_PATH}`,method:"GET"})},sendMessage(t){return s.request({url:e,method:"POST",data:t})},async*sendMessageStream(t){try{let a=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(t)});if(!a.ok)throw new Error(`Stream request failed: ${a.statusText}`);yield*d(a);}catch{}},cancelTask(t){return s.request({url:e,method:"POST",data:t})},getTask(t){return s.request({url:e,method:"POST",data:t})},async*resubscribeTask(t){try{let a=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(t)});if(!a.ok)throw new Error(`Stream request failed: ${a.statusText}`);yield*d(a);}catch{}},async*chat(t,a={}){let{taskId:r}=a,u=t.find(i=>i.role==="system"),o=t.filter(i=>i.role!=="system"),p=o[o.length-1],x={jsonrpc:"2.0",id:c(),method:"message/stream",params:{message:{contextId:h()||c(),kind:"message",messageId:c(),role:"user",parts:[{kind:"text",text:p?.content??""}],...r&&{taskId:r},...u&&{metadata:{systemPrompt:u.content}}}}};for await(let i of this.sendMessageStream(x)){let l=k(i);l&&(yield l);}},cancelChat(t){let a={jsonrpc:"2.0",id:c(),method:"tasks/cancel",params:{id:t}};return this.cancelTask(a)},getChatStatus(t){let a={jsonrpc:"2.0",id:c(),method:"tasks/get",params:{id:t}};return this.getTask(a)}};return {chat:n.chat.bind(n),cancelChat:n.cancelChat.bind(n),getChatStatus:n.getChatStatus.bind(n)}}exports.createCopilotClient=y;//# sourceMappingURL=index.cjs.map
237
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/copilot-client.ts"],"names":["createParser","createHttpClient","AGENT_CARD_PATH"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n AgentCard,\n CancelTaskRequest,\n CancelTaskResponse,\n GetTaskRequest,\n GetTaskResponse,\n SendMessageRequest,\n SendMessageResponse,\n SendStreamingMessageRequest,\n SendStreamingMessageResponse,\n TaskResubscriptionRequest,\n TaskState,\n} from \"@a2a-js/sdk\";\nimport { AGENT_CARD_PATH } from \"@a2a-js/sdk\";\nimport { createParser } from \"eventsource-parser\";\nimport { type ClientResult, createHttpClient, type HttpClient } from \"@amaster.ai/http-client\";\n\n// ============ UUID Generator with fallback ============\n\n/**\n * Generate a UUID v4 with better browser compatibility\n * Falls back to crypto.getRandomValues if crypto.randomUUID is not available\n */\nfunction generateUUID(): string {\n // Try using crypto.randomUUID if available (modern browsers)\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n // Fallback: use crypto.getRandomValues (better compatibility)\n if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const randomValues = crypto.getRandomValues(new Uint8Array(1));\n const r = (randomValues[0] ?? 0) % 16;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Extract app_id from current page URL or domain\n * Method 1: From URL path - /app/{app_id}/...\n * Method 2: From domain (subdomain) - {app_id}-{env}.amaster.local\n */\nfunction extractAppIdFromUrl(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n // Method 1: Try to extract from URL path first\n const url = window.location.href;\n const pathMatch = /\\/app\\/([\\da-f-]+)(?:\\/|$)/.exec(url);\n if (pathMatch && pathMatch[1]) {\n return pathMatch[1];\n }\n\n // Method 2: Try to extract from domain (subdomain)\n const hostname = window.location.hostname;\n const domainMatch = /^([\\da-f-]+)(?:-[^.]+)?\\.amaster\\.(?:local|ai)$/.exec(hostname);\n if (domainMatch && domainMatch[1]) {\n return domainMatch[1];\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n// ============ Simplified API Types ============\n\nexport interface ChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface ChatOptions {\n taskId?: string;\n}\n\nexport interface ChatChunk {\n taskId: string;\n text: string;\n status: TaskState;\n isFinal: boolean | undefined;\n}\n\n// ============ Client Types ============\n\n// Internal client with all A2A methods\ntype InternalCopilotClient = {\n getAgentCard(): Promise<ClientResult<AgentCard>>;\n sendMessage(request: SendMessageRequest): Promise<ClientResult<SendMessageResponse>>;\n sendMessageStream(\n request: SendStreamingMessageRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n cancelTask(request: CancelTaskRequest): Promise<ClientResult<CancelTaskResponse>>;\n getTask(request: GetTaskRequest): Promise<ClientResult<GetTaskResponse>>;\n resubscribeTask(\n request: TaskResubscriptionRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\n// Public client with only simplified API\nexport type CopilotClient = {\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\nasync function* streamSSEResponse(\n response: Response\n): AsyncGenerator<SendStreamingMessageResponse, void, unknown> {\n if (!response.body) {\n return;\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n const queue: SendStreamingMessageResponse[] = [];\n\n const parser = createParser({\n onEvent: (event) => {\n try {\n queue.push(JSON.parse(event.data));\n } catch {\n // Ignore parse errors for malformed SSE data\n }\n },\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n parser.feed(decoder.decode(value, { stream: true }));\n while (queue.length > 0) {\n const item = queue.shift();\n if (item) {\n yield item;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction extractTextFromResponse(response: SendStreamingMessageResponse): string {\n if (\"error\" in response) {\n return \"\";\n }\n const result = response.result;\n if (!result) {\n return \"\";\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n const parts = result.status?.message?.parts;\n if (!parts) {\n return \"\";\n }\n return parts\n .filter((part): part is { kind: \"text\"; text: string } => part.kind === \"text\")\n .map((part) => part.text)\n .join(\"\");\n }\n return \"\";\n}\n\nfunction parseChunk(response: SendStreamingMessageResponse): ChatChunk | null {\n if (\"error\" in response) {\n return null;\n }\n const result = response.result;\n if (!result) {\n return null;\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n return {\n taskId: result.taskId,\n text: extractTextFromResponse(response),\n status: result.status.state,\n isFinal: result.final ?? false,\n };\n }\n return null;\n}\n\nexport function createCopilotClient(http: HttpClient = createHttpClient()): CopilotClient {\n const baseUrl = \"/api/proxy/builtin/platform/copilot\";\n\n const internal: InternalCopilotClient = {\n getAgentCard() {\n return http.request<AgentCard>({\n url: `${baseUrl}/${AGENT_CARD_PATH}`,\n method: \"GET\",\n });\n },\n\n sendMessage(request) {\n return http.request<SendMessageResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *sendMessageStream(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore stream errors - caller should handle connection issues\n }\n },\n\n cancelTask(request) {\n return http.request<CancelTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n getTask(request) {\n return http.request<GetTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *resubscribeTask(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore resubscribe errors - caller should handle reconnection\n }\n },\n\n // ============ Simplified API Implementation ============\n\n async *chat(messages, options = {}) {\n const { taskId } = options;\n\n const systemMsg = messages.find((m) => m.role === \"system\");\n const nonSystemMsgs = messages.filter((m) => m.role !== \"system\");\n const lastUserMsg = nonSystemMsgs[nonSystemMsgs.length - 1];\n\n const request: SendStreamingMessageRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"message/stream\",\n params: {\n message: {\n contextId: extractAppIdFromUrl() || generateUUID(),\n kind: \"message\",\n messageId: generateUUID(),\n role: \"user\",\n parts: [{ kind: \"text\", text: lastUserMsg?.content ?? \"\" }],\n ...(taskId && { taskId }),\n ...(systemMsg && {\n metadata: { systemPrompt: systemMsg.content },\n }),\n },\n },\n };\n\n for await (const response of this.sendMessageStream(request)) {\n const chunk = parseChunk(response);\n if (chunk) {\n yield chunk;\n }\n }\n },\n\n cancelChat(taskId) {\n const request: CancelTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/cancel\",\n params: { id: taskId },\n };\n return this.cancelTask(request);\n },\n\n getChatStatus(taskId) {\n const request: GetTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/get\",\n params: { id: taskId },\n };\n return this.getTask(request);\n },\n };\n\n // Return only the public API\n return {\n chat: internal.chat.bind(internal),\n cancelChat: internal.cancelChat.bind(internal),\n getChatStatus: internal.getChatStatus.bind(internal),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/copilot-client.ts"],"names":["generateUUID","c","r","extractAppIdFromUrl","url","pathMatch","hostname","domainMatch","streamSSEResponse","response","reader","decoder","queue","parser","createParser","event","done","value","item","extractTextFromResponse","result","parts","part","parseChunk","createCopilotClient","http","createHttpClient","baseUrl","internal","AGENT_CARD_PATH","request","messages","options","taskId","systemMsg","m","nonSystemMsgs","lastUserMsg","chunk"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n AgentCard,\n CancelTaskRequest,\n CancelTaskResponse,\n GetTaskRequest,\n GetTaskResponse,\n SendMessageRequest,\n SendMessageResponse,\n SendStreamingMessageRequest,\n SendStreamingMessageResponse,\n TaskResubscriptionRequest,\n TaskState,\n} from \"@a2a-js/sdk\";\nimport { AGENT_CARD_PATH } from \"@a2a-js/sdk\";\nimport { createParser } from \"eventsource-parser\";\nimport { type ClientResult, createHttpClient, type HttpClient } from \"@amaster.ai/http-client\";\n\n// ============ UUID Generator with fallback ============\n\n/**\n * Generate a UUID v4 with better browser compatibility\n * Falls back to crypto.getRandomValues if crypto.randomUUID is not available\n */\nfunction generateUUID(): string {\n // Try using crypto.randomUUID if available (modern browsers)\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n // Fallback: use crypto.getRandomValues (better compatibility)\n if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const randomValues = crypto.getRandomValues(new Uint8Array(1));\n const r = (randomValues[0] ?? 0) % 16;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Extract app_id from current page URL or domain\n * Method 1: From URL path - /app/{app_id}/...\n * Method 2: From domain (subdomain) - {app_id}-{env}.amaster.local\n */\nfunction extractAppIdFromUrl(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n // Method 1: Try to extract from URL path first\n const url = window.location.href;\n const pathMatch = /\\/app\\/([\\da-f-]+)(?:\\/|$)/.exec(url);\n if (pathMatch && pathMatch[1]) {\n return pathMatch[1];\n }\n\n // Method 2: Try to extract from domain (subdomain)\n const hostname = window.location.hostname;\n const domainMatch = /^([\\da-f-]+)(?:-[^.]+)?\\.amaster\\.(?:local|ai)$/.exec(hostname);\n if (domainMatch && domainMatch[1]) {\n return domainMatch[1];\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n// ============ Simplified API Types ============\n\nexport interface ChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface ChatOptions {\n taskId?: string;\n}\n\nexport interface ChatChunk {\n taskId: string;\n text: string;\n status: TaskState;\n isFinal: boolean | undefined;\n}\n\n// ============ Client Types ============\n\n// Internal client with all A2A methods\ntype InternalCopilotClient = {\n getAgentCard(): Promise<ClientResult<AgentCard>>;\n sendMessage(request: SendMessageRequest): Promise<ClientResult<SendMessageResponse>>;\n sendMessageStream(\n request: SendStreamingMessageRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n cancelTask(request: CancelTaskRequest): Promise<ClientResult<CancelTaskResponse>>;\n getTask(request: GetTaskRequest): Promise<ClientResult<GetTaskResponse>>;\n resubscribeTask(\n request: TaskResubscriptionRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\n// Public client with only simplified API\nexport type CopilotClient = {\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\nasync function* streamSSEResponse(\n response: Response\n): AsyncGenerator<SendStreamingMessageResponse, void, unknown> {\n if (!response.body) {\n return;\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n const queue: SendStreamingMessageResponse[] = [];\n\n const parser = createParser({\n onEvent: (event) => {\n try {\n queue.push(JSON.parse(event.data));\n } catch {\n // Ignore parse errors for malformed SSE data\n }\n },\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n parser.feed(decoder.decode(value, { stream: true }));\n while (queue.length > 0) {\n const item = queue.shift();\n if (item) {\n yield item;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction extractTextFromResponse(response: SendStreamingMessageResponse): string {\n if (\"error\" in response) {\n return \"\";\n }\n const result = response.result;\n if (!result) {\n return \"\";\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n const parts = result.status?.message?.parts;\n if (!parts) {\n return \"\";\n }\n return parts\n .filter((part): part is { kind: \"text\"; text: string } => part.kind === \"text\")\n .map((part) => part.text)\n .join(\"\");\n }\n return \"\";\n}\n\nfunction parseChunk(response: SendStreamingMessageResponse): ChatChunk | null {\n if (\"error\" in response) {\n return null;\n }\n const result = response.result;\n if (!result) {\n return null;\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n return {\n taskId: result.taskId,\n text: extractTextFromResponse(response),\n status: result.status.state,\n isFinal: result.final ?? false,\n };\n }\n return null;\n}\n\nexport function createCopilotClient(http: HttpClient = createHttpClient()): CopilotClient {\n const baseUrl = \"/api/proxy/builtin/platform/copilot\";\n\n const internal: InternalCopilotClient = {\n getAgentCard() {\n return http.request<AgentCard>({\n url: `${baseUrl}/${AGENT_CARD_PATH}`,\n method: \"GET\",\n });\n },\n\n sendMessage(request) {\n return http.request<SendMessageResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *sendMessageStream(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore stream errors - caller should handle connection issues\n }\n },\n\n cancelTask(request) {\n return http.request<CancelTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n getTask(request) {\n return http.request<GetTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *resubscribeTask(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore resubscribe errors - caller should handle reconnection\n }\n },\n\n // ============ Simplified API Implementation ============\n\n async *chat(messages, options = {}) {\n const { taskId } = options;\n\n const systemMsg = messages.find((m) => m.role === \"system\");\n const nonSystemMsgs = messages.filter((m) => m.role !== \"system\");\n const lastUserMsg = nonSystemMsgs[nonSystemMsgs.length - 1];\n\n const request: SendStreamingMessageRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"message/stream\",\n params: {\n message: {\n contextId: extractAppIdFromUrl() || generateUUID(),\n kind: \"message\",\n messageId: generateUUID(),\n role: \"user\",\n parts: [{ kind: \"text\", text: lastUserMsg?.content ?? \"\" }],\n ...(taskId && { taskId }),\n ...(systemMsg && {\n metadata: { systemPrompt: systemMsg.content },\n }),\n },\n },\n };\n\n for await (const response of this.sendMessageStream(request)) {\n const chunk = parseChunk(response);\n if (chunk) {\n yield chunk;\n }\n }\n },\n\n cancelChat(taskId) {\n const request: CancelTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/cancel\",\n params: { id: taskId },\n };\n return this.cancelTask(request);\n },\n\n getChatStatus(taskId) {\n const request: GetTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/get\",\n params: { id: taskId },\n };\n return this.getTask(request);\n },\n };\n\n // Return only the public API\n return {\n chat: internal.chat.bind(internal),\n cancelChat: internal.cancelChat.bind(internal),\n getChatStatus: internal.getChatStatus.bind(internal),\n };\n}\n"]}
package/dist/index.js CHANGED
@@ -1,235 +1,2 @@
1
- import { AGENT_CARD_PATH } from '@a2a-js/sdk';
2
- import { createParser } from 'eventsource-parser';
3
- import { createHttpClient } from '@amaster.ai/http-client';
4
-
5
- // src/copilot-client.ts
6
- function generateUUID() {
7
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
8
- return crypto.randomUUID();
9
- }
10
- if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
11
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
12
- const randomValues = crypto.getRandomValues(new Uint8Array(1));
13
- const r = (randomValues[0] ?? 0) % 16;
14
- const v = c === "x" ? r : r & 3 | 8;
15
- return v.toString(16);
16
- });
17
- }
18
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
19
- const r = Math.random() * 16 | 0;
20
- const v = c === "x" ? r : r & 3 | 8;
21
- return v.toString(16);
22
- });
23
- }
24
- function extractAppIdFromUrl() {
25
- if (typeof window === "undefined") {
26
- return null;
27
- }
28
- try {
29
- const url = window.location.href;
30
- const pathMatch = /\/app\/([\da-f-]+)(?:\/|$)/.exec(url);
31
- if (pathMatch && pathMatch[1]) {
32
- return pathMatch[1];
33
- }
34
- const hostname = window.location.hostname;
35
- const domainMatch = /^([\da-f-]+)(?:-[^.]+)?\.amaster\.(?:local|ai)$/.exec(hostname);
36
- if (domainMatch && domainMatch[1]) {
37
- return domainMatch[1];
38
- }
39
- return null;
40
- } catch {
41
- return null;
42
- }
43
- }
44
- async function* streamSSEResponse(response) {
45
- if (!response.body) {
46
- return;
47
- }
48
- const reader = response.body.getReader();
49
- const decoder = new TextDecoder();
50
- const queue = [];
51
- const parser = createParser({
52
- onEvent: (event) => {
53
- try {
54
- queue.push(JSON.parse(event.data));
55
- } catch {
56
- }
57
- }
58
- });
59
- try {
60
- while (true) {
61
- const { done, value } = await reader.read();
62
- if (done) {
63
- break;
64
- }
65
- parser.feed(decoder.decode(value, { stream: true }));
66
- while (queue.length > 0) {
67
- const item = queue.shift();
68
- if (item) {
69
- yield item;
70
- }
71
- }
72
- }
73
- } finally {
74
- reader.releaseLock();
75
- }
76
- }
77
- function extractTextFromResponse(response) {
78
- if ("error" in response) {
79
- return "";
80
- }
81
- const result = response.result;
82
- if (!result) {
83
- return "";
84
- }
85
- if ("kind" in result && result.kind === "status-update") {
86
- const parts = result.status?.message?.parts;
87
- if (!parts) {
88
- return "";
89
- }
90
- return parts.filter((part) => part.kind === "text").map((part) => part.text).join("");
91
- }
92
- return "";
93
- }
94
- function parseChunk(response) {
95
- if ("error" in response) {
96
- return null;
97
- }
98
- const result = response.result;
99
- if (!result) {
100
- return null;
101
- }
102
- if ("kind" in result && result.kind === "status-update") {
103
- return {
104
- taskId: result.taskId,
105
- text: extractTextFromResponse(response),
106
- status: result.status.state,
107
- isFinal: result.final ?? false
108
- };
109
- }
110
- return null;
111
- }
112
- function createCopilotClient(http = createHttpClient()) {
113
- const baseUrl = "/api/proxy/builtin/platform/copilot";
114
- const internal = {
115
- getAgentCard() {
116
- return http.request({
117
- url: `${baseUrl}/${AGENT_CARD_PATH}`,
118
- method: "GET"
119
- });
120
- },
121
- sendMessage(request) {
122
- return http.request({
123
- url: baseUrl,
124
- method: "POST",
125
- data: request
126
- });
127
- },
128
- async *sendMessageStream(request) {
129
- try {
130
- const response = await fetch(baseUrl, {
131
- method: "POST",
132
- headers: {
133
- "Content-Type": "application/json"
134
- },
135
- credentials: "include",
136
- body: JSON.stringify(request)
137
- });
138
- if (!response.ok) {
139
- throw new Error(`Stream request failed: ${response.statusText}`);
140
- }
141
- yield* streamSSEResponse(response);
142
- } catch {
143
- }
144
- },
145
- cancelTask(request) {
146
- return http.request({
147
- url: baseUrl,
148
- method: "POST",
149
- data: request
150
- });
151
- },
152
- getTask(request) {
153
- return http.request({
154
- url: baseUrl,
155
- method: "POST",
156
- data: request
157
- });
158
- },
159
- async *resubscribeTask(request) {
160
- try {
161
- const response = await fetch(baseUrl, {
162
- method: "POST",
163
- headers: {
164
- "Content-Type": "application/json"
165
- },
166
- credentials: "include",
167
- body: JSON.stringify(request)
168
- });
169
- if (!response.ok) {
170
- throw new Error(`Stream request failed: ${response.statusText}`);
171
- }
172
- yield* streamSSEResponse(response);
173
- } catch {
174
- }
175
- },
176
- // ============ Simplified API Implementation ============
177
- async *chat(messages, options = {}) {
178
- const { taskId } = options;
179
- const systemMsg = messages.find((m) => m.role === "system");
180
- const nonSystemMsgs = messages.filter((m) => m.role !== "system");
181
- const lastUserMsg = nonSystemMsgs[nonSystemMsgs.length - 1];
182
- const request = {
183
- jsonrpc: "2.0",
184
- id: generateUUID(),
185
- method: "message/stream",
186
- params: {
187
- message: {
188
- contextId: extractAppIdFromUrl() || generateUUID(),
189
- kind: "message",
190
- messageId: generateUUID(),
191
- role: "user",
192
- parts: [{ kind: "text", text: lastUserMsg?.content ?? "" }],
193
- ...taskId && { taskId },
194
- ...systemMsg && {
195
- metadata: { systemPrompt: systemMsg.content }
196
- }
197
- }
198
- }
199
- };
200
- for await (const response of this.sendMessageStream(request)) {
201
- const chunk = parseChunk(response);
202
- if (chunk) {
203
- yield chunk;
204
- }
205
- }
206
- },
207
- cancelChat(taskId) {
208
- const request = {
209
- jsonrpc: "2.0",
210
- id: generateUUID(),
211
- method: "tasks/cancel",
212
- params: { id: taskId }
213
- };
214
- return this.cancelTask(request);
215
- },
216
- getChatStatus(taskId) {
217
- const request = {
218
- jsonrpc: "2.0",
219
- id: generateUUID(),
220
- method: "tasks/get",
221
- params: { id: taskId }
222
- };
223
- return this.getTask(request);
224
- }
225
- };
226
- return {
227
- chat: internal.chat.bind(internal),
228
- cancelChat: internal.cancelChat.bind(internal),
229
- getChatStatus: internal.getChatStatus.bind(internal)
230
- };
231
- }
232
-
233
- export { createCopilotClient };
234
- //# sourceMappingURL=index.js.map
1
+ import {AGENT_CARD_PATH}from'@a2a-js/sdk';import {createParser}from'eventsource-parser';import {createHttpClient}from'@amaster.ai/http-client';function c(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():typeof crypto<"u"&&typeof crypto.getRandomValues=="function"?"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let n=(crypto.getRandomValues(new Uint8Array(1))[0]??0)%16;return (s==="x"?n:n&3|8).toString(16)}):"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let e=Math.random()*16|0;return (s==="x"?e:e&3|8).toString(16)})}function h(){if(typeof window>"u")return null;try{let s=window.location.href,e=/\/app\/([\da-f-]+)(?:\/|$)/.exec(s);if(e&&e[1])return e[1];let n=window.location.hostname,t=/^([\da-f-]+)(?:-[^.]+)?\.amaster\.(?:local|ai)$/.exec(n);return t&&t[1]?t[1]:null}catch{return null}}async function*d(s){if(!s.body)return;let e=s.body.getReader(),n=new TextDecoder,t=[],a=createParser({onEvent:r=>{try{t.push(JSON.parse(r.data));}catch{}}});try{for(;;){let{done:r,value:u}=await e.read();if(r)break;for(a.feed(n.decode(u,{stream:!0}));t.length>0;){let o=t.shift();o&&(yield o);}}}finally{e.releaseLock();}}function f(s){if("error"in s)return "";let e=s.result;if(!e)return "";if("kind"in e&&e.kind==="status-update"){let n=e.status?.message?.parts;return n?n.filter(t=>t.kind==="text").map(t=>t.text).join(""):""}return ""}function k(s){if("error"in s)return null;let e=s.result;return e&&"kind"in e&&e.kind==="status-update"?{taskId:e.taskId,text:f(s),status:e.status.state,isFinal:e.final??false}:null}function y(s=createHttpClient()){let e="/api/proxy/builtin/platform/copilot",n={getAgentCard(){return s.request({url:`${e}/${AGENT_CARD_PATH}`,method:"GET"})},sendMessage(t){return s.request({url:e,method:"POST",data:t})},async*sendMessageStream(t){try{let a=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(t)});if(!a.ok)throw new Error(`Stream request failed: ${a.statusText}`);yield*d(a);}catch{}},cancelTask(t){return s.request({url:e,method:"POST",data:t})},getTask(t){return s.request({url:e,method:"POST",data:t})},async*resubscribeTask(t){try{let a=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(t)});if(!a.ok)throw new Error(`Stream request failed: ${a.statusText}`);yield*d(a);}catch{}},async*chat(t,a={}){let{taskId:r}=a,u=t.find(i=>i.role==="system"),o=t.filter(i=>i.role!=="system"),p=o[o.length-1],x={jsonrpc:"2.0",id:c(),method:"message/stream",params:{message:{contextId:h()||c(),kind:"message",messageId:c(),role:"user",parts:[{kind:"text",text:p?.content??""}],...r&&{taskId:r},...u&&{metadata:{systemPrompt:u.content}}}}};for await(let i of this.sendMessageStream(x)){let l=k(i);l&&(yield l);}},cancelChat(t){let a={jsonrpc:"2.0",id:c(),method:"tasks/cancel",params:{id:t}};return this.cancelTask(a)},getChatStatus(t){let a={jsonrpc:"2.0",id:c(),method:"tasks/get",params:{id:t}};return this.getTask(a)}};return {chat:n.chat.bind(n),cancelChat:n.cancelChat.bind(n),getChatStatus:n.getChatStatus.bind(n)}}export{y as createCopilotClient};//# sourceMappingURL=index.js.map
235
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/copilot-client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n AgentCard,\n CancelTaskRequest,\n CancelTaskResponse,\n GetTaskRequest,\n GetTaskResponse,\n SendMessageRequest,\n SendMessageResponse,\n SendStreamingMessageRequest,\n SendStreamingMessageResponse,\n TaskResubscriptionRequest,\n TaskState,\n} from \"@a2a-js/sdk\";\nimport { AGENT_CARD_PATH } from \"@a2a-js/sdk\";\nimport { createParser } from \"eventsource-parser\";\nimport { type ClientResult, createHttpClient, type HttpClient } from \"@amaster.ai/http-client\";\n\n// ============ UUID Generator with fallback ============\n\n/**\n * Generate a UUID v4 with better browser compatibility\n * Falls back to crypto.getRandomValues if crypto.randomUUID is not available\n */\nfunction generateUUID(): string {\n // Try using crypto.randomUUID if available (modern browsers)\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n // Fallback: use crypto.getRandomValues (better compatibility)\n if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const randomValues = crypto.getRandomValues(new Uint8Array(1));\n const r = (randomValues[0] ?? 0) % 16;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Extract app_id from current page URL or domain\n * Method 1: From URL path - /app/{app_id}/...\n * Method 2: From domain (subdomain) - {app_id}-{env}.amaster.local\n */\nfunction extractAppIdFromUrl(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n // Method 1: Try to extract from URL path first\n const url = window.location.href;\n const pathMatch = /\\/app\\/([\\da-f-]+)(?:\\/|$)/.exec(url);\n if (pathMatch && pathMatch[1]) {\n return pathMatch[1];\n }\n\n // Method 2: Try to extract from domain (subdomain)\n const hostname = window.location.hostname;\n const domainMatch = /^([\\da-f-]+)(?:-[^.]+)?\\.amaster\\.(?:local|ai)$/.exec(hostname);\n if (domainMatch && domainMatch[1]) {\n return domainMatch[1];\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n// ============ Simplified API Types ============\n\nexport interface ChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface ChatOptions {\n taskId?: string;\n}\n\nexport interface ChatChunk {\n taskId: string;\n text: string;\n status: TaskState;\n isFinal: boolean | undefined;\n}\n\n// ============ Client Types ============\n\n// Internal client with all A2A methods\ntype InternalCopilotClient = {\n getAgentCard(): Promise<ClientResult<AgentCard>>;\n sendMessage(request: SendMessageRequest): Promise<ClientResult<SendMessageResponse>>;\n sendMessageStream(\n request: SendStreamingMessageRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n cancelTask(request: CancelTaskRequest): Promise<ClientResult<CancelTaskResponse>>;\n getTask(request: GetTaskRequest): Promise<ClientResult<GetTaskResponse>>;\n resubscribeTask(\n request: TaskResubscriptionRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\n// Public client with only simplified API\nexport type CopilotClient = {\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\nasync function* streamSSEResponse(\n response: Response\n): AsyncGenerator<SendStreamingMessageResponse, void, unknown> {\n if (!response.body) {\n return;\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n const queue: SendStreamingMessageResponse[] = [];\n\n const parser = createParser({\n onEvent: (event) => {\n try {\n queue.push(JSON.parse(event.data));\n } catch {\n // Ignore parse errors for malformed SSE data\n }\n },\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n parser.feed(decoder.decode(value, { stream: true }));\n while (queue.length > 0) {\n const item = queue.shift();\n if (item) {\n yield item;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction extractTextFromResponse(response: SendStreamingMessageResponse): string {\n if (\"error\" in response) {\n return \"\";\n }\n const result = response.result;\n if (!result) {\n return \"\";\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n const parts = result.status?.message?.parts;\n if (!parts) {\n return \"\";\n }\n return parts\n .filter((part): part is { kind: \"text\"; text: string } => part.kind === \"text\")\n .map((part) => part.text)\n .join(\"\");\n }\n return \"\";\n}\n\nfunction parseChunk(response: SendStreamingMessageResponse): ChatChunk | null {\n if (\"error\" in response) {\n return null;\n }\n const result = response.result;\n if (!result) {\n return null;\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n return {\n taskId: result.taskId,\n text: extractTextFromResponse(response),\n status: result.status.state,\n isFinal: result.final ?? false,\n };\n }\n return null;\n}\n\nexport function createCopilotClient(http: HttpClient = createHttpClient()): CopilotClient {\n const baseUrl = \"/api/proxy/builtin/platform/copilot\";\n\n const internal: InternalCopilotClient = {\n getAgentCard() {\n return http.request<AgentCard>({\n url: `${baseUrl}/${AGENT_CARD_PATH}`,\n method: \"GET\",\n });\n },\n\n sendMessage(request) {\n return http.request<SendMessageResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *sendMessageStream(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore stream errors - caller should handle connection issues\n }\n },\n\n cancelTask(request) {\n return http.request<CancelTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n getTask(request) {\n return http.request<GetTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *resubscribeTask(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore resubscribe errors - caller should handle reconnection\n }\n },\n\n // ============ Simplified API Implementation ============\n\n async *chat(messages, options = {}) {\n const { taskId } = options;\n\n const systemMsg = messages.find((m) => m.role === \"system\");\n const nonSystemMsgs = messages.filter((m) => m.role !== \"system\");\n const lastUserMsg = nonSystemMsgs[nonSystemMsgs.length - 1];\n\n const request: SendStreamingMessageRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"message/stream\",\n params: {\n message: {\n contextId: extractAppIdFromUrl() || generateUUID(),\n kind: \"message\",\n messageId: generateUUID(),\n role: \"user\",\n parts: [{ kind: \"text\", text: lastUserMsg?.content ?? \"\" }],\n ...(taskId && { taskId }),\n ...(systemMsg && {\n metadata: { systemPrompt: systemMsg.content },\n }),\n },\n },\n };\n\n for await (const response of this.sendMessageStream(request)) {\n const chunk = parseChunk(response);\n if (chunk) {\n yield chunk;\n }\n }\n },\n\n cancelChat(taskId) {\n const request: CancelTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/cancel\",\n params: { id: taskId },\n };\n return this.cancelTask(request);\n },\n\n getChatStatus(taskId) {\n const request: GetTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/get\",\n params: { id: taskId },\n };\n return this.getTask(request);\n },\n };\n\n // Return only the public API\n return {\n chat: internal.chat.bind(internal),\n cancelChat: internal.cancelChat.bind(internal),\n getChatStatus: internal.getChatStatus.bind(internal),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/copilot-client.ts"],"names":["generateUUID","c","r","extractAppIdFromUrl","url","pathMatch","hostname","domainMatch","streamSSEResponse","response","reader","decoder","queue","parser","createParser","event","done","value","item","extractTextFromResponse","result","parts","part","parseChunk","createCopilotClient","http","createHttpClient","baseUrl","internal","AGENT_CARD_PATH","request","messages","options","taskId","systemMsg","m","nonSystemMsgs","lastUserMsg","chunk"],"mappings":"+IAuBA,SAASA,CAAAA,EAAuB,CAE9B,OAAI,OAAO,OAAW,GAAA,EAAe,OAAO,MAAA,CAAO,UAAA,EAAe,WACzD,MAAA,CAAO,UAAA,EAAW,CAIvB,OAAO,OAAW,GAAA,EAAe,OAAO,MAAA,CAAO,eAAA,EAAoB,WAC9D,sCAAA,CAAuC,OAAA,CAAQ,QAAUC,CAAAA,EAAM,CAEpE,IAAMC,CAAAA,CAAAA,CADe,MAAA,CAAO,eAAA,CAAgB,IAAI,WAAW,CAAC,CAAC,CAAA,CACrC,CAAC,GAAK,CAAA,EAAK,EAAA,CAEnC,OAAA,CADUD,CAAAA,GAAM,IAAMC,CAAAA,CAAKA,CAAAA,CAAI,EAAO,CAAA,EAC7B,QAAA,CAAS,EAAE,CACtB,CAAC,CAAA,CAEI,sCAAA,CAAuC,QAAQ,OAAA,CAAUD,CAAAA,EAAM,CACpE,IAAMC,CAAAA,CAAK,KAAK,MAAA,EAAO,CAAI,EAAA,CAAM,CAAA,CAEjC,QADUD,CAAAA,GAAM,GAAA,CAAMC,EAAKA,CAAAA,CAAI,CAAA,CAAO,GAC7B,QAAA,CAAS,EAAE,CACtB,CAAC,CACH,CAOA,SAASC,CAAAA,EAAqC,CAC5C,GAAI,OAAO,MAAA,CAAW,GAAA,CACpB,OAAO,KAGT,GAAI,CAEF,IAAMC,CAAAA,CAAM,MAAA,CAAO,SAAS,IAAA,CACtBC,CAAAA,CAAY,4BAAA,CAA6B,IAAA,CAAKD,CAAG,CAAA,CACvD,GAAIC,CAAAA,EAAaA,CAAAA,CAAU,CAAC,CAAA,CAC1B,OAAOA,CAAAA,CAAU,CAAC,EAIpB,IAAMC,CAAAA,CAAW,OAAO,QAAA,CAAS,QAAA,CAC3BC,EAAc,iDAAA,CAAkD,IAAA,CAAKD,CAAQ,CAAA,CACnF,OAAIC,CAAAA,EAAeA,CAAAA,CAAY,CAAC,CAAA,CACvBA,EAAY,CAAC,CAAA,CAGf,IACT,CAAA,KAAQ,CACN,OAAO,IACT,CACF,CA8CA,eAAgBC,EACdC,CAAAA,CAC6D,CAC7D,GAAI,CAACA,EAAS,IAAA,CACZ,OAGF,IAAMC,CAAAA,CAASD,CAAAA,CAAS,KAAK,SAAA,EAAU,CACjCE,CAAAA,CAAU,IAAI,YAEdC,CAAAA,CAAwC,GAExCC,CAAAA,CAASC,YAAAA,CAAa,CAC1B,OAAA,CAAUC,CAAAA,EAAU,CAClB,GAAI,CACFH,CAAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAMG,EAAM,IAAI,CAAC,EACnC,CAAA,KAAQ,CAER,CACF,CACF,CAAC,CAAA,CAED,GAAI,CACF,OAAa,CACX,GAAM,CAAE,KAAAC,CAAAA,CAAM,KAAA,CAAAC,CAAM,CAAA,CAAI,MAAMP,CAAAA,CAAO,IAAA,EAAK,CAC1C,GAAIM,EACF,MAGF,IADAH,EAAO,IAAA,CAAKF,CAAAA,CAAQ,OAAOM,CAAAA,CAAO,CAAE,MAAA,CAAQ,CAAA,CAAK,CAAC,CAAC,CAAA,CAC5CL,CAAAA,CAAM,MAAA,CAAS,GAAG,CACvB,IAAMM,CAAAA,CAAON,CAAAA,CAAM,OAAM,CACrBM,CAAAA,GACF,MAAMA,CAAAA,EAEV,CACF,CACF,CAAA,OAAE,CACAR,CAAAA,CAAO,WAAA,GACT,CACF,CAEA,SAASS,CAAAA,CAAwBV,CAAAA,CAAgD,CAC/E,GAAI,OAAA,GAAWA,CAAAA,CACb,OAAO,GAET,IAAMW,CAAAA,CAASX,EAAS,MAAA,CACxB,GAAI,CAACW,CAAAA,CACH,OAAO,EAAA,CAIT,GAAI,SAAUA,CAAAA,EAAUA,CAAAA,CAAO,IAAA,GAAS,eAAA,CAAiB,CACvD,IAAMC,CAAAA,CAAQD,CAAAA,CAAO,MAAA,EAAQ,SAAS,KAAA,CACtC,OAAKC,EAGEA,CAAAA,CACJ,MAAA,CAAQC,GAAiDA,CAAAA,CAAK,IAAA,GAAS,MAAM,CAAA,CAC7E,IAAKA,CAAAA,EAASA,CAAAA,CAAK,IAAI,CAAA,CACvB,IAAA,CAAK,EAAE,CAAA,CALD,EAMX,CACA,OAAO,EACT,CAEA,SAASC,EAAWd,CAAAA,CAA0D,CAC5E,GAAI,OAAA,GAAWA,CAAAA,CACb,OAAO,IAAA,CAET,IAAMW,CAAAA,CAASX,CAAAA,CAAS,MAAA,CACxB,OAAKW,GAKD,MAAA,GAAUA,CAAAA,EAAUA,CAAAA,CAAO,IAAA,GAAS,gBAC/B,CACL,MAAA,CAAQA,EAAO,MAAA,CACf,IAAA,CAAMD,EAAwBV,CAAQ,CAAA,CACtC,MAAA,CAAQW,CAAAA,CAAO,OAAO,KAAA,CACtB,OAAA,CAASA,EAAO,KAAA,EAAS,KAC3B,EAVO,IAaX,CAEO,SAASI,CAAAA,CAAoBC,EAAmBC,gBAAAA,EAAiB,CAAkB,CACxF,IAAMC,CAAAA,CAAU,sCAEVC,CAAAA,CAAkC,CACtC,YAAA,EAAe,CACb,OAAOH,CAAAA,CAAK,OAAA,CAAmB,CAC7B,GAAA,CAAK,GAAGE,CAAO,CAAA,CAAA,EAAIE,eAAe,CAAA,CAAA,CAClC,OAAQ,KACV,CAAC,CACH,CAAA,CAEA,WAAA,CAAYC,EAAS,CACnB,OAAOL,CAAAA,CAAK,OAAA,CAA6B,CACvC,GAAA,CAAKE,CAAAA,CACL,MAAA,CAAQ,MAAA,CACR,KAAMG,CACR,CAAC,CACH,CAAA,CAEA,MAAO,iBAAA,CAAkBA,CAAAA,CAAS,CAChC,GAAI,CACF,IAAMrB,CAAAA,CAAW,MAAM,KAAA,CAAMkB,CAAAA,CAAS,CACpC,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CACP,eAAgB,kBAClB,CAAA,CACA,WAAA,CAAa,SAAA,CACb,KAAM,IAAA,CAAK,SAAA,CAAUG,CAAO,CAC9B,CAAC,EAED,GAAI,CAACrB,CAAAA,CAAS,EAAA,CACZ,MAAM,IAAI,KAAA,CAAM,0BAA0BA,CAAAA,CAAS,UAAU,EAAE,CAAA,CAGjE,MAAOD,CAAAA,CAAkBC,CAAQ,EACnC,CAAA,KAAQ,CAER,CACF,CAAA,CAEA,UAAA,CAAWqB,EAAS,CAClB,OAAOL,CAAAA,CAAK,OAAA,CAA4B,CACtC,GAAA,CAAKE,CAAAA,CACL,MAAA,CAAQ,MAAA,CACR,KAAMG,CACR,CAAC,CACH,CAAA,CAEA,QAAQA,CAAAA,CAAS,CACf,OAAOL,CAAAA,CAAK,OAAA,CAAyB,CACnC,GAAA,CAAKE,CAAAA,CACL,MAAA,CAAQ,MAAA,CACR,KAAMG,CACR,CAAC,CACH,CAAA,CAEA,MAAO,eAAA,CAAgBA,CAAAA,CAAS,CAC9B,GAAI,CACF,IAAMrB,CAAAA,CAAW,MAAM,KAAA,CAAMkB,CAAAA,CAAS,CACpC,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CACP,eAAgB,kBAClB,CAAA,CACA,WAAA,CAAa,SAAA,CACb,KAAM,IAAA,CAAK,SAAA,CAAUG,CAAO,CAC9B,CAAC,CAAA,CAED,GAAI,CAACrB,CAAAA,CAAS,EAAA,CACZ,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0BA,CAAAA,CAAS,UAAU,CAAA,CAAE,CAAA,CAGjE,MAAOD,CAAAA,CAAkBC,CAAQ,EACnC,CAAA,KAAQ,CAER,CACF,CAAA,CAIA,MAAO,IAAA,CAAKsB,CAAAA,CAAUC,EAAU,EAAC,CAAG,CAClC,GAAM,CAAE,MAAA,CAAAC,CAAO,EAAID,CAAAA,CAEbE,CAAAA,CAAYH,CAAAA,CAAS,IAAA,CAAMI,GAAMA,CAAAA,CAAE,IAAA,GAAS,QAAQ,CAAA,CACpDC,EAAgBL,CAAAA,CAAS,MAAA,CAAQI,GAAMA,CAAAA,CAAE,IAAA,GAAS,QAAQ,CAAA,CAC1DE,CAAAA,CAAcD,CAAAA,CAAcA,CAAAA,CAAc,OAAS,CAAC,CAAA,CAEpDN,CAAAA,CAAuC,CAC3C,QAAS,KAAA,CACT,EAAA,CAAI9B,CAAAA,EAAa,CACjB,OAAQ,gBAAA,CACR,MAAA,CAAQ,CACN,OAAA,CAAS,CACP,UAAWG,CAAAA,EAAoB,EAAKH,CAAAA,EAAa,CACjD,KAAM,SAAA,CACN,SAAA,CAAWA,CAAAA,EAAa,CACxB,KAAM,MAAA,CACN,KAAA,CAAO,CAAC,CAAE,KAAM,MAAA,CAAQ,IAAA,CAAMqC,GAAa,OAAA,EAAW,EAAG,CAAC,CAAA,CAC1D,GAAIJ,CAAAA,EAAU,CAAE,OAAAA,CAAO,CAAA,CACvB,GAAIC,CAAAA,EAAa,CACf,SAAU,CAAE,YAAA,CAAcA,CAAAA,CAAU,OAAQ,CAC9C,CACF,CACF,CACF,CAAA,CAEA,UAAA,IAAiBzB,KAAY,IAAA,CAAK,iBAAA,CAAkBqB,CAAO,CAAA,CAAG,CAC5D,IAAMQ,CAAAA,CAAQf,CAAAA,CAAWd,CAAQ,EAC7B6B,CAAAA,GACF,MAAMA,CAAAA,EAEV,CACF,EAEA,UAAA,CAAWL,CAAAA,CAAQ,CACjB,IAAMH,CAAAA,CAA6B,CACjC,OAAA,CAAS,KAAA,CACT,EAAA,CAAI9B,CAAAA,GACJ,MAAA,CAAQ,cAAA,CACR,OAAQ,CAAE,EAAA,CAAIiC,CAAO,CACvB,CAAA,CACA,OAAO,IAAA,CAAK,WAAWH,CAAO,CAChC,EAEA,aAAA,CAAcG,CAAAA,CAAQ,CACpB,IAAMH,CAAAA,CAA0B,CAC9B,OAAA,CAAS,MACT,EAAA,CAAI9B,CAAAA,EAAa,CACjB,MAAA,CAAQ,YACR,MAAA,CAAQ,CAAE,EAAA,CAAIiC,CAAO,CACvB,CAAA,CACA,OAAO,KAAK,OAAA,CAAQH,CAAO,CAC7B,CACF,CAAA,CAGA,OAAO,CACL,KAAMF,CAAAA,CAAS,IAAA,CAAK,KAAKA,CAAQ,CAAA,CACjC,WAAYA,CAAAA,CAAS,UAAA,CAAW,IAAA,CAAKA,CAAQ,EAC7C,aAAA,CAAeA,CAAAA,CAAS,cAAc,IAAA,CAAKA,CAAQ,CACrD,CACF","file":"index.js","sourcesContent":["import type {\n AgentCard,\n CancelTaskRequest,\n CancelTaskResponse,\n GetTaskRequest,\n GetTaskResponse,\n SendMessageRequest,\n SendMessageResponse,\n SendStreamingMessageRequest,\n SendStreamingMessageResponse,\n TaskResubscriptionRequest,\n TaskState,\n} from \"@a2a-js/sdk\";\nimport { AGENT_CARD_PATH } from \"@a2a-js/sdk\";\nimport { createParser } from \"eventsource-parser\";\nimport { type ClientResult, createHttpClient, type HttpClient } from \"@amaster.ai/http-client\";\n\n// ============ UUID Generator with fallback ============\n\n/**\n * Generate a UUID v4 with better browser compatibility\n * Falls back to crypto.getRandomValues if crypto.randomUUID is not available\n */\nfunction generateUUID(): string {\n // Try using crypto.randomUUID if available (modern browsers)\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n // Fallback: use crypto.getRandomValues (better compatibility)\n if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const randomValues = crypto.getRandomValues(new Uint8Array(1));\n const r = (randomValues[0] ?? 0) % 16;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Extract app_id from current page URL or domain\n * Method 1: From URL path - /app/{app_id}/...\n * Method 2: From domain (subdomain) - {app_id}-{env}.amaster.local\n */\nfunction extractAppIdFromUrl(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n // Method 1: Try to extract from URL path first\n const url = window.location.href;\n const pathMatch = /\\/app\\/([\\da-f-]+)(?:\\/|$)/.exec(url);\n if (pathMatch && pathMatch[1]) {\n return pathMatch[1];\n }\n\n // Method 2: Try to extract from domain (subdomain)\n const hostname = window.location.hostname;\n const domainMatch = /^([\\da-f-]+)(?:-[^.]+)?\\.amaster\\.(?:local|ai)$/.exec(hostname);\n if (domainMatch && domainMatch[1]) {\n return domainMatch[1];\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n// ============ Simplified API Types ============\n\nexport interface ChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface ChatOptions {\n taskId?: string;\n}\n\nexport interface ChatChunk {\n taskId: string;\n text: string;\n status: TaskState;\n isFinal: boolean | undefined;\n}\n\n// ============ Client Types ============\n\n// Internal client with all A2A methods\ntype InternalCopilotClient = {\n getAgentCard(): Promise<ClientResult<AgentCard>>;\n sendMessage(request: SendMessageRequest): Promise<ClientResult<SendMessageResponse>>;\n sendMessageStream(\n request: SendStreamingMessageRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n cancelTask(request: CancelTaskRequest): Promise<ClientResult<CancelTaskResponse>>;\n getTask(request: GetTaskRequest): Promise<ClientResult<GetTaskResponse>>;\n resubscribeTask(\n request: TaskResubscriptionRequest\n ): AsyncGenerator<SendStreamingMessageResponse, void, unknown>;\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\n// Public client with only simplified API\nexport type CopilotClient = {\n chat(messages: ChatMessage[], options?: ChatOptions): AsyncGenerator<ChatChunk, void, unknown>;\n cancelChat(taskId: string): Promise<ClientResult<CancelTaskResponse>>;\n getChatStatus(taskId: string): Promise<ClientResult<GetTaskResponse>>;\n};\n\nasync function* streamSSEResponse(\n response: Response\n): AsyncGenerator<SendStreamingMessageResponse, void, unknown> {\n if (!response.body) {\n return;\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n const queue: SendStreamingMessageResponse[] = [];\n\n const parser = createParser({\n onEvent: (event) => {\n try {\n queue.push(JSON.parse(event.data));\n } catch {\n // Ignore parse errors for malformed SSE data\n }\n },\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n parser.feed(decoder.decode(value, { stream: true }));\n while (queue.length > 0) {\n const item = queue.shift();\n if (item) {\n yield item;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction extractTextFromResponse(response: SendStreamingMessageResponse): string {\n if (\"error\" in response) {\n return \"\";\n }\n const result = response.result;\n if (!result) {\n return \"\";\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n const parts = result.status?.message?.parts;\n if (!parts) {\n return \"\";\n }\n return parts\n .filter((part): part is { kind: \"text\"; text: string } => part.kind === \"text\")\n .map((part) => part.text)\n .join(\"\");\n }\n return \"\";\n}\n\nfunction parseChunk(response: SendStreamingMessageResponse): ChatChunk | null {\n if (\"error\" in response) {\n return null;\n }\n const result = response.result;\n if (!result) {\n return null;\n }\n\n // TaskStatusUpdateEvent has kind: 'status-update'\n if (\"kind\" in result && result.kind === \"status-update\") {\n return {\n taskId: result.taskId,\n text: extractTextFromResponse(response),\n status: result.status.state,\n isFinal: result.final ?? false,\n };\n }\n return null;\n}\n\nexport function createCopilotClient(http: HttpClient = createHttpClient()): CopilotClient {\n const baseUrl = \"/api/proxy/builtin/platform/copilot\";\n\n const internal: InternalCopilotClient = {\n getAgentCard() {\n return http.request<AgentCard>({\n url: `${baseUrl}/${AGENT_CARD_PATH}`,\n method: \"GET\",\n });\n },\n\n sendMessage(request) {\n return http.request<SendMessageResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *sendMessageStream(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore stream errors - caller should handle connection issues\n }\n },\n\n cancelTask(request) {\n return http.request<CancelTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n getTask(request) {\n return http.request<GetTaskResponse>({\n url: baseUrl,\n method: \"POST\",\n data: request,\n });\n },\n\n async *resubscribeTask(request) {\n try {\n const response = await fetch(baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Stream request failed: ${response.statusText}`);\n }\n\n yield* streamSSEResponse(response);\n } catch {\n // Ignore resubscribe errors - caller should handle reconnection\n }\n },\n\n // ============ Simplified API Implementation ============\n\n async *chat(messages, options = {}) {\n const { taskId } = options;\n\n const systemMsg = messages.find((m) => m.role === \"system\");\n const nonSystemMsgs = messages.filter((m) => m.role !== \"system\");\n const lastUserMsg = nonSystemMsgs[nonSystemMsgs.length - 1];\n\n const request: SendStreamingMessageRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"message/stream\",\n params: {\n message: {\n contextId: extractAppIdFromUrl() || generateUUID(),\n kind: \"message\",\n messageId: generateUUID(),\n role: \"user\",\n parts: [{ kind: \"text\", text: lastUserMsg?.content ?? \"\" }],\n ...(taskId && { taskId }),\n ...(systemMsg && {\n metadata: { systemPrompt: systemMsg.content },\n }),\n },\n },\n };\n\n for await (const response of this.sendMessageStream(request)) {\n const chunk = parseChunk(response);\n if (chunk) {\n yield chunk;\n }\n }\n },\n\n cancelChat(taskId) {\n const request: CancelTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/cancel\",\n params: { id: taskId },\n };\n return this.cancelTask(request);\n },\n\n getChatStatus(taskId) {\n const request: GetTaskRequest = {\n jsonrpc: \"2.0\",\n id: generateUUID(),\n method: \"tasks/get\",\n params: { id: taskId },\n };\n return this.getTask(request);\n },\n };\n\n // Return only the public API\n return {\n chat: internal.chat.bind(internal),\n cancelChat: internal.cancelChat.bind(internal),\n getChatStatus: internal.getChatStatus.bind(internal),\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amaster.ai/copilot-client",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "AI copilot chat client with streaming support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -31,7 +31,7 @@
31
31
  "registry": "https://registry.npmjs.org/"
32
32
  },
33
33
  "dependencies": {
34
- "@amaster.ai/http-client": "1.0.0-beta.0"
34
+ "@amaster.ai/http-client": "1.0.0-beta.2"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@a2a-js/sdk": "^0.3.7",