@assistant-ui/core 0.2.6 → 0.2.8
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/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -0
- package/dist/internal/duplicate-detection.d.ts +5 -0
- package/dist/internal/duplicate-detection.d.ts.map +1 -0
- package/dist/internal/duplicate-detection.js +11 -0
- package/dist/internal/duplicate-detection.js.map +1 -0
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +2 -2
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js.map +1 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/tool.d.ts.map +1 -1
- package/dist/react/AssistantProvider.d.ts.map +1 -1
- package/dist/react/AssistantProvider.js.map +1 -1
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +26 -15
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/index.d.ts +5 -4
- package/dist/react/index.js +2 -2
- package/dist/react/model-context/toolbox.d.ts +29 -2
- package/dist/react/model-context/toolbox.d.ts.map +1 -1
- package/dist/react/model-context/toolbox.js +18 -0
- package/dist/react/model-context/toolbox.js.map +1 -0
- package/dist/react/model-context/useAssistantTool.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantTool.js +6 -3
- package/dist/react/model-context/useAssistantTool.js.map +1 -1
- package/dist/react/model-context/useAssistantToolUI.d.ts +6 -0
- package/dist/react/model-context/useAssistantToolUI.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantToolUI.js +4 -2
- package/dist/react/model-context/useAssistantToolUI.js.map +1 -1
- package/dist/react/model-context/useInlineRender.js.map +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.d.ts +49 -7
- package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js +28 -3
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +2 -7
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.js +6 -5
- package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/external-message-converter.d.ts +1 -1
- package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +1 -0
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreSharedOptions.d.ts +7 -0
- package/dist/react/runtimes/useExternalStoreSharedOptions.d.ts.map +1 -0
- package/dist/react/runtimes/useExternalStoreSharedOptions.js +21 -0
- package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -0
- package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
- package/dist/react/types/scopes/tools.d.ts +19 -2
- package/dist/react/types/scopes/tools.d.ts.map +1 -1
- package/dist/react/utils/groupParts.d.ts +32 -11
- package/dist/react/utils/groupParts.d.ts.map +1 -1
- package/dist/react/utils/groupParts.js +13 -6
- package/dist/react/utils/groupParts.js.map +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
- package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
- package/dist/runtime/api/attachment-runtime.js.map +1 -1
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/base/base-assistant-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +8 -0
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts +9 -1
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +34 -14
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/thread-message-like.d.ts +1 -0
- package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +2 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtimes/external-store/external-store-adapter.d.ts +31 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-shared-options.d.ts +8 -0
- package/dist/runtimes/external-store/external-store-shared-options.d.ts.map +1 -0
- package/dist/runtimes/external-store/external-store-shared-options.js +11 -0
- package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -0
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +25 -2
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +106 -26
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/thread-message-converter.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +168 -0
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -0
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +449 -0
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -0
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
- package/dist/types/message.d.ts +6 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/id.d.ts +1 -3
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +1 -4
- package/dist/utils/id.js.map +1 -1
- package/package.json +10 -10
- package/src/adapters/index.ts +1 -4
- package/src/adapters/speech.ts +0 -1
- package/src/index.ts +12 -0
- package/src/internal/duplicate-detection.ts +26 -0
- package/src/internal.ts +0 -2
- package/src/model-context/frame/host.ts +0 -1
- package/src/model-context/frame/provider.ts +0 -1
- package/src/react/AssistantProvider.tsx +2 -3
- package/src/react/client/Interactables.ts +0 -1
- package/src/react/client/Tools.ts +50 -25
- package/src/react/index.ts +9 -8
- package/src/react/model-context/toolbox.ts +46 -1
- package/src/react/model-context/useAssistantTool.ts +8 -3
- package/src/react/model-context/useAssistantToolUI.ts +9 -2
- package/src/react/model-context/useInlineRender.ts +0 -1
- package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -2
- package/src/react/primitives/message/MessageAttachments.test.tsx +1 -1
- package/src/react/primitives/message/MessageGroupedParts.tsx +102 -13
- package/src/react/primitives/message/MessageParts.tsx +4 -7
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +0 -3
- package/src/react/runtimes/RuntimeAdapterProvider.tsx +12 -7
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +0 -3
- package/src/react/runtimes/external-message-converter.ts +5 -1
- package/src/react/runtimes/useExternalStoreSharedOptions.ts +23 -0
- package/src/react/runtimes/useLocalRuntime.ts +0 -10
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +0 -6
- package/src/react/types/scopes/tools.ts +20 -1
- package/src/react/utils/groupParts.ts +49 -18
- package/src/runtime/api/attachment-runtime.ts +1 -2
- package/src/runtime/interfaces/thread-runtime-core.ts +8 -0
- package/src/runtime/internal.ts +1 -4
- package/src/runtime/utils/message-repository.ts +57 -16
- package/src/runtime/utils/thread-message-like.ts +2 -0
- package/src/runtimes/external-store/external-store-adapter.ts +33 -0
- package/src/runtimes/external-store/external-store-shared-options.ts +18 -0
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +1 -3
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +179 -37
- package/src/runtimes/tool-invocations/EDGE_CASES.md +194 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +1054 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +782 -0
- package/src/subscribable/subscribable.ts +3 -3
- package/src/tests/MessageRepository.test.ts +83 -52
- package/src/tests/OptimisticState-delete-crash.test.ts +2 -0
- package/src/tests/OptimisticState-list-race.test.ts +2 -4
- package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +5 -5
- package/src/tests/auiV0Encode.test.ts +1 -1
- package/src/tests/composer-can-send.test.ts +8 -4
- package/src/tests/duplicate-detection.test.ts +34 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +1 -1
- package/src/tests/external-store-thread-runtime-core.test.ts +112 -79
- package/src/tests/groupParts.test.ts +70 -0
- package/src/tests/no-unsafe-process-env.test.ts +1 -0
- package/src/tests/remote-thread-list-isLoading.test.ts +2 -5
- package/src/tests/thread-message-like.test.ts +4 -1
- package/src/types/index.ts +1 -4
- package/src/types/message.ts +6 -0
- package/src/utils/id.ts +0 -4
- package/dist/react/runtimes/useToolInvocations.d.ts +0 -53
- package/dist/react/runtimes/useToolInvocations.d.ts.map +0 -1
- package/dist/react/runtimes/useToolInvocations.js +0 -380
- package/dist/react/runtimes/useToolInvocations.js.map +0 -1
- package/src/react/runtimes/useToolInvocations.ts +0 -694
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","names":[],"sources":["../../src/types/message.ts"],"sourcesContent":["import type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ToolModelContentPart } from \"assistant-stream\";\nimport type { CompleteAttachment } from \"./attachment\";\n\nexport type { ToolModelContentPart };\n\nexport type TextMessagePart = {\n readonly type: \"text\";\n readonly text: string;\n readonly parentId?: string;\n};\n\nexport type ReasoningMessagePart = {\n readonly type: \"reasoning\";\n readonly text: string;\n readonly parentId?: string;\n};\n\nexport type SourceProviderMetadata = {\n readonly [providerName: string]: ReadonlyJSONObject;\n};\n\nexport type SourceMessagePart =\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly url?: undefined;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n };\n\nexport type ImageMessagePart = {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n};\n\nexport type FileMessagePart = {\n readonly type: \"file\";\n readonly filename?: string;\n readonly data: string;\n readonly mimeType: string;\n readonly parentId?: string;\n};\n\nexport type Unstable_AudioMessagePart = {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n};\n\nexport type DataMessagePart<T = any> = {\n readonly type: \"data\";\n readonly name: string;\n readonly data: T;\n};\n\n/**\n * A JSON spec describing a tree of UI components to render.\n *\n * The agent emits a {@link GenerativeUIMessagePart} containing this spec, and\n * the consumer-provided component allowlist is used to resolve `component`\n * names. Any component referenced that is not present in the allowlist is\n * rejected with a typed error — the allowlist is the security boundary in the\n * default same-realm rendering path.\n */\nexport type GenerativeUINode =\n | string\n | {\n /** Allowlisted component name (resolved against the consumer registry). */\n readonly component: string;\n /** Props passed to the resolved component (must be JSON-serializable). */\n readonly props?: Record<string, unknown>;\n /** Optional children — strings render as text, objects recurse. */\n readonly children?: readonly GenerativeUINode[];\n /** Optional stable key for React reconciliation. */\n readonly key?: string;\n };\n\n/**\n * The root spec for a generative UI tree.\n */\nexport type GenerativeUISpec = {\n /** Root node(s) to render. */\n readonly root: GenerativeUINode | readonly GenerativeUINode[];\n};\n\n/**\n * A message part that carries a JSON spec describing UI to render.\n *\n * Render with `<MessagePrimitive.GenerativeUI components={...} />`. The\n * primitive resolves component names against the consumer-provided allowlist\n * — any unknown name throws a typed error rather than rendering. Stream-\n * friendly: a partially-streamed spec renders progressively.\n */\nexport type GenerativeUIMessagePart = {\n readonly type: \"generative-ui\";\n /** The JSON spec describing the UI tree. */\n readonly spec: GenerativeUISpec;\n /** Optional id (useful for replays / stable keys). */\n readonly id?: string;\n readonly parentId?: string;\n};\n\nexport type McpAppMetadata = {\n readonly resourceUri: string;\n readonly mimeType?: string;\n readonly visibility?: readonly (\"model\" | \"app\")[];\n};\n\nexport const MCP_APP_URI_SCHEME = \"ui://\";\n\nexport const isMcpAppUri = (uri: string | undefined): boolean =>\n !!uri?.startsWith(MCP_APP_URI_SCHEME);\n\nexport type ToolCallMessagePartMcpMetadata = {\n readonly app?: McpAppMetadata;\n};\n\nexport type ToolCallMessagePart<\n TArgs = ReadonlyJSONObject,\n TResult = unknown,\n> = {\n /** Identifies this part as a tool call. */\n readonly type: \"tool-call\";\n /** Stable identifier for this invocation of the tool. */\n readonly toolCallId: string;\n /** Name of the tool requested by the model. */\n readonly toolName: string;\n /**\n * Arguments supplied by the model. During streaming this is a partial parse:\n * fields may be missing or incomplete. From a tool-call renderer, use\n * `useToolArgsStatus` to detect which fields are still arriving.\n */\n readonly args: TArgs;\n /** Result returned by the tool, if it has completed. */\n readonly result?: TResult | undefined;\n /** Whether the result represents a tool execution error. */\n readonly isError?: boolean | undefined;\n /** Raw JSON argument text streamed by the model. */\n readonly argsText: string;\n /** UI-only artifact associated with the tool result. */\n readonly artifact?: unknown;\n /** MCP app metadata associated with this tool call, when present. */\n readonly mcp?: ToolCallMessagePartMcpMetadata;\n /** Content returned to the model for this tool result. */\n readonly modelContent?: readonly ToolModelContentPart[] | undefined;\n /** Human-input request that must be resolved before the run can continue. */\n readonly interrupt?: { type: \"human\"; payload: unknown };\n /** Server-side approval gate. `approved === undefined` is the only state in which `respondToApproval` may be called. */\n readonly approval?: {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n };\n /** Parent message-part ID when this part belongs to a nested structure. */\n readonly parentId?: string;\n /**\n * Nested thread messages produced by this tool call, for example a sub-agent\n * conversation.\n */\n readonly messages?: readonly ThreadMessage[];\n};\n\nexport type ThreadUserMessagePart =\n | TextMessagePart\n | ImageMessagePart\n | FileMessagePart\n | DataMessagePart\n | Unstable_AudioMessagePart;\n\nexport type ThreadAssistantMessagePart =\n | TextMessagePart\n | ReasoningMessagePart\n | ToolCallMessagePart\n | SourceMessagePart\n | FileMessagePart\n | ImageMessagePart\n | DataMessagePart\n | GenerativeUIMessagePart;\n\nexport type MessagePartStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"complete\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: unknown;\n };\n\nexport type ToolCallMessagePartStatus =\n | {\n /** The tool call is waiting for UI or human input before continuing. */\n readonly type: \"requires-action\";\n /** Reason the tool call requires action. */\n readonly reason: \"interrupt\";\n }\n | MessagePartStatus;\n\nexport type MessageStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"requires-action\";\n readonly reason: \"tool-calls\" | \"interrupt\";\n }\n | {\n readonly type: \"complete\";\n readonly reason: \"stop\" | \"unknown\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"tool-calls\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: ReadonlyJSONValue;\n };\n\nexport type MessageTiming = {\n readonly streamStartTime: number;\n readonly firstTokenTime?: number;\n readonly totalStreamTime?: number;\n readonly tokenCount?: number;\n readonly tokensPerSecond?: number;\n readonly totalChunks: number;\n readonly toolCallCount: number;\n};\n\nexport type ThreadStep = {\n readonly messageId?: string;\n readonly usage?:\n | {\n readonly inputTokens: number;\n readonly outputTokens: number;\n }\n | undefined;\n};\n\ntype MessageCommonProps = {\n readonly id: string;\n readonly createdAt: Date;\n};\n\nexport type ThreadSystemMessage = MessageCommonProps & {\n readonly role: \"system\";\n readonly content: readonly [TextMessagePart];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadUserMessage = MessageCommonProps & {\n readonly role: \"user\";\n readonly content: readonly ThreadUserMessagePart[];\n readonly attachments: readonly CompleteAttachment[];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadAssistantMessage = MessageCommonProps & {\n readonly role: \"assistant\";\n readonly content: readonly ThreadAssistantMessagePart[];\n readonly status: MessageStatus;\n readonly metadata: {\n readonly unstable_state: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n readonly custom: Record<string, unknown>;\n };\n};\n\ntype BaseThreadMessage = {\n readonly status?: ThreadAssistantMessage[\"status\"];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations?: readonly ReadonlyJSONValue[];\n readonly unstable_data?: readonly ReadonlyJSONValue[];\n readonly steps?: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n readonly custom: Record<string, unknown>;\n };\n readonly attachments?: ThreadUserMessage[\"attachments\"];\n};\n\nexport type ThreadMessage = BaseThreadMessage &\n (ThreadSystemMessage | ThreadUserMessage | ThreadAssistantMessage);\n\nexport type MessageRole = ThreadMessage[\"role\"];\n\nexport type RunConfig = {\n readonly custom?: Record<string, unknown>;\n};\n\nexport type AppendMessage = Omit<ThreadMessage, \"id\"> & {\n parentId: string | null;\n\n /** The ID of the message that was edited or undefined. */\n sourceId: string | null;\n runConfig: RunConfig | undefined;\n startRun?: boolean | undefined;\n};\n"],"mappings":";AAgIA,MAAa,qBAAqB;AAElC,MAAa,eAAe,QAC1B,CAAC,CAAC,KAAK,WAAW,kBAAkB"}
|
|
1
|
+
{"version":3,"file":"message.js","names":[],"sources":["../../src/types/message.ts"],"sourcesContent":["import type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ToolModelContentPart } from \"assistant-stream\";\nimport type { CompleteAttachment } from \"./attachment\";\n\nexport type { ToolModelContentPart };\n\nexport type TextMessagePart = {\n readonly type: \"text\";\n readonly text: string;\n readonly parentId?: string;\n};\n\nexport type ReasoningMessagePart = {\n readonly type: \"reasoning\";\n readonly text: string;\n readonly parentId?: string;\n};\n\nexport type SourceProviderMetadata = {\n readonly [providerName: string]: ReadonlyJSONObject;\n};\n\nexport type SourceMessagePart =\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly url?: undefined;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n };\n\nexport type ImageMessagePart = {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n};\n\nexport type FileMessagePart = {\n readonly type: \"file\";\n readonly filename?: string;\n readonly data: string;\n readonly mimeType: string;\n readonly parentId?: string;\n};\n\nexport type Unstable_AudioMessagePart = {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n};\n\nexport type DataMessagePart<T = any> = {\n readonly type: \"data\";\n readonly name: string;\n readonly data: T;\n};\n\n/**\n * A JSON spec describing a tree of UI components to render.\n *\n * The agent emits a {@link GenerativeUIMessagePart} containing this spec, and\n * the consumer-provided component allowlist is used to resolve `component`\n * names. Any component referenced that is not present in the allowlist is\n * rejected with a typed error — the allowlist is the security boundary in the\n * default same-realm rendering path.\n */\nexport type GenerativeUINode =\n | string\n | {\n /** Allowlisted component name (resolved against the consumer registry). */\n readonly component: string;\n /** Props passed to the resolved component (must be JSON-serializable). */\n readonly props?: Record<string, unknown>;\n /** Optional children — strings render as text, objects recurse. */\n readonly children?: readonly GenerativeUINode[];\n /** Optional stable key for React reconciliation. */\n readonly key?: string;\n };\n\n/**\n * The root spec for a generative UI tree.\n */\nexport type GenerativeUISpec = {\n /** Root node(s) to render. */\n readonly root: GenerativeUINode | readonly GenerativeUINode[];\n};\n\n/**\n * A message part that carries a JSON spec describing UI to render.\n *\n * Render with `<MessagePrimitive.GenerativeUI components={...} />`. The\n * primitive resolves component names against the consumer-provided allowlist\n * — any unknown name throws a typed error rather than rendering. Stream-\n * friendly: a partially-streamed spec renders progressively.\n */\nexport type GenerativeUIMessagePart = {\n readonly type: \"generative-ui\";\n /** The JSON spec describing the UI tree. */\n readonly spec: GenerativeUISpec;\n /** Optional id (useful for replays / stable keys). */\n readonly id?: string;\n readonly parentId?: string;\n};\n\nexport type McpAppMetadata = {\n readonly resourceUri: string;\n readonly mimeType?: string;\n readonly visibility?: readonly (\"model\" | \"app\")[];\n};\n\nexport const MCP_APP_URI_SCHEME = \"ui://\";\n\nexport const isMcpAppUri = (uri: string | undefined): boolean =>\n !!uri?.startsWith(MCP_APP_URI_SCHEME);\n\nexport type ToolCallMessagePartMcpMetadata = {\n readonly app?: McpAppMetadata;\n};\n\nexport type ToolCallMessagePart<\n TArgs = ReadonlyJSONObject,\n TResult = unknown,\n> = {\n /** Identifies this part as a tool call. */\n readonly type: \"tool-call\";\n /** Stable identifier for this invocation of the tool. */\n readonly toolCallId: string;\n /** Name of the tool requested by the model. */\n readonly toolName: string;\n /**\n * Arguments supplied by the model. During streaming this is a partial parse:\n * fields may be missing or incomplete. From a tool-call renderer, use\n * `useToolArgsStatus` to detect which fields are still arriving.\n */\n readonly args: TArgs;\n /** Result returned by the tool, if it has completed. */\n readonly result?: TResult | undefined;\n /** Whether the result represents a tool execution error. */\n readonly isError?: boolean | undefined;\n /** Raw JSON argument text streamed by the model. */\n readonly argsText: string;\n /** UI-only artifact associated with the tool result. */\n readonly artifact?: unknown;\n /** MCP app metadata associated with this tool call, when present. */\n readonly mcp?: ToolCallMessagePartMcpMetadata;\n /** Content returned to the model for this tool result. */\n readonly modelContent?: readonly ToolModelContentPart[] | undefined;\n /** Human-input request that must be resolved before the run can continue. */\n readonly interrupt?: { type: \"human\"; payload: unknown };\n /** Server-side approval gate. `approved === undefined` is the only state in which `respondToApproval` may be called. */\n readonly approval?: {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n };\n /** Parent message-part ID when this part belongs to a nested structure. */\n readonly parentId?: string;\n /**\n * Nested thread messages produced by this tool call, for example a sub-agent\n * conversation.\n */\n readonly messages?: readonly ThreadMessage[];\n};\n\nexport type ThreadUserMessagePart =\n | TextMessagePart\n | ImageMessagePart\n | FileMessagePart\n | DataMessagePart\n | Unstable_AudioMessagePart;\n\nexport type ThreadAssistantMessagePart =\n | TextMessagePart\n | ReasoningMessagePart\n | ToolCallMessagePart\n | SourceMessagePart\n | FileMessagePart\n | ImageMessagePart\n | DataMessagePart\n | GenerativeUIMessagePart;\n\nexport type MessagePartStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"complete\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: unknown;\n };\n\nexport type ToolCallMessagePartStatus =\n | {\n /** The tool call is waiting for UI or human input before continuing. */\n readonly type: \"requires-action\";\n /** Reason the tool call requires action. */\n readonly reason: \"interrupt\";\n }\n | MessagePartStatus;\n\nexport type MessageStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"requires-action\";\n readonly reason: \"tool-calls\" | \"interrupt\";\n }\n | {\n readonly type: \"complete\";\n readonly reason: \"stop\" | \"unknown\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"tool-calls\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: ReadonlyJSONValue;\n };\n\nexport type MessageTiming = {\n readonly streamStartTime: number;\n readonly firstTokenTime?: number;\n readonly totalStreamTime?: number;\n readonly tokenCount?: number;\n readonly tokensPerSecond?: number;\n readonly totalChunks: number;\n readonly toolCallCount: number;\n};\n\nexport type ThreadStep = {\n readonly messageId?: string;\n readonly usage?:\n | {\n readonly inputTokens: number;\n readonly outputTokens: number;\n }\n | undefined;\n};\n\ntype MessageCommonProps = {\n readonly id: string;\n readonly createdAt: Date;\n};\n\nexport type ThreadSystemMessage = MessageCommonProps & {\n readonly role: \"system\";\n readonly content: readonly [TextMessagePart];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadUserMessage = MessageCommonProps & {\n readonly role: \"user\";\n readonly content: readonly ThreadUserMessagePart[];\n readonly attachments: readonly CompleteAttachment[];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadAssistantMessage = MessageCommonProps & {\n readonly role: \"assistant\";\n readonly content: readonly ThreadAssistantMessagePart[];\n readonly status: MessageStatus;\n readonly metadata: {\n readonly unstable_state: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n /**\n * Marks a client-side optimistic placeholder. Such messages are evicted\n * once off the head branch and are never persisted.\n */\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n};\n\ntype BaseThreadMessage = {\n readonly status?: ThreadAssistantMessage[\"status\"];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations?: readonly ReadonlyJSONValue[];\n readonly unstable_data?: readonly ReadonlyJSONValue[];\n readonly steps?: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n readonly attachments?: ThreadUserMessage[\"attachments\"];\n};\n\nexport type ThreadMessage = BaseThreadMessage &\n (ThreadSystemMessage | ThreadUserMessage | ThreadAssistantMessage);\n\nexport type MessageRole = ThreadMessage[\"role\"];\n\nexport type RunConfig = {\n readonly custom?: Record<string, unknown>;\n};\n\nexport type AppendMessage = Omit<ThreadMessage, \"id\"> & {\n parentId: string | null;\n\n /** The ID of the message that was edited or undefined. */\n sourceId: string | null;\n runConfig: RunConfig | undefined;\n startRun?: boolean | undefined;\n};\n"],"mappings":";AAgIA,MAAa,qBAAqB;AAElC,MAAa,eAAe,QAC1B,CAAC,CAAC,KAAK,WAAW,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composite-context-provider.d.ts","names":[],"sources":["../../src/utils/composite-context-provider.ts"],"mappings":";;cAKa,wBAAA,YAAoC,oBAAA;EAAA,QACvC,UAAA;EAER,eAAA,
|
|
1
|
+
{"version":3,"file":"composite-context-provider.d.ts","names":[],"sources":["../../src/utils/composite-context-provider.ts"],"mappings":";;cAKa,wBAAA,YAAoC,oBAAA;EAAA,QACvC,UAAA;EAER,eAAA,IAHoC,YAAA;EAOpC,4BAAA,CAA6B,QAAA,EAAU,oBAAA;EAAA,QAa/B,YAAA;EAER,iBAAA;EAIA,SAAA,CAAU,QAAA;AAAA"}
|
package/dist/utils/id.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
//#region src/utils/id.d.ts
|
|
2
2
|
declare const generateId: (size?: number) => string;
|
|
3
|
-
declare const generateOptimisticId: () => string;
|
|
4
|
-
declare const isOptimisticId: (id: string) => boolean;
|
|
5
3
|
declare const generateErrorMessageId: () => string;
|
|
6
4
|
declare const isErrorMessageId: (id: string) => boolean;
|
|
7
5
|
//#endregion
|
|
8
|
-
export { generateErrorMessageId, generateId,
|
|
6
|
+
export { generateErrorMessageId, generateId, isErrorMessageId };
|
|
9
7
|
//# sourceMappingURL=id.d.ts.map
|
package/dist/utils/id.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.d.ts","names":[],"sources":["../../src/utils/id.ts"],"mappings":";cAEa,UAAA,GAAU,IAAA;AAAA,cAMV,
|
|
1
|
+
{"version":3,"file":"id.d.ts","names":[],"sources":["../../src/utils/id.ts"],"mappings":";cAEa,UAAA,GAAU,IAAA;AAAA,cAMV,sBAAA;AAAA,cACA,gBAAA,GAAoB,EAAU"}
|
package/dist/utils/id.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { customAlphabet } from "nanoid/non-secure";
|
|
2
2
|
//#region src/utils/id.ts
|
|
3
3
|
const generateId = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 7);
|
|
4
|
-
const optimisticPrefix = "__optimistic__";
|
|
5
|
-
const generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
|
|
6
|
-
const isOptimisticId = (id) => id.startsWith(optimisticPrefix);
|
|
7
4
|
const errorPrefix = "__error__";
|
|
8
5
|
const generateErrorMessageId = () => `${errorPrefix}${generateId()}`;
|
|
9
6
|
const isErrorMessageId = (id) => id.startsWith(errorPrefix);
|
|
10
7
|
//#endregion
|
|
11
|
-
export { generateErrorMessageId, generateId,
|
|
8
|
+
export { generateErrorMessageId, generateId, isErrorMessageId };
|
|
12
9
|
|
|
13
10
|
//# sourceMappingURL=id.js.map
|
package/dist/utils/id.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.js","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["import { customAlphabet } from \"nanoid/non-secure\";\n\nexport const generateId = customAlphabet(\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\",\n 7,\n);\n\nconst
|
|
1
|
+
{"version":3,"file":"id.js","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["import { customAlphabet } from \"nanoid/non-secure\";\n\nexport const generateId = customAlphabet(\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\",\n 7,\n);\n\nconst errorPrefix = \"__error__\";\nexport const generateErrorMessageId = () => `${errorPrefix}${generateId()}`;\nexport const isErrorMessageId = (id: string) => id.startsWith(errorPrefix);\n"],"mappings":";;AAEA,MAAa,aAAa,eACxB,kEACA,CACF;AAEA,MAAM,cAAc;AACpB,MAAa,+BAA+B,GAAG,cAAc,WAAW;AACxE,MAAa,oBAAoB,OAAe,GAAG,WAAW,WAAW"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Framework-agnostic core runtime for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assistant",
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
],
|
|
60
60
|
"sideEffects": false,
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"assistant-stream": "^0.3.
|
|
62
|
+
"assistant-stream": "^0.3.18",
|
|
63
63
|
"nanoid": "^5.1.11"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@assistant-ui/store": "^0.2.
|
|
67
|
-
"@assistant-ui/tap": "^0.5.
|
|
66
|
+
"@assistant-ui/store": "^0.2.13",
|
|
67
|
+
"@assistant-ui/tap": "^0.5.14",
|
|
68
68
|
"@types/react": "*",
|
|
69
69
|
"react": "^18 || ^19",
|
|
70
|
-
"assistant-cloud": "^0.1.
|
|
70
|
+
"assistant-cloud": "^0.1.30",
|
|
71
71
|
"zustand": "^5.0.11"
|
|
72
72
|
},
|
|
73
73
|
"peerDependenciesMeta": {
|
|
@@ -88,11 +88,11 @@
|
|
|
88
88
|
"@types/react": "^19.2.15",
|
|
89
89
|
"react": "^19.2.6",
|
|
90
90
|
"vitest": "^4.1.7",
|
|
91
|
-
"zustand": "^5.0.
|
|
92
|
-
"@assistant-ui/store": "0.2.
|
|
93
|
-
"@assistant-ui/tap": "0.5.
|
|
94
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
95
|
-
"assistant-cloud": "0.1.
|
|
91
|
+
"zustand": "^5.0.14",
|
|
92
|
+
"@assistant-ui/store": "0.2.13",
|
|
93
|
+
"@assistant-ui/tap": "0.5.14",
|
|
94
|
+
"@assistant-ui/x-buildutils": "0.0.10",
|
|
95
|
+
"assistant-cloud": "0.1.30"
|
|
96
96
|
},
|
|
97
97
|
"publishConfig": {
|
|
98
98
|
"access": "public",
|
package/src/adapters/index.ts
CHANGED
|
@@ -8,10 +8,7 @@ export {
|
|
|
8
8
|
|
|
9
9
|
// Speech adapters
|
|
10
10
|
export type { SpeechSynthesisAdapter, DictationAdapter } from "./speech";
|
|
11
|
-
export {
|
|
12
|
-
WebSpeechSynthesisAdapter,
|
|
13
|
-
WebSpeechDictationAdapter,
|
|
14
|
-
} from "./speech";
|
|
11
|
+
export { WebSpeechSynthesisAdapter, WebSpeechDictationAdapter } from "./speech";
|
|
15
12
|
|
|
16
13
|
// Voice adapter
|
|
17
14
|
export type { RealtimeVoiceAdapter } from "./voice";
|
package/src/adapters/speech.ts
CHANGED
|
@@ -64,7 +64,6 @@ export class WebSpeechSynthesisAdapter implements SpeechSynthesisAdapter {
|
|
|
64
64
|
if (res.status.type === "ended") return;
|
|
65
65
|
|
|
66
66
|
res.status = { type: "ended", reason, error };
|
|
67
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
68
67
|
subscribers.forEach((handler) => handler());
|
|
69
68
|
};
|
|
70
69
|
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
// @assistant-ui/core - Framework-agnostic core runtime (public API)
|
|
2
2
|
|
|
3
|
+
/// <reference path="./store/scope-registration.ts" />
|
|
4
|
+
|
|
5
|
+
import { checkDuplicateCore } from "./internal/duplicate-detection";
|
|
6
|
+
|
|
7
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8
|
+
checkDuplicateCore();
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
export type {
|
|
4
12
|
// Message parts
|
|
5
13
|
TextMessagePart,
|
|
@@ -80,6 +88,8 @@ export { mergeModelContexts } from "./model-context/types";
|
|
|
80
88
|
|
|
81
89
|
export { tool } from "./model-context/tool";
|
|
82
90
|
|
|
91
|
+
export type { ToolExecutionStatus } from "./runtimes/tool-invocations/ToolInvocationTracker";
|
|
92
|
+
|
|
83
93
|
export { ModelContextRegistry } from "./model-context/registry";
|
|
84
94
|
export type {
|
|
85
95
|
ModelContextRegistryToolHandle,
|
|
@@ -272,6 +282,8 @@ export type {
|
|
|
272
282
|
ExternalStoreThreadListAdapter,
|
|
273
283
|
ExternalStoreThreadData,
|
|
274
284
|
} from "./runtimes/external-store/external-store-adapter";
|
|
285
|
+
export type { ExternalStoreSharedOptions } from "./runtimes/external-store/external-store-shared-options";
|
|
286
|
+
export { pickExternalStoreSharedOptions } from "./runtimes/external-store/external-store-shared-options";
|
|
275
287
|
|
|
276
288
|
// Remote Thread List (user-facing)
|
|
277
289
|
export type {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Warns once if a second copy of @assistant-ui/core is loaded into the
|
|
2
|
+
// same runtime. Mismatched transitive versions of core silently break
|
|
3
|
+
// runtime behavior — tools registered via `makeAssistantTool` don't reach
|
|
4
|
+
// the active runtime, context lookups resolve to the wrong provider,
|
|
5
|
+
// `instanceof` checks fail (see issue #4101). The actual version diagnosis
|
|
6
|
+
// lives in `npx assistant-ui doctor`.
|
|
7
|
+
//
|
|
8
|
+
// The caller is responsible for gating on `process.env.NODE_ENV` so this
|
|
9
|
+
// module tree-shakes out of production bundles.
|
|
10
|
+
|
|
11
|
+
const KEY = Symbol.for("@assistant-ui/core.loaded");
|
|
12
|
+
|
|
13
|
+
export function checkDuplicateCore(): void {
|
|
14
|
+
const g = globalThis as unknown as Record<symbol, boolean | undefined>;
|
|
15
|
+
if (g[KEY]) {
|
|
16
|
+
// eslint-disable-next-line no-console
|
|
17
|
+
console.warn(
|
|
18
|
+
"[@assistant-ui/core] Multiple copies of @assistant-ui/core are " +
|
|
19
|
+
"loaded into the same runtime. This causes subtle bugs (tools not " +
|
|
20
|
+
"reaching the runtime, context lookups returning the wrong " +
|
|
21
|
+
"provider, instanceof checks failing). Run " +
|
|
22
|
+
"`npx assistant-ui doctor` to diagnose.",
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
g[KEY] = true;
|
|
26
|
+
}
|
package/src/internal.ts
CHANGED
|
@@ -175,7 +175,6 @@ export class AssistantFrameHost implements ModelContextProvider {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
private notifySubscribers() {
|
|
178
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
179
178
|
this._subscribers.forEach((callback) => callback());
|
|
180
179
|
}
|
|
181
180
|
|
|
@@ -179,7 +179,6 @@ export class AssistantFrameProvider {
|
|
|
179
179
|
const instance = AssistantFrameProvider._instance;
|
|
180
180
|
window.removeEventListener("message", instance.handleMessage);
|
|
181
181
|
|
|
182
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
183
182
|
instance._providerUnsubscribes.forEach((unsubscribe) => unsubscribe?.());
|
|
184
183
|
instance._providerUnsubscribes.clear();
|
|
185
184
|
instance._providers.clear();
|
|
@@ -10,9 +10,8 @@ import type { AssistantRuntimeCore } from "../runtime/interfaces/assistant-runti
|
|
|
10
10
|
import { RuntimeAdapter } from "./RuntimeAdapter";
|
|
11
11
|
|
|
12
12
|
export const getRenderComponent = (runtime: AssistantRuntime) => {
|
|
13
|
-
return (runtime as { _core?: AssistantRuntimeCore })._core
|
|
14
|
-
|
|
|
15
|
-
| undefined;
|
|
13
|
+
return (runtime as { _core?: AssistantRuntimeCore })._core
|
|
14
|
+
?.RenderComponent as ComponentType | undefined;
|
|
16
15
|
};
|
|
17
16
|
|
|
18
17
|
export type AssistantProviderBaseProps = PropsWithChildren<{
|
|
@@ -253,7 +253,6 @@ export const Interactables = resource((): ClientOutput<"interactables"> => {
|
|
|
253
253
|
[setDefState],
|
|
254
254
|
);
|
|
255
255
|
|
|
256
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: state dep triggers notification
|
|
257
256
|
tapEffect(() => {
|
|
258
257
|
for (const cb of subscribersRef.current) cb();
|
|
259
258
|
}, [state]);
|
|
@@ -15,7 +15,10 @@ import {
|
|
|
15
15
|
} from "@assistant-ui/store";
|
|
16
16
|
import type { McpAppResourceOutput, ToolsState } from "../types/scopes/tools";
|
|
17
17
|
import type { Tool } from "assistant-stream";
|
|
18
|
-
import
|
|
18
|
+
import {
|
|
19
|
+
isStandaloneToolDisplay,
|
|
20
|
+
type Toolkit,
|
|
21
|
+
} from "../model-context/toolbox";
|
|
19
22
|
import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
|
|
20
23
|
import { ModelContext } from "../../store";
|
|
21
24
|
|
|
@@ -45,36 +48,53 @@ export const Tools = resource(
|
|
|
45
48
|
);
|
|
46
49
|
const mcpAppOutput = mcpAppOutputs[0];
|
|
47
50
|
|
|
48
|
-
const [
|
|
49
|
-
tools: ToolsState["tools"];
|
|
50
|
-
}>(() => ({
|
|
51
|
-
tools: {},
|
|
52
|
-
}));
|
|
51
|
+
const [toolUIs, setToolUIs] = tapState<ToolsState["toolUIs"]>(() => ({}));
|
|
53
52
|
|
|
54
53
|
const state = tapMemo(
|
|
55
|
-
(): ToolsState => ({
|
|
56
|
-
|
|
54
|
+
(): ToolsState => ({
|
|
55
|
+
toolUIs,
|
|
56
|
+
mcpApp: mcpAppOutput,
|
|
57
|
+
// Deprecated component-only view, derived from `toolUIs`. Removed in v0.15.
|
|
58
|
+
tools: Object.fromEntries(
|
|
59
|
+
Object.entries(toolUIs).map(([name, regs]) => [
|
|
60
|
+
name,
|
|
61
|
+
regs.map((r) => r.render),
|
|
62
|
+
]),
|
|
63
|
+
),
|
|
64
|
+
}),
|
|
65
|
+
[toolUIs, mcpAppOutput],
|
|
57
66
|
);
|
|
58
67
|
|
|
59
68
|
const clientRef = tapAssistantClientRef();
|
|
60
69
|
|
|
61
70
|
const setToolUI = tapCallback(
|
|
62
|
-
(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
(
|
|
72
|
+
toolName: string,
|
|
73
|
+
render: ToolCallMessagePartComponent,
|
|
74
|
+
options?: { standalone?: boolean },
|
|
75
|
+
) => {
|
|
76
|
+
// One registration object per call; identity is the removal key, so
|
|
77
|
+
// the per-name list stays correctly ref-counted across re-registers.
|
|
78
|
+
const registration = {
|
|
79
|
+
render,
|
|
80
|
+
standalone: options?.standalone ?? false,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
setToolUIs((prev) => ({
|
|
84
|
+
...prev,
|
|
85
|
+
[toolName]: [...(prev[toolName] ?? []), registration],
|
|
68
86
|
}));
|
|
69
87
|
|
|
70
88
|
return () => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
89
|
+
setToolUIs((prev) => {
|
|
90
|
+
const next =
|
|
91
|
+
prev[toolName]?.filter((r) => r !== registration) ?? [];
|
|
92
|
+
if (next.length > 0) return { ...prev, [toolName]: next };
|
|
93
|
+
// Drop the key entirely so repeatedly mounted/unmounted tools
|
|
94
|
+
// don't leave empty arrays accumulating across a long session.
|
|
95
|
+
const { [toolName]: _removed, ...rest } = prev;
|
|
96
|
+
return rest;
|
|
97
|
+
});
|
|
78
98
|
};
|
|
79
99
|
},
|
|
80
100
|
[],
|
|
@@ -87,14 +107,20 @@ export const Tools = resource(
|
|
|
87
107
|
// Register tool UIs (exclude symbols)
|
|
88
108
|
for (const [toolName, tool] of Object.entries(toolkit)) {
|
|
89
109
|
if (tool.render) {
|
|
90
|
-
unsubscribes.push(
|
|
110
|
+
unsubscribes.push(
|
|
111
|
+
setToolUI(toolName, tool.render, {
|
|
112
|
+
standalone: isStandaloneToolDisplay(tool),
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
91
115
|
}
|
|
92
116
|
}
|
|
93
117
|
|
|
94
|
-
// Register tools with model context (exclude symbols)
|
|
118
|
+
// Register tools with model context (exclude symbols). `render` and
|
|
119
|
+
// `display` are client-only presentation concerns and never reach the
|
|
120
|
+
// model.
|
|
95
121
|
const toolsWithoutRender = Object.entries(toolkit).reduce(
|
|
96
122
|
(acc, [name, tool]) => {
|
|
97
|
-
const { render, ...rest } = tool;
|
|
123
|
+
const { render, display, ...rest } = tool;
|
|
98
124
|
acc[name] = rest;
|
|
99
125
|
return acc;
|
|
100
126
|
},
|
|
@@ -112,7 +138,6 @@ export const Tools = resource(
|
|
|
112
138
|
);
|
|
113
139
|
|
|
114
140
|
return () => {
|
|
115
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
116
141
|
unsubscribes.forEach((fn) => fn());
|
|
117
142
|
};
|
|
118
143
|
}, [toolkit, setToolUI, clientRef]);
|
package/src/react/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference path="../store/scope-registration.ts" />
|
|
1
2
|
/// <reference path="./types/store-augmentation.ts" />
|
|
2
3
|
|
|
3
4
|
// model-context
|
|
@@ -31,7 +32,12 @@ export {
|
|
|
31
32
|
type AssistantDataUIProps,
|
|
32
33
|
} from "./model-context/useAssistantDataUI";
|
|
33
34
|
export { useInlineRender } from "./model-context/useInlineRender";
|
|
34
|
-
export
|
|
35
|
+
export {
|
|
36
|
+
type Toolkit,
|
|
37
|
+
type ToolDefinition,
|
|
38
|
+
type ToolkitDeclaration,
|
|
39
|
+
type ToolkitDeclarationDefinition,
|
|
40
|
+
} from "./model-context/toolbox";
|
|
35
41
|
export {
|
|
36
42
|
useAssistantInteractable,
|
|
37
43
|
type AssistantInteractableProps,
|
|
@@ -129,13 +135,8 @@ export {
|
|
|
129
135
|
useRuntimeAdapters,
|
|
130
136
|
type RuntimeAdapters,
|
|
131
137
|
} from "./runtimes/RuntimeAdapterProvider";
|
|
132
|
-
export {
|
|
133
|
-
useToolInvocations,
|
|
134
|
-
type ToolExecutionStatus,
|
|
135
|
-
type AssistantTransportState,
|
|
136
|
-
type AddToolResultCommand,
|
|
137
|
-
} from "./runtimes/useToolInvocations";
|
|
138
138
|
export { useExternalStoreRuntime } from "./runtimes/useExternalStoreRuntime";
|
|
139
|
+
export { useExternalStoreSharedOptions } from "./runtimes/useExternalStoreSharedOptions";
|
|
139
140
|
export {
|
|
140
141
|
useExternalMessageConverter,
|
|
141
142
|
convertExternalMessages,
|
|
@@ -178,7 +179,7 @@ export {
|
|
|
178
179
|
type PartState,
|
|
179
180
|
} from "./primitives/message/MessageParts";
|
|
180
181
|
export { MessagePrimitiveGroupedParts } from "./primitives/message/MessageGroupedParts";
|
|
181
|
-
export { groupPartByType } from "./utils/groupParts";
|
|
182
|
+
export { groupPartByType, type GroupByContext } from "./utils/groupParts";
|
|
182
183
|
export {
|
|
183
184
|
MessagePrimitiveGenerativeUI,
|
|
184
185
|
GenerativeUIRender,
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
import type { Tool } from "assistant-stream";
|
|
1
|
+
import type { Tool, ToolDeclaration } from "assistant-stream";
|
|
2
2
|
import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Resolves whether a tool's UI should be presented standalone (outside the
|
|
6
|
+
* chain-of-thought grouping), applying the type-based defaults.
|
|
7
|
+
*
|
|
8
|
+
* An explicit `display` wins. Otherwise `human` tools default to standalone
|
|
9
|
+
* (they prompt the user), and every other tool defaults to inline (a trace of
|
|
10
|
+
* what the model is doing). MCP-app tool calls are detected separately from
|
|
11
|
+
* the part itself and are not resolved here.
|
|
12
|
+
*/
|
|
13
|
+
export const isStandaloneToolDisplay = (
|
|
14
|
+
tool: Pick<Tool<any, any>, "type" | "display">,
|
|
15
|
+
): boolean => {
|
|
16
|
+
if (tool.display !== undefined) return tool.display === "standalone";
|
|
17
|
+
return tool.type === "human";
|
|
18
|
+
};
|
|
19
|
+
|
|
4
20
|
type WithRender<T, TArgs extends Record<string, unknown>, TResult> = T extends {
|
|
5
21
|
type: "frontend" | "human";
|
|
6
22
|
}
|
|
@@ -43,6 +59,35 @@ export type ToolDefinition<
|
|
|
43
59
|
*/
|
|
44
60
|
export type Toolkit = Record<string, ToolDefinition<any, any>>;
|
|
45
61
|
|
|
62
|
+
/**
|
|
63
|
+
* A tool as authored, before the build splits it: like {@link ToolDefinition}
|
|
64
|
+
* but it may declare `description`, `parameters`, and a server-side `execute`
|
|
65
|
+
* alongside its `render`. The `type` field is **not** authored — the
|
|
66
|
+
* `"use generative"` compiler infers it (`execute: hitl()` → human; `execute`
|
|
67
|
+
* with a `"use client"` directive → frontend; otherwise backend) and writes it
|
|
68
|
+
* back — so declaring it here is a type error.
|
|
69
|
+
*/
|
|
70
|
+
export type ToolkitDeclarationDefinition<
|
|
71
|
+
TArgs extends Record<string, unknown>,
|
|
72
|
+
TResult,
|
|
73
|
+
> = WithRender<
|
|
74
|
+
Omit<ToolDeclaration<TArgs, TResult>, "type">,
|
|
75
|
+
TArgs,
|
|
76
|
+
TResult
|
|
77
|
+
> & {
|
|
78
|
+
type?: never;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The permissive, authoring-time counterpart to {@link Toolkit} — the input to
|
|
83
|
+
* {@link defineToolkit}. Backend entries may carry their server `execute` here;
|
|
84
|
+
* the canonical {@link Toolkit} keeps those fields `undefined`.
|
|
85
|
+
*/
|
|
86
|
+
export type ToolkitDeclaration = Record<
|
|
87
|
+
string,
|
|
88
|
+
ToolkitDeclarationDefinition<any, any>
|
|
89
|
+
>;
|
|
90
|
+
|
|
46
91
|
/** Configuration for the {@link Tools} resource. */
|
|
47
92
|
export type ToolsConfig = {
|
|
48
93
|
/** Tools to register with model context and, when provided, message renderers. */
|
|
@@ -2,6 +2,7 @@ import { useEffect } from "react";
|
|
|
2
2
|
import { useAui } from "@assistant-ui/store";
|
|
3
3
|
import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
|
|
4
4
|
import type { AssistantToolProps as CoreAssistantToolProps } from "../..";
|
|
5
|
+
import { isStandaloneToolDisplay } from "./toolbox";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Props used to register a tool from React.
|
|
@@ -52,13 +53,17 @@ export const useAssistantTool = <
|
|
|
52
53
|
) => {
|
|
53
54
|
const aui = useAui();
|
|
54
55
|
|
|
56
|
+
const standalone = isStandaloneToolDisplay(tool);
|
|
57
|
+
|
|
55
58
|
useEffect(() => {
|
|
56
59
|
if (!tool.render) return undefined;
|
|
57
|
-
return aui.tools().setToolUI(tool.toolName, tool.render);
|
|
58
|
-
}, [aui, tool.toolName, tool.render]);
|
|
60
|
+
return aui.tools().setToolUI(tool.toolName, tool.render, { standalone });
|
|
61
|
+
}, [aui, tool.toolName, tool.render, standalone]);
|
|
59
62
|
|
|
60
63
|
useEffect(() => {
|
|
61
|
-
|
|
64
|
+
// `render` and `display` are client-only presentation concerns and never
|
|
65
|
+
// reach the model.
|
|
66
|
+
const { toolName, render, display, ...rest } = tool;
|
|
62
67
|
const context = {
|
|
63
68
|
tools: {
|
|
64
69
|
[toolName]: rest,
|
|
@@ -8,6 +8,12 @@ export type AssistantToolUIProps<TArgs, TResult> = {
|
|
|
8
8
|
toolName: string;
|
|
9
9
|
/** Component rendered for matching tool-call message parts. */
|
|
10
10
|
render: ToolCallMessagePartComponent<TArgs, TResult>;
|
|
11
|
+
/**
|
|
12
|
+
* How the UI is presented relative to the chain-of-thought trace. Set
|
|
13
|
+
* `"standalone"` to surface it on its own (e.g. human-in-the-loop or
|
|
14
|
+
* generative UI for a backend/MCP tool). Defaults to `"inline"`.
|
|
15
|
+
*/
|
|
16
|
+
display?: "standalone" | "inline";
|
|
11
17
|
};
|
|
12
18
|
|
|
13
19
|
/**
|
|
@@ -23,8 +29,9 @@ export const useAssistantToolUI = (
|
|
|
23
29
|
tool: AssistantToolUIProps<any, any> | null,
|
|
24
30
|
) => {
|
|
25
31
|
const aui = useAui();
|
|
32
|
+
const standalone = tool?.display === "standalone";
|
|
26
33
|
useEffect(() => {
|
|
27
34
|
if (!tool?.toolName || !tool?.render) return undefined;
|
|
28
|
-
return aui.tools().setToolUI(tool.toolName, tool.render);
|
|
29
|
-
}, [aui, tool?.toolName, tool?.render]);
|
|
35
|
+
return aui.tools().setToolUI(tool.toolName, tool.render, { standalone });
|
|
36
|
+
}, [aui, tool?.toolName, tool?.render, standalone]);
|
|
30
37
|
};
|
|
@@ -17,7 +17,6 @@ export const useInlineRender = <TArgs, TResult>(
|
|
|
17
17
|
|
|
18
18
|
return useCallback(
|
|
19
19
|
function ToolUI(args) {
|
|
20
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
21
20
|
const store = useToolUIStore();
|
|
22
21
|
return store.toolUI(args);
|
|
23
22
|
},
|
|
@@ -86,8 +86,7 @@ export const ChainOfThoughtPrimitiveParts: FC<
|
|
|
86
86
|
);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
//
|
|
90
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
89
|
+
// oxlint-disable-next-line react-hooks/rules-of-hooks -- intentional conditional hook below the early return above
|
|
91
90
|
const messageComponents = useMemo(
|
|
92
91
|
() => ({
|
|
93
92
|
Reasoning: components?.Reasoning,
|
|
@@ -4,7 +4,7 @@ import { MessagePrimitiveAttachments } from "./MessageAttachments";
|
|
|
4
4
|
|
|
5
5
|
const mockUseAuiState = vi.fn();
|
|
6
6
|
type UseAuiStateSelector = Parameters<
|
|
7
|
-
typeof import("@assistant-ui/store")["useAuiState"]
|
|
7
|
+
(typeof import("@assistant-ui/store"))["useAuiState"]
|
|
8
8
|
>[0];
|
|
9
9
|
type AttachmentsElement = ReactElement<{ children: () => null }>;
|
|
10
10
|
|