@anvia/core 0.26.0 → 1.0.0-rc.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.
Files changed (184) hide show
  1. package/README.md +400 -94
  2. package/dist/agent/index.d.ts +67 -71
  3. package/dist/agent/index.js +36 -18
  4. package/dist/agent/interactions/index.d.ts +122 -0
  5. package/dist/agent/interactions/index.js +20 -0
  6. package/dist/agent-DWzW9SoH.d.ts +150 -0
  7. package/dist/chunk-3RM57ZT2.js +31 -0
  8. package/dist/chunk-3RM57ZT2.js.map +1 -0
  9. package/dist/chunk-3RWESPUG.js +331 -0
  10. package/dist/chunk-3RWESPUG.js.map +1 -0
  11. package/dist/{chunk-NCPN4SJR.js → chunk-3SKZ2BKP.js} +15 -13
  12. package/dist/chunk-3SKZ2BKP.js.map +1 -0
  13. package/dist/chunk-3XQGVDU5.js +69 -0
  14. package/dist/chunk-3XQGVDU5.js.map +1 -0
  15. package/dist/{chunk-MRQLEK2B.js → chunk-5C6B6ZRH.js} +69 -51
  16. package/dist/chunk-5C6B6ZRH.js.map +1 -0
  17. package/dist/chunk-6BBOCFHV.js +323 -0
  18. package/dist/chunk-6BBOCFHV.js.map +1 -0
  19. package/dist/chunk-7JLAIN6E.js +15 -0
  20. package/dist/chunk-7JLAIN6E.js.map +1 -0
  21. package/dist/chunk-7PHMK7W4.js +1516 -0
  22. package/dist/chunk-7PHMK7W4.js.map +1 -0
  23. package/dist/{chunk-CWUJUSOS.js → chunk-AZB6N7P4.js} +94 -65
  24. package/dist/chunk-AZB6N7P4.js.map +1 -0
  25. package/dist/chunk-D4PACGPA.js +37 -0
  26. package/dist/chunk-D4PACGPA.js.map +1 -0
  27. package/dist/chunk-EFLT7XZD.js +51 -0
  28. package/dist/chunk-EFLT7XZD.js.map +1 -0
  29. package/dist/chunk-EMZKPRE6.js +667 -0
  30. package/dist/chunk-EMZKPRE6.js.map +1 -0
  31. package/dist/chunk-I3Q7XSBB.js +59 -0
  32. package/dist/chunk-I3Q7XSBB.js.map +1 -0
  33. package/dist/chunk-J6LVLV6P.js +13 -0
  34. package/dist/chunk-J6LVLV6P.js.map +1 -0
  35. package/dist/chunk-LTXABCOO.js +127 -0
  36. package/dist/chunk-LTXABCOO.js.map +1 -0
  37. package/dist/chunk-OJBFDBLG.js +164 -0
  38. package/dist/chunk-OJBFDBLG.js.map +1 -0
  39. package/dist/chunk-QGX73TSQ.js +177 -0
  40. package/dist/chunk-QGX73TSQ.js.map +1 -0
  41. package/dist/chunk-QOUPWOGW.js +29 -0
  42. package/dist/chunk-QOUPWOGW.js.map +1 -0
  43. package/dist/chunk-SJMSS5SI.js +171 -0
  44. package/dist/chunk-SJMSS5SI.js.map +1 -0
  45. package/dist/chunk-T2C3CGDQ.js +56 -0
  46. package/dist/chunk-T2C3CGDQ.js.map +1 -0
  47. package/dist/chunk-VX3HS6PE.js +4569 -0
  48. package/dist/chunk-VX3HS6PE.js.map +1 -0
  49. package/dist/chunk-X4LK4ODN.js +86 -0
  50. package/dist/chunk-X4LK4ODN.js.map +1 -0
  51. package/dist/chunk-ZA564323.js +331 -0
  52. package/dist/chunk-ZA564323.js.map +1 -0
  53. package/dist/completion/index.d.ts +6 -36
  54. package/dist/completion/index.js +34 -29
  55. package/dist/documents/index.d.ts +34 -0
  56. package/dist/documents/index.js +340 -0
  57. package/dist/documents/index.js.map +1 -0
  58. package/dist/dynamic-tools-aIZlg5x1.d.ts +45 -0
  59. package/dist/embeddings/index.d.ts +11 -9
  60. package/dist/embeddings/index.js +3 -4
  61. package/dist/evals/index.d.ts +57 -21
  62. package/dist/evals/index.js +209 -104
  63. package/dist/evals/index.js.map +1 -1
  64. package/dist/extractor/index.d.ts +27 -42
  65. package/dist/extractor/index.js +9 -22
  66. package/dist/guardrails/index.d.ts +7 -129
  67. package/dist/guardrails/index.js +1 -1
  68. package/dist/image-generation/index.d.ts +23 -23
  69. package/dist/image-generation/index.js +7 -39
  70. package/dist/image-generation/index.js.map +1 -1
  71. package/dist/index.d.ts +24 -22
  72. package/dist/index.js +85 -68
  73. package/dist/internal/agent.d.ts +156 -10
  74. package/dist/internal/agent.js +58 -18
  75. package/dist/internal/agent.js.map +1 -1
  76. package/dist/mcp/index.d.ts +7 -15
  77. package/dist/mcp/index.js +3 -348
  78. package/dist/mcp/index.js.map +1 -1
  79. package/dist/memory/index.d.ts +20 -6
  80. package/dist/memory/index.js +11 -10
  81. package/dist/middleware-kcF8AusP.d.ts +59 -0
  82. package/dist/model-call-options-CZkSw_xN.d.ts +6 -0
  83. package/dist/model-listing/index.d.ts +3 -1
  84. package/dist/observability/index.d.ts +23 -4
  85. package/dist/observability/index.js +10 -5
  86. package/dist/observability/index.js.map +1 -1
  87. package/dist/pipeline/index.d.ts +111 -73
  88. package/dist/pipeline/index.js +471 -286
  89. package/dist/pipeline/index.js.map +1 -1
  90. package/dist/provider-output-error-BEwDgVv3.d.ts +99 -0
  91. package/dist/retry-CjvSlKGW.d.ts +16 -0
  92. package/dist/skills/index.d.ts +5 -4
  93. package/dist/skills/index.js +8 -8
  94. package/dist/speech-generation/index.d.ts +37 -0
  95. package/dist/speech-generation/index.js +10 -0
  96. package/dist/streaming/index.js +37 -3
  97. package/dist/streaming/index.js.map +1 -1
  98. package/dist/text-ZLECpQE7.d.ts +32 -0
  99. package/dist/think-tool-BwCsJ365.d.ts +40 -0
  100. package/dist/tool/index.d.ts +11 -6
  101. package/dist/tool/index.js +21 -21
  102. package/dist/tool-BpqpoRSE.d.ts +58 -0
  103. package/dist/transcription/index.d.ts +29 -22
  104. package/dist/transcription/index.js +7 -57
  105. package/dist/transcription/index.js.map +1 -1
  106. package/dist/type-utils-CtHVDRn_.d.ts +6 -0
  107. package/dist/types-CXNE592e.d.ts +130 -0
  108. package/dist/types-Cr4uiYo5.d.ts +99 -0
  109. package/dist/{types-04LqWrmy.d.ts → types-DC1U1XwW.d.ts} +1 -1
  110. package/dist/types-DKOXVTcq.d.ts +155 -0
  111. package/dist/types-DgvozfPc.d.ts +349 -0
  112. package/dist/types-DhkodEft.d.ts +105 -0
  113. package/dist/types-DjqRHeAi.d.ts +31 -0
  114. package/dist/types-Sue2hb_L.d.ts +403 -0
  115. package/dist/vector-store/index.d.ts +34 -34
  116. package/dist/vector-store/index.js +10 -6
  117. package/package.json +22 -24
  118. package/dist/agent-x3YTyv5i.d.ts +0 -222
  119. package/dist/audio-generation/index.d.ts +0 -33
  120. package/dist/audio-generation/index.js +0 -42
  121. package/dist/audio-generation/index.js.map +0 -1
  122. package/dist/chunk-2ODTMRHP.js +0 -54
  123. package/dist/chunk-2ODTMRHP.js.map +0 -1
  124. package/dist/chunk-ADH7NNCS.js +0 -512
  125. package/dist/chunk-ADH7NNCS.js.map +0 -1
  126. package/dist/chunk-BALBBVI3.js +0 -2732
  127. package/dist/chunk-BALBBVI3.js.map +0 -1
  128. package/dist/chunk-CQNNSZPG.js +0 -9
  129. package/dist/chunk-CQNNSZPG.js.map +0 -1
  130. package/dist/chunk-CWUJUSOS.js.map +0 -1
  131. package/dist/chunk-DALYP4PX.js +0 -225
  132. package/dist/chunk-DALYP4PX.js.map +0 -1
  133. package/dist/chunk-HYUYZEAJ.js +0 -223
  134. package/dist/chunk-HYUYZEAJ.js.map +0 -1
  135. package/dist/chunk-I6XOQ4LK.js +0 -466
  136. package/dist/chunk-I6XOQ4LK.js.map +0 -1
  137. package/dist/chunk-JI5YZWNT.js +0 -220
  138. package/dist/chunk-JI5YZWNT.js.map +0 -1
  139. package/dist/chunk-MC3CCKEB.js +0 -221
  140. package/dist/chunk-MC3CCKEB.js.map +0 -1
  141. package/dist/chunk-MELYDKWQ.js +0 -337
  142. package/dist/chunk-MELYDKWQ.js.map +0 -1
  143. package/dist/chunk-MNWK2USR.js +0 -243
  144. package/dist/chunk-MNWK2USR.js.map +0 -1
  145. package/dist/chunk-MRQLEK2B.js.map +0 -1
  146. package/dist/chunk-NCPN4SJR.js.map +0 -1
  147. package/dist/chunk-OIMLU4SF.js +0 -20
  148. package/dist/chunk-OIMLU4SF.js.map +0 -1
  149. package/dist/chunk-Q25IWLBT.js +0 -138
  150. package/dist/chunk-Q25IWLBT.js.map +0 -1
  151. package/dist/chunk-UQX6EXWG.js +0 -33
  152. package/dist/chunk-UQX6EXWG.js.map +0 -1
  153. package/dist/chunk-WQKHFADH.js +0 -12
  154. package/dist/chunk-WQKHFADH.js.map +0 -1
  155. package/dist/chunk-XUUY2L2D.js +0 -42
  156. package/dist/chunk-XUUY2L2D.js.map +0 -1
  157. package/dist/chunk-XWUC7CIT.js +0 -1
  158. package/dist/chunk-XWUC7CIT.js.map +0 -1
  159. package/dist/chunk-YLMDBQO4.js +0 -141
  160. package/dist/chunk-YLMDBQO4.js.map +0 -1
  161. package/dist/errors-2moLDuuN.d.ts +0 -17
  162. package/dist/hooks/index.d.ts +0 -12
  163. package/dist/hooks/index.js +0 -17
  164. package/dist/index-BxSbmOMr.d.ts +0 -257
  165. package/dist/json-BVPssigK.d.ts +0 -39
  166. package/dist/loaders/index.d.ts +0 -91
  167. package/dist/loaders/index.js +0 -299
  168. package/dist/loaders/index.js.map +0 -1
  169. package/dist/middleware-Dp3d_pxi.d.ts +0 -90
  170. package/dist/request/index.d.ts +0 -28
  171. package/dist/request/index.js +0 -25
  172. package/dist/think-tool-DfCMuO8e.d.ts +0 -26
  173. package/dist/tool-Cohdv5GC.d.ts +0 -65
  174. package/dist/types-BCTRUGex.d.ts +0 -47
  175. package/dist/types-BrLbKnEz.d.ts +0 -119
  176. package/dist/types-D9JpeAPF.d.ts +0 -114
  177. package/dist/types-G12i56s2.d.ts +0 -354
  178. package/dist/types-JJCxRnaZ.d.ts +0 -70
  179. package/dist/types-O-abTIin.d.ts +0 -79
  180. package/dist/ui/index.d.ts +0 -107
  181. package/dist/ui/index.js +0 -10
  182. package/dist/ui/index.js.map +0 -1
  183. /package/dist/{hooks → agent/interactions}/index.js.map +0 -0
  184. /package/dist/{request → speech-generation}/index.js.map +0 -0
