@adonis-agora/agent 0.51.0 → 0.52.0

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +25 -10
  3. package/dist/providers/agent_provider.d.ts.map +1 -1
  4. package/dist/providers/agent_provider.js +53 -1
  5. package/dist/providers/agent_provider.js.map +1 -1
  6. package/dist/src/agent-service.d.ts +30 -0
  7. package/dist/src/agent-service.d.ts.map +1 -1
  8. package/dist/src/agent-service.js +67 -0
  9. package/dist/src/agent-service.js.map +1 -1
  10. package/dist/src/index.d.ts +1 -1
  11. package/dist/src/index.js +1 -1
  12. package/dist/src/react/csrf.d.ts +16 -0
  13. package/dist/src/react/csrf.d.ts.map +1 -0
  14. package/dist/src/react/csrf.js +50 -0
  15. package/dist/src/react/csrf.js.map +1 -0
  16. package/dist/src/react/genui/index.d.ts +8 -0
  17. package/dist/src/react/genui/index.d.ts.map +1 -0
  18. package/dist/src/react/genui/index.js +8 -0
  19. package/dist/src/react/genui/index.js.map +1 -0
  20. package/dist/src/react/genui/json-render.d.ts +6 -0
  21. package/dist/src/react/genui/json-render.d.ts.map +1 -0
  22. package/dist/src/react/genui/json-render.js +6 -0
  23. package/dist/src/react/genui/json-render.js.map +1 -0
  24. package/dist/src/react/index.d.ts +42 -1
  25. package/dist/src/react/index.d.ts.map +1 -1
  26. package/dist/src/react/index.js +60 -1
  27. package/dist/src/react/index.js.map +1 -1
  28. package/dist/src/react/markdown.d.ts +7 -0
  29. package/dist/src/react/markdown.d.ts.map +1 -0
  30. package/dist/src/react/markdown.js +7 -0
  31. package/dist/src/react/markdown.js.map +1 -0
  32. package/dist/src/spi/agent-store.d.ts +6 -0
  33. package/dist/src/spi/agent-store.d.ts.map +1 -1
  34. package/dist/src/spi/agent-store.js.map +1 -1
  35. package/dist/src/spi/chat-queue.d.ts +5 -0
  36. package/dist/src/spi/chat-queue.d.ts.map +1 -1
  37. package/dist/src/spi/chat-queue.js.map +1 -1
  38. package/dist/src/stores/lucid-schema.d.ts.map +1 -1
  39. package/dist/src/stores/lucid-schema.js +3 -1
  40. package/dist/src/stores/lucid-schema.js.map +1 -1
  41. package/dist/src/stores/lucid.d.ts +1 -0
  42. package/dist/src/stores/lucid.d.ts.map +1 -1
  43. package/dist/src/stores/lucid.js +10 -0
  44. package/dist/src/stores/lucid.js.map +1 -1
  45. package/dist/src/testing/chat-queue-store-contract.d.ts.map +1 -1
  46. package/dist/src/testing/chat-queue-store-contract.js +23 -0
  47. package/dist/src/testing/chat-queue-store-contract.js.map +1 -1
  48. package/dist/src/testing/in-memory-store.d.ts +1 -0
  49. package/dist/src/testing/in-memory-store.d.ts.map +1 -1
  50. package/dist/src/testing/in-memory-store.js +13 -0
  51. package/dist/src/testing/in-memory-store.js.map +1 -1
  52. package/package.json +28 -2
  53. package/skills/agent-setup/SKILL.md +43 -0
  54. package/dist/src/react/use-agent-chat.d.ts +0 -33
  55. package/dist/src/react/use-agent-chat.d.ts.map +0 -1
  56. package/dist/src/react/use-agent-chat.js +0 -117
  57. package/dist/src/react/use-agent-chat.js.map +0 -1
@@ -19,6 +19,8 @@ sources:
19
19
  - "DavideCarvalho/adonis-agent:packages/adonis/docs/config-reference.mdx"
20
20
  - "DavideCarvalho/adonis-agent:packages/adonis/src/define_config.ts"
21
21
  - "DavideCarvalho/adonis-agent:packages/adonis/src/stores/factory.ts"
22
+ - "DavideCarvalho/adonis-agent:packages/adonis/docs/react.mdx"
23
+ - "DavideCarvalho/adonis-agent:packages/adonis/src/react/index.ts"
22
24
  ---
23
25
 
24
26
  # Setting up @adonis-agora/agent
@@ -181,8 +183,49 @@ bring-your-own `RedisStreamClient`). Pair with `durable: true` for cross-instanc
181
183
  Source: `packages/adonis/src/stores/factory.ts` (`tokenSinks`),
