@assistant-ui/react-ag-ui 0.1.7 → 0.1.9
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/dist/runtime/AgUiThreadController.d.ts +10 -0
- package/dist/runtime/AgUiThreadController.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadController.js +86 -32
- package/dist/runtime/AgUiThreadController.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts +10 -0
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +9 -4
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/types.d.ts +6 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/useAgUiRuntime.d.ts.map +1 -1
- package/dist/useAgUiRuntime.js +6 -2
- package/dist/useAgUiRuntime.js.map +1 -1
- package/package.json +1 -1
- package/src/runtime/AgUiThreadController.connect.test.ts +372 -0
- package/src/runtime/AgUiThreadController.notifications.test.ts +126 -0
- package/src/runtime/AgUiThreadController.ts +158 -36
- package/src/runtime/adapter/conversions.subagent-messages.test.ts +117 -0
- package/src/runtime/adapter/conversions.ts +40 -5
- package/src/runtime/types.ts +6 -0
- package/src/useAgUiRuntime.connect.test.tsx +169 -0
- package/src/useAgUiRuntime.external-store.test.tsx +46 -1
- package/src/useAgUiRuntime.ts +8 -2
package/dist/runtime/types.d.ts
CHANGED
|
@@ -59,6 +59,12 @@ export type UseAgUiRuntimeOptions = ExternalStoreSharedOptions & {
|
|
|
59
59
|
logger?: Partial<Logger>;
|
|
60
60
|
showThinking?: boolean;
|
|
61
61
|
joinStrategy?: JoinStrategy;
|
|
62
|
+
/**
|
|
63
|
+
* Join adjacent assistant records of an imported snapshot into one message.
|
|
64
|
+
* See `FromAgUiMessagesOptions.joinAdjacentAssistantMessages`. Defaults to
|
|
65
|
+
* `false`.
|
|
66
|
+
*/
|
|
67
|
+
joinAdjacentAssistantMessages?: boolean;
|
|
62
68
|
/**
|
|
63
69
|
* Return context entries for each run. `messages` is the exact AG-UI
|
|
64
70
|
* transcript sent in the run input, after transcript selection and message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/runtime/types.ts"],"sourcesContent":["import type {\n CreateAppendMessage,\n AttachmentAdapter,\n DictationAdapter,\n ExternalStoreSharedOptions,\n ExternalStoreThreadListAdapter,\n FeedbackAdapter,\n RealtimeVoiceAdapter,\n RunConfig,\n SpeechSynthesisAdapter,\n ThreadHistoryAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport type { JoinStrategy } from \"@assistant-ui/core/react\";\nimport type {\n AbstractAgent,\n ContentPart,\n Context,\n Message,\n} from \"@ag-ui/client\";\nimport type { Logger } from \"./logger\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport type { McpToolCallResult } from \"./mcp-tool-result\";\n\nexport const AG_UI_METADATA_NAMESPACE = \"agui\";\nexport const MCP_APPS_ACTIVITY_TYPE = \"mcp-apps\";\nexport const A2UI_SURFACE_ACTIVITY_TYPE = \"a2ui-surface\";\n\n// Defensive guard against a malformed or cyclic parentToolCallId /\n// parentSubagentRunId chain, not a realistic nesting depth.\nexport const MAX_SUBAGENT_DEPTH = 16;\n\nexport type AgUiOpaqueReasoning = {\n id: string;\n encryptedValue: string;\n metadata?: Record<string, unknown>;\n after?: boolean;\n};\n\nexport type AgUiCustomMetadata = {\n /** Wire role restored on export for messages the internal model cannot\n * represent (a developer record rides as a system message). */\n role?: \"developer\";\n interrupts?: AgUiInterrupt[];\n pendingToolCallIds?: string[];\n opaqueReasoning?: AgUiOpaqueReasoning[];\n};\n\n/**\n * Same as ExternalStoreThreadListAdapter, except `onSwitchToThread` returns\n * the messages (and optional state) to hydrate the thread with.\n *\n * @deprecated Experimental since 2026-06-13. Not scheduled for removal; the API may change in any release.\n */\ntype SwitchToThreadResult = {\n messages: readonly ThreadMessage[];\n state?: ReadonlyJSONValue;\n /**\n * Set when the thread has a run in flight. The runtime resumes the run\n * after hydrating, the same way `ThreadHistoryAdapter.load()` does when it\n * returns `unstable_resume: true`.\n *\n * @deprecated Experimental since 2025-03-31. Not scheduled for removal; the API may change in any release.\n */\n unstable_resume?: boolean;\n};\n\nexport type UseAgUiThreadListAdapter = Omit<\n ExternalStoreThreadListAdapter,\n \"onSwitchToThread\"\n> & {\n onSwitchToThread?:\n | ((\n threadId: string,\n ) => Promise<SwitchToThreadResult> | SwitchToThreadResult)\n | undefined;\n};\n\nexport type UseAgUiRuntimeAdapters = {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n dictation?: DictationAdapter;\n voice?: RealtimeVoiceAdapter;\n feedback?: FeedbackAdapter;\n history?: ThreadHistoryAdapter;\n /** @deprecated Experimental since 2026-01-28. Not scheduled for removal; the API may change in any release. */\n threadList?: UseAgUiThreadListAdapter;\n};\n\nexport type AgUiResumeTranscript = \"full\" | \"appended\";\n\nexport type UseAgUiRuntimeOptions = ExternalStoreSharedOptions & {\n agent: AbstractAgent;\n logger?: Partial<Logger>;\n showThinking?: boolean;\n joinStrategy?: JoinStrategy;\n /**\n * Return context entries for each run. `messages` is the exact AG-UI\n * transcript sent in the run input, after transcript selection and message\n * conversion. On resume, it follows `resumeTranscript`: \"full\" sends the\n * whole thread, while \"appended\" sends messages after the interrupted\n * assistant message, falling back to the whole thread if that message is\n * missing. `runConfig` is the run config passed while building that input.\n * If the getter throws, the error is reported and the run continues without host entries.\n */\n getRunContext?:\n | ((input: {\n messages: readonly Message[];\n runConfig: RunConfig | undefined;\n }) => readonly Context[])\n | undefined;\n /**\n * What `messages` carries on a resume run, meaning a `RunAgentInput` that\n * also carries `resume`. The AG-UI interrupt spec leaves this undefined: its\n * contract rules constrain the thread id, interrupt coverage, idempotency,\n * and expiry, and none of them mentions `messages`. Hosts therefore disagree,\n * and both readings are conformant.\n *\n * `\"full\"` sends the whole thread, which is what `@ag-ui/client` itself does.\n * Hosts that resume from a checkpoint ignore the transcript, and hosts that\n * rebuild the interrupted run from it need it.\n *\n * `\"appended\"` sends only what was appended locally after the interrupted\n * assistant message, which is nothing for an approval or a denial and the new\n * user turn for `steerAway`. Choose it for a host that owns the thread and\n * seeds a resume request from its own stored snapshot, because such a host\n * appends the request body to that snapshot and a re-sent transcript\n * duplicates the interrupted turn in its stored history. A host that rebuilds\n * the run from `messages` has nothing to resume from under `\"appended\"`, and\n * a host that derives its outgoing `MESSAGES_SNAPSHOT` from the request body\n * emits a truncated one.\n *\n * Defaults to `\"full\"`.\n */\n resumeTranscript?: AgUiResumeTranscript | undefined;\n /**\n * When the user sends, edits, or reloads a message while client-side tool\n * calls are still pending, automatically cancel the unresolved tool calls\n * with an error result so the agent's tool-call accounting stays\n * consistent. Pending AG-UI interrupts are exempt: they still reject the\n * run and must be answered with `useAgUiSubmitInterruptResponses` or\n * discarded with `useAgUiSteerAway`. When disabled, `useAgUiSteerAway`\n * remains the explicit way to cancel pending tool calls.\n * Defaults to `true`.\n */\n autoCancelPendingToolCalls?: boolean | undefined;\n /**\n * Buffer a message sent while a run is in flight and send it once the run\n * settles, exposing it on `composer.queue` for `ComposerPrimitive.Queue`.\n * The runtime owns the queue lifecycle because flushing needs the agent's\n * send path and the run's own busy and idle edges.\n *\n * @deprecated Experimental since 2026-06-04. Not scheduled for removal; the API may change in any release.\n */\n unstable_enableMessageQueue?: boolean | undefined;\n onError?: (e: Error) => void;\n onCancel?: () => void;\n adapters?: UseAgUiRuntimeAdapters;\n};\n\nexport type AgUiInterruptReason =\n | \"tool_call\"\n | \"input_required\"\n | \"confirmation\"\n | (string & {});\n\nexport type AgUiInterrupt = {\n id: string;\n reason: AgUiInterruptReason;\n message?: string;\n toolCallId?: string;\n responseSchema?: Record<string, unknown>;\n expiresAt?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type AgUiResumeEntry = {\n interruptId: string;\n status: \"resolved\" | \"cancelled\";\n payload?: unknown;\n};\n\nexport type AgUiRuntimeExtras = {\n interrupts: readonly AgUiInterrupt[];\n sendA2uiAction: (action: Record<string, unknown>) => void;\n submitInterruptResponses: (\n responses: readonly AgUiResumeEntry[],\n ) => Promise<void>;\n steerAway: (\n message: CreateAppendMessage,\n responses?: readonly AgUiResumeEntry[],\n ) => Promise<void>;\n state: ReadonlyJSONValue | undefined;\n setState: (\n next:\n | ReadonlyJSONValue\n | ((prev: ReadonlyJSONValue | undefined) => ReadonlyJSONValue),\n ) => void;\n};\n\nexport type AgUiRunFinishedOutcome =\n | { type: \"success\"; pendingToolCallIds?: string[] }\n | { type: \"interrupt\"; interrupts: AgUiInterrupt[] }\n | { type: \"cancelled\" };\n\nexport type AgUiSubagentFinishedOutcome =\n | { type: \"success\" }\n | { type: \"suspended\"; interruptIds?: string[] };\n\nexport type AgUiEvent =\n | { type: \"RUN_STARTED\"; runId: string }\n | {\n type: \"RUN_FINISHED\";\n runId: string;\n outcome?: AgUiRunFinishedOutcome;\n }\n | { type: \"RUN_CANCELLED\"; runId?: string }\n | { type: \"RUN_ERROR\"; message?: string; code?: string }\n | { type: \"TEXT_MESSAGE_START\"; messageId?: string; subagentRunId?: string }\n | {\n type: \"TEXT_MESSAGE_CONTENT\";\n messageId?: string;\n delta: string;\n subagentRunId?: string;\n }\n | { type: \"TEXT_MESSAGE_END\"; messageId?: string; subagentRunId?: string }\n | {\n type: \"REASONING_START\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"REASONING_MESSAGE_START\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"REASONING_MESSAGE_CONTENT\";\n messageId: string;\n delta: string;\n subagentRunId?: string;\n }\n | {\n type: \"REASONING_MESSAGE_END\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"REASONING_ENCRYPTED_VALUE\";\n subtype: \"message\" | \"tool-call\";\n entityId: string;\n encryptedValue: string;\n subagentRunId?: string;\n }\n | {\n type: \"REASONING_END\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"TOOL_CALL_START\";\n toolCallId: string;\n toolCallName?: string;\n parentMessageId?: string;\n subagentRunId?: string;\n }\n | {\n type: \"TOOL_CALL_ARGS\";\n toolCallId: string;\n delta: string;\n subagentRunId?: string;\n }\n | { type: \"TOOL_CALL_END\"; toolCallId: string; subagentRunId?: string }\n | {\n type: \"TOOL_CALL_RESULT\";\n messageId?: string;\n toolCallId: string;\n content: string | ContentPart[];\n role?: \"tool\";\n mcpResult?: McpToolCallResult;\n metadata?: Record<string, unknown>;\n subagentRunId?: string;\n }\n | {\n type: \"ACTIVITY_SNAPSHOT\";\n activityType: string;\n content: Record<string, unknown>;\n messageId?: string;\n replace?: boolean;\n subagentRunId?: string;\n }\n | {\n type: \"ACTIVITY_DELTA\";\n messageId: string;\n activityType: string;\n patch: any[];\n subagentRunId?: string;\n }\n | { type: \"RAW\"; event: any; source?: string }\n | { type: \"CUSTOM\"; name: string; value: any }\n | { type: \"STATE_SNAPSHOT\"; snapshot: any }\n | { type: \"STATE_DELTA\"; delta: any[] }\n | { type: \"MESSAGES_SNAPSHOT\"; messages: any[] }\n | {\n type: \"SUBAGENT_STARTED\";\n subagentRunId: string;\n name: string;\n description?: string;\n parentSubagentRunId?: string;\n parentToolCallId?: string;\n parentMessageId?: string;\n }\n | {\n type: \"SUBAGENT_FINISHED\";\n subagentRunId: string;\n result?: unknown;\n outcome?: AgUiSubagentFinishedOutcome;\n }\n | {\n type: \"SUBAGENT_ERROR\";\n subagentRunId: string;\n message: string;\n code?: string;\n };\n"],"mappings":";AAwBA,MAAa,2BAA2B;AACxC,MAAa,yBAAyB;AACtC,MAAa,6BAA6B;AAI1C,MAAa,qBAAqB"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/runtime/types.ts"],"sourcesContent":["import type {\n CreateAppendMessage,\n AttachmentAdapter,\n DictationAdapter,\n ExternalStoreSharedOptions,\n ExternalStoreThreadListAdapter,\n FeedbackAdapter,\n RealtimeVoiceAdapter,\n RunConfig,\n SpeechSynthesisAdapter,\n ThreadHistoryAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport type { JoinStrategy } from \"@assistant-ui/core/react\";\nimport type {\n AbstractAgent,\n ContentPart,\n Context,\n Message,\n} from \"@ag-ui/client\";\nimport type { Logger } from \"./logger\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport type { McpToolCallResult } from \"./mcp-tool-result\";\n\nexport const AG_UI_METADATA_NAMESPACE = \"agui\";\nexport const MCP_APPS_ACTIVITY_TYPE = \"mcp-apps\";\nexport const A2UI_SURFACE_ACTIVITY_TYPE = \"a2ui-surface\";\n\n// Defensive guard against a malformed or cyclic parentToolCallId /\n// parentSubagentRunId chain, not a realistic nesting depth.\nexport const MAX_SUBAGENT_DEPTH = 16;\n\nexport type AgUiOpaqueReasoning = {\n id: string;\n encryptedValue: string;\n metadata?: Record<string, unknown>;\n after?: boolean;\n};\n\nexport type AgUiCustomMetadata = {\n /** Wire role restored on export for messages the internal model cannot\n * represent (a developer record rides as a system message). */\n role?: \"developer\";\n interrupts?: AgUiInterrupt[];\n pendingToolCallIds?: string[];\n opaqueReasoning?: AgUiOpaqueReasoning[];\n};\n\n/**\n * Same as ExternalStoreThreadListAdapter, except `onSwitchToThread` returns\n * the messages (and optional state) to hydrate the thread with.\n *\n * @deprecated Experimental since 2026-06-13. Not scheduled for removal; the API may change in any release.\n */\ntype SwitchToThreadResult = {\n messages: readonly ThreadMessage[];\n state?: ReadonlyJSONValue;\n /**\n * Set when the thread has a run in flight. The runtime resumes the run\n * after hydrating, the same way `ThreadHistoryAdapter.load()` does when it\n * returns `unstable_resume: true`.\n *\n * @deprecated Experimental since 2025-03-31. Not scheduled for removal; the API may change in any release.\n */\n unstable_resume?: boolean;\n};\n\nexport type UseAgUiThreadListAdapter = Omit<\n ExternalStoreThreadListAdapter,\n \"onSwitchToThread\"\n> & {\n onSwitchToThread?:\n | ((\n threadId: string,\n ) => Promise<SwitchToThreadResult> | SwitchToThreadResult)\n | undefined;\n};\n\nexport type UseAgUiRuntimeAdapters = {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n dictation?: DictationAdapter;\n voice?: RealtimeVoiceAdapter;\n feedback?: FeedbackAdapter;\n history?: ThreadHistoryAdapter;\n /** @deprecated Experimental since 2026-01-28. Not scheduled for removal; the API may change in any release. */\n threadList?: UseAgUiThreadListAdapter;\n};\n\nexport type AgUiResumeTranscript = \"full\" | \"appended\";\n\nexport type UseAgUiRuntimeOptions = ExternalStoreSharedOptions & {\n agent: AbstractAgent;\n logger?: Partial<Logger>;\n showThinking?: boolean;\n joinStrategy?: JoinStrategy;\n /**\n * Join adjacent assistant records of an imported snapshot into one message.\n * See `FromAgUiMessagesOptions.joinAdjacentAssistantMessages`. Defaults to\n * `false`.\n */\n joinAdjacentAssistantMessages?: boolean;\n /**\n * Return context entries for each run. `messages` is the exact AG-UI\n * transcript sent in the run input, after transcript selection and message\n * conversion. On resume, it follows `resumeTranscript`: \"full\" sends the\n * whole thread, while \"appended\" sends messages after the interrupted\n * assistant message, falling back to the whole thread if that message is\n * missing. `runConfig` is the run config passed while building that input.\n * If the getter throws, the error is reported and the run continues without host entries.\n */\n getRunContext?:\n | ((input: {\n messages: readonly Message[];\n runConfig: RunConfig | undefined;\n }) => readonly Context[])\n | undefined;\n /**\n * What `messages` carries on a resume run, meaning a `RunAgentInput` that\n * also carries `resume`. The AG-UI interrupt spec leaves this undefined: its\n * contract rules constrain the thread id, interrupt coverage, idempotency,\n * and expiry, and none of them mentions `messages`. Hosts therefore disagree,\n * and both readings are conformant.\n *\n * `\"full\"` sends the whole thread, which is what `@ag-ui/client` itself does.\n * Hosts that resume from a checkpoint ignore the transcript, and hosts that\n * rebuild the interrupted run from it need it.\n *\n * `\"appended\"` sends only what was appended locally after the interrupted\n * assistant message, which is nothing for an approval or a denial and the new\n * user turn for `steerAway`. Choose it for a host that owns the thread and\n * seeds a resume request from its own stored snapshot, because such a host\n * appends the request body to that snapshot and a re-sent transcript\n * duplicates the interrupted turn in its stored history. A host that rebuilds\n * the run from `messages` has nothing to resume from under `\"appended\"`, and\n * a host that derives its outgoing `MESSAGES_SNAPSHOT` from the request body\n * emits a truncated one.\n *\n * Defaults to `\"full\"`.\n */\n resumeTranscript?: AgUiResumeTranscript | undefined;\n /**\n * When the user sends, edits, or reloads a message while client-side tool\n * calls are still pending, automatically cancel the unresolved tool calls\n * with an error result so the agent's tool-call accounting stays\n * consistent. Pending AG-UI interrupts are exempt: they still reject the\n * run and must be answered with `useAgUiSubmitInterruptResponses` or\n * discarded with `useAgUiSteerAway`. When disabled, `useAgUiSteerAway`\n * remains the explicit way to cancel pending tool calls.\n * Defaults to `true`.\n */\n autoCancelPendingToolCalls?: boolean | undefined;\n /**\n * Buffer a message sent while a run is in flight and send it once the run\n * settles, exposing it on `composer.queue` for `ComposerPrimitive.Queue`.\n * The runtime owns the queue lifecycle because flushing needs the agent's\n * send path and the run's own busy and idle edges.\n *\n * @deprecated Experimental since 2026-06-04. Not scheduled for removal; the API may change in any release.\n */\n unstable_enableMessageQueue?: boolean | undefined;\n onError?: (e: Error) => void;\n onCancel?: () => void;\n adapters?: UseAgUiRuntimeAdapters;\n};\n\nexport type AgUiInterruptReason =\n | \"tool_call\"\n | \"input_required\"\n | \"confirmation\"\n | (string & {});\n\nexport type AgUiInterrupt = {\n id: string;\n reason: AgUiInterruptReason;\n message?: string;\n toolCallId?: string;\n responseSchema?: Record<string, unknown>;\n expiresAt?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type AgUiResumeEntry = {\n interruptId: string;\n status: \"resolved\" | \"cancelled\";\n payload?: unknown;\n};\n\nexport type AgUiRuntimeExtras = {\n interrupts: readonly AgUiInterrupt[];\n sendA2uiAction: (action: Record<string, unknown>) => void;\n submitInterruptResponses: (\n responses: readonly AgUiResumeEntry[],\n ) => Promise<void>;\n steerAway: (\n message: CreateAppendMessage,\n responses?: readonly AgUiResumeEntry[],\n ) => Promise<void>;\n state: ReadonlyJSONValue | undefined;\n setState: (\n next:\n | ReadonlyJSONValue\n | ((prev: ReadonlyJSONValue | undefined) => ReadonlyJSONValue),\n ) => void;\n};\n\nexport type AgUiRunFinishedOutcome =\n | { type: \"success\"; pendingToolCallIds?: string[] }\n | { type: \"interrupt\"; interrupts: AgUiInterrupt[] }\n | { type: \"cancelled\" };\n\nexport type AgUiSubagentFinishedOutcome =\n | { type: \"success\" }\n | { type: \"suspended\"; interruptIds?: string[] };\n\nexport type AgUiEvent =\n | { type: \"RUN_STARTED\"; runId: string }\n | {\n type: \"RUN_FINISHED\";\n runId: string;\n outcome?: AgUiRunFinishedOutcome;\n }\n | { type: \"RUN_CANCELLED\"; runId?: string }\n | { type: \"RUN_ERROR\"; message?: string; code?: string }\n | { type: \"TEXT_MESSAGE_START\"; messageId?: string; subagentRunId?: string }\n | {\n type: \"TEXT_MESSAGE_CONTENT\";\n messageId?: string;\n delta: string;\n subagentRunId?: string;\n }\n | { type: \"TEXT_MESSAGE_END\"; messageId?: string; subagentRunId?: string }\n | {\n type: \"REASONING_START\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"REASONING_MESSAGE_START\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"REASONING_MESSAGE_CONTENT\";\n messageId: string;\n delta: string;\n subagentRunId?: string;\n }\n | {\n type: \"REASONING_MESSAGE_END\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"REASONING_ENCRYPTED_VALUE\";\n subtype: \"message\" | \"tool-call\";\n entityId: string;\n encryptedValue: string;\n subagentRunId?: string;\n }\n | {\n type: \"REASONING_END\";\n messageId: string;\n subagentRunId?: string;\n timestamp?: number;\n }\n | {\n type: \"TOOL_CALL_START\";\n toolCallId: string;\n toolCallName?: string;\n parentMessageId?: string;\n subagentRunId?: string;\n }\n | {\n type: \"TOOL_CALL_ARGS\";\n toolCallId: string;\n delta: string;\n subagentRunId?: string;\n }\n | { type: \"TOOL_CALL_END\"; toolCallId: string; subagentRunId?: string }\n | {\n type: \"TOOL_CALL_RESULT\";\n messageId?: string;\n toolCallId: string;\n content: string | ContentPart[];\n role?: \"tool\";\n mcpResult?: McpToolCallResult;\n metadata?: Record<string, unknown>;\n subagentRunId?: string;\n }\n | {\n type: \"ACTIVITY_SNAPSHOT\";\n activityType: string;\n content: Record<string, unknown>;\n messageId?: string;\n replace?: boolean;\n subagentRunId?: string;\n }\n | {\n type: \"ACTIVITY_DELTA\";\n messageId: string;\n activityType: string;\n patch: any[];\n subagentRunId?: string;\n }\n | { type: \"RAW\"; event: any; source?: string }\n | { type: \"CUSTOM\"; name: string; value: any }\n | { type: \"STATE_SNAPSHOT\"; snapshot: any }\n | { type: \"STATE_DELTA\"; delta: any[] }\n | { type: \"MESSAGES_SNAPSHOT\"; messages: any[] }\n | {\n type: \"SUBAGENT_STARTED\";\n subagentRunId: string;\n name: string;\n description?: string;\n parentSubagentRunId?: string;\n parentToolCallId?: string;\n parentMessageId?: string;\n }\n | {\n type: \"SUBAGENT_FINISHED\";\n subagentRunId: string;\n result?: unknown;\n outcome?: AgUiSubagentFinishedOutcome;\n }\n | {\n type: \"SUBAGENT_ERROR\";\n subagentRunId: string;\n message: string;\n code?: string;\n };\n"],"mappings":";AAwBA,MAAa,2BAA2B;AACxC,MAAa,yBAAyB;AACtC,MAAa,6BAA6B;AAI1C,MAAa,qBAAqB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAgUiRuntime.d.ts","sourceRoot":"","sources":["../src/useAgUiRuntime.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,qBAAqB,EACtB,2BAAwB;AASzB,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IACpD;;;OAGG;IACH,6BAA6B,EAAE,MAAM,SAAS,aAAa,EAAE,CAAC;IAC9D;;;;OAIG;IACH,iCAAiC,EAAE,CACjC,SAAS,EAAE,SAAS,eAAe,EAAE,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,
|
|
1
|
+
{"version":3,"file":"useAgUiRuntime.d.ts","sourceRoot":"","sources":["../src/useAgUiRuntime.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,qBAAqB,EACtB,2BAAwB;AASzB,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IACpD;;;OAGG;IACH,6BAA6B,EAAE,MAAM,SAAS,aAAa,EAAE,CAAC;IAC9D;;;;OAIG;IACH,iCAAiC,EAAE,CACjC,SAAS,EAAE,SAAS,eAAe,EAAE,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CA+WtB"}
|
package/dist/useAgUiRuntime.js
CHANGED
|
@@ -23,6 +23,7 @@ function useAgUiRuntime(options) {
|
|
|
23
23
|
logger,
|
|
24
24
|
showThinking: options.showThinking ?? true,
|
|
25
25
|
joinStrategy: options.joinStrategy,
|
|
26
|
+
joinAdjacentAssistantMessages: options.joinAdjacentAssistantMessages ?? false,
|
|
26
27
|
getRunContext: options.getRunContext,
|
|
27
28
|
resumeTranscript: options.resumeTranscript,
|
|
28
29
|
autoCancelPendingToolCalls: options.autoCancelPendingToolCalls,
|
|
@@ -39,6 +40,7 @@ function useAgUiRuntime(options) {
|
|
|
39
40
|
logger,
|
|
40
41
|
showThinking: options.showThinking ?? true,
|
|
41
42
|
joinStrategy: options.joinStrategy,
|
|
43
|
+
joinAdjacentAssistantMessages: options.joinAdjacentAssistantMessages ?? false,
|
|
42
44
|
getRunContext: options.getRunContext,
|
|
43
45
|
resumeTranscript: options.resumeTranscript,
|
|
44
46
|
autoCancelPendingToolCalls: options.autoCancelPendingToolCalls,
|
|
@@ -100,9 +102,11 @@ function useAgUiRuntime(options) {
|
|
|
100
102
|
const { onSwitchToNewThread, onSwitchToThread, ...rest } = threadListAdapter;
|
|
101
103
|
const abandonPreviousThread = () => {
|
|
102
104
|
queueRef.current?.notifyCancelled();
|
|
103
|
-
if (core.isRunning())
|
|
105
|
+
if (core.isRunning()) try {
|
|
106
|
+
core.leave();
|
|
107
|
+
} catch (error) {
|
|
104
108
|
logger.error?.("[agui] cancelling the run on thread switch failed", error);
|
|
105
|
-
}
|
|
109
|
+
}
|
|
106
110
|
queueRef.current?.clear();
|
|
107
111
|
};
|
|
108
112
|
const releaseSwitch = (generation) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAgUiRuntime.js","names":[],"sources":["../src/useAgUiRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport {\n useExternalStoreRuntime,\n useExternalStoreSharedOptions,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport {\n useIsomorphicLayoutEffect,\n useReplaySafeEffect,\n} from \"@assistant-ui/store/internal\";\nimport { createMessageQueue } from \"@assistant-ui/core\";\nimport type {\n MessageQueueController,\n ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport type {\n AssistantRuntime,\n AppendMessage,\n ExternalStoreAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport { makeLogger } from \"./runtime/logger\";\nimport type {\n AgUiInterrupt,\n AgUiResumeEntry,\n UseAgUiRuntimeOptions,\n} from \"./runtime/types\";\nimport { AgUiThreadController } from \"./runtime/AgUiThreadController\";\nimport { agUiExtras } from \"./agUiExtras\";\nimport type { QueueItemState } from \"@assistant-ui/core/store\";\n\nconst EMPTY_INTERRUPTS: readonly AgUiInterrupt[] = [];\nconst EMPTY_QUEUE_ITEMS: readonly QueueItemState[] = Object.freeze([]);\nconst subscribeNoop = () => () => {};\n\nexport type AgUiAssistantRuntime = AssistantRuntime & {\n /**\n * @deprecated Use the `useAgUiInterrupts()` hook instead. This method is kept\n * for backward compatibility and will be removed in a future major release.\n */\n unstable_getPendingInterrupts: () => readonly AgUiInterrupt[];\n /**\n * @deprecated Use the `useAgUiSubmitInterruptResponses()` hook instead. This\n * method is kept for backward compatibility and will be removed in a future\n * major release.\n */\n unstable_submitInterruptResponses: (\n responses: readonly AgUiResumeEntry[],\n ) => Promise<void>;\n};\n\nexport function useAgUiRuntime(\n options: UseAgUiRuntimeOptions,\n): AgUiAssistantRuntime {\n const logger = useMemo(() => makeLogger(options.logger), [options.logger]);\n const coreRef = useRef<AgUiThreadController | null>(null);\n const threadSwitchGenerationRef = useRef(0);\n const switchingGenerationRef = useRef<number | null>(null);\n const runtimeAdapters = useRuntimeAdapters();\n\n const historyAdapter = options.adapters?.history ?? runtimeAdapters?.history;\n const threadListAdapter = options.adapters?.threadList;\n\n if (!coreRef.current) {\n coreRef.current = new AgUiThreadController({\n agent: options.agent,\n logger,\n showThinking: options.showThinking ?? true,\n joinStrategy: options.joinStrategy,\n getRunContext: options.getRunContext,\n resumeTranscript: options.resumeTranscript,\n autoCancelPendingToolCalls: options.autoCancelPendingToolCalls,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(historyAdapter && { history: historyAdapter }),\n isThreadSwitching: () => switchingGenerationRef.current !== null,\n });\n }\n\n const core = coreRef.current;\n const snapshot = useSyncExternalStore(\n core.subscribe,\n core.getSnapshot,\n core.getSnapshot,\n );\n useEffect(() => {\n core.updateOptions({\n agent: options.agent,\n logger,\n showThinking: options.showThinking ?? true,\n joinStrategy: options.joinStrategy,\n getRunContext: options.getRunContext,\n resumeTranscript: options.resumeTranscript,\n autoCancelPendingToolCalls: options.autoCancelPendingToolCalls,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(historyAdapter && { history: historyAdapter }),\n });\n });\n\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const isRunning = snapshot.isRunning || hasExecutingTools;\n\n // The driver sends through the agent core rather than the runtime, because\n // the runtime's append routes every tail append back into this queue.\n const queueRef = useRef<MessageQueueController | null>(null);\n // Counts rendered busy edges, whether a run start or an interrupt arriving.\n // A dispatch whose count never moves was never observed as busy, so no\n // falling edge is coming to release the queue.\n const busyEdgesRef = useRef(0);\n const lastQueueEdgeRef = useRef<{\n controller: MessageQueueController;\n busy: boolean;\n } | null>(null);\n if (options.unstable_enableMessageQueue && !queueRef.current) {\n queueRef.current = createMessageQueue({\n run: (message) => {\n const controller = queueRef.current;\n // A send dispatched mid-switch is dropped, and the queue released, or\n // it would wait for an idle edge that never comes.\n if (switchingGenerationRef.current !== null) {\n controller?.notifyIdle();\n return;\n }\n const edgesAtDispatch = busyEdgesRef.current;\n // The queue drops the item before dispatching and stays busy until an\n // idle edge. An append observed as busy is released by that falling\n // edge, and releasing again here would advance the queue twice; one\n // that never runs (a pre-run rejection, or startRun false) has to be\n // released here or every later send buffers forever. An interrupt is\n // rechecked because a run that resolves without yielding to React\n // reaches here before the effect below has seen either edge.\n const releaseIfNoRun = () => {\n if (\n queueRef.current !== controller ||\n busyEdgesRef.current !== edgesAtDispatch ||\n core.getPendingInterrupts() !== null\n )\n return;\n controller?.notifyIdle();\n };\n void core.append(message).then(releaseIfNoRun, (e: unknown) => {\n releaseIfNoRun();\n logger.error?.(\"[agui] queued message failed to send\", e);\n });\n },\n });\n }\n const queueController = options.unstable_enableMessageQueue\n ? queueRef.current\n : null;\n useIsomorphicLayoutEffect(() => {\n if (options.unstable_enableMessageQueue || !queueRef.current) return;\n const controller = queueRef.current;\n queueRef.current = null;\n controller.clear();\n }, [options.unstable_enableMessageQueue]);\n\n // Feeds the store memo below: the runtime core skips an adapter whose\n // identity is unchanged, so queue items have to move the store reference or\n // subscribers never see composer.queue change.\n const queueItems = useSyncExternalStore(\n queueController?.subscribe ?? subscribeNoop,\n () => queueController?.adapter.items ?? EMPTY_QUEUE_ITEMS,\n () => EMPTY_QUEUE_ITEMS,\n );\n const steerQueueItems = useSyncExternalStore(\n queueController?.subscribe ?? subscribeNoop,\n () => queueController?.adapter.steerItems ?? EMPTY_QUEUE_ITEMS,\n () => EMPTY_QUEUE_ITEMS,\n );\n\n // Holds the queue while client-side tools are still executing, and while an\n // interrupt is unanswered: `append` refuses a new run until it is resolved,\n // and the queue drops an item before dispatching it, so draining into that\n // refusal would lose the message instead of keeping it visible.\n const queueBusy = isRunning || core.getPendingInterrupts() !== null;\n useEffect(() => {\n if (options.isSendDisabled === true) {\n queueController?.hold();\n } else {\n queueController?.release();\n }\n }, [options.isSendDisabled, queueController]);\n\n useEffect(() => {\n if (!queueController) return;\n if (\n lastQueueEdgeRef.current?.controller === queueController &&\n lastQueueEdgeRef.current.busy === queueBusy\n )\n return;\n lastQueueEdgeRef.current = { controller: queueController, busy: queueBusy };\n if (queueBusy) {\n busyEdgesRef.current++;\n queueController.notifyBusy();\n } else {\n queueController.notifyIdle();\n }\n }, [queueBusy, queueController]);\n\n const threadList = useMemo(() => {\n if (!threadListAdapter) return undefined;\n\n const { onSwitchToNewThread, onSwitchToThread, ...rest } =\n threadListAdapter;\n\n const abandonPreviousThread = () => {\n queueRef.current?.notifyCancelled();\n if (core.isRunning()) {\n void core.cancel().catch((error: unknown) => {\n logger.error?.(\n \"[agui] cancelling the run on thread switch failed\",\n error,\n );\n });\n }\n queueRef.current?.clear();\n };\n\n const releaseSwitch = (generation: number) => {\n if (switchingGenerationRef.current === generation) {\n switchingGenerationRef.current = null;\n }\n };\n\n return {\n ...rest,\n onSwitchToNewThread: onSwitchToNewThread\n ? async () => {\n const generation = ++threadSwitchGenerationRef.current;\n switchingGenerationRef.current = generation;\n try {\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\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.resetThreadState();\n await onSwitchToNewThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n core.applyExternalMessages([]);\n core.resetThreadState();\n } finally {\n releaseSwitch(generation);\n }\n }\n : undefined,\n onSwitchToThread: onSwitchToThread\n ? async (threadId: string) => {\n const generation = ++threadSwitchGenerationRef.current;\n switchingGenerationRef.current = generation;\n try {\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\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.resetThreadState();\n const result = await onSwitchToThread(threadId);\n if (generation !== threadSwitchGenerationRef.current) return;\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n core.applyExternalMessages([]);\n core.resetThreadState();\n core.applyExternalMessages(result.messages);\n if (result.state !== undefined) {\n core.loadExternalState(result.state);\n }\n if (generation !== threadSwitchGenerationRef.current) return;\n releaseSwitch(generation);\n if (result.unstable_resume) {\n void core.resumeInFlightRun(result.messages);\n }\n } finally {\n releaseSwitch(generation);\n }\n }\n : undefined,\n };\n }, [threadListAdapter, core, logger]);\n\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 const shared = useExternalStoreSharedOptions(options);\n const store = useMemo(\n () => {\n return {\n ...shared,\n isLoading: snapshot.isLoading,\n messageRepository: snapshot.messageRepository,\n state: snapshot.state,\n isRunning: snapshot.isRunning,\n extras: agUiExtras.provide({\n interrupts:\n core.getPendingInterrupts()?.interrupts ?? EMPTY_INTERRUPTS,\n sendA2uiAction: (action) => core.sendA2uiAction(action),\n submitInterruptResponses: (responses) =>\n core.submitInterruptResponses(responses),\n steerAway: (message, responses) => core.steerAway(message, responses),\n state: snapshot.state,\n setState: (next) => core.setState(next),\n }),\n unstable_enableToolInvocations: true,\n unstable_persistsHistory: true,\n setToolStatuses,\n onNew: (message: AppendMessage) =>\n switchingGenerationRef.current !== null\n ? Promise.resolve()\n : core.append(message),\n onVoiceTranscript: (message) => core.appendVoiceTranscript(message),\n onEdit: (message: AppendMessage) => {\n queueController?.clear();\n return core.edit(message);\n },\n onReload: (parentId: string | null, config: { runConfig?: any }) => {\n queueController?.clear();\n return core.reload(parentId, config);\n },\n onDelete: (messageId: string) => core.deleteMessage(messageId),\n onCancel: async () => {\n queueController?.notifyCancelled();\n core.cancel();\n },\n onAddToolResult: (options) => core.addToolResult(options),\n unstable_onRecordToolInteraction: (options) =>\n core.recordToolInteraction(options),\n onRespondToToolApproval: (options) =>\n core.respondToToolApproval(options).catch((error: unknown) => {\n core.reportError(error);\n throw error;\n }),\n onResume: (config) => core.resume(config),\n setMessages: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n onImport: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n onLoadExternalState: (state: ReadonlyJSONValue) =>\n core.loadExternalState(state),\n adapters: adapterAdapters,\n ...(queueController && { queue: queueController.adapter }),\n } satisfies ExternalStoreAdapter<ThreadMessage>;\n },\n // toolInvocations intentionally excluded: abort/resume use refs internally and work with stale captures\n [\n adapterAdapters,\n core,\n isRunning,\n queueController,\n queueItems,\n steerQueueItems,\n shared,\n snapshot,\n ],\n );\n\n const baseRuntime = useExternalStoreRuntime(store);\n\n const createRuntime = (): AgUiAssistantRuntime => {\n return {\n threads: baseRuntime.threads,\n get thread() {\n return baseRuntime.thread;\n },\n registerModelContextProvider: (provider) =>\n baseRuntime.registerModelContextProvider(provider),\n unstable_getPendingInterrupts: () =>\n core.getPendingInterrupts()?.interrupts ?? [],\n unstable_submitInterruptResponses: (responses) =>\n core.submitInterruptResponses(responses),\n };\n };\n const [pinnedRuntime, setPinnedRuntime] = useState(() => ({\n baseRuntime,\n runtime: createRuntime(),\n }));\n let currentRuntime = pinnedRuntime;\n if (pinnedRuntime.baseRuntime !== baseRuntime) {\n currentRuntime = { baseRuntime, runtime: createRuntime() };\n setPinnedRuntime(currentRuntime);\n }\n const runtime = currentRuntime.runtime;\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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"}
|
|
1
|
+
{"version":3,"file":"useAgUiRuntime.js","names":[],"sources":["../src/useAgUiRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport {\n useExternalStoreRuntime,\n useExternalStoreSharedOptions,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport {\n useIsomorphicLayoutEffect,\n useReplaySafeEffect,\n} from \"@assistant-ui/store/internal\";\nimport { createMessageQueue } from \"@assistant-ui/core\";\nimport type {\n MessageQueueController,\n ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport type {\n AssistantRuntime,\n AppendMessage,\n ExternalStoreAdapter,\n ThreadMessage,\n} from \"@assistant-ui/core\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport { makeLogger } from \"./runtime/logger\";\nimport type {\n AgUiInterrupt,\n AgUiResumeEntry,\n UseAgUiRuntimeOptions,\n} from \"./runtime/types\";\nimport { AgUiThreadController } from \"./runtime/AgUiThreadController\";\nimport { agUiExtras } from \"./agUiExtras\";\nimport type { QueueItemState } from \"@assistant-ui/core/store\";\n\nconst EMPTY_INTERRUPTS: readonly AgUiInterrupt[] = [];\nconst EMPTY_QUEUE_ITEMS: readonly QueueItemState[] = Object.freeze([]);\nconst subscribeNoop = () => () => {};\n\nexport type AgUiAssistantRuntime = AssistantRuntime & {\n /**\n * @deprecated Use the `useAgUiInterrupts()` hook instead. This method is kept\n * for backward compatibility and will be removed in a future major release.\n */\n unstable_getPendingInterrupts: () => readonly AgUiInterrupt[];\n /**\n * @deprecated Use the `useAgUiSubmitInterruptResponses()` hook instead. This\n * method is kept for backward compatibility and will be removed in a future\n * major release.\n */\n unstable_submitInterruptResponses: (\n responses: readonly AgUiResumeEntry[],\n ) => Promise<void>;\n};\n\nexport function useAgUiRuntime(\n options: UseAgUiRuntimeOptions,\n): AgUiAssistantRuntime {\n const logger = useMemo(() => makeLogger(options.logger), [options.logger]);\n const coreRef = useRef<AgUiThreadController | null>(null);\n const threadSwitchGenerationRef = useRef(0);\n const switchingGenerationRef = useRef<number | null>(null);\n const runtimeAdapters = useRuntimeAdapters();\n\n const historyAdapter = options.adapters?.history ?? runtimeAdapters?.history;\n const threadListAdapter = options.adapters?.threadList;\n\n if (!coreRef.current) {\n coreRef.current = new AgUiThreadController({\n agent: options.agent,\n logger,\n showThinking: options.showThinking ?? true,\n joinStrategy: options.joinStrategy,\n joinAdjacentAssistantMessages:\n options.joinAdjacentAssistantMessages ?? false,\n getRunContext: options.getRunContext,\n resumeTranscript: options.resumeTranscript,\n autoCancelPendingToolCalls: options.autoCancelPendingToolCalls,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(historyAdapter && { history: historyAdapter }),\n isThreadSwitching: () => switchingGenerationRef.current !== null,\n });\n }\n\n const core = coreRef.current;\n const snapshot = useSyncExternalStore(\n core.subscribe,\n core.getSnapshot,\n core.getSnapshot,\n );\n useEffect(() => {\n core.updateOptions({\n agent: options.agent,\n logger,\n showThinking: options.showThinking ?? true,\n joinStrategy: options.joinStrategy,\n joinAdjacentAssistantMessages:\n options.joinAdjacentAssistantMessages ?? false,\n getRunContext: options.getRunContext,\n resumeTranscript: options.resumeTranscript,\n autoCancelPendingToolCalls: options.autoCancelPendingToolCalls,\n ...(options.onError && { onError: options.onError }),\n ...(options.onCancel && { onCancel: options.onCancel }),\n ...(historyAdapter && { history: historyAdapter }),\n });\n });\n\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const isRunning = snapshot.isRunning || hasExecutingTools;\n\n // The driver sends through the agent core rather than the runtime, because\n // the runtime's append routes every tail append back into this queue.\n const queueRef = useRef<MessageQueueController | null>(null);\n // Counts rendered busy edges, whether a run start or an interrupt arriving.\n // A dispatch whose count never moves was never observed as busy, so no\n // falling edge is coming to release the queue.\n const busyEdgesRef = useRef(0);\n const lastQueueEdgeRef = useRef<{\n controller: MessageQueueController;\n busy: boolean;\n } | null>(null);\n if (options.unstable_enableMessageQueue && !queueRef.current) {\n queueRef.current = createMessageQueue({\n run: (message) => {\n const controller = queueRef.current;\n // A send dispatched mid-switch is dropped, and the queue released, or\n // it would wait for an idle edge that never comes.\n if (switchingGenerationRef.current !== null) {\n controller?.notifyIdle();\n return;\n }\n const edgesAtDispatch = busyEdgesRef.current;\n // The queue drops the item before dispatching and stays busy until an\n // idle edge. An append observed as busy is released by that falling\n // edge, and releasing again here would advance the queue twice; one\n // that never runs (a pre-run rejection, or startRun false) has to be\n // released here or every later send buffers forever. An interrupt is\n // rechecked because a run that resolves without yielding to React\n // reaches here before the effect below has seen either edge.\n const releaseIfNoRun = () => {\n if (\n queueRef.current !== controller ||\n busyEdgesRef.current !== edgesAtDispatch ||\n core.getPendingInterrupts() !== null\n )\n return;\n controller?.notifyIdle();\n };\n void core.append(message).then(releaseIfNoRun, (e: unknown) => {\n releaseIfNoRun();\n logger.error?.(\"[agui] queued message failed to send\", e);\n });\n },\n });\n }\n const queueController = options.unstable_enableMessageQueue\n ? queueRef.current\n : null;\n useIsomorphicLayoutEffect(() => {\n if (options.unstable_enableMessageQueue || !queueRef.current) return;\n const controller = queueRef.current;\n queueRef.current = null;\n controller.clear();\n }, [options.unstable_enableMessageQueue]);\n\n // Feeds the store memo below: the runtime core skips an adapter whose\n // identity is unchanged, so queue items have to move the store reference or\n // subscribers never see composer.queue change.\n const queueItems = useSyncExternalStore(\n queueController?.subscribe ?? subscribeNoop,\n () => queueController?.adapter.items ?? EMPTY_QUEUE_ITEMS,\n () => EMPTY_QUEUE_ITEMS,\n );\n const steerQueueItems = useSyncExternalStore(\n queueController?.subscribe ?? subscribeNoop,\n () => queueController?.adapter.steerItems ?? EMPTY_QUEUE_ITEMS,\n () => EMPTY_QUEUE_ITEMS,\n );\n\n // Holds the queue while client-side tools are still executing, and while an\n // interrupt is unanswered: `append` refuses a new run until it is resolved,\n // and the queue drops an item before dispatching it, so draining into that\n // refusal would lose the message instead of keeping it visible.\n const queueBusy = isRunning || core.getPendingInterrupts() !== null;\n useEffect(() => {\n if (options.isSendDisabled === true) {\n queueController?.hold();\n } else {\n queueController?.release();\n }\n }, [options.isSendDisabled, queueController]);\n\n useEffect(() => {\n if (!queueController) return;\n if (\n lastQueueEdgeRef.current?.controller === queueController &&\n lastQueueEdgeRef.current.busy === queueBusy\n )\n return;\n lastQueueEdgeRef.current = { controller: queueController, busy: queueBusy };\n if (queueBusy) {\n busyEdgesRef.current++;\n queueController.notifyBusy();\n } else {\n queueController.notifyIdle();\n }\n }, [queueBusy, queueController]);\n\n const threadList = useMemo(() => {\n if (!threadListAdapter) return undefined;\n\n const { onSwitchToNewThread, onSwitchToThread, ...rest } =\n threadListAdapter;\n\n const abandonPreviousThread = () => {\n queueRef.current?.notifyCancelled();\n if (core.isRunning()) {\n try {\n core.leave();\n } catch (error) {\n logger.error?.(\n \"[agui] cancelling the run on thread switch failed\",\n error,\n );\n }\n }\n queueRef.current?.clear();\n };\n\n const releaseSwitch = (generation: number) => {\n if (switchingGenerationRef.current === generation) {\n switchingGenerationRef.current = null;\n }\n };\n\n return {\n ...rest,\n onSwitchToNewThread: onSwitchToNewThread\n ? async () => {\n const generation = ++threadSwitchGenerationRef.current;\n switchingGenerationRef.current = generation;\n try {\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\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.resetThreadState();\n await onSwitchToNewThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n core.applyExternalMessages([]);\n core.resetThreadState();\n } finally {\n releaseSwitch(generation);\n }\n }\n : undefined,\n onSwitchToThread: onSwitchToThread\n ? async (threadId: string) => {\n const generation = ++threadSwitchGenerationRef.current;\n switchingGenerationRef.current = generation;\n try {\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\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.resetThreadState();\n const result = await onSwitchToThread(threadId);\n if (generation !== threadSwitchGenerationRef.current) return;\n abandonPreviousThread();\n if (generation !== threadSwitchGenerationRef.current) return;\n core.applyExternalMessages([]);\n core.resetThreadState();\n core.applyExternalMessages(result.messages);\n if (result.state !== undefined) {\n core.loadExternalState(result.state);\n }\n if (generation !== threadSwitchGenerationRef.current) return;\n releaseSwitch(generation);\n if (result.unstable_resume) {\n void core.resumeInFlightRun(result.messages);\n }\n } finally {\n releaseSwitch(generation);\n }\n }\n : undefined,\n };\n }, [threadListAdapter, core, logger]);\n\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 const shared = useExternalStoreSharedOptions(options);\n const store = useMemo(\n () => {\n return {\n ...shared,\n isLoading: snapshot.isLoading,\n messageRepository: snapshot.messageRepository,\n state: snapshot.state,\n isRunning: snapshot.isRunning,\n extras: agUiExtras.provide({\n interrupts:\n core.getPendingInterrupts()?.interrupts ?? EMPTY_INTERRUPTS,\n sendA2uiAction: (action) => core.sendA2uiAction(action),\n submitInterruptResponses: (responses) =>\n core.submitInterruptResponses(responses),\n steerAway: (message, responses) => core.steerAway(message, responses),\n state: snapshot.state,\n setState: (next) => core.setState(next),\n }),\n unstable_enableToolInvocations: true,\n unstable_persistsHistory: true,\n setToolStatuses,\n onNew: (message: AppendMessage) =>\n switchingGenerationRef.current !== null\n ? Promise.resolve()\n : core.append(message),\n onVoiceTranscript: (message) => core.appendVoiceTranscript(message),\n onEdit: (message: AppendMessage) => {\n queueController?.clear();\n return core.edit(message);\n },\n onReload: (parentId: string | null, config: { runConfig?: any }) => {\n queueController?.clear();\n return core.reload(parentId, config);\n },\n onDelete: (messageId: string) => core.deleteMessage(messageId),\n onCancel: async () => {\n queueController?.notifyCancelled();\n core.cancel();\n },\n onAddToolResult: (options) => core.addToolResult(options),\n unstable_onRecordToolInteraction: (options) =>\n core.recordToolInteraction(options),\n onRespondToToolApproval: (options) =>\n core.respondToToolApproval(options).catch((error: unknown) => {\n core.reportError(error);\n throw error;\n }),\n onResume: (config) => core.resume(config),\n setMessages: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n onImport: (messages: readonly ThreadMessage[]) =>\n core.applyExternalMessages(messages),\n onLoadExternalState: (state: ReadonlyJSONValue) =>\n core.loadExternalState(state),\n adapters: adapterAdapters,\n ...(queueController && { queue: queueController.adapter }),\n } satisfies ExternalStoreAdapter<ThreadMessage>;\n },\n // toolInvocations intentionally excluded: abort/resume use refs internally and work with stale captures\n [\n adapterAdapters,\n core,\n isRunning,\n queueController,\n queueItems,\n steerQueueItems,\n shared,\n snapshot,\n ],\n );\n\n const baseRuntime = useExternalStoreRuntime(store);\n\n const createRuntime = (): AgUiAssistantRuntime => {\n return {\n threads: baseRuntime.threads,\n get thread() {\n return baseRuntime.thread;\n },\n registerModelContextProvider: (provider) =>\n baseRuntime.registerModelContextProvider(provider),\n unstable_getPendingInterrupts: () =>\n core.getPendingInterrupts()?.interrupts ?? [],\n unstable_submitInterruptResponses: (responses) =>\n core.submitInterruptResponses(responses),\n };\n };\n const [pinnedRuntime, setPinnedRuntime] = useState(() => ({\n baseRuntime,\n runtime: createRuntime(),\n }));\n let currentRuntime = pinnedRuntime;\n if (pinnedRuntime.baseRuntime !== baseRuntime) {\n currentRuntime = { baseRuntime, runtime: createRuntime() };\n setPinnedRuntime(currentRuntime);\n }\n const runtime = currentRuntime.runtime;\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":";;;;;;;;;AAwCA,MAAM,mBAA6C,CAAC;AACpD,MAAM,oBAA+C,OAAO,OAAO,CAAC,CAAC;AACrE,MAAM,4BAA4B,CAAC;AAkBnC,SAAgB,eACd,SACsB;CACtB,MAAM,SAAS,cAAc,WAAW,QAAQ,MAAM,GAAG,CAAC,QAAQ,MAAM,CAAC;CACzE,MAAM,UAAU,OAAoC,IAAI;CACxD,MAAM,4BAA4B,OAAO,CAAC;CAC1C,MAAM,yBAAyB,OAAsB,IAAI;CACzD,MAAM,kBAAkB,mBAAmB;CAE3C,MAAM,iBAAiB,QAAQ,UAAU,WAAW,iBAAiB;CACrE,MAAM,oBAAoB,QAAQ,UAAU;CAE5C,IAAI,CAAC,QAAQ,SACX,QAAQ,UAAU,IAAI,qBAAqB;EACzC,OAAO,QAAQ;EACf;EACA,cAAc,QAAQ,gBAAgB;EACtC,cAAc,QAAQ;EACtB,+BACE,QAAQ,iCAAiC;EAC3C,eAAe,QAAQ;EACvB,kBAAkB,QAAQ;EAC1B,4BAA4B,QAAQ;EACpC,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,QAAQ;EAClD,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;EACrD,GAAI,kBAAkB,EAAE,SAAS,eAAe;EAChD,yBAAyB,uBAAuB,YAAY;CAC9D,CAAC;CAGH,MAAM,OAAO,QAAQ;CACrB,MAAM,WAAW,qBACf,KAAK,WACL,KAAK,aACL,KAAK,WACP;CACA,gBAAgB;EACd,KAAK,cAAc;GACjB,OAAO,QAAQ;GACf;GACA,cAAc,QAAQ,gBAAgB;GACtC,cAAc,QAAQ;GACtB,+BACE,QAAQ,iCAAiC;GAC3C,eAAe,QAAQ;GACvB,kBAAkB,QAAQ;GAC1B,4BAA4B,QAAQ;GACpC,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,QAAQ;GAClD,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;GACrD,GAAI,kBAAkB,EAAE,SAAS,eAAe;EAClD,CAAC;CACH,CAAC;CAED,MAAM,CAAC,cAAc,mBAAmB,SAEtC,CAAC,CAAC;CAEJ,MAAM,oBAAoB,OAAO,OAAO,YAAY,CAAC,CAAC,MACnD,MAAM,GAAG,SAAS,WACrB;CACA,MAAM,YAAY,SAAS,aAAa;CAIxC,MAAM,WAAW,OAAsC,IAAI;CAI3D,MAAM,eAAe,OAAO,CAAC;CAC7B,MAAM,mBAAmB,OAGf,IAAI;CACd,IAAI,QAAQ,+BAA+B,CAAC,SAAS,SACnD,SAAS,UAAU,mBAAmB,EACpC,MAAM,YAAY;EAChB,MAAM,aAAa,SAAS;EAG5B,IAAI,uBAAuB,YAAY,MAAM;GAC3C,YAAY,WAAW;GACvB;EACF;EACA,MAAM,kBAAkB,aAAa;EAQrC,MAAM,uBAAuB;GAC3B,IACE,SAAS,YAAY,cACrB,aAAa,YAAY,mBACzB,KAAK,qBAAqB,MAAM,MAEhC;GACF,YAAY,WAAW;EACzB;EACA,KAAU,OAAO,OAAO,CAAC,CAAC,KAAK,iBAAiB,MAAe;GAC7D,eAAe;GACf,OAAO,QAAQ,wCAAwC,CAAC;EAC1D,CAAC;CACH,EACF,CAAC;CAEH,MAAM,kBAAkB,QAAQ,8BAC5B,SAAS,UACT;CACJ,gCAAgC;EAC9B,IAAI,QAAQ,+BAA+B,CAAC,SAAS,SAAS;EAC9D,MAAM,aAAa,SAAS;EAC5B,SAAS,UAAU;EACnB,WAAW,MAAM;CACnB,GAAG,CAAC,QAAQ,2BAA2B,CAAC;CAKxC,MAAM,aAAa,qBACjB,iBAAiB,aAAa,qBACxB,iBAAiB,QAAQ,SAAS,yBAClC,iBACR;CACA,MAAM,kBAAkB,qBACtB,iBAAiB,aAAa,qBACxB,iBAAiB,QAAQ,cAAc,yBACvC,iBACR;CAMA,MAAM,YAAY,aAAa,KAAK,qBAAqB,MAAM;CAC/D,gBAAgB;EACd,IAAI,QAAQ,mBAAmB,MAC7B,iBAAiB,KAAK;OAEtB,iBAAiB,QAAQ;CAE7B,GAAG,CAAC,QAAQ,gBAAgB,eAAe,CAAC;CAE5C,gBAAgB;EACd,IAAI,CAAC,iBAAiB;EACtB,IACE,iBAAiB,SAAS,eAAe,mBACzC,iBAAiB,QAAQ,SAAS,WAElC;EACF,iBAAiB,UAAU;GAAE,YAAY;GAAiB,MAAM;EAAU;EAC1E,IAAI,WAAW;GACb,aAAa;GACb,gBAAgB,WAAW;EAC7B,OACE,gBAAgB,WAAW;CAE/B,GAAG,CAAC,WAAW,eAAe,CAAC;CAE/B,MAAM,aAAa,cAAc;EAC/B,IAAI,CAAC,mBAAmB,OAAO,KAAA;EAE/B,MAAM,EAAE,qBAAqB,kBAAkB,GAAG,SAChD;EAEF,MAAM,8BAA8B;GAClC,SAAS,SAAS,gBAAgB;GAClC,IAAI,KAAK,UAAU,GACjB,IAAI;IACF,KAAK,MAAM;GACb,SAAS,OAAO;IACd,OAAO,QACL,qDACA,KACF;GACF;GAEF,SAAS,SAAS,MAAM;EAC1B;EAEA,MAAM,iBAAiB,eAAuB;GAC5C,IAAI,uBAAuB,YAAY,YACrC,uBAAuB,UAAU;EAErC;EAEA,OAAO;GACL,GAAG;GACH,qBAAqB,sBACjB,YAAY;IACV,MAAM,aAAa,EAAE,0BAA0B;IAC/C,uBAAuB,UAAU;IACjC,IAAI;KACF,sBAAsB;KACtB,IAAI,eAAe,0BAA0B,SAAS;KAGtD,KAAK,sBAAsB,CAAC,CAAC;KAC7B,KAAK,iBAAiB;KACtB,MAAM,oBAAoB;KAC1B,IAAI,eAAe,0BAA0B,SAAS;KACtD,sBAAsB;KACtB,IAAI,eAAe,0BAA0B,SAAS;KACtD,KAAK,sBAAsB,CAAC,CAAC;KAC7B,KAAK,iBAAiB;IACxB,UAAU;KACR,cAAc,UAAU;IAC1B;GACF,IACA,KAAA;GACJ,kBAAkB,mBACd,OAAO,aAAqB;IAC1B,MAAM,aAAa,EAAE,0BAA0B;IAC/C,uBAAuB,UAAU;IACjC,IAAI;KACF,sBAAsB;KACtB,IAAI,eAAe,0BAA0B,SAAS;KAGtD,KAAK,sBAAsB,CAAC,CAAC;KAC7B,KAAK,iBAAiB;KACtB,MAAM,SAAS,MAAM,iBAAiB,QAAQ;KAC9C,IAAI,eAAe,0BAA0B,SAAS;KACtD,sBAAsB;KACtB,IAAI,eAAe,0BAA0B,SAAS;KACtD,KAAK,sBAAsB,CAAC,CAAC;KAC7B,KAAK,iBAAiB;KACtB,KAAK,sBAAsB,OAAO,QAAQ;KAC1C,IAAI,OAAO,UAAU,KAAA,GACnB,KAAK,kBAAkB,OAAO,KAAK;KAErC,IAAI,eAAe,0BAA0B,SAAS;KACtD,cAAc,UAAU;KACxB,IAAI,OAAO,iBACT,KAAU,kBAAkB,OAAO,QAAQ;IAE/C,UAAU;KACR,cAAc,UAAU;IAC1B;GACF,IACA,KAAA;EACN;CACF,GAAG;EAAC;EAAmB;EAAM;CAAM,CAAC;CAEpC,MAAM,WAAW,QAAQ;CACzB,MAAM,kBAAkB,eACf;EACL,aAAa,UAAU,eAAe,iBAAiB;EACvD,QAAQ,UAAU;EAClB,WAAW,UAAU;EACrB,OAAO,UAAU;EACjB,UAAU,UAAU;EACpB;CACF,IACA;EAAC;EAAU;EAAiB;CAAU,CACxC;CAEA,MAAM,SAAS,8BAA8B,OAAO;CACpD,MAAM,QAAQ,cACN;EACJ,OAAO;GACL,GAAG;GACH,WAAW,SAAS;GACpB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,WAAW,SAAS;GACpB,QAAQ,WAAW,QAAQ;IACzB,YACE,KAAK,qBAAqB,CAAC,EAAE,cAAc;IAC7C,iBAAiB,WAAW,KAAK,eAAe,MAAM;IACtD,2BAA2B,cACzB,KAAK,yBAAyB,SAAS;IACzC,YAAY,SAAS,cAAc,KAAK,UAAU,SAAS,SAAS;IACpE,OAAO,SAAS;IAChB,WAAW,SAAS,KAAK,SAAS,IAAI;GACxC,CAAC;GACD,gCAAgC;GAChC,0BAA0B;GAC1B;GACA,QAAQ,YACN,uBAAuB,YAAY,OAC/B,QAAQ,QAAQ,IAChB,KAAK,OAAO,OAAO;GACzB,oBAAoB,YAAY,KAAK,sBAAsB,OAAO;GAClE,SAAS,YAA2B;IAClC,iBAAiB,MAAM;IACvB,OAAO,KAAK,KAAK,OAAO;GAC1B;GACA,WAAW,UAAyB,WAAgC;IAClE,iBAAiB,MAAM;IACvB,OAAO,KAAK,OAAO,UAAU,MAAM;GACrC;GACA,WAAW,cAAsB,KAAK,cAAc,SAAS;GAC7D,UAAU,YAAY;IACpB,iBAAiB,gBAAgB;IACjC,KAAK,OAAO;GACd;GACA,kBAAkB,YAAY,KAAK,cAAc,OAAO;GACxD,mCAAmC,YACjC,KAAK,sBAAsB,OAAO;GACpC,0BAA0B,YACxB,KAAK,sBAAsB,OAAO,CAAC,CAAC,OAAO,UAAmB;IAC5D,KAAK,YAAY,KAAK;IACtB,MAAM;GACR,CAAC;GACH,WAAW,WAAW,KAAK,OAAO,MAAM;GACxC,cAAc,aACZ,KAAK,sBAAsB,QAAQ;GACrC,WAAW,aACT,KAAK,sBAAsB,QAAQ;GACrC,sBAAsB,UACpB,KAAK,kBAAkB,KAAK;GAC9B,UAAU;GACV,GAAI,mBAAmB,EAAE,OAAO,gBAAgB,QAAQ;EAC1D;CACF,GAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,MAAM,cAAc,wBAAwB,KAAK;CAEjD,MAAM,sBAA4C;EAChD,OAAO;GACL,SAAS,YAAY;GACrB,IAAI,SAAS;IACX,OAAO,YAAY;GACrB;GACA,+BAA+B,aAC7B,YAAY,6BAA6B,QAAQ;GACnD,qCACE,KAAK,qBAAqB,CAAC,EAAE,cAAc,CAAC;GAC9C,oCAAoC,cAClC,KAAK,yBAAyB,SAAS;EAC3C;CACF;CACA,MAAM,CAAC,eAAe,oBAAoB,gBAAgB;EACxD;EACA,SAAS,cAAc;CACzB,EAAE;CACF,IAAI,iBAAiB;CACrB,IAAI,cAAc,gBAAgB,aAAa;EAC7C,iBAAiB;GAAE;GAAa,SAAS,cAAc;EAAE;EACzD,iBAAiB,cAAc;CACjC;CACA,MAAM,UAAU,eAAe;CAE/B,0BAA0B;EACxB,KAAK,cAAc,OAAO;EAC1B,aAAa;GACX,KAAK,cAAc;EACrB;CACF,GAAG,CAAC,MAAM,OAAO,CAAC;CAElB,gBAAgB;EACd,KAAK,gBAAgB;CACvB,GAAG,CAAC,IAAI,CAAC;CAET,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
HttpAgent,
|
|
4
|
+
type AbstractAgent,
|
|
5
|
+
runHttpRequest,
|
|
6
|
+
transformHttpEventStream,
|
|
7
|
+
type RunAgentInput,
|
|
8
|
+
} from "@ag-ui/client";
|
|
9
|
+
import type { ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
|
|
10
|
+
import { AgUiThreadController } from "./AgUiThreadController";
|
|
11
|
+
import { makeLogger } from "./logger";
|
|
12
|
+
|
|
13
|
+
const sse = (events: object[]) =>
|
|
14
|
+
new Response(
|
|
15
|
+
events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join(""),
|
|
16
|
+
{ headers: { "Content-Type": "text/event-stream" } },
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const inFlightRun = [
|
|
20
|
+
{ type: "RUN_STARTED", threadId: "thread", runId: "server-run" },
|
|
21
|
+
{ type: "TEXT_MESSAGE_START", messageId: "answer", role: "assistant" },
|
|
22
|
+
{ type: "TEXT_MESSAGE_CONTENT", messageId: "answer", delta: "Hello " },
|
|
23
|
+
{ type: "TEXT_MESSAGE_CONTENT", messageId: "answer", delta: "again" },
|
|
24
|
+
{ type: "TEXT_MESSAGE_END", messageId: "answer" },
|
|
25
|
+
{ type: "RUN_FINISHED", threadId: "thread", runId: "server-run" },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
class ReconnectingAgent extends HttpAgent {
|
|
29
|
+
readonly connectInputs: RunAgentInput[] = [];
|
|
30
|
+
|
|
31
|
+
protected override connect(input: RunAgentInput) {
|
|
32
|
+
this.connectInputs.push(input);
|
|
33
|
+
return transformHttpEventStream(
|
|
34
|
+
runHttpRequest(() =>
|
|
35
|
+
this.fetch(`${this.url}/stream`, {
|
|
36
|
+
signal: this.abortController.signal,
|
|
37
|
+
}),
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const storedUser: ThreadMessage = {
|
|
44
|
+
id: "question",
|
|
45
|
+
role: "user",
|
|
46
|
+
content: [{ type: "text", text: "Hi" }],
|
|
47
|
+
attachments: [],
|
|
48
|
+
createdAt: new Date(0),
|
|
49
|
+
metadata: { custom: {} },
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const historyOf = (unstableResume: boolean): ThreadHistoryAdapter => ({
|
|
53
|
+
load: vi.fn().mockResolvedValue({
|
|
54
|
+
headId: storedUser.id,
|
|
55
|
+
messages: [{ parentId: null, message: storedUser }],
|
|
56
|
+
...(unstableResume && { unstable_resume: true }),
|
|
57
|
+
}),
|
|
58
|
+
append: vi.fn().mockResolvedValue(undefined),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
function setup(
|
|
62
|
+
agent: AbstractAgent,
|
|
63
|
+
unstableResume: boolean,
|
|
64
|
+
onError?: (error: Error) => void,
|
|
65
|
+
) {
|
|
66
|
+
return new AgUiThreadController({
|
|
67
|
+
agent,
|
|
68
|
+
logger: makeLogger(),
|
|
69
|
+
showThinking: false,
|
|
70
|
+
history: historyOf(unstableResume),
|
|
71
|
+
...(onError && { onError }),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fetchFor = (routes: Record<string, object[]>) =>
|
|
76
|
+
vi.fn(async (url: string) => sse(routes[url] ?? []));
|
|
77
|
+
|
|
78
|
+
const transcript = (core: AgUiThreadController) =>
|
|
79
|
+
core.getMessages().map((message) => ({
|
|
80
|
+
id: message.id,
|
|
81
|
+
role: message.role,
|
|
82
|
+
text: message.content
|
|
83
|
+
.map((part) => (part.type === "text" ? part.text : ""))
|
|
84
|
+
.join(""),
|
|
85
|
+
status: message.role === "assistant" ? message.status?.type : undefined,
|
|
86
|
+
}));
|
|
87
|
+
|
|
88
|
+
const openStream = (init?: RequestInit) =>
|
|
89
|
+
new Response(
|
|
90
|
+
new ReadableStream<Uint8Array>({
|
|
91
|
+
start(controller) {
|
|
92
|
+
controller.enqueue(
|
|
93
|
+
new TextEncoder().encode(
|
|
94
|
+
`data: ${JSON.stringify(inFlightRun[0])}\n\n`,
|
|
95
|
+
),
|
|
96
|
+
);
|
|
97
|
+
init?.signal?.addEventListener("abort", () => controller.close(), {
|
|
98
|
+
once: true,
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
}),
|
|
102
|
+
{ headers: { "Content-Type": "text/event-stream" } },
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
describe("AgUiThreadController reconnect through agent.connect()", () => {
|
|
106
|
+
it("joins the in-flight run instead of starting a new one", async () => {
|
|
107
|
+
const fetch = fetchFor({ "https://agent.test/stream": inFlightRun });
|
|
108
|
+
const agent = new ReconnectingAgent({ url: "https://agent.test", fetch });
|
|
109
|
+
const core = setup(agent, true);
|
|
110
|
+
|
|
111
|
+
await core.__internal_load();
|
|
112
|
+
|
|
113
|
+
expect(fetch.mock.calls.map(([url]) => url)).toEqual([
|
|
114
|
+
"https://agent.test/stream",
|
|
115
|
+
]);
|
|
116
|
+
expect(agent.connectInputs).toHaveLength(1);
|
|
117
|
+
expect(transcript(core)).toEqual([
|
|
118
|
+
{ id: "question", role: "user", text: "Hi", status: undefined },
|
|
119
|
+
{
|
|
120
|
+
id: "answer",
|
|
121
|
+
role: "assistant",
|
|
122
|
+
text: "Hello again",
|
|
123
|
+
status: "complete",
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
expect(core.isRunning()).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("rejoins the in-flight run after a thread switch", async () => {
|
|
130
|
+
const onError = vi.fn();
|
|
131
|
+
const fetch = fetchFor({ "https://agent.test/stream": inFlightRun });
|
|
132
|
+
const agent = new ReconnectingAgent({ url: "https://agent.test", fetch });
|
|
133
|
+
const core = setup(agent, false, onError);
|
|
134
|
+
await core.__internal_load();
|
|
135
|
+
|
|
136
|
+
await core.resumeInFlightRun(core.getMessages());
|
|
137
|
+
|
|
138
|
+
expect(onError).not.toHaveBeenCalled();
|
|
139
|
+
expect(transcript(core).map(({ id, text }) => [id, text])).toEqual([
|
|
140
|
+
["question", "Hi"],
|
|
141
|
+
["answer", "Hello again"],
|
|
142
|
+
]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("rejoins through a connect class field without starting a new run", async () => {
|
|
146
|
+
class FieldReconnectingAgent extends HttpAgent {
|
|
147
|
+
protected override connect = (_input: RunAgentInput) =>
|
|
148
|
+
transformHttpEventStream(
|
|
149
|
+
runHttpRequest(() =>
|
|
150
|
+
this.fetch(`${this.url}/stream`, {
|
|
151
|
+
signal: this.abortController.signal,
|
|
152
|
+
}),
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const fetch = fetchFor({ "https://agent.test/stream": inFlightRun });
|
|
157
|
+
const agent = new FieldReconnectingAgent({
|
|
158
|
+
url: "https://agent.test",
|
|
159
|
+
fetch,
|
|
160
|
+
});
|
|
161
|
+
const core = setup(agent, true);
|
|
162
|
+
|
|
163
|
+
await core.__internal_load();
|
|
164
|
+
|
|
165
|
+
expect(fetch.mock.calls.map(([url]) => url)).toEqual([
|
|
166
|
+
"https://agent.test/stream",
|
|
167
|
+
]);
|
|
168
|
+
expect(transcript(core).map(({ id, text }) => [id, text])).toEqual([
|
|
169
|
+
["question", "Hi"],
|
|
170
|
+
["answer", "Hello again"],
|
|
171
|
+
]);
|
|
172
|
+
expect(core.isRunning()).toBe(false);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("keeps starting a run for an agent without connect()", async () => {
|
|
176
|
+
const fetch = fetchFor({ "https://agent.test": inFlightRun });
|
|
177
|
+
const agent = new HttpAgent({ url: "https://agent.test", fetch });
|
|
178
|
+
const core = setup(agent, true);
|
|
179
|
+
|
|
180
|
+
await core.__internal_load();
|
|
181
|
+
|
|
182
|
+
expect(fetch.mock.calls.map(([url]) => url)).toEqual([
|
|
183
|
+
"https://agent.test",
|
|
184
|
+
]);
|
|
185
|
+
expect(transcript(core).at(-1)).toMatchObject({ text: "Hello again" });
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("a rejoined run that replays a messages snapshot", () => {
|
|
189
|
+
const question = { id: "question", role: "user", content: "Hi" };
|
|
190
|
+
const rejoin = async (events: object[]) => {
|
|
191
|
+
const fetch = fetchFor({ "https://agent.test/stream": events });
|
|
192
|
+
const agent = new ReconnectingAgent({ url: "https://agent.test", fetch });
|
|
193
|
+
const core = setup(agent, true);
|
|
194
|
+
await core.__internal_load();
|
|
195
|
+
return core;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
it("continues the answer the snapshot restored", async () => {
|
|
199
|
+
const core = await rejoin([
|
|
200
|
+
{ type: "RUN_STARTED", threadId: "thread", runId: "server-run" },
|
|
201
|
+
{
|
|
202
|
+
type: "MESSAGES_SNAPSHOT",
|
|
203
|
+
messages: [
|
|
204
|
+
question,
|
|
205
|
+
{ id: "answer", role: "assistant", content: "Hello " },
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
{ type: "TEXT_MESSAGE_START", messageId: "answer", role: "assistant" },
|
|
209
|
+
{ type: "TEXT_MESSAGE_CONTENT", messageId: "answer", delta: "again" },
|
|
210
|
+
{ type: "TEXT_MESSAGE_END", messageId: "answer" },
|
|
211
|
+
{ type: "RUN_FINISHED", threadId: "thread", runId: "server-run" },
|
|
212
|
+
]);
|
|
213
|
+
|
|
214
|
+
expect(transcript(core)).toEqual([
|
|
215
|
+
{ id: "question", role: "user", text: "Hi", status: undefined },
|
|
216
|
+
{
|
|
217
|
+
id: "answer",
|
|
218
|
+
role: "assistant",
|
|
219
|
+
text: "Hello again",
|
|
220
|
+
status: "complete",
|
|
221
|
+
},
|
|
222
|
+
]);
|
|
223
|
+
expect(core.isRunning()).toBe(false);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("keeps a snapshot taken mid-stream from duplicating the answer", async () => {
|
|
227
|
+
const core = await rejoin([
|
|
228
|
+
{ type: "RUN_STARTED", threadId: "thread", runId: "server-run" },
|
|
229
|
+
{ type: "TEXT_MESSAGE_START", messageId: "answer", role: "assistant" },
|
|
230
|
+
{ type: "TEXT_MESSAGE_CONTENT", messageId: "answer", delta: "Hello " },
|
|
231
|
+
{
|
|
232
|
+
type: "MESSAGES_SNAPSHOT",
|
|
233
|
+
messages: [
|
|
234
|
+
question,
|
|
235
|
+
{ id: "answer", role: "assistant", content: "Hello " },
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
{ type: "TEXT_MESSAGE_CONTENT", messageId: "answer", delta: "again" },
|
|
239
|
+
{ type: "TEXT_MESSAGE_END", messageId: "answer" },
|
|
240
|
+
{ type: "RUN_FINISHED", threadId: "thread", runId: "server-run" },
|
|
241
|
+
]);
|
|
242
|
+
|
|
243
|
+
expect(transcript(core).map(({ id, text }) => [id, text])).toEqual([
|
|
244
|
+
["question", "Hi"],
|
|
245
|
+
["answer", "Hello again"],
|
|
246
|
+
]);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("settles a snapshot's pending tool call when the stream ends early", async () => {
|
|
250
|
+
const core = await rejoin([
|
|
251
|
+
{ type: "RUN_STARTED", threadId: "thread", runId: "server-run" },
|
|
252
|
+
{
|
|
253
|
+
type: "MESSAGES_SNAPSHOT",
|
|
254
|
+
messages: [
|
|
255
|
+
question,
|
|
256
|
+
{
|
|
257
|
+
id: "answer",
|
|
258
|
+
role: "assistant",
|
|
259
|
+
content: "Let me check.",
|
|
260
|
+
toolCalls: [
|
|
261
|
+
{
|
|
262
|
+
id: "call",
|
|
263
|
+
type: "function",
|
|
264
|
+
function: { name: "lookup", arguments: "{}" },
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
]);
|
|
271
|
+
|
|
272
|
+
expect(core.isRunning()).toBe(false);
|
|
273
|
+
expect(transcript(core).at(-1)).toMatchObject({
|
|
274
|
+
id: "answer",
|
|
275
|
+
text: "Let me check.",
|
|
276
|
+
});
|
|
277
|
+
const answer = core.getMessages().at(-1);
|
|
278
|
+
expect(answer?.status).toMatchObject({
|
|
279
|
+
type: "incomplete",
|
|
280
|
+
reason: "error",
|
|
281
|
+
});
|
|
282
|
+
expect(
|
|
283
|
+
answer?.content.filter((part) => part.type === "tool-call"),
|
|
284
|
+
).toMatchObject([{ toolCallId: "call", toolName: "lookup" }]);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe("leaving a thread mid-run", () => {
|
|
289
|
+
const startOpenRun = async () => {
|
|
290
|
+
const agent = new ReconnectingAgent({
|
|
291
|
+
url: "https://agent.test",
|
|
292
|
+
fetch: vi.fn(async (_url: string, init?: RequestInit) =>
|
|
293
|
+
openStream(init),
|
|
294
|
+
),
|
|
295
|
+
});
|
|
296
|
+
const abortRun = vi.spyOn(agent, "abortRun");
|
|
297
|
+
const detachActiveRun = vi.spyOn(agent, "detachActiveRun");
|
|
298
|
+
const core = setup(agent, true);
|
|
299
|
+
void core.__internal_load();
|
|
300
|
+
await vi.waitFor(() => expect(core.isRunning()).toBe(true));
|
|
301
|
+
return { core, abortRun, detachActiveRun };
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
it("detaches on a thread switch so the run can be rejoined", async () => {
|
|
305
|
+
const { core, abortRun, detachActiveRun } = await startOpenRun();
|
|
306
|
+
|
|
307
|
+
core.resetThreadState();
|
|
308
|
+
|
|
309
|
+
expect(detachActiveRun).toHaveBeenCalledTimes(1);
|
|
310
|
+
expect(abortRun).not.toHaveBeenCalled();
|
|
311
|
+
expect(core.isRunning()).toBe(false);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it("detaches when the runtime unmounts", async () => {
|
|
315
|
+
const { core, abortRun, detachActiveRun } = await startOpenRun();
|
|
316
|
+
|
|
317
|
+
core.detachRuntime();
|
|
318
|
+
|
|
319
|
+
expect(detachActiveRun).toHaveBeenCalledTimes(1);
|
|
320
|
+
expect(abortRun).not.toHaveBeenCalled();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("aborts the run on an explicit cancel", async () => {
|
|
324
|
+
const { core, abortRun, detachActiveRun } = await startOpenRun();
|
|
325
|
+
|
|
326
|
+
await core.cancel();
|
|
327
|
+
|
|
328
|
+
expect(abortRun).toHaveBeenCalledTimes(1);
|
|
329
|
+
expect(detachActiveRun).not.toHaveBeenCalled();
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
describe("with an agent built on another copy of @ag-ui/client", () => {
|
|
334
|
+
// Same shape as AbstractAgent: a root class that defines connect() and
|
|
335
|
+
// connectAgent() and extends nothing, as a second installed copy would.
|
|
336
|
+
class ForeignAbstractAgent {
|
|
337
|
+
threadId = "thread";
|
|
338
|
+
messages: unknown[] = [];
|
|
339
|
+
state = {};
|
|
340
|
+
readonly runAgent = vi.fn(async () => ({ newMessages: [] }));
|
|
341
|
+
readonly connectAgent = vi.fn(async () => ({ newMessages: [] }));
|
|
342
|
+
readonly abortRun = vi.fn();
|
|
343
|
+
readonly detachActiveRun = vi.fn(async () => {});
|
|
344
|
+
connect(): never {
|
|
345
|
+
throw new Error("connect not implemented");
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
class ForeignReconnectingAgent extends ForeignAbstractAgent {
|
|
349
|
+
override connect(): never {
|
|
350
|
+
throw new Error("unused");
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const asAgent = (agent: ForeignAbstractAgent) =>
|
|
354
|
+
agent as unknown as AbstractAgent;
|
|
355
|
+
|
|
356
|
+
it("starts a run for a stock agent", async () => {
|
|
357
|
+
const agent = new ForeignAbstractAgent();
|
|
358
|
+
await setup(asAgent(agent), true).__internal_load();
|
|
359
|
+
|
|
360
|
+
expect(agent.runAgent).toHaveBeenCalledTimes(1);
|
|
361
|
+
expect(agent.connectAgent).not.toHaveBeenCalled();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it("rejoins through connectAgent() for an agent that overrides connect()", async () => {
|
|
365
|
+
const agent = new ForeignReconnectingAgent();
|
|
366
|
+
await setup(asAgent(agent), true).__internal_load();
|
|
367
|
+
|
|
368
|
+
expect(agent.connectAgent).toHaveBeenCalledTimes(1);
|
|
369
|
+
expect(agent.runAgent).not.toHaveBeenCalled();
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
});
|