@raindrop-ai/langchain 0.0.9 → 0.1.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 +48 -7
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +60 -9
- package/dist/index.mjs +60 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ await raindrop.flush();
|
|
|
49
49
|
| `projectId` | `string` | - | Route events to a specific project (slug); omit for the default **Production** project |
|
|
50
50
|
| `eventName` | `string` | `ai_generation` | Event name applied to every event (the `event` field in the dashboard) |
|
|
51
51
|
| `debug` | `boolean` | `false` | Enable verbose logging |
|
|
52
|
-
| `traceChains` | `boolean` | `
|
|
52
|
+
| `traceChains` | `boolean` | `false` | Create spans for chain/runnable execution. Off by default because LangGraph agents emit many structural "chain" spans that bury the LLM and tool spans. |
|
|
53
53
|
| `traceRetrievers` | `boolean` | `true` | Create spans for retriever calls |
|
|
54
54
|
| `filterLangGraphInternals` | `boolean` | `true` | Filter LangGraph-internal chain events and deduplicate LLM callbacks |
|
|
55
55
|
| `maxTextFieldChars` | `number` | `1000000` | Per-field cap for event input/output and serialized span payloads, enforced before/during serialization (truncated values end with `...[truncated by raindrop]`; a stricter `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` env var is honored) |
|
|
@@ -67,17 +67,58 @@ const raindrop = createRaindropLangChain({
|
|
|
67
67
|
|
|
68
68
|
This sets the `X-Raindrop-Project-Id` header on every event. Omit it (or pass `"default"`) to use your org's default **Production** project — the existing behavior. Single-project orgs need nothing new.
|
|
69
69
|
|
|
70
|
-
## LangGraph
|
|
70
|
+
## Agents (LangGraph / ReAct)
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
For a prebuilt agent (`createReactAgent`) or any LangGraph graph, pass the handler
|
|
73
|
+
**once** to the top-level `invoke` call. LangChain propagates the callback down to
|
|
74
|
+
every LLM step and tool call in the run, and the handler threads them onto a single
|
|
75
|
+
Raindrop event (with a span tree) via each callback's `runId`/`parentRunId`.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { createRaindropLangChain } from "@raindrop-ai/langchain";
|
|
79
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
80
|
+
import { tool } from "@langchain/core/tools";
|
|
81
|
+
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
|
82
|
+
import { z } from "zod";
|
|
83
|
+
|
|
84
|
+
const raindrop = createRaindropLangChain({
|
|
85
|
+
writeKey: "your-write-key",
|
|
86
|
+
userId: "user-123",
|
|
87
|
+
eventName: "support-agent",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const getWeather = tool(async ({ city }) => `It is sunny and 72F in ${city}.`, {
|
|
91
|
+
name: "get_weather",
|
|
92
|
+
description: "Get the current weather for a city.",
|
|
93
|
+
schema: z.object({ city: z.string() }),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const agent = createReactAgent({
|
|
97
|
+
llm: new ChatOpenAI({ model: "gpt-4o-mini" }),
|
|
98
|
+
tools: [getWeather],
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// One handler on the top-level invoke captures the whole agent run:
|
|
102
|
+
// LLM steps + tool calls, all on one event.
|
|
103
|
+
await agent.invoke(
|
|
104
|
+
{ messages: [{ role: "user", content: "What's the weather in SF?" }] },
|
|
105
|
+
{ callbacks: [raindrop.handler] },
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
await raindrop.flush(); // await before the process/lambda exits
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
See `examples/langchain-agent-basic/` for a full runnable example.
|
|
112
|
+
|
|
113
|
+
The handler works with LangGraph out of the box and automatically:
|
|
73
114
|
- Filters LangGraph-internal chain events (graph executor, `__start__`, `__end__`, channel nodes)
|
|
74
115
|
- Deduplicates LLM callbacks that LangGraph fires multiple times with the same `runId`
|
|
75
116
|
|
|
76
|
-
Pass the handler both at `graph.invoke()` and inside your LLM node. See `examples/langchain-langgraph-basic/` for a full example.
|
|
77
|
-
|
|
78
117
|
**Best practices:**
|
|
79
|
-
-
|
|
80
|
-
-
|
|
118
|
+
- **Prebuilt agents / graphs**: attach the handler to the top-level `invoke(...)` (as above). This is the one place that reliably captures the full run.
|
|
119
|
+
- **Hand-built graphs with custom callback wiring**: attach the handler to the **model inside your node** rather than duplicating it at each layer, to avoid double events from manual callback propagation.
|
|
120
|
+
- Create a new handler instance per request in server environments.
|
|
121
|
+
- Always `await raindrop.flush()` (or `shutdown()`) before exit — in short scripts and serverless the process can freeze before the batched spans ship.
|
|
81
122
|
|
|
82
123
|
## LangSmith Coexistence
|
|
83
124
|
|
package/dist/index.d.mts
CHANGED
|
@@ -435,6 +435,12 @@ interface RaindropCallbackHandlerOptions {
|
|
|
435
435
|
traceShipper: TraceShipper;
|
|
436
436
|
userId?: string;
|
|
437
437
|
convoId?: string;
|
|
438
|
+
/**
|
|
439
|
+
* Emit a span for every chain / runnable event. For LangGraph agents this
|
|
440
|
+
* produces many structural "chain" spans (per-node runnable wrappers) that
|
|
441
|
+
* bury the meaningful LLM and tool spans, so it defaults to `false`. The
|
|
442
|
+
* event is still finalized correctly when a chain is the root run.
|
|
443
|
+
*/
|
|
438
444
|
traceChains?: boolean;
|
|
439
445
|
traceRetrievers?: boolean;
|
|
440
446
|
/**
|
|
@@ -510,6 +516,11 @@ interface LangChainOptions {
|
|
|
510
516
|
* generic default. Defaults to `"ai_generation"`.
|
|
511
517
|
*/
|
|
512
518
|
eventName?: string;
|
|
519
|
+
/**
|
|
520
|
+
* Emit a span for every chain / runnable event. LangGraph agents produce many
|
|
521
|
+
* structural "chain" spans (per-node runnable wrappers) that bury the LLM and
|
|
522
|
+
* tool spans, so this defaults to `false`. Event threading is unaffected.
|
|
523
|
+
*/
|
|
513
524
|
traceChains?: boolean;
|
|
514
525
|
traceRetrievers?: boolean;
|
|
515
526
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -435,6 +435,12 @@ interface RaindropCallbackHandlerOptions {
|
|
|
435
435
|
traceShipper: TraceShipper;
|
|
436
436
|
userId?: string;
|
|
437
437
|
convoId?: string;
|
|
438
|
+
/**
|
|
439
|
+
* Emit a span for every chain / runnable event. For LangGraph agents this
|
|
440
|
+
* produces many structural "chain" spans (per-node runnable wrappers) that
|
|
441
|
+
* bury the meaningful LLM and tool spans, so it defaults to `false`. The
|
|
442
|
+
* event is still finalized correctly when a chain is the root run.
|
|
443
|
+
*/
|
|
438
444
|
traceChains?: boolean;
|
|
439
445
|
traceRetrievers?: boolean;
|
|
440
446
|
/**
|
|
@@ -510,6 +516,11 @@ interface LangChainOptions {
|
|
|
510
516
|
* generic default. Defaults to `"ai_generation"`.
|
|
511
517
|
*/
|
|
512
518
|
eventName?: string;
|
|
519
|
+
/**
|
|
520
|
+
* Emit a span for every chain / runnable event. LangGraph agents produce many
|
|
521
|
+
* structural "chain" spans (per-node runnable wrappers) that bury the LLM and
|
|
522
|
+
* tool spans, so this defaults to `false`. Event threading is unaffected.
|
|
523
|
+
*/
|
|
513
524
|
traceChains?: boolean;
|
|
514
525
|
traceRetrievers?: boolean;
|
|
515
526
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1323,6 +1323,7 @@ function boundedStringify(value, limit) {
|
|
|
1323
1323
|
}
|
|
1324
1324
|
|
|
1325
1325
|
// src/callback-handler.ts
|
|
1326
|
+
var MESSAGE_CONTENT_CAP = 4096;
|
|
1326
1327
|
var LANGGRAPH_INTERNAL_NAMES = /* @__PURE__ */ new Set([
|
|
1327
1328
|
"LangGraph",
|
|
1328
1329
|
"__start__",
|
|
@@ -1342,7 +1343,7 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1342
1343
|
this.traceShipper = opts.traceShipper;
|
|
1343
1344
|
this.userId = opts.userId;
|
|
1344
1345
|
this.convoId = opts.convoId;
|
|
1345
|
-
this.traceChains = (_a = opts.traceChains) != null ? _a :
|
|
1346
|
+
this.traceChains = (_a = opts.traceChains) != null ? _a : false;
|
|
1346
1347
|
this.traceRetrievers = (_b = opts.traceRetrievers) != null ? _b : true;
|
|
1347
1348
|
this.filterLangGraphInternals = (_c = opts.filterLangGraphInternals) != null ? _c : true;
|
|
1348
1349
|
}
|
|
@@ -1402,9 +1403,20 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1402
1403
|
name: "llm",
|
|
1403
1404
|
parent: this.getParent(parentRunId),
|
|
1404
1405
|
eventId,
|
|
1406
|
+
// `ai.generateText` classifies the span as an LLM generation at ingest
|
|
1407
|
+
// (a bare `llm`/`chat` operationId maps to INTERNAL and is skipped by
|
|
1408
|
+
// the rich-interaction extractor). `ai.prompt.messages` carries the
|
|
1409
|
+
// per-step trajectory so the Convo view can weave in tool calls
|
|
1410
|
+
// inline, matching the shape the ai-sdk / strands SDKs emit.
|
|
1405
1411
|
attributes: [
|
|
1406
1412
|
attrString("ai.model.provider", modelId),
|
|
1407
|
-
attrString("ai.operationId", "
|
|
1413
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
1414
|
+
attrString(
|
|
1415
|
+
"ai.prompt.messages",
|
|
1416
|
+
boundedStringify([
|
|
1417
|
+
{ role: "user", content: capText2(prompts.join("\n"), MESSAGE_CONTENT_CAP) }
|
|
1418
|
+
])
|
|
1419
|
+
)
|
|
1408
1420
|
]
|
|
1409
1421
|
});
|
|
1410
1422
|
this.spans.set(runId, span);
|
|
@@ -1424,17 +1436,21 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1424
1436
|
if (this.filterLangGraphInternals && this.spans.has(runId)) return;
|
|
1425
1437
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1426
1438
|
const modelId = getName(llm, runName);
|
|
1439
|
+
const allMessages = messages.flat();
|
|
1427
1440
|
const span = this.traceShipper.startSpan({
|
|
1428
1441
|
name: "llm",
|
|
1429
1442
|
parent: this.getParent(parentRunId),
|
|
1430
1443
|
eventId,
|
|
1444
|
+
// See handleLLMStart: `ai.generateText` + `ai.prompt.messages` let the
|
|
1445
|
+
// rich-interaction extractor render this step (and any tool calls
|
|
1446
|
+
// between it and the next step) inline in the Convo view.
|
|
1431
1447
|
attributes: [
|
|
1432
1448
|
attrString("ai.model.provider", modelId),
|
|
1433
|
-
attrString("ai.operationId", "
|
|
1449
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
1450
|
+
attrString("ai.prompt.messages", serializeChatMessages(allMessages))
|
|
1434
1451
|
]
|
|
1435
1452
|
});
|
|
1436
1453
|
this.spans.set(runId, span);
|
|
1437
|
-
const allMessages = messages.flat();
|
|
1438
1454
|
const userMessages = allMessages.filter((m) => {
|
|
1439
1455
|
var _a, _b;
|
|
1440
1456
|
const role = (_b = (_a = m._getType) == null ? void 0 : _a.call(m)) != null ? _b : "unknown";
|
|
@@ -1463,6 +1479,10 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1463
1479
|
this.traceShipper.endSpan(span, {
|
|
1464
1480
|
attributes: [
|
|
1465
1481
|
attrString("ai.response.model", model),
|
|
1482
|
+
// The assistant completion for this step; paired with
|
|
1483
|
+
// `ai.prompt.messages` this is what the Convo view renders as the
|
|
1484
|
+
// assistant turn (empty on tool-only steps, so no blank bubble).
|
|
1485
|
+
attrString("ai.response.text", capText2(outputText, MESSAGE_CONTENT_CAP)),
|
|
1466
1486
|
attrInt("ai.usage.prompt_tokens", promptTokens),
|
|
1467
1487
|
attrInt("ai.usage.completion_tokens", completionTokens)
|
|
1468
1488
|
]
|
|
@@ -1547,12 +1567,13 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1547
1567
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1548
1568
|
const toolName = getName(tool, runName);
|
|
1549
1569
|
const span = this.traceShipper.startSpan({
|
|
1550
|
-
name: "
|
|
1570
|
+
name: "ai.toolCall",
|
|
1551
1571
|
parent: this.getParent(parentRunId),
|
|
1552
1572
|
eventId,
|
|
1573
|
+
operationId: "ai.toolCall",
|
|
1553
1574
|
attributes: [
|
|
1554
|
-
attrString("
|
|
1555
|
-
attrString("
|
|
1575
|
+
attrString("ai.toolCall.name", toolName),
|
|
1576
|
+
attrString("ai.toolCall.args", truncate(input, 4096))
|
|
1556
1577
|
]
|
|
1557
1578
|
});
|
|
1558
1579
|
this.spans.set(runId, span);
|
|
@@ -1566,7 +1587,7 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1566
1587
|
if (span) {
|
|
1567
1588
|
const outputStr = typeof output === "string" ? output : safeStringify(output, 4096);
|
|
1568
1589
|
this.traceShipper.endSpan(span, {
|
|
1569
|
-
attributes: [attrString("
|
|
1590
|
+
attributes: [attrString("ai.toolCall.result", truncate(outputStr, 4096))]
|
|
1570
1591
|
});
|
|
1571
1592
|
}
|
|
1572
1593
|
await this.finalizeEventIfRoot(runId);
|
|
@@ -1599,6 +1620,9 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1599
1620
|
name: "retriever",
|
|
1600
1621
|
parent: this.getParent(parentRunId),
|
|
1601
1622
|
eventId,
|
|
1623
|
+
// Ingest drops spans without an `ai.operationId` (or traceloop/gen_ai)
|
|
1624
|
+
// attribute; stamp one so retriever spans are persisted.
|
|
1625
|
+
operationId: "retriever",
|
|
1602
1626
|
attributes: [
|
|
1603
1627
|
attrString("retriever.name", retrieverName),
|
|
1604
1628
|
attrString("retriever.query", truncate(query, 2048))
|
|
@@ -1646,6 +1670,9 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1646
1670
|
name: "agent_action",
|
|
1647
1671
|
parent: this.getParent(parentRunId),
|
|
1648
1672
|
eventId,
|
|
1673
|
+
// Ingest drops spans without an `ai.operationId` (or traceloop/gen_ai)
|
|
1674
|
+
// attribute; stamp one so agent_action spans are persisted.
|
|
1675
|
+
operationId: "agent_action",
|
|
1649
1676
|
attributes: [
|
|
1650
1677
|
attrString("agent.tool", action.tool),
|
|
1651
1678
|
attrString("agent.tool_input", truncate(
|
|
@@ -1700,6 +1727,30 @@ function truncate(str, maxLen) {
|
|
|
1700
1727
|
if (str.length <= maxLen) return str;
|
|
1701
1728
|
return str.slice(0, maxLen - 3) + "...";
|
|
1702
1729
|
}
|
|
1730
|
+
function messageRole(message) {
|
|
1731
|
+
var _a;
|
|
1732
|
+
switch ((_a = message._getType) == null ? void 0 : _a.call(message)) {
|
|
1733
|
+
case "human":
|
|
1734
|
+
return "user";
|
|
1735
|
+
case "ai":
|
|
1736
|
+
return "assistant";
|
|
1737
|
+
case "system":
|
|
1738
|
+
return "system";
|
|
1739
|
+
case "tool":
|
|
1740
|
+
case "function":
|
|
1741
|
+
return "tool";
|
|
1742
|
+
default:
|
|
1743
|
+
return "user";
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
function serializeChatMessages(messages) {
|
|
1747
|
+
if (messages.length === 0) return void 0;
|
|
1748
|
+
const shaped = messages.map((message) => ({
|
|
1749
|
+
role: messageRole(message),
|
|
1750
|
+
content: typeof message.content === "string" ? capText2(message.content, MESSAGE_CONTENT_CAP) : message.content
|
|
1751
|
+
}));
|
|
1752
|
+
return boundedStringify(shaped);
|
|
1753
|
+
}
|
|
1703
1754
|
function extractLLMMetadata(output) {
|
|
1704
1755
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1705
1756
|
const gen = (_b = (_a = output.generations) == null ? void 0 : _a[0]) == null ? void 0 : _b[0];
|
|
@@ -1720,7 +1771,7 @@ function extractLLMMetadata(output) {
|
|
|
1720
1771
|
// package.json
|
|
1721
1772
|
var package_default = {
|
|
1722
1773
|
name: "@raindrop-ai/langchain",
|
|
1723
|
-
version: "0.0
|
|
1774
|
+
version: "0.1.0",
|
|
1724
1775
|
description: "Raindrop integration for LangChain",
|
|
1725
1776
|
main: "dist/index.js",
|
|
1726
1777
|
module: "dist/index.mjs",
|
package/dist/index.mjs
CHANGED
|
@@ -1296,6 +1296,7 @@ function boundedStringify(value, limit) {
|
|
|
1296
1296
|
}
|
|
1297
1297
|
|
|
1298
1298
|
// src/callback-handler.ts
|
|
1299
|
+
var MESSAGE_CONTENT_CAP = 4096;
|
|
1299
1300
|
var LANGGRAPH_INTERNAL_NAMES = /* @__PURE__ */ new Set([
|
|
1300
1301
|
"LangGraph",
|
|
1301
1302
|
"__start__",
|
|
@@ -1315,7 +1316,7 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1315
1316
|
this.traceShipper = opts.traceShipper;
|
|
1316
1317
|
this.userId = opts.userId;
|
|
1317
1318
|
this.convoId = opts.convoId;
|
|
1318
|
-
this.traceChains = (_a = opts.traceChains) != null ? _a :
|
|
1319
|
+
this.traceChains = (_a = opts.traceChains) != null ? _a : false;
|
|
1319
1320
|
this.traceRetrievers = (_b = opts.traceRetrievers) != null ? _b : true;
|
|
1320
1321
|
this.filterLangGraphInternals = (_c = opts.filterLangGraphInternals) != null ? _c : true;
|
|
1321
1322
|
}
|
|
@@ -1375,9 +1376,20 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1375
1376
|
name: "llm",
|
|
1376
1377
|
parent: this.getParent(parentRunId),
|
|
1377
1378
|
eventId,
|
|
1379
|
+
// `ai.generateText` classifies the span as an LLM generation at ingest
|
|
1380
|
+
// (a bare `llm`/`chat` operationId maps to INTERNAL and is skipped by
|
|
1381
|
+
// the rich-interaction extractor). `ai.prompt.messages` carries the
|
|
1382
|
+
// per-step trajectory so the Convo view can weave in tool calls
|
|
1383
|
+
// inline, matching the shape the ai-sdk / strands SDKs emit.
|
|
1378
1384
|
attributes: [
|
|
1379
1385
|
attrString("ai.model.provider", modelId),
|
|
1380
|
-
attrString("ai.operationId", "
|
|
1386
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
1387
|
+
attrString(
|
|
1388
|
+
"ai.prompt.messages",
|
|
1389
|
+
boundedStringify([
|
|
1390
|
+
{ role: "user", content: capText2(prompts.join("\n"), MESSAGE_CONTENT_CAP) }
|
|
1391
|
+
])
|
|
1392
|
+
)
|
|
1381
1393
|
]
|
|
1382
1394
|
});
|
|
1383
1395
|
this.spans.set(runId, span);
|
|
@@ -1397,17 +1409,21 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1397
1409
|
if (this.filterLangGraphInternals && this.spans.has(runId)) return;
|
|
1398
1410
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1399
1411
|
const modelId = getName(llm, runName);
|
|
1412
|
+
const allMessages = messages.flat();
|
|
1400
1413
|
const span = this.traceShipper.startSpan({
|
|
1401
1414
|
name: "llm",
|
|
1402
1415
|
parent: this.getParent(parentRunId),
|
|
1403
1416
|
eventId,
|
|
1417
|
+
// See handleLLMStart: `ai.generateText` + `ai.prompt.messages` let the
|
|
1418
|
+
// rich-interaction extractor render this step (and any tool calls
|
|
1419
|
+
// between it and the next step) inline in the Convo view.
|
|
1404
1420
|
attributes: [
|
|
1405
1421
|
attrString("ai.model.provider", modelId),
|
|
1406
|
-
attrString("ai.operationId", "
|
|
1422
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
1423
|
+
attrString("ai.prompt.messages", serializeChatMessages(allMessages))
|
|
1407
1424
|
]
|
|
1408
1425
|
});
|
|
1409
1426
|
this.spans.set(runId, span);
|
|
1410
|
-
const allMessages = messages.flat();
|
|
1411
1427
|
const userMessages = allMessages.filter((m) => {
|
|
1412
1428
|
var _a, _b;
|
|
1413
1429
|
const role = (_b = (_a = m._getType) == null ? void 0 : _a.call(m)) != null ? _b : "unknown";
|
|
@@ -1436,6 +1452,10 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1436
1452
|
this.traceShipper.endSpan(span, {
|
|
1437
1453
|
attributes: [
|
|
1438
1454
|
attrString("ai.response.model", model),
|
|
1455
|
+
// The assistant completion for this step; paired with
|
|
1456
|
+
// `ai.prompt.messages` this is what the Convo view renders as the
|
|
1457
|
+
// assistant turn (empty on tool-only steps, so no blank bubble).
|
|
1458
|
+
attrString("ai.response.text", capText2(outputText, MESSAGE_CONTENT_CAP)),
|
|
1439
1459
|
attrInt("ai.usage.prompt_tokens", promptTokens),
|
|
1440
1460
|
attrInt("ai.usage.completion_tokens", completionTokens)
|
|
1441
1461
|
]
|
|
@@ -1520,12 +1540,13 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1520
1540
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1521
1541
|
const toolName = getName(tool, runName);
|
|
1522
1542
|
const span = this.traceShipper.startSpan({
|
|
1523
|
-
name: "
|
|
1543
|
+
name: "ai.toolCall",
|
|
1524
1544
|
parent: this.getParent(parentRunId),
|
|
1525
1545
|
eventId,
|
|
1546
|
+
operationId: "ai.toolCall",
|
|
1526
1547
|
attributes: [
|
|
1527
|
-
attrString("
|
|
1528
|
-
attrString("
|
|
1548
|
+
attrString("ai.toolCall.name", toolName),
|
|
1549
|
+
attrString("ai.toolCall.args", truncate(input, 4096))
|
|
1529
1550
|
]
|
|
1530
1551
|
});
|
|
1531
1552
|
this.spans.set(runId, span);
|
|
@@ -1539,7 +1560,7 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1539
1560
|
if (span) {
|
|
1540
1561
|
const outputStr = typeof output === "string" ? output : safeStringify(output, 4096);
|
|
1541
1562
|
this.traceShipper.endSpan(span, {
|
|
1542
|
-
attributes: [attrString("
|
|
1563
|
+
attributes: [attrString("ai.toolCall.result", truncate(outputStr, 4096))]
|
|
1543
1564
|
});
|
|
1544
1565
|
}
|
|
1545
1566
|
await this.finalizeEventIfRoot(runId);
|
|
@@ -1572,6 +1593,9 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1572
1593
|
name: "retriever",
|
|
1573
1594
|
parent: this.getParent(parentRunId),
|
|
1574
1595
|
eventId,
|
|
1596
|
+
// Ingest drops spans without an `ai.operationId` (or traceloop/gen_ai)
|
|
1597
|
+
// attribute; stamp one so retriever spans are persisted.
|
|
1598
|
+
operationId: "retriever",
|
|
1575
1599
|
attributes: [
|
|
1576
1600
|
attrString("retriever.name", retrieverName),
|
|
1577
1601
|
attrString("retriever.query", truncate(query, 2048))
|
|
@@ -1619,6 +1643,9 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1619
1643
|
name: "agent_action",
|
|
1620
1644
|
parent: this.getParent(parentRunId),
|
|
1621
1645
|
eventId,
|
|
1646
|
+
// Ingest drops spans without an `ai.operationId` (or traceloop/gen_ai)
|
|
1647
|
+
// attribute; stamp one so agent_action spans are persisted.
|
|
1648
|
+
operationId: "agent_action",
|
|
1622
1649
|
attributes: [
|
|
1623
1650
|
attrString("agent.tool", action.tool),
|
|
1624
1651
|
attrString("agent.tool_input", truncate(
|
|
@@ -1673,6 +1700,30 @@ function truncate(str, maxLen) {
|
|
|
1673
1700
|
if (str.length <= maxLen) return str;
|
|
1674
1701
|
return str.slice(0, maxLen - 3) + "...";
|
|
1675
1702
|
}
|
|
1703
|
+
function messageRole(message) {
|
|
1704
|
+
var _a;
|
|
1705
|
+
switch ((_a = message._getType) == null ? void 0 : _a.call(message)) {
|
|
1706
|
+
case "human":
|
|
1707
|
+
return "user";
|
|
1708
|
+
case "ai":
|
|
1709
|
+
return "assistant";
|
|
1710
|
+
case "system":
|
|
1711
|
+
return "system";
|
|
1712
|
+
case "tool":
|
|
1713
|
+
case "function":
|
|
1714
|
+
return "tool";
|
|
1715
|
+
default:
|
|
1716
|
+
return "user";
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
function serializeChatMessages(messages) {
|
|
1720
|
+
if (messages.length === 0) return void 0;
|
|
1721
|
+
const shaped = messages.map((message) => ({
|
|
1722
|
+
role: messageRole(message),
|
|
1723
|
+
content: typeof message.content === "string" ? capText2(message.content, MESSAGE_CONTENT_CAP) : message.content
|
|
1724
|
+
}));
|
|
1725
|
+
return boundedStringify(shaped);
|
|
1726
|
+
}
|
|
1676
1727
|
function extractLLMMetadata(output) {
|
|
1677
1728
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1678
1729
|
const gen = (_b = (_a = output.generations) == null ? void 0 : _a[0]) == null ? void 0 : _b[0];
|
|
@@ -1693,7 +1744,7 @@ function extractLLMMetadata(output) {
|
|
|
1693
1744
|
// package.json
|
|
1694
1745
|
var package_default = {
|
|
1695
1746
|
name: "@raindrop-ai/langchain",
|
|
1696
|
-
version: "0.0
|
|
1747
|
+
version: "0.1.0",
|
|
1697
1748
|
description: "Raindrop integration for LangChain",
|
|
1698
1749
|
main: "dist/index.js",
|
|
1699
1750
|
module: "dist/index.mjs",
|