182
184
  `packages/adonis/docs/streaming-and-http.mdx` ("Single-replica by default" callout).
183
185
 
186
+ ### Pattern 4 — a React chat with `@adonis-agora/agent/react`
187
+
188
+ The React layer is `@dudousxd/nestjs-agent-react` re-exported (an optional peer — install it with
189
+ `@ai-sdk/react` and `ai`), plus an `AgentProvider` that already sends the session cookie and
190
+ shield's CSRF token. No controller, no fetch code:
191
+
192
+ ```tsx
193
+ import { AgentProvider, useAgentChat } from '@adonis-agora/agent/react'
194
+
195
+ export default function ChatPage() {
196
+ return (
197
+ <AgentProvider>
198
+ <Chat />
199
+ </AgentProvider>
200
+ )
201
+ }
202
+
203
+ function Chat() {
204
+ const { transcript, composer, queue } = useAgentChat({ threadId, agent: 'support' })
205
+ // transcript.items[].blocks — text / tools (approvals) / elicitation / ui
206
+ // queue.items — messages sent while a turn was running, waiting server-side
207
+ // composer.text / setText / submit() / canSend / files
208
+ }
209
+ ```
210
+
211
+ `useAgentChat({ threadId })` loads the thread and re-attaches to a turn still streaming on it. A send
212
+ made mid-turn is queued (`whileRunning: 'block'` to refuse instead). `path` on the provider must
213
+ match `config/agent.ts`'s `path`.
214
+
184
215
  ## Common mistakes
185
216
 
217
+ ### HIGH — calling `useAgentChat()` outside `<AgentProvider>`
218
+
219
+ ```tsx
220
+ // Wrong — falls back to a bare client with no CSRF header: shield answers every POST with 403.
221
+ function Chat() { const chat = useAgentChat() } // no provider above
222
+
223
+ // Correct — the provider reads XSRF-TOKEN (or <meta name="csrf-token">) per request.
224
+ <AgentProvider><Chat /></AgentProvider>
225
+ ```
226
+
227
+ Outside React, `createAgentClient()` from the same entry builds the client with the same defaults.
228
+
186
229
  ### HIGH — omitting `actorResolver` in an app that has logins
187
230
 
