@raindrop-ai/ai-sdk 0.2.1 → 0.3.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.
- package/README.md +114 -0
- package/dist/{chunk-V636SYSR.mjs → chunk-GMY7QXIQ.mjs} +824 -18
- package/dist/{index-BUWOlY-2.d.mts → index-BqXHiknB.d.mts} +532 -1
- package/dist/{index-BUWOlY-2.d.ts → index-BqXHiknB.d.ts} +532 -1
- package/dist/index.browser.d.mts +532 -1
- package/dist/index.browser.d.ts +532 -1
- package/dist/index.browser.js +836 -17
- package/dist/index.browser.mjs +824 -18
- package/dist/index.node.d.mts +1 -1
- package/dist/index.node.d.ts +1 -1
- package/dist/index.node.js +836 -17
- package/dist/index.node.mjs +1 -1
- package/dist/index.workers.d.mts +1 -1
- package/dist/index.workers.d.ts +1 -1
- package/dist/index.workers.js +836 -17
- package/dist/index.workers.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -190,6 +190,120 @@ Sub-agents (a `generateText`/`streamText` invoked from inside a tool's
|
|
|
190
190
|
`execute`) nest automatically: the inner generation's spans are parented under
|
|
191
191
|
the tool span so parent and child spans stay correctly nested.
|
|
192
192
|
|
|
193
|
+
## Detached sub-agents
|
|
194
|
+
|
|
195
|
+
A **detached** sub-agent is different: it runs in another process (a queue
|
|
196
|
+
worker, a container, another machine), does not block its caller, and reports as
|
|
197
|
+
its own Raindrop event with its own lifecycle. Neither the trace nor the event id
|
|
198
|
+
survives that boundary, so the link is carried explicitly — the caller stamps it
|
|
199
|
+
on the span it dispatched from, the child stamps the reverse reference on every
|
|
200
|
+
span it emits, and a carrier travels with the job.
|
|
201
|
+
|
|
202
|
+
**Caller** — allocate the child's event id and get the headers to send:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
const rd = raindrop({ context: { userId: "user_123" } });
|
|
206
|
+
registerTelemetry(rd);
|
|
207
|
+
|
|
208
|
+
const launch_subagent = tool({
|
|
209
|
+
description: "Hand a task to a background sub-agent",
|
|
210
|
+
inputSchema: z.object({ task: z.string() }),
|
|
211
|
+
execute: async ({ task }) => {
|
|
212
|
+
const dispatch = rd.subagent({ name: "researcher", input: { task } });
|
|
213
|
+
await queue.send({ task, headers: dispatch.headers });
|
|
214
|
+
// Return a handle, not an answer — the answer is the child's to report.
|
|
215
|
+
return { jobId: dispatch.childEventId, status: "accepted" };
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The dispatch span is **your tool's span**, so it carries your tool's name — the
|
|
221
|
+
example above emits `launch_subagent` because that is what the tool is called
|
|
222
|
+
here, not because the SDK imposes it. `launch_subagent` is only the fallback
|
|
223
|
+
name, used when `subagent()` has to synthesize a dispatch span because no tool
|
|
224
|
+
call was open; pass `toolName` to choose your own. The sub-agent's own name
|
|
225
|
+
travels on `raindrop.handoff.name` either way, which is where readers group by
|
|
226
|
+
it.
|
|
227
|
+
|
|
228
|
+
`subagent()` allocates `childEventId` **before** dispatching, so the caller's
|
|
229
|
+
hand-off resolves while the job is still queued. It also opts the turn in to
|
|
230
|
+
producing an event: a turn whose entire content is launches finishes with
|
|
231
|
+
`finishReason: "tool-calls"` and no assistant text, and such turns are dropped as
|
|
232
|
+
intermediate steps by default. If you launch from outside a turn this SDK
|
|
233
|
+
instruments (the v4-v6 `wrap()` path), pass the opt-in yourself with
|
|
234
|
+
`eventMetadata({ toolEvents: "allow" })`.
|
|
235
|
+
|
|
236
|
+
The caller never writes the child's status. It returned a job handle and moved
|
|
237
|
+
on; status is derived from the child's own event.
|
|
238
|
+
|
|
239
|
+
**Child** — resume from the carrier and report under the id the caller allocated:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
const run = rd.subagents.resume(dispatch.headers);
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
await generateText({
|
|
246
|
+
model: anthropic("claude-sonnet-4-5"),
|
|
247
|
+
prompt: job.task,
|
|
248
|
+
experimental_telemetry: { isEnabled: true, metadata: eventMetadata(run.metadata) },
|
|
249
|
+
});
|
|
250
|
+
} catch (err) {
|
|
251
|
+
// Only needed for a failure OUTSIDE a generation — one that throws already
|
|
252
|
+
// reports itself.
|
|
253
|
+
await run.fail(err);
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
`run.metadata` carries the child's event id, identity, and the reverse reference,
|
|
258
|
+
which the integration stamps on every span the run emits. A cancellation is the
|
|
259
|
+
one outcome telemetry cannot show on its own (spans close, nothing errors, there
|
|
260
|
+
is just no answer), so state it with `run.cancel(reason)`; a generation cancelled
|
|
261
|
+
via its `AbortSignal` is marked automatically.
|
|
262
|
+
|
|
263
|
+
A child that ends without reporting anything produces no event at all, which
|
|
264
|
+
leaves its caller unable to tell a failed job from one that never started. The
|
|
265
|
+
SDK therefore records an abort reason as the run's output whenever a detached
|
|
266
|
+
child errors, aborts, or is cancelled.
|
|
267
|
+
|
|
268
|
+
Output alone is not enough for a failure, though. Status is derived from the
|
|
269
|
+
child's telemetry — a run with final output and no errored span reads as
|
|
270
|
+
`finished` — so `run.fail()` also marks the child's own spans as errored, and
|
|
271
|
+
records one when the job died before it reached the model and left nothing to
|
|
272
|
+
mark. `run.cancel()` deliberately does not: cancelled and failed are different
|
|
273
|
+
states, and error spans are what separate them.
|
|
274
|
+
|
|
275
|
+
`resume(headers)` returns a usable run even when there is no carrier — a child
|
|
276
|
+
invoked directly rather than dispatched is a legitimate state, not an error — so
|
|
277
|
+
call sites stay unconditional.
|
|
278
|
+
|
|
279
|
+
The carrier wins over anything local. `resume(headers, { convoId })` treats its
|
|
280
|
+
options as fallbacks for the no-carrier case, not overrides, because every field
|
|
281
|
+
the carrier supplies names something the caller already recorded: a child that
|
|
282
|
+
keeps its own convo id lands in a different conversation from the supervisor that
|
|
283
|
+
launched it, and one that keeps its own event id leaves the caller's reference
|
|
284
|
+
pointing at nothing.
|
|
285
|
+
|
|
286
|
+
> **Trust boundary.** A carrier names the event a child will be attributed to, so
|
|
287
|
+
> accepting one from an untrusted caller lets that caller write into another
|
|
288
|
+
> tenant's trace. Only read carriers that came from inside your own trust
|
|
289
|
+
> boundary.
|
|
290
|
+
|
|
291
|
+
`fromHeaders` also accepts LangSmith's `langsmith-trace` + `langsmith-metadata`
|
|
292
|
+
headers, so a service already propagating those links with no call-site change.
|
|
293
|
+
|
|
294
|
+
**Send every header `dispatch.headers` gives you, not just `traceparent`.** There
|
|
295
|
+
are three: the standard `traceparent` and `baggage` pair, which other readers
|
|
296
|
+
understand, and `x-raindrop-handoff`, which carries the same fields under a name
|
|
297
|
+
no propagator owns. The standard pair is not ours to rely on — an instrumented
|
|
298
|
+
HTTP client rewrites `traceparent` from its own client span, and OTel's baggage
|
|
299
|
+
propagator *replaces* `baggage` with the caller's own entries, so a caller
|
|
300
|
+
propagating something ordinary like a tenant id would otherwise strip every
|
|
301
|
+
hand-off identity and leave the child unlinked. The Raindrop header is read last
|
|
302
|
+
and wins; the standard pair remains the fallback for a carrier written by a
|
|
303
|
+
different sender. A carrier header that arrives **repeated with differing values**
|
|
304
|
+
is refused entirely, leaving an honestly unlinked child rather than a guess about
|
|
305
|
+
which value gets to name the event this process is attributed to.
|
|
306
|
+
|
|
193
307
|
### AI SDK v7+ native telemetry (advanced)
|
|
194
308
|
|
|
195
309
|
For finer control you can build the integration from a `createRaindropAISDK`
|