@cloudflare/ai-chat 0.0.1 → 0.0.4
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 +37 -0
- package/README.md +570 -0
- package/dist/ai-chat-v5-migration.d.ts +155 -0
- package/dist/ai-chat-v5-migration.js +155 -0
- package/dist/ai-chat-v5-migration.js.map +1 -0
- package/dist/index.d.ts +330 -0
- package/dist/index.js +1170 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +282 -0
- package/dist/react.js +637 -0
- package/dist/react.js.map +1 -0
- package/dist/types.d.ts +123 -0
- package/dist/types.js +24 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -9
- package/scripts/build.ts +31 -0
- package/src/ai-chat-v5-migration.ts +376 -0
- package/src/index.ts +2094 -0
- package/src/react-tests/use-agent-chat.test.tsx +612 -0
- package/src/react-tests/vitest.config.ts +17 -0
- package/src/react.tsx +1407 -0
- package/src/tests/chat-context.test.ts +84 -0
- package/src/tests/chat-persistence.test.ts +425 -0
- package/src/tests/client-tool-duplicate-message.test.ts +543 -0
- package/src/tests/client-tools-broadcast.test.ts +138 -0
- package/src/tests/cloudflare-test.d.ts +5 -0
- package/src/tests/non-sse-response.test.ts +186 -0
- package/src/tests/resumable-streaming.test.ts +501 -0
- package/src/tests/test-utils.ts +39 -0
- package/src/tests/tsconfig.json +10 -0
- package/src/tests/vitest.config.ts +28 -0
- package/src/tests/worker.ts +258 -0
- package/src/tests/wrangler.jsonc +26 -0
- package/src/types.ts +122 -0
- package/tsconfig.json +4 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createExecutionContext, env } from "cloudflare:test";
|
|
2
|
+
import { expect } from "vitest";
|
|
3
|
+
import { MessageType, type OutgoingMessage } from "../types";
|
|
4
|
+
import worker from "./worker";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Connects to the chat agent and returns the WebSocket and execution context
|
|
8
|
+
*/
|
|
9
|
+
export async function connectChatWS(
|
|
10
|
+
path: string
|
|
11
|
+
): Promise<{ ws: WebSocket; ctx: ExecutionContext }> {
|
|
12
|
+
const ctx = createExecutionContext();
|
|
13
|
+
const req = new Request(`http://example.com${path}`, {
|
|
14
|
+
headers: { Upgrade: "websocket" }
|
|
15
|
+
});
|
|
16
|
+
const res = await worker.fetch(req, env, ctx);
|
|
17
|
+
expect(res.status).toBe(101);
|
|
18
|
+
const ws = res.webSocket as WebSocket;
|
|
19
|
+
expect(ws).toBeDefined();
|
|
20
|
+
ws.accept();
|
|
21
|
+
return { ws, ctx };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Type guard for CF_AGENT_USE_CHAT_RESPONSE messages
|
|
26
|
+
*/
|
|
27
|
+
export function isUseChatResponseMessage(
|
|
28
|
+
m: unknown
|
|
29
|
+
): m is Extract<
|
|
30
|
+
OutgoingMessage,
|
|
31
|
+
{ type: MessageType.CF_AGENT_USE_CHAT_RESPONSE }
|
|
32
|
+
> {
|
|
33
|
+
return (
|
|
34
|
+
typeof m === "object" &&
|
|
35
|
+
m !== null &&
|
|
36
|
+
"type" in m &&
|
|
37
|
+
m.type === MessageType.CF_AGENT_USE_CHAT_RESPONSE
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
|
|
2
|
+
|
|
3
|
+
export default defineWorkersConfig({
|
|
4
|
+
test: {
|
|
5
|
+
deps: {
|
|
6
|
+
optimizer: {
|
|
7
|
+
ssr: {
|
|
8
|
+
include: [
|
|
9
|
+
// vitest can't seem to properly import
|
|
10
|
+
// `require('./path/to/anything.json')` files,
|
|
11
|
+
// which ajv uses (by way of @modelcontextprotocol/sdk)
|
|
12
|
+
// the workaround is to add the package to the include list
|
|
13
|
+
"ajv"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
poolOptions: {
|
|
19
|
+
workers: {
|
|
20
|
+
isolatedStorage: false,
|
|
21
|
+
singleWorker: true,
|
|
22
|
+
wrangler: {
|
|
23
|
+
configPath: "./wrangler.jsonc"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { AIChatAgent } from "../";
|
|
2
|
+
import type { UIMessage as ChatMessage } from "ai";
|
|
3
|
+
import { callable, getCurrentAgent, routeAgentRequest } from "agents";
|
|
4
|
+
|
|
5
|
+
// Type helper for tool call parts - extracts from ChatMessage parts
|
|
6
|
+
type TestToolCallPart = Extract<
|
|
7
|
+
ChatMessage["parts"][number],
|
|
8
|
+
{ type: `tool-${string}` }
|
|
9
|
+
>;
|
|
10
|
+
|
|
11
|
+
export type Env = {
|
|
12
|
+
TestChatAgent: DurableObjectNamespace<TestChatAgent>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class TestChatAgent extends AIChatAgent<Env> {
|
|
16
|
+
observability = undefined;
|
|
17
|
+
// Store captured context for testing
|
|
18
|
+
private _capturedContext: {
|
|
19
|
+
hasAgent: boolean;
|
|
20
|
+
hasConnection: boolean;
|
|
21
|
+
connectionId: string | undefined;
|
|
22
|
+
} | null = null;
|
|
23
|
+
// Store context captured from nested async function (simulates tool execute)
|
|
24
|
+
private _nestedContext: {
|
|
25
|
+
hasAgent: boolean;
|
|
26
|
+
hasConnection: boolean;
|
|
27
|
+
connectionId: string | undefined;
|
|
28
|
+
} | null = null;
|
|
29
|
+
|
|
30
|
+
async onChatMessage() {
|
|
31
|
+
// Capture getCurrentAgent() context for testing
|
|
32
|
+
const { agent, connection } = getCurrentAgent();
|
|
33
|
+
this._capturedContext = {
|
|
34
|
+
hasAgent: agent !== undefined,
|
|
35
|
+
hasConnection: connection !== undefined,
|
|
36
|
+
connectionId: connection?.id
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Simulate what happens inside a tool's execute function:
|
|
40
|
+
// It's a nested async function called from within onChatMessage
|
|
41
|
+
await this._simulateToolExecute();
|
|
42
|
+
|
|
43
|
+
// Simple echo response for testing
|
|
44
|
+
return new Response("Hello from chat agent!", {
|
|
45
|
+
headers: { "Content-Type": "text/plain" }
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// This simulates an AI SDK tool's execute function being called
|
|
50
|
+
private async _simulateToolExecute(): Promise<void> {
|
|
51
|
+
// Add a small delay to ensure we're in a new microtask (like real tool execution)
|
|
52
|
+
await Promise.resolve();
|
|
53
|
+
|
|
54
|
+
// Capture context inside the "tool execute" function
|
|
55
|
+
const { agent, connection } = getCurrentAgent();
|
|
56
|
+
this._nestedContext = {
|
|
57
|
+
hasAgent: agent !== undefined,
|
|
58
|
+
hasConnection: connection !== undefined,
|
|
59
|
+
connectionId: connection?.id
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@callable()
|
|
64
|
+
getCapturedContext(): {
|
|
65
|
+
hasAgent: boolean;
|
|
66
|
+
hasConnection: boolean;
|
|
67
|
+
connectionId: string | undefined;
|
|
68
|
+
} | null {
|
|
69
|
+
return this._capturedContext;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@callable()
|
|
73
|
+
getNestedContext(): {
|
|
74
|
+
hasAgent: boolean;
|
|
75
|
+
hasConnection: boolean;
|
|
76
|
+
connectionId: string | undefined;
|
|
77
|
+
} | null {
|
|
78
|
+
return this._nestedContext;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@callable()
|
|
82
|
+
clearCapturedContext(): void {
|
|
83
|
+
this._capturedContext = null;
|
|
84
|
+
this._nestedContext = null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@callable()
|
|
88
|
+
getPersistedMessages(): ChatMessage[] {
|
|
89
|
+
const rawMessages = (
|
|
90
|
+
this.sql`select * from cf_ai_chat_agent_messages order by created_at` ||
|
|
91
|
+
[]
|
|
92
|
+
).map((row) => {
|
|
93
|
+
return JSON.parse(row.message as string);
|
|
94
|
+
});
|
|
95
|
+
return rawMessages;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@callable()
|
|
99
|
+
async testPersistToolCall(messageId: string, toolName: string) {
|
|
100
|
+
const toolCallPart: TestToolCallPart = {
|
|
101
|
+
type: `tool-${toolName}`,
|
|
102
|
+
toolCallId: `call_${messageId}`,
|
|
103
|
+
state: "input-available",
|
|
104
|
+
input: { location: "London" }
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const messageWithToolCall: ChatMessage = {
|
|
108
|
+
id: messageId,
|
|
109
|
+
role: "assistant",
|
|
110
|
+
parts: [toolCallPart] as ChatMessage["parts"]
|
|
111
|
+
};
|
|
112
|
+
await this.persistMessages([messageWithToolCall]);
|
|
113
|
+
return messageWithToolCall;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@callable()
|
|
117
|
+
async testPersistToolResult(
|
|
118
|
+
messageId: string,
|
|
119
|
+
toolName: string,
|
|
120
|
+
output: string
|
|
121
|
+
) {
|
|
122
|
+
const toolResultPart: TestToolCallPart = {
|
|
123
|
+
type: `tool-${toolName}`,
|
|
124
|
+
toolCallId: `call_${messageId}`,
|
|
125
|
+
state: "output-available",
|
|
126
|
+
input: { location: "London" },
|
|
127
|
+
output
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const messageWithToolOutput: ChatMessage = {
|
|
131
|
+
id: messageId,
|
|
132
|
+
role: "assistant",
|
|
133
|
+
parts: [toolResultPart] as ChatMessage["parts"]
|
|
134
|
+
};
|
|
135
|
+
await this.persistMessages([messageWithToolOutput]);
|
|
136
|
+
return messageWithToolOutput;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Resumable streaming test helpers
|
|
140
|
+
|
|
141
|
+
@callable()
|
|
142
|
+
testStartStream(requestId: string): string {
|
|
143
|
+
return this._startStream(requestId);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@callable()
|
|
147
|
+
testStoreStreamChunk(streamId: string, body: string): void {
|
|
148
|
+
this._storeStreamChunk(streamId, body);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@callable()
|
|
152
|
+
testFlushChunkBuffer(): void {
|
|
153
|
+
this._flushChunkBuffer();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
@callable()
|
|
157
|
+
testCompleteStream(streamId: string): void {
|
|
158
|
+
this._completeStream(streamId);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@callable()
|
|
162
|
+
testMarkStreamError(streamId: string): void {
|
|
163
|
+
this._markStreamError(streamId);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@callable()
|
|
167
|
+
getActiveStreamId(): string | null {
|
|
168
|
+
return this._activeStreamId;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@callable()
|
|
172
|
+
getActiveRequestId(): string | null {
|
|
173
|
+
return this._activeRequestId;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@callable()
|
|
177
|
+
getStreamChunks(
|
|
178
|
+
streamId: string
|
|
179
|
+
): Array<{ body: string; chunk_index: number }> {
|
|
180
|
+
return (
|
|
181
|
+
this.sql<{ body: string; chunk_index: number }>`
|
|
182
|
+
select body, chunk_index from cf_ai_chat_stream_chunks
|
|
183
|
+
where stream_id = ${streamId}
|
|
184
|
+
order by chunk_index asc
|
|
185
|
+
` || []
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@callable()
|
|
190
|
+
getStreamMetadata(
|
|
191
|
+
streamId: string
|
|
192
|
+
): { status: string; request_id: string } | null {
|
|
193
|
+
const result = this.sql<{ status: string; request_id: string }>`
|
|
194
|
+
select status, request_id from cf_ai_chat_stream_metadata
|
|
195
|
+
where id = ${streamId}
|
|
196
|
+
`;
|
|
197
|
+
return result && result.length > 0 ? result[0] : null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@callable()
|
|
201
|
+
getAllStreamMetadata(): Array<{
|
|
202
|
+
id: string;
|
|
203
|
+
status: string;
|
|
204
|
+
request_id: string;
|
|
205
|
+
created_at: number;
|
|
206
|
+
}> {
|
|
207
|
+
return (
|
|
208
|
+
this.sql<{
|
|
209
|
+
id: string;
|
|
210
|
+
status: string;
|
|
211
|
+
request_id: string;
|
|
212
|
+
created_at: number;
|
|
213
|
+
}>`select id, status, request_id, created_at from cf_ai_chat_stream_metadata` ||
|
|
214
|
+
[]
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@callable()
|
|
219
|
+
testInsertStaleStream(
|
|
220
|
+
streamId: string,
|
|
221
|
+
requestId: string,
|
|
222
|
+
ageMs: number
|
|
223
|
+
): void {
|
|
224
|
+
const createdAt = Date.now() - ageMs;
|
|
225
|
+
this.sql`
|
|
226
|
+
insert into cf_ai_chat_stream_metadata (id, request_id, status, created_at)
|
|
227
|
+
values (${streamId}, ${requestId}, 'streaming', ${createdAt})
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@callable()
|
|
232
|
+
testRestoreActiveStream(): void {
|
|
233
|
+
this._restoreActiveStream();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export default {
|
|
238
|
+
async fetch(request: Request, env: Env, _ctx: ExecutionContext) {
|
|
239
|
+
const url = new URL(request.url);
|
|
240
|
+
|
|
241
|
+
if (url.pathname === "/500") {
|
|
242
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
(await routeAgentRequest(request, env)) ||
|
|
247
|
+
new Response("Not found", { status: 404 })
|
|
248
|
+
);
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
async email(
|
|
252
|
+
_message: ForwardableEmailMessage,
|
|
253
|
+
_env: Env,
|
|
254
|
+
_ctx: ExecutionContext
|
|
255
|
+
) {
|
|
256
|
+
// Bring this in when we write tests for the complete email handler flow
|
|
257
|
+
}
|
|
258
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compatibility_date": "2025-04-17",
|
|
3
|
+
"compatibility_flags": [
|
|
4
|
+
"nodejs_compat",
|
|
5
|
+
// adding these flags since the vitest runner needs them
|
|
6
|
+
"enable_nodejs_tty_module",
|
|
7
|
+
"enable_nodejs_fs_module",
|
|
8
|
+
"enable_nodejs_http_modules",
|
|
9
|
+
"enable_nodejs_perf_hooks_module"
|
|
10
|
+
],
|
|
11
|
+
"durable_objects": {
|
|
12
|
+
"bindings": [
|
|
13
|
+
{
|
|
14
|
+
"class_name": "TestChatAgent",
|
|
15
|
+
"name": "TestChatAgent"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"main": "worker.ts",
|
|
20
|
+
"migrations": [
|
|
21
|
+
{
|
|
22
|
+
"new_sqlite_classes": ["TestChatAgent"],
|
|
23
|
+
"tag": "v1"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { UIMessage } from "ai";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Enum for message types to improve type safety and maintainability
|
|
5
|
+
*/
|
|
6
|
+
export enum MessageType {
|
|
7
|
+
CF_AGENT_CHAT_MESSAGES = "cf_agent_chat_messages",
|
|
8
|
+
CF_AGENT_USE_CHAT_REQUEST = "cf_agent_use_chat_request",
|
|
9
|
+
CF_AGENT_USE_CHAT_RESPONSE = "cf_agent_use_chat_response",
|
|
10
|
+
CF_AGENT_CHAT_CLEAR = "cf_agent_chat_clear",
|
|
11
|
+
CF_AGENT_CHAT_REQUEST_CANCEL = "cf_agent_chat_request_cancel",
|
|
12
|
+
|
|
13
|
+
/** Sent by server when client connects and there's an active stream to resume */
|
|
14
|
+
CF_AGENT_STREAM_RESUMING = "cf_agent_stream_resuming",
|
|
15
|
+
/** Sent by client to acknowledge stream resuming notification and request chunks */
|
|
16
|
+
CF_AGENT_STREAM_RESUME_ACK = "cf_agent_stream_resume_ack",
|
|
17
|
+
|
|
18
|
+
/** Client sends tool result to server (for client-side tools) */
|
|
19
|
+
CF_AGENT_TOOL_RESULT = "cf_agent_tool_result",
|
|
20
|
+
/** Server notifies client that a message was updated (e.g., tool result applied) */
|
|
21
|
+
CF_AGENT_MESSAGE_UPDATED = "cf_agent_message_updated"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Types of messages sent from the Agent to clients
|
|
26
|
+
*/
|
|
27
|
+
export type OutgoingMessage<ChatMessage extends UIMessage = UIMessage> =
|
|
28
|
+
| {
|
|
29
|
+
/** Indicates this message is a command to clear chat history */
|
|
30
|
+
type: MessageType.CF_AGENT_CHAT_CLEAR;
|
|
31
|
+
}
|
|
32
|
+
| {
|
|
33
|
+
/** Indicates this message contains updated chat messages */
|
|
34
|
+
type: MessageType.CF_AGENT_CHAT_MESSAGES;
|
|
35
|
+
/** Array of chat messages */
|
|
36
|
+
messages: ChatMessage[];
|
|
37
|
+
}
|
|
38
|
+
| {
|
|
39
|
+
/** Indicates this message is a response to a chat request */
|
|
40
|
+
type: MessageType.CF_AGENT_USE_CHAT_RESPONSE;
|
|
41
|
+
/** Unique ID of the request this response corresponds to */
|
|
42
|
+
id: string;
|
|
43
|
+
/** Content body of the response */
|
|
44
|
+
body: string;
|
|
45
|
+
/** Whether this is the final chunk of the response */
|
|
46
|
+
done: boolean;
|
|
47
|
+
/** Whether this response contains an error */
|
|
48
|
+
error?: boolean;
|
|
49
|
+
/** Whether this is a continuation (append to last assistant message) */
|
|
50
|
+
continuation?: boolean;
|
|
51
|
+
}
|
|
52
|
+
| {
|
|
53
|
+
/** Indicates the server is resuming an active stream */
|
|
54
|
+
type: MessageType.CF_AGENT_STREAM_RESUMING;
|
|
55
|
+
/** The request ID of the stream being resumed */
|
|
56
|
+
id: string;
|
|
57
|
+
}
|
|
58
|
+
| {
|
|
59
|
+
/** Server notifies client that a message was updated (e.g., tool result applied) */
|
|
60
|
+
type: MessageType.CF_AGENT_MESSAGE_UPDATED;
|
|
61
|
+
/** The updated message */
|
|
62
|
+
message: ChatMessage;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Types of messages sent from clients to the Agent
|
|
67
|
+
*/
|
|
68
|
+
export type IncomingMessage<ChatMessage extends UIMessage = UIMessage> =
|
|
69
|
+
| {
|
|
70
|
+
/** Indicates this message is a command to clear chat history */
|
|
71
|
+
type: MessageType.CF_AGENT_CHAT_CLEAR;
|
|
72
|
+
}
|
|
73
|
+
| {
|
|
74
|
+
/** Indicates this message is a request to the chat API */
|
|
75
|
+
type: MessageType.CF_AGENT_USE_CHAT_REQUEST;
|
|
76
|
+
/** Unique ID for this request */
|
|
77
|
+
id: string;
|
|
78
|
+
/** Request initialization options */
|
|
79
|
+
init: Pick<
|
|
80
|
+
RequestInit,
|
|
81
|
+
| "method"
|
|
82
|
+
| "keepalive"
|
|
83
|
+
| "headers"
|
|
84
|
+
| "body"
|
|
85
|
+
| "redirect"
|
|
86
|
+
| "integrity"
|
|
87
|
+
| "credentials"
|
|
88
|
+
| "mode"
|
|
89
|
+
| "referrer"
|
|
90
|
+
| "referrerPolicy"
|
|
91
|
+
| "window"
|
|
92
|
+
>;
|
|
93
|
+
}
|
|
94
|
+
| {
|
|
95
|
+
/** Indicates this message contains updated chat messages */
|
|
96
|
+
type: MessageType.CF_AGENT_CHAT_MESSAGES;
|
|
97
|
+
/** Array of chat messages */
|
|
98
|
+
messages: ChatMessage[];
|
|
99
|
+
}
|
|
100
|
+
| {
|
|
101
|
+
/** Indicates the user wants to stop generation of this message */
|
|
102
|
+
type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL;
|
|
103
|
+
id: string;
|
|
104
|
+
}
|
|
105
|
+
| {
|
|
106
|
+
/** Client acknowledges stream resuming notification and is ready to receive chunks */
|
|
107
|
+
type: MessageType.CF_AGENT_STREAM_RESUME_ACK;
|
|
108
|
+
/** The request ID of the stream being resumed */
|
|
109
|
+
id: string;
|
|
110
|
+
}
|
|
111
|
+
| {
|
|
112
|
+
/** Client sends tool result to server (for client-side tools) */
|
|
113
|
+
type: MessageType.CF_AGENT_TOOL_RESULT;
|
|
114
|
+
/** The tool call ID this result is for */
|
|
115
|
+
toolCallId: string;
|
|
116
|
+
/** The name of the tool */
|
|
117
|
+
toolName: string;
|
|
118
|
+
/** The output from the tool execution */
|
|
119
|
+
output: unknown;
|
|
120
|
+
/** Whether server should auto-continue the conversation after applying result */
|
|
121
|
+
autoContinue?: boolean;
|
|
122
|
+
};
|
package/tsconfig.json
ADDED