@assistant-ui/core 0.2.5 → 0.2.7

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.
Files changed (140) hide show
  1. package/dist/index.d.ts +4 -2
  2. package/dist/index.js +6 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/internal/duplicate-detection.d.ts +5 -0
  5. package/dist/internal/duplicate-detection.d.ts.map +1 -0
  6. package/dist/internal/duplicate-detection.js +11 -0
  7. package/dist/internal/duplicate-detection.js.map +1 -0
  8. package/dist/react/AssistantProvider.d.ts.map +1 -1
  9. package/dist/react/AssistantProvider.js.map +1 -1
  10. package/dist/react/index.d.ts +3 -2
  11. package/dist/react/index.js +2 -2
  12. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
  13. package/dist/react/primitives/message/MessageGroupedParts.d.ts +25 -21
  14. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  15. package/dist/react/primitives/message/MessageGroupedParts.js +6 -7
  16. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  17. package/dist/react/primitives/message/MessageParts.d.ts +2 -1
  18. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  19. package/dist/react/primitives/message/MessageParts.js +9 -4
  20. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  21. package/dist/react/providers/TextMessagePartProvider.d.ts.map +1 -1
  22. package/dist/react/providers/TextMessagePartProvider.js +3 -0
  23. package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
  24. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +3 -1
  25. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  26. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +3 -1
  27. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  28. package/dist/react/runtimes/external-message-converter.d.ts +1 -1
  29. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  30. package/dist/react/runtimes/external-message-converter.js +7 -3
  31. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  32. package/dist/react/types/MessagePartComponentTypes.d.ts +8 -0
  33. package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
  34. package/dist/react/utils/groupParts.d.ts +40 -12
  35. package/dist/react/utils/groupParts.d.ts.map +1 -1
  36. package/dist/react/utils/groupParts.js +51 -9
  37. package/dist/react/utils/groupParts.js.map +1 -1
  38. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  39. package/dist/runtime/api/attachment-runtime.js.map +1 -1
  40. package/dist/runtime/api/message-part-runtime.d.ts +8 -0
  41. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  42. package/dist/runtime/api/message-part-runtime.js +13 -0
  43. package/dist/runtime/api/message-part-runtime.js.map +1 -1
  44. package/dist/runtime/api/thread-runtime.d.ts +2 -1
  45. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  46. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -1
  47. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  48. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  49. package/dist/runtime/interfaces/thread-runtime-core.d.ts +15 -1
  50. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  51. package/dist/runtime/utils/thread-message-like.d.ts +10 -0
  52. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  53. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  54. package/dist/runtimes/external-store/external-store-adapter.d.ts +33 -1
  55. package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
  56. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  57. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  58. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +27 -1
  59. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  60. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +98 -3
  61. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  62. package/dist/runtimes/local/local-thread-runtime-core.d.ts +2 -1
  63. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  64. package/dist/runtimes/local/local-thread-runtime-core.js +3 -0
  65. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  66. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -0
  67. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  68. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +3 -0
  69. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  70. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  71. package/dist/runtimes/remote-thread-list/empty-thread-core.js +3 -0
  72. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  73. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +168 -0
  74. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -0
  75. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +449 -0
  76. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -0
  77. package/dist/store/clients/thread-message-client.d.ts.map +1 -1
  78. package/dist/store/clients/thread-message-client.js +3 -0
  79. package/dist/store/clients/thread-message-client.js.map +1 -1
  80. package/dist/store/runtime-clients/message-part-runtime-client.js +1 -0
  81. package/dist/store/runtime-clients/message-part-runtime-client.js.map +1 -1
  82. package/dist/store/scopes/part.d.ts +7 -0
  83. package/dist/store/scopes/part.d.ts.map +1 -1
  84. package/dist/subscribable/subscribable.d.ts.map +1 -1
  85. package/dist/subscribable/subscribable.js.map +1 -1
  86. package/dist/types/message.d.ts +6 -0
  87. package/dist/types/message.d.ts.map +1 -1
  88. package/dist/types/message.js.map +1 -1
  89. package/package.json +4 -4
  90. package/src/adapters/index.ts +1 -4
  91. package/src/index.ts +11 -0
  92. package/src/internal/duplicate-detection.ts +26 -0
  93. package/src/react/AssistantProvider.tsx +2 -3
  94. package/src/react/index.ts +2 -6
  95. package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -2
  96. package/src/react/primitives/message/MessageAttachments.test.tsx +1 -1
  97. package/src/react/primitives/message/MessageGroupedParts.tsx +38 -31
  98. package/src/react/primitives/message/MessageParts.tsx +14 -1
  99. package/src/react/providers/TextMessagePartProvider.tsx +3 -0
  100. package/src/react/runtimes/external-message-converter.ts +26 -13
  101. package/src/react/types/MessagePartComponentTypes.ts +8 -0
  102. package/src/react/utils/groupParts.ts +67 -22
  103. package/src/runtime/api/attachment-runtime.ts +1 -2
  104. package/src/runtime/api/message-part-runtime.ts +26 -0
  105. package/src/runtime/base/base-thread-runtime-core.ts +4 -0
  106. package/src/runtime/interfaces/thread-runtime-core.ts +15 -0
  107. package/src/runtime/internal.ts +1 -4
  108. package/src/runtime/utils/thread-message-like.ts +7 -0
  109. package/src/runtimes/external-store/external-store-adapter.ts +37 -0
  110. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +1 -3
  111. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +168 -4
  112. package/src/runtimes/local/local-thread-runtime-core.ts +5 -0
  113. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +4 -0
  114. package/src/runtimes/remote-thread-list/empty-thread-core.ts +4 -0
  115. package/src/runtimes/tool-invocations/EDGE_CASES.md +194 -0
  116. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +1054 -0
  117. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +783 -0
  118. package/src/store/clients/thread-message-client.ts +3 -0
  119. package/src/store/runtime-clients/message-part-runtime-client.ts +2 -0
  120. package/src/store/scopes/part.ts +4 -0
  121. package/src/subscribable/subscribable.ts +3 -3
  122. package/src/tests/OptimisticState-delete-crash.test.ts +2 -0
  123. package/src/tests/OptimisticState-list-race.test.ts +2 -0
  124. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +5 -5
  125. package/src/tests/auiV0Encode.test.ts +1 -1
  126. package/src/tests/composer-can-send.test.ts +8 -4
  127. package/src/tests/duplicate-detection.test.ts +34 -0
  128. package/src/tests/external-store-thread-list-runtime-core.test.ts +1 -1
  129. package/src/tests/external-store-thread-runtime-core.test.ts +7 -6
  130. package/src/tests/groupParts.test.ts +118 -32
  131. package/src/tests/no-unsafe-process-env.test.ts +1 -0
  132. package/src/tests/remote-thread-list-isLoading.test.ts +2 -0
  133. package/src/tests/thread-message-like.test.ts +4 -1
  134. package/src/types/index.ts +1 -4
  135. package/src/types/message.ts +7 -0
  136. package/dist/react/runtimes/useToolInvocations.d.ts +0 -53
  137. package/dist/react/runtimes/useToolInvocations.d.ts.map +0 -1
  138. package/dist/react/runtimes/useToolInvocations.js +0 -380
  139. package/dist/react/runtimes/useToolInvocations.js.map +0 -1
  140. package/src/react/runtimes/useToolInvocations.ts +0 -694
