@raindrop-ai/langchain 0.0.8 → 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 +49 -7
- package/dist/index.d.mts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +69 -13
- package/dist/index.mjs +69 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,8 +47,9 @@ await raindrop.flush();
|
|
|
47
47
|
| `userId` | `string` | - | Associate all events with a user |
|
|
48
48
|
| `convoId` | `string` | - | Group events into a conversation |
|
|
49
49
|
| `projectId` | `string` | - | Route events to a specific project (slug); omit for the default **Production** project |
|
|
50
|
+
| `eventName` | `string` | `ai_generation` | Event name applied to every event (the `event` field in the dashboard) |
|
|
50
51
|
| `debug` | `boolean` | `false` | Enable verbose logging |
|
|
51
|
-
| `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. |
|
|
52
53
|
| `traceRetrievers` | `boolean` | `true` | Create spans for retriever calls |
|
|
53
54
|
| `filterLangGraphInternals` | `boolean` | `true` | Filter LangGraph-internal chain events and deduplicate LLM callbacks |
|
|
54
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) |
|
|
@@ -66,17 +67,58 @@ const raindrop = createRaindropLangChain({
|
|
|
66
67
|
|
|
67
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.
|
|
68
69
|
|
|
69
|
-
## LangGraph
|
|
70
|
+
## Agents (LangGraph / ReAct)
|
|
70
71
|
|
|
71
|
-
|
|
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:
|
|
72
114
|
- Filters LangGraph-internal chain events (graph executor, `__start__`, `__end__`, channel nodes)
|
|
73
115
|
- Deduplicates LLM callbacks that LangGraph fires multiple times with the same `runId`
|
|
74
116
|
|
|
75
|
-
Pass the handler both at `graph.invoke()` and inside your LLM node. See `examples/langchain-langgraph-basic/` for a full example.
|
|
76
|
-
|
|
77
117
|
**Best practices:**
|
|
78
|
-
-
|
|
79
|
-
-
|
|
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.
|
|
80
122
|
|
|
81
123
|
## LangSmith Coexistence
|
|
82
124
|
|
package/dist/index.d.mts
CHANGED
|
@@ -61,6 +61,7 @@ type Patch = {
|
|
|
61
61
|
output?: string;
|
|
62
62
|
model?: string;
|
|
63
63
|
properties?: Record<string, unknown>;
|
|
64
|
+
featureFlags?: Record<string, string>;
|
|
64
65
|
attachments?: Attachment[];
|
|
65
66
|
isPending?: boolean;
|
|
66
67
|
timestamp?: string;
|
|
@@ -161,6 +162,7 @@ declare class EventShipper {
|
|
|
161
162
|
output?: string;
|
|
162
163
|
model?: string;
|
|
163
164
|
properties?: Record<string, unknown>;
|
|
165
|
+
featureFlags?: Record<string, string>;
|
|
164
166
|
userId?: string;
|
|
165
167
|
}): Promise<void>;
|
|
166
168
|
flush(): Promise<void>;
|
|
@@ -433,6 +435,12 @@ interface RaindropCallbackHandlerOptions {
|
|
|
433
435
|
traceShipper: TraceShipper;
|
|
434
436
|
userId?: string;
|
|
435
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
|
+
*/
|
|
436
444
|
traceChains?: boolean;
|
|
437
445
|
traceRetrievers?: boolean;
|
|
438
446
|
/**
|
|
@@ -501,6 +509,18 @@ interface LangChainOptions {
|
|
|
501
509
|
* resolves to `default` server-side; byte-identical to prior behavior).
|
|
502
510
|
*/
|
|
503
511
|
projectId?: string;
|
|
512
|
+
/**
|
|
513
|
+
* Event name applied to every event produced by this integration (the
|
|
514
|
+
* `event` field in the Raindrop dashboard). Lets you distinguish LangChain
|
|
515
|
+
* traffic — e.g. `"support_agent"` vs `"billing_agent"` — instead of the
|
|
516
|
+
* generic default. Defaults to `"ai_generation"`.
|
|
517
|
+
*/
|
|
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
|
+
*/
|
|
504
524
|
traceChains?: boolean;
|
|
505
525
|
traceRetrievers?: boolean;
|
|
506
526
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ type Patch = {
|
|
|
61
61
|
output?: string;
|
|
62
62
|
model?: string;
|
|
63
63
|
properties?: Record<string, unknown>;
|
|
64
|
+
featureFlags?: Record<string, string>;
|
|
64
65
|
attachments?: Attachment[];
|
|
65
66
|
isPending?: boolean;
|
|
66
67
|
timestamp?: string;
|
|
@@ -161,6 +162,7 @@ declare class EventShipper {
|
|
|
161
162
|
output?: string;
|
|
162
163
|
model?: string;
|
|
163
164
|
properties?: Record<string, unknown>;
|
|
165
|
+
featureFlags?: Record<string, string>;
|
|
164
166
|
userId?: string;
|
|
165
167
|
}): Promise<void>;
|
|
166
168
|
flush(): Promise<void>;
|
|
@@ -433,6 +435,12 @@ interface RaindropCallbackHandlerOptions {
|
|
|
433
435
|
traceShipper: TraceShipper;
|
|
434
436
|
userId?: string;
|
|
435
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
|
+
*/
|
|
436
444
|
traceChains?: boolean;
|
|
437
445
|
traceRetrievers?: boolean;
|
|
438
446
|
/**
|
|
@@ -501,6 +509,18 @@ interface LangChainOptions {
|
|
|
501
509
|
* resolves to `default` server-side; byte-identical to prior behavior).
|
|
502
510
|
*/
|
|
503
511
|
projectId?: string;
|
|
512
|
+
/**
|
|
513
|
+
* Event name applied to every event produced by this integration (the
|
|
514
|
+
* `event` field in the Raindrop dashboard). Lets you distinguish LangChain
|
|
515
|
+
* traffic — e.g. `"support_agent"` vs `"billing_agent"` — instead of the
|
|
516
|
+
* generic default. Defaults to `"ai_generation"`.
|
|
517
|
+
*/
|
|
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
|
+
*/
|
|
504
524
|
traceChains?: boolean;
|
|
505
525
|
traceRetrievers?: boolean;
|
|
506
526
|
/**
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
28
28
|
// src/callback-handler.ts
|
|
29
29
|
var import_base = require("@langchain/core/callbacks/base");
|
|
30
30
|
|
|
31
|
-
// ../core/dist/chunk-
|
|
31
|
+
// ../core/dist/chunk-ITAZONWL.js
|
|
32
32
|
function getCrypto() {
|
|
33
33
|
const c = globalThis.crypto;
|
|
34
34
|
return c;
|
|
@@ -418,13 +418,16 @@ function projectIdHeaders(projectId) {
|
|
|
418
418
|
var SHUTDOWN_DEADLINE_MS = 1e4;
|
|
419
419
|
var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
420
420
|
function mergePatches(target, source) {
|
|
421
|
-
var _a, _b, _c, _d;
|
|
421
|
+
var _a, _b, _c, _d, _e, _f;
|
|
422
422
|
const out = { ...target, ...source };
|
|
423
423
|
if (target.properties || source.properties) {
|
|
424
424
|
out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
|
|
425
425
|
}
|
|
426
|
+
if (target.featureFlags || source.featureFlags) {
|
|
427
|
+
out.featureFlags = { ...(_c = target.featureFlags) != null ? _c : {}, ...(_d = source.featureFlags) != null ? _d : {} };
|
|
428
|
+
}
|
|
426
429
|
if (target.attachments || source.attachments) {
|
|
427
|
-
out.attachments = [...(
|
|
430
|
+
out.attachments = [...(_e = target.attachments) != null ? _e : [], ...(_f = source.attachments) != null ? _f : []];
|
|
428
431
|
}
|
|
429
432
|
return out;
|
|
430
433
|
}
|
|
@@ -694,6 +697,7 @@ var EventShipper = class {
|
|
|
694
697
|
...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
|
|
695
698
|
$context: this.context
|
|
696
699
|
},
|
|
700
|
+
...accumulated.featureFlags && Object.keys(accumulated.featureFlags).length > 0 ? { feature_flags: accumulated.featureFlags } : {},
|
|
697
701
|
attachments: accumulated.attachments,
|
|
698
702
|
is_pending: isPending
|
|
699
703
|
};
|
|
@@ -1319,6 +1323,7 @@ function boundedStringify(value, limit) {
|
|
|
1319
1323
|
}
|
|
1320
1324
|
|
|
1321
1325
|
// src/callback-handler.ts
|
|
1326
|
+
var MESSAGE_CONTENT_CAP = 4096;
|
|
1322
1327
|
var LANGGRAPH_INTERNAL_NAMES = /* @__PURE__ */ new Set([
|
|
1323
1328
|
"LangGraph",
|
|
1324
1329
|
"__start__",
|
|
@@ -1338,7 +1343,7 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1338
1343
|
this.traceShipper = opts.traceShipper;
|
|
1339
1344
|
this.userId = opts.userId;
|
|
1340
1345
|
this.convoId = opts.convoId;
|
|
1341
|
-
this.traceChains = (_a = opts.traceChains) != null ? _a :
|
|
1346
|
+
this.traceChains = (_a = opts.traceChains) != null ? _a : false;
|
|
1342
1347
|
this.traceRetrievers = (_b = opts.traceRetrievers) != null ? _b : true;
|
|
1343
1348
|
this.filterLangGraphInternals = (_c = opts.filterLangGraphInternals) != null ? _c : true;
|
|
1344
1349
|
}
|
|
@@ -1398,9 +1403,20 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1398
1403
|
name: "llm",
|
|
1399
1404
|
parent: this.getParent(parentRunId),
|
|
1400
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.
|
|
1401
1411
|
attributes: [
|
|
1402
1412
|
attrString("ai.model.provider", modelId),
|
|
1403
|
-
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
|
+
)
|
|
1404
1420
|
]
|
|
1405
1421
|
});
|
|
1406
1422
|
this.spans.set(runId, span);
|
|
@@ -1420,17 +1436,21 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1420
1436
|
if (this.filterLangGraphInternals && this.spans.has(runId)) return;
|
|
1421
1437
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1422
1438
|
const modelId = getName(llm, runName);
|
|
1439
|
+
const allMessages = messages.flat();
|
|
1423
1440
|
const span = this.traceShipper.startSpan({
|
|
1424
1441
|
name: "llm",
|
|
1425
1442
|
parent: this.getParent(parentRunId),
|
|
1426
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.
|
|
1427
1447
|
attributes: [
|
|
1428
1448
|
attrString("ai.model.provider", modelId),
|
|
1429
|
-
attrString("ai.operationId", "
|
|
1449
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
1450
|
+
attrString("ai.prompt.messages", serializeChatMessages(allMessages))
|
|
1430
1451
|
]
|
|
1431
1452
|
});
|
|
1432
1453
|
this.spans.set(runId, span);
|
|
1433
|
-
const allMessages = messages.flat();
|
|
1434
1454
|
const userMessages = allMessages.filter((m) => {
|
|
1435
1455
|
var _a, _b;
|
|
1436
1456
|
const role = (_b = (_a = m._getType) == null ? void 0 : _a.call(m)) != null ? _b : "unknown";
|
|
@@ -1459,6 +1479,10 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1459
1479
|
this.traceShipper.endSpan(span, {
|
|
1460
1480
|
attributes: [
|
|
1461
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)),
|
|
1462
1486
|
attrInt("ai.usage.prompt_tokens", promptTokens),
|
|
1463
1487
|
attrInt("ai.usage.completion_tokens", completionTokens)
|
|
1464
1488
|
]
|
|
@@ -1543,12 +1567,13 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1543
1567
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1544
1568
|
const toolName = getName(tool, runName);
|
|
1545
1569
|
const span = this.traceShipper.startSpan({
|
|
1546
|
-
name: "
|
|
1570
|
+
name: "ai.toolCall",
|
|
1547
1571
|
parent: this.getParent(parentRunId),
|
|
1548
1572
|
eventId,
|
|
1573
|
+
operationId: "ai.toolCall",
|
|
1549
1574
|
attributes: [
|
|
1550
|
-
attrString("
|
|
1551
|
-
attrString("
|
|
1575
|
+
attrString("ai.toolCall.name", toolName),
|
|
1576
|
+
attrString("ai.toolCall.args", truncate(input, 4096))
|
|
1552
1577
|
]
|
|
1553
1578
|
});
|
|
1554
1579
|
this.spans.set(runId, span);
|
|
@@ -1562,7 +1587,7 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1562
1587
|
if (span) {
|
|
1563
1588
|
const outputStr = typeof output === "string" ? output : safeStringify(output, 4096);
|
|
1564
1589
|
this.traceShipper.endSpan(span, {
|
|
1565
|
-
attributes: [attrString("
|
|
1590
|
+
attributes: [attrString("ai.toolCall.result", truncate(outputStr, 4096))]
|
|
1566
1591
|
});
|
|
1567
1592
|
}
|
|
1568
1593
|
await this.finalizeEventIfRoot(runId);
|
|
@@ -1595,6 +1620,9 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1595
1620
|
name: "retriever",
|
|
1596
1621
|
parent: this.getParent(parentRunId),
|
|
1597
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",
|
|
1598
1626
|
attributes: [
|
|
1599
1627
|
attrString("retriever.name", retrieverName),
|
|
1600
1628
|
attrString("retriever.query", truncate(query, 2048))
|
|
@@ -1642,6 +1670,9 @@ var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
|
1642
1670
|
name: "agent_action",
|
|
1643
1671
|
parent: this.getParent(parentRunId),
|
|
1644
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",
|
|
1645
1676
|
attributes: [
|
|
1646
1677
|
attrString("agent.tool", action.tool),
|
|
1647
1678
|
attrString("agent.tool_input", truncate(
|
|
@@ -1696,6 +1727,30 @@ function truncate(str, maxLen) {
|
|
|
1696
1727
|
if (str.length <= maxLen) return str;
|
|
1697
1728
|
return str.slice(0, maxLen - 3) + "...";
|
|
1698
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
|
+
}
|
|
1699
1754
|
function extractLLMMetadata(output) {
|
|
1700
1755
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1701
1756
|
const gen = (_b = (_a = output.generations) == null ? void 0 : _a[0]) == null ? void 0 : _b[0];
|
|
@@ -1716,7 +1771,7 @@ function extractLLMMetadata(output) {
|
|
|
1716
1771
|
// package.json
|
|
1717
1772
|
var package_default = {
|
|
1718
1773
|
name: "@raindrop-ai/langchain",
|
|
1719
|
-
version: "0.0
|
|
1774
|
+
version: "0.1.0",
|
|
1720
1775
|
description: "Raindrop integration for LangChain",
|
|
1721
1776
|
main: "dist/index.js",
|
|
1722
1777
|
module: "dist/index.mjs",
|
|
@@ -1797,7 +1852,8 @@ function createRaindropLangChain(opts) {
|
|
|
1797
1852
|
projectId: opts.projectId,
|
|
1798
1853
|
sdkName: "langchain",
|
|
1799
1854
|
libraryName,
|
|
1800
|
-
libraryVersion
|
|
1855
|
+
libraryVersion,
|
|
1856
|
+
defaultEventName: opts.eventName
|
|
1801
1857
|
});
|
|
1802
1858
|
const traceShipper = new TraceShipper({
|
|
1803
1859
|
writeKey,
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/callback-handler.ts
|
|
2
2
|
import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
|
|
3
3
|
|
|
4
|
-
// ../core/dist/chunk-
|
|
4
|
+
// ../core/dist/chunk-ITAZONWL.js
|
|
5
5
|
function getCrypto() {
|
|
6
6
|
const c = globalThis.crypto;
|
|
7
7
|
return c;
|
|
@@ -391,13 +391,16 @@ function projectIdHeaders(projectId) {
|
|
|
391
391
|
var SHUTDOWN_DEADLINE_MS = 1e4;
|
|
392
392
|
var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
393
393
|
function mergePatches(target, source) {
|
|
394
|
-
var _a, _b, _c, _d;
|
|
394
|
+
var _a, _b, _c, _d, _e, _f;
|
|
395
395
|
const out = { ...target, ...source };
|
|
396
396
|
if (target.properties || source.properties) {
|
|
397
397
|
out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
|
|
398
398
|
}
|
|
399
|
+
if (target.featureFlags || source.featureFlags) {
|
|
400
|
+
out.featureFlags = { ...(_c = target.featureFlags) != null ? _c : {}, ...(_d = source.featureFlags) != null ? _d : {} };
|
|
401
|
+
}
|
|
399
402
|
if (target.attachments || source.attachments) {
|
|
400
|
-
out.attachments = [...(
|
|
403
|
+
out.attachments = [...(_e = target.attachments) != null ? _e : [], ...(_f = source.attachments) != null ? _f : []];
|
|
401
404
|
}
|
|
402
405
|
return out;
|
|
403
406
|
}
|
|
@@ -667,6 +670,7 @@ var EventShipper = class {
|
|
|
667
670
|
...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
|
|
668
671
|
$context: this.context
|
|
669
672
|
},
|
|
673
|
+
...accumulated.featureFlags && Object.keys(accumulated.featureFlags).length > 0 ? { feature_flags: accumulated.featureFlags } : {},
|
|
670
674
|
attachments: accumulated.attachments,
|
|
671
675
|
is_pending: isPending
|
|
672
676
|
};
|
|
@@ -1292,6 +1296,7 @@ function boundedStringify(value, limit) {
|
|
|
1292
1296
|
}
|
|
1293
1297
|
|
|
1294
1298
|
// src/callback-handler.ts
|
|
1299
|
+
var MESSAGE_CONTENT_CAP = 4096;
|
|
1295
1300
|
var LANGGRAPH_INTERNAL_NAMES = /* @__PURE__ */ new Set([
|
|
1296
1301
|
"LangGraph",
|
|
1297
1302
|
"__start__",
|
|
@@ -1311,7 +1316,7 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1311
1316
|
this.traceShipper = opts.traceShipper;
|
|
1312
1317
|
this.userId = opts.userId;
|
|
1313
1318
|
this.convoId = opts.convoId;
|
|
1314
|
-
this.traceChains = (_a = opts.traceChains) != null ? _a :
|
|
1319
|
+
this.traceChains = (_a = opts.traceChains) != null ? _a : false;
|
|
1315
1320
|
this.traceRetrievers = (_b = opts.traceRetrievers) != null ? _b : true;
|
|
1316
1321
|
this.filterLangGraphInternals = (_c = opts.filterLangGraphInternals) != null ? _c : true;
|
|
1317
1322
|
}
|
|
@@ -1371,9 +1376,20 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1371
1376
|
name: "llm",
|
|
1372
1377
|
parent: this.getParent(parentRunId),
|
|
1373
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.
|
|
1374
1384
|
attributes: [
|
|
1375
1385
|
attrString("ai.model.provider", modelId),
|
|
1376
|
-
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
|
+
)
|
|
1377
1393
|
]
|
|
1378
1394
|
});
|
|
1379
1395
|
this.spans.set(runId, span);
|
|
@@ -1393,17 +1409,21 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1393
1409
|
if (this.filterLangGraphInternals && this.spans.has(runId)) return;
|
|
1394
1410
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1395
1411
|
const modelId = getName(llm, runName);
|
|
1412
|
+
const allMessages = messages.flat();
|
|
1396
1413
|
const span = this.traceShipper.startSpan({
|
|
1397
1414
|
name: "llm",
|
|
1398
1415
|
parent: this.getParent(parentRunId),
|
|
1399
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.
|
|
1400
1420
|
attributes: [
|
|
1401
1421
|
attrString("ai.model.provider", modelId),
|
|
1402
|
-
attrString("ai.operationId", "
|
|
1422
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
1423
|
+
attrString("ai.prompt.messages", serializeChatMessages(allMessages))
|
|
1403
1424
|
]
|
|
1404
1425
|
});
|
|
1405
1426
|
this.spans.set(runId, span);
|
|
1406
|
-
const allMessages = messages.flat();
|
|
1407
1427
|
const userMessages = allMessages.filter((m) => {
|
|
1408
1428
|
var _a, _b;
|
|
1409
1429
|
const role = (_b = (_a = m._getType) == null ? void 0 : _a.call(m)) != null ? _b : "unknown";
|
|
@@ -1432,6 +1452,10 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1432
1452
|
this.traceShipper.endSpan(span, {
|
|
1433
1453
|
attributes: [
|
|
1434
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)),
|
|
1435
1459
|
attrInt("ai.usage.prompt_tokens", promptTokens),
|
|
1436
1460
|
attrInt("ai.usage.completion_tokens", completionTokens)
|
|
1437
1461
|
]
|
|
@@ -1516,12 +1540,13 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1516
1540
|
const eventId = this.getEventId(runId, parentRunId);
|
|
1517
1541
|
const toolName = getName(tool, runName);
|
|
1518
1542
|
const span = this.traceShipper.startSpan({
|
|
1519
|
-
name: "
|
|
1543
|
+
name: "ai.toolCall",
|
|
1520
1544
|
parent: this.getParent(parentRunId),
|
|
1521
1545
|
eventId,
|
|
1546
|
+
operationId: "ai.toolCall",
|
|
1522
1547
|
attributes: [
|
|
1523
|
-
attrString("
|
|
1524
|
-
attrString("
|
|
1548
|
+
attrString("ai.toolCall.name", toolName),
|
|
1549
|
+
attrString("ai.toolCall.args", truncate(input, 4096))
|
|
1525
1550
|
]
|
|
1526
1551
|
});
|
|
1527
1552
|
this.spans.set(runId, span);
|
|
@@ -1535,7 +1560,7 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1535
1560
|
if (span) {
|
|
1536
1561
|
const outputStr = typeof output === "string" ? output : safeStringify(output, 4096);
|
|
1537
1562
|
this.traceShipper.endSpan(span, {
|
|
1538
|
-
attributes: [attrString("
|
|
1563
|
+
attributes: [attrString("ai.toolCall.result", truncate(outputStr, 4096))]
|
|
1539
1564
|
});
|
|
1540
1565
|
}
|
|
1541
1566
|
await this.finalizeEventIfRoot(runId);
|
|
@@ -1568,6 +1593,9 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1568
1593
|
name: "retriever",
|
|
1569
1594
|
parent: this.getParent(parentRunId),
|
|
1570
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",
|
|
1571
1599
|
attributes: [
|
|
1572
1600
|
attrString("retriever.name", retrieverName),
|
|
1573
1601
|
attrString("retriever.query", truncate(query, 2048))
|
|
@@ -1615,6 +1643,9 @@ var RaindropCallbackHandler = class extends BaseCallbackHandler {
|
|
|
1615
1643
|
name: "agent_action",
|
|
1616
1644
|
parent: this.getParent(parentRunId),
|
|
1617
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",
|
|
1618
1649
|
attributes: [
|
|
1619
1650
|
attrString("agent.tool", action.tool),
|
|
1620
1651
|
attrString("agent.tool_input", truncate(
|
|
@@ -1669,6 +1700,30 @@ function truncate(str, maxLen) {
|
|
|
1669
1700
|
if (str.length <= maxLen) return str;
|
|
1670
1701
|
return str.slice(0, maxLen - 3) + "...";
|
|
1671
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
|
+
}
|
|
1672
1727
|
function extractLLMMetadata(output) {
|
|
1673
1728
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1674
1729
|
const gen = (_b = (_a = output.generations) == null ? void 0 : _a[0]) == null ? void 0 : _b[0];
|
|
@@ -1689,7 +1744,7 @@ function extractLLMMetadata(output) {
|
|
|
1689
1744
|
// package.json
|
|
1690
1745
|
var package_default = {
|
|
1691
1746
|
name: "@raindrop-ai/langchain",
|
|
1692
|
-
version: "0.0
|
|
1747
|
+
version: "0.1.0",
|
|
1693
1748
|
description: "Raindrop integration for LangChain",
|
|
1694
1749
|
main: "dist/index.js",
|
|
1695
1750
|
module: "dist/index.mjs",
|
|
@@ -1770,7 +1825,8 @@ function createRaindropLangChain(opts) {
|
|
|
1770
1825
|
projectId: opts.projectId,
|
|
1771
1826
|
sdkName: "langchain",
|
|
1772
1827
|
libraryName,
|
|
1773
|
-
libraryVersion
|
|
1828
|
+
libraryVersion,
|
|
1829
|
+
defaultEventName: opts.eventName
|
|
1774
1830
|
});
|
|
1775
1831
|
const traceShipper = new TraceShipper({
|
|
1776
1832
|
writeKey,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raindrop-ai/langchain",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Raindrop integration for LangChain",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"tsup": "^8.4.0",
|
|
32
32
|
"typescript": "^5.3.3",
|
|
33
33
|
"vitest": "^2.1.9",
|
|
34
|
-
"@raindrop-ai/core": "0.
|
|
34
|
+
"@raindrop-ai/core": "0.1.1"
|
|
35
35
|
},
|
|
36
36
|
"tsup": {
|
|
37
37
|
"entry": [
|