package/README.md CHANGED
@@ -12,10 +12,17 @@ The package is dependency-injection oriented: create provider models, typed tool
12
12
 
13
13
  ## Installation
14
14
 
15
+ Anvia 1.0 is currently published on npm under the `rc` tag. The unqualified `latest` tag remains
16
+ on the maintenance-only v0 line until 1.0 reaches general availability. Keep Core and every Anvia
17
+ adapter on the same release channel.
18
+
15
19
  ```sh
16
- pnpm add @anvia/core
20
+ pnpm add @anvia/core@rc
17
21
  ```
18
22
 
23
+ See the repository's [1.0 release policy](../../docs/releases/v1.md) for channel and support
24
+ details.
25
+
19
26
  In this monorepo, the package is available through the workspace:
20
27
 
21
28
  ```sh
@@ -26,177 +33,379 @@ pnpm --filter @anvia/core build
26
33
 
27
34
  ```ts
28
35
  import { z } from "zod";
29
- import { AgentBuilder, createTool } from "@anvia/core";
36
+ import { Agent, createTool } from "@anvia/core";
30
37
  import { OpenAIClient } from "@anvia/openai";
31
38
 
32
39
  const client = new OpenAIClient({
33
40
  apiKey,
34
41
  });
35
42
 
36
- const model = client.completionModel("gpt-5");
43
+ const model = client.completionModel({ modelId: "gpt-5", api: "responses" });
37
44
 
