Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: vercel/ai
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ai@3.0.7
Choose a base ref
...
head repository: vercel/ai
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ai@3.0.8
Choose a head ref
  • 3 commits
  • 23 files changed
  • 5 contributors

Commits on Mar 8, 2024

  1. Move assistant response docs. (#1127)

    lgrammel authored Mar 8, 2024
    Copy the full SHA
    eccbec9 View commit details

Commits on Mar 9, 2024

  1. fix(ai/rsc): Optimize streamable value (#1130)

    Co-authored-by: Max Leiter <max.leiter@vercel.com>
    shuding and MaxLeiter authored Mar 9, 2024
    Copy the full SHA
    a94aab2 View commit details
  2. Version Packages (#1131)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
    github-actions[bot] and github-actions[bot] authored Mar 9, 2024
    Copy the full SHA
    5b7c9ec View commit details
1 change: 0 additions & 1 deletion docs/pages/docs/api-reference/_meta.json
Original file line number Diff line number Diff line change
@@ -8,6 +8,5 @@
"stream-data": "experimental_StreamData",
"streaming-text-response": "StreamingTextResponse",
"stream-to-response": "streamToResponse",
"assistant-response": "experimental_AssistantResponse",
"tokens": "<Tokens />"
}
3 changes: 2 additions & 1 deletion docs/pages/docs/api-reference/providers/_meta.json
Original file line number Diff line number Diff line change
@@ -8,5 +8,6 @@
"openai-stream": "OpenAIStream",
"mistral-stream": "MistralStream",
"replicate-stream": "ReplicateStream",
"inkeep-stream": "InkeepStream"
"inkeep-stream": "InkeepStream",
"assistant-response": "experimental_AssistantResponse"
}
2 changes: 1 addition & 1 deletion examples/next-anthropic/package.json
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
},
"dependencies": {
"@anthropic-ai/sdk": "0.15.0",
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"react": "18.2.0",
"react-dom": "^18.2.0"
2 changes: 1 addition & 1 deletion examples/next-aws-bedrock/package.json
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
},
"dependencies": {
"@aws-sdk/client-bedrock-runtime": "3.451.0",
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"react": "18.2.0",
"react-dom": "^18.2.0"
2 changes: 1 addition & 1 deletion examples/next-fireworks/package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"openai": "4.16.1",
"react": "18.2.0",
2 changes: 1 addition & 1 deletion examples/next-google-generative-ai/package.json
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
},
"dependencies": {
"@google/generative-ai": "0.1.1",
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"react": "18.2.0",
"react-dom": "^18.2.0"
2 changes: 1 addition & 1 deletion examples/next-huggingface/package.json
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
"dependencies": {
"@huggingface/inference": "^2.5.1",
"next": "14.1.1",
"ai": "3.0.7",
"ai": "3.0.8",
"react": "18.2.0",
"react-dom": "^18.2.0"
},
2 changes: 1 addition & 1 deletion examples/next-inkeep/package.json
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
},
"dependencies": {
"@inkeep/ai-api": "^0.1.8",
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"react": "18.2.0",
"react-dom": "^18.2.0"
2 changes: 1 addition & 1 deletion examples/next-langchain/package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"ai": "3.0.7",
"ai": "3.0.8",
"langchain": "^0.0.196",
"next": "14.1.1",
"react": "18.2.0",
2 changes: 1 addition & 1 deletion examples/next-mistral/package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"@mistralai/mistralai": "0.1.3",
"react": "18.2.0",
2 changes: 1 addition & 1 deletion examples/next-openai-pages/package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"openai": "4.16.1",
"react": "18.2.0",
2 changes: 1 addition & 1 deletion examples/next-openai-rate-limits/package.json
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
"dependencies": {
"@upstash/ratelimit": "^0.4.3",
"@vercel/kv": "^0.2.2",
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"openai": "4.16.1",
"react": "18.2.0",
2 changes: 1 addition & 1 deletion examples/next-openai/package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"openai": "4.16.1",
"react": "18.2.0",
2 changes: 1 addition & 1 deletion examples/next-perplexity/package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"ai": "3.0.7",
"ai": "3.0.8",
"next": "14.1.1",
"openai": "4.16.1",
"react": "18.2.0",
2 changes: 1 addition & 1 deletion examples/nuxt-openai/package.json
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
"@vue/runtime-core": "^3.3.4",
"@vue/runtime-dom": "^3.3.4",
"@vue/shared": "^3.3.4",
"ai": "3.0.7",
"ai": "3.0.8",
"nuxt": "^3.6.5",
"openai": "4.16.1",
"tailwindcss": "^3.3.3",
2 changes: 1 addition & 1 deletion examples/solidstart-openai/package.json
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
"dependencies": {
"@solidjs/meta": "0.29.3",
"@solidjs/router": "0.8.2",
"ai": "3.0.7",
"ai": "3.0.8",
"openai": "4.16.1",
"solid-js": "1.8.7",
"solid-start": "0.3.10",
2 changes: 1 addition & 1 deletion examples/sveltekit-openai/package.json
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
},
"dependencies": {
"openai": "4.16.1",
"ai": "3.0.7"
"ai": "3.0.8"
},
"devDependencies": {
"@fontsource/fira-mono": "^4.5.10",
6 changes: 6 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# ai

## 3.0.8

### Patch Changes

- a94aab2: ai/rsc: optimize streamable value stream size

## 3.0.7

### Patch Changes
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ai",
"version": "3.0.7",
"version": "3.0.8",
"license": "Apache-2.0",
"sideEffects": false,
"main": "./dist/index.js",
81 changes: 73 additions & 8 deletions packages/core/rsc/shared-client/streamable.ui.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { createStreamableValue } from '../streamable';
import { readStreamableValue } from './streamable';

function nextTick() {
return Promise.resolve();
}

describe('rsc - readStreamableValue()', () => {
it('should return an async iterable', () => {
const streamable = createStreamableValue();
@@ -11,20 +15,81 @@ describe('rsc - readStreamableValue()', () => {
expect(result[Symbol.asyncIterator]).toBeDefined();
});

it('should be able to read all values', async () => {
const streamable = createStreamableValue(0);
it('should directly emit the final value when reading .value', async () => {
const streamable = createStreamableValue('1');
streamable.update('2');
streamable.update('3');

expect(streamable.value).toMatchInlineSnapshot(`
{
"curr": "3",
"next": Promise {},
"type": Symbol(ui.streamable.value),
}
`);

streamable.done('4');

expect(streamable.value).toMatchInlineSnapshot(`
{
"curr": "4",
"type": Symbol(ui.streamable.value),
}
`);
});

it('should be able to stream any JSON values', async () => {
const streamable = createStreamableValue();
streamable.update({ v: 123 });

expect(streamable.value).toMatchInlineSnapshot(`
{
"curr": {
"v": 123,
},
"next": Promise {},
"type": Symbol(ui.streamable.value),
}
`);

streamable.done();
});

streamable.update(1);
streamable.update(2);
streamable.done(3);
it('should support .error()', async () => {
const streamable = createStreamableValue();
streamable.error('This is an error');

expect(streamable.value).toMatchInlineSnapshot(`
{
"error": "This is an error",
"type": Symbol(ui.streamable.value),
}
`);
});

it('should support reading streamed values and errors', async () => {
const streamable = createStreamableValue(1);
(async () => {
await nextTick();
streamable.update(2);
await nextTick();
streamable.update(3);
await nextTick();
streamable.error('This is an error');
})();

const values = [];
for await (const v of readStreamableValue(streamable.value)) {
values.push(v);

try {
for await (const v of readStreamableValue(streamable.value)) {
values.push(v);
}
} catch (e) {
expect(e).toMatchInlineSnapshot(`"This is an error"`);
}

expect(values).toMatchInlineSnapshot(`
[
0,
1,
2,
3,
60 changes: 36 additions & 24 deletions packages/core/rsc/streamable.tsx
Original file line number Diff line number Diff line change
@@ -113,7 +113,12 @@ export function createStreamableUI(initialValue?: React.ReactNode) {
*/
export function createStreamableValue<T = any, E = any>(initialValue?: T) {
let closed = false;
let { promise, resolve } = createResolvablePromise<StreamableValue<T, E>>();
let resolvable = createResolvablePromise<StreamableValue<T, E>>();

let currentValue = initialValue;
let currentError: E | undefined;
let currentPromise: typeof resolvable.promise | undefined =
resolvable.promise;

function assertStream(method: string) {
if (closed) {
@@ -136,35 +141,37 @@ export function createStreamableValue<T = any, E = any>(initialValue?: T) {
}
warnUnclosedStream();

function createWrapped(
val: T | undefined,
initial?: boolean,
): StreamableValue<T, E> {
if (initial) {
return {
type: STREAMABLE_VALUE_TYPE,
curr: val,
next: promise,
};
function createWrapped(withType?: boolean): StreamableValue<T, E> {
// This makes the payload much smaller if there're mutative updates before the first read.
const init: Partial<StreamableValue<T, E>> =
currentError === undefined
? { curr: currentValue }
: { error: currentError };

if (currentPromise) {
init.next = currentPromise;
}

return {
curr: val,
next: promise,
};
if (withType) {
init.type = STREAMABLE_VALUE_TYPE;
}

return init;
}

return {
value: createWrapped(initialValue, true),
get value() {
return createWrapped(true);
},
update(value: T) {
assertStream('.update()');

const resolvePrevious = resolve;
const resolvable = createResolvablePromise();
promise = resolvable.promise;
resolve = resolvable.resolve;
const resolvePrevious = resolvable.resolve;
resolvable = createResolvablePromise();

resolvePrevious(createWrapped(value));
currentValue = value;
currentPromise = resolvable.promise;
resolvePrevious(createWrapped());

warnUnclosedStream();
},
@@ -175,7 +182,10 @@ export function createStreamableValue<T = any, E = any>(initialValue?: T) {
clearTimeout(warningTimeout);
}
closed = true;
resolve({ error });
currentError = error;
currentPromise = undefined;

resolvable.resolve({ error });
},
done(...args: any) {
assertStream('.done()');
@@ -184,13 +194,15 @@ export function createStreamableValue<T = any, E = any>(initialValue?: T) {
clearTimeout(warningTimeout);
}
closed = true;
currentPromise = undefined;

if (args.length) {
resolve({ curr: args[0] });
currentValue = args[0];
resolvable.resolve({ curr: args[0] });
return;
}

resolve({});
resolvable.resolve({});
},
};
}
Loading