188
231
  ```ts
@@ -1,33 +0,0 @@
1
- import { type AgentChatClientOptions, type AgentChatRequestBody, type ChatPart } from '../client/index.js';
2
- /** A message in the chat transcript — the user's text, or the assistant's streamed parts. */
3
- export interface AgentChatMessage {
4
- id: string;
5
- role: 'user' | 'assistant';
6
- parts: ChatPart[];
7
- /** `true` while this assistant message is still receiving stream frames. */
8
- streaming?: boolean;
9
- }
10
- export type AgentChatStatus = 'idle' | 'streaming' | 'error';
11
- export interface UseAgentChatOptions extends AgentChatClientOptions {
12
- /**
13
- * Builds the request body for a typed message. Defaults to `{ message }`. Override to attach
14
- * `pageContext`, `agent`, `persona`, etc. The `threadId` is injected by the hook after the first
15
- * turn, so a custom `buildBody` should NOT set it.
16
- */
17
- buildBody?: (message: string) => AgentChatRequestBody;
18
- }
19
- export interface UseAgentChatResult {
20
- messages: AgentChatMessage[];
21
- status: AgentChatStatus;
22
- error: string | null;
23
- send: (text: string) => Promise<void>;
24
- cancel: () => void;
25
- }
26
- /**
27
- * React binding over {@link createAgentChatClient}: owns the transcript, thread id, and streaming
28
- * status, and drives one `AbortController` per turn. Reconnection (re-attach on a dropped stream) is
29
- * handled by the client — the hook just renders whatever parts it reports. Pass client options
30
- * (`basePath`, `fetch`, `getHeaders`, `resume`) straight through.
31
- */
32
- export declare function useAgentChat(options?: UseAgentChatOptions): UseAgentChatResult;
33
- //# sourceMappingURL=use-agent-chat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-agent-chat.d.ts","sourceRoot":"","sources":["../../../src/react/use-agent-chat.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,sBAAsB,EAE3B,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EAEd,MAAM,oBAAoB,CAAC;AAE5B,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,mBAAoB,SAAQ,sBAAsB;IACjE;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,oBAAoB,CAAC;CACvD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAQD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,kBAAkB,CA6HlF"}
@@ -1,117 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
- import { AgentChatDisconnectedError, createAgentChatClient, } from '../client/index.js';
3
- function randomId() {
4
- return (globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`);
5
- }
6
- /**
7
- * React binding over {@link createAgentChatClient}: owns the transcript, thread id, and streaming
8
- * status, and drives one `AbortController` per turn. Reconnection (re-attach on a dropped stream) is
9
- * handled by the client — the hook just renders whatever parts it reports. Pass client options
10
- * (`basePath`, `fetch`, `getHeaders`, `resume`) straight through.
11
- */
12
- export function useAgentChat(options = {}) {
13
- const { buildBody, ...clientOptions } = options;
14
- const [messages, setMessages] = useState([]);
15
- const [status, setStatus] = useState('idle');
16
- const [error, setError] = useState(null);
17
- const threadIdRef = useRef(undefined);
18
- const abortRef = useRef(null);
19
- const streamingIdRef = useRef(null);
20
- // Keep one client instance stable across renders; the latest options ride on a ref so option
21
- // changes take effect on the next send without re-creating the client.
22
- const optionsRef = useRef(clientOptions);
23
- optionsRef.current = clientOptions;
24
- const buildBodyRef = useRef(buildBody);
25
- buildBodyRef.current = buildBody;
26
- const clientRef = useRef(createAgentChatClient({
27
- ...clientOptions,
28
- getHeaders: () => optionsRef.current.getHeaders?.() ?? {},
29
- }));
30
- useEffect(() => {
31
- return () => {
32
- abortRef.current?.abort();
33
- };
34
- }, []);
35
- const send = useCallback(async (text) => {
36
- const trimmed = text.trim();
37
- if (!trimmed || streamingIdRef.current) {
38
- return;
39
- }
40
- setError(null);
41
- const userMessage = {
42
- id: randomId(),
43
- role: 'user',
44
- parts: [{ type: 'text', text: trimmed }],
45
- };
46
- const assistantId = randomId();
47
- setMessages((prev) => [
48
- ...prev,
49
- userMessage,
50
- { id: assistantId, role: 'assistant', parts: [], streaming: true },
51
- ]);
52
- setStatus('streaming');
53
- const controller = new AbortController();
54
- abortRef.current = controller;
55
- streamingIdRef.current = assistantId;
56
- const applyParts = (parts) => setMessages((prev) => prev.map((message) => (message.id === assistantId ? { ...message, parts } : message)));
57
- const stopStreaming = () => setMessages((prev) => prev.map((message) => message.id === assistantId ? { ...message, streaming: false } : message));
58
- const body = {
59
- ...(buildBodyRef.current?.(trimmed) ?? { message: trimmed }),
60
- ...(threadIdRef.current ? { threadId: threadIdRef.current } : {}),
61
- };
62
- try {
63
- const result = await clientRef.current.send({
64
- body,
65
- signal: controller.signal,
66
- onParts: applyParts,
67
- onThreadId: (id) => {
68
- threadIdRef.current = id;
69
- },
70
- });
71
- if (result.queued !== undefined) {
72
- // Another turn holds the thread (another tab, another device): the server queued the
73
- // message. If it started at once, follow its run; otherwise there is no answer to show yet
74
- // — it arrives when the turn ahead settles (a reload of the thread shows it).
75
- if (result.queued.runId !== undefined) {
76
- await clientRef.current.resume(result.queued.runId, {
77
- signal: controller.signal,
78
- onParts: applyParts,
79
- });
80
- }
81
- else {
82
- setMessages((prev) => prev.filter((message) => message.id !== assistantId));
83
- }
84
- }
85
- stopStreaming();
86
- setStatus('idle');
87
- }
88
- catch (caught) {
89
- if (controller.signal.aborted) {
90
- return;
91
- }
92
- // Keep whatever streamed before the drop so the user doesn't lose a long answer.
93
- if (caught instanceof AgentChatDisconnectedError && caught.parts.length > 0) {
94
- applyParts(caught.parts);
95
- }
96
- stopStreaming();
97
- setError(caught instanceof Error ? caught.message : 'Failed to reach the agent.');
98
- setStatus('error');
99
- }
100
- finally {
101
- abortRef.current = null;
102
- streamingIdRef.current = null;
103
- }
104
- }, []);
105
- const cancel = useCallback(() => {
106
- abortRef.current?.abort();
107
- abortRef.current = null;
108
- const streamingId = streamingIdRef.current;
109
- if (streamingId) {
110
- setMessages((prev) => prev.map((message) => message.id === streamingId ? { ...message, streaming: false } : message));
111
- streamingIdRef.current = null;
112
- }
113
- setStatus('idle');
114
- }, []);
115
- return { messages, status, error, send, cancel };
116
- }
117
- //# sourceMappingURL=use-agent-chat.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-agent-chat.js","sourceRoot":"","sources":["../../../src/react/use-agent-chat.ts"],"names":[],"mappings":"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"}