38
45
  const lookupOrder = createTool({
39
46
  name: "lookup_order",
40
47
  description: "Look up an order by id.",
41
- input: z.object({ orderId: z.string() }),
48
+ inputSchema: z.object({ orderId: z.string() }),
42
49
  execute: async ({ orderId }) => ({ orderId, status: "processing" }),
43
50
  });
44
51
 
45
- const agent = new AgentBuilder("support", model)
46
- .instructions("Help customers with order questions.")
47
- .tool(lookupOrder)
48
- .defaultMaxTurns(4)
49
- .build();
50
-
51
- const response = await agent.prompt("What is happening with order A123?").send();
52
+ const agent = new Agent({
53
+ id: "support",
54
+ model,
55
+ instructions: "Help customers with order questions.",
56
+ maxTurns: 4,
57
+ tools: [lookupOrder],
58
+ });
52
59
 
53
- console.log(response.output);
60
+ const result = await agent.generate({ prompt: "What is happening with order A123?" });
61
+ if (result.status === "completed") console.log(result.output);
54
62
  ```
55
63
 
56
64
  ## Direct Completions
57
65
 
58
- Use `createCompletion` when you want a single provider call without agent turns, memory, or
59
- tool execution:
66
+ Use `generateCompletion` for one provider call without Agent turns, memory, or local tool
67
+ execution. The model and input are part of one options object:
60
68
 
61
69
  ```ts
62
- import { createCompletion } from "@anvia/core";
70
+ import { generateCompletion } from "@anvia/core";
63
71
  import { OpenAIClient } from "@anvia/openai";
64
72
 
