Skip to content

Commit

Permalink
feat: Composer.unstable_on("send", callback) (#1279)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yonom authored Dec 28, 2024
1 parent 0fe546b commit 094c8f3
Show file tree
Hide file tree
Showing 15 changed files with 83 additions and 18 deletions.
2 changes: 1 addition & 1 deletion packages/react-ai-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"zustand": "^5.0.2"
},
"peerDependencies": {
"@assistant-ui/react": "^0.7.20",
"@assistant-ui/react": "^0.7.21",
"@types/react": "*",
"react": "^18 || ^19 || ^19.0.0-rc"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/react-hook-form/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"zod": "^3.24.1"
},
"peerDependencies": {
"@assistant-ui/react": "^0.7.20",
"@assistant-ui/react": "^0.7.21",
"@types/react": "*",
"react": "^18 || ^19 || ^19.0.0-rc",
"react-hook-form": "^7"
Expand Down
2 changes: 1 addition & 1 deletion packages/react-langgraph/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"zod": "^3.24.1"
},
"peerDependencies": {
"@assistant-ui/react": "^0.7.20",
"@assistant-ui/react": "^0.7.21",
"@types/react": "*",
"react": "^18 || ^19 || ^19.0.0-rc"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/react-markdown/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"react-markdown": "^9.0.1"
},
"peerDependencies": {
"@assistant-ui/react": "^0.7.20",
"@assistant-ui/react": "^0.7.21",
"@types/react": "*",
"react": "^18 || ^19 || ^19.0.0-rc",
"tailwindcss": "^3.4.4"
Expand Down
2 changes: 1 addition & 1 deletion packages/react-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"zustand": "^5.0.2"
},
"peerDependencies": {
"@assistant-ui/react": "^0.7.20",
"@assistant-ui/react": "^0.7.21",
"@types/react": "*",
"react": "^18 || ^19 || ^19.0.0-rc",
"tailwindcss": "^3.4.4"
Expand Down
2 changes: 1 addition & 1 deletion packages/react-syntax-highlighter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"build": "tsup src/index.ts --format cjs,esm --dts --sourcemap --clean"
},
"peerDependencies": {
"@assistant-ui/react": "^0.7.20",
"@assistant-ui/react": "^0.7.21",
"@assistant-ui/react-markdown": "^0.7.7",
"@types/react": "*",
"@types/react-syntax-highlighter": "*",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-trieve/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"unist-util-visit": "^5.0.0"
},
"peerDependencies": {
"@assistant-ui/react": "^0.7.20",
"@assistant-ui/react": "^0.7.21",
"@assistant-ui/react-markdown": "^0.7.7",
"@types/react": "*",
"react": "^18 || ^19 || ^19.0.0-rc",
Expand Down
6 changes: 6 additions & 0 deletions packages/react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @assistant-ui/react

## 0.7.21

### Patch Changes

- feat: Composer.unstable_on("send", callback)

## 0.7.20

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"conversational-ui",
"conversational-ai"
],
"version": "0.7.20",
"version": "0.7.21",
"license": "MIT",
"exports": {
".": {
Expand Down
8 changes: 8 additions & 0 deletions packages/react/src/api/ComposerRuntime.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Attachment, PendingAttachment } from "../types/AttachmentTypes";
import {
ComposerRuntimeCore,
ComposerRuntimeEventType,
ThreadComposerRuntimeCore,
} from "../runtimes/core/ComposerRuntimeCore";
import { Unsubscribe } from "../types";
Expand Down Expand Up @@ -162,6 +163,13 @@ export abstract class ComposerRuntimeImpl implements ComposerRuntime {
return this._core.subscribe(callback);
}

public unstable_on(event: ComposerRuntimeEventType, callback: () => void) {
const core = this._core.getState();
if (!core) throw new Error("Composer is not available");

return core.unstable_on(event, callback);
}

public getAttachmentAccept(): string {
const core = this._core.getState();
if (!core) throw new Error("Composer is not available");
Expand Down
55 changes: 48 additions & 7 deletions packages/react/src/runtimes/composer/BaseComposerRuntimeCore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import {
} from "../../types/AttachmentTypes";
import { AppendMessage, Unsubscribe } from "../../types";
import { AttachmentAdapter } from "../attachment";
import { ComposerRuntimeCore } from "../core/ComposerRuntimeCore";
import {
ComposerRuntimeCore,
ComposerRuntimeEventType,
} from "../core/ComposerRuntimeCore";
import { MessageRole } from "../../types/AssistantTypes";

const isAttachmentComplete = (a: Attachment): a is CompleteAttachment =>
Expand Down Expand Up @@ -48,23 +51,27 @@ export abstract class BaseComposerRuntimeCore implements ComposerRuntimeCore {
return this._role;
}

setRole(role: MessageRole) {
public setRole(role: MessageRole) {
this._role = role;
this.notifySubscribers();
}

setText(value: string) {
public setText(value: string) {
this._text = value;
this.notifySubscribers();
}

reset() {
private _resetInternal() {
this._text = "";
this._role = "user";
this._attachments = [];
this.notifySubscribers();
}

public reset() {
this._resetInternal();
}

public async send() {
const adapter = this.getAttachmentAdapter();
const attachments =
Expand All @@ -83,12 +90,18 @@ export abstract class BaseComposerRuntimeCore implements ComposerRuntimeCore {
content: this.text ? [{ type: "text", text: this.text }] : [],
attachments,
};
this.reset();
this._resetInternal();

this.handleSend(message);
this._notifyEventSubscribers("send");
}
public abstract handleSend(message: Omit<AppendMessage, "parentId">): void;
public abstract cancel(): void;

public cancel() {
this.handleCancel();
}

protected abstract handleSend(message: Omit<AppendMessage, "parentId">): void;
protected abstract handleCancel(): void;

async addAttachment(file: File) {
const adapter = this.getAttachmentAdapter();
Expand All @@ -115,6 +128,7 @@ export abstract class BaseComposerRuntimeCore implements ComposerRuntimeCore {
}

private _subscriptions = new Set<() => void>();

protected notifySubscribers() {
for (const callback of this._subscriptions) callback();
}
Expand All @@ -123,4 +137,31 @@ export abstract class BaseComposerRuntimeCore implements ComposerRuntimeCore {
this._subscriptions.add(callback);
return () => this._subscriptions.delete(callback);
}

private _eventSubscribers = new Map<
ComposerRuntimeEventType,
Set<() => void>
>();

protected _notifyEventSubscribers(event: ComposerRuntimeEventType) {
const subscribers = this._eventSubscribers.get(event);
if (!subscribers) return;

for (const callback of subscribers) callback();
}

public unstable_on(event: ComposerRuntimeEventType, callback: () => void) {
const subscribers = this._eventSubscribers.get(event);
if (!subscribers) {
this._eventSubscribers.set(event, new Set([callback]));
} else {
subscribers.add(callback);
}

return () => {
const subscribers = this._eventSubscribers.get(event);
if (!subscribers) return;
subscribers.delete(callback);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
this.notifySubscribers();
}

public async cancel() {
public handleCancel() {
this.endEditCallback();
this.notifySubscribers();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class DefaultThreadComposerRuntimeCore
});
}

public async cancel() {
public async handleCancel() {
this.runtime.cancelRun();
}
}
5 changes: 4 additions & 1 deletion packages/react/src/runtimes/core/BaseThreadRuntimeCore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,10 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
this._notifySubscribers();
}

private _eventSubscribers = new Map<string, Set<() => void>>();
private _eventSubscribers = new Map<
ThreadRuntimeEventType,
Set<() => void>
>();

public unstable_on(event: ThreadRuntimeEventType, callback: () => void) {
if (event === "model-config-update") {
Expand Down
7 changes: 7 additions & 0 deletions packages/react/src/runtimes/core/ComposerRuntimeCore.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Attachment, PendingAttachment, Unsubscribe } from "../../types";
import { MessageRole } from "../../types/AssistantTypes";

export type ComposerRuntimeEventType = "send";

export type ComposerRuntimeCore = Readonly<{
attachments: readonly Attachment[];

Expand All @@ -25,6 +27,11 @@ export type ComposerRuntimeCore = Readonly<{
cancel: () => void;

subscribe: (callback: () => void) => Unsubscribe;

unstable_on: (
event: ComposerRuntimeEventType,
callback: () => void,
) => Unsubscribe;
}>;

export type ThreadComposerRuntimeCore = ComposerRuntimeCore &
Expand Down

0 comments on commit 094c8f3

Please sign in to comment.