@assistant-ui/react-a2a 0.2.38 → 0.2.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/A2AThreadRuntimeCore.d.ts.map +1 -1
- package/dist/A2AThreadRuntimeCore.js +4 -1
- package/dist/A2AThreadRuntimeCore.js.map +1 -1
- package/dist/conversions.d.ts.map +1 -1
- package/dist/conversions.js +8 -4
- package/dist/conversions.js.map +1 -1
- package/dist/useA2ARuntime.d.ts.map +1 -1
- package/dist/useA2ARuntime.js +34 -9
- package/dist/useA2ARuntime.js.map +1 -1
- package/package.json +10 -7
- package/src/A2AThreadRuntimeCore.test.ts +2 -0
- package/src/A2AThreadRuntimeCore.ts +1 -0
- package/src/conversions.test.ts +34 -0
- package/src/conversions.ts +5 -4
- package/src/useA2ARuntime.fast-refresh.test.tsx +159 -0
- package/src/useA2ARuntime.ts +38 -12
package/LICENSE
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"A2AThreadRuntimeCore.d.ts","sourceRoot":"","sources":["../src/A2AThreadRuntimeCore.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,yBAAyB,EAIzB,oBAAoB,EACpB,aAAa,EAEb,qCAAqC,EACtC,MAAM,oBAAoB,CAAC;AAa5B,OAAO,KAAK,EAAE,SAAS,EAAE,uBAAoB;AAC7C,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EAEZ,2BAA2B,EAE3B,OAAO,EAGR,mBAAgB;AAqBjB,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,aAAa,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;IACxD,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACpC,kBAAkB,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACnE,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC3C,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAwBF,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,kBAAkB,CAAgD;IAC1E,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAE1C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,YAAY,CAAsB;IAG1C,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,cAAc,CAA2B;IAGjD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAoC;IAC5E,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoC;IAClE,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,oBAAoB,CAAqC;IACjE,OAAO,CAAC,yBAAyB,CAAS;IAE1C,OAAO,CAAC,oBAAoB,CAAqB;gBAErC,OAAO,EAAE,2BAA2B;IAYhD,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,2BAA2B,EAAE,cAAc,CAAC;IA4BxE;kFAC8E;IAC9E,YAAY,IAAI,IAAI;IAgBpB,aAAa,CAAC,OAAO,EAAE,gBAAgB;IAIvC,aAAa;IASb,UAAU,IAAI,gBAAgB,GAAG,SAAS;IAI1C,WAAW,IAAI,SAAS,aAAa,EAAE;IAIvC,oBAAoB,IAAI,yBAAyB;IAIpC,qBAAqB,CAAC,EACjC,SAAS,EACT,UAAU,EACV,WAAW,GACZ,EAAE,qCAAqC,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CxD,OAAO,IAAI,OAAO,GAAG,SAAS;IAI9B,YAAY,IAAI,SAAS,WAAW,EAAE;IAItC,YAAY,IAAI,YAAY,GAAG,SAAS;IAIxC,SAAS,IAAI,OAAO;IAIpB,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,OAAO,CAAC,aAAa;YAwBP,gBAAgB;IAoB9B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC1B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBnD,qBAAqB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAQ7C,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,MAAM,CACV,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAO,GACpD,OAAO,CAAC,IAAI,CAAC;IAaV,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"A2AThreadRuntimeCore.d.ts","sourceRoot":"","sources":["../src/A2AThreadRuntimeCore.ts"],"names":[],"mappings":"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"}
|
|
@@ -240,7 +240,10 @@ var A2AThreadRuntimeCore = class {
|
|
|
240
240
|
this.abortController.abort();
|
|
241
241
|
if (task?.id) try {
|
|
242
242
|
const updated = await this.client.cancelTask(task.id);
|
|
243
|
-
if (this.currentTask === task && this.runGeneration === generation)
|
|
243
|
+
if (this.currentTask === task && this.runGeneration === generation) {
|
|
244
|
+
this.currentTask = updated;
|
|
245
|
+
this.notifyUpdate();
|
|
246
|
+
}
|
|
244
247
|
} catch {}
|
|
245
248
|
}
|
|
246
249
|
appendLinearChain(messages) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"A2AThreadRuntimeCore.js","names":["isRecord"],"sources":["../src/A2AThreadRuntimeCore.ts"],"sourcesContent":["\"use client\";\n\nimport { generateId, fromThreadMessageLike } from \"@assistant-ui/core\";\nimport type {\n AppendMessage,\n AssistantRuntime,\n ExportedMessageRepository,\n MessageStatus,\n ThreadAssistantMessage,\n ThreadAssistantMessagePart,\n ThreadHistoryAdapter,\n ThreadMessage,\n ToolCallMessagePart,\n Unstable_RecordToolInteractionOptions,\n} from \"@assistant-ui/core\";\nimport {\n appendToolInteraction,\n createMessageRepositorySession,\n invokeUserCallback,\n} from \"@assistant-ui/core/internal\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport {\n applyA2uiOperations,\n convertSurfaceToUISpec,\n surfaceToOperations,\n type A2uiState,\n} from \"@assistant-ui/react-generative-ui/a2ui\";\nimport type { A2AClient } from \"./A2AClient\";\nimport type {\n A2AArtifact,\n A2AAgentCard,\n A2AMessage,\n A2ASendMessageConfiguration,\n A2AStreamEvent,\n A2ATask,\n A2ATaskArtifactUpdateEvent,\n A2ATaskStatusUpdateEvent,\n} from \"./types\";\n\nimport {\n a2aMessageToContent,\n a2uiPartsToOperations,\n isTerminalTaskState,\n threadMessageToA2AMessage,\n taskStateToMessageStatus,\n} from \"./conversions\";\n\nconst INITIAL_AGENT_CARD_RETRY_DELAY_MS = 5_000;\nconst MAX_AGENT_CARD_RETRY_DELAY_MS = 5 * 60_000;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst storedArtifact = (artifact: A2AArtifact): A2AArtifact => ({\n ...artifact,\n parts: artifact.parts.map(({ raw: _raw, ...part }) => part),\n});\n\nexport type A2AThreadRuntimeCoreOptions = {\n client: A2AClient;\n contextId?: string | undefined;\n configuration?: A2ASendMessageConfiguration | undefined;\n onError?: ((error: Error) => void) | undefined;\n onCancel?: (() => void) | undefined;\n onArtifactComplete?: ((artifact: A2AArtifact) => void) | undefined;\n history?: ThreadHistoryAdapter | undefined;\n notifyUpdate: () => void;\n};\n\nconst FALLBACK_USER_STATUS = {\n type: \"complete\",\n reason: \"unknown\",\n} as const;\n\ntype A2ARuntimeCallbackName = \"onError\" | \"onCancel\" | \"onArtifactComplete\";\n\nconst invokeRuntimeCallback = <TArgs extends readonly unknown[]>(\n name: A2ARuntimeCallbackName,\n callback: ((...args: TArgs) => unknown) | undefined,\n ...args: TArgs\n): void => {\n void invokeUserCallback(\"react-a2a\", name, callback, ...args);\n};\n\nfunction normalizeArtifact(artifact: A2AArtifact): A2AArtifact {\n return {\n ...artifact,\n parts: Array.isArray(artifact.parts) ? artifact.parts : [],\n };\n}\n\nexport class A2AThreadRuntimeCore {\n private client: A2AClient;\n private contextId: string | undefined;\n private configuration: A2ASendMessageConfiguration | undefined;\n private onError: ((error: Error) => void) | undefined;\n private onCancel: (() => void) | undefined;\n private onArtifactComplete: ((artifact: A2AArtifact) => void) | undefined;\n private history: ThreadHistoryAdapter | undefined;\n private readonly notifyUpdate: () => void;\n\n private runtime: AssistantRuntime | undefined;\n private readonly session = createMessageRepositorySession();\n private isRunningFlag = false;\n private abortController: AbortController | null = null;\n private runGeneration = 0;\n private pendingError: Error | null = null;\n\n // A2A-specific state\n private currentTask: A2ATask | undefined;\n private currentArtifacts: A2AArtifact[] = [];\n private a2uiState: A2uiState = new Map();\n private readonly a2uiMessageIds = new Set<string>();\n private agentCardValue: A2AAgentCard | undefined;\n\n // History tracking\n private readonly assistantHistoryParents = new Map<string, string | null>();\n private readonly recordedHistoryIds = new Set<string>();\n private readonly historyWrites = new Map<string, Promise<void>>();\n private _isLoading = false;\n private _loadPromise: Promise<void> | undefined;\n private _historyLoadGeneration = 0;\n private _loadRequested = false;\n private _agentCardPromise: Promise<void> | undefined;\n private _agentCardRetryAfter = 0;\n private _agentCardRetryDelay = INITIAL_AGENT_CARD_RETRY_DELAY_MS;\n private _agentCardDiscoveryFailed = false;\n\n private lastOptionsContextId: string | undefined;\n\n constructor(options: A2AThreadRuntimeCoreOptions) {\n this.client = options.client;\n this.contextId = options.contextId;\n this.lastOptionsContextId = options.contextId;\n this.configuration = options.configuration;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.onArtifactComplete = options.onArtifactComplete;\n this.history = options.history;\n this.notifyUpdate = options.notifyUpdate;\n }\n\n updateOptions(options: Omit<A2AThreadRuntimeCoreOptions, \"notifyUpdate\">) {\n this.client = options.client;\n // The hook re-applies options on every render, including renders caused\n // by this core's own notifyUpdate. The option only seeds the context: a\n // re-render with the same value must not clobber a server-assigned\n // contextId learned from the stream.\n if (options.contextId !== this.lastOptionsContextId) {\n this.contextId = options.contextId;\n this.lastOptionsContextId = options.contextId;\n }\n this.configuration = options.configuration;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.onArtifactComplete = options.onArtifactComplete;\n const previousHistory = this.history;\n this.history = options.history;\n\n if (\n this._loadRequested &&\n !this._loadPromise &&\n !previousHistory &&\n options.history &&\n this.session.getMessages().length === 0\n ) {\n void this.__internal_load();\n }\n }\n\n /** Thread-boundary reset: applyExternalMessages alone also serves branch\n * switches, deletes, and cancel resyncs, which must keep the live context. */\n resetContext(): void {\n this._historyLoadGeneration++;\n this._isLoading = false;\n // Restore the seed before aborting: an onCancel callback that starts a\n // new run must not pick up the old thread's context, and its controller\n // must not be discarded.\n const controller = this.abortController;\n this.contextId = this.lastOptionsContextId;\n if (controller) {\n controller.abort();\n if (this.abortController === controller) {\n this.abortController = null;\n }\n }\n }\n\n attachRuntime(runtime: AssistantRuntime) {\n this.runtime = runtime;\n }\n\n detachRuntime() {\n this.runtime = undefined;\n // Abort in-flight requests on unmount\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n }\n\n getRuntime(): AssistantRuntime | undefined {\n return this.runtime;\n }\n\n getMessages(): readonly ThreadMessage[] {\n return this.session.getMessages();\n }\n\n getMessageRepository(): ExportedMessageRepository {\n return this.session.export();\n }\n\n public async recordToolInteraction({\n messageId,\n toolCallId,\n interaction,\n }: Unstable_RecordToolInteractionOptions): Promise<void> {\n const message = this.session.tryGetMessage(messageId)?.message;\n if (!message) {\n throw new Error(\n \"Tried to record a tool interaction on a non-existing message\",\n );\n }\n if (message.role !== \"assistant\") {\n throw new Error(\n \"Tried to record a tool interaction on a non-assistant message\",\n );\n }\n const target = message.content.find(\n (part) => part.type === \"tool-call\" && part.toolCallId === toolCallId,\n );\n if (!target || target.type !== \"tool-call\") {\n throw new Error(\n \"Tried to record a tool interaction on a non-existing tool call\",\n );\n }\n\n const touched = this.session.updateMessage(messageId, (current) => {\n if (current.role !== \"assistant\") return current;\n return {\n ...current,\n content: current.content.map((part) =>\n part.type === \"tool-call\" && part.toolCallId === toolCallId\n ? {\n ...part,\n unstable_interactions: appendToolInteraction(\n part.unstable_interactions,\n interaction,\n ),\n }\n : part,\n ),\n };\n });\n if (touched) {\n this.notifyUpdate();\n this.persistAssistantHistory(messageId);\n }\n }\n\n getTask(): A2ATask | undefined {\n return this.currentTask;\n }\n\n getArtifacts(): readonly A2AArtifact[] {\n return this.currentArtifacts;\n }\n\n getAgentCard(): A2AAgentCard | undefined {\n return this.agentCardValue;\n }\n\n isRunning(): boolean {\n return this.isRunningFlag;\n }\n\n get isLoading(): boolean {\n return this._isLoading;\n }\n\n private loadAgentCard(): Promise<void> {\n if (Date.now() < this._agentCardRetryAfter) return Promise.resolve();\n\n this._agentCardPromise ??= this.client.getAgentCard().then(\n (agentCard) => {\n this.agentCardValue = agentCard;\n this._agentCardRetryAfter = 0;\n this._agentCardRetryDelay = INITIAL_AGENT_CARD_RETRY_DELAY_MS;\n this._agentCardDiscoveryFailed = false;\n this.notifyUpdate();\n },\n () => {\n this._agentCardDiscoveryFailed = true;\n this._agentCardRetryAfter = Date.now() + this._agentCardRetryDelay;\n this._agentCardRetryDelay = Math.min(\n this._agentCardRetryDelay * 2,\n MAX_AGENT_CARD_RETRY_DELAY_MS,\n );\n this._agentCardPromise = undefined;\n },\n );\n return this._agentCardPromise;\n }\n\n private async waitForAgentCard(signal: AbortSignal): Promise<boolean> {\n const shouldWait = !this._agentCardDiscoveryFailed;\n const load = this.loadAgentCard();\n if (signal.aborted) return false;\n if (!shouldWait) return true;\n\n let onAbort!: () => void;\n const abort = new Promise<void>((resolve) => {\n onAbort = resolve;\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n\n try {\n await Promise.race([load, abort]);\n } finally {\n signal.removeEventListener(\"abort\", onAbort);\n }\n return !signal.aborted;\n }\n\n __internal_load(): Promise<void> {\n this._loadRequested = true;\n const agentCardPromise = this.loadAgentCard();\n\n if (this._loadPromise) return this._loadPromise;\n if (!this.history) return agentCardPromise;\n\n this._isLoading = true;\n\n const generation = this._historyLoadGeneration;\n const historyPromise = this.history.load();\n\n this._loadPromise = historyPromise\n .then((repo) => {\n if (generation !== this._historyLoadGeneration) return;\n if (repo) {\n this.session.applyExternalMessageRepository(repo);\n this.finalizeExternalApply();\n }\n })\n .catch((error) => {\n if (generation !== this._historyLoadGeneration) return;\n invokeRuntimeCallback(\n \"onError\",\n this.onError,\n error instanceof Error ? error : new Error(String(error)),\n );\n })\n .finally(() => {\n if (generation !== this._historyLoadGeneration) return;\n this._isLoading = false;\n this.notifyUpdate();\n });\n\n this.notifyUpdate();\n return this._loadPromise;\n }\n\n async append(message: AppendMessage): Promise<void> {\n const startRun = message.startRun ?? message.role === \"user\";\n\n const threadMessage = fromThreadMessageLike(\n message as any,\n generateId(),\n FALLBACK_USER_STATUS,\n );\n const parentId =\n message.parentId === null\n ? null\n : message.parentId && this.session.hasMessage(message.parentId)\n ? message.parentId\n : this.session.headId;\n this.session.addOrUpdateMessage(parentId, threadMessage);\n this.session.switchToBranch(threadMessage.id);\n this.notifyUpdate();\n this.recordHistoryEntry(parentId, threadMessage);\n\n if (!startRun) return;\n await this.startRun(threadMessage);\n }\n\n appendVoiceTranscript(message: ThreadMessage): void {\n const parentId = this.session.headId;\n this.session.addOrUpdateMessage(parentId, message);\n this.session.switchToBranch(message.id);\n this.notifyUpdate();\n this.recordHistoryEntry(parentId, message);\n }\n\n async edit(message: AppendMessage): Promise<void> {\n await this.append(message);\n }\n\n async reload(\n parentId: string | null,\n _config: { runConfig?: Record<string, unknown> } = {},\n ): Promise<void> {\n const messages =\n parentId === null\n ? []\n : (this.session.tryGetMessages(parentId) ?? this.getMessages());\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"user\") {\n await this.startRun(messages[i]!);\n return;\n }\n }\n }\n\n async cancel(): Promise<void> {\n if (!this.abortController) return;\n\n // Read the server target before aborting: the abort listener runs the\n // onCancel callback synchronously, which may clear the thread and with it\n // the task this cancellation is for, or start a new run.\n const task = this.currentTask;\n const generation = this.runGeneration;\n\n // Abort locally first so the stream stops immediately\n this.abortController.abort();\n\n // Then try to cancel the task on the server\n if (task?.id) {\n try {\n const updated = await this.client.cancelTask(task.id);\n // Only apply the response while nothing newer exists. A newer snapshot\n // or a cleared thread replaces the task object; a follow-up run that\n // has not emitted yet keeps it, so the run generation is what rules\n // that case out.\n if (this.currentTask === task && this.runGeneration === generation) {\n this.currentTask = updated;\n }\n } catch {\n // Server cancel failed; local abort already handled\n }\n }\n }\n\n private appendLinearChain(messages: readonly ThreadMessage[]): string | null {\n let parentId: string | null = null;\n let lastId: string | null = null;\n const seen = new Set<string>();\n\n for (const message of messages) {\n if (seen.has(message.id)) continue;\n seen.add(message.id);\n this.session.addOrUpdateMessage(parentId, message);\n parentId = message.id;\n lastId = message.id;\n }\n\n return lastId;\n }\n\n private finalizeExternalApply(): void {\n this.assistantHistoryParents.clear();\n this.recordedHistoryIds.clear();\n for (const { message } of this.getMessageRepository().messages) {\n this.recordedHistoryIds.add(message.id);\n }\n this.currentTask = undefined;\n this.currentArtifacts = [];\n this.a2uiState = new Map();\n this.a2uiMessageIds.clear();\n this.notifyUpdate();\n }\n\n applyExternalMessages(messages: readonly ThreadMessage[]): void {\n if (messages.length === 0) {\n this.session.clear();\n } else {\n let expectedParentId: string | null = null;\n let lastAppliedId: string | null = null;\n let hardReplace = false;\n const seen = new Set<string>();\n\n for (const message of messages) {\n if (seen.has(message.id)) continue;\n seen.add(message.id);\n const existing = this.session.tryGetMessage(message.id);\n if (existing && existing.parentId !== expectedParentId) {\n hardReplace = true;\n break;\n }\n this.session.addOrUpdateMessage(expectedParentId, message);\n expectedParentId = message.id;\n lastAppliedId = message.id;\n }\n\n if (hardReplace) {\n this.session.clear();\n lastAppliedId = this.appendLinearChain(messages);\n }\n\n this.session.resetHead(lastAppliedId);\n }\n\n this.finalizeExternalApply();\n }\n\n // --- Run logic ---\n\n private async startRun(userThreadMessage: ThreadMessage): Promise<void> {\n this.runGeneration++;\n\n // Cancel any in-progress run before starting a new one\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n\n const a2aMessage = threadMessageToA2AMessage(userThreadMessage, {\n contextId: this.contextId,\n taskId:\n this.currentTask?.id &&\n !isTerminalTaskState(this.currentTask.status.state)\n ? this.currentTask.id\n : undefined,\n });\n\n // Clear task if previous task reached terminal state\n if (\n this.currentTask &&\n isTerminalTaskState(this.currentTask.status.state)\n ) {\n this.currentTask = undefined;\n }\n\n this.currentArtifacts = [];\n this.a2uiState = new Map();\n this.a2uiMessageIds.clear();\n\n const assistantParentId = userThreadMessage.id;\n const assistantId = this.insertAssistantPlaceholder(assistantParentId);\n this.markPendingAssistantHistory(assistantId, assistantParentId);\n\n const abortController = new AbortController();\n this.abortController = abortController;\n\n abortController.signal.addEventListener(\n \"abort\",\n () => {\n this.updateAssistantStatus(assistantId, {\n type: \"incomplete\",\n reason: \"cancelled\",\n });\n this.finishRun(abortController);\n invokeRuntimeCallback(\"onCancel\", this.onCancel);\n },\n { once: true },\n );\n\n this.setRunning(true);\n\n try {\n if (!(await this.waitForAgentCard(abortController.signal))) return;\n\n const supportsStreaming =\n this.agentCardValue?.capabilities?.streaming !== false;\n if (supportsStreaming) {\n await this.runStreaming(a2aMessage, assistantId, abortController);\n } else {\n await this.runSync(a2aMessage, assistantId, abortController);\n }\n } catch (error) {\n if (!abortController.signal.aborted) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.updateAssistantStatus(assistantId, {\n type: \"incomplete\",\n reason: \"error\",\n });\n invokeRuntimeCallback(\"onError\", this.onError, err);\n this.pendingError = this.pendingError ?? err;\n }\n } finally {\n this.finishRun(abortController);\n }\n\n if (this.pendingError) {\n const err = this.pendingError;\n this.pendingError = null;\n throw err;\n }\n }\n\n private async runStreaming(\n a2aMessage: A2AMessage,\n assistantId: string,\n abortController: AbortController,\n ): Promise<void> {\n const stream = this.client.streamMessage(\n a2aMessage,\n this.configuration,\n undefined, // metadata\n abortController.signal,\n );\n\n let receivedEvent = false;\n let skipReason: string | undefined;\n const diagnosedStream = (async function* () {\n const reason = yield* stream;\n if (typeof reason === \"string\") skipReason = reason;\n })();\n\n for await (const event of diagnosedStream) {\n if (abortController.signal.aborted) break;\n receivedEvent = true;\n this.handleStreamEvent(assistantId, event);\n }\n\n if (!abortController.signal.aborted) {\n if (!receivedEvent) {\n throw new Error(\n skipReason\n ? `A2A message stream ended without any events. First skipped frame: ${skipReason}`\n : \"A2A message stream ended without any events.\",\n );\n }\n\n const lastStatus = this.getAssistantStatus(assistantId);\n if (lastStatus?.type === \"running\") {\n this.updateAssistantStatus(assistantId, {\n type: \"complete\",\n reason: \"stop\",\n });\n }\n }\n }\n\n private async runSync(\n a2aMessage: A2AMessage,\n assistantId: string,\n abortController: AbortController,\n ): Promise<void> {\n const result = await this.client.sendMessage(\n a2aMessage,\n this.configuration,\n undefined, // metadata\n abortController.signal,\n );\n\n if (abortController.signal.aborted) return;\n\n // Result is either A2ATask or A2AMessage\n if (\"id\" in result && \"status\" in result) {\n // It's a Task\n this.handleTaskSnapshot(assistantId, result as A2ATask);\n } else if (\"messageId\" in result && \"parts\" in result) {\n // It's a Message\n this.handleMessage(assistantId, result as A2AMessage);\n this.updateAssistantStatus(assistantId, {\n type: \"complete\",\n reason: \"stop\",\n });\n }\n }\n\n private handleStreamEvent(assistantId: string, event: A2AStreamEvent) {\n switch (event.type) {\n case \"statusUpdate\":\n this.handleStatusUpdate(assistantId, event.event);\n break;\n case \"artifactUpdate\":\n this.handleArtifactUpdate(assistantId, event.event);\n break;\n case \"message\":\n this.handleMessage(assistantId, event.message);\n break;\n case \"task\":\n this.handleTaskSnapshot(assistantId, event.task);\n break;\n }\n }\n\n private handleStatusUpdate(\n assistantId: string,\n event: A2ATaskStatusUpdateEvent,\n ) {\n if (!this.currentTask) {\n this.currentTask = {\n id: event.taskId,\n contextId: event.contextId,\n status: event.status,\n };\n } else {\n this.currentTask = { ...this.currentTask, status: event.status };\n }\n\n if (event.contextId) {\n this.contextId = event.contextId;\n }\n\n if (event.status.message) {\n this.applyA2uiMessage(event.status.message);\n const content = a2aMessageToContent(event.status.message);\n this.updateAssistantContent(assistantId, content);\n }\n\n const status = taskStateToMessageStatus(event.status.state);\n this.updateAssistantStatus(assistantId, status);\n\n this.notifyUpdate();\n }\n\n private handleArtifactUpdate(\n assistantId: string,\n event: A2ATaskArtifactUpdateEvent,\n ) {\n const { append, lastChunk } = event;\n const artifact = normalizeArtifact(event.artifact);\n const existingIdx = this.currentArtifacts.findIndex(\n (a) => a.artifactId === artifact.artifactId,\n );\n\n let updated: A2AArtifact;\n if (existingIdx >= 0 && append) {\n const existing = this.currentArtifacts[existingIdx]!;\n updated = {\n ...existing,\n parts: [...existing.parts, ...artifact.parts],\n };\n this.currentArtifacts = [\n ...this.currentArtifacts.slice(0, existingIdx),\n updated,\n ...this.currentArtifacts.slice(existingIdx + 1),\n ];\n } else if (existingIdx >= 0) {\n updated = artifact;\n this.currentArtifacts = [\n ...this.currentArtifacts.slice(0, existingIdx),\n updated,\n ...this.currentArtifacts.slice(existingIdx + 1),\n ];\n } else {\n updated = artifact;\n this.currentArtifacts = [...this.currentArtifacts, updated];\n }\n\n this.applyA2uiParts(artifact.parts);\n this.updateAssistantArtifacts(assistantId);\n this.rebuildAssistantA2uiSurfaces(assistantId);\n\n if (lastChunk) {\n invokeRuntimeCallback(\n \"onArtifactComplete\",\n this.onArtifactComplete,\n updated,\n );\n }\n\n this.notifyUpdate();\n }\n\n private handleMessage(assistantId: string, message: A2AMessage) {\n if (message.role !== \"agent\") return;\n\n this.applyA2uiMessage(message);\n const content = a2aMessageToContent(message);\n this.updateAssistantContent(assistantId, content);\n this.notifyUpdate();\n }\n\n private handleTaskSnapshot(assistantId: string, task: A2ATask) {\n const artifacts =\n task.artifacts === undefined\n ? undefined\n : Array.isArray(task.artifacts)\n ? task.artifacts.map(normalizeArtifact)\n : [];\n const history =\n task.history === undefined\n ? undefined\n : Array.isArray(task.history)\n ? task.history\n : [];\n this.currentTask = {\n ...task,\n ...(artifacts === undefined ? {} : { artifacts }),\n ...(history === undefined ? {} : { history }),\n };\n\n if (task.contextId) {\n this.contextId = task.contextId;\n }\n const isCompleteSnapshot = history !== undefined && artifacts !== undefined;\n const artifactsToApply = isCompleteSnapshot\n ? artifacts\n : artifacts?.filter(\n (artifact) =>\n !this.currentArtifacts.some(\n ({ artifactId }) => artifactId === artifact.artifactId,\n ),\n );\n\n if (isCompleteSnapshot) {\n this.currentArtifacts = artifacts;\n this.a2uiState = new Map();\n this.a2uiMessageIds.clear();\n } else if (artifactsToApply) {\n this.currentArtifacts = [...this.currentArtifacts, ...artifactsToApply];\n }\n\n for (const message of history ?? []) {\n if (message.role === \"agent\") this.applyA2uiMessage(message, true);\n }\n for (const artifact of artifactsToApply ?? []) {\n this.applyA2uiParts(artifact.parts);\n }\n if (task.status.message) {\n this.applyA2uiMessage(task.status.message, true);\n }\n\n if (isCompleteSnapshot || artifactsToApply?.length) {\n this.updateAssistantArtifacts(assistantId);\n }\n\n if (task.status.message) {\n const content = a2aMessageToContent(task.status.message);\n this.updateAssistantContent(assistantId, content);\n } else {\n this.rebuildAssistantA2uiSurfaces(assistantId);\n }\n\n const status = taskStateToMessageStatus(task.status.state);\n this.updateAssistantStatus(assistantId, status);\n\n this.notifyUpdate();\n }\n\n // --- Message helpers ---\n\n private insertAssistantPlaceholder(parentId: string): string {\n const id = generateId();\n const assistant: ThreadAssistantMessage = {\n id,\n role: \"assistant\",\n createdAt: new Date(),\n status: { type: \"running\" },\n content: [],\n metadata: {\n unstable_state: null,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n custom: {},\n },\n };\n this.session.addOrUpdateMessage(parentId, assistant);\n this.session.switchToBranch(id);\n this.notifyUpdate();\n return id;\n }\n\n private updateAssistantContent(\n messageId: string,\n content: ThreadAssistantMessage[\"content\"],\n ) {\n this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n return {\n ...message,\n content: this.withA2uiSurfaces(content, message.content),\n };\n });\n }\n\n private applyA2uiMessage(message: A2AMessage, replay = false) {\n if (message.messageId) {\n if (replay && this.a2uiMessageIds.has(message.messageId)) return;\n this.a2uiMessageIds.add(message.messageId);\n }\n this.applyA2uiParts(message.parts);\n }\n\n private applyA2uiParts(parts: readonly A2AMessage[\"parts\"][number][]) {\n const operations = a2uiPartsToOperations(parts);\n if (operations.length === 0) return;\n this.a2uiState = applyA2uiOperations(this.a2uiState, operations).state;\n }\n\n private a2uiSurfaceParts(): ThreadAssistantMessagePart[] {\n const parts: ThreadAssistantMessagePart[] = [];\n for (const [surfaceId, surface] of this.a2uiState) {\n const { spec } = convertSurfaceToUISpec(surface);\n if (!spec) continue;\n parts.push({\n type: \"tool-call\",\n toolCallId: `a2ui:${surfaceId}`,\n toolName: \"present\",\n args: spec as unknown as ReadonlyJSONObject,\n argsText: JSON.stringify(spec),\n result: {},\n artifact: { a2ui: surfaceToOperations(surface) },\n });\n }\n return parts;\n }\n\n private withA2uiSurfaces(\n content: ThreadAssistantMessage[\"content\"],\n previousContent: ThreadAssistantMessage[\"content\"] = content,\n ): ThreadAssistantMessage[\"content\"] {\n const preserved = content.filter(\n (part) =>\n !(part.type === \"tool-call\" && part.toolCallId.startsWith(\"a2ui:\")),\n );\n const interactionSource = [...previousContent, ...content];\n return this.withPreservedToolInteractions(interactionSource, [\n ...preserved,\n ...this.a2uiSurfaceParts(),\n ]);\n }\n\n private withPreservedToolInteractions(\n previousContent: ThreadAssistantMessage[\"content\"],\n content: ThreadAssistantMessage[\"content\"],\n ): ThreadAssistantMessage[\"content\"] {\n const interactions = new Map<\n string,\n ToolCallMessagePart[\"unstable_interactions\"]\n >();\n for (const part of previousContent) {\n if (\n part.type === \"tool-call\" &&\n part.unstable_interactions !== undefined\n ) {\n interactions.set(part.toolCallId, part.unstable_interactions);\n }\n }\n if (interactions.size === 0) return content;\n return content.map((part) => {\n if (\n part.type !== \"tool-call\" ||\n part.unstable_interactions !== undefined\n ) {\n return part;\n }\n const unstable_interactions = interactions.get(part.toolCallId);\n return unstable_interactions === undefined\n ? part\n : { ...part, unstable_interactions };\n });\n }\n\n private rebuildAssistantA2uiSurfaces(messageId: string) {\n const touched = this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n return {\n ...message,\n content: this.withA2uiSurfaces(message.content),\n };\n });\n if (touched) this.notifyUpdate();\n }\n\n private updateAssistantArtifacts(messageId: string) {\n const touched = this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n const custom = message.metadata.custom;\n const a2a = isRecord(custom.a2a) ? custom.a2a : {};\n return {\n ...message,\n metadata: {\n ...message.metadata,\n custom: {\n ...custom,\n a2a: {\n ...a2a,\n artifacts: this.currentArtifacts.map(storedArtifact),\n },\n },\n },\n };\n });\n if (touched) this.notifyUpdate();\n }\n\n private updateAssistantStatus(messageId: string, status: MessageStatus) {\n const touched = this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n return { ...message, status };\n });\n if (touched) {\n this.notifyUpdate();\n if (this.isPersistableAssistantStatus(status)) {\n this.persistAssistantHistory(messageId);\n }\n }\n }\n\n private getAssistantStatus(messageId: string): MessageStatus | undefined {\n const msg = this.session.tryGetMessage(messageId)?.message;\n if (msg?.role !== \"assistant\") return undefined;\n return msg.status;\n }\n\n private isPersistableAssistantStatus(status: MessageStatus): boolean {\n return (\n status.type === \"complete\" ||\n status.type === \"incomplete\" ||\n (status.type === \"requires-action\" && status.reason === \"interrupt\")\n );\n }\n\n // --- Lifecycle helpers ---\n\n private setRunning(running: boolean) {\n this.isRunningFlag = running;\n this.notifyUpdate();\n }\n\n private finishRun(controller: AbortController | null) {\n if (this.abortController !== controller) return;\n this.abortController = null;\n this.setRunning(false);\n }\n\n // --- History persistence ---\n\n private recordHistoryEntry(parentId: string | null, message: ThreadMessage) {\n void this.appendHistoryItem(parentId, message)?.catch((error) => {\n console.error(\"[react-a2a] failed to append history entry\", error);\n });\n }\n\n private markPendingAssistantHistory(\n messageId: string,\n parentId: string | null,\n ) {\n if (!this.history) return;\n this.assistantHistoryParents.set(messageId, parentId);\n }\n\n private persistAssistantHistory(messageId: string) {\n if (!this.history) return;\n const messageData = this.session.tryGetMessage(messageId);\n const parentId = this.assistantHistoryParents.get(messageId);\n if (parentId === undefined && !this.recordedHistoryIds.has(messageId)) {\n return;\n }\n const resolvedParentId =\n parentId === undefined ? messageData?.parentId : parentId;\n if (resolvedParentId === undefined) return;\n const message = messageData?.message;\n if (!message || message.role !== \"assistant\") return;\n if (!this.isPersistableAssistantStatus(message.status)) return;\n const isPausing = message.status.type === \"requires-action\";\n\n if (isPausing && !this.history.update) return;\n\n if (this.recordedHistoryIds.has(messageId)) {\n if (this.history.update) {\n const update = this.history.update.bind(this.history);\n const write = this.chainHistoryWrite(messageId, () =>\n update({ parentId: resolvedParentId, message }),\n );\n if (!isPausing) {\n this.assistantHistoryParents.delete(messageId);\n }\n void write.then(\n () => {\n this.recordedHistoryIds.add(messageId);\n },\n (error) => {\n const pending = this.historyWrites.get(messageId);\n if (pending === undefined || pending === write) {\n this.assistantHistoryParents.set(messageId, resolvedParentId);\n }\n console.error(\"[react-a2a] failed to update history entry\", error);\n },\n );\n return;\n }\n if (!isPausing) {\n this.assistantHistoryParents.delete(messageId);\n }\n return;\n }\n const write = this.appendHistoryItem(resolvedParentId, message);\n if (!write) return;\n if (!isPausing) {\n this.assistantHistoryParents.delete(messageId);\n }\n void write.catch((error) => {\n const pending = this.historyWrites.get(messageId);\n if (pending === undefined || pending === write) {\n this.assistantHistoryParents.set(messageId, resolvedParentId);\n }\n console.error(\"[react-a2a] failed to append history entry\", error);\n });\n }\n\n private appendHistoryItem(\n parentId: string | null,\n message: ThreadMessage,\n ): Promise<void> | undefined {\n if (!this.history || this.recordedHistoryIds.has(message.id)) return;\n this.recordedHistoryIds.add(message.id);\n const append = this.history.append.bind(this.history);\n const write = this.chainHistoryWrite(message.id, () =>\n append({ parentId, message }),\n );\n void write.catch(() => {\n this.recordedHistoryIds.delete(message.id);\n });\n return write;\n }\n\n private chainHistoryWrite(\n id: string,\n write: () => Promise<void>,\n ): Promise<void> {\n const pending = this.historyWrites.get(id);\n let next: Promise<void>;\n if (pending) {\n next = pending.then(write, write);\n } else {\n try {\n next = Promise.resolve(write());\n } catch (error) {\n next = Promise.reject(error);\n }\n }\n this.historyWrites.set(id, next);\n void next.then(\n () => {\n if (this.historyWrites.get(id) === next) {\n this.historyWrites.delete(id);\n }\n },\n () => {\n if (this.historyWrites.get(id) === next) {\n this.historyWrites.delete(id);\n }\n },\n );\n return next;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"A2AThreadRuntimeCore.js","names":["isRecord"],"sources":["../src/A2AThreadRuntimeCore.ts"],"sourcesContent":["\"use client\";\n\nimport { generateId, fromThreadMessageLike } from \"@assistant-ui/core\";\nimport type {\n AppendMessage,\n AssistantRuntime,\n ExportedMessageRepository,\n MessageStatus,\n ThreadAssistantMessage,\n ThreadAssistantMessagePart,\n ThreadHistoryAdapter,\n ThreadMessage,\n ToolCallMessagePart,\n Unstable_RecordToolInteractionOptions,\n} from \"@assistant-ui/core\";\nimport {\n appendToolInteraction,\n createMessageRepositorySession,\n invokeUserCallback,\n} from \"@assistant-ui/core/internal\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport {\n applyA2uiOperations,\n convertSurfaceToUISpec,\n surfaceToOperations,\n type A2uiState,\n} from \"@assistant-ui/react-generative-ui/a2ui\";\nimport type { A2AClient } from \"./A2AClient\";\nimport type {\n A2AArtifact,\n A2AAgentCard,\n A2AMessage,\n A2ASendMessageConfiguration,\n A2AStreamEvent,\n A2ATask,\n A2ATaskArtifactUpdateEvent,\n A2ATaskStatusUpdateEvent,\n} from \"./types\";\n\nimport {\n a2aMessageToContent,\n a2uiPartsToOperations,\n isTerminalTaskState,\n threadMessageToA2AMessage,\n taskStateToMessageStatus,\n} from \"./conversions\";\n\nconst INITIAL_AGENT_CARD_RETRY_DELAY_MS = 5_000;\nconst MAX_AGENT_CARD_RETRY_DELAY_MS = 5 * 60_000;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst storedArtifact = (artifact: A2AArtifact): A2AArtifact => ({\n ...artifact,\n parts: artifact.parts.map(({ raw: _raw, ...part }) => part),\n});\n\nexport type A2AThreadRuntimeCoreOptions = {\n client: A2AClient;\n contextId?: string | undefined;\n configuration?: A2ASendMessageConfiguration | undefined;\n onError?: ((error: Error) => void) | undefined;\n onCancel?: (() => void) | undefined;\n onArtifactComplete?: ((artifact: A2AArtifact) => void) | undefined;\n history?: ThreadHistoryAdapter | undefined;\n notifyUpdate: () => void;\n};\n\nconst FALLBACK_USER_STATUS = {\n type: \"complete\",\n reason: \"unknown\",\n} as const;\n\ntype A2ARuntimeCallbackName = \"onError\" | \"onCancel\" | \"onArtifactComplete\";\n\nconst invokeRuntimeCallback = <TArgs extends readonly unknown[]>(\n name: A2ARuntimeCallbackName,\n callback: ((...args: TArgs) => unknown) | undefined,\n ...args: TArgs\n): void => {\n void invokeUserCallback(\"react-a2a\", name, callback, ...args);\n};\n\nfunction normalizeArtifact(artifact: A2AArtifact): A2AArtifact {\n return {\n ...artifact,\n parts: Array.isArray(artifact.parts) ? artifact.parts : [],\n };\n}\n\nexport class A2AThreadRuntimeCore {\n private client: A2AClient;\n private contextId: string | undefined;\n private configuration: A2ASendMessageConfiguration | undefined;\n private onError: ((error: Error) => void) | undefined;\n private onCancel: (() => void) | undefined;\n private onArtifactComplete: ((artifact: A2AArtifact) => void) | undefined;\n private history: ThreadHistoryAdapter | undefined;\n private readonly notifyUpdate: () => void;\n\n private runtime: AssistantRuntime | undefined;\n private readonly session = createMessageRepositorySession();\n private isRunningFlag = false;\n private abortController: AbortController | null = null;\n private runGeneration = 0;\n private pendingError: Error | null = null;\n\n // A2A-specific state\n private currentTask: A2ATask | undefined;\n private currentArtifacts: A2AArtifact[] = [];\n private a2uiState: A2uiState = new Map();\n private readonly a2uiMessageIds = new Set<string>();\n private agentCardValue: A2AAgentCard | undefined;\n\n // History tracking\n private readonly assistantHistoryParents = new Map<string, string | null>();\n private readonly recordedHistoryIds = new Set<string>();\n private readonly historyWrites = new Map<string, Promise<void>>();\n private _isLoading = false;\n private _loadPromise: Promise<void> | undefined;\n private _historyLoadGeneration = 0;\n private _loadRequested = false;\n private _agentCardPromise: Promise<void> | undefined;\n private _agentCardRetryAfter = 0;\n private _agentCardRetryDelay = INITIAL_AGENT_CARD_RETRY_DELAY_MS;\n private _agentCardDiscoveryFailed = false;\n\n private lastOptionsContextId: string | undefined;\n\n constructor(options: A2AThreadRuntimeCoreOptions) {\n this.client = options.client;\n this.contextId = options.contextId;\n this.lastOptionsContextId = options.contextId;\n this.configuration = options.configuration;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.onArtifactComplete = options.onArtifactComplete;\n this.history = options.history;\n this.notifyUpdate = options.notifyUpdate;\n }\n\n updateOptions(options: Omit<A2AThreadRuntimeCoreOptions, \"notifyUpdate\">) {\n this.client = options.client;\n // The hook re-applies options on every render, including renders caused\n // by this core's own notifyUpdate. The option only seeds the context: a\n // re-render with the same value must not clobber a server-assigned\n // contextId learned from the stream.\n if (options.contextId !== this.lastOptionsContextId) {\n this.contextId = options.contextId;\n this.lastOptionsContextId = options.contextId;\n }\n this.configuration = options.configuration;\n this.onError = options.onError;\n this.onCancel = options.onCancel;\n this.onArtifactComplete = options.onArtifactComplete;\n const previousHistory = this.history;\n this.history = options.history;\n\n if (\n this._loadRequested &&\n !this._loadPromise &&\n !previousHistory &&\n options.history &&\n this.session.getMessages().length === 0\n ) {\n void this.__internal_load();\n }\n }\n\n /** Thread-boundary reset: applyExternalMessages alone also serves branch\n * switches, deletes, and cancel resyncs, which must keep the live context. */\n resetContext(): void {\n this._historyLoadGeneration++;\n this._isLoading = false;\n // Restore the seed before aborting: an onCancel callback that starts a\n // new run must not pick up the old thread's context, and its controller\n // must not be discarded.\n const controller = this.abortController;\n this.contextId = this.lastOptionsContextId;\n if (controller) {\n controller.abort();\n if (this.abortController === controller) {\n this.abortController = null;\n }\n }\n }\n\n attachRuntime(runtime: AssistantRuntime) {\n this.runtime = runtime;\n }\n\n detachRuntime() {\n this.runtime = undefined;\n // Abort in-flight requests on unmount\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n }\n\n getRuntime(): AssistantRuntime | undefined {\n return this.runtime;\n }\n\n getMessages(): readonly ThreadMessage[] {\n return this.session.getMessages();\n }\n\n getMessageRepository(): ExportedMessageRepository {\n return this.session.export();\n }\n\n public async recordToolInteraction({\n messageId,\n toolCallId,\n interaction,\n }: Unstable_RecordToolInteractionOptions): Promise<void> {\n const message = this.session.tryGetMessage(messageId)?.message;\n if (!message) {\n throw new Error(\n \"Tried to record a tool interaction on a non-existing message\",\n );\n }\n if (message.role !== \"assistant\") {\n throw new Error(\n \"Tried to record a tool interaction on a non-assistant message\",\n );\n }\n const target = message.content.find(\n (part) => part.type === \"tool-call\" && part.toolCallId === toolCallId,\n );\n if (!target || target.type !== \"tool-call\") {\n throw new Error(\n \"Tried to record a tool interaction on a non-existing tool call\",\n );\n }\n\n const touched = this.session.updateMessage(messageId, (current) => {\n if (current.role !== \"assistant\") return current;\n return {\n ...current,\n content: current.content.map((part) =>\n part.type === \"tool-call\" && part.toolCallId === toolCallId\n ? {\n ...part,\n unstable_interactions: appendToolInteraction(\n part.unstable_interactions,\n interaction,\n ),\n }\n : part,\n ),\n };\n });\n if (touched) {\n this.notifyUpdate();\n this.persistAssistantHistory(messageId);\n }\n }\n\n getTask(): A2ATask | undefined {\n return this.currentTask;\n }\n\n getArtifacts(): readonly A2AArtifact[] {\n return this.currentArtifacts;\n }\n\n getAgentCard(): A2AAgentCard | undefined {\n return this.agentCardValue;\n }\n\n isRunning(): boolean {\n return this.isRunningFlag;\n }\n\n get isLoading(): boolean {\n return this._isLoading;\n }\n\n private loadAgentCard(): Promise<void> {\n if (Date.now() < this._agentCardRetryAfter) return Promise.resolve();\n\n this._agentCardPromise ??= this.client.getAgentCard().then(\n (agentCard) => {\n this.agentCardValue = agentCard;\n this._agentCardRetryAfter = 0;\n this._agentCardRetryDelay = INITIAL_AGENT_CARD_RETRY_DELAY_MS;\n this._agentCardDiscoveryFailed = false;\n this.notifyUpdate();\n },\n () => {\n this._agentCardDiscoveryFailed = true;\n this._agentCardRetryAfter = Date.now() + this._agentCardRetryDelay;\n this._agentCardRetryDelay = Math.min(\n this._agentCardRetryDelay * 2,\n MAX_AGENT_CARD_RETRY_DELAY_MS,\n );\n this._agentCardPromise = undefined;\n },\n );\n return this._agentCardPromise;\n }\n\n private async waitForAgentCard(signal: AbortSignal): Promise<boolean> {\n const shouldWait = !this._agentCardDiscoveryFailed;\n const load = this.loadAgentCard();\n if (signal.aborted) return false;\n if (!shouldWait) return true;\n\n let onAbort!: () => void;\n const abort = new Promise<void>((resolve) => {\n onAbort = resolve;\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n\n try {\n await Promise.race([load, abort]);\n } finally {\n signal.removeEventListener(\"abort\", onAbort);\n }\n return !signal.aborted;\n }\n\n __internal_load(): Promise<void> {\n this._loadRequested = true;\n const agentCardPromise = this.loadAgentCard();\n\n if (this._loadPromise) return this._loadPromise;\n if (!this.history) return agentCardPromise;\n\n this._isLoading = true;\n\n const generation = this._historyLoadGeneration;\n const historyPromise = this.history.load();\n\n this._loadPromise = historyPromise\n .then((repo) => {\n if (generation !== this._historyLoadGeneration) return;\n if (repo) {\n this.session.applyExternalMessageRepository(repo);\n this.finalizeExternalApply();\n }\n })\n .catch((error) => {\n if (generation !== this._historyLoadGeneration) return;\n invokeRuntimeCallback(\n \"onError\",\n this.onError,\n error instanceof Error ? error : new Error(String(error)),\n );\n })\n .finally(() => {\n if (generation !== this._historyLoadGeneration) return;\n this._isLoading = false;\n this.notifyUpdate();\n });\n\n this.notifyUpdate();\n return this._loadPromise;\n }\n\n async append(message: AppendMessage): Promise<void> {\n const startRun = message.startRun ?? message.role === \"user\";\n\n const threadMessage = fromThreadMessageLike(\n message as any,\n generateId(),\n FALLBACK_USER_STATUS,\n );\n const parentId =\n message.parentId === null\n ? null\n : message.parentId && this.session.hasMessage(message.parentId)\n ? message.parentId\n : this.session.headId;\n this.session.addOrUpdateMessage(parentId, threadMessage);\n this.session.switchToBranch(threadMessage.id);\n this.notifyUpdate();\n this.recordHistoryEntry(parentId, threadMessage);\n\n if (!startRun) return;\n await this.startRun(threadMessage);\n }\n\n appendVoiceTranscript(message: ThreadMessage): void {\n const parentId = this.session.headId;\n this.session.addOrUpdateMessage(parentId, message);\n this.session.switchToBranch(message.id);\n this.notifyUpdate();\n this.recordHistoryEntry(parentId, message);\n }\n\n async edit(message: AppendMessage): Promise<void> {\n await this.append(message);\n }\n\n async reload(\n parentId: string | null,\n _config: { runConfig?: Record<string, unknown> } = {},\n ): Promise<void> {\n const messages =\n parentId === null\n ? []\n : (this.session.tryGetMessages(parentId) ?? this.getMessages());\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"user\") {\n await this.startRun(messages[i]!);\n return;\n }\n }\n }\n\n async cancel(): Promise<void> {\n if (!this.abortController) return;\n\n // Read the server target before aborting: the abort listener runs the\n // onCancel callback synchronously, which may clear the thread and with it\n // the task this cancellation is for, or start a new run.\n const task = this.currentTask;\n const generation = this.runGeneration;\n\n // Abort locally first so the stream stops immediately\n this.abortController.abort();\n\n // Then try to cancel the task on the server\n if (task?.id) {\n try {\n const updated = await this.client.cancelTask(task.id);\n // Only apply the response while nothing newer exists. A newer snapshot\n // or a cleared thread replaces the task object; a follow-up run that\n // has not emitted yet keeps it, so the run generation is what rules\n // that case out.\n if (this.currentTask === task && this.runGeneration === generation) {\n this.currentTask = updated;\n this.notifyUpdate();\n }\n } catch {\n // Server cancel failed; local abort already handled\n }\n }\n }\n\n private appendLinearChain(messages: readonly ThreadMessage[]): string | null {\n let parentId: string | null = null;\n let lastId: string | null = null;\n const seen = new Set<string>();\n\n for (const message of messages) {\n if (seen.has(message.id)) continue;\n seen.add(message.id);\n this.session.addOrUpdateMessage(parentId, message);\n parentId = message.id;\n lastId = message.id;\n }\n\n return lastId;\n }\n\n private finalizeExternalApply(): void {\n this.assistantHistoryParents.clear();\n this.recordedHistoryIds.clear();\n for (const { message } of this.getMessageRepository().messages) {\n this.recordedHistoryIds.add(message.id);\n }\n this.currentTask = undefined;\n this.currentArtifacts = [];\n this.a2uiState = new Map();\n this.a2uiMessageIds.clear();\n this.notifyUpdate();\n }\n\n applyExternalMessages(messages: readonly ThreadMessage[]): void {\n if (messages.length === 0) {\n this.session.clear();\n } else {\n let expectedParentId: string | null = null;\n let lastAppliedId: string | null = null;\n let hardReplace = false;\n const seen = new Set<string>();\n\n for (const message of messages) {\n if (seen.has(message.id)) continue;\n seen.add(message.id);\n const existing = this.session.tryGetMessage(message.id);\n if (existing && existing.parentId !== expectedParentId) {\n hardReplace = true;\n break;\n }\n this.session.addOrUpdateMessage(expectedParentId, message);\n expectedParentId = message.id;\n lastAppliedId = message.id;\n }\n\n if (hardReplace) {\n this.session.clear();\n lastAppliedId = this.appendLinearChain(messages);\n }\n\n this.session.resetHead(lastAppliedId);\n }\n\n this.finalizeExternalApply();\n }\n\n // --- Run logic ---\n\n private async startRun(userThreadMessage: ThreadMessage): Promise<void> {\n this.runGeneration++;\n\n // Cancel any in-progress run before starting a new one\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n\n const a2aMessage = threadMessageToA2AMessage(userThreadMessage, {\n contextId: this.contextId,\n taskId:\n this.currentTask?.id &&\n !isTerminalTaskState(this.currentTask.status.state)\n ? this.currentTask.id\n : undefined,\n });\n\n // Clear task if previous task reached terminal state\n if (\n this.currentTask &&\n isTerminalTaskState(this.currentTask.status.state)\n ) {\n this.currentTask = undefined;\n }\n\n this.currentArtifacts = [];\n this.a2uiState = new Map();\n this.a2uiMessageIds.clear();\n\n const assistantParentId = userThreadMessage.id;\n const assistantId = this.insertAssistantPlaceholder(assistantParentId);\n this.markPendingAssistantHistory(assistantId, assistantParentId);\n\n const abortController = new AbortController();\n this.abortController = abortController;\n\n abortController.signal.addEventListener(\n \"abort\",\n () => {\n this.updateAssistantStatus(assistantId, {\n type: \"incomplete\",\n reason: \"cancelled\",\n });\n this.finishRun(abortController);\n invokeRuntimeCallback(\"onCancel\", this.onCancel);\n },\n { once: true },\n );\n\n this.setRunning(true);\n\n try {\n if (!(await this.waitForAgentCard(abortController.signal))) return;\n\n const supportsStreaming =\n this.agentCardValue?.capabilities?.streaming !== false;\n if (supportsStreaming) {\n await this.runStreaming(a2aMessage, assistantId, abortController);\n } else {\n await this.runSync(a2aMessage, assistantId, abortController);\n }\n } catch (error) {\n if (!abortController.signal.aborted) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.updateAssistantStatus(assistantId, {\n type: \"incomplete\",\n reason: \"error\",\n });\n invokeRuntimeCallback(\"onError\", this.onError, err);\n this.pendingError = this.pendingError ?? err;\n }\n } finally {\n this.finishRun(abortController);\n }\n\n if (this.pendingError) {\n const err = this.pendingError;\n this.pendingError = null;\n throw err;\n }\n }\n\n private async runStreaming(\n a2aMessage: A2AMessage,\n assistantId: string,\n abortController: AbortController,\n ): Promise<void> {\n const stream = this.client.streamMessage(\n a2aMessage,\n this.configuration,\n undefined, // metadata\n abortController.signal,\n );\n\n let receivedEvent = false;\n let skipReason: string | undefined;\n const diagnosedStream = (async function* () {\n const reason = yield* stream;\n if (typeof reason === \"string\") skipReason = reason;\n })();\n\n for await (const event of diagnosedStream) {\n if (abortController.signal.aborted) break;\n receivedEvent = true;\n this.handleStreamEvent(assistantId, event);\n }\n\n if (!abortController.signal.aborted) {\n if (!receivedEvent) {\n throw new Error(\n skipReason\n ? `A2A message stream ended without any events. First skipped frame: ${skipReason}`\n : \"A2A message stream ended without any events.\",\n );\n }\n\n const lastStatus = this.getAssistantStatus(assistantId);\n if (lastStatus?.type === \"running\") {\n this.updateAssistantStatus(assistantId, {\n type: \"complete\",\n reason: \"stop\",\n });\n }\n }\n }\n\n private async runSync(\n a2aMessage: A2AMessage,\n assistantId: string,\n abortController: AbortController,\n ): Promise<void> {\n const result = await this.client.sendMessage(\n a2aMessage,\n this.configuration,\n undefined, // metadata\n abortController.signal,\n );\n\n if (abortController.signal.aborted) return;\n\n // Result is either A2ATask or A2AMessage\n if (\"id\" in result && \"status\" in result) {\n // It's a Task\n this.handleTaskSnapshot(assistantId, result as A2ATask);\n } else if (\"messageId\" in result && \"parts\" in result) {\n // It's a Message\n this.handleMessage(assistantId, result as A2AMessage);\n this.updateAssistantStatus(assistantId, {\n type: \"complete\",\n reason: \"stop\",\n });\n }\n }\n\n private handleStreamEvent(assistantId: string, event: A2AStreamEvent) {\n switch (event.type) {\n case \"statusUpdate\":\n this.handleStatusUpdate(assistantId, event.event);\n break;\n case \"artifactUpdate\":\n this.handleArtifactUpdate(assistantId, event.event);\n break;\n case \"message\":\n this.handleMessage(assistantId, event.message);\n break;\n case \"task\":\n this.handleTaskSnapshot(assistantId, event.task);\n break;\n }\n }\n\n private handleStatusUpdate(\n assistantId: string,\n event: A2ATaskStatusUpdateEvent,\n ) {\n if (!this.currentTask) {\n this.currentTask = {\n id: event.taskId,\n contextId: event.contextId,\n status: event.status,\n };\n } else {\n this.currentTask = { ...this.currentTask, status: event.status };\n }\n\n if (event.contextId) {\n this.contextId = event.contextId;\n }\n\n if (event.status.message) {\n this.applyA2uiMessage(event.status.message);\n const content = a2aMessageToContent(event.status.message);\n this.updateAssistantContent(assistantId, content);\n }\n\n const status = taskStateToMessageStatus(event.status.state);\n this.updateAssistantStatus(assistantId, status);\n\n this.notifyUpdate();\n }\n\n private handleArtifactUpdate(\n assistantId: string,\n event: A2ATaskArtifactUpdateEvent,\n ) {\n const { append, lastChunk } = event;\n const artifact = normalizeArtifact(event.artifact);\n const existingIdx = this.currentArtifacts.findIndex(\n (a) => a.artifactId === artifact.artifactId,\n );\n\n let updated: A2AArtifact;\n if (existingIdx >= 0 && append) {\n const existing = this.currentArtifacts[existingIdx]!;\n updated = {\n ...existing,\n parts: [...existing.parts, ...artifact.parts],\n };\n this.currentArtifacts = [\n ...this.currentArtifacts.slice(0, existingIdx),\n updated,\n ...this.currentArtifacts.slice(existingIdx + 1),\n ];\n } else if (existingIdx >= 0) {\n updated = artifact;\n this.currentArtifacts = [\n ...this.currentArtifacts.slice(0, existingIdx),\n updated,\n ...this.currentArtifacts.slice(existingIdx + 1),\n ];\n } else {\n updated = artifact;\n this.currentArtifacts = [...this.currentArtifacts, updated];\n }\n\n this.applyA2uiParts(artifact.parts);\n this.updateAssistantArtifacts(assistantId);\n this.rebuildAssistantA2uiSurfaces(assistantId);\n\n if (lastChunk) {\n invokeRuntimeCallback(\n \"onArtifactComplete\",\n this.onArtifactComplete,\n updated,\n );\n }\n\n this.notifyUpdate();\n }\n\n private handleMessage(assistantId: string, message: A2AMessage) {\n if (message.role !== \"agent\") return;\n\n this.applyA2uiMessage(message);\n const content = a2aMessageToContent(message);\n this.updateAssistantContent(assistantId, content);\n this.notifyUpdate();\n }\n\n private handleTaskSnapshot(assistantId: string, task: A2ATask) {\n const artifacts =\n task.artifacts === undefined\n ? undefined\n : Array.isArray(task.artifacts)\n ? task.artifacts.map(normalizeArtifact)\n : [];\n const history =\n task.history === undefined\n ? undefined\n : Array.isArray(task.history)\n ? task.history\n : [];\n this.currentTask = {\n ...task,\n ...(artifacts === undefined ? {} : { artifacts }),\n ...(history === undefined ? {} : { history }),\n };\n\n if (task.contextId) {\n this.contextId = task.contextId;\n }\n const isCompleteSnapshot = history !== undefined && artifacts !== undefined;\n const artifactsToApply = isCompleteSnapshot\n ? artifacts\n : artifacts?.filter(\n (artifact) =>\n !this.currentArtifacts.some(\n ({ artifactId }) => artifactId === artifact.artifactId,\n ),\n );\n\n if (isCompleteSnapshot) {\n this.currentArtifacts = artifacts;\n this.a2uiState = new Map();\n this.a2uiMessageIds.clear();\n } else if (artifactsToApply) {\n this.currentArtifacts = [...this.currentArtifacts, ...artifactsToApply];\n }\n\n for (const message of history ?? []) {\n if (message.role === \"agent\") this.applyA2uiMessage(message, true);\n }\n for (const artifact of artifactsToApply ?? []) {\n this.applyA2uiParts(artifact.parts);\n }\n if (task.status.message) {\n this.applyA2uiMessage(task.status.message, true);\n }\n\n if (isCompleteSnapshot || artifactsToApply?.length) {\n this.updateAssistantArtifacts(assistantId);\n }\n\n if (task.status.message) {\n const content = a2aMessageToContent(task.status.message);\n this.updateAssistantContent(assistantId, content);\n } else {\n this.rebuildAssistantA2uiSurfaces(assistantId);\n }\n\n const status = taskStateToMessageStatus(task.status.state);\n this.updateAssistantStatus(assistantId, status);\n\n this.notifyUpdate();\n }\n\n // --- Message helpers ---\n\n private insertAssistantPlaceholder(parentId: string): string {\n const id = generateId();\n const assistant: ThreadAssistantMessage = {\n id,\n role: \"assistant\",\n createdAt: new Date(),\n status: { type: \"running\" },\n content: [],\n metadata: {\n unstable_state: null,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n custom: {},\n },\n };\n this.session.addOrUpdateMessage(parentId, assistant);\n this.session.switchToBranch(id);\n this.notifyUpdate();\n return id;\n }\n\n private updateAssistantContent(\n messageId: string,\n content: ThreadAssistantMessage[\"content\"],\n ) {\n this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n return {\n ...message,\n content: this.withA2uiSurfaces(content, message.content),\n };\n });\n }\n\n private applyA2uiMessage(message: A2AMessage, replay = false) {\n if (message.messageId) {\n if (replay && this.a2uiMessageIds.has(message.messageId)) return;\n this.a2uiMessageIds.add(message.messageId);\n }\n this.applyA2uiParts(message.parts);\n }\n\n private applyA2uiParts(parts: readonly A2AMessage[\"parts\"][number][]) {\n const operations = a2uiPartsToOperations(parts);\n if (operations.length === 0) return;\n this.a2uiState = applyA2uiOperations(this.a2uiState, operations).state;\n }\n\n private a2uiSurfaceParts(): ThreadAssistantMessagePart[] {\n const parts: ThreadAssistantMessagePart[] = [];\n for (const [surfaceId, surface] of this.a2uiState) {\n const { spec } = convertSurfaceToUISpec(surface);\n if (!spec) continue;\n parts.push({\n type: \"tool-call\",\n toolCallId: `a2ui:${surfaceId}`,\n toolName: \"present\",\n args: spec as unknown as ReadonlyJSONObject,\n argsText: JSON.stringify(spec),\n result: {},\n artifact: { a2ui: surfaceToOperations(surface) },\n });\n }\n return parts;\n }\n\n private withA2uiSurfaces(\n content: ThreadAssistantMessage[\"content\"],\n previousContent: ThreadAssistantMessage[\"content\"] = content,\n ): ThreadAssistantMessage[\"content\"] {\n const preserved = content.filter(\n (part) =>\n !(part.type === \"tool-call\" && part.toolCallId.startsWith(\"a2ui:\")),\n );\n const interactionSource = [...previousContent, ...content];\n return this.withPreservedToolInteractions(interactionSource, [\n ...preserved,\n ...this.a2uiSurfaceParts(),\n ]);\n }\n\n private withPreservedToolInteractions(\n previousContent: ThreadAssistantMessage[\"content\"],\n content: ThreadAssistantMessage[\"content\"],\n ): ThreadAssistantMessage[\"content\"] {\n const interactions = new Map<\n string,\n ToolCallMessagePart[\"unstable_interactions\"]\n >();\n for (const part of previousContent) {\n if (\n part.type === \"tool-call\" &&\n part.unstable_interactions !== undefined\n ) {\n interactions.set(part.toolCallId, part.unstable_interactions);\n }\n }\n if (interactions.size === 0) return content;\n return content.map((part) => {\n if (\n part.type !== \"tool-call\" ||\n part.unstable_interactions !== undefined\n ) {\n return part;\n }\n const unstable_interactions = interactions.get(part.toolCallId);\n return unstable_interactions === undefined\n ? part\n : { ...part, unstable_interactions };\n });\n }\n\n private rebuildAssistantA2uiSurfaces(messageId: string) {\n const touched = this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n return {\n ...message,\n content: this.withA2uiSurfaces(message.content),\n };\n });\n if (touched) this.notifyUpdate();\n }\n\n private updateAssistantArtifacts(messageId: string) {\n const touched = this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n const custom = message.metadata.custom;\n const a2a = isRecord(custom.a2a) ? custom.a2a : {};\n return {\n ...message,\n metadata: {\n ...message.metadata,\n custom: {\n ...custom,\n a2a: {\n ...a2a,\n artifacts: this.currentArtifacts.map(storedArtifact),\n },\n },\n },\n };\n });\n if (touched) this.notifyUpdate();\n }\n\n private updateAssistantStatus(messageId: string, status: MessageStatus) {\n const touched = this.session.updateMessage(messageId, (message) => {\n if (message.role !== \"assistant\") return message;\n return { ...message, status };\n });\n if (touched) {\n this.notifyUpdate();\n if (this.isPersistableAssistantStatus(status)) {\n this.persistAssistantHistory(messageId);\n }\n }\n }\n\n private getAssistantStatus(messageId: string): MessageStatus | undefined {\n const msg = this.session.tryGetMessage(messageId)?.message;\n if (msg?.role !== \"assistant\") return undefined;\n return msg.status;\n }\n\n private isPersistableAssistantStatus(status: MessageStatus): boolean {\n return (\n status.type === \"complete\" ||\n status.type === \"incomplete\" ||\n (status.type === \"requires-action\" && status.reason === \"interrupt\")\n );\n }\n\n // --- Lifecycle helpers ---\n\n private setRunning(running: boolean) {\n this.isRunningFlag = running;\n this.notifyUpdate();\n }\n\n private finishRun(controller: AbortController | null) {\n if (this.abortController !== controller) return;\n this.abortController = null;\n this.setRunning(false);\n }\n\n // --- History persistence ---\n\n private recordHistoryEntry(parentId: string | null, message: ThreadMessage) {\n void this.appendHistoryItem(parentId, message)?.catch((error) => {\n console.error(\"[react-a2a] failed to append history entry\", error);\n });\n }\n\n private markPendingAssistantHistory(\n messageId: string,\n parentId: string | null,\n ) {\n if (!this.history) return;\n this.assistantHistoryParents.set(messageId, parentId);\n }\n\n private persistAssistantHistory(messageId: string) {\n if (!this.history) return;\n const messageData = this.session.tryGetMessage(messageId);\n const parentId = this.assistantHistoryParents.get(messageId);\n if (parentId === undefined && !this.recordedHistoryIds.has(messageId)) {\n return;\n }\n const resolvedParentId =\n parentId === undefined ? messageData?.parentId : parentId;\n if (resolvedParentId === undefined) return;\n const message = messageData?.message;\n if (!message || message.role !== \"assistant\") return;\n if (!this.isPersistableAssistantStatus(message.status)) return;\n const isPausing = message.status.type === \"requires-action\";\n\n if (isPausing && !this.history.update) return;\n\n if (this.recordedHistoryIds.has(messageId)) {\n if (this.history.update) {\n const update = this.history.update.bind(this.history);\n const write = this.chainHistoryWrite(messageId, () =>\n update({ parentId: resolvedParentId, message }),\n );\n if (!isPausing) {\n this.assistantHistoryParents.delete(messageId);\n }\n void write.then(\n () => {\n this.recordedHistoryIds.add(messageId);\n },\n (error) => {\n const pending = this.historyWrites.get(messageId);\n if (pending === undefined || pending === write) {\n this.assistantHistoryParents.set(messageId, resolvedParentId);\n }\n console.error(\"[react-a2a] failed to update history entry\", error);\n },\n );\n return;\n }\n if (!isPausing) {\n this.assistantHistoryParents.delete(messageId);\n }\n return;\n }\n const write = this.appendHistoryItem(resolvedParentId, message);\n if (!write) return;\n if (!isPausing) {\n this.assistantHistoryParents.delete(messageId);\n }\n void write.catch((error) => {\n const pending = this.historyWrites.get(messageId);\n if (pending === undefined || pending === write) {\n this.assistantHistoryParents.set(messageId, resolvedParentId);\n }\n console.error(\"[react-a2a] failed to append history entry\", error);\n });\n }\n\n private appendHistoryItem(\n parentId: string | null,\n message: ThreadMessage,\n ): Promise<void> | undefined {\n if (!this.history || this.recordedHistoryIds.has(message.id)) return;\n this.recordedHistoryIds.add(message.id);\n const append = this.history.append.bind(this.history);\n const write = this.chainHistoryWrite(message.id, () =>\n append({ parentId, message }),\n );\n void write.catch(() => {\n this.recordedHistoryIds.delete(message.id);\n });\n return write;\n }\n\n private chainHistoryWrite(\n id: string,\n write: () => Promise<void>,\n ): Promise<void> {\n const pending = this.historyWrites.get(id);\n let next: Promise<void>;\n if (pending) {\n next = pending.then(write, write);\n } else {\n try {\n next = Promise.resolve(write());\n } catch (error) {\n next = Promise.reject(error);\n }\n }\n this.historyWrites.set(id, next);\n void next.then(\n () => {\n if (this.historyWrites.get(id) === next) {\n this.historyWrites.delete(id);\n }\n },\n () => {\n if (this.historyWrites.get(id) === next) {\n this.historyWrites.delete(id);\n }\n },\n );\n return next;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../src/conversions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EACtB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAK5B,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,mBAAgB;AAwBjE,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAarD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,OAAO,EAAE,CAGtE;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,OAAO,EAAE,GACxB,SAAS,OAAO,EAAE,CAGpB;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,GACZ,sBAAsB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../src/conversions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EACtB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAK5B,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,mBAAgB;AAwBjE,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAarD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,OAAO,EAAE,CAGtE;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,OAAO,EAAE,GACxB,SAAS,OAAO,EAAE,CAGpB;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,GACZ,sBAAsB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAwC3C;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EAAE,GACf,sBAAsB,CAAC,SAAS,CAAC,CAInC;AAcD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAEhE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAEnE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAkB3E;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IACtC,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CACtD,CAAC,EACF,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,EAAE,CA0EX;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,UAAU,GAClB,sBAAsB,CAAC,SAAS,CAAC,CAEnC;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxB,GACL,UAAU,CA6BZ"}
|
package/dist/conversions.js
CHANGED
|
@@ -27,11 +27,15 @@ function a2uiPartsToOperations(parts) {
|
|
|
27
27
|
return parts.flatMap(a2uiPartToOperations);
|
|
28
28
|
}
|
|
29
29
|
function a2aPartToContent(part) {
|
|
30
|
-
if (part
|
|
30
|
+
if (!isRecord$1(part)) return {
|
|
31
|
+
type: "text",
|
|
32
|
+
text: ""
|
|
33
|
+
};
|
|
34
|
+
if (part.text != null) return {
|
|
31
35
|
type: "text",
|
|
32
36
|
text: part.text
|
|
33
37
|
};
|
|
34
|
-
if (part.url
|
|
38
|
+
if (part.url != null) {
|
|
35
39
|
if (isImageMediaType(part.mediaType)) return {
|
|
36
40
|
type: "image",
|
|
37
41
|
image: part.url,
|
|
@@ -45,7 +49,7 @@ function a2aPartToContent(part) {
|
|
|
45
49
|
...part.filename && { filename: part.filename }
|
|
46
50
|
};
|
|
47
51
|
}
|
|
48
|
-
if (part.raw
|
|
52
|
+
if (part.raw != null) {
|
|
49
53
|
if (isImageMediaType(part.mediaType)) return {
|
|
50
54
|
type: "image",
|
|
51
55
|
image: `data:${part.mediaType};base64,${part.raw}`,
|
|
@@ -68,7 +72,7 @@ function a2aPartToContent(part) {
|
|
|
68
72
|
};
|
|
69
73
|
}
|
|
70
74
|
function a2aPartsToContent(parts) {
|
|
71
|
-
return (Array.isArray(parts) ? parts : []).filter((part) => !isA2uiDataPart(part)).map(a2aPartToContent);
|
|
75
|
+
return (Array.isArray(parts) ? parts : []).filter((part) => isRecord$1(part) && !isA2uiDataPart(part)).map(a2aPartToContent);
|
|
72
76
|
}
|
|
73
77
|
const TERMINAL_STATES = /* @__PURE__ */ new Set([
|
|
74
78
|
"completed",
|
package/dist/conversions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversions.js","names":["isRecord"],"sources":["../src/conversions.ts"],"sourcesContent":["\"use client\";\n\nimport type {\n MessageStatus,\n ThreadAssistantMessage,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport {\n parseDataUrl,\n resolveFilePartSource,\n} from \"@assistant-ui/core/internal\";\nimport type { A2AMessage, A2APart, A2ATaskState } from \"./types\";\n\nfunction isImageMediaType(mediaType?: string): boolean {\n return !!mediaType && mediaType.startsWith(\"image/\");\n}\n\nconst A2UI_OPERATION_KEYS = [\n \"createSurface\",\n \"updateComponents\",\n \"updateDataModel\",\n \"deleteSurface\",\n] as const;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isA2uiOperation = (value: unknown): boolean =>\n isRecord(value) &&\n typeof value.version === \"string\" &&\n A2UI_OPERATION_KEYS.some((key) => Object.hasOwn(value, key));\n\nconst hasA2uiMediaType = (value: unknown): boolean =>\n typeof value === \"string\" && value.toLowerCase().includes(\"a2ui\");\n\nexport function isA2uiDataPart(part: A2APart): boolean {\n if (part.data === undefined) return false;\n\n const metadata = isRecord(part.metadata) ? part.metadata : {};\n return (\n hasA2uiMediaType(part.mediaType) ||\n hasA2uiMediaType(metadata.mimeType) ||\n hasA2uiMediaType(metadata.mediaType) ||\n isA2uiOperation(part.data) ||\n (Array.isArray(part.data) &&\n part.data.length > 0 &&\n part.data.every(isA2uiOperation))\n );\n}\n\nexport function a2uiPartToOperations(part: A2APart): readonly unknown[] {\n if (!isA2uiDataPart(part)) return [];\n return Array.isArray(part.data) ? part.data : [part.data];\n}\n\nexport function a2uiPartsToOperations(\n parts: readonly A2APart[],\n): readonly unknown[] {\n if (!Array.isArray(parts)) return [];\n return parts.flatMap(a2uiPartToOperations);\n}\n\nexport function a2aPartToContent(\n part: A2APart,\n): ThreadAssistantMessage[\"content\"][number] {\n if (part.text !== undefined) {\n return { type: \"text\", text: part.text };\n }\n if (part.url !== undefined) {\n if (isImageMediaType(part.mediaType)) {\n return {\n type: \"image\",\n image: part.url,\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n type: \"file\",\n data: part.url,\n mimeType: part.mediaType ?? \"application/octet-stream\",\n sourceType: \"url\",\n ...(part.filename && { filename: part.filename }),\n };\n }\n if (part.raw !== undefined) {\n if (isImageMediaType(part.mediaType)) {\n return {\n type: \"image\",\n image: `data:${part.mediaType};base64,${part.raw}`,\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n type: \"file\",\n data: part.raw,\n mimeType: part.mediaType ?? \"application/octet-stream\",\n ...(part.filename && { filename: part.filename }),\n };\n }\n if (part.data !== undefined) {\n return { type: \"text\", text: JSON.stringify(part.data, null, 2) };\n }\n return { type: \"text\", text: \"\" };\n}\n\nexport function a2aPartsToContent(\n parts: A2APart[],\n): ThreadAssistantMessage[\"content\"] {\n return (Array.isArray(parts) ? parts : [])\n .filter((part) => !isA2uiDataPart(part))\n .map(a2aPartToContent);\n}\n\nconst TERMINAL_STATES = new Set<A2ATaskState>([\n \"completed\",\n \"failed\",\n \"canceled\",\n \"rejected\",\n]);\n\nconst INTERRUPTED_STATES = new Set<A2ATaskState>([\n \"input_required\",\n \"auth_required\",\n]);\n\nexport function isTerminalTaskState(state: A2ATaskState): boolean {\n return TERMINAL_STATES.has(state);\n}\n\nexport function isInterruptedTaskState(state: A2ATaskState): boolean {\n return INTERRUPTED_STATES.has(state);\n}\n\nexport function taskStateToMessageStatus(state: A2ATaskState): MessageStatus {\n switch (state) {\n case \"submitted\":\n case \"working\":\n return { type: \"running\" };\n case \"completed\":\n return { type: \"complete\", reason: \"stop\" };\n case \"failed\":\n case \"rejected\":\n return { type: \"incomplete\", reason: \"error\" };\n case \"canceled\":\n return { type: \"incomplete\", reason: \"cancelled\" };\n case \"input_required\":\n case \"auth_required\":\n return { type: \"requires-action\", reason: \"interrupt\" };\n default:\n return { type: \"running\" };\n }\n}\n\nexport function contentPartsToA2AParts(\n content: ReadonlyArray<{\n type: string;\n text?: string | undefined;\n image?: string | undefined;\n data?: unknown;\n mimeType?: string | undefined;\n filename?: string | undefined;\n sourceType?: \"url\" | \"id\" | undefined;\n audio?: { data: string; format: string } | undefined;\n }>,\n fallbackMimeType?: string,\n): A2APart[] {\n return content\n .map((part): A2APart | null => {\n switch (part.type) {\n case \"text\":\n return { text: part.text ?? \"\" };\n case \"image\": {\n if (!part.image) return null;\n const parsed = parseDataUrl(part.image);\n if (parsed) {\n return {\n raw: parsed.data,\n mediaType: parsed.mimeType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n url: part.image,\n ...(fallbackMimeType && { mediaType: fallbackMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n case \"file\": {\n if (typeof part.data !== \"string\") return null;\n const declaredMimeType = part.mimeType || fallbackMimeType;\n const source = resolveFilePartSource({\n data: part.data,\n mimeType: declaredMimeType ?? \"application/octet-stream\",\n sourceType: part.sourceType,\n });\n if (source.kind === \"url\") {\n return {\n url: source.url,\n ...(declaredMimeType && { mediaType: declaredMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n const parsed = parseDataUrl(part.data);\n if (parsed) {\n return {\n raw: source.data,\n mediaType: source.mimeType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n if (/^data:/i.test(part.data)) {\n return {\n url: part.data,\n ...(declaredMimeType && { mediaType: declaredMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n raw: source.data,\n ...(declaredMimeType && { mediaType: declaredMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n case \"audio\": {\n if (!part.audio) return null;\n return {\n raw: parseDataUrl(part.audio.data)?.data ?? part.audio.data,\n mediaType: `audio/${part.audio.format}`,\n };\n }\n case \"data\": {\n if (part.data === undefined) return null;\n return { data: part.data };\n }\n default:\n return null;\n }\n })\n .filter((p): p is A2APart => p !== null);\n}\n\nexport function a2aMessageToContent(\n message: A2AMessage,\n): ThreadAssistantMessage[\"content\"] {\n return a2aPartsToContent(message?.parts ?? []);\n}\n\nexport function threadMessageToA2AMessage(\n message: ThreadMessage,\n options: {\n contextId?: string | undefined;\n taskId?: string | undefined;\n } = {},\n): A2AMessage {\n const parts: A2APart[] = [];\n\n if (message.role === \"user\") {\n parts.push(...contentPartsToA2AParts(message.content));\n for (const attachment of message.attachments ?? []) {\n parts.push(\n ...contentPartsToA2AParts(\n attachment.content ?? [],\n attachment.contentType,\n ),\n );\n }\n }\n\n const a2aMsg: A2AMessage = {\n messageId: message.id,\n role: \"user\",\n parts,\n };\n\n if (options.contextId) {\n a2aMsg.contextId = options.contextId;\n }\n if (options.taskId) {\n a2aMsg.taskId = options.taskId;\n }\n\n return a2aMsg;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"conversions.js","names":["isRecord"],"sources":["../src/conversions.ts"],"sourcesContent":["\"use client\";\n\nimport type {\n MessageStatus,\n ThreadAssistantMessage,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport {\n parseDataUrl,\n resolveFilePartSource,\n} from \"@assistant-ui/core/internal\";\nimport type { A2AMessage, A2APart, A2ATaskState } from \"./types\";\n\nfunction isImageMediaType(mediaType?: string): boolean {\n return !!mediaType && mediaType.startsWith(\"image/\");\n}\n\nconst A2UI_OPERATION_KEYS = [\n \"createSurface\",\n \"updateComponents\",\n \"updateDataModel\",\n \"deleteSurface\",\n] as const;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isA2uiOperation = (value: unknown): boolean =>\n isRecord(value) &&\n typeof value.version === \"string\" &&\n A2UI_OPERATION_KEYS.some((key) => Object.hasOwn(value, key));\n\nconst hasA2uiMediaType = (value: unknown): boolean =>\n typeof value === \"string\" && value.toLowerCase().includes(\"a2ui\");\n\nexport function isA2uiDataPart(part: A2APart): boolean {\n if (part.data === undefined) return false;\n\n const metadata = isRecord(part.metadata) ? part.metadata : {};\n return (\n hasA2uiMediaType(part.mediaType) ||\n hasA2uiMediaType(metadata.mimeType) ||\n hasA2uiMediaType(metadata.mediaType) ||\n isA2uiOperation(part.data) ||\n (Array.isArray(part.data) &&\n part.data.length > 0 &&\n part.data.every(isA2uiOperation))\n );\n}\n\nexport function a2uiPartToOperations(part: A2APart): readonly unknown[] {\n if (!isA2uiDataPart(part)) return [];\n return Array.isArray(part.data) ? part.data : [part.data];\n}\n\nexport function a2uiPartsToOperations(\n parts: readonly A2APart[],\n): readonly unknown[] {\n if (!Array.isArray(parts)) return [];\n return parts.flatMap(a2uiPartToOperations);\n}\n\nexport function a2aPartToContent(\n part: A2APart,\n): ThreadAssistantMessage[\"content\"][number] {\n if (!isRecord(part)) return { type: \"text\", text: \"\" };\n if (part.text != null) {\n return { type: \"text\", text: part.text };\n }\n if (part.url != null) {\n if (isImageMediaType(part.mediaType)) {\n return {\n type: \"image\",\n image: part.url,\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n type: \"file\",\n data: part.url,\n mimeType: part.mediaType ?? \"application/octet-stream\",\n sourceType: \"url\",\n ...(part.filename && { filename: part.filename }),\n };\n }\n if (part.raw != null) {\n if (isImageMediaType(part.mediaType)) {\n return {\n type: \"image\",\n image: `data:${part.mediaType};base64,${part.raw}`,\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n type: \"file\",\n data: part.raw,\n mimeType: part.mediaType ?? \"application/octet-stream\",\n ...(part.filename && { filename: part.filename }),\n };\n }\n if (part.data !== undefined) {\n return { type: \"text\", text: JSON.stringify(part.data, null, 2) };\n }\n return { type: \"text\", text: \"\" };\n}\n\nexport function a2aPartsToContent(\n parts: A2APart[],\n): ThreadAssistantMessage[\"content\"] {\n return (Array.isArray(parts) ? parts : [])\n .filter((part) => isRecord(part) && !isA2uiDataPart(part))\n .map(a2aPartToContent);\n}\n\nconst TERMINAL_STATES = new Set<A2ATaskState>([\n \"completed\",\n \"failed\",\n \"canceled\",\n \"rejected\",\n]);\n\nconst INTERRUPTED_STATES = new Set<A2ATaskState>([\n \"input_required\",\n \"auth_required\",\n]);\n\nexport function isTerminalTaskState(state: A2ATaskState): boolean {\n return TERMINAL_STATES.has(state);\n}\n\nexport function isInterruptedTaskState(state: A2ATaskState): boolean {\n return INTERRUPTED_STATES.has(state);\n}\n\nexport function taskStateToMessageStatus(state: A2ATaskState): MessageStatus {\n switch (state) {\n case \"submitted\":\n case \"working\":\n return { type: \"running\" };\n case \"completed\":\n return { type: \"complete\", reason: \"stop\" };\n case \"failed\":\n case \"rejected\":\n return { type: \"incomplete\", reason: \"error\" };\n case \"canceled\":\n return { type: \"incomplete\", reason: \"cancelled\" };\n case \"input_required\":\n case \"auth_required\":\n return { type: \"requires-action\", reason: \"interrupt\" };\n default:\n return { type: \"running\" };\n }\n}\n\nexport function contentPartsToA2AParts(\n content: ReadonlyArray<{\n type: string;\n text?: string | undefined;\n image?: string | undefined;\n data?: unknown;\n mimeType?: string | undefined;\n filename?: string | undefined;\n sourceType?: \"url\" | \"id\" | undefined;\n audio?: { data: string; format: string } | undefined;\n }>,\n fallbackMimeType?: string,\n): A2APart[] {\n return content\n .map((part): A2APart | null => {\n switch (part.type) {\n case \"text\":\n return { text: part.text ?? \"\" };\n case \"image\": {\n if (!part.image) return null;\n const parsed = parseDataUrl(part.image);\n if (parsed) {\n return {\n raw: parsed.data,\n mediaType: parsed.mimeType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n url: part.image,\n ...(fallbackMimeType && { mediaType: fallbackMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n case \"file\": {\n if (typeof part.data !== \"string\") return null;\n const declaredMimeType = part.mimeType || fallbackMimeType;\n const source = resolveFilePartSource({\n data: part.data,\n mimeType: declaredMimeType ?? \"application/octet-stream\",\n sourceType: part.sourceType,\n });\n if (source.kind === \"url\") {\n return {\n url: source.url,\n ...(declaredMimeType && { mediaType: declaredMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n const parsed = parseDataUrl(part.data);\n if (parsed) {\n return {\n raw: source.data,\n mediaType: source.mimeType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n if (/^data:/i.test(part.data)) {\n return {\n url: part.data,\n ...(declaredMimeType && { mediaType: declaredMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n return {\n raw: source.data,\n ...(declaredMimeType && { mediaType: declaredMimeType }),\n ...(part.filename && { filename: part.filename }),\n };\n }\n case \"audio\": {\n if (!part.audio) return null;\n return {\n raw: parseDataUrl(part.audio.data)?.data ?? part.audio.data,\n mediaType: `audio/${part.audio.format}`,\n };\n }\n case \"data\": {\n if (part.data === undefined) return null;\n return { data: part.data };\n }\n default:\n return null;\n }\n })\n .filter((p): p is A2APart => p !== null);\n}\n\nexport function a2aMessageToContent(\n message: A2AMessage,\n): ThreadAssistantMessage[\"content\"] {\n return a2aPartsToContent(message?.parts ?? []);\n}\n\nexport function threadMessageToA2AMessage(\n message: ThreadMessage,\n options: {\n contextId?: string | undefined;\n taskId?: string | undefined;\n } = {},\n): A2AMessage {\n const parts: A2APart[] = [];\n\n if (message.role === \"user\") {\n parts.push(...contentPartsToA2AParts(message.content));\n for (const attachment of message.attachments ?? []) {\n parts.push(\n ...contentPartsToA2AParts(\n attachment.content ?? [],\n attachment.contentType,\n ),\n );\n }\n }\n\n const a2aMsg: A2AMessage = {\n messageId: message.id,\n role: \"user\",\n parts,\n };\n\n if (options.contextId) {\n a2aMsg.contextId = options.contextId;\n }\n if (options.taskId) {\n a2aMsg.taskId = options.taskId;\n }\n\n return a2aMsg;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useA2ARuntime.d.ts","sourceRoot":"","sources":["../src/useA2ARuntime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useA2ARuntime.d.ts","sourceRoot":"","sources":["../src/useA2ARuntime.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAgB;AAmBpD,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,gBAAgB,CAmM7E"}
|
package/dist/useA2ARuntime.js
CHANGED
|
@@ -4,6 +4,7 @@ import { A2AThreadRuntimeCore } from "./A2AThreadRuntimeCore.js";
|
|
|
4
4
|
import { a2aExtras } from "./a2aExtras.js";
|
|
5
5
|
import { useExternalStoreRuntime, useExternalStoreSharedOptions, useRuntimeAdapters } from "@assistant-ui/core/react";
|
|
6
6
|
import { useCallback, useEffect, useInsertionEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { useReplaySafeEffect } from "@assistant-ui/store/internal";
|
|
7
8
|
//#region src/useA2ARuntime.ts
|
|
8
9
|
const serializeManagedClientOptions = (options) => {
|
|
9
10
|
const fetchOptions = Object.fromEntries(Object.entries(options.fetchOptions ?? {}).sort(([a], [b]) => a.localeCompare(b)));
|
|
@@ -33,18 +34,29 @@ function useA2ARuntime(options) {
|
|
|
33
34
|
extensions: options.extensions,
|
|
34
35
|
fetchOptions: options.fetchOptions
|
|
35
36
|
}) : null;
|
|
36
|
-
const
|
|
37
|
+
const createClient = () => {
|
|
37
38
|
if (options.client) return options.client;
|
|
38
39
|
if (!managedClientOptionsKey) throw new Error("useA2ARuntime requires either `client` or `baseUrl`");
|
|
39
40
|
return new A2AClient({
|
|
40
41
|
...JSON.parse(managedClientOptionsKey),
|
|
41
42
|
headers: resolveHeaders
|
|
42
43
|
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
};
|
|
45
|
+
const [pinnedClient, setPinnedClient] = useState(() => ({
|
|
46
|
+
key: managedClientOptionsKey,
|
|
47
|
+
provided: options.client,
|
|
48
|
+
client: createClient()
|
|
49
|
+
}));
|
|
50
|
+
let currentClient = pinnedClient;
|
|
51
|
+
if (pinnedClient.key !== managedClientOptionsKey || pinnedClient.provided !== options.client) {
|
|
52
|
+
currentClient = {
|
|
53
|
+
key: managedClientOptionsKey,
|
|
54
|
+
provided: options.client,
|
|
55
|
+
client: createClient()
|
|
56
|
+
};
|
|
57
|
+
setPinnedClient(currentClient);
|
|
58
|
+
}
|
|
59
|
+
const client = currentClient.client;
|
|
48
60
|
const coreOptions = {
|
|
49
61
|
client,
|
|
50
62
|
contextId: options.contextId,
|
|
@@ -56,11 +68,24 @@ function useA2ARuntime(options) {
|
|
|
56
68
|
};
|
|
57
69
|
const coreOptionsRef = useRef(coreOptions);
|
|
58
70
|
coreOptionsRef.current = coreOptions;
|
|
59
|
-
const
|
|
71
|
+
const createCore = () => new A2AThreadRuntimeCore({
|
|
60
72
|
...coreOptionsRef.current,
|
|
61
73
|
client,
|
|
62
74
|
notifyUpdate
|
|
63
|
-
})
|
|
75
|
+
});
|
|
76
|
+
const [pinnedCore, setPinnedCore] = useState(() => ({
|
|
77
|
+
client,
|
|
78
|
+
core: createCore()
|
|
79
|
+
}));
|
|
80
|
+
let currentCore = pinnedCore;
|
|
81
|
+
if (pinnedCore.client !== client) {
|
|
82
|
+
currentCore = {
|
|
83
|
+
client,
|
|
84
|
+
core: createCore()
|
|
85
|
+
};
|
|
86
|
+
setPinnedCore(currentCore);
|
|
87
|
+
}
|
|
88
|
+
const core = currentCore.core;
|
|
64
89
|
useEffect(() => {
|
|
65
90
|
core.updateOptions(coreOptions);
|
|
66
91
|
});
|
|
@@ -134,7 +159,7 @@ function useA2ARuntime(options) {
|
|
|
134
159
|
shared
|
|
135
160
|
]);
|
|
136
161
|
const runtime = useExternalStoreRuntime(store);
|
|
137
|
-
|
|
162
|
+
useReplaySafeEffect(() => {
|
|
138
163
|
core.attachRuntime(runtime);
|
|
139
164
|
return () => {
|
|
140
165
|
core.detachRuntime();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useA2ARuntime.js","names":[],"sources":["../src/useA2ARuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n useExternalStoreRuntime,\n useExternalStoreSharedOptions,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport type {\n AssistantRuntime,\n AppendMessage,\n ExternalStoreAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport { A2AClient, type A2AClientOptions } from \"./A2AClient\";\nimport { A2AThreadRuntimeCore } from \"./A2AThreadRuntimeCore\";\nimport { a2aExtras } from \"./a2aExtras\";\nimport type { UseA2ARuntimeOptions } from \"./types\";\n\ntype ManagedA2AClientOptions = Omit<A2AClientOptions, \"headers\">;\n\nconst serializeManagedClientOptions = (\n options: ManagedA2AClientOptions,\n): string => {\n const fetchOptions = Object.fromEntries(\n Object.entries(options.fetchOptions ?? {}).sort(([a], [b]) =>\n a.localeCompare(b),\n ),\n );\n\n return JSON.stringify({\n ...options,\n fetchOptions,\n });\n};\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 const headersRef = useRef(options.headers);\n useInsertionEffect(() => {\n headersRef.current = options.headers;\n });\n const resolveHeaders = useCallback(() => {\n const headers = headersRef.current;\n return typeof headers === \"function\" ? headers() : (headers ?? {});\n }, []);\n\n const managedClientOptionsKey = options.client\n ? null\n : options.baseUrl\n ? serializeManagedClientOptions({\n baseUrl: options.baseUrl,\n basePath: options.basePath,\n tenant: options.tenant,\n extensions: options.extensions,\n fetchOptions: options.fetchOptions,\n })\n : null;\n\n const client = useMemo(() => {\n if (options.client) return options.client;\n if (!managedClientOptionsKey) {\n throw new Error(\"useA2ARuntime requires either `client` or `baseUrl`\");\n }\n\n return new A2AClient({\n ...(JSON.parse(managedClientOptionsKey) as ManagedA2AClientOptions),\n headers: resolveHeaders,\n });\n }, [managedClientOptionsKey, options.client, resolveHeaders]);\n\n const coreOptions = {\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 const coreOptionsRef = useRef(coreOptions);\n coreOptionsRef.current = coreOptions;\n\n const core = useMemo(\n () =>\n new A2AThreadRuntimeCore({\n ...coreOptionsRef.current,\n client,\n notifyUpdate,\n }),\n [client, notifyUpdate],\n );\n\n useEffect(() => {\n core.updateOptions(coreOptions);\n });\n\n // Thread list\n const threadSwitchGenerationRef = useRef(0);\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 const generation = ++threadSwitchGenerationRef.current;\n // Clear before the thread id flips, or the old messages leak\n // into the new thread as a sibling branch.\n core.applyExternalMessages([]);\n core.resetContext();\n await onSwitchToNewThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n // Apply first so the abort inside resetContext finds an already\n // cleared repository and cannot persist the old thread's partial\n // assistant message.\n core.applyExternalMessages([]);\n core.resetContext();\n }\n : undefined,\n onSwitchToThread: onSwitchToThread\n ? async (threadId: string) => {\n const generation = ++threadSwitchGenerationRef.current;\n // Clear before the thread id flips, or the old messages leak\n // into the new thread as a sibling branch.\n core.applyExternalMessages([]);\n core.resetContext();\n const result = await onSwitchToThread(threadId);\n if (generation !== threadSwitchGenerationRef.current) return;\n core.applyExternalMessages([]);\n core.applyExternalMessages(result.messages);\n core.resetContext();\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 messageRepository: core.getMessageRepository(),\n isRunning: core.isRunning(),\n unstable_persistsHistory: true,\n extras: a2aExtras.provide({\n task: core.getTask(),\n artifacts: core.getArtifacts(),\n agentCard: core.getAgentCard(),\n }),\n onNew: (message: AppendMessage) => core.append(message),\n onVoiceTranscript: (message: ThreadMessage) =>\n core.appendVoiceTranscript(message),\n onEdit: (message: AppendMessage) => core.edit(message),\n onReload: (parentId: string | null) => core.reload(parentId),\n onCancel: () => core.cancel(),\n unstable_onRecordToolInteraction: (options) =>\n core.recordToolInteraction(options),\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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"}
|
|
1
|
+
{"version":3,"file":"useA2ARuntime.js","names":[],"sources":["../src/useA2ARuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n useExternalStoreRuntime,\n useExternalStoreSharedOptions,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport { useReplaySafeEffect } from \"@assistant-ui/store/internal\";\nimport type {\n AssistantRuntime,\n AppendMessage,\n ExternalStoreAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport { A2AClient, type A2AClientOptions } from \"./A2AClient\";\nimport { A2AThreadRuntimeCore } from \"./A2AThreadRuntimeCore\";\nimport { a2aExtras } from \"./a2aExtras\";\nimport type { UseA2ARuntimeOptions } from \"./types\";\n\ntype ManagedA2AClientOptions = Omit<A2AClientOptions, \"headers\">;\n\nconst serializeManagedClientOptions = (\n options: ManagedA2AClientOptions,\n): string => {\n const fetchOptions = Object.fromEntries(\n Object.entries(options.fetchOptions ?? {}).sort(([a], [b]) =>\n a.localeCompare(b),\n ),\n );\n\n return JSON.stringify({\n ...options,\n fetchOptions,\n });\n};\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 const headersRef = useRef(options.headers);\n useInsertionEffect(() => {\n headersRef.current = options.headers;\n });\n const resolveHeaders = useCallback(() => {\n const headers = headersRef.current;\n return typeof headers === \"function\" ? headers() : (headers ?? {});\n }, []);\n\n const managedClientOptionsKey = options.client\n ? null\n : options.baseUrl\n ? serializeManagedClientOptions({\n baseUrl: options.baseUrl,\n basePath: options.basePath,\n tenant: options.tenant,\n extensions: options.extensions,\n fetchOptions: options.fetchOptions,\n })\n : null;\n\n const createClient = () => {\n if (options.client) return options.client;\n if (!managedClientOptionsKey) {\n throw new Error(\"useA2ARuntime requires either `client` or `baseUrl`\");\n }\n\n return new A2AClient({\n ...(JSON.parse(managedClientOptionsKey) as ManagedA2AClientOptions),\n headers: resolveHeaders,\n });\n };\n const [pinnedClient, setPinnedClient] = useState(() => ({\n key: managedClientOptionsKey,\n provided: options.client,\n client: createClient(),\n }));\n let currentClient = pinnedClient;\n if (\n pinnedClient.key !== managedClientOptionsKey ||\n pinnedClient.provided !== options.client\n ) {\n currentClient = {\n key: managedClientOptionsKey,\n provided: options.client,\n client: createClient(),\n };\n setPinnedClient(currentClient);\n }\n const client = currentClient.client;\n\n const coreOptions = {\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 const coreOptionsRef = useRef(coreOptions);\n coreOptionsRef.current = coreOptions;\n\n const createCore = () =>\n new A2AThreadRuntimeCore({\n ...coreOptionsRef.current,\n client,\n notifyUpdate,\n });\n const [pinnedCore, setPinnedCore] = useState(() => ({\n client,\n core: createCore(),\n }));\n let currentCore = pinnedCore;\n if (pinnedCore.client !== client) {\n currentCore = { client, core: createCore() };\n setPinnedCore(currentCore);\n }\n const core = currentCore.core;\n\n useEffect(() => {\n core.updateOptions(coreOptions);\n });\n\n // Thread list\n const threadSwitchGenerationRef = useRef(0);\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 const generation = ++threadSwitchGenerationRef.current;\n // Clear before the thread id flips, or the old messages leak\n // into the new thread as a sibling branch.\n core.applyExternalMessages([]);\n core.resetContext();\n await onSwitchToNewThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n // Apply first so the abort inside resetContext finds an already\n // cleared repository and cannot persist the old thread's partial\n // assistant message.\n core.applyExternalMessages([]);\n core.resetContext();\n }\n : undefined,\n onSwitchToThread: onSwitchToThread\n ? async (threadId: string) => {\n const generation = ++threadSwitchGenerationRef.current;\n // Clear before the thread id flips, or the old messages leak\n // into the new thread as a sibling branch.\n core.applyExternalMessages([]);\n core.resetContext();\n const result = await onSwitchToThread(threadId);\n if (generation !== threadSwitchGenerationRef.current) return;\n core.applyExternalMessages([]);\n core.applyExternalMessages(result.messages);\n core.resetContext();\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 messageRepository: core.getMessageRepository(),\n isRunning: core.isRunning(),\n unstable_persistsHistory: true,\n extras: a2aExtras.provide({\n task: core.getTask(),\n artifacts: core.getArtifacts(),\n agentCard: core.getAgentCard(),\n }),\n onNew: (message: AppendMessage) => core.append(message),\n onVoiceTranscript: (message: ThreadMessage) =>\n core.appendVoiceTranscript(message),\n onEdit: (message: AppendMessage) => core.edit(message),\n onReload: (parentId: string | null) => core.reload(parentId),\n onCancel: () => core.cancel(),\n unstable_onRecordToolInteraction: (options) =>\n core.recordToolInteraction(options),\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 useReplaySafeEffect(() => {\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.
|
|
3
|
+
"version": "0.2.40",
|
|
4
4
|
"description": "A2A (Agent-to-Agent) v1.0 protocol adapter for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"a2a",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@assistant-ui/core": "^0.3.
|
|
33
|
-
"@assistant-ui/react-generative-ui": "^0.0.
|
|
34
|
-
"@assistant-ui/store": "^0.3.
|
|
35
|
-
"assistant-stream": "^0.3.
|
|
32
|
+
"@assistant-ui/core": "^0.3.23",
|
|
33
|
+
"@assistant-ui/react-generative-ui": "^0.0.23",
|
|
34
|
+
"@assistant-ui/store": "^0.3.17",
|
|
35
|
+
"assistant-stream": "^0.3.47"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@types/react": "*",
|
|
@@ -44,14 +44,15 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
47
|
+
"@assistant-ui/x-buildutils": "0.0.30",
|
|
48
|
+
"@assistant-ui/x-react18": "0.0.0",
|
|
48
49
|
"@testing-library/dom": "^10.4.2",
|
|
49
50
|
"@testing-library/react": "^16.3.3",
|
|
50
51
|
"@types/react": "^19.3.0",
|
|
51
52
|
"jsdom": "^30.0.1",
|
|
52
53
|
"react": "^19.3.0",
|
|
53
54
|
"react-dom": "^19.3.0",
|
|
54
|
-
"vitest": "^5.0.
|
|
55
|
+
"vitest": "^5.0.3"
|
|
55
56
|
},
|
|
56
57
|
"publishConfig": {
|
|
57
58
|
"access": "public",
|
|
@@ -70,6 +71,8 @@
|
|
|
70
71
|
"build": "aui-build",
|
|
71
72
|
"test": "vitest run",
|
|
72
73
|
"typecheck": "tsc --noEmit",
|
|
74
|
+
"test:peer-react18": "vitest run --config vitest.peer-react18.config.ts",
|
|
75
|
+
"test:types:peer-react18": "aui-react18-types",
|
|
73
76
|
"test:watch": "vitest"
|
|
74
77
|
}
|
|
75
78
|
}
|
|
@@ -2380,11 +2380,13 @@ describe("A2AThreadRuntimeCore", () => {
|
|
|
2380
2380
|
status: { state: "working" },
|
|
2381
2381
|
};
|
|
2382
2382
|
(core as any).abortController = new AbortController();
|
|
2383
|
+
notifyUpdate.mockClear();
|
|
2383
2384
|
|
|
2384
2385
|
await core.cancel();
|
|
2385
2386
|
|
|
2386
2387
|
expect(cancelTask).toHaveBeenCalledWith("t1");
|
|
2387
2388
|
expect(core.getTask()!.status.state).toBe("canceled");
|
|
2389
|
+
expect(notifyUpdate).toHaveBeenCalledOnce();
|
|
2388
2390
|
});
|
|
2389
2391
|
|
|
2390
2392
|
it("does nothing when no abort controller", async () => {
|
|
@@ -434,6 +434,7 @@ export class A2AThreadRuntimeCore {
|
|
|
434
434
|
// that case out.
|
|
435
435
|
if (this.currentTask === task && this.runGeneration === generation) {
|
|
436
436
|
this.currentTask = updated;
|
|
437
|
+
this.notifyUpdate();
|
|
437
438
|
}
|
|
438
439
|
} catch {
|
|
439
440
|
// Server cancel failed; local abort already handled
|
package/src/conversions.test.ts
CHANGED
|
@@ -156,6 +156,35 @@ describe("a2aPartToContent", () => {
|
|
|
156
156
|
const part: A2APart = {};
|
|
157
157
|
expect(a2aPartToContent(part)).toEqual({ type: "text", text: "" });
|
|
158
158
|
});
|
|
159
|
+
|
|
160
|
+
it.each(["text", "url", "raw"])("treats a null %s as absent", (field) => {
|
|
161
|
+
const part = { [field]: null } as unknown as A2APart;
|
|
162
|
+
expect(a2aPartToContent(part)).toEqual({ type: "text", text: "" });
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("reads the url of a part whose text is null", () => {
|
|
166
|
+
const part = {
|
|
167
|
+
text: null,
|
|
168
|
+
url: "https://example.com/doc.pdf",
|
|
169
|
+
mediaType: "application/pdf",
|
|
170
|
+
} as unknown as A2APart;
|
|
171
|
+
expect(a2aPartToContent(part)).toEqual({
|
|
172
|
+
type: "file",
|
|
173
|
+
data: "https://example.com/doc.pdf",
|
|
174
|
+
mimeType: "application/pdf",
|
|
175
|
+
sourceType: "url",
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it.each([null, undefined, "text", 1])(
|
|
180
|
+
"returns an empty text part for the non-object part %s",
|
|
181
|
+
(part) => {
|
|
182
|
+
expect(a2aPartToContent(part as unknown as A2APart)).toEqual({
|
|
183
|
+
type: "text",
|
|
184
|
+
text: "",
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
);
|
|
159
188
|
});
|
|
160
189
|
|
|
161
190
|
describe("A2UI data parts", () => {
|
|
@@ -313,6 +342,11 @@ describe("a2aPartsToContent", () => {
|
|
|
313
342
|
expect(a2aPartsToContent(parts as unknown as A2APart[])).toEqual([]);
|
|
314
343
|
},
|
|
315
344
|
);
|
|
345
|
+
|
|
346
|
+
it("skips null and undefined entries in parts", () => {
|
|
347
|
+
const parts = [null, { text: "Hello" }, undefined] as unknown as A2APart[];
|
|
348
|
+
expect(a2aPartsToContent(parts)).toEqual([{ type: "text", text: "Hello" }]);
|
|
349
|
+
});
|
|
316
350
|
});
|
|
317
351
|
|
|
318
352
|
describe("a2aMessageToContent", () => {
|
package/src/conversions.ts
CHANGED
|
@@ -63,10 +63,11 @@ export function a2uiPartsToOperations(
|
|
|
63
63
|
export function a2aPartToContent(
|
|
64
64
|
part: A2APart,
|
|
65
65
|
): ThreadAssistantMessage["content"][number] {
|
|
66
|
-
if (part
|
|
66
|
+
if (!isRecord(part)) return { type: "text", text: "" };
|
|
67
|
+
if (part.text != null) {
|
|
67
68
|
return { type: "text", text: part.text };
|
|
68
69
|
}
|
|
69
|
-
if (part.url
|
|
70
|
+
if (part.url != null) {
|
|
70
71
|
if (isImageMediaType(part.mediaType)) {
|
|
71
72
|
return {
|
|
72
73
|
type: "image",
|
|
@@ -82,7 +83,7 @@ export function a2aPartToContent(
|
|
|
82
83
|
...(part.filename && { filename: part.filename }),
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
|
-
if (part.raw
|
|
86
|
+
if (part.raw != null) {
|
|
86
87
|
if (isImageMediaType(part.mediaType)) {
|
|
87
88
|
return {
|
|
88
89
|
type: "image",
|
|
@@ -107,7 +108,7 @@ export function a2aPartsToContent(
|
|
|
107
108
|
parts: A2APart[],
|
|
108
109
|
): ThreadAssistantMessage["content"] {
|
|
109
110
|
return (Array.isArray(parts) ? parts : [])
|
|
110
|
-
.filter((part) => !isA2uiDataPart(part))
|
|
111
|
+
.filter((part) => isRecord(part) && !isA2uiDataPart(part))
|
|
111
112
|
.map(a2aPartToContent);
|
|
112
113
|
}
|
|
113
114
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { act, Activity, version } from "react";
|
|
4
|
+
import { afterAll, afterEach, expect, it, vi } from "vitest";
|
|
5
|
+
import type { AssistantRuntime } from "@assistant-ui/core";
|
|
6
|
+
import { A2AClient } from "./A2AClient";
|
|
7
|
+
import { A2AThreadRuntimeCore } from "./A2AThreadRuntimeCore";
|
|
8
|
+
import type { UseA2ARuntimeOptions } from "./types";
|
|
9
|
+
import { useA2ARuntime } from "./useA2ARuntime";
|
|
10
|
+
|
|
11
|
+
const onReact18 = version.startsWith("18.");
|
|
12
|
+
|
|
13
|
+
type Family = { current: unknown };
|
|
14
|
+
type RendererInternals = {
|
|
15
|
+
setRefreshHandler: (resolve: (type: unknown) => Family | undefined) => void;
|
|
16
|
+
scheduleRefresh: (
|
|
17
|
+
root: unknown,
|
|
18
|
+
update: { staleFamilies: Set<Family>; updatedFamilies: Set<Family> },
|
|
19
|
+
) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
let renderer: RendererInternals | undefined;
|
|
23
|
+
const fiberRoots = new Set<unknown>();
|
|
24
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
25
|
+
vi.stubGlobal("__REACT_DEVTOOLS_GLOBAL_HOOK__", {
|
|
26
|
+
supportsFiber: true,
|
|
27
|
+
inject: (internals: RendererInternals) => {
|
|
28
|
+
renderer = internals;
|
|
29
|
+
return 1;
|
|
30
|
+
},
|
|
31
|
+
onScheduleFiberRoot: () => {},
|
|
32
|
+
onCommitFiberRoot: (_id: number, root: unknown) => fiberRoots.add(root),
|
|
33
|
+
onCommitFiberUnmount: () => {},
|
|
34
|
+
});
|
|
35
|
+
const { cleanup, render, waitFor } = await import("@testing-library/react");
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
cleanup();
|
|
39
|
+
fiberRoots.clear();
|
|
40
|
+
vi.restoreAllMocks();
|
|
41
|
+
});
|
|
42
|
+
afterAll(() => vi.unstubAllGlobals());
|
|
43
|
+
|
|
44
|
+
let options: UseA2ARuntimeOptions;
|
|
45
|
+
let runtime: AssistantRuntime;
|
|
46
|
+
const createProbe = () => {
|
|
47
|
+
const Before = () => {
|
|
48
|
+
runtime = useA2ARuntime(options);
|
|
49
|
+
return null;
|
|
50
|
+
};
|
|
51
|
+
const After = () => {
|
|
52
|
+
runtime = useA2ARuntime(options);
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
return { Before, After };
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const refresh = async (Before: unknown, After: unknown) => {
|
|
59
|
+
const family: Family = { current: After };
|
|
60
|
+
renderer!.setRefreshHandler((type) =>
|
|
61
|
+
type === Before || type === After ? family : undefined,
|
|
62
|
+
);
|
|
63
|
+
await act(async () => {
|
|
64
|
+
for (const root of fiberRoots) {
|
|
65
|
+
renderer!.scheduleRefresh(root, {
|
|
66
|
+
staleFamilies: new Set(),
|
|
67
|
+
updatedFamilies: new Set([family]),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
await act(async () => {});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
it("keeps the managed client and core across refresh, then replaces both when options change", async () => {
|
|
75
|
+
vi.spyOn(A2AClient.prototype, "getAgentCard").mockResolvedValue(
|
|
76
|
+
{} as Awaited<ReturnType<A2AClient["getAgentCard"]>>,
|
|
77
|
+
);
|
|
78
|
+
const attach = vi.spyOn(A2AThreadRuntimeCore.prototype, "attachRuntime");
|
|
79
|
+
const update = vi.spyOn(A2AThreadRuntimeCore.prototype, "updateOptions");
|
|
80
|
+
options = { baseUrl: "https://first.example" };
|
|
81
|
+
const { Before, After } = createProbe();
|
|
82
|
+
const view = render(<Before />);
|
|
83
|
+
const firstCore = attach.mock.instances[0]! as A2AThreadRuntimeCore;
|
|
84
|
+
const firstClient = update.mock.lastCall![0].client;
|
|
85
|
+
|
|
86
|
+
await refresh(Before, After);
|
|
87
|
+
expect(attach.mock.instances.at(-1)).toBe(firstCore);
|
|
88
|
+
expect(update.mock.lastCall![0].client).toBe(firstClient);
|
|
89
|
+
expect(firstCore.getRuntime()).toBe(runtime);
|
|
90
|
+
|
|
91
|
+
options = { baseUrl: "https://second.example" };
|
|
92
|
+
view.rerender(<After />);
|
|
93
|
+
await act(async () => {});
|
|
94
|
+
expect(attach.mock.instances.at(-1)).not.toBe(firstCore);
|
|
95
|
+
expect(update.mock.lastCall![0].client).not.toBe(firstClient);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const keepsStreamAcrossRefresh = async (
|
|
99
|
+
exit: "hidden" | "unmount",
|
|
100
|
+
inActivity: boolean,
|
|
101
|
+
) => {
|
|
102
|
+
let signal: AbortSignal | undefined;
|
|
103
|
+
const client = {
|
|
104
|
+
getAgentCard: vi.fn().mockResolvedValue(undefined),
|
|
105
|
+
streamMessage: vi.fn((_message, _configuration, _metadata, runSignal) => {
|
|
106
|
+
signal = runSignal as AbortSignal;
|
|
107
|
+
return {
|
|
108
|
+
async *[Symbol.asyncIterator]() {
|
|
109
|
+
await new Promise<void>((resolve) =>
|
|
110
|
+
signal!.addEventListener("abort", () => resolve(), {
|
|
111
|
+
once: true,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}),
|
|
117
|
+
} as unknown as A2AClient;
|
|
118
|
+
const attach = vi.spyOn(A2AThreadRuntimeCore.prototype, "attachRuntime");
|
|
119
|
+
const detach = vi.spyOn(A2AThreadRuntimeCore.prototype, "detachRuntime");
|
|
120
|
+
options = { client };
|
|
121
|
+
const { Before, After } = createProbe();
|
|
122
|
+
const Shell = ({ mode }: { mode: "visible" | "hidden" }) => (
|
|
123
|
+
<Activity mode={mode}>
|
|
124
|
+
<Before />
|
|
125
|
+
</Activity>
|
|
126
|
+
);
|
|
127
|
+
const view = render(inActivity ? <Shell mode="visible" /> : <Before />);
|
|
128
|
+
const core = attach.mock.instances[0]!;
|
|
129
|
+
act(() => {
|
|
130
|
+
void runtime.thread.append("hello");
|
|
131
|
+
});
|
|
132
|
+
await waitFor(() => expect(client.streamMessage).toHaveBeenCalledOnce());
|
|
133
|
+
|
|
134
|
+
await refresh(Before, After);
|
|
135
|
+
expect(signal?.aborted).toBe(false);
|
|
136
|
+
expect(detach).not.toHaveBeenCalled();
|
|
137
|
+
expect(attach.mock.instances.at(-1)).toBe(core);
|
|
138
|
+
|
|
139
|
+
if (exit === "hidden") view.rerender(<Shell mode="hidden" />);
|
|
140
|
+
else view.unmount();
|
|
141
|
+
await act(async () => {});
|
|
142
|
+
expect(detach).toHaveBeenCalledOnce();
|
|
143
|
+
expect(signal?.aborted).toBe(true);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Activity is React 19 only
|
|
147
|
+
it.skipIf(onReact18)(
|
|
148
|
+
"keeps an in-flight stream across refresh and detaches when hidden",
|
|
149
|
+
() => keepsStreamAcrossRefresh("hidden", true),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Activity is React 19 only
|
|
153
|
+
it.skipIf(onReact18)(
|
|
154
|
+
"keeps an in-flight stream across refresh and detaches when unmounted inside Activity",
|
|
155
|
+
() => keepsStreamAcrossRefresh("unmount", true),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
it("keeps an in-flight stream across refresh and detaches when unmounted", () =>
|
|
159
|
+
keepsStreamAcrossRefresh("unmount", false));
|
package/src/useA2ARuntime.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
useExternalStoreSharedOptions,
|
|
14
14
|
useRuntimeAdapters,
|
|
15
15
|
} from "@assistant-ui/core/react";
|
|
16
|
+
import { useReplaySafeEffect } from "@assistant-ui/store/internal";
|
|
16
17
|
import type {
|
|
17
18
|
AssistantRuntime,
|
|
18
19
|
AppendMessage,
|
|
@@ -69,7 +70,7 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
|
|
|
69
70
|
})
|
|
70
71
|
: null;
|
|
71
72
|
|
|
72
|
-
const
|
|
73
|
+
const createClient = () => {
|
|
73
74
|
if (options.client) return options.client;
|
|
74
75
|
if (!managedClientOptionsKey) {
|
|
75
76
|
throw new Error("useA2ARuntime requires either `client` or `baseUrl`");
|
|
@@ -79,7 +80,25 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
|
|
|
79
80
|
...(JSON.parse(managedClientOptionsKey) as ManagedA2AClientOptions),
|
|
80
81
|
headers: resolveHeaders,
|
|
81
82
|
});
|
|
82
|
-
}
|
|
83
|
+
};
|
|
84
|
+
const [pinnedClient, setPinnedClient] = useState(() => ({
|
|
85
|
+
key: managedClientOptionsKey,
|
|
86
|
+
provided: options.client,
|
|
87
|
+
client: createClient(),
|
|
88
|
+
}));
|
|
89
|
+
let currentClient = pinnedClient;
|
|
90
|
+
if (
|
|
91
|
+
pinnedClient.key !== managedClientOptionsKey ||
|
|
92
|
+
pinnedClient.provided !== options.client
|
|
93
|
+
) {
|
|
94
|
+
currentClient = {
|
|
95
|
+
key: managedClientOptionsKey,
|
|
96
|
+
provided: options.client,
|
|
97
|
+
client: createClient(),
|
|
98
|
+
};
|
|
99
|
+
setPinnedClient(currentClient);
|
|
100
|
+
}
|
|
101
|
+
const client = currentClient.client;
|
|
83
102
|
|
|
84
103
|
const coreOptions = {
|
|
85
104
|
client,
|
|
@@ -95,15 +114,22 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
|
|
|
95
114
|
const coreOptionsRef = useRef(coreOptions);
|
|
96
115
|
coreOptionsRef.current = coreOptions;
|
|
97
116
|
|
|
98
|
-
const
|
|
99
|
-
(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
const createCore = () =>
|
|
118
|
+
new A2AThreadRuntimeCore({
|
|
119
|
+
...coreOptionsRef.current,
|
|
120
|
+
client,
|
|
121
|
+
notifyUpdate,
|
|
122
|
+
});
|
|
123
|
+
const [pinnedCore, setPinnedCore] = useState(() => ({
|
|
124
|
+
client,
|
|
125
|
+
core: createCore(),
|
|
126
|
+
}));
|
|
127
|
+
let currentCore = pinnedCore;
|
|
128
|
+
if (pinnedCore.client !== client) {
|
|
129
|
+
currentCore = { client, core: createCore() };
|
|
130
|
+
setPinnedCore(currentCore);
|
|
131
|
+
}
|
|
132
|
+
const core = currentCore.core;
|
|
107
133
|
|
|
108
134
|
useEffect(() => {
|
|
109
135
|
core.updateOptions(coreOptions);
|
|
@@ -199,7 +225,7 @@ export function useA2ARuntime(options: UseA2ARuntimeOptions): AssistantRuntime {
|
|
|
199
225
|
|
|
200
226
|
const runtime = useExternalStoreRuntime(store);
|
|
201
227
|
|
|
202
|
-
|
|
228
|
+
useReplaySafeEffect(() => {
|
|
203
229
|
core.attachRuntime(runtime);
|
|
204
230
|
return () => {
|
|
205
231
|
core.detachRuntime();
|