65
- const model = new OpenAIClient({ apiKey }).completionModel("gpt-5");
73
+ const model = new OpenAIClient({ apiKey }).completionModel({ modelId: "gpt-5", api: "responses" });
66
74
 
67
- const result = await createCompletion(model, {
68
- input: "Summarize Anvia in one sentence.",
75
+ const result = await generateCompletion({
76
+ model,
77
+ prompt: "Summarize Anvia in one sentence.",
69
78
  instructions: "Answer clearly and concisely.",
70
79
  });
71
80
 
72
- console.log(result.text);
81
+ console.log(result.output); // string
73
82
  ```
74
83
 
75
- Use `messages` when you already own the transcript. If `input` is also provided, it is appended as
76
- the final message:
84
+ Use `messages` when the application already owns the transcript. Exactly one of `prompt` or
85
+ `messages` is required:
77
86
 
78
87
  ```ts
79
- import { Message, createCompletion } from "@anvia/core";
88
+ import { generateCompletion, type Message } from "@anvia/core";
80
89
 
81
- const result = await createCompletion(model, {
90
+ const result = await generateCompletion({
91
+ model,
82
92
  messages: [
83
- Message.system("You are concise."),
84
- Message.user("Explain Anvia."),
85
- ],
93
+ { role: "system", content: "You are concise." },
94
+ { role: "user", content: "Explain Anvia." },
95
+ ] satisfies readonly Message[],
86
96
  maxTokens: 300,
87
- params: {
97
+ providerOptions: {
88
98
  reasoning: { effort: "low" },
89
99
  },
90
100
  });
91
101
  ```
92
102
 
93
- Use `createCompletionStream` to receive raw completion stream events from the model:
103
+ Messages are plain, readonly `{ role, content }` objects. Use structural literals with
104
+ `satisfies Message` or `satisfies readonly Message[]`; there is no message factory namespace.
105
+ Multimodal user content uses `text`, `image`, and `file` parts, while assistant tool calls use
106
+ `{ type: "tool-call", toolCallId, toolName, input }`. At external boundaries, validate with
107
+ `parseMessage`, `parseMessages`, `messageSchema`, or an application-specific
108
+ `createMessageSchema({ metadataSchema })`.
109
+
110
+ Add `outputSchema` to the same function for typed, schema-validated output:
111
+
112
+ ```ts
113
+ import { generateCompletion } from "@anvia/core";
114
+ import { z } from "zod";
115
+
116
+ const result = await generateCompletion({
117
+ model,
118
+ prompt: "Extract: Acme reports a high-priority checkout failure.",
119
+ outputSchema: z.object({
120
+ customer: z.string(),
121
+ priority: z.enum(["low", "medium", "high"]),
122
+ }),
123
+ });
124
+
125
+ console.log(result.output.priority); // fully typed
126
+ ```
127
+
128
+ `CompletionResult` consistently contains `output`, the original `text`, normalized `content`,
129
+ `usage`, and `rawResponse`, plus optional message, context, source, provider-tool, and finish-reason
130
+ metadata. First-party adapters normalize provider termination into `finishReason` (`stop`, `length`,
131
+ `content-filter`, `tool-calls`, or `other`) while preserving the provider value separately as
132
+ `providerFinishReason`.
133
+
134
+ Schema-backed completion checks termination before JSON parsing. `finishReason: "length"` throws
135
+ `CompletionStructuredOutputError` with `phase: "truncated"`; `finishReason: "content-filter"`
136
+ throws it with `phase: "content-filter"` and is not retried by the default policy. Ordinary text
137
+ completion remains intentional: partial text is returned unchanged with its finish reason so the
138
+ application decides whether to display, continue, or discard it. A direct structured stream can
139
+ similarly end with one typed error event after any already-emitted deltas; it does not silently
140
+ retract public stream progress.
141
+
142
+ Use `streamCompletion` for the streaming form:
94
143
 
95
144
  ```ts
96
- import { createCompletionStream } from "@anvia/core";
145
+ import { streamCompletion } from "@anvia/core";
97
146
 
98
- for await (const event of createCompletionStream(model, {
99
- input: "Write a short launch note.",
147
+ for await (const event of streamCompletion({
148
+ model,
149
+ prompt: "Write a short launch note.",
100
150
  })) {
101
151
  if (event.type === "text_delta") process.stdout.write(event.delta);
152
+ if (event.type === "final") console.log(event.result.usage);
153
+ if (event.type === "error") console.error(event.error);
102
154
  }
103
155
  ```
104
156
 
105
- React hooks keep `UIMessage[]` state locally, but send core `Message[]` in their request body. Pass
106
- those messages directly to `createCompletionStream`:
157
+ Tool-call deltas are always emitted when a provider supplies them; there is no opt-in flag. A
158
+ high-level stream emits at most one terminal `error` event and then closes. Provider model adapters
159
+ use the lower-level `CompletionModelStreamEvent`, whose terminal event is `{ type: "final",
160
+ response }`; `streamCompletion` normalizes it to `{ type: "final", result }`.
107
161
 
108
- ```ts
109
- import { createCompletionStream } from "@anvia/core";
110
- import type { UIStreamRequest } from "@anvia/core/ui";
162
+ Client requests carry core `Message[]`, so an endpoint can validate and pass them directly:
111
163
 
112
- const body = (await request.json()) as UIStreamRequest;
164
+ ```ts
165
+ import { completionToClientStream, parseClientStreamRequest } from "@anvia/client";
166
+ import { streamCompletion } from "@anvia/core";
167
+ import { createClientStreamResponse } from "@anvia/server";
113
168
 
114
- const events = createCompletionStream(model, {
115
- messages: body.messages,
169
+ const body = parseClientStreamRequest(await request.json());
170
+ const events = completionToClientStream({
171
+ events: streamCompletion({ model, messages: body.messages }),
116
172
  });
173
+ return createClientStreamResponse({ events });
117
174
  ```
118
175
 
119
- Use `createParsedCompletion` when you want a direct completion to return schema-validated data:
176
+ Core does not own UI messages, HTTP transports, or the public wire protocol. Those boundaries live
177
+ in `@anvia/client`, `@anvia/server`, and framework packages such as `@anvia/react`.
178
+
179
+ ## Retries, Provider Options, and Cancellation
180
+
181
+ Direct completion and media calls accept `retries?: RetryOptions | false`. An omitted or `false`
182
+ value makes one provider attempt; `{}` enables the default retry policy. Only retry-safe provider
183
+ calls are repeated.
120
184
 
121
185
  ```ts
122
- import { createParsedCompletion } from "@anvia/core";
123
- import { z } from "zod";
186
+ const controller = new AbortController();
187
+
188
+ const result = await generateCompletion({
189
+ model,
190
+ prompt: "Summarize this incident.",
191
+ retries: { maxAttempts: 3, initialDelayMs: 100, maxDelayMs: 1_000 },
192
+ abortSignal: controller.signal,
193
+ providerOptions: { reasoning: { effort: "medium" } },
194
+ });
195
+ ```
124
196
 
125
- const eventSchema = z.object({
126
- name: z.string(),
127
- date: z.string(),
197
+ `providerOptions` contains a strict JSON object passed to an adapter. Runtime values such as
198
+ `undefined`, non-finite numbers, cycles, a top-level array, and class instances are rejected rather
199
+ than coerced. Nested arrays are valid JSON. Canonical Anvia fields such as model, input,
200
+ temperature, tools, dimensions, text, and voice take precedence over conflicting provider keys.
201
+ Cancellation is forwarded to provider SDK calls and is never retried.
202
+
203
+ ## Agents
204
+
205
+ Agents own their default retry policy. A run with no `retries` value inherits the Agent setting;
206
+ `false` disables it for that run; an object replaces it for that run. Retries apply to the current
207
+ completion only, so completed tools and earlier turns are never replayed. `maxAttempts` is the
208
+ total number of model attempts for that completion, including the initial attempt; it is not the
209
+ number of additional retries.
210
+
211
+ ```ts
212
+ const agent = new Agent({
213
+ id: "support",
214
+ model,
215
+ retries: { maxAttempts: 3 },
128
216
  });
129
217
 
130
- const event = await createParsedCompletion(model, {
131
- schema: eventSchema,
132
- input: "Alice and Bob are going to a science fair on Friday.",
218
+ await agent.generate({ prompt: "Try normally." });
219
+ await agent.generate({ prompt: "Do not retry this run.", retries: false });
220
+ await agent.generate({
221
+ prompt: "Use one custom policy.",
222
+ retries: { maxAttempts: 2, initialDelayMs: 0, maxDelayMs: 0 },
133
223
  });
224
+ ```
225
+
226
+ When an Agent has `outputSchema`, truncation, JSON parsing, and schema-validation failures use the
227
+ same retry budget when retries are explicitly enabled. Each retry starts from the original request
228
+ rather than recursively accumulating failed attempts. Truncated output and reasoning are omitted;
229
+ parse and schema repairs include only a bounded, text-only preview of the latest failed response.
230
+ The correction asks for shorter raw JSON matching the schema, without Markdown or commentary.
231
+ Transport failures and structured-output failures therefore cannot exceed `maxAttempts` in total.
232
+ Completed Agent results expose the last generation's `finishReason` and `providerFinishReason`, and
233
+ the same fields remain attached to each assistant message's Anvia generation metadata.
234
+
235
+ Malformed, incomplete, or non-JSON provider tool arguments fail with
236
+ `CompletionProviderOutputError`. The default policy retries only explicitly retry-safe provider
237
+ output failures when retries are enabled; it does not make arbitrary `SyntaxError` instances
238
+ retryable. Tool calls are validated as a complete set before any tool executes, and filtered tool
239
+ calls are never retried by default. Raw provider arguments are not retained in the error or retry
240
+ metadata. A no-argument tool call must still contain the JSON value `{}`; blank argument text is
241
+ malformed provider output and is never replaced with invented input.
242
+
243
+ Streaming attempts are retried only before any provider event has been exposed. Once progress has
244
+ been emitted, Anvia returns the failure without starting another provider attempt, because replaying
245
+ the stream could duplicate text, tool-call deltas, or other observable events. Applications that
246
+ want post-progress recovery must buffer attempts and define their own reset or resume protocol.
247
+
248
+ Structured output remains strict: Core trims surrounding whitespace, parses JSON, and validates the
249
+ result with the configured Zod schema. As a compatibility fallback for OpenAI-compatible providers
250
+ that violate strict JSON mode, Core also accepts a response consisting entirely of one lowercase
251
+ `json` Markdown fence or one unlabeled Markdown fence. It does not search prose for JSON, accept
252
+ content before or after a fence, or bypass schema validation. `AgentStructuredOutputError` reports
253
+ the `truncated`, `content-filter`, `parse`, or `schema` phase, attempt counts, output length/format
254
+ metadata, per-attempt and cumulative usage, finish reasons, and the original `cause` when one
255
+ exists; its message never contains the rejected model response. The `completion.retry` observer
256
+ event records the same safe diagnostics and whether failed output was omitted or previewed, never
257
+ the model output itself.
258
+
259
+ Agent results are discriminated by `status`. Completed results include typed `output` and `text`;
260
+ guardrail blocks return `status: "blocked"`, `stage`, and `text`; tool approvals and first-class
261
+ questions return a JSON-safe `status: "suspended"` result.
134
262
 
135
- console.log(event.data);
263
+ ```ts
264
+ const result = await agent.generate({ prompt: "Help with this request." });
265
+
266
+ if (result.status === "completed") console.log(result.output);
267
+ if (result.status === "blocked") console.log(result.stage, result.text);
268
+ if (result.status === "suspended") {
269
+ const resumed = await agent.generate({
270
+ continuation: result.continuation,
271
+ response:
272
+ result.interaction.type === "tool-approval"
273
+ ? { type: "tool-approval", approved: true }
274
+ : {
275
+ type: "tool-question",
276
+ answers: result.interaction.questions.map((question) => ({
277
+ questionId: question.id,
278
+ value: "application-provided answer",
279
+ })),
280
+ },
281
+ });
282
+ console.log(resumed.status, resumed.resumedFrom);
283
+ }
136
284
  ```
137
285
 
138
- ## Prompts and Memory
286
+ Keep continuations server-side. A resumed phase receives a new `runId`; Core validates the
287
+ continuation and current Agent/tool registration but does not provide a durable continuation store
288
+ or exactly-once execution. Use `createQuestionTool({ name, description })` when a model must ask for
289
+ structured free-text or choice answers.
139
290
 
140
- Use a plain prompt for stateless calls:
291
+ Import JSON-safe interaction contracts and parsers from their browser-safe subpath. This entrypoint
292
+ does not load the Agent runtime, MCP clients, or Node infrastructure:
141
293
 
142
294
  ```ts
143
- await agent.prompt("Summarize this ticket.").send();
295
+ import {
296
+ type AgentInteractionResponse,
297
+ parseAgentInteractionRequest,
298
+ parseAgentInteractionResponse,
299
+ } from "@anvia/core/agent/interactions";
144
300
  ```
145
301
 
146
- Use a message array when you already own the transcript. The last message is the active prompt and earlier messages are request history:
302
+ An Agent with `outputSchema` carries that output type through `generate`, `stream`, `asTool`, and
303
+ Pipeline Agent stages. Agent stream finals use the same result shape:
147
304
 
148
305
  ```ts
149
- import { Message } from "@anvia/core";
150
-
151
- await agent
152
- .prompt([
153
- Message.user("My project is named Anvia."),
154
- Message.assistant("Noted."),
155
- Message.user("What is my project named?"),
156
- ])
157
- .send();
306
+ for await (const event of agent.stream({ prompt: "Help with this request." })) {
307
+ if (event.type === "final") {
308
+ if (event.result.status === "completed") console.log(event.result.output);
309
+ else console.log(event.result.stage, event.result.text);
310
+ }
311
+ }
158
312
  ```
159
313
 
160
- Configure durable conversation memory on the agent, then run through a session:
314
+ Pass `abortSignal` on a run to cancel the active provider call, tools, and nested Agent tools.
315
+
316
+ ## Memory
317
+
318
+ Configure durable conversation memory on the Agent, then run through a session:
161
319
 
162
320
  ```ts
163
- import { AgentBuilder, type MemoryStore, type Message } from "@anvia/core";
164
- import type { MemoryAppendInput, MemoryContext } from "@anvia/core/memory";
321
+ import { Agent, type MemoryStore, type Message } from "@anvia/core";
322
+ import type { MemoryAppendOptions, MemoryScope } from "@anvia/core/memory";
165
323
 
166
324
  class AppMemoryStore implements MemoryStore {
167
325
  private readonly sessions = new Map<string, Message[]>();
168
326
 
169
- async load(context: MemoryContext): Promise<Message[]> {
170
- return [...(this.sessions.get(context.sessionId) ?? [])];
327
+ async load({ scope }: { scope: MemoryScope }): Promise<Message[]> {
328
+ return [...(this.sessions.get(scope.sessionId) ?? [])];
171
329
  }
172
330
 
173
- async append(input: MemoryAppendInput): Promise<void> {
174
- const current = this.sessions.get(input.context.sessionId) ?? [];
175
- this.sessions.set(input.context.sessionId, [...current, ...input.messages]);
331
+ async append(input: MemoryAppendOptions): Promise<void> {
332
+ const current = this.sessions.get(input.scope.sessionId) ?? [];
333
+ this.sessions.set(input.scope.sessionId, [...current, ...input.messages]);
176
334
  }
177
335
 
178
- async clear(context: MemoryContext): Promise<void> {
179
- this.sessions.delete(context.sessionId);
336
+ async clear({ scope }: { scope: MemoryScope }): Promise<void> {
337
+ this.sessions.delete(scope.sessionId);
180
338
  }
181
339
  }
182
340
 
183
341
  const memory = new AppMemoryStore();
184
- const agent = new AgentBuilder("support", model).memory(memory).build();
342
+ const agent = new Agent({
343
+ id: "support",
344
+ model: model,
345
+ memory: { store: memory },
346
+ });
185
347
 
186
- await agent.session("thread_123", { userId: "user_456" }).prompt("Remember my plan.").send();
187
- await agent.session("thread_123", { userId: "user_456" }).prompt("What is my plan?").send();
348
+ const session = { sessionId: "thread_123", userId: "user_456" };
349
+ await agent.generate({ prompt: "Remember my plan.", session });
350
+ await agent.generate({ prompt: "What is my plan?", session });
188
351
  ```
189
352
 
190
353
  Memory defaults to `savePolicy: "message"`, which saves the user prompt, each completed assistant message, and each completed tool result as soon as they are ready. You can choose `"turn"` or `"run"` at configuration time:
191
354
 
192
355
  ```ts
193
- new AgentBuilder("support", model).memory(memory, { savePolicy: "turn" });
356
+ new Agent({
357
+ id: "support",
358
+ model,
359
+ memory: { store: memory, savePolicy: "turn" },
360
+ });
194
361
  ```
195
362
 
363
+ Without `session`, the same Agent is stateless. Pass `{ messages }` when the caller already owns a
364
+ complete transcript; transcripts cannot be combined with persisted sessions.
365
+
366
+ Compaction is an explicit Agent policy over a store capability. The adapter persists the summary as
367
+ an ordinary system message with `metadata.anvia.memoryCompaction`, so `load()` and inspectors expose
368
+ exactly what future runs receive:
369
+
370
+ ```ts
371
+ import { createSummaryMemoryCompactor } from "@anvia/core/memory";
372
+
373
+ const compactor = createSummaryMemoryCompactor({
374
+ model: summaryModel,
375
+ maxTokens: 1024,
376
+ retries: { maxAttempts: 2 },
377
+ });
378
+
379
+ const agent = new Agent({
380
+ id: "support",
381
+ model,
382
+ memory: {
383
+ store: memory,
384
+ savePolicy: "message",
385
+ compaction: {
386
+ trigger: { afterMessages: 50 },
387
+ retention: { recentUserTurns: 4 },
388
+ compactor,
389
+ conflictRetries: false,
390
+ },
391
+ },
392
+ });
393
+
394
+ for await (const event of agent.stream({ prompt: "What did we decide?", session })) {
395
+ if (event.type === "memory_compaction") {
396
+ console.log(event.compactedMessageCount, event.usage);
397
+ }
398
+ }
399
+ ```
400
+
401
+ The trigger is a threshold, not a hard storage limit. Summary-provider retries belong to the
402
+ compactor; full snapshot-to-replacement conflict retries are separately opt-in.
403
+
196
404
  ## Structured Extraction
197
405
 
198
406
  ```ts
199
- import { ExtractorBuilder } from "@anvia/core/extractor";
407
+ import { extract } from "@anvia/core/extractor";
408
+ import { z } from "zod";
200
409
 
201
410
  const ticketSchema = z.object({
202
411
  customer: z.string(),
@@ -204,45 +413,142 @@ const ticketSchema = z.object({
204
413
  summary: z.string(),
205
414
  });
206
415
 
207
- const extractor = new ExtractorBuilder(model, ticketSchema).retries(1).build();
208
-
209
- const ticket = await extractor.extract(
210
- "Acme Co. reports checkout failures. Priority is high.",
211
- );
416
+ const { output: ticket } = await extract({
417
+ model,
418
+ text: "Acme Co. reports checkout failures. Priority is high.",
419
+ outputSchema: ticketSchema,
420
+ retries: { maxAttempts: 2 },
421
+ });
212
422
  ```
213
423
 
214
424
  ## Pipelines
215
425
 
216
426
  ```ts
217
- import { PipelineBuilder } from "@anvia/core/pipeline";
427
+ import { Pipeline } from "@anvia/core/pipeline";
218
428
  import { z } from "zod";
219
429
 
220
- const pipeline = new PipelineBuilder(z.string())
221
- .step((input) => `Extract this support ticket:\n\n${input}`)
222
- .prompt(agent)
223
- .extract(extractor)
224
- .build();
430
+ const pipeline = new Pipeline({ id: "support-flow", inputSchema: z.string() })
431
+ .agent({
432
+ id: "draft",
433
+ agent,
434
+ suspension: "reject",
435
+ request: ({ input }) => ({ prompt: `Draft a reply for this ticket:\n\n${input}` }),
436
+ })
437
+ .extract({
438
+ id: "parse",
439
+ model,
440
+ outputSchema: ticketSchema,
441
+ text: ({ input }) => input,
442
+ });
443
+
444
+ const { runId, output } = await pipeline.run({
445
+ input: "Customer cannot complete checkout.",
446
+ });
447
+ ```
448
+
449
+ ## Documents
450
+
451
+ Applications own file discovery, file reads, source metadata, and per-file error policy. Core only
452
+ provides deterministic in-memory chunking and scoped PDF text extraction:
453
+
454
+ PDF extraction uses the optional `pdfjs-dist` peer dependency. Install it in applications that call
455
+ `extractPdfText`:
456
+
457
+ ```sh
458
+ pnpm add pdfjs-dist
459
+ ```
460
+
461
+ ```ts
462
+ import { readFile } from "node:fs/promises";
463
+ import { chunkText, extractPdfText } from "@anvia/core/documents";
464
+
465
+ const text = await readFile("guide.txt", "utf8");
466
+ const chunks = chunkText({
467
+ text,
468
+ strategy: "recursive",
469
+ maxSize: 1_000,
470
+ overlap: 100,
471
+ separators: ["\n\n", "\n", " "],
472
+ });
473
+
474
+ const { pages } = await extractPdfText({
475
+ data: new Uint8Array(await readFile("guide.pdf")),
476
+ abortSignal,
477
+ });
478
+ ```
479
+
480
+ Use `strategy: "fixed"` for deterministic sliding windows. Recursive chunking requires an explicit
481
+ separator order and falls back to fixed-size splitting when none of those separators can divide an
482
+ oversized section. Chunk offsets use JavaScript string indices and always identify the exact source
483
+ slice. PDF pages are one-based, and the parser task is disposed before extraction settles.
484
+ If parsing or abort handling fails together with parser cleanup, extraction rejects with an
485
+ `AggregateError` containing the operation failure first and the cleanup failure second.
486
+
487
+ ## Media
488
+
489
+ Media helpers follow the same one-object API and share `providerOptions`, `retries`, and
490
+ `abortSignal`:
491
+
492
+ ```ts
493
+ import { generateImage, generateSpeech, transcribe } from "@anvia/core";
494
+
495
+ const image = await generateImage({
496
+ model: client.imageGenerationModel({ modelId: "gpt-image-1" }),
497
+ prompt: "A compact robot drawing an architecture diagram.",
498
+ width: 1024,
499
+ height: 1024,
500
+ });
501
+ console.log(image.images[0].data);
225
502
 
226
- const result = await pipeline.run("Customer cannot complete checkout.");
503
+ const speech = await generateSpeech({
504
+ model: client.speechGenerationModel({ modelId: "gpt-4o-mini-tts" }),
505
+ text: "Hello from Anvia.",
506
+ voice: "alloy",
507
+ });
508
+
509
+ const transcript = await transcribe({
510
+ model: client.transcriptionModel({ modelId: "gpt-4o-mini-transcribe" }),
511
+ audio: {
512
+ data: speech.audio.data,
513
+ filename: "speech.mp3",
514
+ mediaType: speech.audio.mediaType,
515
+ },
516
+ });
517
+ console.log(transcript.text);
518
+ ```
519
+
520
+ ## MCP
521
+
522
+ MCP clients live in the optional `@anvia/mcp` package. Core retains the lightweight registration
523
+ contracts that let agents receive immutable MCP server snapshots without owning or closing their
524
+ underlying transports:
525
+
526
+ ```sh
527
+ pnpm add @anvia/mcp
227
528
  ```
228
529
 
530
+ Import `McpClient` and `McpClientGroup` from `@anvia/mcp`, connect them, and pass the resulting
531
+ `servers` to `new Agent({ mcpServers })`. See the `@anvia/mcp` README for transport configuration,
532
+ connection ownership, URL safety, and cleanup.
533
+
229
534
  ## Public Areas
230
535
 
231
- - `agent`: agent runtime and `AgentBuilder`
536
+ - `agent`: typed Agent runtime, retries, and stream events
537
+ - `agent/interactions`: browser-safe interaction contracts, schemas, assertions, and parsers
232
538
  - `tool`: typed tool creation and tool sets
233
- - `completion`: provider-neutral completion request and response types
539
+ - `completion`: direct completion helpers and provider-neutral model contracts
234
540
  - `memory`: durable session memory interfaces and in-memory store
235
541
  - `extractor`: schema-first structured extraction
236
542
  - `pipeline`: typed sequential and parallel workflows
237
543
  - `embeddings`: embedding helpers and document embedding utilities
238
544
  - `vector-store`: in-memory vector search and vector search tools
239
545
  - `streaming`: normalized stream helpers
240
- - `mcp`: MCP server connection helpers
546
+ - `mcp`: lightweight MCP tool and server registration contracts used by Agent
241
547
  - `skills`: local skill loading
242
548
  - `observability`: observer interfaces for runs, generations, and tool calls
243
549
  - `evals`: evaluation helpers and reporters
244
- - `loaders`: document loading utilities
245
- - `audio-generation`, `image-generation`, `transcription`: provider-neutral media interfaces
550
+ - `documents`: in-memory text chunking and PDF text extraction
551
+ - `speech-generation`, `image-generation`, `transcription`: provider-neutral media interfaces
246
552
 
247
553
  ## Development
248
554