@assistant-ui/react-a2a 0.2.16 → 0.2.17

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.
@@ -6,7 +6,8 @@ type A2AClientOptions = {
6
6
  basePath?: string | undefined; /** Optional tenant ID for multi-tenant servers. */
7
7
  tenant?: string | undefined;
8
8
  headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>) | undefined; /** A2A extension URIs to negotiate. Sent as A2A-Extensions header. */
9
- extensions?: string[] | undefined;
9
+ extensions?: string[] | undefined; /** Extra fetch options applied to every request. */
10
+ fetchOptions?: Omit<RequestInit, "headers" | "body" | "method" | "signal"> | undefined;
10
11
  };
11
12
  declare class A2AError extends Error {
12
13
  code: number;
@@ -19,6 +20,7 @@ declare class A2AClient {
19
20
  private basePath;
20
21
  private tenant;
21
22
  private extensionUris;
23
+ private fetchOptions;
22
24
  private headersFn;
23
25
  constructor(options: A2AClientOptions);
24
26
  private getBasePath;
@@ -1 +1 @@
1
- {"version":3,"file":"A2AClient.d.ts","names":[],"sources":["../src/A2AClient.ts"],"mappings":";;;KAgBY,gBAAA;EACV,OAAA,UADU;EAGV,QAAA;EAEA,MAAA;EACA,OAAA,GACI,MAAA,0BACO,MAAA,mBAAyB,OAAA,CAAQ,MAAA,gCAAA;EAG5C,UAAA;AAAA;AAAA,cAGW,QAAA,SAAiB,KAAK;EACjC,IAAA;EACA,MAAA;EACA,OAAA;cAEY,IAAA,EAAM,YAAA;AAAA;AAAA,cAwHP,SAAA;EAAA,QACH,OAAA;EAAA,QACA,QAAA;EAAA,QACA,MAAA;EAAA,QACA,aAAA;EAAA,QACA,SAAA;cAII,OAAA,EAAS,gBAAA;EAAA,QAUb,WAAA;EAAA,QAIM,UAAA;EAAA,QAqBA,kBAAA;EAAA,QAyBA,SAAA;EAsBR,YAAA,CAAa,MAAA,GAAS,WAAA,GAAc,OAAA,CAAQ,YAAA;EAW5C,oBAAA,CAAqB,MAAA,GAAS,WAAA,GAAc,OAAA,CAAQ,YAAA;EASpD,WAAA,CACJ,OAAA,EAAS,UAAA,EACT,aAAA,GAAgB,2BAAA,EAChB,QAAA,GAAW,MAAA,mBACX,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,OAAA,GAAU,UAAA;EAuBd,aAAA,CACL,OAAA,EAAS,UAAA,EACT,aAAA,GAAgB,2BAAA,EAChB,QAAA,GAAW,MAAA,mBACX,MAAA,GAAS,WAAA,GACR,cAAA,CAAe,cAAA;EA4BZ,OAAA,CACJ,MAAA,UACA,aAAA,WACA,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,OAAA;EAaL,SAAA,CACJ,OAAA,GAAU,mBAAA,EACV,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,oBAAA;EAoBL,UAAA,CACJ,MAAA,UACA,QAAA,GAAW,MAAA,mBACX,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,OAAA;EAYJ,eAAA,CACL,MAAA,UACA,MAAA,GAAS,WAAA,GACR,cAAA,CAAe,cAAA;EAiBZ,gCAAA,CACJ,MAAA,EAAQ,6BAAA,EACR,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,6BAAA;EAaL,6BAAA,CACJ,MAAA,UACA,QAAA,UACA,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,6BAAA;EAOL,+BAAA,CACJ,MAAA,UACA,OAAA;IAAY,QAAA;IAAmB,SAAA;EAAA,GAC/B,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,0CAAA;EAYL,gCAAA,CACJ,MAAA,UACA,QAAA,UACA,MAAA,GAAS,WAAA,GACR,OAAA;EAAA,QAcY,QAAA;AAAA"}
1
+ {"version":3,"file":"A2AClient.d.ts","names":[],"sources":["../src/A2AClient.ts"],"mappings":";;;KAgBY,gBAAA;EACV,OAAA,UADU;EAGV,QAAA;EAEA,MAAA;EACA,OAAA,GACI,MAAA,0BACO,MAAA,mBAAyB,OAAA,CAAQ,MAAA,gCAAA;EAG5C,UAAA,yBAGS;EADT,YAAA,GACI,IAAA,CAAK,WAAA;AAAA;AAAA,cAIE,QAAA,SAAiB,KAAK;EACjC,IAAA;EACA,MAAA;EACA,OAAA;cAEY,IAAA,EAAM,YAAA;AAAA;AAAA,cAuHP,SAAA;EAAA,QACH,OAAA;EAAA,QACA,QAAA;EAAA,QACA,MAAA;EAAA,QACA,aAAA;EAAA,QACA,YAAA;EAAA,QAIA,SAAA;cAII,OAAA,EAAS,gBAAA;EAAA,QAkBb,WAAA;EAAA,QAIM,UAAA;EAAA,QAqBA,kBAAA;EAAA,QAyBA,SAAA;EAuBR,YAAA,CAAa,MAAA,GAAS,WAAA,GAAc,OAAA,CAAQ,YAAA;EAe5C,oBAAA,CAAqB,MAAA,GAAS,WAAA,GAAc,OAAA,CAAQ,YAAA;EASpD,WAAA,CACJ,OAAA,EAAS,UAAA,EACT,aAAA,GAAgB,2BAAA,EAChB,QAAA,GAAW,MAAA,mBACX,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,OAAA,GAAU,UAAA;EAuBd,aAAA,CACL,OAAA,EAAS,UAAA,EACT,aAAA,GAAgB,2BAAA,EAChB,QAAA,GAAW,MAAA,mBACX,MAAA,GAAS,WAAA,GACR,cAAA,CAAe,cAAA;EA6BZ,OAAA,CACJ,MAAA,UACA,aAAA,WACA,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,OAAA;EAaL,SAAA,CACJ,OAAA,GAAU,mBAAA,EACV,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,oBAAA;EAoBL,UAAA,CACJ,MAAA,UACA,QAAA,GAAW,MAAA,mBACX,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,OAAA;EAYJ,eAAA,CACL,MAAA,UACA,MAAA,GAAS,WAAA,GACR,cAAA,CAAe,cAAA;EAqBZ,gCAAA,CACJ,MAAA,EAAQ,6BAAA,EACR,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,6BAAA;EAaL,6BAAA,CACJ,MAAA,UACA,QAAA,UACA,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,6BAAA;EAOL,+BAAA,CACJ,MAAA,UACA,OAAA;IAAY,QAAA;IAAmB,SAAA;EAAA,GAC/B,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,0CAAA;EAYL,gCAAA,CACJ,MAAA,UACA,QAAA,UACA,MAAA,GAAS,WAAA,GACR,OAAA;EAAA,QAmBY,QAAA;AAAA"}
package/dist/A2AClient.js CHANGED
@@ -51,11 +51,9 @@ function toWireTaskState(state) {
51
51
  return `TASK_STATE_${state.toUpperCase()}`;
52
52
  }
53
53
  function toWireMessage(msg) {
54
- const { parts, ...rest } = msg;
55
54
  return {
56
- ...rest,
57
- role: toWireRole(msg.role),
58
- content: parts
55
+ ...msg,
56
+ role: toWireRole(msg.role)
59
57
  };
60
58
  }
61
59
  function discriminateStreamResponse(data) {
@@ -85,12 +83,15 @@ var A2AClient = class {
85
83
  basePath;
86
84
  tenant;
87
85
  extensionUris;
86
+ fetchOptions;
88
87
  headersFn;
89
88
  constructor(options) {
90
89
  this.baseUrl = options.baseUrl.replace(/\/$/, "");
91
90
  this.basePath = options.basePath ? `/${options.basePath.replace(/^\/|\/$/g, "")}` : "";
92
91
  this.tenant = options.tenant;
93
92
  this.extensionUris = options.extensions;
93
+ const { headers: _h, body: _b, method: _m, signal: _s, ...safeFetchOptions } = options.fetchOptions ?? {};
94
+ this.fetchOptions = safeFetchOptions;
94
95
  this.headersFn = options.headers ?? {};
95
96
  }
96
97
  getBasePath() {
@@ -130,6 +131,7 @@ var A2AClient = class {
130
131
  const isGet = !options.method || options.method.toUpperCase() === "GET";
131
132
  const headers = await this.getHeaders(!isGet);
132
133
  const response = await fetch(`${this.baseUrl}${path}`, {
134
+ ...this.fetchOptions,
133
135
  ...options,
134
136
  headers: {
135
137
  ...headers,
@@ -143,6 +145,7 @@ var A2AClient = class {
143
145
  const headers = await this.getHeaders(false);
144
146
  const url = `${this.baseUrl}/.well-known/agent-card.json`;
145
147
  const response = await fetch(url, {
148
+ ...this.fetchOptions,
146
149
  headers,
147
150
  ...signalInit(signal)
148
151
  });
@@ -172,6 +175,7 @@ var A2AClient = class {
172
175
  if (configuration) body.configuration = configuration;
173
176
  if (metadata) body.metadata = metadata;
174
177
  const response = await fetch(`${this.baseUrl}${this.getBasePath()}/message:stream`, {
178
+ ...this.fetchOptions,
175
179
  method: "POST",
176
180
  headers,
177
181
  body: JSON.stringify(body),
@@ -210,6 +214,7 @@ var A2AClient = class {
210
214
  const headers = await this.getHeaders(false);
211
215
  headers.Accept = "text/event-stream";
212
216
  const response = await fetch(`${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}:subscribe`, {
217
+ ...this.fetchOptions,
213
218
  headers,
214
219
  ...signalInit(signal)
215
220
  });
@@ -238,6 +243,7 @@ var A2AClient = class {
238
243
  async deleteTaskPushNotificationConfig(taskId, configId, signal) {
239
244
  const headers = await this.getHeaders(true);
240
245
  const response = await fetch(`${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs/${encodeURIComponent(configId)}`, {
246
+ ...this.fetchOptions,
241
247
  method: "DELETE",
242
248
  headers,
243
249
  ...signalInit(signal)
@@ -1 +1 @@
1
- {"version":3,"file":"A2AClient.js","names":[],"sources":["../src/A2AClient.ts"],"sourcesContent":["import type {\n A2AAgentCard,\n A2AErrorInfo,\n A2AListTaskPushNotificationConfigsResponse,\n A2AListTasksRequest,\n A2AListTasksResponse,\n A2AMessage,\n A2ARole,\n A2ASendMessageConfiguration,\n A2AStreamEvent,\n A2ATask,\n A2ATaskPushNotificationConfig,\n A2ATaskState,\n} from \"./types\";\nimport { A2A_PROTOCOL_VERSION } from \"./types\";\n\nexport type A2AClientOptions = {\n baseUrl: string;\n /** Optional path prefix for all API endpoints (e.g. \"/v1\"). Does not affect agent card discovery. */\n basePath?: string | undefined;\n /** Optional tenant ID for multi-tenant servers. */\n tenant?: string | undefined;\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined;\n /** A2A extension URIs to negotiate. Sent as A2A-Extensions header. */\n extensions?: string[] | undefined;\n};\n\nexport class A2AError extends Error {\n code: number;\n status: string;\n details: unknown[] | undefined;\n\n constructor(info: A2AErrorInfo) {\n super(info.message);\n this.name = \"A2AError\";\n this.code = info.code;\n this.status = info.status;\n this.details = info.details;\n }\n}\n\n// Incoming key normalization: snake_case → camelCase, plus ProtoJSON enum normalization.\nfunction toCamelCase(key: string): string {\n return key.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase());\n}\n\n// Fields whose values are opaque user data (google.protobuf.Struct / Value).\n// Keys inside these objects must NOT be camelCased or have enum normalization applied.\nconst OPAQUE_FIELDS = new Set([\n \"metadata\",\n \"data\",\n \"params\",\n \"forwardedProps\",\n \"scopes\",\n]);\n\nfunction normalizeKeys(obj: unknown, opaque = false): unknown {\n if (Array.isArray(obj)) return obj.map((v) => normalizeKeys(v, opaque));\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n // Inside opaque fields: preserve keys and values as-is (only recurse arrays/objects structurally)\n if (opaque) {\n result[key] =\n typeof value === \"object\" && value !== null\n ? normalizeKeys(value, true)\n : value;\n continue;\n }\n\n const camelKey = toCamelCase(key);\n const isOpaqueChild = OPAQUE_FIELDS.has(camelKey);\n\n if (\n camelKey === \"state\" &&\n typeof value === \"string\" &&\n value.startsWith(\"TASK_STATE_\")\n ) {\n result[camelKey] = value.slice(11).toLowerCase();\n } else if (\n camelKey === \"role\" &&\n typeof value === \"string\" &&\n value.startsWith(\"ROLE_\")\n ) {\n result[camelKey] = value.slice(5).toLowerCase();\n } else if (camelKey === \"content\" && Array.isArray(value)) {\n // v1.0 proto uses \"content\" for message/artifact parts; map to internal \"parts\"\n result.parts = normalizeKeys(value, false);\n } else if (camelKey !== \"parts\" || !(\"parts\" in result)) {\n // skip \"parts\" if \"content\" already mapped it (prefer content over parts)\n result[camelKey] = isOpaqueChild ? value : normalizeKeys(value, false);\n }\n }\n return result;\n }\n return obj;\n}\n\n// Outgoing enum conversion (v1.0 ProtoJSON format)\nfunction toWireRole(role: A2ARole): string {\n if (role === \"user\") return \"ROLE_USER\";\n if (role === \"agent\") return \"ROLE_AGENT\";\n return \"ROLE_UNSPECIFIED\";\n}\n\nfunction toWireTaskState(state: A2ATaskState): string {\n return `TASK_STATE_${state.toUpperCase()}`;\n}\n\nfunction toWireMessage(msg: A2AMessage): unknown {\n const { parts, ...rest } = msg;\n return { ...rest, role: toWireRole(msg.role), content: parts };\n}\n\nfunction discriminateStreamResponse(\n data: Record<string, unknown>,\n): A2AStreamEvent | null {\n if (\"task\" in data && data.task) {\n return { type: \"task\", task: data.task as A2ATask };\n }\n if (\"message\" in data && data.message) {\n return { type: \"message\", message: data.message as A2AMessage };\n }\n if (\"statusUpdate\" in data && data.statusUpdate) {\n return {\n type: \"statusUpdate\",\n event: data.statusUpdate as A2AStreamEvent extends {\n type: \"statusUpdate\";\n event: infer E;\n }\n ? E\n : never,\n };\n }\n if (\"artifactUpdate\" in data && data.artifactUpdate) {\n return {\n type: \"artifactUpdate\",\n event: data.artifactUpdate as A2AStreamEvent extends {\n type: \"artifactUpdate\";\n event: infer E;\n }\n ? E\n : never,\n };\n }\n return null;\n}\n\nfunction signalInit(signal?: AbortSignal): RequestInit {\n return signal ? { signal } : {};\n}\n\nexport class A2AClient {\n private baseUrl: string;\n private basePath: string;\n private tenant: string | undefined;\n private extensionUris: string[] | undefined;\n private headersFn:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n\n constructor(options: A2AClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.basePath = options.basePath\n ? `/${options.basePath.replace(/^\\/|\\/$/g, \"\")}`\n : \"\";\n this.tenant = options.tenant;\n this.extensionUris = options.extensions;\n this.headersFn = options.headers ?? {};\n }\n\n private getBasePath(): string {\n return `${this.basePath}${this.tenant ? `/${encodeURIComponent(this.tenant)}` : \"\"}`;\n }\n\n private async getHeaders(\n includeContentType = true,\n ): Promise<Record<string, string>> {\n const custom =\n typeof this.headersFn === \"function\"\n ? await this.headersFn()\n : this.headersFn;\n const headers: Record<string, string> = {\n Accept: \"application/a2a+json, application/json\",\n \"A2A-Version\": A2A_PROTOCOL_VERSION,\n ...custom,\n };\n if (includeContentType) {\n headers[\"Content-Type\"] = \"application/a2a+json\";\n }\n if (this.extensionUris?.length) {\n headers[\"A2A-Extensions\"] = this.extensionUris.join(\", \");\n }\n return headers;\n }\n\n private async throwResponseError(response: Response): Promise<never> {\n let errorBody: unknown;\n try {\n errorBody = await response.json();\n } catch {\n // no parseable body\n }\n\n if (errorBody && typeof errorBody === \"object\" && \"error\" in errorBody) {\n const err = (errorBody as Record<string, any>).error;\n throw new A2AError({\n code: err.code ?? response.status,\n status: err.status ?? response.statusText,\n message: err.message ?? `A2A request failed: ${response.status}`,\n details: err.details,\n });\n }\n\n throw new A2AError({\n code: response.status,\n status: response.statusText,\n message: `A2A request failed: ${response.status} ${response.statusText}`,\n });\n }\n\n private async fetchJSON<T>(\n path: string,\n options: RequestInit = {},\n ): Promise<T> {\n const isGet = !options.method || options.method.toUpperCase() === \"GET\";\n const headers = await this.getHeaders(!isGet);\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...options,\n headers: {\n ...headers,\n ...(options.headers as Record<string, string>),\n },\n });\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n const json = await response.json();\n return normalizeKeys(json) as T;\n }\n\n // --- Agent Card ---\n\n async getAgentCard(signal?: AbortSignal): Promise<A2AAgentCard> {\n const headers = await this.getHeaders(false); // GET: no Content-Type\n const url = `${this.baseUrl}/.well-known/agent-card.json`;\n const response = await fetch(url, { headers, ...signalInit(signal) });\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n const json = await response.json();\n return normalizeKeys(json) as A2AAgentCard;\n }\n\n async getExtendedAgentCard(signal?: AbortSignal): Promise<A2AAgentCard> {\n return this.fetchJSON<A2AAgentCard>(\n `${this.getBasePath()}/extendedAgentCard`,\n signalInit(signal),\n );\n }\n\n // --- Message ---\n\n async sendMessage(\n message: A2AMessage,\n configuration?: A2ASendMessageConfiguration,\n metadata?: Record<string, unknown>,\n signal?: AbortSignal,\n ): Promise<A2ATask | A2AMessage> {\n const body: Record<string, unknown> = {\n message: toWireMessage(message),\n };\n if (configuration) body.configuration = configuration;\n if (metadata) body.metadata = metadata;\n\n const result = await this.fetchJSON<Record<string, unknown>>(\n `${this.getBasePath()}/message:send`,\n {\n method: \"POST\",\n body: JSON.stringify(body),\n ...signalInit(signal),\n },\n );\n\n // Unwrap SendMessageResponse: {task: Task} | {message: Message}\n if (\"task\" in result && result.task) return result.task as A2ATask;\n if (\"message\" in result && result.message)\n return result.message as A2AMessage;\n return result as unknown as A2ATask | A2AMessage;\n }\n\n async *streamMessage(\n message: A2AMessage,\n configuration?: A2ASendMessageConfiguration,\n metadata?: Record<string, unknown>,\n signal?: AbortSignal,\n ): AsyncGenerator<A2AStreamEvent> {\n const headers = await this.getHeaders(true);\n headers.Accept = \"text/event-stream\";\n\n const body: Record<string, unknown> = {\n message: toWireMessage(message),\n };\n if (configuration) body.configuration = configuration;\n if (metadata) body.metadata = metadata;\n\n const response = await fetch(\n `${this.baseUrl}${this.getBasePath()}/message:stream`,\n {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n ...signalInit(signal),\n },\n );\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n\n yield* this.parseSSE(response);\n }\n\n // --- Tasks ---\n\n async getTask(\n taskId: string,\n historyLength?: number,\n signal?: AbortSignal,\n ): Promise<A2ATask> {\n const params = new URLSearchParams();\n if (historyLength !== undefined) {\n // Proto field name for HTTP transcoding query params\n params.set(\"history_length\", String(historyLength));\n }\n const qs = params.toString();\n return this.fetchJSON<A2ATask>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}${qs ? `?${qs}` : \"\"}`,\n signalInit(signal),\n );\n }\n\n async listTasks(\n request?: A2AListTasksRequest,\n signal?: AbortSignal,\n ): Promise<A2AListTasksResponse> {\n const params = new URLSearchParams();\n if (request?.contextId) params.set(\"context_id\", request.contextId);\n if (request?.status) params.set(\"status\", toWireTaskState(request.status));\n if (request?.pageSize !== undefined)\n params.set(\"page_size\", String(request.pageSize));\n if (request?.pageToken) params.set(\"page_token\", request.pageToken);\n if (request?.historyLength !== undefined)\n params.set(\"history_length\", String(request.historyLength));\n if (request?.statusTimestampAfter)\n params.set(\"status_timestamp_after\", request.statusTimestampAfter);\n if (request?.includeArtifacts !== undefined)\n params.set(\"include_artifacts\", String(request.includeArtifacts));\n const qs = params.toString();\n return this.fetchJSON<A2AListTasksResponse>(\n `${this.getBasePath()}/tasks${qs ? `?${qs}` : \"\"}`,\n signalInit(signal),\n );\n }\n\n async cancelTask(\n taskId: string,\n metadata?: Record<string, unknown>,\n signal?: AbortSignal,\n ): Promise<A2ATask> {\n const body = metadata ? { metadata } : {};\n return this.fetchJSON<A2ATask>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}:cancel`,\n {\n method: \"POST\",\n body: JSON.stringify(body),\n ...signalInit(signal),\n },\n );\n }\n\n async *subscribeToTask(\n taskId: string,\n signal?: AbortSignal,\n ): AsyncGenerator<A2AStreamEvent> {\n const headers = await this.getHeaders(false); // GET: no Content-Type\n headers.Accept = \"text/event-stream\";\n\n const response = await fetch(\n `${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}:subscribe`,\n { headers, ...signalInit(signal) },\n );\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n\n yield* this.parseSSE(response);\n }\n\n // --- Push Notification Configs ---\n\n async createTaskPushNotificationConfig(\n config: A2ATaskPushNotificationConfig,\n signal?: AbortSignal,\n ): Promise<A2ATaskPushNotificationConfig> {\n const taskId = config.taskId;\n if (!taskId) throw new Error(\"taskId is required\");\n return this.fetchJSON<A2ATaskPushNotificationConfig>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs`,\n {\n method: \"POST\",\n body: JSON.stringify(config),\n ...signalInit(signal),\n },\n );\n }\n\n async getTaskPushNotificationConfig(\n taskId: string,\n configId: string,\n signal?: AbortSignal,\n ): Promise<A2ATaskPushNotificationConfig> {\n return this.fetchJSON<A2ATaskPushNotificationConfig>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs/${encodeURIComponent(configId)}`,\n signalInit(signal),\n );\n }\n\n async listTaskPushNotificationConfigs(\n taskId: string,\n options?: { pageSize?: number; pageToken?: string },\n signal?: AbortSignal,\n ): Promise<A2AListTaskPushNotificationConfigsResponse> {\n const params = new URLSearchParams();\n if (options?.pageSize !== undefined)\n params.set(\"page_size\", String(options.pageSize));\n if (options?.pageToken) params.set(\"page_token\", options.pageToken);\n const qs = params.toString();\n return this.fetchJSON<A2AListTaskPushNotificationConfigsResponse>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs${qs ? `?${qs}` : \"\"}`,\n signalInit(signal),\n );\n }\n\n async deleteTaskPushNotificationConfig(\n taskId: string,\n configId: string,\n signal?: AbortSignal,\n ): Promise<void> {\n const isGet = false;\n const headers = await this.getHeaders(!isGet);\n const response = await fetch(\n `${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs/${encodeURIComponent(configId)}`,\n { method: \"DELETE\", headers, ...signalInit(signal) },\n );\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n }\n\n // --- SSE Parsing ---\n\n private async *parseSSE(response: Response): AsyncGenerator<A2AStreamEvent> {\n const reader = response.body?.getReader();\n if (!reader) throw new Error(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n let eventEnd: number = buffer.indexOf(\"\\n\\n\");\n while (eventEnd !== -1) {\n const eventText = buffer.slice(0, eventEnd);\n buffer = buffer.slice(eventEnd + 2);\n\n const dataLines: string[] = [];\n\n for (const line of eventText.split(\"\\n\")) {\n const trimmed = line.replace(/\\r$/, \"\");\n if (trimmed.startsWith(\"data:\")) {\n dataLines.push(trimmed.slice(5).trim());\n }\n // event:, id:, retry: lines are parsed but not used —\n // we discriminate event type from the JSON payload.\n }\n\n if (dataLines.length === 0) continue;\n\n try {\n let parsed = JSON.parse(dataLines.join(\"\\n\"));\n\n // Unwrap JSON-RPC envelope if present\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"jsonrpc\" in parsed &&\n \"result\" in parsed\n ) {\n parsed = parsed.result;\n }\n\n const normalized = normalizeKeys(parsed) as Record<string, unknown>;\n const event = discriminateStreamResponse(normalized);\n if (event) yield event;\n } catch {\n // Skip malformed events\n }\n eventEnd = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"A2AClient.js","names":[],"sources":["../src/A2AClient.ts"],"sourcesContent":["import type {\n A2AAgentCard,\n A2AErrorInfo,\n A2AListTaskPushNotificationConfigsResponse,\n A2AListTasksRequest,\n A2AListTasksResponse,\n A2AMessage,\n A2ARole,\n A2ASendMessageConfiguration,\n A2AStreamEvent,\n A2ATask,\n A2ATaskPushNotificationConfig,\n A2ATaskState,\n} from \"./types\";\nimport { A2A_PROTOCOL_VERSION } from \"./types\";\n\nexport type A2AClientOptions = {\n baseUrl: string;\n /** Optional path prefix for all API endpoints (e.g. \"/v1\"). Does not affect agent card discovery. */\n basePath?: string | undefined;\n /** Optional tenant ID for multi-tenant servers. */\n tenant?: string | undefined;\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined;\n /** A2A extension URIs to negotiate. Sent as A2A-Extensions header. */\n extensions?: string[] | undefined;\n /** Extra fetch options applied to every request. */\n fetchOptions?:\n | Omit<RequestInit, \"headers\" | \"body\" | \"method\" | \"signal\">\n | undefined;\n};\n\nexport class A2AError extends Error {\n code: number;\n status: string;\n details: unknown[] | undefined;\n\n constructor(info: A2AErrorInfo) {\n super(info.message);\n this.name = \"A2AError\";\n this.code = info.code;\n this.status = info.status;\n this.details = info.details;\n }\n}\n\n// Incoming key normalization: snake_case → camelCase, plus ProtoJSON enum normalization.\nfunction toCamelCase(key: string): string {\n return key.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase());\n}\n\n// Fields whose values are opaque user data (google.protobuf.Struct / Value).\n// Keys inside these objects must NOT be camelCased or have enum normalization applied.\nconst OPAQUE_FIELDS = new Set([\n \"metadata\",\n \"data\",\n \"params\",\n \"forwardedProps\",\n \"scopes\",\n]);\n\nfunction normalizeKeys(obj: unknown, opaque = false): unknown {\n if (Array.isArray(obj)) return obj.map((v) => normalizeKeys(v, opaque));\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n // Inside opaque fields: preserve keys and values as-is (only recurse arrays/objects structurally)\n if (opaque) {\n result[key] =\n typeof value === \"object\" && value !== null\n ? normalizeKeys(value, true)\n : value;\n continue;\n }\n\n const camelKey = toCamelCase(key);\n const isOpaqueChild = OPAQUE_FIELDS.has(camelKey);\n\n if (\n camelKey === \"state\" &&\n typeof value === \"string\" &&\n value.startsWith(\"TASK_STATE_\")\n ) {\n result[camelKey] = value.slice(11).toLowerCase();\n } else if (\n camelKey === \"role\" &&\n typeof value === \"string\" &&\n value.startsWith(\"ROLE_\")\n ) {\n result[camelKey] = value.slice(5).toLowerCase();\n } else if (camelKey === \"content\" && Array.isArray(value)) {\n // v0.3 servers used \"content\" for message/artifact parts; normalize to \"parts\" for backward compat\n result.parts = normalizeKeys(value, false);\n } else if (camelKey !== \"parts\" || !(\"parts\" in result)) {\n // dedup: \"content\" was already mapped to parts above; don't overwrite\n result[camelKey] = isOpaqueChild ? value : normalizeKeys(value, false);\n }\n }\n return result;\n }\n return obj;\n}\n\n// Outgoing enum conversion (v1.0 ProtoJSON format)\nfunction toWireRole(role: A2ARole): string {\n if (role === \"user\") return \"ROLE_USER\";\n if (role === \"agent\") return \"ROLE_AGENT\";\n return \"ROLE_UNSPECIFIED\";\n}\n\nfunction toWireTaskState(state: A2ATaskState): string {\n return `TASK_STATE_${state.toUpperCase()}`;\n}\n\nfunction toWireMessage(msg: A2AMessage): unknown {\n return { ...msg, role: toWireRole(msg.role) };\n}\n\nfunction discriminateStreamResponse(\n data: Record<string, unknown>,\n): A2AStreamEvent | null {\n if (\"task\" in data && data.task) {\n return { type: \"task\", task: data.task as A2ATask };\n }\n if (\"message\" in data && data.message) {\n return { type: \"message\", message: data.message as A2AMessage };\n }\n if (\"statusUpdate\" in data && data.statusUpdate) {\n return {\n type: \"statusUpdate\",\n event: data.statusUpdate as A2AStreamEvent extends {\n type: \"statusUpdate\";\n event: infer E;\n }\n ? E\n : never,\n };\n }\n if (\"artifactUpdate\" in data && data.artifactUpdate) {\n return {\n type: \"artifactUpdate\",\n event: data.artifactUpdate as A2AStreamEvent extends {\n type: \"artifactUpdate\";\n event: infer E;\n }\n ? E\n : never,\n };\n }\n return null;\n}\n\nfunction signalInit(signal?: AbortSignal): RequestInit {\n return signal ? { signal } : {};\n}\n\nexport class A2AClient {\n private baseUrl: string;\n private basePath: string;\n private tenant: string | undefined;\n private extensionUris: string[] | undefined;\n private fetchOptions: Omit<\n RequestInit,\n \"headers\" | \"body\" | \"method\" | \"signal\"\n >;\n private headersFn:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n\n constructor(options: A2AClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.basePath = options.basePath\n ? `/${options.basePath.replace(/^\\/|\\/$/g, \"\")}`\n : \"\";\n this.tenant = options.tenant;\n this.extensionUris = options.extensions;\n const {\n headers: _h,\n body: _b,\n method: _m,\n signal: _s,\n ...safeFetchOptions\n } = (options.fetchOptions ?? {}) as RequestInit;\n this.fetchOptions = safeFetchOptions;\n this.headersFn = options.headers ?? {};\n }\n\n private getBasePath(): string {\n return `${this.basePath}${this.tenant ? `/${encodeURIComponent(this.tenant)}` : \"\"}`;\n }\n\n private async getHeaders(\n includeContentType = true,\n ): Promise<Record<string, string>> {\n const custom =\n typeof this.headersFn === \"function\"\n ? await this.headersFn()\n : this.headersFn;\n const headers: Record<string, string> = {\n Accept: \"application/a2a+json, application/json\",\n \"A2A-Version\": A2A_PROTOCOL_VERSION,\n ...custom,\n };\n if (includeContentType) {\n headers[\"Content-Type\"] = \"application/a2a+json\";\n }\n if (this.extensionUris?.length) {\n headers[\"A2A-Extensions\"] = this.extensionUris.join(\", \");\n }\n return headers;\n }\n\n private async throwResponseError(response: Response): Promise<never> {\n let errorBody: unknown;\n try {\n errorBody = await response.json();\n } catch {\n // no parseable body\n }\n\n if (errorBody && typeof errorBody === \"object\" && \"error\" in errorBody) {\n const err = (errorBody as Record<string, any>).error;\n throw new A2AError({\n code: err.code ?? response.status,\n status: err.status ?? response.statusText,\n message: err.message ?? `A2A request failed: ${response.status}`,\n details: err.details,\n });\n }\n\n throw new A2AError({\n code: response.status,\n status: response.statusText,\n message: `A2A request failed: ${response.status} ${response.statusText}`,\n });\n }\n\n private async fetchJSON<T>(\n path: string,\n options: RequestInit = {},\n ): Promise<T> {\n const isGet = !options.method || options.method.toUpperCase() === \"GET\";\n const headers = await this.getHeaders(!isGet);\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...this.fetchOptions,\n ...options,\n headers: {\n ...headers,\n ...(options.headers as Record<string, string>),\n },\n });\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n const json = await response.json();\n return normalizeKeys(json) as T;\n }\n\n // --- Agent Card ---\n\n async getAgentCard(signal?: AbortSignal): Promise<A2AAgentCard> {\n const headers = await this.getHeaders(false); // GET: no Content-Type\n const url = `${this.baseUrl}/.well-known/agent-card.json`;\n const response = await fetch(url, {\n ...this.fetchOptions,\n headers,\n ...signalInit(signal),\n });\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n const json = await response.json();\n return normalizeKeys(json) as A2AAgentCard;\n }\n\n async getExtendedAgentCard(signal?: AbortSignal): Promise<A2AAgentCard> {\n return this.fetchJSON<A2AAgentCard>(\n `${this.getBasePath()}/extendedAgentCard`,\n signalInit(signal),\n );\n }\n\n // --- Message ---\n\n async sendMessage(\n message: A2AMessage,\n configuration?: A2ASendMessageConfiguration,\n metadata?: Record<string, unknown>,\n signal?: AbortSignal,\n ): Promise<A2ATask | A2AMessage> {\n const body: Record<string, unknown> = {\n message: toWireMessage(message),\n };\n if (configuration) body.configuration = configuration;\n if (metadata) body.metadata = metadata;\n\n const result = await this.fetchJSON<Record<string, unknown>>(\n `${this.getBasePath()}/message:send`,\n {\n method: \"POST\",\n body: JSON.stringify(body),\n ...signalInit(signal),\n },\n );\n\n // Unwrap SendMessageResponse: {task: Task} | {message: Message}\n if (\"task\" in result && result.task) return result.task as A2ATask;\n if (\"message\" in result && result.message)\n return result.message as A2AMessage;\n return result as unknown as A2ATask | A2AMessage;\n }\n\n async *streamMessage(\n message: A2AMessage,\n configuration?: A2ASendMessageConfiguration,\n metadata?: Record<string, unknown>,\n signal?: AbortSignal,\n ): AsyncGenerator<A2AStreamEvent> {\n const headers = await this.getHeaders(true);\n headers.Accept = \"text/event-stream\";\n\n const body: Record<string, unknown> = {\n message: toWireMessage(message),\n };\n if (configuration) body.configuration = configuration;\n if (metadata) body.metadata = metadata;\n\n const response = await fetch(\n `${this.baseUrl}${this.getBasePath()}/message:stream`,\n {\n ...this.fetchOptions,\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n ...signalInit(signal),\n },\n );\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n\n yield* this.parseSSE(response);\n }\n\n // --- Tasks ---\n\n async getTask(\n taskId: string,\n historyLength?: number,\n signal?: AbortSignal,\n ): Promise<A2ATask> {\n const params = new URLSearchParams();\n if (historyLength !== undefined) {\n // Proto field name for HTTP transcoding query params\n params.set(\"history_length\", String(historyLength));\n }\n const qs = params.toString();\n return this.fetchJSON<A2ATask>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}${qs ? `?${qs}` : \"\"}`,\n signalInit(signal),\n );\n }\n\n async listTasks(\n request?: A2AListTasksRequest,\n signal?: AbortSignal,\n ): Promise<A2AListTasksResponse> {\n const params = new URLSearchParams();\n if (request?.contextId) params.set(\"context_id\", request.contextId);\n if (request?.status) params.set(\"status\", toWireTaskState(request.status));\n if (request?.pageSize !== undefined)\n params.set(\"page_size\", String(request.pageSize));\n if (request?.pageToken) params.set(\"page_token\", request.pageToken);\n if (request?.historyLength !== undefined)\n params.set(\"history_length\", String(request.historyLength));\n if (request?.statusTimestampAfter)\n params.set(\"status_timestamp_after\", request.statusTimestampAfter);\n if (request?.includeArtifacts !== undefined)\n params.set(\"include_artifacts\", String(request.includeArtifacts));\n const qs = params.toString();\n return this.fetchJSON<A2AListTasksResponse>(\n `${this.getBasePath()}/tasks${qs ? `?${qs}` : \"\"}`,\n signalInit(signal),\n );\n }\n\n async cancelTask(\n taskId: string,\n metadata?: Record<string, unknown>,\n signal?: AbortSignal,\n ): Promise<A2ATask> {\n const body = metadata ? { metadata } : {};\n return this.fetchJSON<A2ATask>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}:cancel`,\n {\n method: \"POST\",\n body: JSON.stringify(body),\n ...signalInit(signal),\n },\n );\n }\n\n async *subscribeToTask(\n taskId: string,\n signal?: AbortSignal,\n ): AsyncGenerator<A2AStreamEvent> {\n const headers = await this.getHeaders(false); // GET: no Content-Type\n headers.Accept = \"text/event-stream\";\n\n const response = await fetch(\n `${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}:subscribe`,\n {\n ...this.fetchOptions,\n headers,\n ...signalInit(signal),\n },\n );\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n\n yield* this.parseSSE(response);\n }\n\n // --- Push Notification Configs ---\n\n async createTaskPushNotificationConfig(\n config: A2ATaskPushNotificationConfig,\n signal?: AbortSignal,\n ): Promise<A2ATaskPushNotificationConfig> {\n const taskId = config.taskId;\n if (!taskId) throw new Error(\"taskId is required\");\n return this.fetchJSON<A2ATaskPushNotificationConfig>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs`,\n {\n method: \"POST\",\n body: JSON.stringify(config),\n ...signalInit(signal),\n },\n );\n }\n\n async getTaskPushNotificationConfig(\n taskId: string,\n configId: string,\n signal?: AbortSignal,\n ): Promise<A2ATaskPushNotificationConfig> {\n return this.fetchJSON<A2ATaskPushNotificationConfig>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs/${encodeURIComponent(configId)}`,\n signalInit(signal),\n );\n }\n\n async listTaskPushNotificationConfigs(\n taskId: string,\n options?: { pageSize?: number; pageToken?: string },\n signal?: AbortSignal,\n ): Promise<A2AListTaskPushNotificationConfigsResponse> {\n const params = new URLSearchParams();\n if (options?.pageSize !== undefined)\n params.set(\"page_size\", String(options.pageSize));\n if (options?.pageToken) params.set(\"page_token\", options.pageToken);\n const qs = params.toString();\n return this.fetchJSON<A2AListTaskPushNotificationConfigsResponse>(\n `${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs${qs ? `?${qs}` : \"\"}`,\n signalInit(signal),\n );\n }\n\n async deleteTaskPushNotificationConfig(\n taskId: string,\n configId: string,\n signal?: AbortSignal,\n ): Promise<void> {\n const isGet = false;\n const headers = await this.getHeaders(!isGet);\n const response = await fetch(\n `${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs/${encodeURIComponent(configId)}`,\n {\n ...this.fetchOptions,\n method: \"DELETE\",\n headers,\n ...signalInit(signal),\n },\n );\n if (!response.ok) {\n await this.throwResponseError(response);\n }\n }\n\n // --- SSE Parsing ---\n\n private async *parseSSE(response: Response): AsyncGenerator<A2AStreamEvent> {\n const reader = response.body?.getReader();\n if (!reader) throw new Error(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n let eventEnd: number = buffer.indexOf(\"\\n\\n\");\n while (eventEnd !== -1) {\n const eventText = buffer.slice(0, eventEnd);\n buffer = buffer.slice(eventEnd + 2);\n\n const dataLines: string[] = [];\n\n for (const line of eventText.split(\"\\n\")) {\n const trimmed = line.replace(/\\r$/, \"\");\n if (trimmed.startsWith(\"data:\")) {\n dataLines.push(trimmed.slice(5).trim());\n }\n // event:, id:, retry: lines are parsed but not used —\n // we discriminate event type from the JSON payload.\n }\n\n if (dataLines.length === 0) continue;\n\n try {\n let parsed = JSON.parse(dataLines.join(\"\\n\"));\n\n // Unwrap JSON-RPC envelope if present\n if (\n parsed &&\n typeof parsed === \"object\" &&\n \"jsonrpc\" in parsed &&\n \"result\" in parsed\n ) {\n parsed = parsed.result;\n }\n\n const normalized = normalizeKeys(parsed) as Record<string, unknown>;\n const event = discriminateStreamResponse(normalized);\n if (event) yield event;\n } catch {\n // Skip malformed events\n }\n eventEnd = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"A2AThreadRuntimeCore.d.ts","names":[],"sources":["../src/A2AThreadRuntimeCore.ts"],"mappings":";;;;;KA6BY,2BAAA;EACV,MAAA,EAAQ,SAAA;EACR,SAAA;EACA,aAAA,GAAgB,2BAAA;EAChB,OAAA,KAAY,KAAA,EAAO,KAAA;EACnB,QAAA;EACA,kBAAA,KAAuB,QAAA,EAAU,WAAA;EACjC,OAAA,GAAU,oBAAA;EACV,YAAA;AAAA;AAAA,cAQW,oBAAA;EAAA,QACH,MAAA;EAAA,QACA,SAAA;EAAA,QACA,aAAA;EAAA,QACA,OAAA;EAAA,QACA,QAAA;EAAA,QACA,kBAAA;EAAA,QACA,OAAA;EAAA,iBACS,YAAA;EAAA,QAET,OAAA;EAAA,QACA,QAAA;EAAA,QACA,aAAA;EAAA,QACA,eAAA;EAAA,QACA,YAAA;EAAA,QAGA,WAAA;EAAA,QACA,gBAAA;EAAA,QACA,cAAA;EAAA,iBAGS,uBAAA;EAAA,iBACA,kBAAA;EAAA,QACT,UAAA;EAAA,QACA,YAAA;cAEI,OAAA,EAAS,2BAAA;EAWrB,aAAA,CAAc,OAAA,EAAS,IAAA,CAAK,2BAAA;EAU5B,aAAA,CAAc,OAAA,EAAS,gBAAA;EAIvB,aAAA,CAAA;EASA,UAAA,CAAA,GAAc,gBAAA;EAId,WAAA,CAAA,YAAwB,aAAA;EAIxB,OAAA,CAAA,GAAW,OAAA;EAIX,YAAA,CAAA,YAAyB,WAAA;EAIzB,YAAA,CAAA,GAAgB,YAAA;EAIhB,SAAA,CAAA;EAAA,IAII,SAAA,CAAA;EAIJ,eAAA,CAAA,GAAmB,OAAA;EAgCb,MAAA,CAAO,OAAA,EAAS,aAAA,GAAgB,OAAA;EAsBhC,IAAA,CAAK,OAAA,EAAS,aAAA,GAAgB,OAAA;EAI9B,MAAA,CACJ,QAAA,iBACA,OAAA;IAAW,SAAA,GAAY,MAAA;EAAA,IACtB,OAAA;EAaG,MAAA,CAAA,GAAU,OAAA;EAiBhB,qBAAA,CAAsB,QAAA,WAAmB,aAAA;EAAA,QAe3B,QAAA;EAAA,QAwEA,YAAA;EAAA,QA4BA,OAAA;EAAA,QA4BN,iBAAA;EAAA,QAiBA,kBAAA;EAAA,QA6BA,oBAAA;EAAA,QAqCA,aAAA;EAAA,QAQA,kBAAA;EAAA,QAuBA,yBAAA;EAAA,QAiCA,0BAAA;EAAA,QAqBA,sBAAA;EAAA,QAWA,qBAAA;EAAA,QAgBA,kBAAA;EAAA,QASA,UAAA;EAAA,QAKA,SAAA;EAAA,QAOA,SAAA;EAAA,QAcA,kBAAA;EAAA,QAIA,2BAAA;EAAA,QAQA,uBAAA;EAAA,QAeA,iBAAA;AAAA"}
1
+ {"version":3,"file":"A2AThreadRuntimeCore.d.ts","names":[],"sources":["../src/A2AThreadRuntimeCore.ts"],"mappings":";;;;;KA6BY,2BAAA;EACV,MAAA,EAAQ,SAAA;EACR,SAAA;EACA,aAAA,GAAgB,2BAAA;EAChB,OAAA,KAAY,KAAA,EAAO,KAAA;EACnB,QAAA;EACA,kBAAA,KAAuB,QAAA,EAAU,WAAA;EACjC,OAAA,GAAU,oBAAA;EACV,YAAA;AAAA;AAAA,cAQW,oBAAA;EAAA,QACH,MAAA;EAAA,QACA,SAAA;EAAA,QACA,aAAA;EAAA,QACA,OAAA;EAAA,QACA,QAAA;EAAA,QACA,kBAAA;EAAA,QACA,OAAA;EAAA,iBACS,YAAA;EAAA,QAET,OAAA;EAAA,QACA,QAAA;EAAA,QACA,aAAA;EAAA,QACA,eAAA;EAAA,QACA,YAAA;EAAA,QAGA,WAAA;EAAA,QACA,gBAAA;EAAA,QACA,cAAA;EAAA,iBAGS,uBAAA;EAAA,iBACA,kBAAA;EAAA,QACT,UAAA;EAAA,QACA,YAAA;cAEI,OAAA,EAAS,2BAAA;EAWrB,aAAA,CAAc,OAAA,EAAS,IAAA,CAAK,2BAAA;EAU5B,aAAA,CAAc,OAAA,EAAS,gBAAA;EAIvB,aAAA;EASA,UAAA,IAAc,gBAAA;EAId,WAAA,aAAwB,aAAA;EAIxB,OAAA,IAAW,OAAA;EAIX,YAAA,aAAyB,WAAA;EAIzB,YAAA,IAAgB,YAAA;EAIhB,SAAA;EAAA,IAII,SAAA;EAIJ,eAAA,IAAmB,OAAA;EAgCb,MAAA,CAAO,OAAA,EAAS,aAAA,GAAgB,OAAA;EAsBhC,IAAA,CAAK,OAAA,EAAS,aAAA,GAAgB,OAAA;EAI9B,MAAA,CACJ,QAAA,iBACA,OAAA;IAAW,SAAA,GAAY,MAAA;EAAA,IACtB,OAAA;EAaG,MAAA,IAAU,OAAA;EAiBhB,qBAAA,CAAsB,QAAA,WAAmB,aAAA;EAAA,QAe3B,QAAA;EAAA,QAwEA,YAAA;EAAA,QA4BA,OAAA;EAAA,QA4BN,iBAAA;EAAA,QAiBA,kBAAA;EAAA,QA6BA,oBAAA;EAAA,QAqCA,aAAA;EAAA,QAQA,kBAAA;EAAA,QAuBA,yBAAA;EAAA,QAiCA,0BAAA;EAAA,QAqBA,sBAAA;EAAA,QAWA,qBAAA;EAAA,QAgBA,kBAAA;EAAA,QASA,UAAA;EAAA,QAKA,SAAA;EAAA,QAOA,SAAA;EAAA,QAcA,kBAAA;EAAA,QAIA,2BAAA;EAAA,QAQA,uBAAA;EAAA,QAeA,iBAAA;AAAA"}
@@ -1,7 +1,6 @@
1
- /// <reference types="@assistant-ui/core/store" />
2
1
  import { A2AAgentCard, A2AArtifact, A2ASendMessageConfiguration, A2ATask } from "./types.js";
3
2
  import { A2AClient, A2AClientOptions } from "./A2AClient.js";
4
- import { AssistantRuntime, AttachmentAdapter, FeedbackAdapter, SpeechSynthesisAdapter, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
3
+ import { AssistantRuntime, AttachmentAdapter, DictationAdapter, ExternalStoreSharedOptions, FeedbackAdapter, RealtimeVoiceAdapter, SpeechSynthesisAdapter, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
5
4
 
6
5
  //#region src/useA2ARuntime.d.ts
7
6
  declare const useA2ATask: () => A2ATask | undefined;
@@ -14,13 +13,14 @@ type UseA2AThreadListAdapter = {
14
13
  messages: readonly ThreadMessage[];
15
14
  }>;
16
15
  };
17
- type UseA2ARuntimeOptions = {
16
+ type UseA2ARuntimeOptions = ExternalStoreSharedOptions & {
18
17
  /** Pre-built A2A client instance. Provide this OR baseUrl. */client?: A2AClient; /** Base URL of the A2A server. Used to create a client if `client` is not provided. */
19
18
  baseUrl?: string; /** Optional path prefix for all API endpoints (e.g. "/v1"). Does not affect agent card discovery. Only used with baseUrl. */
20
19
  basePath?: string; /** Optional tenant ID for multi-tenant servers. Only used with baseUrl. */
21
20
  tenant?: string; /** Headers for the A2A client (only used with baseUrl). */
22
21
  headers?: A2AClientOptions["headers"]; /** A2A extension URIs to negotiate. Only used with baseUrl. */
23
- extensions?: string[]; /** Initial context ID for the conversation. */
22
+ extensions?: string[]; /** Extra fetch options (e.g. `{ credentials: 'include' }`). Only used with `baseUrl`. */
23
+ fetchOptions?: A2AClientOptions["fetchOptions"]; /** Initial context ID for the conversation. */
24
24
  contextId?: string; /** Default send message configuration. */
25
25
  configuration?: A2ASendMessageConfiguration; /** Called when an error occurs. */
26
26
  onError?: (error: Error) => void; /** Called when a run is cancelled. */
@@ -29,6 +29,8 @@ type UseA2ARuntimeOptions = {
29
29
  adapters?: {
30
30
  attachments?: AttachmentAdapter;
31
31
  speech?: SpeechSynthesisAdapter;
32
+ dictation?: DictationAdapter;
33
+ voice?: RealtimeVoiceAdapter;
32
34
  feedback?: FeedbackAdapter;
33
35
  history?: ThreadHistoryAdapter;
34
36
  threadList?: UseA2AThreadListAdapter;
@@ -1 +1 @@
1
- {"version":3,"file":"useA2ARuntime.d.ts","names":[],"sources":["../src/useA2ARuntime.ts"],"mappings":";;;;;cAsDa,UAAA,QAAU,OAAA;AAAA,cAIV,eAAA,iBAAe,WAAA;AAAA,cAIf,eAAA,QAAe,YAAA;AAAA,KAMhB,uBAAA;EACV,QAAA;EACA,mBAAA,SAA4B,OAAA;EAC5B,gBAAA,IAAoB,QAAA,aAAqB,OAAA;IACvC,QAAA,WAAmB,aAAA;EAAA;AAAA;AAAA,KAMX,oBAAA;EAhBC,8DAkBX,MAAA,GAAS,SAAA;EAET,OAAA,WApB0B;EAsB1B,QAAA,WAhBiC;EAkBjC,MAAA,WAhB4B;EAkB5B,OAAA,GAAU,gBAAA,aAjB+B;EAmBzC,UAAA,aAnBgD;EAsBhD,SAAA,WAvBA;EAyBA,aAAA,GAAgB,2BAAA,EAxBhB;EA2BA,OAAA,IAAW,KAAA,EAAO,KAAA,WA3BuB;EA6BzC,QAAA,eA5BqB;EA8BrB,kBAAA,IAAsB,QAAA,EAJC,WAAA;EAMvB,QAAA;IACE,WAAA,GAAc,iBAAA;IACd,MAAA,GAAS,sBAAA;IACT,QAAA,GAAW,eAAA;IACX,OAAA,GAAU,oBAAA;IACV,UAAA,GAAa,uBAAA;EAAA;AAAA;AAAA,iBAMD,aAAA,CAAc,OAAA,EAAS,oBAAA,GAAuB,gBAAgB"}
1
+ {"version":3,"file":"useA2ARuntime.d.ts","names":[],"sources":["../src/useA2ARuntime.ts"],"mappings":";;;;;cAyDa,UAAA,QAAU,OAAA;AAAA,cAIV,eAAA,iBAAe,WAAA;AAAA,cAIf,eAAA,QAAe,YAAA;AAAA,KAMhB,uBAAA;EACV,QAAA;EACA,mBAAA,SAA4B,OAAA;EAC5B,gBAAA,IAAoB,QAAA,aAAqB,OAAA;IACvC,QAAA,WAAmB,aAAA;EAAA;AAAA;AAAA,KAMX,oBAAA,GAAuB,0BAAA;EAhBtB,8DAkBX,MAAA,GAAS,SAAA;EAET,OAAA,WApB0B;EAsB1B,QAAA,WAhBiC;EAkBjC,MAAA,WAhB4B;EAkB5B,OAAA,GAAU,gBAAA,aAjB+B;EAmBzC,UAAA,aAnBgD;EAqBhD,YAAA,GAAe,gBAAA,kBAtBf;EAyBA,SAAA,WAxBA;EA0BA,aAAA,GAAgB,2BAAA,EA1ByB;EA6BzC,OAAA,IAAW,KAAA,EAAO,KAAA,WA5BG;EA8BrB,QAAA,eA9BkC;EAgClC,kBAAA,IAAsB,QAAA,EAJC,WAAA;EAMvB,QAAA;IACE,WAAA,GAAc,iBAAA;IACd,MAAA,GAAS,sBAAA;IACT,SAAA,GAAY,gBAAA;IACZ,KAAA,GAAQ,oBAAA;IACR,QAAA,GAAW,eAAA;IACX,OAAA,GAAU,oBAAA;IACV,UAAA,GAAa,uBAAA;EAAA;AAAA;AAAA,iBAMD,aAAA,CAAc,OAAA,EAAS,oBAAA,GAAuB,gBAAgB"}
@@ -2,7 +2,7 @@
2
2
  import { A2AClient } from "./A2AClient.js";
3
3
  import { A2AThreadRuntimeCore } from "./A2AThreadRuntimeCore.js";
4
4
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
- import { useExternalStoreRuntime, useRuntimeAdapters } from "@assistant-ui/core/react";
5
+ import { useExternalStoreRuntime, useExternalStoreSharedOptions, useRuntimeAdapters } from "@assistant-ui/core/react";
6
6
  import { useAuiState } from "@assistant-ui/store";
7
7
  //#region src/useA2ARuntime.ts
8
8
  const symbolA2AExtras = Symbol("a2a-extras");
@@ -32,7 +32,8 @@ function useA2ARuntime(options) {
32
32
  basePath: options.basePath,
33
33
  tenant: options.tenant,
34
34
  headers: options.headers,
35
- extensions: options.extensions
35
+ extensions: options.extensions,
36
+ fetchOptions: options.fetchOptions
36
37
  });
37
38
  else throw new Error("useA2ARuntime requires either `client` or `baseUrl`");
38
39
  const client = clientRef.current;
@@ -76,6 +77,8 @@ function useA2ARuntime(options) {
76
77
  const adapterAdapters = useMemo(() => ({
77
78
  attachments: adapters?.attachments ?? runtimeAdapters?.attachments,
78
79
  speech: adapters?.speech,
80
+ dictation: adapters?.dictation,
81
+ voice: adapters?.voice,
79
82
  feedback: adapters?.feedback,
80
83
  threadList
81
84
  }), [
@@ -83,8 +86,10 @@ function useA2ARuntime(options) {
83
86
  runtimeAdapters,
84
87
  threadList
85
88
  ]);
89
+ const shared = useExternalStoreSharedOptions(options);
86
90
  const runtime = useExternalStoreRuntime(useMemo(() => {
87
91
  return {
92
+ ...shared,
88
93
  isLoading: core.isLoading,
89
94
  messages: core.getMessages(),
90
95
  isRunning: core.isRunning(),
@@ -105,7 +110,8 @@ function useA2ARuntime(options) {
105
110
  }, [
106
111
  adapterAdapters,
107
112
  core,
108
- _version
113
+ _version,
114
+ shared
109
115
  ]));
110
116
  useEffect(() => {
111
117
  core.attachRuntime(runtime);
@@ -1 +1 @@
1
- {"version":3,"file":"useA2ARuntime.js","names":[],"sources":["../src/useA2ARuntime.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/store\" />\n\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n useExternalStoreRuntime,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport type {\n AssistantRuntime,\n AppendMessage,\n AttachmentAdapter,\n ExternalStoreAdapter,\n FeedbackAdapter,\n SpeechSynthesisAdapter,\n ThreadHistoryAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { A2AClient } from \"./A2AClient\";\nimport type { A2AClientOptions } from \"./A2AClient\";\nimport { A2AThreadRuntimeCore } from \"./A2AThreadRuntimeCore\";\nimport type {\n A2AArtifact,\n A2AAgentCard,\n A2ASendMessageConfiguration,\n A2ATask,\n} from \"./types\";\n\n// --- Extras symbol for A2A-specific state ---\n\nconst symbolA2AExtras = Symbol(\"a2a-extras\");\n\ntype A2AExtras = {\n [symbolA2AExtras]: true;\n task: A2ATask | undefined;\n artifacts: readonly A2AArtifact[];\n agentCard: A2AAgentCard | undefined;\n};\n\nconst asA2AExtras = (extras: unknown): A2AExtras => {\n if (\n typeof extras !== \"object\" ||\n extras == null ||\n !(symbolA2AExtras in extras)\n )\n throw new Error(\n \"This hook can only be used inside a useA2ARuntime provider\",\n );\n return extras as A2AExtras;\n};\n\n// --- Public hooks for A2A state ---\n\nexport const useA2ATask = () => {\n return useAuiState((s) => asA2AExtras(s.thread.extras).task);\n};\n\nexport const useA2AArtifacts = () => {\n return useAuiState((s) => asA2AExtras(s.thread.extras).artifacts);\n};\n\nexport const useA2AAgentCard = () => {\n return useAuiState((s) => asA2AExtras(s.thread.extras).agentCard);\n};\n\n// --- Thread list adapter type ---\n\nexport type UseA2AThreadListAdapter = {\n threadId?: string;\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (threadId: string) => Promise<{\n messages: readonly ThreadMessage[];\n }>;\n};\n\n// --- Options ---\n\nexport type UseA2ARuntimeOptions = {\n /** Pre-built A2A client instance. Provide this OR baseUrl. */\n client?: A2AClient;\n /** Base URL of the A2A server. Used to create a client if `client` is not provided. */\n baseUrl?: string;\n /** Optional path prefix for all API endpoints (e.g. \"/v1\"). Does not affect agent card discovery. Only used with baseUrl. */\n basePath?: string;\n /** Optional tenant ID for multi-tenant servers. Only used with baseUrl. */\n tenant?: string;\n /** Headers for the A2A client (only used with baseUrl). */\n headers?: A2AClientOptions[\"headers\"];\n /** A2A extension URIs to negotiate. Only used with baseUrl. */\n extensions?: string[];\n\n /** Initial context ID for the conversation. */\n contextId?: string;\n /** Default send message configuration. */\n configuration?: A2ASendMessageConfiguration;\n\n /** Called when an error occurs. */\n onError?: (error: Error) => void;\n /** Called when a run is cancelled. */\n onCancel?: () => void;\n /** Called when an artifact is fully received (lastChunk). */\n onArtifactComplete?: (artifact: import(\"./types\").A2AArtifact) => void;\n\n adapters?: {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n feedback?: FeedbackAdapter;\n history?: ThreadHistoryAdapter;\n threadList?: UseA2AThreadListAdapter;\n };\n};\n\n// --- Main hook ---\n\nexport function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {\n const [_version, setVersion] = useState(0);\n const notifyUpdate = useCallback(() => setVersion((v) => v + 1), []);\n const runtimeAdapters = useRuntimeAdapters();\n const historyAdapter = options.adapters?.history ?? runtimeAdapters?.history;\n const threadListAdapter = options.adapters?.threadList;\n\n // Create or reuse client\n const clientRef = useRef<A2AClient | null>(null);\n if (!clientRef.current) {\n if (options.client) {\n clientRef.current = options.client;\n } else if (options.baseUrl) {\n clientRef.current = new A2AClient({\n baseUrl: options.baseUrl,\n basePath: options.basePath,\n tenant: options.tenant,\n headers: options.headers,\n extensions: options.extensions,\n });\n } else {\n throw new Error(\"useA2ARuntime requires either `client` or `baseUrl`\");\n }\n }\n const client = clientRef.current;\n\n // Create or reuse core\n const coreRef = useRef<A2AThreadRuntimeCore | null>(null);\n if (!coreRef.current) {\n coreRef.current = new A2AThreadRuntimeCore({\n client,\n contextId: options.contextId,\n configuration: options.configuration,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(options.onArtifactComplete && {\n onArtifactComplete: options.onArtifactComplete,\n }),\n ...(historyAdapter && { history: historyAdapter }),\n notifyUpdate,\n });\n }\n\n const core = coreRef.current;\n core.updateOptions({\n client,\n contextId: options.contextId,\n configuration: options.configuration,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(options.onArtifactComplete && {\n onArtifactComplete: options.onArtifactComplete,\n }),\n ...(historyAdapter && { history: historyAdapter }),\n });\n\n // Thread list\n const threadList = useMemo(() => {\n if (!threadListAdapter) return undefined;\n\n const { onSwitchToNewThread, onSwitchToThread } = threadListAdapter;\n\n return {\n threadId: threadListAdapter.threadId,\n onSwitchToNewThread: onSwitchToNewThread\n ? async () => {\n await onSwitchToNewThread();\n core.applyExternalMessages([]);\n }\n : undefined,\n onSwitchToThread: onSwitchToThread\n ? async (threadId: string) => {\n const result = await onSwitchToThread(threadId);\n core.applyExternalMessages(result.messages);\n }\n : undefined,\n };\n }, [threadListAdapter, core]);\n\n // Adapters\n const adapters = options.adapters;\n const adapterAdapters = useMemo(\n () => ({\n attachments: adapters?.attachments ?? runtimeAdapters?.attachments,\n speech: adapters?.speech,\n feedback: adapters?.feedback,\n threadList,\n }),\n [adapters, runtimeAdapters, threadList],\n );\n\n // Build store adapter\n const store = useMemo(() => {\n void _version;\n\n return {\n isLoading: core.isLoading,\n messages: core.getMessages(),\n isRunning: core.isRunning(),\n extras: {\n [symbolA2AExtras]: true,\n task: core.getTask(),\n artifacts: core.getArtifacts(),\n agentCard: core.getAgentCard(),\n } satisfies A2AExtras,\n onNew: (message: AppendMessage) => core.append(message),\n onEdit: (message: AppendMessage) => core.edit(message),\n onReload: (parentId: string | null) => core.reload(parentId),\n onCancel: () => core.cancel(),\n setMessages: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n onImport: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n adapters: adapterAdapters,\n } satisfies ExternalStoreAdapter<ThreadMessage>;\n }, [adapterAdapters, core, _version]);\n\n const runtime = useExternalStoreRuntime(store);\n\n useEffect(() => {\n core.attachRuntime(runtime);\n return () => {\n core.detachRuntime();\n };\n }, [core, runtime]);\n\n useEffect(() => {\n core.__internal_load();\n }, [core]);\n\n return runtime;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useA2ARuntime.js","names":[],"sources":["../src/useA2ARuntime.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n useExternalStoreRuntime,\n useExternalStoreSharedOptions,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport type {\n AssistantRuntime,\n AppendMessage,\n AttachmentAdapter,\n DictationAdapter,\n ExternalStoreAdapter,\n ExternalStoreSharedOptions,\n FeedbackAdapter,\n RealtimeVoiceAdapter,\n SpeechSynthesisAdapter,\n ThreadHistoryAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { A2AClient } from \"./A2AClient\";\nimport type { A2AClientOptions } from \"./A2AClient\";\nimport { A2AThreadRuntimeCore } from \"./A2AThreadRuntimeCore\";\nimport type {\n A2AArtifact,\n A2AAgentCard,\n A2ASendMessageConfiguration,\n A2ATask,\n} from \"./types\";\n\n// --- Extras symbol for A2A-specific state ---\n\nconst symbolA2AExtras = Symbol(\"a2a-extras\");\n\ntype A2AExtras = {\n [symbolA2AExtras]: true;\n task: A2ATask | undefined;\n artifacts: readonly A2AArtifact[];\n agentCard: A2AAgentCard | undefined;\n};\n\nconst asA2AExtras = (extras: unknown): A2AExtras => {\n if (\n typeof extras !== \"object\" ||\n extras == null ||\n !(symbolA2AExtras in extras)\n )\n throw new Error(\n \"This hook can only be used inside a useA2ARuntime provider\",\n );\n return extras as A2AExtras;\n};\n\n// --- Public hooks for A2A state ---\n\nexport const useA2ATask = () => {\n return useAuiState((s) => asA2AExtras(s.thread.extras).task);\n};\n\nexport const useA2AArtifacts = () => {\n return useAuiState((s) => asA2AExtras(s.thread.extras).artifacts);\n};\n\nexport const useA2AAgentCard = () => {\n return useAuiState((s) => asA2AExtras(s.thread.extras).agentCard);\n};\n\n// --- Thread list adapter type ---\n\nexport type UseA2AThreadListAdapter = {\n threadId?: string;\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (threadId: string) => Promise<{\n messages: readonly ThreadMessage[];\n }>;\n};\n\n// --- Options ---\n\nexport type UseA2ARuntimeOptions = ExternalStoreSharedOptions & {\n /** Pre-built A2A client instance. Provide this OR baseUrl. */\n client?: A2AClient;\n /** Base URL of the A2A server. Used to create a client if `client` is not provided. */\n baseUrl?: string;\n /** Optional path prefix for all API endpoints (e.g. \"/v1\"). Does not affect agent card discovery. Only used with baseUrl. */\n basePath?: string;\n /** Optional tenant ID for multi-tenant servers. Only used with baseUrl. */\n tenant?: string;\n /** Headers for the A2A client (only used with baseUrl). */\n headers?: A2AClientOptions[\"headers\"];\n /** A2A extension URIs to negotiate. Only used with baseUrl. */\n extensions?: string[];\n /** Extra fetch options (e.g. `{ credentials: 'include' }`). Only used with `baseUrl`. */\n fetchOptions?: A2AClientOptions[\"fetchOptions\"];\n\n /** Initial context ID for the conversation. */\n contextId?: string;\n /** Default send message configuration. */\n configuration?: A2ASendMessageConfiguration;\n\n /** Called when an error occurs. */\n onError?: (error: Error) => void;\n /** Called when a run is cancelled. */\n onCancel?: () => void;\n /** Called when an artifact is fully received (lastChunk). */\n onArtifactComplete?: (artifact: import(\"./types\").A2AArtifact) => void;\n\n adapters?: {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n dictation?: DictationAdapter;\n voice?: RealtimeVoiceAdapter;\n feedback?: FeedbackAdapter;\n history?: ThreadHistoryAdapter;\n threadList?: UseA2AThreadListAdapter;\n };\n};\n\n// --- Main hook ---\n\nexport function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {\n const [_version, setVersion] = useState(0);\n const notifyUpdate = useCallback(() => setVersion((v) => v + 1), []);\n const runtimeAdapters = useRuntimeAdapters();\n const historyAdapter = options.adapters?.history ?? runtimeAdapters?.history;\n const threadListAdapter = options.adapters?.threadList;\n\n // Create or reuse client\n const clientRef = useRef<A2AClient | null>(null);\n if (!clientRef.current) {\n if (options.client) {\n clientRef.current = options.client;\n } else if (options.baseUrl) {\n clientRef.current = new A2AClient({\n baseUrl: options.baseUrl,\n basePath: options.basePath,\n tenant: options.tenant,\n headers: options.headers,\n extensions: options.extensions,\n fetchOptions: options.fetchOptions,\n });\n } else {\n throw new Error(\"useA2ARuntime requires either `client` or `baseUrl`\");\n }\n }\n const client = clientRef.current;\n\n // Create or reuse core\n const coreRef = useRef<A2AThreadRuntimeCore | null>(null);\n if (!coreRef.current) {\n coreRef.current = new A2AThreadRuntimeCore({\n client,\n contextId: options.contextId,\n configuration: options.configuration,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(options.onArtifactComplete && {\n onArtifactComplete: options.onArtifactComplete,\n }),\n ...(historyAdapter && { history: historyAdapter }),\n notifyUpdate,\n });\n }\n\n const core = coreRef.current;\n core.updateOptions({\n client,\n contextId: options.contextId,\n configuration: options.configuration,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(options.onArtifactComplete && {\n onArtifactComplete: options.onArtifactComplete,\n }),\n ...(historyAdapter && { history: historyAdapter }),\n });\n\n // Thread list\n const threadList = useMemo(() => {\n if (!threadListAdapter) return undefined;\n\n const { onSwitchToNewThread, onSwitchToThread } = threadListAdapter;\n\n return {\n threadId: threadListAdapter.threadId,\n onSwitchToNewThread: onSwitchToNewThread\n ? async () => {\n await onSwitchToNewThread();\n core.applyExternalMessages([]);\n }\n : undefined,\n onSwitchToThread: onSwitchToThread\n ? async (threadId: string) => {\n const result = await onSwitchToThread(threadId);\n core.applyExternalMessages(result.messages);\n }\n : undefined,\n };\n }, [threadListAdapter, core]);\n\n // Adapters\n const adapters = options.adapters;\n const adapterAdapters = useMemo(\n () => ({\n attachments: adapters?.attachments ?? runtimeAdapters?.attachments,\n speech: adapters?.speech,\n dictation: adapters?.dictation,\n voice: adapters?.voice,\n feedback: adapters?.feedback,\n threadList,\n }),\n [adapters, runtimeAdapters, threadList],\n );\n\n // Build store adapter\n const shared = useExternalStoreSharedOptions(options);\n const store = useMemo(() => {\n void _version;\n\n return {\n ...shared,\n isLoading: core.isLoading,\n messages: core.getMessages(),\n isRunning: core.isRunning(),\n extras: {\n [symbolA2AExtras]: true,\n task: core.getTask(),\n artifacts: core.getArtifacts(),\n agentCard: core.getAgentCard(),\n } satisfies A2AExtras,\n onNew: (message: AppendMessage) => core.append(message),\n onEdit: (message: AppendMessage) => core.edit(message),\n onReload: (parentId: string | null) => core.reload(parentId),\n onCancel: () => core.cancel(),\n setMessages: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n onImport: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n adapters: adapterAdapters,\n } satisfies ExternalStoreAdapter<ThreadMessage>;\n }, [adapterAdapters, core, _version, shared]);\n\n const runtime = useExternalStoreRuntime(store);\n\n useEffect(() => {\n core.attachRuntime(runtime);\n return () => {\n core.detachRuntime();\n };\n }, [core, runtime]);\n\n useEffect(() => {\n core.__internal_load();\n }, [core]);\n\n return runtime;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-a2a",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "A2A (Agent-to-Agent) v1.0 protocol adapter for assistant-ui",
5
5
  "keywords": [
6
6
  "a2a",
@@ -29,8 +29,8 @@
29
29
  ],
30
30
  "sideEffects": false,
31
31
  "dependencies": {
32
- "@assistant-ui/core": "^0.2.5",
33
- "@assistant-ui/store": "^0.2.12"
32
+ "@assistant-ui/core": "^0.2.8",
33
+ "@assistant-ui/store": "^0.2.13"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@types/react": "*",
@@ -45,7 +45,7 @@
45
45
  "@types/react": "^19.2.15",
46
46
  "react": "^19.2.6",
47
47
  "vitest": "^4.1.7",
48
- "@assistant-ui/x-buildutils": "0.0.9"
48
+ "@assistant-ui/x-buildutils": "0.0.10"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public",
@@ -148,6 +148,115 @@ describe("A2AClient", () => {
148
148
  });
149
149
  });
150
150
 
151
+ describe("fetchOptions", () => {
152
+ it("applies fetchOptions to all request types", async () => {
153
+ const fetchOptionsClient = new A2AClient({
154
+ baseUrl: "https://agent.test",
155
+ fetchOptions: { credentials: "include" },
156
+ });
157
+
158
+ fetchMock
159
+ .mockResolvedValueOnce(
160
+ mockFetchResponse({
161
+ task: { id: "t1", status: { state: "completed" } },
162
+ }),
163
+ )
164
+ .mockResolvedValueOnce(
165
+ mockFetchResponse({
166
+ name: "Test Agent",
167
+ description: "A test",
168
+ version: "1.0",
169
+ supportedInterfaces: [],
170
+ capabilities: {},
171
+ defaultInputModes: [],
172
+ defaultOutputModes: [],
173
+ skills: [],
174
+ }),
175
+ )
176
+ .mockResolvedValueOnce(
177
+ mockSSEResponse([
178
+ `data: ${JSON.stringify({ status_update: { task_id: "t1", context_id: "ctx-1", status: { state: "TASK_STATE_WORKING" } } })}`,
179
+ "",
180
+ "",
181
+ ]),
182
+ )
183
+ .mockResolvedValueOnce(
184
+ mockSSEResponse([
185
+ `data: ${JSON.stringify({ status_update: { task_id: "t1", context_id: "ctx-1", status: { state: "TASK_STATE_WORKING" } } })}`,
186
+ "",
187
+ "",
188
+ ]),
189
+ )
190
+ .mockResolvedValueOnce({
191
+ ok: true,
192
+ status: 204,
193
+ statusText: "No Content",
194
+ headers: new Headers(),
195
+ });
196
+
197
+ await fetchOptionsClient.sendMessage(userMessage);
198
+ await fetchOptionsClient.getAgentCard();
199
+ for await (const _ of fetchOptionsClient.streamMessage(userMessage)) {
200
+ void _;
201
+ }
202
+ for await (const _ of fetchOptionsClient.subscribeToTask("t1")) {
203
+ void _;
204
+ }
205
+ await fetchOptionsClient.deleteTaskPushNotificationConfig("t1", "pnc-1");
206
+
207
+ for (const [, init] of fetchMock.mock.calls) {
208
+ expect(init.credentials).toBe("include");
209
+ }
210
+ });
211
+
212
+ it("strips internally-managed fields even when smuggled via cast", async () => {
213
+ const smuggledSignal = new AbortController().signal;
214
+ const fetchOptionsClient = new A2AClient({
215
+ baseUrl: "https://agent.test",
216
+ fetchOptions: {
217
+ method: "GET",
218
+ headers: { "X-Injected": "1" },
219
+ body: "smuggled",
220
+ signal: smuggledSignal,
221
+ } as RequestInit,
222
+ });
223
+
224
+ fetchMock
225
+ .mockResolvedValueOnce(
226
+ mockFetchResponse({
227
+ task: { id: "t1", status: { state: "completed" } },
228
+ }),
229
+ )
230
+ .mockResolvedValueOnce(
231
+ mockFetchResponse({
232
+ name: "Test",
233
+ description: "desc",
234
+ version: "1.0",
235
+ supportedInterfaces: [],
236
+ capabilities: {},
237
+ defaultInputModes: [],
238
+ defaultOutputModes: [],
239
+ skills: [],
240
+ }),
241
+ );
242
+
243
+ await fetchOptionsClient.sendMessage(userMessage);
244
+ await fetchOptionsClient.getAgentCard();
245
+
246
+ for (const [, init] of fetchMock.mock.calls) {
247
+ expect(init.headers["X-Injected"]).toBeUndefined();
248
+ expect(init.body).not.toBe("smuggled");
249
+ expect(init.signal).not.toBe(smuggledSignal);
250
+ }
251
+
252
+ expect(fetchMock.mock.calls[0]![1].method).toBe("POST");
253
+ expect(fetchMock.mock.calls[0]![1].headers["Content-Type"]).toBe(
254
+ "application/a2a+json",
255
+ );
256
+ expect(fetchMock.mock.calls[1]![1].method).toBeUndefined();
257
+ });
258
+ });
259
+
151
260
  // --- Tenant ---
152
261
 
153
262
  describe("tenant", () => {
@@ -275,7 +384,7 @@ describe("A2AClient", () => {
275
384
  expect(body.message.messageId).toBe("msg-1");
276
385
  });
277
386
 
278
- it("sends 'content' not 'parts' per A2A v1.0 proto spec", async () => {
387
+ it("sends 'parts' per A2A v1.0 spec (gRPC + JSON-RPC unified in a2aproject/A2A#1100)", async () => {
279
388
  fetchMock.mockResolvedValue(
280
389
  mockFetchResponse({
281
390
  task: { id: "t1", status: { state: "completed" } },
@@ -285,8 +394,8 @@ describe("A2AClient", () => {
285
394
  await client.sendMessage(userMessage);
286
395
 
287
396
  const body = JSON.parse(fetchMock.mock.calls[0]![1].body);
288
- expect(body.message.content).toEqual([{ text: "Hello" }]);
289
- expect(body.message.parts).toBeUndefined();
397
+ expect(body.message.parts).toEqual([{ text: "Hello" }]);
398
+ expect(body.message.content).toBeUndefined();
290
399
  });
291
400
 
292
401
  it("unwraps task from SendMessageResponse", async () => {
@@ -320,7 +429,7 @@ describe("A2AClient", () => {
320
429
  expect((result as any).role).toBe("agent");
321
430
  });
322
431
 
323
- it("normalizes 'content' array from v1.0 server response to internal 'parts'", async () => {
432
+ it("normalizes 'content' array from v0.3 server response to internal 'parts'", async () => {
324
433
  fetchMock.mockResolvedValue(
325
434
  mockFetchResponse({
326
435
  message: {
@@ -778,7 +887,7 @@ describe("A2AClient", () => {
778
887
  expect(events).toHaveLength(2);
779
888
  });
780
889
 
781
- it("normalizes v1.0 'content' to 'parts' in SSE artifact update events", async () => {
890
+ it("normalizes 'content' array from v0.3 server response to 'parts' in SSE artifact update events", async () => {
782
891
  const sseData = JSON.stringify({
783
892
  artifact_update: {
784
893
  task_id: "t1",
@@ -810,7 +919,7 @@ describe("A2AClient", () => {
810
919
  expect((evt.event.artifact as any).content).toBeUndefined();
811
920
  });
812
921
 
813
- it("normalizes v1.0 'content' to 'parts' in SSE status update messages", async () => {
922
+ it("normalizes 'content' array from v0.3 server response to 'parts' in SSE status update messages", async () => {
814
923
  const sseData = JSON.stringify({
815
924
  status_update: {
816
925
  task_id: "t1",
package/src/A2AClient.ts CHANGED
@@ -26,6 +26,10 @@ export type A2AClientOptions = {
26
26
  | undefined;
27
27
  /** A2A extension URIs to negotiate. Sent as A2A-Extensions header. */
28
28
  extensions?: string[] | undefined;
29
+ /** Extra fetch options applied to every request. */
30
+ fetchOptions?:
31
+ | Omit<RequestInit, "headers" | "body" | "method" | "signal">
32
+ | undefined;
29
33
  };
30
34
 
31
35
  export class A2AError extends Error {
@@ -87,10 +91,10 @@ function normalizeKeys(obj: unknown, opaque = false): unknown {
87
91
  ) {
88
92
  result[camelKey] = value.slice(5).toLowerCase();
89
93
  } else if (camelKey === "content" && Array.isArray(value)) {
90
- // v1.0 proto uses "content" for message/artifact parts; map to internal "parts"
94
+ // v0.3 servers used "content" for message/artifact parts; normalize to "parts" for backward compat
91
95
  result.parts = normalizeKeys(value, false);
92
96
  } else if (camelKey !== "parts" || !("parts" in result)) {
93
- // skip "parts" if "content" already mapped it (prefer content over parts)
97
+ // dedup: "content" was already mapped to parts above; don't overwrite
94
98
  result[camelKey] = isOpaqueChild ? value : normalizeKeys(value, false);
95
99
  }
96
100
  }
@@ -111,8 +115,7 @@ function toWireTaskState(state: A2ATaskState): string {
111
115
  }
112
116
 
113
117
  function toWireMessage(msg: A2AMessage): unknown {
114
- const { parts, ...rest } = msg;
115
- return { ...rest, role: toWireRole(msg.role), content: parts };
118
+ return { ...msg, role: toWireRole(msg.role) };
116
119
  }
117
120
 
118
121
  function discriminateStreamResponse(
@@ -158,6 +161,10 @@ export class A2AClient {
158
161
  private basePath: string;
159
162
  private tenant: string | undefined;
160
163
  private extensionUris: string[] | undefined;
164
+ private fetchOptions: Omit<
165
+ RequestInit,
166
+ "headers" | "body" | "method" | "signal"
167
+ >;
161
168
  private headersFn:
162
169
  | Record<string, string>
163
170
  | (() => Record<string, string> | Promise<Record<string, string>>);
@@ -169,6 +176,14 @@ export class A2AClient {
169
176
  : "";
170
177
  this.tenant = options.tenant;
171
178
  this.extensionUris = options.extensions;
179
+ const {
180
+ headers: _h,
181
+ body: _b,
182
+ method: _m,
183
+ signal: _s,
184
+ ...safeFetchOptions
185
+ } = (options.fetchOptions ?? {}) as RequestInit;
186
+ this.fetchOptions = safeFetchOptions;
172
187
  this.headersFn = options.headers ?? {};
173
188
  }
174
189
 
@@ -229,6 +244,7 @@ export class A2AClient {
229
244
  const isGet = !options.method || options.method.toUpperCase() === "GET";
230
245
  const headers = await this.getHeaders(!isGet);
231
246
  const response = await fetch(`${this.baseUrl}${path}`, {
247
+ ...this.fetchOptions,
232
248
  ...options,
233
249
  headers: {
234
250
  ...headers,
@@ -247,7 +263,11 @@ export class A2AClient {
247
263
  async getAgentCard(signal?: AbortSignal): Promise<A2AAgentCard> {
248
264
  const headers = await this.getHeaders(false); // GET: no Content-Type
249
265
  const url = `${this.baseUrl}/.well-known/agent-card.json`;
250
- const response = await fetch(url, { headers, ...signalInit(signal) });
266
+ const response = await fetch(url, {
267
+ ...this.fetchOptions,
268
+ headers,
269
+ ...signalInit(signal),
270
+ });
251
271
  if (!response.ok) {
252
272
  await this.throwResponseError(response);
253
273
  }
@@ -310,6 +330,7 @@ export class A2AClient {
310
330
  const response = await fetch(
311
331
  `${this.baseUrl}${this.getBasePath()}/message:stream`,
312
332
  {
333
+ ...this.fetchOptions,
313
334
  method: "POST",
314
335
  headers,
315
336
  body: JSON.stringify(body),
@@ -390,7 +411,11 @@ export class A2AClient {
390
411
 
391
412
  const response = await fetch(
392
413
  `${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}:subscribe`,
393
- { headers, ...signalInit(signal) },
414
+ {
415
+ ...this.fetchOptions,
416
+ headers,
417
+ ...signalInit(signal),
418
+ },
394
419
  );
395
420
  if (!response.ok) {
396
421
  await this.throwResponseError(response);
@@ -453,7 +478,12 @@ export class A2AClient {
453
478
  const headers = await this.getHeaders(!isGet);
454
479
  const response = await fetch(
455
480
  `${this.baseUrl}${this.getBasePath()}/tasks/${encodeURIComponent(taskId)}/pushNotificationConfigs/${encodeURIComponent(configId)}`,
456
- { method: "DELETE", headers, ...signalInit(signal) },
481
+ {
482
+ ...this.fetchOptions,
483
+ method: "DELETE",
484
+ headers,
485
+ ...signalInit(signal),
486
+ },
457
487
  );
458
488
  if (!response.ok) {
459
489
  await this.throwResponseError(response);
@@ -37,7 +37,7 @@ function createUserAppendMessage(text: string): AppendMessage {
37
37
  parentId: null,
38
38
  role: "user",
39
39
  content: [{ type: "text", text }],
40
- };
40
+ } as unknown as AppendMessage;
41
41
  }
42
42
 
43
43
  function statusUpdateEvent(state: string, text?: string): A2AStreamEvent {
@@ -90,7 +90,7 @@ describe("A2AThreadRuntimeCore", () => {
90
90
  ) {
91
91
  return new A2AThreadRuntimeCore({
92
92
  client: createMockClient(clientOverrides),
93
- notifyUpdate,
93
+ notifyUpdate: notifyUpdate as unknown as () => void,
94
94
  ...coreOverrides,
95
95
  });
96
96
  }
@@ -369,7 +369,7 @@ describe("A2AThreadRuntimeCore", () => {
369
369
  }),
370
370
  }),
371
371
  onArtifactComplete,
372
- notifyUpdate,
372
+ notifyUpdate: notifyUpdate as unknown as () => void,
373
373
  });
374
374
 
375
375
  await core.append(createUserAppendMessage("Go"));
@@ -588,7 +588,7 @@ describe("A2AThreadRuntimeCore", () => {
588
588
  })),
589
589
  }),
590
590
  onError,
591
- notifyUpdate,
591
+ notifyUpdate: notifyUpdate as unknown as () => void,
592
592
  });
593
593
 
594
594
  await expect(core.append(createUserAppendMessage("Go"))).rejects.toThrow(
@@ -680,7 +680,7 @@ describe("A2AThreadRuntimeCore", () => {
680
680
  createdAt: new Date(),
681
681
  content: [{ type: "text", text: "External" }],
682
682
  status: { type: "complete", reason: "stop" },
683
- } as ThreadMessage,
683
+ } as unknown as ThreadMessage,
684
684
  ];
685
685
 
686
686
  core.applyExternalMessages(msgs);
@@ -200,14 +200,12 @@ describe("taskStateToMessageStatus", () => {
200
200
  });
201
201
 
202
202
  describe("isTerminalTaskState", () => {
203
- it.each([
204
- "completed",
205
- "failed",
206
- "canceled",
207
- "rejected",
208
- ] as A2ATaskState[])("returns true for %s", (state) => {
209
- expect(isTerminalTaskState(state)).toBe(true);
210
- });
203
+ it.each(["completed", "failed", "canceled", "rejected"] as A2ATaskState[])(
204
+ "returns true for %s",
205
+ (state) => {
206
+ expect(isTerminalTaskState(state)).toBe(true);
207
+ },
208
+ );
211
209
 
212
210
  it.each([
213
211
  "submitted",
@@ -221,12 +219,12 @@ describe("isTerminalTaskState", () => {
221
219
  });
222
220
 
223
221
  describe("isInterruptedTaskState", () => {
224
- it.each([
225
- "input_required",
226
- "auth_required",
227
- ] as A2ATaskState[])("returns true for %s", (state) => {
228
- expect(isInterruptedTaskState(state)).toBe(true);
229
- });
222
+ it.each(["input_required", "auth_required"] as A2ATaskState[])(
223
+ "returns true for %s",
224
+ (state) => {
225
+ expect(isInterruptedTaskState(state)).toBe(true);
226
+ },
227
+ );
230
228
 
231
229
  it.each([
232
230
  "submitted",
@@ -1,17 +1,20 @@
1
- /// <reference types="@assistant-ui/core/store" />
2
1
  "use client";
3
2
 
4
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
4
  import {
6
5
  useExternalStoreRuntime,
6
+ useExternalStoreSharedOptions,
7
7
  useRuntimeAdapters,
8
8
  } from "@assistant-ui/core/react";
9
9
  import type {
10
10
  AssistantRuntime,
11
11
  AppendMessage,
12
12
  AttachmentAdapter,
13
+ DictationAdapter,
13
14
  ExternalStoreAdapter,
15
+ ExternalStoreSharedOptions,
14
16
  FeedbackAdapter,
17
+ RealtimeVoiceAdapter,
15
18
  SpeechSynthesisAdapter,
16
19
  ThreadHistoryAdapter,
17
20
  ThreadMessage,
@@ -76,7 +79,7 @@ export type UseA2AThreadListAdapter = {
76
79
 
77
80
  // --- Options ---
78
81
 
79
- export type UseA2ARuntimeOptions = {
82
+ export type UseA2ARuntimeOptions = ExternalStoreSharedOptions & {
80
83
  /** Pre-built A2A client instance. Provide this OR baseUrl. */
81
84
  client?: A2AClient;
82
85
  /** Base URL of the A2A server. Used to create a client if `client` is not provided. */
@@ -89,6 +92,8 @@ export type UseA2ARuntimeOptions = {
89
92
  headers?: A2AClientOptions["headers"];
90
93
  /** A2A extension URIs to negotiate. Only used with baseUrl. */
91
94
  extensions?: string[];
95
+ /** Extra fetch options (e.g. `{ credentials: 'include' }`). Only used with `baseUrl`. */
96
+ fetchOptions?: A2AClientOptions["fetchOptions"];
92
97
 
93
98
  /** Initial context ID for the conversation. */
94
99
  contextId?: string;
@@ -105,6 +110,8 @@ export type UseA2ARuntimeOptions = {
105
110
  adapters?: {
106
111
  attachments?: AttachmentAdapter;
107
112
  speech?: SpeechSynthesisAdapter;
113
+ dictation?: DictationAdapter;
114
+ voice?: RealtimeVoiceAdapter;
108
115
  feedback?: FeedbackAdapter;
109
116
  history?: ThreadHistoryAdapter;
110
117
  threadList?: UseA2AThreadListAdapter;
@@ -132,6 +139,7 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
132
139
  tenant: options.tenant,
133
140
  headers: options.headers,
134
141
  extensions: options.extensions,
142
+ fetchOptions: options.fetchOptions,
135
143
  });
136
144
  } else {
137
145
  throw new Error("useA2ARuntime requires either `client` or `baseUrl`");
@@ -198,6 +206,8 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
198
206
  () => ({
199
207
  attachments: adapters?.attachments ?? runtimeAdapters?.attachments,
200
208
  speech: adapters?.speech,
209
+ dictation: adapters?.dictation,
210
+ voice: adapters?.voice,
201
211
  feedback: adapters?.feedback,
202
212
  threadList,
203
213
  }),
@@ -205,10 +215,12 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
205
215
  );
206
216
 
207
217
  // Build store adapter
218
+ const shared = useExternalStoreSharedOptions(options);
208
219
  const store = useMemo(() => {
209
220
  void _version;
210
221
 
211
222
  return {
223
+ ...shared,
212
224
  isLoading: core.isLoading,
213
225
  messages: core.getMessages(),
214
226
  isRunning: core.isRunning(),
@@ -228,7 +240,7 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
228
240
  core.applyExternalMessages(messages),
229
241
  adapters: adapterAdapters,
230
242
  } satisfies ExternalStoreAdapter<ThreadMessage>;
231
- }, [adapterAdapters, core, _version]);
243
+ }, [adapterAdapters, core, _version, shared]);
232
244
 
233
245
  const runtime = useExternalStoreRuntime(store);
234
246