@@ -1 +1 @@
1
- {"version":3,"file":"subscribable.js","names":[],"sources":["../../src/subscribable/subscribable.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\n\nexport const SKIP_UPDATE = Symbol(\"skip-update\");\nexport type SKIP_UPDATE = typeof SKIP_UPDATE;\n\nexport type Subscribable = {\n subscribe: (callback: () => void) => Unsubscribe;\n};\n\nexport type SubscribableWithState<TState, TPath> = Subscribable & {\n path: TPath;\n getState: () => TState;\n};\n\nexport type NestedSubscribable<\n TState extends Subscribable | undefined,\n TPath,\n> = SubscribableWithState<TState, TPath>;\n\nexport type EventSubscribable<TEvent extends string> = {\n event: TEvent;\n binding: SubscribableWithState<\n | {\n unstable_on: (\n event: TEvent,\n callback: (payload?: unknown) => void,\n ) => Unsubscribe;\n }\n | undefined,\n unknown\n >;\n};\n\nfunction shallowEqual<T extends object>(\n objA: T | undefined,\n objB: T | undefined,\n) {\n if (objA === undefined && objB === undefined) return true;\n if (objA === undefined) return false;\n if (objB === undefined) return false;\n\n for (const key of Object.keys(objA)) {\n const valueA = objA[key as keyof T];\n const valueB = objB[key as keyof T];\n if (!Object.is(valueA, valueB)) return false;\n }\n\n return true;\n}\n\nexport class BaseSubscribable {\n private _subscribers = new Set<() => void>();\n\n public subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n public waitForUpdate() {\n return new Promise<void>((resolve) => {\n const unsubscribe = this.subscribe(() => {\n unsubscribe();\n resolve();\n });\n });\n }\n\n protected _notifySubscribers() {\n const errors = [];\n for (const callback of this._subscribers) {\n try {\n callback();\n } catch (error) {\n errors.push(error);\n }\n }\n\n if (errors.length > 0) {\n if (errors.length === 1) {\n throw errors[0];\n } else {\n for (const error of errors) {\n console.error(error);\n }\n throw new AggregateError(errors);\n }\n }\n }\n}\n\n// lazy connect/disconnect: only opens upstream subscription while it has subscribers\nexport abstract class BaseSubject {\n private _subscriptions = new Set<(payload?: unknown) => void>();\n private _connection: Unsubscribe | undefined;\n\n protected get isConnected() {\n return !!this._connection;\n }\n\n protected abstract _connect(): Unsubscribe;\n\n protected notifySubscribers(payload?: unknown) {\n for (const callback of this._subscriptions) callback(payload);\n }\n\n private _updateConnection() {\n if (this._subscriptions.size > 0) {\n if (this._connection) return;\n this._connection = this._connect();\n } else {\n this._connection?.();\n this._connection = undefined;\n }\n }\n\n public subscribe(callback: (payload?: unknown) => void) {\n this._subscriptions.add(callback);\n this._updateConnection();\n\n return () => {\n this._subscriptions.delete(callback);\n this._updateConnection();\n };\n }\n}\n\nexport class ShallowMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n constructor(\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>,\n ) {\n super();\n const state = binding.getState();\n if (state === SKIP_UPDATE)\n throw new Error(\"Entry not available in the store\");\n this._previousState = state;\n }\n\n private _previousState: TState;\n public getState = () => {\n if (!this.isConnected) this._syncState();\n return this._previousState;\n };\n\n private _syncState() {\n const state = this.binding.getState();\n if (state === SKIP_UPDATE) return false;\n if (shallowEqual(state, this._previousState)) return false;\n this._previousState = state;\n return true;\n }\n\n protected _connect() {\n const callback = () => {\n if (this._syncState()) {\n this.notifySubscribers();\n }\n };\n\n return this.binding.subscribe(callback);\n }\n}\n\nexport class LazyMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n constructor(\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>,\n ) {\n super();\n }\n\n private _previousStateDirty = true;\n private _previousState: TState | undefined;\n public getState = () => {\n if (!this.isConnected || this._previousStateDirty) {\n const newState = this.binding.getState();\n if (newState !== SKIP_UPDATE) {\n this._previousState = newState;\n }\n this._previousStateDirty = false;\n }\n if (this._previousState === undefined)\n throw new Error(\"Entry not available in the store\");\n return this._previousState;\n };\n\n protected _connect() {\n const callback = () => {\n this._previousStateDirty = true;\n this.notifySubscribers();\n };\n\n return this.binding.subscribe(callback);\n }\n}\n\nexport class NestedSubscriptionSubject<\n TState extends Subscribable | undefined,\n TPath,\n >\n extends BaseSubject\n implements\n SubscribableWithState<TState, TPath>,\n NestedSubscribable<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n constructor(private binding: NestedSubscribable<TState, TPath>) {\n super();\n }\n\n public getState() {\n return this.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const callback = () => {\n this.notifySubscribers();\n };\n\n let lastState = this.binding.getState();\n let innerUnsubscribe = lastState?.subscribe(callback);\n const onRuntimeUpdate = () => {\n const newState = this.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.subscribe(callback);\n\n callback();\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n\nexport class EventSubscriptionSubject<\n TEvent extends string,\n> extends BaseSubject {\n constructor(private config: EventSubscribable<TEvent>) {\n super();\n }\n\n public getState() {\n return this.config.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.config.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const callback = (payload?: unknown) => {\n this.notifySubscribers(payload);\n };\n\n let lastState = this.config.binding.getState();\n let innerUnsubscribe = lastState?.unstable_on(this.config.event, callback);\n const onRuntimeUpdate = () => {\n const newState = this.config.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.unstable_on(this.config.event, callback);\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"subscribable.js","names":[],"sources":["../../src/subscribable/subscribable.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\n\nexport const SKIP_UPDATE = Symbol(\"skip-update\");\nexport type SKIP_UPDATE = typeof SKIP_UPDATE;\n\nexport type Subscribable = {\n subscribe: (callback: () => void) => Unsubscribe;\n};\n\nexport type SubscribableWithState<TState, TPath> = Subscribable & {\n path: TPath;\n getState: () => TState;\n};\n\nexport type NestedSubscribable<\n TState extends Subscribable | undefined,\n TPath,\n> = SubscribableWithState<TState, TPath>;\n\nexport type EventSubscribable<TEvent extends string> = {\n event: TEvent;\n binding: SubscribableWithState<\n | {\n unstable_on: (\n event: TEvent,\n callback: (payload?: unknown) => void,\n ) => Unsubscribe;\n }\n | undefined,\n unknown\n >;\n};\n\nfunction shallowEqual<T extends object>(\n objA: T | undefined,\n objB: T | undefined,\n) {\n if (objA === undefined && objB === undefined) return true;\n if (objA === undefined) return false;\n if (objB === undefined) return false;\n\n for (const key of Object.keys(objA)) {\n const valueA = objA[key as keyof T];\n const valueB = objB[key as keyof T];\n if (!Object.is(valueA, valueB)) return false;\n }\n\n return true;\n}\n\nexport class BaseSubscribable {\n private _subscribers = new Set<() => void>();\n\n public subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n public waitForUpdate() {\n return new Promise<void>((resolve) => {\n const unsubscribe = this.subscribe(() => {\n unsubscribe();\n resolve();\n });\n });\n }\n\n protected _notifySubscribers() {\n const errors = [];\n for (const callback of this._subscribers) {\n try {\n callback();\n } catch (error) {\n errors.push(error);\n }\n }\n\n if (errors.length > 0) {\n if (errors.length === 1) {\n throw errors[0];\n } else {\n for (const error of errors) {\n console.error(error);\n }\n throw new AggregateError(errors);\n }\n }\n }\n}\n\n// lazy connect/disconnect: only opens upstream subscription while it has subscribers\nexport abstract class BaseSubject {\n private _subscriptions = new Set<(payload?: unknown) => void>();\n private _connection: Unsubscribe | undefined;\n\n protected get isConnected() {\n return !!this._connection;\n }\n\n protected abstract _connect(): Unsubscribe;\n\n protected notifySubscribers(payload?: unknown) {\n for (const callback of this._subscriptions) callback(payload);\n }\n\n private _updateConnection() {\n if (this._subscriptions.size > 0) {\n if (this._connection) return;\n this._connection = this._connect();\n } else {\n this._connection?.();\n this._connection = undefined;\n }\n }\n\n public subscribe(callback: (payload?: unknown) => void) {\n this._subscriptions.add(callback);\n this._updateConnection();\n\n return () => {\n this._subscriptions.delete(callback);\n this._updateConnection();\n };\n }\n}\n\nexport class ShallowMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n constructor(\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>,\n ) {\n super();\n const state = binding.getState();\n if (state === SKIP_UPDATE)\n throw new Error(\"Entry not available in the store\");\n this._previousState = state;\n }\n\n private _previousState: TState;\n public getState = () => {\n if (!this.isConnected) this._syncState();\n return this._previousState;\n };\n\n private _syncState() {\n const state = this.binding.getState();\n if (state === SKIP_UPDATE) return false;\n if (shallowEqual(state, this._previousState)) return false;\n this._previousState = state;\n return true;\n }\n\n protected _connect() {\n const callback = () => {\n if (this._syncState()) {\n this.notifySubscribers();\n }\n };\n\n return this.binding.subscribe(callback);\n }\n}\n\nexport class LazyMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n constructor(\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>,\n ) {\n super();\n }\n\n private _previousStateDirty = true;\n private _previousState: TState | undefined;\n public getState = () => {\n if (!this.isConnected || this._previousStateDirty) {\n const newState = this.binding.getState();\n if (newState !== SKIP_UPDATE) {\n this._previousState = newState;\n }\n this._previousStateDirty = false;\n }\n if (this._previousState === undefined)\n throw new Error(\"Entry not available in the store\");\n return this._previousState;\n };\n\n protected _connect() {\n const callback = () => {\n this._previousStateDirty = true;\n this.notifySubscribers();\n };\n\n return this.binding.subscribe(callback);\n }\n}\n\nexport class NestedSubscriptionSubject<\n TState extends Subscribable | undefined,\n TPath,\n>\n extends BaseSubject\n implements\n SubscribableWithState<TState, TPath>,\n NestedSubscribable<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n constructor(private binding: NestedSubscribable<TState, TPath>) {\n super();\n }\n\n public getState() {\n return this.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const callback = () => {\n this.notifySubscribers();\n };\n\n let lastState = this.binding.getState();\n let innerUnsubscribe = lastState?.subscribe(callback);\n const onRuntimeUpdate = () => {\n const newState = this.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.subscribe(callback);\n\n callback();\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n\nexport class EventSubscriptionSubject<\n TEvent extends string,\n> extends BaseSubject {\n constructor(private config: EventSubscribable<TEvent>) {\n super();\n }\n\n public getState() {\n return this.config.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.config.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const callback = (payload?: unknown) => {\n this.notifySubscribers(payload);\n };\n\n let lastState = this.config.binding.getState();\n let innerUnsubscribe = lastState?.unstable_on(this.config.event, callback);\n const onRuntimeUpdate = () => {\n const newState = this.config.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.unstable_on(this.config.event, callback);\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n"],"mappings":"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"}
@@ -123,6 +123,12 @@ type ToolCallMessagePart<TArgs = ReadonlyJSONObject, TResult = unknown> = {
123
123
  readonly interrupt?: {
124
124
  type: "human";
125
125
  payload: unknown;
126
+ }; /** Server-side approval gate. `approved === undefined` is the only state in which `respondToApproval` may be called. */
127
+ readonly approval?: {
128
+ readonly id: string;
129
+ readonly approved?: boolean;
130
+ readonly reason?: string;
131
+ readonly isAutomatic?: boolean;
126
132
  }; /** Parent message-part ID when this part belongs to a nested structure. */
127
133
  readonly parentId?: string;
128
134
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","names":[],"sources":["../../src/types/message.ts"],"mappings":"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"}
1
+ {"version":3,"file":"message.d.ts","names":[],"sources":["../../src/types/message.ts"],"mappings":"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"}
@@ -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 /** 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 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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/core",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Framework-agnostic core runtime for assistant-ui",
5
5
  "keywords": [
6
6
  "assistant",
@@ -59,12 +59,12 @@
59
59
  ],
60
60
  "sideEffects": false,
61
61
  "dependencies": {
62
- "assistant-stream": "^0.3.16",
62
+ "assistant-stream": "^0.3.17",
63
63
  "nanoid": "^5.1.11"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "@assistant-ui/store": "^0.2.12",
67
- "@assistant-ui/tap": "^0.5.12",
67
+ "@assistant-ui/tap": "^0.5.13",
68
68
  "@types/react": "*",
69
69
  "react": "^18 || ^19",
70
70
  "assistant-cloud": "^0.1.29",
@@ -90,7 +90,7 @@
90
90
  "vitest": "^4.1.7",
91
91
  "zustand": "^5.0.13",
92
92
  "@assistant-ui/store": "0.2.12",
93
- "@assistant-ui/tap": "0.5.12",
93
+ "@assistant-ui/tap": "0.5.13",
94
94
  "@assistant-ui/x-buildutils": "0.0.9",
95
95
  "assistant-cloud": "0.1.29"
96
96
  },
@@ -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/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,
@@ -170,6 +180,7 @@ export type {
170
180
  RuntimeCapabilities,
171
181
  AddToolResultOptions,
172
182
  ResumeToolCallOptions,
183
+ RespondToToolApprovalOptions,
173
184
  SubmitFeedbackOptions,
174
185
  ThreadSuggestion,
175
186
  SpeechState,
@@ -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
+ }
@@ -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?.RenderComponent as
14
- | ComponentType
15
- | undefined;
13
+ return (runtime as { _core?: AssistantRuntimeCore })._core
14
+ ?.RenderComponent as ComponentType | undefined;
16
15
  };
17
16
 
18
17
  export type AssistantProviderBaseProps = PropsWithChildren<{
@@ -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
@@ -129,12 +130,6 @@ export {
129
130
  useRuntimeAdapters,
130
131
  type RuntimeAdapters,
131
132
  } from "./runtimes/RuntimeAdapterProvider";
132
- export {
133
- useToolInvocations,
134
- type ToolExecutionStatus,
135
- type AssistantTransportState,
136
- type AddToolResultCommand,
137
- } from "./runtimes/useToolInvocations";
138
133
  export { useExternalStoreRuntime } from "./runtimes/useExternalStoreRuntime";
139
134
  export {
140
135
  useExternalMessageConverter,
@@ -178,6 +173,7 @@ export {
178
173
  type PartState,
179
174
  } from "./primitives/message/MessageParts";
180
175
  export { MessagePrimitiveGroupedParts } from "./primitives/message/MessageGroupedParts";
176
+ export { groupPartByType } from "./utils/groupParts";
181
177
  export {
182
178
  MessagePrimitiveGenerativeUI,
183
179
  GenerativeUIRender,
@@ -86,8 +86,7 @@ export const ChainOfThoughtPrimitiveParts: FC<
86
86
  );
87
87
  }
88
88
 
89
- // eslint-disable-next-line react-hooks/exhaustive-deps
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
 
@@ -10,9 +10,8 @@ import type {
10
10
  } from "../../../types/message";
11
11
  import {
12
12
  buildGroupTree,
13
- type GroupKey,
13
+ GROUPBY_MEMO_KEY,
14
14
  type GroupNode,
15
- normalizeGroupKey,
16
15
  } from "../../utils/groupParts";
17
16
  import { MessagePartChildren, type EnrichedPartState } from "./MessageParts";
18
17
 
@@ -47,30 +46,32 @@ export namespace MessagePrimitiveGroupedParts {
47
46
 
48
47
  export type Props<TKey extends `group-${string}` = `group-${string}`> = {
49
48
  /**
50
- * Maps each part to its group key path. Adjacent parts that share a
51
- * prefix coalesce up to that prefix. Return `null`, `undefined`, or
52
- * `[]` to leave a part ungrouped — it will be rendered as a leaf
53
- * through `children` with `part` set to its {@link EnrichedPartState}.
49
+ * Maps each part to a group-key path. Adjacent parts that share a
50
+ * prefix coalesce into the same group. Return `[]` (or `null`) to
51
+ * leave a part ungrouped.
54
52
  *
55
- * Keys must start with `"group-"` so the renderer's
56
- * `switch (part.type)` can distinguish groups from real part types.
53
+ * Group keys must start with `"group-"` so the renderer's
54
+ * `switch (part.type)` can tell groups apart from real part types.
57
55
  *
58
- * For best performance, pass a stable reference (module-level
59
- * constant or `useCallback`).
56
+ * **Prefer {@link groupPartByType}** for the common case of mapping by
57
+ * `part.type` it ships a stable memo fingerprint so the tree
58
+ * survives unrelated re-renders. Use an inline function only when
59
+ * the helper isn't expressive enough (e.g. branching on
60
+ * `part.toolName` or part metadata).
60
61
  *
61
62
  * @example
62
- * ```ts
63
- * const groupBy = (part) =>
64
- * part.type === "reasoning" ? ["group-thought", "group-reasoning"] :
65
- * part.type === "tool-call" ? ["group-thought", "group-tool"] :
66
- * null;
63
+ * ```tsx
64
+ * import { groupPartByType } from "@assistant-ui/react";
65
+ *
66
+ * <MessagePrimitive.GroupedParts
67
+ * groupBy={groupPartByType({
68
+ * reasoning: ["group-thought", "group-reasoning"],
69
+ * "tool-call": ["group-thought", "group-tool"],
70
+ * })}
71
+ * >
67
72
  * ```
68
73
  */
69
- readonly groupBy: (
70
- part: PartState,
71
- index: number,
72
- parts: readonly PartState[],
73
- ) => GroupKey<TKey>;
74
+ readonly groupBy: (part: PartState) => readonly TKey[] | null;
74
75
 
75
76
  /**
76
77
  * Render function called once per group node and once per leaf part.
@@ -79,7 +80,7 @@ export namespace MessagePrimitiveGroupedParts {
79
80
  *
80
81
  * Leaf parts receive the same {@link EnrichedPartState} that
81
82
  * `<MessagePrimitive.Parts>` would produce (`toolUI`, `addResult`,
82
- * `resume`, `dataRendererUI`).
83
+ * `resume`, `respondToApproval`, `dataRendererUI`).
83
84
  */
84
85
  readonly children: (info: RenderInfo<TKey>) => ReactNode;
85
86
  };
@@ -148,11 +149,10 @@ const renderNode = <TKey extends `group-${string}`>(
148
149
  * @example
149
150
  * ```tsx
150
151
  * <MessagePrimitive.GroupedParts
151
- * groupBy={(part) =>
152
- * part.type === "reasoning" ? ["group-thought", "group-reasoning"] :
153
- * part.type === "tool-call" ? ["group-thought", "group-tool"] :
154
- * null
155
- * }
152
+ * groupBy={groupPartByType({
153
+ * reasoning: ["group-thought", "group-reasoning"],
154
+ * "tool-call": ["group-thought", "group-tool"],
155
+ * })}
156
156
  * >
157
157
  * {({ part, children }) => {
158
158
  * switch (part.type) {
@@ -173,12 +173,19 @@ export const MessagePrimitiveGroupedParts = <TKey extends `group-${string}`>({
173
173
  }: MessagePrimitiveGroupedParts.Props<TKey>): ReactNode => {
174
174
  const parts = useAuiState(useShallow((s) => s.message.parts));
175
175
 
176
+ // Helpers like `groupPartByType` tag the function with `GROUPBY_MEMO_KEY`
177
+ // (a stable string fingerprint of the helper config). When present,
178
+ // memo on `[parts, memoKey]` so the tree survives unrelated renders.
179
+ // For inline `groupBy`, fall back to recomputing each render — O(n)
180
+ // and cheap.
181
+ const memoKey = (groupBy as { [GROUPBY_MEMO_KEY]?: string })[
182
+ GROUPBY_MEMO_KEY
183
+ ];
184
+ const memoDep = memoKey ?? groupBy;
176
185
  const tree = useMemo(
177
- () =>
178
- buildGroupTree(
179
- parts.map((part, i) => normalizeGroupKey(groupBy(part, i, parts))),
180
- ),
181
- [parts, groupBy],
186
+ () => buildGroupTree(parts.map((part) => groupBy(part) ?? [])),
187
+ // oxlint-disable-next-line tap-hooks/exhaustive-deps -- groupBy is captured via memoDep (either its identity or the helper's memoKey fingerprint); listing it directly would defeat the helper-tagged memo path
188
+ [parts, memoDep],
182
189
  );
183
190
 
184
191
  return <>{tree.map((node) => renderNode(node, parts, children))}</>;
@@ -379,8 +379,16 @@ export const MessagePartComponent: FC<MessagePartComponentProps> = ({
379
379
  if (type === "tool-call") {
380
380
  const addResult = aui.part().addToolResult;
381
381
  const resume = aui.part().resumeToolCall;
382
+ const respondToApproval = aui.part().respondToToolApproval;
382
383
  if ("Override" in tools)
383
- return <tools.Override {...part} addResult={addResult} resume={resume} />;
384
+ return (
385
+ <tools.Override
386
+ {...part}
387
+ addResult={addResult}
388
+ resume={resume}
389
+ respondToApproval={respondToApproval}
390
+ />
391
+ );
384
392
  const Tool = tools.by_name?.[part.toolName] ?? tools.Fallback;
385
393
  return (
386
394
  <ToolUIDisplay
@@ -388,6 +396,7 @@ export const MessagePartComponent: FC<MessagePartComponentProps> = ({
388
396
  Fallback={Tool}
389
397
  addResult={addResult}
390
398
  resume={resume}
399
+ respondToApproval={respondToApproval}
391
400
  />
392
401
  );
393
402
  }
@@ -592,6 +601,7 @@ const RegisteredToolUI: FC = () => {
592
601
  {...part}
593
602
  addResult={aui.part().addToolResult}
594
603
  resume={aui.part().resumeToolCall}
604
+ respondToApproval={aui.part().respondToToolApproval}
595
605
  />
596
606
  );
597
607
  };
@@ -657,6 +667,8 @@ export type EnrichedPartState =
657
667
  addResult: ToolCallMessagePartProps["addResult"];
658
668
  /** Resume a tool call waiting for human input. */
659
669
  resume: ToolCallMessagePartProps["resume"];
670
+ /** Respond to a server-side tool approval gate. */
671
+ respondToApproval: ToolCallMessagePartProps["respondToApproval"];
660
672
  })
661
673
  | (Extract<PartState, { type: "data" }> & {
662
674
  /** The registered data renderer UI element, or null if none registered. */
@@ -706,6 +718,7 @@ export const MessagePartChildren: FC<{
706
718
  toolUI: hasUI ? <RegisteredToolUI /> : null,
707
719
  addResult: partMethods.addToolResult,
708
720
  resume: partMethods.resumeToolCall,
721
+ respondToApproval: partMethods.respondToToolApproval,
709
722
  };
710
723
  }
711
724
  if (state.type === "data") {
@@ -28,6 +28,9 @@ const TextMessagePartClient = resource(
28
28
  resumeToolCall: () => {
29
29
  throw new Error("Not supported");
30
30
  },
31
+ respondToToolApproval: () => {
32
+ throw new Error("Not supported");
33
+ },
31
34
  };
32
35
  },
33
36
  );
@@ -12,7 +12,7 @@ import {
12
12
  type ThreadMessageLike,
13
13
  } from "../../runtime/utils/thread-message-like";
14
14
  import { getAutoStatus, isAutoStatus } from "../../runtime/utils/auto-status";
15
- import type { ToolExecutionStatus } from "./useToolInvocations";
15
+ import type { ToolExecutionStatus } from "../../runtimes/tool-invocations/ToolInvocationTracker";
16
16
  import type { ReadonlyJSONValue } from "assistant-stream/utils";
17
17
  import { generateErrorMessageId } from "../../utils/id";
18
18
  import type {
@@ -22,6 +22,22 @@ import type {
22
22
  } from "../../types/message";
23
23
  import type { MessageTiming } from "../../types/message";
24
24
 
25
+ type ThreadMessageLikeContentItem = Exclude<
26
+ ThreadMessageLike["content"],
27
+ string
28
+ >[number];
29
+
30
+ const isPendingToolCall = (c: ThreadMessageLikeContentItem): boolean =>
31
+ c.type === "tool-call" && c.result === undefined;
32
+
33
+ const isInterruptedToolCall = (c: ThreadMessageLikeContentItem): boolean => {
34
+ if (c.type !== "tool-call" || c.result !== undefined) return false;
35
+ return (
36
+ c.interrupt != null ||
37
+ (c.approval != null && c.approval.approved === undefined)
38
+ );
39
+ };
40
+
25
41
  export namespace useExternalMessageConverter {
26
42
  export type Message =
27
43
  | (ThreadMessageLike & {
@@ -335,15 +351,16 @@ export const convertExternalMessages = <T extends WeakKey>(
335
351
  const result = chunks.map((message, idx) => {
336
352
  const isLast = idx === chunks.length - 1;
337
353
  const joined = joinExternalMessages(message.outputs);
354
+ const hasInterruptedToolCalls =
355
+ typeof joined.content === "object" &&
356
+ joined.content.some(isInterruptedToolCall);
338
357
  const hasPendingToolCalls =
339
358
  typeof joined.content === "object" &&
340
- joined.content.some(
341
- (c) => c.type === "tool-call" && c.result === undefined,
342
- );
359
+ joined.content.some(isPendingToolCall);
343
360
  const autoStatus = getAutoStatus(
344
361
  isLast,
345
362
  isRunning,
346
- hasPendingToolCalls,
363
+ hasInterruptedToolCalls,
347
364
  hasPendingToolCalls,
348
365
  isLast ? metadata.error : undefined,
349
366
  );
@@ -425,20 +442,16 @@ export const useExternalMessageConverter = <T extends WeakKey>({
425
442
  const isLast = idx === chunks.length - 1;
426
443
 
427
444
  const joined = joinExternalMessages(message.outputs);
428
- const hasSuspendedToolCalls =
445
+ const hasInterruptedToolCalls =
429
446
  typeof joined.content === "object" &&
430
- joined.content.some(
431
- (c) => c.type === "tool-call" && c.result === undefined,
432
- );
447
+ joined.content.some(isInterruptedToolCall);
433
448
  const hasPendingToolCalls =
434
449
  typeof joined.content === "object" &&
435
- joined.content.some(
436
- (c) => c.type === "tool-call" && c.result === undefined,
437
- );
450
+ joined.content.some(isPendingToolCall);
438
451
  const autoStatus = getAutoStatus(
439
452
  isLast,
440
453
  isRunning,
441
- hasSuspendedToolCalls,
454
+ hasInterruptedToolCalls,
442
455
  hasPendingToolCalls,
443
456
  isLast ? state.metadata.error : undefined,
444
457
  );
@@ -71,6 +71,14 @@ export type ToolCallMessagePartProps<
71
71
  * paused frontend tool execution.
72
72
  */
73
73
  resume: (payload: unknown) => void;
74
+ /**
75
+ * Responds to a server-side tool approval gate. Only valid while
76
+ * `approval` is set on the part and `approval.approved === undefined`.
77
+ */
78
+ respondToApproval: (response: {
79
+ approved: boolean;
80
+ reason?: string;
81
+ }) => void;
74
82
  };
75
83
 
76
84
  /** Component used to render a tool-call message part. */