dopus 0.2.9 → 0.2.10
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/README.md +22 -14
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +16 -5
- package/dist/index.js +10 -5
- package/dist/{version-NYbd20Zw.js → version-CWmiLdVn.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -256,27 +256,35 @@ export function Agent({ userId, ...props }: AgentChatProps & { userId: string })
|
|
|
256
256
|
}
|
|
257
257
|
```
|
|
258
258
|
|
|
259
|
-
In your database: save on the server, where you know the user, and load from the client.
|
|
259
|
+
In your database: save on the server, where you know the user, and load from the client. `onFinish` gives you who
|
|
260
|
+
(`user`, from `identify`), which conversation (`conversationId`) and what this request added (`newMessages`: the user's
|
|
261
|
+
message and the agent's reply, with tool calls and results inside).
|
|
260
262
|
|
|
261
263
|
```ts
|
|
262
|
-
// agent.config.ts
|
|
263
|
-
onFinish: async ({ user,
|
|
264
|
-
if (user)
|
|
264
|
+
// agent.config.ts (needs `identify`, so `user` is set)
|
|
265
|
+
onFinish: async ({ user, conversationId, newMessages }) => {
|
|
266
|
+
if (!user) return
|
|
267
|
+
for (const message of newMessages) {
|
|
268
|
+
// Upsert by id: after an approval the reply arrives again, continued. Key by user too, since
|
|
269
|
+
// conversationId comes from the browser.
|
|
270
|
+
await db.chatMessage.upsert({ id: message.id, userId: user.id, conversationId, message })
|
|
271
|
+
}
|
|
265
272
|
},
|
|
266
273
|
```
|
|
267
274
|
|
|
268
275
|
```tsx
|
|
269
|
-
// components/agent/agent.tsx: loadChat is your server action returning the
|
|
270
|
-
;<AgentWidget
|
|
271
|
-
history={{
|
|
272
|
-
load: () => loadChat(),
|
|
273
|
-
save: (m) => {
|
|
274
|
-
if (m.length === 0) clearChat()
|
|
275
|
-
},
|
|
276
|
-
}}
|
|
277
|
-
/>
|
|
276
|
+
// components/agent/agent.tsx: loadChat is your server action returning the latest conversation's messages
|
|
277
|
+
;<AgentWidget history={{ load: () => loadChat() }} />
|
|
278
278
|
```
|
|
279
279
|
|
|
280
|
+
- **`conversationId`** is the id of the conversation's first message: the same after a reload (when `history.load`
|
|
281
|
+
restores it), new after "New chat". A list of past conversations is yours to build from it.
|
|
282
|
+
- **`newMessages`** rather than the whole history: the browser sends the whole conversation with every request, so
|
|
283
|
+
saving only what this request added keeps earlier stored messages out of its reach. `messages` (the whole
|
|
284
|
+
conversation) is there too if one snapshot per conversation is enough.
|
|
285
|
+
- **Stopped or failed turns** do not reach `onFinish`. To keep the user's message anyway, save it in `beforeRequest`
|
|
286
|
+
(it gets `user` and `messages`).
|
|
287
|
+
|
|
280
288
|
Things to know:
|
|
281
289
|
|
|
282
290
|
- **Tool results are stored too.** Whatever your tools returned (orders, names) is in the saved conversation. Keep it
|
|
@@ -340,7 +348,7 @@ defineAgent({
|
|
|
340
348
|
},
|
|
341
349
|
|
|
342
350
|
// Once per request, when the reply is done: tokens summed over all steps.
|
|
343
|
-
// also gets
|
|
351
|
+
// also gets conversationId, newMessages and messages, to save the chat (see "Chat history")
|
|
344
352
|
onFinish: async ({ user, model, usage, steps, finishReason, durationMs }) => {
|
|
345
353
|
await db.usage.insert({ userId: user?.id, model: model.modelId, ...usage })
|
|
346
354
|
},
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as PROVIDERS, t as VERSION } from "./version-
|
|
2
|
+
import { n as PROVIDERS, t as VERSION } from "./version-CWmiLdVn.js";
|
|
3
3
|
import { execFileSync, spawn } from "node:child_process";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
import * as p from "@clack/prompts";
|
package/dist/index.d.ts
CHANGED
|
@@ -112,8 +112,8 @@ interface AgentConfig<TOOLS extends DopusToolSet = DopusToolSet> {
|
|
|
112
112
|
/** Called once per tool call: ran (`success` / `error`) or declined by the user (`denied`). For audit logs. */
|
|
113
113
|
onToolCall?: (event: ToolCallEvent) => void | Promise<void>;
|
|
114
114
|
/**
|
|
115
|
-
* Called once per request when the reply is finished: tokens, steps, model (usage tracking), and the
|
|
116
|
-
*
|
|
115
|
+
* Called once per request when the reply is finished: tokens, steps, model (usage tracking), and the conversation
|
|
116
|
+
* (to save chat history in your database: `user`, `conversationId`, `newMessages`).
|
|
117
117
|
*/
|
|
118
118
|
onFinish?: (event: FinishEvent) => void | Promise<void>;
|
|
119
119
|
/** Maximum model steps (tool round trips) per request. Default 10. */
|
|
@@ -173,8 +173,19 @@ interface FinishEvent {
|
|
|
173
173
|
finishReason: string;
|
|
174
174
|
durationMs: number;
|
|
175
175
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
176
|
+
* Which conversation this is: the id of its first message. The same across reloads (when the chat UI restores
|
|
177
|
+
* its `history`), new after "New chat". Sent by the browser, so store it under `user`, never on its own.
|
|
178
|
+
*/
|
|
179
|
+
conversationId: string;
|
|
180
|
+
/**
|
|
181
|
+
* What this request added or changed: the user's message (when the request started with one) and the
|
|
182
|
+
* assistant's reply. After an approval the reply is the same message, continued, so upsert by `id`.
|
|
183
|
+
* Saving only these keeps earlier stored messages out of the browser's reach.
|
|
184
|
+
*/
|
|
185
|
+
newMessages: UIMessage[];
|
|
186
|
+
/**
|
|
187
|
+
* The whole conversation after this reply, as the chat UI holds it. Handy to store one snapshot per
|
|
188
|
+
* conversation; it comes from the browser, so it can differ from what you stored earlier.
|
|
178
189
|
*/
|
|
179
190
|
messages: UIMessage[];
|
|
180
191
|
}
|
|
@@ -224,5 +235,5 @@ interface ProviderInfo {
|
|
|
224
235
|
}
|
|
225
236
|
/** Verified against @ai-sdk/openai@4.0.111, @ai-sdk/anthropic@4.0.99, @ai-sdk/google@4.0.114. */
|
|
226
237
|
export declare const PROVIDERS: Record<ProviderId, ProviderInfo>;
|
|
227
|
-
export declare const VERSION = "0.2.
|
|
238
|
+
export declare const VERSION = "0.2.10";
|
|
228
239
|
export type { AgentConfig, AgentUser, ClientContext, ConfirmOption, DopusTool, DopusToolSet, FinishEvent, HandlerOptions, PromptLayers, ProviderId, ProviderInfo, RuntimeContext, ToolCallEvent, ToolContext, ToolOptions };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as PROVIDERS, t as VERSION } from "./version-
|
|
1
|
+
import { n as PROVIDERS, t as VERSION } from "./version-CWmiLdVn.js";
|
|
2
2
|
import { convertToModelMessages, createUIMessageStreamResponse, getToolName, isStepCount, isToolUIPart, safeValidateUIMessages, streamText, toUIMessageStream, tool } from "ai";
|
|
3
3
|
// src/job.ts
|
|
4
4
|
/**
|
|
@@ -379,11 +379,11 @@ function createAgentHandler(config, options = {}) {
|
|
|
379
379
|
};
|
|
380
380
|
const approvalSecret = config.approvalSecret ?? process.env.DOPUS_APPROVAL_SECRET;
|
|
381
381
|
const finish = { async emit() {
|
|
382
|
-
if (this.done || !this.usage || !this.
|
|
382
|
+
if (this.done || !this.usage || !this.conversation) return;
|
|
383
383
|
this.done = true;
|
|
384
384
|
await runHook(config.onFinish, {
|
|
385
385
|
...this.usage,
|
|
386
|
-
|
|
386
|
+
...this.conversation
|
|
387
387
|
}, report);
|
|
388
388
|
} };
|
|
389
389
|
const result = streamText({
|
|
@@ -441,9 +441,14 @@ function createAgentHandler(config, options = {}) {
|
|
|
441
441
|
stream: result.stream,
|
|
442
442
|
tools,
|
|
443
443
|
originalMessages: messages,
|
|
444
|
-
onEnd: async ({ messages: final, isAborted }) => {
|
|
444
|
+
onEnd: async ({ messages: final, responseMessage, isAborted }) => {
|
|
445
445
|
if (isAborted) return;
|
|
446
|
-
|
|
446
|
+
const last = messages.at(-1);
|
|
447
|
+
finish.conversation = {
|
|
448
|
+
conversationId: messages[0]?.id ?? responseMessage.id,
|
|
449
|
+
newMessages: last?.role === "user" ? [last, responseMessage] : [responseMessage],
|
|
450
|
+
messages: final
|
|
451
|
+
};
|
|
447
452
|
await finish.emit();
|
|
448
453
|
},
|
|
449
454
|
onError: (error) => {
|
package/package.json
CHANGED