From 2b7c6fe211df5abfb63a13f3dcf2e0587e6ca2c9 Mon Sep 17 00:00:00 2001 From: Simon Farshid Date: Wed, 2 Oct 2024 12:54:12 -0700 Subject: [PATCH] refactor: define interface types for the new runtime API (#940) --- .changeset/yellow-mangos-switch.md | 5 + .../src/lib/playground-runtime.ts | 9 +- packages/react/src/api/AssistantRuntime.ts | 27 +++- packages/react/src/api/AttachmentRuntime.ts | 29 +++- packages/react/src/api/ComposerRuntime.ts | 113 +++++++++++++-- packages/react/src/api/ContentPartRuntime.ts | 9 +- packages/react/src/api/MessageRuntime.ts | 48 +++++- packages/react/src/api/ThreadRuntime.ts | 137 ++++++++++++++++-- packages/react/src/api/index.ts | 1 + .../providers/TextContentPartProvider.tsx | 4 +- packages/react/src/internal.ts | 4 +- .../src/runtimes/core/ThreadRuntimeCore.tsx | 1 + .../external-store/ExternalStoreAdapter.tsx | 1 + .../ExternalStoreThreadRuntimeCore.tsx | 6 + .../useExternalStoreRuntime.tsx | 9 +- .../runtimes/local/LocalThreadRuntimeCore.tsx | 4 + .../src/runtimes/local/useLocalRuntime.tsx | 8 +- 17 files changed, 354 insertions(+), 61 deletions(-) create mode 100644 .changeset/yellow-mangos-switch.md diff --git a/.changeset/yellow-mangos-switch.md b/.changeset/yellow-mangos-switch.md new file mode 100644 index 000000000..f65f01cab --- /dev/null +++ b/.changeset/yellow-mangos-switch.md @@ -0,0 +1,5 @@ +--- +"@assistant-ui/react": patch +--- + +refactor: define interface types for the new runtime API diff --git a/packages/react-playground/src/lib/playground-runtime.ts b/packages/react-playground/src/lib/playground-runtime.ts index f467853da..9a1663609 100644 --- a/packages/react-playground/src/lib/playground-runtime.ts +++ b/packages/react-playground/src/lib/playground-runtime.ts @@ -31,8 +31,8 @@ const { ProxyConfigProvider, generateId, DefaultThreadComposerRuntimeCore, - AssistantRuntime, - ThreadRuntime, + AssistantRuntimeImpl, + ThreadRuntimeImpl, } = INTERNAL; const makeModelConfigStore = () => @@ -108,6 +108,7 @@ export class PlaygroundThreadRuntimeCore implements INTERNAL.ThreadRuntimeCore { public readonly threadId = generateId(); public readonly isDisabled = false; public readonly capabilities = CAPABILITIES; + public readonly extras = undefined; private configProvider = new ProxyConfigProvider(); @@ -504,7 +505,7 @@ export class PlaygroundThreadRuntimeCore implements INTERNAL.ThreadRuntimeCore { } } -class PlaygroundThreadRuntime extends ThreadRuntime { +class PlaygroundThreadRuntime extends ThreadRuntimeImpl { constructor(private binding: INTERNAL.ThreadRuntimeCoreBinding) { super(binding); } @@ -532,7 +533,7 @@ export const usePlaygroundRuntime = ({ ); return useMemo( - () => new AssistantRuntime(runtime, PlaygroundThreadRuntime), + () => new AssistantRuntimeImpl(runtime, PlaygroundThreadRuntime), [runtime], ); }; diff --git a/packages/react/src/api/AssistantRuntime.ts b/packages/react/src/api/AssistantRuntime.ts index c49cc2fda..ca3c9d07d 100644 --- a/packages/react/src/api/AssistantRuntime.ts +++ b/packages/react/src/api/AssistantRuntime.ts @@ -2,10 +2,31 @@ import { AssistantRuntimeCore } from "../runtimes/core/AssistantRuntimeCore"; import { NestedSubscriptionSubject } from "./subscribable/NestedSubscriptionSubject"; import { ModelConfigProvider } from "../types/ModelConfigTypes"; import { ThreadRuntime, ThreadRuntimeCoreBinding } from "./ThreadRuntime"; +import { Unsubscribe } from "../types"; -export class AssistantRuntime< - TThreadRuntime extends ThreadRuntime = ThreadRuntime, -> implements AssistantRuntimeCore +export type AssistantRuntime = { + thread: ThreadRuntime; + + switchToNewThread(): void; + + switchToThread(threadId: string): void; + /** + * @deprecated Use `switchToNewThread` instead. This will be removed in 0.6.0. + */ + switchToThread(threadId: string | null): void; + + registerModelConfigProvider(provider: ModelConfigProvider): Unsubscribe; + + /** + * @deprecated Thread is now static and never gets updated. This will be removed in 0.6.0. + */ + subscribe(callback: () => void): Unsubscribe; +}; + +export class AssistantRuntimeImpl< + TThreadRuntime extends ThreadRuntime = ThreadRuntime, + > + implements AssistantRuntimeCore, AssistantRuntime { constructor( private _core: AssistantRuntimeCore, diff --git a/packages/react/src/api/AttachmentRuntime.ts b/packages/react/src/api/AttachmentRuntime.ts index a1c6a9d53..f025d1625 100644 --- a/packages/react/src/api/AttachmentRuntime.ts +++ b/packages/react/src/api/AttachmentRuntime.ts @@ -1,7 +1,12 @@ import { SubscribableWithState } from "./subscribable/Subscribable"; import { ComposerRuntimeCoreBinding } from "./ComposerRuntime"; -import { Attachment, CompleteAttachment, PendingAttachment } from "../types"; +import { + Attachment, + CompleteAttachment, + PendingAttachment, + Unsubscribe, +} from "../types"; type MessageAttachmentState = CompleteAttachment & { source: "message"; @@ -37,9 +42,19 @@ type AttachmentSnapshotBinding = type AttachmentRuntimeSource = AttachmentState["source"]; -export abstract class AttachmentRuntime< +export type AttachmentRuntime< + TSource extends AttachmentRuntimeSource = AttachmentRuntimeSource, +> = { + readonly source: TSource; + getState(): AttachmentState & { source: TSource }; + remove(): Promise; + subscribe(callback: () => void): Unsubscribe; +}; + +export abstract class AttachmentRuntimeImpl< Source extends AttachmentRuntimeSource = AttachmentRuntimeSource, -> { +> implements AttachmentRuntime +{ public abstract get source(): Source; constructor(private _core: AttachmentSnapshotBinding) {} @@ -57,7 +72,7 @@ export abstract class AttachmentRuntime< abstract class ComposerAttachmentRuntime< Source extends "thread-composer" | "edit-composer", -> extends AttachmentRuntime { +> extends AttachmentRuntimeImpl { constructor( core: AttachmentSnapshotBinding, private _composerApi: ComposerRuntimeCoreBinding, @@ -72,19 +87,19 @@ abstract class ComposerAttachmentRuntime< } } -export class ThreadComposerAttachmentRuntime extends ComposerAttachmentRuntime<"thread-composer"> { +export class ThreadComposerAttachmentRuntimeImpl extends ComposerAttachmentRuntime<"thread-composer"> { public get source(): "thread-composer" { return "thread-composer"; } } -export class EditComposerAttachmentRuntime extends ComposerAttachmentRuntime<"edit-composer"> { +export class EditComposerAttachmentRuntimeImpl extends ComposerAttachmentRuntime<"edit-composer"> { public get source(): "edit-composer" { return "edit-composer"; } } -export class MessageAttachmentRuntime extends AttachmentRuntime<"message"> { +export class MessageAttachmentRuntimeImpl extends AttachmentRuntimeImpl<"message"> { public get source(): "message" { return "message"; } diff --git a/packages/react/src/api/ComposerRuntime.ts b/packages/react/src/api/ComposerRuntime.ts index 7d1c476da..1322dad83 100644 --- a/packages/react/src/api/ComposerRuntime.ts +++ b/packages/react/src/api/ComposerRuntime.ts @@ -9,8 +9,8 @@ import { LazyMemoizeSubject } from "./subscribable/LazyMemoizeSubject"; import { AttachmentRuntime, AttachmentState, - EditComposerAttachmentRuntime, - ThreadComposerAttachmentRuntime, + EditComposerAttachmentRuntimeImpl, + ThreadComposerAttachmentRuntimeImpl, } from "./AttachmentRuntime"; import { ShallowMemoizeSubject } from "./subscribable/ShallowMemoizeSubject"; import { SKIP_UPDATE } from "./subscribable/SKIP_UPDATE"; @@ -178,7 +178,50 @@ const getEditComposerState = ( }); }; -export abstract class ComposerRuntime implements ComposerRuntimeCore { +export type ComposerRuntime = { + readonly type: "edit" | "thread"; + getState(): ComposerState; + + /** @deprecated Use `getState().isEditing` instead. This will be removed in 0.6.0. */ + readonly isEditing: boolean; + + /** @deprecated Use `getState().isEmpty` instead. This will be removed in 0.6.0. */ + readonly isEmpty: boolean; + + /** @deprecated Use `getState().canCancel` instead. This will be removed in 0.6.0. */ + readonly canCancel: boolean; + + /** @deprecated Use `getState().text` instead. This will be removed in 0.6.0. */ + readonly text: string; + + /** @deprecated Use `getState().attachmentAccept` instead. This will be removed in 0.6.0. */ + readonly attachmentAccept: string; + + /** @deprecated Use `getState().attachments` instead. This will be removed in 0.6.0. */ + readonly attachments: readonly Attachment[]; + + /** @deprecated Use `getState().text` instead. This will be removed in 0.6.0. */ + readonly value: string; + + setText(text: string): void; + setValue(text: string): void; + addAttachment(file: File): void; + + /** @deprecated Use `getAttachmentById(id).removeAttachment()` instead. This will be removed in 0.6.0. */ + removeAttachment(attachmentId: string): void; + + /** @deprecated This method will be removed in 0.6.0. Submit feedback if you need this functionality. */ + reset(): void; + + send(): void; + cancel(): void; + subscribe(callback: () => void): Unsubscribe; + getAttachmentByIndex(idx: number): AttachmentRuntime; +}; + +export abstract class ComposerRuntimeImpl + implements ComposerRuntimeCore, ComposerRuntime +{ public abstract get type(): "edit" | "thread"; constructor(protected _core: ComposerRuntimeCoreBinding) {} @@ -250,9 +293,9 @@ export abstract class ComposerRuntime implements ComposerRuntimeCore { return core.addAttachment(file); } - // /** - // * @deprecated Use `getAttachmentById(id).removeAttachment` instead. This will be removed in 0.6.0. - // */ + /** + * @deprecated Use `getAttachmentById(id).removeAttachment()` instead. This will be removed in 0.6.0. + */ public removeAttachment(attachmentId: string) { const core = this._core.getState(); if (!core) throw new Error("Composer is not available"); @@ -287,9 +330,27 @@ export abstract class ComposerRuntime implements ComposerRuntimeCore { public abstract getAttachmentByIndex(idx: number): AttachmentRuntime; } -export class ThreadComposerRuntime - extends ComposerRuntime - implements ThreadComposerState +export type ThreadComposerRuntime = Omit< + ComposerRuntime, + "getState" | "getAttachmentByIndex" +> & { + readonly type: "thread"; + getState(): ThreadComposerState; + + /** @deprecated This feature is being removed in 0.6.0. Submit feedback if you need it. */ + focus(): void; + + /** @deprecated This feature is being removed in 0.6.0. Submit feedback if you need it. */ + onFocus(callback: () => void): Unsubscribe; + + getAttachmentByIndex( + idx: number, + ): AttachmentRuntime & { source: "thread-composer" }; +}; + +export class ThreadComposerRuntimeImpl + extends ComposerRuntimeImpl + implements ThreadComposerRuntime, ThreadComposerState { public get type() { return "thread" as const; @@ -325,17 +386,23 @@ export class ThreadComposerRuntime // TODO replace with events private _focusListeners = new Set<() => void>(); + /** + * @deprecated This feature is being removed in 0.6.0. Submit feedback if you need it. + */ public focus() { this._focusListeners.forEach((callback) => callback()); } + /** + * @deprecated This feature is being removed in 0.6.0. Submit feedback if you need it. + */ public onFocus(callback: () => void) { this._focusListeners.add(callback); return () => this._focusListeners.delete(callback); } public getAttachmentByIndex(idx: number) { - return new ThreadComposerAttachmentRuntime( + return new ThreadComposerAttachmentRuntimeImpl( new ShallowMemoizeSubject({ getState: () => { const attachments = this.getState().attachments; @@ -355,9 +422,27 @@ export class ThreadComposerRuntime } } -export class EditComposerRuntime - extends ComposerRuntime - implements EditComposerState +export type EditComposerRuntime = Omit< + ComposerRuntime, + "getState" | "getAttachmentByIndex" +> & { + readonly type: "edit"; + getState(): EditComposerState; + beginEdit(): void; + + /** + * @deprecated Use `beginEdit()` instead. This will be removed in 0.6.0. + */ + edit(): void; + + getAttachmentByIndex( + idx: number, + ): AttachmentRuntime & { source: "edit-composer" }; +}; + +export class EditComposerRuntimeImpl + extends ComposerRuntimeImpl + implements EditComposerRuntime, EditComposerState { public get type() { return "edit" as const; @@ -397,7 +482,7 @@ export class EditComposerRuntime } public getAttachmentByIndex(idx: number) { - return new EditComposerAttachmentRuntime( + return new EditComposerAttachmentRuntimeImpl( new ShallowMemoizeSubject({ getState: () => { const attachments = this.getState().attachments; diff --git a/packages/react/src/api/ContentPartRuntime.ts b/packages/react/src/api/ContentPartRuntime.ts index 35a09b0fc..5e6d2527b 100644 --- a/packages/react/src/api/ContentPartRuntime.ts +++ b/packages/react/src/api/ContentPartRuntime.ts @@ -7,6 +7,7 @@ import { import { ThreadRuntimeCoreBinding } from "./ThreadRuntime"; import { MessageStateBinding } from "./MessageRuntime"; import { SubscribableWithState } from "./subscribable/Subscribable"; +import { Unsubscribe } from "../types"; export type ContentPartState = ( | ThreadUserContentPart @@ -21,7 +22,13 @@ export type ContentPartState = ( type ContentPartSnapshotBinding = SubscribableWithState; -export class ContentPartRuntime { +export type ContentPartRuntime = { + getState(): ContentPartState; + addToolResult(result: any): void; + subscribe(callback: () => void): Unsubscribe; +}; + +export class ContentPartRuntimeImpl implements ContentPartRuntime { constructor( private contentBinding: ContentPartSnapshotBinding, private messageApi: MessageStateBinding, diff --git a/packages/react/src/api/MessageRuntime.ts b/packages/react/src/api/MessageRuntime.ts index 3786d3b65..1cc33daf0 100644 --- a/packages/react/src/api/MessageRuntime.ts +++ b/packages/react/src/api/MessageRuntime.ts @@ -1,15 +1,28 @@ +import { SpeechSynthesisAdapter } from "../runtimes"; import { ThreadMessage, ThreadAssistantContentPart, ThreadUserContentPart, + Unsubscribe, } from "../types"; import { ContentPartStatus, ToolCallContentPartStatus, } from "../types/AssistantTypes"; -import { AttachmentState, MessageAttachmentRuntime } from "./AttachmentRuntime"; -import { EditComposerRuntime } from "./ComposerRuntime"; -import { ContentPartRuntime, ContentPartState } from "./ContentPartRuntime"; +import { + AttachmentRuntime, + AttachmentState, + MessageAttachmentRuntimeImpl, +} from "./AttachmentRuntime"; +import { + EditComposerRuntime, + EditComposerRuntimeImpl, +} from "./ComposerRuntime"; +import { + ContentPartRuntime, + ContentPartRuntimeImpl, + ContentPartState, +} from "./ContentPartRuntime"; import { ThreadRuntimeCoreBinding } from "./ThreadRuntime"; import { NestedSubscriptionSubject } from "./subscribable/NestedSubscriptionSubject"; import { SKIP_UPDATE } from "./subscribable/SKIP_UPDATE"; @@ -94,13 +107,34 @@ export type MessageState = ThreadMessage & { export type MessageStateBinding = SubscribableWithState; -export class MessageRuntime { +export type MessageRuntime = { + composer: EditComposerRuntime; + + getState(): MessageState; + reload(): void; + speak(): SpeechSynthesisAdapter.Utterance; + submitFeedback({ type }: { type: "positive" | "negative" }): void; + switchToBranch({ + position, + branchId, + }: { + position?: "previous" | "next" | undefined; + branchId?: string | undefined; + }): void; + + subscribe(callback: () => void): Unsubscribe; + + getContentPartByIndex(idx: number): ContentPartRuntime; + getAttachmentByIndex(idx: number): AttachmentRuntime & { source: "message" }; +}; + +export class MessageRuntimeImpl implements MessageRuntime { constructor( private _core: MessageStateBinding, private _threadBinding: ThreadRuntimeCoreBinding, ) {} - public composer = new EditComposerRuntime( + public composer = new EditComposerRuntimeImpl( new NestedSubscriptionSubject({ getState: () => this._threadBinding @@ -176,7 +210,7 @@ export class MessageRuntime { public getContentPartByIndex(idx: number) { if (idx < 0) throw new Error("Message index must be >= 0"); - return new ContentPartRuntime( + return new ContentPartRuntimeImpl( new ShallowMemoizeSubject({ getState: () => { return getContentPartState(this.getState(), idx); @@ -189,7 +223,7 @@ export class MessageRuntime { } public getAttachmentByIndex(idx: number) { - return new MessageAttachmentRuntime( + return new MessageAttachmentRuntimeImpl( new ShallowMemoizeSubject({ getState: () => { const attachments = this.getState().attachments; diff --git a/packages/react/src/api/ThreadRuntime.ts b/packages/react/src/api/ThreadRuntime.ts index 1b71acb66..ee459fde1 100644 --- a/packages/react/src/api/ThreadRuntime.ts +++ b/packages/react/src/api/ThreadRuntime.ts @@ -5,14 +5,28 @@ import { ThreadRuntimeCore, } from "../runtimes/core/ThreadRuntimeCore"; import { ExportedMessageRepository } from "../runtimes/utils/MessageRepository"; -import { AppendMessage, ThreadMessage } from "../types"; -import { MessageRuntime, MessageState } from "./MessageRuntime"; +import { + AppendMessage, + ModelConfig, + ThreadMessage, + Unsubscribe, +} from "../types"; +import { + MessageRuntime, + MessageRuntimeImpl, + MessageState, +} from "./MessageRuntime"; import { NestedSubscriptionSubject } from "./subscribable/NestedSubscriptionSubject"; import { ShallowMemoizeSubject } from "./subscribable/ShallowMemoizeSubject"; import { SubscribableWithState } from "./subscribable/Subscribable"; -import { ThreadComposerRuntime } from "./ComposerRuntime"; +import { + ThreadComposerRuntime, + ThreadComposerRuntimeImpl, +} from "./ComposerRuntime"; import { LazyMemoizeSubject } from "./subscribable/LazyMemoizeSubject"; import { SKIP_UPDATE } from "./subscribable/SKIP_UPDATE"; +import { SpeechSynthesisAdapter } from "../runtimes/speech/SpeechAdapterTypes"; +import { ComposerRuntimeCore } from "../runtimes/core/ComposerRuntimeCore"; export type CreateAppendMessage = | string @@ -56,6 +70,7 @@ export type ThreadState = Readonly<{ isRunning: boolean; capabilities: RuntimeCapabilities; messages: readonly ThreadMessage[]; + extras: unknown; }>; export const getThreadState = (runtime: ThreadRuntimeCore): ThreadState => { @@ -69,10 +84,96 @@ export const getThreadState = (runtime: ThreadRuntimeCore): ThreadState => { ? false : lastMessage.status.type === "running", messages: runtime.messages, + extras: runtime.extras, }); }; +export type ThreadRuntime = ThreadRuntimeCore & { + composer: ThreadComposerRuntime; + getState(): ThreadState; + + /** + * @deprecated This method will be removed in 0.6.0. Submit feedback if you need this functionality. + */ + unstable_getCore(): ThreadRuntimeCore; + + append(message: CreateAppendMessage): void; + startRun(parentId: string | null): void; + subscribe(callback: () => void): Unsubscribe; + cancelRun(): void; + getModelConfig(): ModelConfig; + export(): ExportedMessageRepository; + import(repository: ExportedMessageRepository): void; + getMesssageByIndex(idx: number): MessageRuntime; + + // Legacy methods with deprecations -export class ThreadRuntime implements ThreadRuntimeCore { + /** + * @deprecated Use `getState().capabilities` instead. This will be removed in 0.6.0. + */ + capabilities: Readonly; + + /** + * @deprecated Use `getState().threadId` instead. This will be removed in 0.6.0. + */ + threadId: string; + + /** + * @deprecated Use `getState().isDisabled` instead. This will be removed in 0.6.0. + */ + isDisabled: boolean; + + /** + * @deprecated Use `getState().isRunning` instead. This will be removed in 0.6.0. + */ + isRunning: boolean; + + /** + * @deprecated Use `getState().messages` instead. This will be removed in 0.6.0. + */ + messages: readonly ThreadMessage[]; + + /** + * @deprecated Use `getState().extras` instead. This will be removed in 0.6.0. + */ + extras: unknown; + + /** + * @deprecated Use `getMesssageById(id).getState().branchNumber` / `getMesssageById(id).getState().branchCount` instead. This will be removed in 0.6.0. + */ + getBranches: (messageId: string) => readonly string[]; + + /** + * @deprecated Use `getMesssageById(id).switchToBranch({ options })` instead. This will be removed in 0.6.0. + */ + switchToBranch: (branchId: string) => void; + + /** + * @deprecated Use `getMesssageById(id).getContentPartByToolCallId(toolCallId).addToolResult({ result })` instead. This will be removed in 0.6.0. + */ + addToolResult: (options: AddToolResultOptions) => void; + + /** + * @deprecated Use `getMesssageById(id).speak()` instead. This will be removed in 0.6.0. + */ + speak: (messageId: string) => SpeechSynthesisAdapter.Utterance; + + /** + * @deprecated Use `getMesssageById(id).submitFeedback({ type })` instead. This will be removed in 0.6.0. + */ + submitFeedback: (feedback: SubmitFeedbackOptions) => void; + + /** + * @deprecated Use `getMesssageById(id).getMessageByIndex(idx).composer` instead. This will be removed in 0.6.0. + */ + getEditComposer: (messageId: string) => ComposerRuntimeCore | undefined; + + /** + * @deprecated Use `getMesssageById(id).getMessageByIndex(idx).composer.beginEdit()` instead. This will be removed in 0.6.0. + */ + beginEdit: (messageId: string) => void; +}; + +export class ThreadRuntimeImpl implements ThreadRuntime { // public path = "assistant.threads[main]"; // TODO /** @@ -103,6 +204,13 @@ export class ThreadRuntime implements ThreadRuntimeCore { return this.getState().capabilities; } + /** + * @deprecated Use `getState().extras` instead. This will be removed in 0.6.0. + */ + public get extras() { + return this._threadBinding.getState().extras; + } + /** * @deprecated Use `getState().messages` instead. This will be removed in 0.6.0. */ @@ -130,7 +238,7 @@ export class ThreadRuntime implements ThreadRuntimeCore { }; } - public readonly composer = new ThreadComposerRuntime( + public readonly composer = new ThreadComposerRuntimeImpl( new NestedSubscriptionSubject({ getState: () => this._threadBinding.getState().composer, subscribe: (callback) => this._threadBinding.subscribe(callback), @@ -153,9 +261,9 @@ export class ThreadRuntime implements ThreadRuntimeCore { return this._threadBinding.subscribe(callback); } - // /** - // * @derprecated Use `getMesssageById(id).getState().branchNumber` / `getMesssageById(id).getState().branchCount` instead. This will be removed in 0.6.0. - // */ + /** + * @derprecated Use `getMesssageById(id).getState().branchNumber` / `getMesssageById(id).getState().branchCount` instead. This will be removed in 0.6.0. + */ public getBranches(messageId: string) { return this._threadBinding.getState().getBranches(messageId); } @@ -169,19 +277,20 @@ export class ThreadRuntime implements ThreadRuntimeCore { return this._threadBinding.getState().startRun(parentId); } - // TODO public cancelRun() { this._threadBinding.getState().cancelRun(); } - // /** - // * @deprecated Use `getMesssageById(id).getContentPartByToolCallId(toolCallId).addToolResult({ result })` instead. This will be removed in 0.6.0. - // */ + /** + * @deprecated Use `getMesssageById(id).getContentPartByToolCallId(toolCallId).addToolResult({ result })` instead. This will be removed in 0.6.0. + */ public addToolResult(options: AddToolResultOptions) { this._threadBinding.getState().addToolResult(options); } - // TODO + /** + * @deprecated Use `getMesssageById(id).switchToBranch({ options })` instead. This will be removed in 0.6.0. + */ public switchToBranch(branchId: string) { return this._threadBinding.getState().switchToBranch(branchId); } @@ -225,7 +334,7 @@ export class ThreadRuntime implements ThreadRuntimeCore { public getMesssageByIndex(idx: number) { if (idx < 0) throw new Error("Message index must be >= 0"); - return new MessageRuntime( + return new MessageRuntimeImpl( new ShallowMemoizeSubject({ getState: () => { const messages = this.getState().messages; diff --git a/packages/react/src/api/index.ts b/packages/react/src/api/index.ts index d68b0f15d..33b6273b4 100644 --- a/packages/react/src/api/index.ts +++ b/packages/react/src/api/index.ts @@ -7,5 +7,6 @@ export type { ThreadComposerRuntime, EditComposerRuntime, EditComposerState, + ThreadComposerState, ComposerState, } from "./ComposerRuntime"; diff --git a/packages/react/src/context/providers/TextContentPartProvider.tsx b/packages/react/src/context/providers/TextContentPartProvider.tsx index 49cf7006f..0246e1803 100644 --- a/packages/react/src/context/providers/TextContentPartProvider.tsx +++ b/packages/react/src/context/providers/TextContentPartProvider.tsx @@ -10,7 +10,7 @@ import { import { ContentPartStatus, TextContentPart } from "../../types/AssistantTypes"; import { writableStore } from "../ReadonlyStore"; import { - ContentPartRuntime, + ContentPartRuntimeImpl, ContentPartState, } from "../../api/ContentPartRuntime"; @@ -33,7 +33,7 @@ export const TextContentPartProvider: FC< const [context] = useState(() => { const useContentPartRuntime = create( // TODO - () => new ContentPartRuntime(null as any, null as any, null as any), + () => new ContentPartRuntimeImpl(null as any, null as any, null as any), ); const useContentPart = create(() => ({ status: isRunning ? RUNNING_STATUS : COMPLETE_STATUS, diff --git a/packages/react/src/internal.ts b/packages/react/src/internal.ts index 18e120bb6..d2308f3c1 100644 --- a/packages/react/src/internal.ts +++ b/packages/react/src/internal.ts @@ -5,9 +5,9 @@ export { MessageRepository } from "./runtimes/utils/MessageRepository"; export { BaseAssistantRuntimeCore } from "./runtimes/core/BaseAssistantRuntimeCore"; export { TooltipIconButton } from "./ui/base/tooltip-icon-button"; export { generateId } from "./utils/idUtils"; -export { AssistantRuntime } from "./api/AssistantRuntime"; +export { AssistantRuntimeImpl } from "./api/AssistantRuntime"; export { - ThreadRuntime, + ThreadRuntimeImpl, type ThreadRuntimeCoreBinding, } from "./api/ThreadRuntime"; diff --git a/packages/react/src/runtimes/core/ThreadRuntimeCore.tsx b/packages/react/src/runtimes/core/ThreadRuntimeCore.tsx index cfd189f34..30946f71e 100644 --- a/packages/react/src/runtimes/core/ThreadRuntimeCore.tsx +++ b/packages/react/src/runtimes/core/ThreadRuntimeCore.tsx @@ -54,6 +54,7 @@ export type ThreadRuntimeCore = Readonly<{ threadId: string; isDisabled: boolean; messages: readonly ThreadMessage[]; + extras: unknown; subscribe: (callback: () => void) => Unsubscribe; diff --git a/packages/react/src/runtimes/external-store/ExternalStoreAdapter.tsx b/packages/react/src/runtimes/external-store/ExternalStoreAdapter.tsx index da139ff6b..a13716eec 100644 --- a/packages/react/src/runtimes/external-store/ExternalStoreAdapter.tsx +++ b/packages/react/src/runtimes/external-store/ExternalStoreAdapter.tsx @@ -42,6 +42,7 @@ type ExternalStoreAdapterBase = { copy?: boolean | undefined; } | undefined; + extras?: unknown; }; export type ExternalStoreAdapter = diff --git a/packages/react/src/runtimes/external-store/ExternalStoreThreadRuntimeCore.tsx b/packages/react/src/runtimes/external-store/ExternalStoreThreadRuntimeCore.tsx index 8effb174e..e860194a5 100644 --- a/packages/react/src/runtimes/external-store/ExternalStoreThreadRuntimeCore.tsx +++ b/packages/react/src/runtimes/external-store/ExternalStoreThreadRuntimeCore.tsx @@ -88,6 +88,11 @@ export class ExternalStoreThreadRuntimeCore implements ThreadRuntimeCore { this.store = store; } + private _extras: unknown; + public get extras() { + return this._extras; + } + public get store() { return this._store; } @@ -101,6 +106,7 @@ export class ExternalStoreThreadRuntimeCore implements ThreadRuntimeCore { const oldStore = this._store as ExternalStoreAdapter | undefined; this._store = store; + this._extras = store.extras; this._capabilities = { switchToBranch: this._store.setMessages !== undefined, edit: this._store.onEdit !== undefined, diff --git a/packages/react/src/runtimes/external-store/useExternalStoreRuntime.tsx b/packages/react/src/runtimes/external-store/useExternalStoreRuntime.tsx index 988bdf4a1..824fa87f6 100644 --- a/packages/react/src/runtimes/external-store/useExternalStoreRuntime.tsx +++ b/packages/react/src/runtimes/external-store/useExternalStoreRuntime.tsx @@ -1,8 +1,8 @@ import { useEffect, useMemo, useState } from "react"; import { ExternalStoreRuntimeCore } from "./ExternalStoreRuntimeCore"; import { ExternalStoreAdapter } from "./ExternalStoreAdapter"; -import { AssistantRuntime } from "../../api/AssistantRuntime"; -import { ThreadRuntime } from "../../api/ThreadRuntime"; +import { AssistantRuntimeImpl } from "../../api/AssistantRuntime"; +import { ThreadRuntimeImpl } from "../../api/ThreadRuntime"; export const useExternalStoreRuntime = (store: ExternalStoreAdapter) => { const [runtime] = useState(() => new ExternalStoreRuntimeCore(store)); @@ -11,5 +11,8 @@ export const useExternalStoreRuntime = (store: ExternalStoreAdapter) => { runtime.thread.store = store; }); - return useMemo(() => new AssistantRuntime(runtime, ThreadRuntime), [runtime]); + return useMemo( + () => new AssistantRuntimeImpl(runtime, ThreadRuntimeImpl), + [runtime], + ); }; diff --git a/packages/react/src/runtimes/local/LocalThreadRuntimeCore.tsx b/packages/react/src/runtimes/local/LocalThreadRuntimeCore.tsx index 8d07eeb9c..2e735175b 100644 --- a/packages/react/src/runtimes/local/LocalThreadRuntimeCore.tsx +++ b/packages/react/src/runtimes/local/LocalThreadRuntimeCore.tsx @@ -75,6 +75,10 @@ export class LocalThreadRuntimeCore implements ThreadRuntimeCore { return this._options; } + public get extras() { + return undefined; + } + public set options({ initialMessages, ...options }: LocalRuntimeOptions) { this._options = options; diff --git a/packages/react/src/runtimes/local/useLocalRuntime.tsx b/packages/react/src/runtimes/local/useLocalRuntime.tsx index 293ddfff4..6d55e0a50 100644 --- a/packages/react/src/runtimes/local/useLocalRuntime.tsx +++ b/packages/react/src/runtimes/local/useLocalRuntime.tsx @@ -4,12 +4,12 @@ import { useInsertionEffect, useMemo, useState } from "react"; import type { ChatModelAdapter } from "./ChatModelAdapter"; import { LocalRuntimeCore } from "./LocalRuntimeCore"; import { LocalRuntimeOptions } from "./LocalRuntimeOptions"; -import { AssistantRuntime } from "../../api/AssistantRuntime"; -import { ThreadRuntime } from "../../api/ThreadRuntime"; +import { AssistantRuntimeImpl } from "../../api/AssistantRuntime"; +import { ThreadRuntimeImpl } from "../../api/ThreadRuntime"; -export class LocalRuntime extends AssistantRuntime { +export class LocalRuntime extends AssistantRuntimeImpl { constructor(private core: LocalRuntimeCore) { - super(core, ThreadRuntime); + super(core, ThreadRuntimeImpl); } public reset(options?: Parameters[0]) {