@ai-sdk/svelte 0.0.0-9477ebb9-20250403064906
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +936 -0
- package/LICENSE +13 -0
- package/README.md +9 -0
- package/dist/chat-context.svelte.d.ts +14 -0
- package/dist/chat-context.svelte.d.ts.map +1 -0
- package/dist/chat-context.svelte.js +13 -0
- package/dist/chat.svelte.d.ts +75 -0
- package/dist/chat.svelte.d.ts.map +1 -0
- package/dist/chat.svelte.js +250 -0
- package/dist/completion-context.svelte.d.ts +15 -0
- package/dist/completion-context.svelte.d.ts.map +1 -0
- package/dist/completion-context.svelte.js +14 -0
- package/dist/completion.svelte.d.ts +37 -0
- package/dist/completion.svelte.d.ts.map +1 -0
- package/dist/completion.svelte.js +111 -0
- package/dist/context-provider.d.ts +2 -0
- package/dist/context-provider.d.ts.map +1 -0
- package/dist/context-provider.js +11 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/structured-object-context.svelte.d.ts +12 -0
- package/dist/structured-object-context.svelte.d.ts.map +1 -0
- package/dist/structured-object-context.svelte.js +12 -0
- package/dist/structured-object.svelte.d.ts +79 -0
- package/dist/structured-object.svelte.d.ts.map +1 -0
- package/dist/structured-object.svelte.js +124 -0
- package/dist/tests/chat-synchronization.svelte +12 -0
- package/dist/tests/chat-synchronization.svelte.d.ts +11 -0
- package/dist/tests/chat-synchronization.svelte.d.ts.map +1 -0
- package/dist/tests/completion-synchronization.svelte +12 -0
- package/dist/tests/completion-synchronization.svelte.d.ts +11 -0
- package/dist/tests/completion-synchronization.svelte.d.ts.map +1 -0
- package/dist/tests/structured-object-synchronization.svelte +22 -0
- package/dist/tests/structured-object-synchronization.svelte.d.ts +28 -0
- package/dist/tests/structured-object-synchronization.svelte.d.ts.map +1 -0
- package/dist/utils.svelte.d.ts +17 -0
- package/dist/utils.svelte.d.ts.map +1 -0
- package/dist/utils.svelte.js +50 -0
- package/package.json +88 -0
- package/src/chat-context.svelte.ts +23 -0
- package/src/chat.svelte.ts +350 -0
- package/src/completion-context.svelte.ts +24 -0
- package/src/completion.svelte.ts +133 -0
- package/src/context-provider.ts +20 -0
- package/src/index.ts +16 -0
- package/src/structured-object-context.svelte.ts +27 -0
- package/src/structured-object.svelte.ts +230 -0
- package/src/tests/chat-synchronization.svelte +12 -0
- package/src/tests/completion-synchronization.svelte +12 -0
- package/src/tests/structured-object-synchronization.svelte +22 -0
- package/src/utils.svelte.ts +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2023 Vercel, Inc.
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# AI SDK: Svelte provider
|
|
2
|
+
|
|
3
|
+
[Svelte](https://svelte.dev/) UI components for the [AI SDK](https://sdk.vercel.ai/docs):
|
|
4
|
+
|
|
5
|
+
- [`Chat`](https://sdk.vercel.ai/docs/reference/ai-sdk-ui/use-chat)
|
|
6
|
+
- [`Completion`](https://sdk.vercel.ai/docs/reference/ai-sdk-ui/use-completion)
|
|
7
|
+
- [`StructuredObject`](https://sdk.vercel.ai/docs/reference/ai-sdk-ui/use-object)
|
|
8
|
+
|
|
9
|
+
For information on the few ways the Svelte APIs differ from the React ones, see [the docs](https://sdk.vercel.ai/docs/getting-started/svelte#how-does-ai-sdksvelte-differ-from-ai-sdkreact)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { JSONValue, UIMessage } from '@ai-sdk/ui-utils';
|
|
2
|
+
import { KeyedStore } from './utils.svelte.js';
|
|
3
|
+
declare class ChatStore {
|
|
4
|
+
messages: UIMessage[];
|
|
5
|
+
data: JSONValue[] | undefined;
|
|
6
|
+
status: "submitted" | "streaming" | "ready" | "error";
|
|
7
|
+
error: Error | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare class KeyedChatStore extends KeyedStore<ChatStore> {
|
|
10
|
+
constructor(value?: Iterable<readonly [string, ChatStore]> | null | undefined);
|
|
11
|
+
}
|
|
12
|
+
export declare const hasChatContext: () => boolean, getChatContext: () => KeyedChatStore, setChatContext: (value: KeyedChatStore) => KeyedChatStore;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=chat-context.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-context.svelte.d.ts","sourceRoot":"","sources":["../src/chat-context.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAiB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9D,cAAM,SAAS;IACb,QAAQ,cAA2B;IACnC,IAAI,0BAAyB;IAC7B,MAAM,gDAAkE;IACxE,KAAK,oBAAmB;CACzB;AAED,qBAAa,cAAe,SAAQ,UAAU,CAAC,SAAS,CAAC;gBAErD,KAAK,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS;CAIpE;AAED,eAAO,MACO,cAAc,iBACd,cAAc,wBACd,cAAc,2CACa,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createContext, KeyedStore } from './utils.svelte.js';
|
|
2
|
+
class ChatStore {
|
|
3
|
+
messages = $state([]);
|
|
4
|
+
data = $state();
|
|
5
|
+
status = $state('ready');
|
|
6
|
+
error = $state();
|
|
7
|
+
}
|
|
8
|
+
export class KeyedChatStore extends KeyedStore {
|
|
9
|
+
constructor(value) {
|
|
10
|
+
super(ChatStore, value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export const { hasContext: hasChatContext, getContext: getChatContext, setContext: setChatContext, } = createContext('Chat');
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type UIMessage, type UseChatOptions, type JSONValue, type Message, type CreateMessage, type ChatRequestOptions } from '@ai-sdk/ui-utils';
|
|
2
|
+
export type ChatOptions = Readonly<Omit<UseChatOptions, 'keepLastMessageOnError'> & {
|
|
3
|
+
/**
|
|
4
|
+
* Maximum number of sequential LLM calls (steps), e.g. when you use tool calls.
|
|
5
|
+
* Must be at least 1.
|
|
6
|
+
* A maximum number is required to prevent infinite loops in the case of misconfigured tools.
|
|
7
|
+
* By default, it's set to 1, which means that only a single LLM call is made.
|
|
8
|
+
* @default 1
|
|
9
|
+
*/
|
|
10
|
+
maxSteps?: number;
|
|
11
|
+
}>;
|
|
12
|
+
export type { CreateMessage, Message, UIMessage };
|
|
13
|
+
export declare class Chat {
|
|
14
|
+
#private;
|
|
15
|
+
/**
|
|
16
|
+
* The id of the chat. If not provided through the constructor, a random ID will be generated
|
|
17
|
+
* using the provided `generateId` function, or a built-in function if not provided.
|
|
18
|
+
*/
|
|
19
|
+
readonly id: string;
|
|
20
|
+
/**
|
|
21
|
+
* Additional data added on the server via StreamData.
|
|
22
|
+
*
|
|
23
|
+
* This is writable, so you can use it to transform or clear the chat data.
|
|
24
|
+
*/
|
|
25
|
+
get data(): JSONValue[] | undefined;
|
|
26
|
+
set data(value: JSONValue[] | undefined);
|
|
27
|
+
/**
|
|
28
|
+
* Hook status:
|
|
29
|
+
*
|
|
30
|
+
* - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.
|
|
31
|
+
* - `streaming`: The response is actively streaming in from the API, receiving chunks of data.
|
|
32
|
+
* - `ready`: The full response has been received and processed; a new user message can be submitted.
|
|
33
|
+
* - `error`: An error occurred during the API request, preventing successful completion.
|
|
34
|
+
*/
|
|
35
|
+
get status(): "submitted" | "streaming" | "ready" | "error";
|
|
36
|
+
/** The error object of the API request */
|
|
37
|
+
get error(): Error | undefined;
|
|
38
|
+
/** The current value of the input. Writable, so it can be bound to form inputs. */
|
|
39
|
+
input: string;
|
|
40
|
+
/**
|
|
41
|
+
* Current messages in the chat.
|
|
42
|
+
*
|
|
43
|
+
* This is writable, which is useful when you want to edit the messages on the client, and then
|
|
44
|
+
* trigger {@link reload} to regenerate the AI response.
|
|
45
|
+
*/
|
|
46
|
+
get messages(): UIMessage[];
|
|
47
|
+
set messages(value: Message[]);
|
|
48
|
+
constructor(options?: ChatOptions);
|
|
49
|
+
/**
|
|
50
|
+
* Append a user message to the chat list. This triggers the API call to fetch
|
|
51
|
+
* the assistant's response.
|
|
52
|
+
* @param message The message to append
|
|
53
|
+
* @param options Additional options to pass to the API call
|
|
54
|
+
*/
|
|
55
|
+
append: (message: Message | CreateMessage, { data, headers, body, experimental_attachments }?: ChatRequestOptions) => Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Reload the last AI chat response for the given chat history. If the last
|
|
58
|
+
* message isn't from the assistant, it will request the API to generate a
|
|
59
|
+
* new response.
|
|
60
|
+
*/
|
|
61
|
+
reload: ({ data, headers, body }?: ChatRequestOptions) => Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Abort the current request immediately, keep the generated tokens if any.
|
|
64
|
+
*/
|
|
65
|
+
stop: () => void;
|
|
66
|
+
/** Form submission handler to automatically reset input and append a user message */
|
|
67
|
+
handleSubmit: (event?: {
|
|
68
|
+
preventDefault?: () => void;
|
|
69
|
+
}, options?: ChatRequestOptions) => Promise<void>;
|
|
70
|
+
addToolResult: ({ toolCallId, result, }: {
|
|
71
|
+
toolCallId: string;
|
|
72
|
+
result: unknown;
|
|
73
|
+
}) => Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=chat.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.svelte.d.ts","sourceRoot":"","sources":["../src/chat.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,SAAS,EAKd,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,kBAAkB,EAKxB,MAAM,kBAAkB,CAAC;AAS1B,MAAM,MAAM,WAAW,GAAG,QAAQ,CAChC,IAAI,CAAC,cAAc,EAAE,wBAAwB,CAAC,GAAG;IAC/C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CACF,CAAC;AAEF,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAElD,qBAAa,IAAI;;IAOf;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAoD;IAI/D;;;;OAIG;IACH,IAAI,IAAI,IAGQ,SAAS,EAAE,GAAG,SAAS,CADtC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,EAEtC;IAED;;;;;;;OAOG;IACH,IAAI,MAAM,kDAET;IAED,0CAA0C;IAC1C,IAAI,KAAK,sBAER;IAED,mFAAmF;IACnF,KAAK,SAAqB;IAE1B;;;;;OAKG;IACH,IAAI,QAAQ,IAAI,SAAS,EAAE,CAE1B;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,EAE5B;gBAEW,OAAO,GAAE,WAAgB;IAYrC;;;;;OAKG;IACH,MAAM,YACK,OAAO,GAAG,aAAa,sDACmB,kBAAkB,mBAgBrE;IAEF;;;;OAIG;IACH,MAAM,6BAAmC,kBAAkB,mBAezD;IAEF;;OAEG;IACH,IAAI,aASF;IAEF,qFAAqF;IACrF,YAAY,WACF;QAAE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,YAC9B,kBAAkB,mBA6B3B;IAEF,aAAa,4BAGV;QACD,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,CAAC;KACjB,mBAmBC;CAmHH"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { fillMessageParts, generateId, extractMaxToolInvocationStep, callChatApi, shouldResubmitMessages, prepareAttachmentsForRequest, getMessageParts, updateToolCallResult, isAssistantMessageWithCompletedToolCalls, } from '@ai-sdk/ui-utils';
|
|
2
|
+
import { isAbortError } from '@ai-sdk/provider-utils';
|
|
3
|
+
import { KeyedChatStore, getChatContext, hasChatContext, } from './chat-context.svelte.js';
|
|
4
|
+
import { untrack } from 'svelte';
|
|
5
|
+
export class Chat {
|
|
6
|
+
#options = {};
|
|
7
|
+
#api = $derived(this.#options.api ?? '/api/chat');
|
|
8
|
+
#generateId = $derived(this.#options.generateId ?? generateId);
|
|
9
|
+
#maxSteps = $derived(this.#options.maxSteps ?? 1);
|
|
10
|
+
#streamProtocol = $derived(this.#options.streamProtocol ?? 'data');
|
|
11
|
+
#keyedStore = $state();
|
|
12
|
+
/**
|
|
13
|
+
* The id of the chat. If not provided through the constructor, a random ID will be generated
|
|
14
|
+
* using the provided `generateId` function, or a built-in function if not provided.
|
|
15
|
+
*/
|
|
16
|
+
id = $derived(this.#options.id ?? this.#generateId());
|
|
17
|
+
#store = $derived(this.#keyedStore.get(this.id));
|
|
18
|
+
#abortController;
|
|
19
|
+
/**
|
|
20
|
+
* Additional data added on the server via StreamData.
|
|
21
|
+
*
|
|
22
|
+
* This is writable, so you can use it to transform or clear the chat data.
|
|
23
|
+
*/
|
|
24
|
+
get data() {
|
|
25
|
+
return this.#store.data;
|
|
26
|
+
}
|
|
27
|
+
set data(value) {
|
|
28
|
+
this.#store.data = value;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Hook status:
|
|
32
|
+
*
|
|
33
|
+
* - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.
|
|
34
|
+
* - `streaming`: The response is actively streaming in from the API, receiving chunks of data.
|
|
35
|
+
* - `ready`: The full response has been received and processed; a new user message can be submitted.
|
|
36
|
+
* - `error`: An error occurred during the API request, preventing successful completion.
|
|
37
|
+
*/
|
|
38
|
+
get status() {
|
|
39
|
+
return this.#store.status;
|
|
40
|
+
}
|
|
41
|
+
/** The error object of the API request */
|
|
42
|
+
get error() {
|
|
43
|
+
return this.#store.error;
|
|
44
|
+
}
|
|
45
|
+
/** The current value of the input. Writable, so it can be bound to form inputs. */
|
|
46
|
+
input = $state();
|
|
47
|
+
/**
|
|
48
|
+
* Current messages in the chat.
|
|
49
|
+
*
|
|
50
|
+
* This is writable, which is useful when you want to edit the messages on the client, and then
|
|
51
|
+
* trigger {@link reload} to regenerate the AI response.
|
|
52
|
+
*/
|
|
53
|
+
get messages() {
|
|
54
|
+
return this.#store.messages;
|
|
55
|
+
}
|
|
56
|
+
set messages(value) {
|
|
57
|
+
untrack(() => (this.#store.messages = fillMessageParts(value)));
|
|
58
|
+
}
|
|
59
|
+
constructor(options = {}) {
|
|
60
|
+
if (hasChatContext()) {
|
|
61
|
+
this.#keyedStore = getChatContext();
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
this.#keyedStore = new KeyedChatStore();
|
|
65
|
+
}
|
|
66
|
+
this.#options = options;
|
|
67
|
+
this.messages = options.initialMessages ?? [];
|
|
68
|
+
this.input = options.initialInput ?? '';
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Append a user message to the chat list. This triggers the API call to fetch
|
|
72
|
+
* the assistant's response.
|
|
73
|
+
* @param message The message to append
|
|
74
|
+
* @param options Additional options to pass to the API call
|
|
75
|
+
*/
|
|
76
|
+
append = async (message, { data, headers, body, experimental_attachments } = {}) => {
|
|
77
|
+
const attachmentsForRequest = await prepareAttachmentsForRequest(experimental_attachments);
|
|
78
|
+
const messages = this.messages.concat({
|
|
79
|
+
...message,
|
|
80
|
+
id: message.id ?? this.#generateId(),
|
|
81
|
+
createdAt: message.createdAt ?? new Date(),
|
|
82
|
+
experimental_attachments: attachmentsForRequest.length > 0 ? attachmentsForRequest : undefined,
|
|
83
|
+
parts: getMessageParts(message),
|
|
84
|
+
});
|
|
85
|
+
return this.#triggerRequest({ messages, headers, body, data });
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Reload the last AI chat response for the given chat history. If the last
|
|
89
|
+
* message isn't from the assistant, it will request the API to generate a
|
|
90
|
+
* new response.
|
|
91
|
+
*/
|
|
92
|
+
reload = async ({ data, headers, body } = {}) => {
|
|
93
|
+
if (this.messages.length === 0) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
97
|
+
await this.#triggerRequest({
|
|
98
|
+
messages: lastMessage.role === 'assistant'
|
|
99
|
+
? this.messages.slice(0, -1)
|
|
100
|
+
: this.messages,
|
|
101
|
+
headers,
|
|
102
|
+
body,
|
|
103
|
+
data,
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Abort the current request immediately, keep the generated tokens if any.
|
|
108
|
+
*/
|
|
109
|
+
stop = () => {
|
|
110
|
+
try {
|
|
111
|
+
this.#abortController?.abort();
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// ignore
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
this.#store.status = 'ready';
|
|
118
|
+
this.#abortController = undefined;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
/** Form submission handler to automatically reset input and append a user message */
|
|
122
|
+
handleSubmit = async (event, options = {}) => {
|
|
123
|
+
event?.preventDefault?.();
|
|
124
|
+
if (!this.input && !options.allowEmptySubmit)
|
|
125
|
+
return;
|
|
126
|
+
const attachmentsForRequest = await prepareAttachmentsForRequest(options.experimental_attachments);
|
|
127
|
+
const messages = this.messages.concat({
|
|
128
|
+
id: this.#generateId(),
|
|
129
|
+
createdAt: new Date(),
|
|
130
|
+
role: 'user',
|
|
131
|
+
content: this.input,
|
|
132
|
+
experimental_attachments: attachmentsForRequest.length > 0 ? attachmentsForRequest : undefined,
|
|
133
|
+
parts: [{ type: 'text', text: this.input }],
|
|
134
|
+
});
|
|
135
|
+
const chatRequest = {
|
|
136
|
+
messages,
|
|
137
|
+
headers: options.headers,
|
|
138
|
+
body: options.body,
|
|
139
|
+
data: options.data,
|
|
140
|
+
};
|
|
141
|
+
const request = this.#triggerRequest(chatRequest);
|
|
142
|
+
this.input = '';
|
|
143
|
+
await request;
|
|
144
|
+
};
|
|
145
|
+
addToolResult = async ({ toolCallId, result, }) => {
|
|
146
|
+
updateToolCallResult({
|
|
147
|
+
messages: this.messages,
|
|
148
|
+
toolCallId,
|
|
149
|
+
toolResult: result,
|
|
150
|
+
});
|
|
151
|
+
// when the request is ongoing, the auto-submit will be triggered after the request is finished
|
|
152
|
+
if (this.#store.status === 'submitted' ||
|
|
153
|
+
this.#store.status === 'streaming') {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
157
|
+
if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {
|
|
158
|
+
await this.#triggerRequest({ messages: this.messages });
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
#triggerRequest = async (chatRequest) => {
|
|
162
|
+
this.#store.status = 'submitted';
|
|
163
|
+
this.#store.error = undefined;
|
|
164
|
+
const messages = fillMessageParts(chatRequest.messages);
|
|
165
|
+
const messageCount = messages.length;
|
|
166
|
+
const maxStep = extractMaxToolInvocationStep(messages[messages.length - 1]?.toolInvocations);
|
|
167
|
+
try {
|
|
168
|
+
const abortController = new AbortController();
|
|
169
|
+
this.#abortController = abortController;
|
|
170
|
+
// Optimistically update messages
|
|
171
|
+
this.messages = messages;
|
|
172
|
+
const constructedMessagesPayload = this.#options.sendExtraMessageFields
|
|
173
|
+
? messages
|
|
174
|
+
: messages.map(({ role, content, experimental_attachments, data, annotations, toolInvocations, parts, }) => ({
|
|
175
|
+
role,
|
|
176
|
+
content,
|
|
177
|
+
...(experimental_attachments !== undefined && {
|
|
178
|
+
experimental_attachments,
|
|
179
|
+
}),
|
|
180
|
+
...(data !== undefined && { data }),
|
|
181
|
+
...(annotations !== undefined && { annotations }),
|
|
182
|
+
...(toolInvocations !== undefined && { toolInvocations }),
|
|
183
|
+
...(parts !== undefined && { parts }),
|
|
184
|
+
}));
|
|
185
|
+
const existingData = this.data ?? [];
|
|
186
|
+
await callChatApi({
|
|
187
|
+
api: this.#api,
|
|
188
|
+
body: {
|
|
189
|
+
id: this.id,
|
|
190
|
+
messages: constructedMessagesPayload,
|
|
191
|
+
data: chatRequest.data,
|
|
192
|
+
...$state.snapshot(this.#options.body),
|
|
193
|
+
...chatRequest.body,
|
|
194
|
+
},
|
|
195
|
+
streamProtocol: this.#streamProtocol,
|
|
196
|
+
credentials: this.#options.credentials,
|
|
197
|
+
headers: {
|
|
198
|
+
...this.#options.headers,
|
|
199
|
+
...chatRequest.headers,
|
|
200
|
+
},
|
|
201
|
+
abortController: () => abortController,
|
|
202
|
+
restoreMessagesOnFailure: () => { },
|
|
203
|
+
onResponse: this.#options.onResponse,
|
|
204
|
+
onUpdate: ({ message, data, replaceLastMessage }) => {
|
|
205
|
+
this.#store.status = 'streaming';
|
|
206
|
+
this.messages = messages;
|
|
207
|
+
if (replaceLastMessage) {
|
|
208
|
+
this.messages[this.messages.length - 1] = message;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.messages.push(message);
|
|
212
|
+
}
|
|
213
|
+
if (data?.length) {
|
|
214
|
+
this.data = existingData;
|
|
215
|
+
this.data.push(...data);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
onToolCall: this.#options.onToolCall,
|
|
219
|
+
onFinish: this.#options.onFinish,
|
|
220
|
+
generateId: this.#generateId,
|
|
221
|
+
fetch: this.#options.fetch,
|
|
222
|
+
// callChatApi calls structuredClone on the message
|
|
223
|
+
lastMessage: $state.snapshot(this.messages[this.messages.length - 1]),
|
|
224
|
+
});
|
|
225
|
+
this.#abortController = undefined;
|
|
226
|
+
this.#store.status = 'ready';
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
if (isAbortError(error)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const coalescedError = error instanceof Error ? error : new Error(String(error));
|
|
233
|
+
if (this.#options.onError) {
|
|
234
|
+
this.#options.onError(coalescedError);
|
|
235
|
+
}
|
|
236
|
+
this.#store.status = 'error';
|
|
237
|
+
this.#store.error = coalescedError;
|
|
238
|
+
}
|
|
239
|
+
// auto-submit when all tool calls in the last assistant message have results
|
|
240
|
+
// and assistant has not answered yet
|
|
241
|
+
if (shouldResubmitMessages({
|
|
242
|
+
originalMaxToolInvocationStep: maxStep,
|
|
243
|
+
originalMessageCount: messageCount,
|
|
244
|
+
maxSteps: this.#maxSteps,
|
|
245
|
+
messages: this.messages,
|
|
246
|
+
})) {
|
|
247
|
+
await this.#triggerRequest({ messages: this.messages });
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JSONValue } from '@ai-sdk/ui-utils';
|
|
2
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
3
|
+
import { KeyedStore } from './utils.svelte.js';
|
|
4
|
+
declare class CompletionStore {
|
|
5
|
+
completions: SvelteMap<string, string>;
|
|
6
|
+
data: JSONValue[];
|
|
7
|
+
loading: boolean;
|
|
8
|
+
error: Error | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare class KeyedCompletionStore extends KeyedStore<CompletionStore> {
|
|
11
|
+
constructor(value?: Iterable<readonly [string, CompletionStore]> | null | undefined);
|
|
12
|
+
}
|
|
13
|
+
export declare const hasCompletionContext: () => boolean, getCompletionContext: () => KeyedCompletionStore, setCompletionContext: (value: KeyedCompletionStore) => KeyedCompletionStore;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=completion-context.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-context.svelte.d.ts","sourceRoot":"","sources":["../src/completion-context.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAiB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9D,cAAM,eAAe;IACnB,WAAW,4BAAmC;IAC9C,IAAI,cAA2B;IAC/B,OAAO,UAAiB;IACxB,KAAK,oBAAmB;CACzB;AAED,qBAAa,oBAAqB,SAAQ,UAAU,CAAC,eAAe,CAAC;gBAEjE,KAAK,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS;CAI1E;AAED,eAAO,MACO,oBAAoB,iBACpB,oBAAoB,8BACpB,oBAAoB,uDACmB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
2
|
+
import { createContext, KeyedStore } from './utils.svelte.js';
|
|
3
|
+
class CompletionStore {
|
|
4
|
+
completions = new SvelteMap();
|
|
5
|
+
data = $state([]);
|
|
6
|
+
loading = $state(false);
|
|
7
|
+
error = $state();
|
|
8
|
+
}
|
|
9
|
+
export class KeyedCompletionStore extends KeyedStore {
|
|
10
|
+
constructor(value) {
|
|
11
|
+
super(CompletionStore, value);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export const { hasContext: hasCompletionContext, getContext: getCompletionContext, setContext: setCompletionContext, } = createContext('Completion');
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type UseCompletionOptions, type JSONValue, type RequestOptions } from '@ai-sdk/ui-utils';
|
|
2
|
+
export type CompletionOptions = Readonly<UseCompletionOptions>;
|
|
3
|
+
export declare class Completion {
|
|
4
|
+
#private;
|
|
5
|
+
/** The current completion result */
|
|
6
|
+
get completion(): string;
|
|
7
|
+
set completion(value: string);
|
|
8
|
+
/**
|
|
9
|
+
* Additional data added on the server via StreamData.
|
|
10
|
+
*
|
|
11
|
+
* This is writable, so you can use it to transform or clear the chat data.
|
|
12
|
+
*/
|
|
13
|
+
get data(): JSONValue[];
|
|
14
|
+
set data(value: JSONValue[]);
|
|
15
|
+
/** The error object of the API request */
|
|
16
|
+
get error(): Error | undefined;
|
|
17
|
+
/** The current value of the input. Writable, so it can be bound to form inputs. */
|
|
18
|
+
input: string;
|
|
19
|
+
/**
|
|
20
|
+
* Flag that indicates whether an API request is in progress.
|
|
21
|
+
*/
|
|
22
|
+
get loading(): boolean;
|
|
23
|
+
constructor(options?: CompletionOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Abort the current request immediately, keep the generated tokens if any.
|
|
26
|
+
*/
|
|
27
|
+
stop: () => void;
|
|
28
|
+
/**
|
|
29
|
+
* Send a new prompt to the API endpoint and update the completion state.
|
|
30
|
+
*/
|
|
31
|
+
complete: (prompt: string, options?: RequestOptions) => Promise<string | null | undefined>;
|
|
32
|
+
/** Form submission handler to automatically reset input and call the completion API */
|
|
33
|
+
handleSubmit: (event?: {
|
|
34
|
+
preventDefault?: () => void;
|
|
35
|
+
}) => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=completion.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.svelte.d.ts","sourceRoot":"","sources":["../src/completion.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACd,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAC;AAO1B,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AAE/D,qBAAa,UAAU;;IASrB,oCAAoC;IACpC,IAAI,UAAU,IAAI,MAAM,CAEvB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IAED;;;;OAIG;IACH,IAAI,IAAI,IAGQ,SAAS,EAAE,CAD1B;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAE1B;IAED,0CAA0C;IAC1C,IAAI,KAAK,sBAER;IAED,mFAAmF;IACnF,KAAK,SAAqB;IAE1B;;OAEG;IACH,IAAI,OAAO,YAEV;gBAEW,OAAO,GAAE,iBAAsB;IAY3C;;OAEG;IACH,IAAI,aASF;IAEF;;OAEG;IACH,QAAQ,WAAkB,MAAM,YAAY,cAAc,wCAClB;IAExC,uFAAuF;IACvF,YAAY,WAAkB;QAAE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,mBAK3D;CAmCH"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { generateId, callCompletionApi, } from '@ai-sdk/ui-utils';
|
|
2
|
+
import { KeyedCompletionStore, getCompletionContext, hasCompletionContext, } from './completion-context.svelte.js';
|
|
3
|
+
export class Completion {
|
|
4
|
+
#options = {};
|
|
5
|
+
#api = $derived(this.#options.api ?? '/api/completion');
|
|
6
|
+
#id = $derived(this.#options.id ?? generateId());
|
|
7
|
+
#streamProtocol = $derived(this.#options.streamProtocol ?? 'data');
|
|
8
|
+
#keyedStore = $state();
|
|
9
|
+
#store = $derived(this.#keyedStore.get(this.#id));
|
|
10
|
+
#abortController;
|
|
11
|
+
/** The current completion result */
|
|
12
|
+
get completion() {
|
|
13
|
+
return this.#store.completions.get(this.#id) ?? '';
|
|
14
|
+
}
|
|
15
|
+
set completion(value) {
|
|
16
|
+
this.#store.completions.set(this.#id, value);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Additional data added on the server via StreamData.
|
|
20
|
+
*
|
|
21
|
+
* This is writable, so you can use it to transform or clear the chat data.
|
|
22
|
+
*/
|
|
23
|
+
get data() {
|
|
24
|
+
return this.#store.data;
|
|
25
|
+
}
|
|
26
|
+
set data(value) {
|
|
27
|
+
this.#store.data = value;
|
|
28
|
+
}
|
|
29
|
+
/** The error object of the API request */
|
|
30
|
+
get error() {
|
|
31
|
+
return this.#store.error;
|
|
32
|
+
}
|
|
33
|
+
/** The current value of the input. Writable, so it can be bound to form inputs. */
|
|
34
|
+
input = $state();
|
|
35
|
+
/**
|
|
36
|
+
* Flag that indicates whether an API request is in progress.
|
|
37
|
+
*/
|
|
38
|
+
get loading() {
|
|
39
|
+
return this.#store.loading;
|
|
40
|
+
}
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
if (hasCompletionContext()) {
|
|
43
|
+
this.#keyedStore = getCompletionContext();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.#keyedStore = new KeyedCompletionStore();
|
|
47
|
+
}
|
|
48
|
+
this.#options = options;
|
|
49
|
+
this.completion = options.initialCompletion ?? '';
|
|
50
|
+
this.input = options.initialInput ?? '';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Abort the current request immediately, keep the generated tokens if any.
|
|
54
|
+
*/
|
|
55
|
+
stop = () => {
|
|
56
|
+
try {
|
|
57
|
+
this.#abortController?.abort();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// ignore
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
this.#store.loading = false;
|
|
64
|
+
this.#abortController = undefined;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Send a new prompt to the API endpoint and update the completion state.
|
|
69
|
+
*/
|
|
70
|
+
complete = async (prompt, options) => this.#triggerRequest(prompt, options);
|
|
71
|
+
/** Form submission handler to automatically reset input and call the completion API */
|
|
72
|
+
handleSubmit = async (event) => {
|
|
73
|
+
event?.preventDefault?.();
|
|
74
|
+
if (this.input) {
|
|
75
|
+
await this.complete(this.input);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
#triggerRequest = async (prompt, options) => {
|
|
79
|
+
return callCompletionApi({
|
|
80
|
+
api: this.#api,
|
|
81
|
+
prompt,
|
|
82
|
+
credentials: this.#options.credentials,
|
|
83
|
+
headers: { ...this.#options.headers, ...options?.headers },
|
|
84
|
+
body: {
|
|
85
|
+
...this.#options.body,
|
|
86
|
+
...options?.body,
|
|
87
|
+
},
|
|
88
|
+
streamProtocol: this.#streamProtocol,
|
|
89
|
+
fetch: this.#options.fetch,
|
|
90
|
+
// throttle streamed ui updates:
|
|
91
|
+
setCompletion: completion => {
|
|
92
|
+
this.completion = completion;
|
|
93
|
+
},
|
|
94
|
+
onData: data => {
|
|
95
|
+
this.data.push(...data);
|
|
96
|
+
},
|
|
97
|
+
setLoading: loading => {
|
|
98
|
+
this.#store.loading = loading;
|
|
99
|
+
},
|
|
100
|
+
setError: error => {
|
|
101
|
+
this.#store.error = error;
|
|
102
|
+
},
|
|
103
|
+
setAbortController: abortController => {
|
|
104
|
+
this.#abortController = abortController ?? undefined;
|
|
105
|
+
},
|
|
106
|
+
onResponse: this.#options.onResponse,
|
|
107
|
+
onFinish: this.#options.onFinish,
|
|
108
|
+
onError: this.#options.onError,
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-provider.d.ts","sourceRoot":"","sources":["../src/context-provider.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe,SAS9B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { KeyedChatStore, setChatContext } from './chat-context.svelte.js';
|
|
2
|
+
import { KeyedCompletionStore, setCompletionContext, } from './completion-context.svelte.js';
|
|
3
|
+
import { KeyedStructuredObjectStore, setStructuredObjectContext, } from './structured-object-context.svelte.js';
|
|
4
|
+
export function createAIContext() {
|
|
5
|
+
const chatStore = new KeyedChatStore();
|
|
6
|
+
setChatContext(chatStore);
|
|
7
|
+
const completionStore = new KeyedCompletionStore();
|
|
8
|
+
setCompletionContext(completionStore);
|
|
9
|
+
const objectStore = new KeyedStructuredObjectStore();
|
|
10
|
+
setStructuredObjectContext(objectStore);
|
|
11
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Chat, type ChatOptions, type CreateMessage, type Message, type UIMessage, } from './chat.svelte.js';
|
|
2
|
+
export { StructuredObject as Experimental_StructuredObject, type Experimental_StructuredObjectOptions, } from './structured-object.svelte.js';
|
|
3
|
+
export { Completion, type CompletionOptions } from './completion.svelte.js';
|
|
4
|
+
export { createAIContext } from './context-provider.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,gBAAgB,IAAI,6BAA6B,EACjD,KAAK,oCAAoC,GAC1C,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DeepPartial } from '@ai-sdk/ui-utils';
|
|
2
|
+
import { KeyedStore } from './utils.svelte.js';
|
|
3
|
+
export declare class StructuredObjectStore<RESULT> {
|
|
4
|
+
object: DeepPartial<RESULT> | undefined;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
error: Error | undefined;
|
|
7
|
+
}
|
|
8
|
+
export declare class KeyedStructuredObjectStore extends KeyedStore<StructuredObjectStore<unknown>> {
|
|
9
|
+
constructor(value?: Iterable<readonly [string, StructuredObjectStore<unknown>]> | null | undefined);
|
|
10
|
+
}
|
|
11
|
+
export declare const hasStructuredObjectContext: () => boolean, getStructuredObjectContext: () => KeyedStructuredObjectStore, setStructuredObjectContext: (value: KeyedStructuredObjectStore) => KeyedStructuredObjectStore;
|
|
12
|
+
//# sourceMappingURL=structured-object-context.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-object-context.svelte.d.ts","sourceRoot":"","sources":["../src/structured-object-context.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAiB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9D,qBAAa,qBAAqB,CAAC,MAAM;IACvC,MAAM,kCAAiC;IACvC,OAAO,UAAiB;IACxB,KAAK,oBAAmB;CACzB;AAED,qBAAa,0BAA2B,SAAQ,UAAU,CACxD,qBAAqB,CAAC,OAAO,CAAC,CAC/B;gBAEG,KAAK,CAAC,EACF,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,GAC3D,IAAI,GACJ,SAAS;CAIhB;AAED,eAAO,MACO,0BAA0B,iBAC1B,0BAA0B,oCAC1B,0BAA0B,mEACyB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createContext, KeyedStore } from './utils.svelte.js';
|
|
2
|
+
export class StructuredObjectStore {
|
|
3
|
+
object = $state();
|
|
4
|
+
loading = $state(false);
|
|
5
|
+
error = $state();
|
|
6
|
+
}
|
|
7
|
+
export class KeyedStructuredObjectStore extends KeyedStore {
|
|
8
|
+
constructor(value) {
|
|
9
|
+
super(StructuredObjectStore, value);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export const { hasContext: hasStructuredObjectContext, getContext: getStructuredObjectContext, setContext: setStructuredObjectContext, } = createContext('StructuredObject');
|