@raindrop-ai/deep-agents 0.1.2 → 0.1.4
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 +11 -1
- package/dist/index.d.mts +77 -3
- package/dist/index.d.ts +77 -3
- package/dist/index.js +712 -103
- package/dist/index.mjs +716 -103
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
PROMPT_TOOLS_ATTRIBUTE: () => PROMPT_TOOLS_ATTRIBUTE,
|
|
23
24
|
RaindropDeepAgentsHandler: () => RaindropDeepAgentsHandler,
|
|
24
25
|
createRaindropDeepAgents: () => createRaindropDeepAgents
|
|
25
26
|
});
|
|
@@ -90,7 +91,7 @@ function evalScopeAttributes() {
|
|
|
90
91
|
return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
// ../core/dist/chunk-
|
|
94
|
+
// ../core/dist/chunk-I6TVJQEC.js
|
|
94
95
|
var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
|
|
95
96
|
function state() {
|
|
96
97
|
const holder = globalThis;
|
|
@@ -2077,6 +2078,158 @@ var TraceShipper = class {
|
|
|
2077
2078
|
}
|
|
2078
2079
|
}
|
|
2079
2080
|
};
|
|
2081
|
+
var PROMPT_TOOLS_ATTRIBUTE = "ai.prompt.tools";
|
|
2082
|
+
function isRecord(value) {
|
|
2083
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2084
|
+
}
|
|
2085
|
+
var JSON_SCHEMA_KEYS = [
|
|
2086
|
+
"type",
|
|
2087
|
+
"properties",
|
|
2088
|
+
"$schema",
|
|
2089
|
+
"$ref",
|
|
2090
|
+
"anyOf",
|
|
2091
|
+
"oneOf",
|
|
2092
|
+
"allOf",
|
|
2093
|
+
"enum",
|
|
2094
|
+
"const",
|
|
2095
|
+
"items",
|
|
2096
|
+
"additionalProperties",
|
|
2097
|
+
"required"
|
|
2098
|
+
];
|
|
2099
|
+
function isJsonSchema(value) {
|
|
2100
|
+
if (!isRecord(value)) return false;
|
|
2101
|
+
if (typeof value["~standard"] === "object") return false;
|
|
2102
|
+
if (isRecord(value._def) || isRecord(value._zod)) return false;
|
|
2103
|
+
if (Object.keys(value).length === 0) return true;
|
|
2104
|
+
return JSON_SCHEMA_KEYS.some((key) => key in value);
|
|
2105
|
+
}
|
|
2106
|
+
function toJsonSchema(value, options) {
|
|
2107
|
+
if (value === void 0 || value === null) return void 0;
|
|
2108
|
+
if (isJsonSchema(value)) return value;
|
|
2109
|
+
if (isRecord(value) && isJsonSchema(value.jsonSchema)) return value.jsonSchema;
|
|
2110
|
+
if (isRecord(value) && isJsonSchema(value.json)) return value.json;
|
|
2111
|
+
if (options == null ? void 0 : options.schema) {
|
|
2112
|
+
try {
|
|
2113
|
+
return options.schema(value);
|
|
2114
|
+
} catch (e) {
|
|
2115
|
+
return void 0;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
return void 0;
|
|
2119
|
+
}
|
|
2120
|
+
function pickString(value) {
|
|
2121
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2122
|
+
}
|
|
2123
|
+
function functionTool(name, description, schema, options) {
|
|
2124
|
+
const tool = { type: "function", name };
|
|
2125
|
+
const desc = pickString(description);
|
|
2126
|
+
if (desc !== void 0) tool.description = desc;
|
|
2127
|
+
const inputSchema = toJsonSchema(schema, options);
|
|
2128
|
+
if (inputSchema !== void 0) tool.inputSchema = inputSchema;
|
|
2129
|
+
return tool;
|
|
2130
|
+
}
|
|
2131
|
+
function normalizeToolDeclaration(tool, options, fallbackName) {
|
|
2132
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2133
|
+
if (!isRecord(tool)) return void 0;
|
|
2134
|
+
if (tool.type === "provider-defined" || tool.type === "provider") {
|
|
2135
|
+
const name2 = (_b = (_a = pickString(tool.name)) != null ? _a : pickString(tool.id)) != null ? _b : fallbackName;
|
|
2136
|
+
if (name2 === void 0) return void 0;
|
|
2137
|
+
const declaration = { type: "provider-defined", name: name2 };
|
|
2138
|
+
const id = pickString(tool.id);
|
|
2139
|
+
if (id !== void 0) declaration.id = id;
|
|
2140
|
+
if (isRecord(tool.args)) declaration.args = tool.args;
|
|
2141
|
+
return declaration;
|
|
2142
|
+
}
|
|
2143
|
+
if (isRecord(tool.toolSpec)) {
|
|
2144
|
+
const spec = tool.toolSpec;
|
|
2145
|
+
const name2 = (_c = pickString(spec.name)) != null ? _c : fallbackName;
|
|
2146
|
+
if (name2 === void 0) return void 0;
|
|
2147
|
+
return functionTool(name2, spec.description, spec.inputSchema, options);
|
|
2148
|
+
}
|
|
2149
|
+
if (isRecord(tool.function)) {
|
|
2150
|
+
const fn = tool.function;
|
|
2151
|
+
const name2 = (_d = pickString(fn.name)) != null ? _d : fallbackName;
|
|
2152
|
+
if (name2 === void 0) return void 0;
|
|
2153
|
+
return functionTool(name2, fn.description, (_e = fn.parameters) != null ? _e : fn.input_schema, options);
|
|
2154
|
+
}
|
|
2155
|
+
const name = (_g = (_f = pickString(tool.name)) != null ? _f : pickString(tool.id)) != null ? _g : fallbackName;
|
|
2156
|
+
if (name === void 0) return void 0;
|
|
2157
|
+
const type = pickString(tool.type);
|
|
2158
|
+
if (type !== void 0 && type !== "function" && type !== "dynamic" && type !== "custom") {
|
|
2159
|
+
if (!("input_schema" in tool) && !("inputSchema" in tool) && !("parameters" in tool)) {
|
|
2160
|
+
return { type: "provider-defined", id: type, name };
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
return functionTool(
|
|
2164
|
+
name,
|
|
2165
|
+
tool.description,
|
|
2166
|
+
(_j = (_i = (_h = tool.inputSchema) != null ? _h : tool.input_schema) != null ? _i : tool.parameters) != null ? _j : tool.schema,
|
|
2167
|
+
options
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
var NOT_A_GEMINI_GROUP_KEYS = ["name", "id", "type", "function", "toolSpec", "cachePoint"];
|
|
2171
|
+
function isGeminiToolGroup(tool) {
|
|
2172
|
+
if (Array.isArray(tool.functionDeclarations)) return true;
|
|
2173
|
+
const keys = Object.keys(tool);
|
|
2174
|
+
if (keys.length === 0 || NOT_A_GEMINI_GROUP_KEYS.some((key) => key in tool)) return false;
|
|
2175
|
+
return keys.every((key) => isRecord(tool[key]));
|
|
2176
|
+
}
|
|
2177
|
+
function expandGeminiTool(tool, options) {
|
|
2178
|
+
const declarations = [];
|
|
2179
|
+
for (const [key, value] of Object.entries(tool)) {
|
|
2180
|
+
if (key === "functionDeclarations" && Array.isArray(value)) {
|
|
2181
|
+
for (const declaration of value) {
|
|
2182
|
+
const normalized = normalizeToolDeclaration(declaration, options);
|
|
2183
|
+
if (normalized) declarations.push(normalized);
|
|
2184
|
+
}
|
|
2185
|
+
} else if (isRecord(value)) {
|
|
2186
|
+
declarations.push({ type: "provider-defined", id: key, name: key, args: value });
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
return declarations;
|
|
2190
|
+
}
|
|
2191
|
+
function normalizeToolDeclarations(tools, options) {
|
|
2192
|
+
if (tools === void 0 || tools === null) return void 0;
|
|
2193
|
+
if (Array.isArray(tools)) {
|
|
2194
|
+
return tools.flatMap((tool) => {
|
|
2195
|
+
if (isRecord(tool) && isGeminiToolGroup(tool)) {
|
|
2196
|
+
return expandGeminiTool(tool, options);
|
|
2197
|
+
}
|
|
2198
|
+
const declaration = normalizeToolDeclaration(tool, options);
|
|
2199
|
+
return declaration ? [declaration] : [];
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2202
|
+
if (!isRecord(tools)) return void 0;
|
|
2203
|
+
return Object.entries(tools).flatMap(([key, tool]) => {
|
|
2204
|
+
const declaration = normalizeToolDeclaration(tool, options, key);
|
|
2205
|
+
return declaration ? [declaration] : [];
|
|
2206
|
+
});
|
|
2207
|
+
}
|
|
2208
|
+
function resolvePromptTools(args) {
|
|
2209
|
+
var _a;
|
|
2210
|
+
if (args.override !== void 0) {
|
|
2211
|
+
return (_a = normalizeToolDeclarations(args.override, args.options)) != null ? _a : [];
|
|
2212
|
+
}
|
|
2213
|
+
return normalizeToolDeclarations(args.inferred, args.options);
|
|
2214
|
+
}
|
|
2215
|
+
function promptToolsAttribute(tools) {
|
|
2216
|
+
const values = promptToolsAttributeValue(tools);
|
|
2217
|
+
if (values === void 0) return void 0;
|
|
2218
|
+
return {
|
|
2219
|
+
key: PROMPT_TOOLS_ATTRIBUTE,
|
|
2220
|
+
value: { arrayValue: { values: values.map((stringValue) => ({ stringValue })) } }
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
function promptToolsAttributeValue(tools) {
|
|
2224
|
+
if (tools === void 0) return void 0;
|
|
2225
|
+
return tools.map((tool) => {
|
|
2226
|
+
try {
|
|
2227
|
+
return JSON.stringify(tool);
|
|
2228
|
+
} catch (e) {
|
|
2229
|
+
return JSON.stringify({ type: tool.type, name: tool.name });
|
|
2230
|
+
}
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2080
2233
|
|
|
2081
2234
|
// ../core/dist/index.node.js
|
|
2082
2235
|
var import_async_hooks = require("async_hooks");
|
|
@@ -2252,7 +2405,470 @@ function installTracingSuppressionHook() {
|
|
|
2252
2405
|
}
|
|
2253
2406
|
installTracingSuppressionHook();
|
|
2254
2407
|
|
|
2408
|
+
// src/conversation.ts
|
|
2409
|
+
var import_messages = require("@langchain/core/messages");
|
|
2410
|
+
|
|
2411
|
+
// src/truncation.ts
|
|
2412
|
+
var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
|
|
2413
|
+
var DEFAULT_MAX_TEXT_FIELD_CHARS2 = 1e6;
|
|
2414
|
+
var MAX_DEPTH = 12;
|
|
2415
|
+
var configuredMaxTextFieldChars;
|
|
2416
|
+
function setMaxTextFieldChars(limit) {
|
|
2417
|
+
if (limit === void 0) return;
|
|
2418
|
+
if (typeof limit === "number" && Number.isFinite(limit) && limit > 0) {
|
|
2419
|
+
configuredMaxTextFieldChars = Math.floor(limit);
|
|
2420
|
+
} else {
|
|
2421
|
+
console.warn(`[raindrop-ai] maxTextFieldChars=${String(limit)} ignored; must be > 0`);
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
function otelEnvLimit() {
|
|
2425
|
+
if (typeof process === "undefined") return void 0;
|
|
2426
|
+
const raw = process.env?.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
|
|
2427
|
+
if (!raw) return void 0;
|
|
2428
|
+
const parsed = Number.parseInt(raw, 10);
|
|
2429
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
2430
|
+
}
|
|
2431
|
+
function eventMaxTextFieldChars() {
|
|
2432
|
+
return configuredMaxTextFieldChars ?? DEFAULT_MAX_TEXT_FIELD_CHARS2;
|
|
2433
|
+
}
|
|
2434
|
+
function spanAttributeLimit(limit) {
|
|
2435
|
+
const env = otelEnvLimit();
|
|
2436
|
+
return env !== void 0 && env < limit ? env : limit;
|
|
2437
|
+
}
|
|
2438
|
+
function effectiveMaxTextFieldChars() {
|
|
2439
|
+
return spanAttributeLimit(eventMaxTextFieldChars());
|
|
2440
|
+
}
|
|
2441
|
+
function truncateToLimit2(text, limit) {
|
|
2442
|
+
if (limit > TRUNCATION_MARKER2.length) {
|
|
2443
|
+
return text.slice(0, limit - TRUNCATION_MARKER2.length) + TRUNCATION_MARKER2;
|
|
2444
|
+
}
|
|
2445
|
+
return text.slice(0, limit);
|
|
2446
|
+
}
|
|
2447
|
+
function capText2(value, limit) {
|
|
2448
|
+
if (typeof value !== "string") return value;
|
|
2449
|
+
const max = limit ?? effectiveMaxTextFieldChars();
|
|
2450
|
+
if (value.length <= max) return value;
|
|
2451
|
+
return truncateToLimit2(value, max);
|
|
2452
|
+
}
|
|
2453
|
+
function boundedClone2(value, budget, depth) {
|
|
2454
|
+
if (budget.remaining <= 0) return TRUNCATION_MARKER2;
|
|
2455
|
+
if (typeof value === "string") {
|
|
2456
|
+
if (value.length > budget.remaining) {
|
|
2457
|
+
const taken = value.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2458
|
+
budget.remaining = 0;
|
|
2459
|
+
return taken;
|
|
2460
|
+
}
|
|
2461
|
+
budget.remaining -= Math.max(value.length, 1);
|
|
2462
|
+
return value;
|
|
2463
|
+
}
|
|
2464
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
2465
|
+
budget.remaining -= 8;
|
|
2466
|
+
return value;
|
|
2467
|
+
}
|
|
2468
|
+
if (typeof value === "bigint") return boundedClone2(value.toString(), budget, depth);
|
|
2469
|
+
if (typeof value !== "object") {
|
|
2470
|
+
budget.remaining -= 1;
|
|
2471
|
+
return value;
|
|
2472
|
+
}
|
|
2473
|
+
if (value instanceof Uint8Array) {
|
|
2474
|
+
const maxBytes = Math.max(0, Math.ceil(budget.remaining * 3 / 4));
|
|
2475
|
+
if (value.byteLength > maxBytes) {
|
|
2476
|
+
const taken = base64Encode(value.subarray(0, maxBytes)) + TRUNCATION_MARKER2;
|
|
2477
|
+
budget.remaining = 0;
|
|
2478
|
+
return taken;
|
|
2479
|
+
}
|
|
2480
|
+
const encoded = base64Encode(value);
|
|
2481
|
+
budget.remaining -= Math.max(encoded.length, 1);
|
|
2482
|
+
return encoded;
|
|
2483
|
+
}
|
|
2484
|
+
if (depth >= MAX_DEPTH) {
|
|
2485
|
+
budget.remaining -= 16;
|
|
2486
|
+
const name = value.constructor?.name ?? "object";
|
|
2487
|
+
return `<max depth: ${name}>`;
|
|
2488
|
+
}
|
|
2489
|
+
const toJSON = value.toJSON;
|
|
2490
|
+
if (typeof toJSON === "function") {
|
|
2491
|
+
budget.remaining -= 2;
|
|
2492
|
+
return boundedClone2(toJSON.call(value), budget, depth + 1);
|
|
2493
|
+
}
|
|
2494
|
+
if (Array.isArray(value)) {
|
|
2495
|
+
budget.remaining -= 2;
|
|
2496
|
+
const out2 = [];
|
|
2497
|
+
for (const item of value) {
|
|
2498
|
+
if (budget.remaining <= 0) {
|
|
2499
|
+
out2.push(TRUNCATION_MARKER2);
|
|
2500
|
+
break;
|
|
2501
|
+
}
|
|
2502
|
+
out2.push(boundedClone2(item, budget, depth + 1));
|
|
2503
|
+
}
|
|
2504
|
+
return out2;
|
|
2505
|
+
}
|
|
2506
|
+
budget.remaining -= 2;
|
|
2507
|
+
const out = {};
|
|
2508
|
+
for (const key in value) {
|
|
2509
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
|
|
2510
|
+
if (budget.remaining <= 0) {
|
|
2511
|
+
out["..."] = TRUNCATION_MARKER2;
|
|
2512
|
+
break;
|
|
2513
|
+
}
|
|
2514
|
+
let cappedKey = key;
|
|
2515
|
+
if (key.length > budget.remaining) {
|
|
2516
|
+
cappedKey = key.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2517
|
+
budget.remaining = 0;
|
|
2518
|
+
out[cappedKey] = TRUNCATION_MARKER2;
|
|
2519
|
+
break;
|
|
2520
|
+
}
|
|
2521
|
+
budget.remaining -= Math.max(key.length, 1);
|
|
2522
|
+
out[cappedKey] = boundedClone2(value[key], budget, depth + 1);
|
|
2523
|
+
}
|
|
2524
|
+
return out;
|
|
2525
|
+
}
|
|
2526
|
+
function boundedStringify(value, limit) {
|
|
2527
|
+
const max = limit ?? effectiveMaxTextFieldChars();
|
|
2528
|
+
try {
|
|
2529
|
+
if (typeof value === "string") {
|
|
2530
|
+
const text2 = JSON.stringify(capText2(value, max));
|
|
2531
|
+
return text2.length <= max ? text2 : truncateToLimit2(text2, max);
|
|
2532
|
+
}
|
|
2533
|
+
const pruned = boundedClone2(value, { remaining: max + TRUNCATION_MARKER2.length + 256 }, 0);
|
|
2534
|
+
const text = JSON.stringify(pruned);
|
|
2535
|
+
if (text === void 0) return void 0;
|
|
2536
|
+
return text.length <= max ? text : truncateToLimit2(text, max);
|
|
2537
|
+
} catch {
|
|
2538
|
+
return void 0;
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
// src/conversation.ts
|
|
2543
|
+
var CAPTURE_TRUNCATED_ROLE = "raindrop";
|
|
2544
|
+
var MESSAGE_OVERHEAD = 32;
|
|
2545
|
+
var PART_OVERHEAD = 24;
|
|
2546
|
+
var MAX_DEPTH2 = 12;
|
|
2547
|
+
function isRecord2(value) {
|
|
2548
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2549
|
+
}
|
|
2550
|
+
function stringField(record, key) {
|
|
2551
|
+
const value = record[key];
|
|
2552
|
+
return typeof value === "string" ? value : void 0;
|
|
2553
|
+
}
|
|
2554
|
+
function takeText(text, budget) {
|
|
2555
|
+
if (text.length > budget.remaining) {
|
|
2556
|
+
const kept = text.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2557
|
+
budget.remaining = 0;
|
|
2558
|
+
budget.truncated = true;
|
|
2559
|
+
return kept;
|
|
2560
|
+
}
|
|
2561
|
+
budget.remaining -= Math.max(text.length, 1);
|
|
2562
|
+
return text;
|
|
2563
|
+
}
|
|
2564
|
+
function reserve(text, budget) {
|
|
2565
|
+
if (text !== void 0) budget.remaining -= Math.max(text.length, 1);
|
|
2566
|
+
return text;
|
|
2567
|
+
}
|
|
2568
|
+
function takeValue(value, budget, depth) {
|
|
2569
|
+
if (typeof value === "string") return takeText(value, budget);
|
|
2570
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
2571
|
+
budget.remaining -= 8;
|
|
2572
|
+
return value;
|
|
2573
|
+
}
|
|
2574
|
+
if (typeof value !== "object") {
|
|
2575
|
+
budget.remaining -= 1;
|
|
2576
|
+
return value;
|
|
2577
|
+
}
|
|
2578
|
+
if (depth >= MAX_DEPTH2) {
|
|
2579
|
+
budget.remaining -= TRUNCATION_MARKER2.length;
|
|
2580
|
+
budget.truncated = true;
|
|
2581
|
+
return TRUNCATION_MARKER2;
|
|
2582
|
+
}
|
|
2583
|
+
if ("toJSON" in value && typeof value.toJSON === "function") {
|
|
2584
|
+
return takeValue(value.toJSON(), budget, depth + 1);
|
|
2585
|
+
}
|
|
2586
|
+
if (Array.isArray(value)) {
|
|
2587
|
+
budget.remaining -= 2;
|
|
2588
|
+
const out2 = [];
|
|
2589
|
+
for (const item of value) {
|
|
2590
|
+
if (budget.remaining <= 0) {
|
|
2591
|
+
budget.truncated = true;
|
|
2592
|
+
out2.push(TRUNCATION_MARKER2);
|
|
2593
|
+
break;
|
|
2594
|
+
}
|
|
2595
|
+
out2.push(takeValue(item, budget, depth + 1));
|
|
2596
|
+
}
|
|
2597
|
+
return out2;
|
|
2598
|
+
}
|
|
2599
|
+
budget.remaining -= 2;
|
|
2600
|
+
const out = {};
|
|
2601
|
+
if (!isRecord2(value)) return out;
|
|
2602
|
+
for (const key in value) {
|
|
2603
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
|
|
2604
|
+
if (budget.remaining <= 0) {
|
|
2605
|
+
budget.truncated = true;
|
|
2606
|
+
out["..."] = TRUNCATION_MARKER2;
|
|
2607
|
+
break;
|
|
2608
|
+
}
|
|
2609
|
+
budget.remaining -= Math.max(key.length, 1);
|
|
2610
|
+
out[key] = takeValue(value[key], budget, depth + 1);
|
|
2611
|
+
}
|
|
2612
|
+
return out;
|
|
2613
|
+
}
|
|
2614
|
+
function messageType(message) {
|
|
2615
|
+
return typeof message._getType === "function" ? message._getType() : void 0;
|
|
2616
|
+
}
|
|
2617
|
+
function textPart(text, budget) {
|
|
2618
|
+
return { type: "text", text: takeText(text, budget) };
|
|
2619
|
+
}
|
|
2620
|
+
function joinedText(content, budget) {
|
|
2621
|
+
const texts = [];
|
|
2622
|
+
for (const block of content) {
|
|
2623
|
+
if (budget.remaining <= 0) {
|
|
2624
|
+
budget.truncated = true;
|
|
2625
|
+
texts.push(TRUNCATION_MARKER2);
|
|
2626
|
+
break;
|
|
2627
|
+
}
|
|
2628
|
+
budget.remaining -= 1;
|
|
2629
|
+
if (!isRecord2(block)) continue;
|
|
2630
|
+
const text = stringField(block, "text");
|
|
2631
|
+
if (text !== void 0) texts.push(takeText(text, budget));
|
|
2632
|
+
}
|
|
2633
|
+
return texts.join("\n");
|
|
2634
|
+
}
|
|
2635
|
+
function contentPart(block, budget) {
|
|
2636
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2637
|
+
if (!isRecord2(block)) return takeValue(block, budget, 0);
|
|
2638
|
+
const type = stringField(block, "type");
|
|
2639
|
+
const text = stringField(block, "text");
|
|
2640
|
+
if (type === "text" && text !== void 0) return textPart(text, budget);
|
|
2641
|
+
if (type === "image_url") {
|
|
2642
|
+
const imageUrl = block["image_url"];
|
|
2643
|
+
const url = typeof imageUrl === "string" ? imageUrl : isRecord2(imageUrl) ? stringField(imageUrl, "url") : void 0;
|
|
2644
|
+
if (url !== void 0) return { type: "image", image: takeText(url, budget) };
|
|
2645
|
+
}
|
|
2646
|
+
if (type === "thinking") {
|
|
2647
|
+
const thinking = stringField(block, "thinking");
|
|
2648
|
+
if (thinking !== void 0) return { type: "reasoning", text: takeText(thinking, budget) };
|
|
2649
|
+
}
|
|
2650
|
+
if (type === "image" || type === "file" || type === "audio") {
|
|
2651
|
+
const mediaType = stringField(block, "mime_type");
|
|
2652
|
+
const sourceType = stringField(block, "source_type");
|
|
2653
|
+
const source = block["source"];
|
|
2654
|
+
if (sourceType === "text" && text !== void 0) return textPart(text, budget);
|
|
2655
|
+
const data = sourceType === "url" ? stringField(block, "url") : sourceType === "base64" ? stringField(block, "data") : isRecord2(source) ? stringField(source, "url") ?? stringField(source, "data") : void 0;
|
|
2656
|
+
const sourceMediaType = mediaType ?? (isRecord2(source) ? stringField(source, "media_type") : void 0);
|
|
2657
|
+
if (data !== void 0) {
|
|
2658
|
+
const filename = stringField(block, "filename");
|
|
2659
|
+
return type === "image" ? { type: "image", image: takeText(data, budget), mediaType: reserve(sourceMediaType, budget) } : {
|
|
2660
|
+
type: "file",
|
|
2661
|
+
data: takeText(data, budget),
|
|
2662
|
+
mediaType: reserve(sourceMediaType, budget),
|
|
2663
|
+
filename: reserve(filename, budget)
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
return takeValue(block, budget, 0);
|
|
2668
|
+
}
|
|
2669
|
+
function contentParts(content, budget, skipToolUseIds) {
|
|
2670
|
+
const parts = [];
|
|
2671
|
+
for (const block of content) {
|
|
2672
|
+
if (budget.remaining <= 0) {
|
|
2673
|
+
budget.truncated = true;
|
|
2674
|
+
parts.push({ type: "text", text: TRUNCATION_MARKER2 });
|
|
2675
|
+
break;
|
|
2676
|
+
}
|
|
2677
|
+
if (isRecord2(block) && (block["type"] === "tool_use" || block["type"] === "tool_call")) {
|
|
2678
|
+
const id = stringField(block, "id");
|
|
2679
|
+
if (id !== void 0 && skipToolUseIds.has(id)) continue;
|
|
2680
|
+
}
|
|
2681
|
+
parts.push(contentPart(block, budget));
|
|
2682
|
+
}
|
|
2683
|
+
return parts;
|
|
2684
|
+
}
|
|
2685
|
+
function assistantMessage(message, budget, toolNames) {
|
|
2686
|
+
const toolCalls = (0, import_messages.isAIMessage)(message) ? message.tool_calls ?? [] : [];
|
|
2687
|
+
if (toolCalls.length === 0 && typeof message.content === "string") {
|
|
2688
|
+
return { role: "assistant", content: takeText(message.content, budget) };
|
|
2689
|
+
}
|
|
2690
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2691
|
+
const callParts = [];
|
|
2692
|
+
for (const call of toolCalls) {
|
|
2693
|
+
if (budget.remaining <= 0) {
|
|
2694
|
+
budget.truncated = true;
|
|
2695
|
+
callParts.push({ type: "text", text: TRUNCATION_MARKER2 });
|
|
2696
|
+
break;
|
|
2697
|
+
}
|
|
2698
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2699
|
+
if (call.id !== void 0) {
|
|
2700
|
+
ids.add(call.id);
|
|
2701
|
+
toolNames.set(call.id, call.name);
|
|
2702
|
+
}
|
|
2703
|
+
callParts.push({
|
|
2704
|
+
type: "tool-call",
|
|
2705
|
+
toolCallId: reserve(call.id, budget),
|
|
2706
|
+
toolName: reserve(call.name, budget),
|
|
2707
|
+
input: takeValue(call.args, budget, 0)
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
const content = typeof message.content === "string" ? message.content.length > 0 ? [textPart(message.content, budget)] : [] : contentParts(message.content, budget, ids);
|
|
2711
|
+
content.push(...callParts);
|
|
2712
|
+
return { role: "assistant", content };
|
|
2713
|
+
}
|
|
2714
|
+
function toolResultOutput(message, budget) {
|
|
2715
|
+
const failed = (0, import_messages.isToolMessage)(message) && message.status === "error";
|
|
2716
|
+
if (typeof message.content === "string") {
|
|
2717
|
+
return { type: failed ? "error-text" : "text", value: takeText(message.content, budget) };
|
|
2718
|
+
}
|
|
2719
|
+
return { type: "content", value: contentParts(message.content, budget, /* @__PURE__ */ new Set()) };
|
|
2720
|
+
}
|
|
2721
|
+
function toolMessage(message, budget, toolNames) {
|
|
2722
|
+
const toolCallId = (0, import_messages.isToolMessage)(message) ? message.tool_call_id : void 0;
|
|
2723
|
+
const toolName = message.name ?? (toolCallId !== void 0 ? toolNames.get(toolCallId) : void 0);
|
|
2724
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2725
|
+
return {
|
|
2726
|
+
role: "tool",
|
|
2727
|
+
content: [{
|
|
2728
|
+
type: "tool-result",
|
|
2729
|
+
toolCallId: reserve(toolCallId, budget),
|
|
2730
|
+
toolName: reserve(toolName, budget),
|
|
2731
|
+
output: toolResultOutput(message, budget)
|
|
2732
|
+
}]
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
function modelMessage(message, budget, toolNames) {
|
|
2736
|
+
budget.remaining -= MESSAGE_OVERHEAD;
|
|
2737
|
+
switch (messageType(message)) {
|
|
2738
|
+
case "system":
|
|
2739
|
+
return {
|
|
2740
|
+
role: "system",
|
|
2741
|
+
content: typeof message.content === "string" ? takeText(message.content, budget) : joinedText(message.content, budget)
|
|
2742
|
+
};
|
|
2743
|
+
case "ai":
|
|
2744
|
+
return assistantMessage(message, budget, toolNames);
|
|
2745
|
+
case "tool":
|
|
2746
|
+
case "function":
|
|
2747
|
+
return toolMessage(message, budget, toolNames);
|
|
2748
|
+
case "generic": {
|
|
2749
|
+
const role = (0, import_messages.isChatMessage)(message) ? message.role : void 0;
|
|
2750
|
+
if (role === "assistant" || role === "system") {
|
|
2751
|
+
return {
|
|
2752
|
+
role,
|
|
2753
|
+
content: typeof message.content === "string" ? takeText(message.content, budget) : joinedText(message.content, budget)
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
return userMessage(message, budget);
|
|
2757
|
+
}
|
|
2758
|
+
default:
|
|
2759
|
+
return userMessage(message, budget);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
function userMessage(message, budget) {
|
|
2763
|
+
return {
|
|
2764
|
+
role: "user",
|
|
2765
|
+
content: typeof message.content === "string" ? takeText(message.content, budget) : contentParts(message.content, budget, /* @__PURE__ */ new Set())
|
|
2766
|
+
};
|
|
2767
|
+
}
|
|
2768
|
+
function truncationRecord(omittedMessages) {
|
|
2769
|
+
return { role: CAPTURE_TRUNCATED_ROLE, truncated: true, marker: TRUNCATION_MARKER2, omittedMessages };
|
|
2770
|
+
}
|
|
2771
|
+
function encodeWithinLimit(items, limit, overflow, convert) {
|
|
2772
|
+
let textBudget = limit;
|
|
2773
|
+
for (let attempt = 0; attempt < 8 && textBudget >= 64; attempt++) {
|
|
2774
|
+
const budget = { remaining: textBudget, truncated: false };
|
|
2775
|
+
const out = [];
|
|
2776
|
+
let omitted = 0;
|
|
2777
|
+
for (let i = 0; i < items.length; i++) {
|
|
2778
|
+
if (overflow === "omit" && budget.remaining <= 0) {
|
|
2779
|
+
omitted = items.length - i;
|
|
2780
|
+
break;
|
|
2781
|
+
}
|
|
2782
|
+
out.push(convert(items[i], budget));
|
|
2783
|
+
}
|
|
2784
|
+
const truncated = budget.truncated || omitted > 0;
|
|
2785
|
+
if (truncated && overflow === "omit") out.push(truncationRecord(omitted));
|
|
2786
|
+
const json2 = JSON.stringify(out);
|
|
2787
|
+
if (json2.length <= limit) return { json: json2, truncated };
|
|
2788
|
+
const excess = json2.length - limit + 128;
|
|
2789
|
+
textBudget = Math.max(textBudget - excess, Math.floor(textBudget / 2));
|
|
2790
|
+
}
|
|
2791
|
+
if (overflow === "keep") return void 0;
|
|
2792
|
+
const json = JSON.stringify([truncationRecord(items.length)]);
|
|
2793
|
+
return json.length <= limit ? { json, truncated: true } : void 0;
|
|
2794
|
+
}
|
|
2795
|
+
function captureConversation(messages, limit) {
|
|
2796
|
+
if (messages.length === 0) return void 0;
|
|
2797
|
+
try {
|
|
2798
|
+
const toolNames = /* @__PURE__ */ new Map();
|
|
2799
|
+
return encodeWithinLimit(
|
|
2800
|
+
messages,
|
|
2801
|
+
limit,
|
|
2802
|
+
"omit",
|
|
2803
|
+
(message, budget) => modelMessage(message, budget, toolNames)
|
|
2804
|
+
);
|
|
2805
|
+
} catch {
|
|
2806
|
+
return void 0;
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
function capturePrompt(prompt, limit) {
|
|
2810
|
+
try {
|
|
2811
|
+
return encodeWithinLimit([prompt], limit, "omit", (text, budget) => {
|
|
2812
|
+
budget.remaining -= MESSAGE_OVERHEAD;
|
|
2813
|
+
return { role: "user", content: takeText(text, budget) };
|
|
2814
|
+
});
|
|
2815
|
+
} catch {
|
|
2816
|
+
return void 0;
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
function captureToolCalls(message, limit) {
|
|
2820
|
+
if (!isRecord2(message) || !Array.isArray(message["tool_calls"])) return void 0;
|
|
2821
|
+
const calls = [];
|
|
2822
|
+
let structural = 0;
|
|
2823
|
+
for (const call of message["tool_calls"]) {
|
|
2824
|
+
structural += PART_OVERHEAD;
|
|
2825
|
+
if (isRecord2(call)) {
|
|
2826
|
+
structural += (stringField(call, "id")?.length ?? 0) + (stringField(call, "name")?.length ?? 0);
|
|
2827
|
+
calls.push(call);
|
|
2828
|
+
}
|
|
2829
|
+
if (structural > limit) return void 0;
|
|
2830
|
+
}
|
|
2831
|
+
if (calls.length === 0) return void 0;
|
|
2832
|
+
try {
|
|
2833
|
+
return encodeWithinLimit(calls, limit, "keep", (call, budget) => {
|
|
2834
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2835
|
+
return {
|
|
2836
|
+
toolCallId: reserve(stringField(call, "id"), budget),
|
|
2837
|
+
toolName: reserve(stringField(call, "name"), budget),
|
|
2838
|
+
input: takeValue(call["args"], budget, 0)
|
|
2839
|
+
};
|
|
2840
|
+
});
|
|
2841
|
+
} catch {
|
|
2842
|
+
return void 0;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
function parseToolCallInput(input) {
|
|
2846
|
+
try {
|
|
2847
|
+
const parsed = JSON.parse(input);
|
|
2848
|
+
if (isRecord2(parsed) && parsed["type"] === "tool_call" && "args" in parsed) {
|
|
2849
|
+
return { id: stringField(parsed, "id"), args: JSON.stringify(parsed["args"]) };
|
|
2850
|
+
}
|
|
2851
|
+
} catch {
|
|
2852
|
+
}
|
|
2853
|
+
return { args: input };
|
|
2854
|
+
}
|
|
2855
|
+
function unwrapToolOutput(output) {
|
|
2856
|
+
if ((0, import_messages.isBaseMessage)(output)) {
|
|
2857
|
+
return {
|
|
2858
|
+
content: output.content,
|
|
2859
|
+
toolCallId: (0, import_messages.isToolMessage)(output) ? output.tool_call_id : void 0
|
|
2860
|
+
};
|
|
2861
|
+
}
|
|
2862
|
+
return { content: output };
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2255
2865
|
// src/callback-handler.ts
|
|
2866
|
+
function inferInvocationTools(extraParams) {
|
|
2867
|
+
const params = extraParams?.invocation_params;
|
|
2868
|
+
if (typeof params !== "object" || params === null) return void 0;
|
|
2869
|
+
const record = { ...params };
|
|
2870
|
+
return record.tools ?? record.functions;
|
|
2871
|
+
}
|
|
2256
2872
|
function resolveEventId(source) {
|
|
2257
2873
|
if (typeof source !== "function") return randomUUID();
|
|
2258
2874
|
try {
|
|
@@ -2269,32 +2885,38 @@ function isInternalName(name) {
|
|
|
2269
2885
|
if (name.startsWith("__") && name.endsWith("__")) return true;
|
|
2270
2886
|
return false;
|
|
2271
2887
|
}
|
|
2272
|
-
|
|
2273
|
-
function extractTextFromContent(content) {
|
|
2888
|
+
function extractTextFromContent(content, limit) {
|
|
2274
2889
|
if (content == null) return void 0;
|
|
2275
2890
|
if (typeof content === "string") return content;
|
|
2276
2891
|
if (Array.isArray(content)) {
|
|
2277
2892
|
const parts = [];
|
|
2893
|
+
let length = 0;
|
|
2278
2894
|
for (const part of content) {
|
|
2895
|
+
if (length > limit) break;
|
|
2896
|
+
length += 1;
|
|
2897
|
+
let text;
|
|
2279
2898
|
if (typeof part === "string") {
|
|
2280
|
-
|
|
2899
|
+
text = part;
|
|
2281
2900
|
} else if (part && typeof part === "object") {
|
|
2282
2901
|
const p = part;
|
|
2283
2902
|
if (typeof p.text === "string") {
|
|
2284
|
-
|
|
2903
|
+
text = p.text;
|
|
2285
2904
|
} else if (p.type === "text" && typeof p.content === "string") {
|
|
2286
|
-
|
|
2905
|
+
text = p.content;
|
|
2287
2906
|
}
|
|
2288
2907
|
}
|
|
2908
|
+
if (text === void 0) continue;
|
|
2909
|
+
parts.push(text.length > limit ? text.slice(0, limit + 1) : text);
|
|
2910
|
+
length += Math.max(text.length, 1);
|
|
2289
2911
|
}
|
|
2290
2912
|
if (parts.length > 0) return parts.join("\n");
|
|
2291
|
-
return
|
|
2913
|
+
return boundedStringify(content, limit);
|
|
2292
2914
|
}
|
|
2293
2915
|
if (typeof content === "object") {
|
|
2294
2916
|
const c = content;
|
|
2295
2917
|
if (typeof c.text === "string") return c.text;
|
|
2296
2918
|
if (typeof c.content === "string") return c.content;
|
|
2297
|
-
return
|
|
2919
|
+
return boundedStringify(content, limit);
|
|
2298
2920
|
}
|
|
2299
2921
|
return String(content);
|
|
2300
2922
|
}
|
|
@@ -2313,6 +2935,17 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2313
2935
|
this.eventName = opts.eventName;
|
|
2314
2936
|
this.eventIdSource = opts.eventId;
|
|
2315
2937
|
this.traceChains = opts.traceChains ?? true;
|
|
2938
|
+
this.configuredSpanMaxChars = opts.maxTextFieldChars ?? eventMaxTextFieldChars();
|
|
2939
|
+
this.eventMaxChars = opts.eventMaxTextFieldChars ?? eventMaxTextFieldChars();
|
|
2940
|
+
this.promptTools = opts.tools;
|
|
2941
|
+
}
|
|
2942
|
+
promptToolsAttribute(extraParams) {
|
|
2943
|
+
return promptToolsAttribute(
|
|
2944
|
+
resolvePromptTools({ override: this.promptTools, inferred: inferInvocationTools(extraParams) })
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
get spanMaxChars() {
|
|
2948
|
+
return spanAttributeLimit(this.configuredSpanMaxChars);
|
|
2316
2949
|
}
|
|
2317
2950
|
getEventId(runId, parentRunId) {
|
|
2318
2951
|
const rootId = parentRunId ? this.rootRunIds.get(parentRunId) ?? parentRunId : runId;
|
|
@@ -2373,18 +3006,27 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2373
3006
|
// ---------------------------------------------------------------------------
|
|
2374
3007
|
// LLM events
|
|
2375
3008
|
// ---------------------------------------------------------------------------
|
|
2376
|
-
async handleLLMStart(llm, prompts, runId, parentRunId,
|
|
3009
|
+
async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
2377
3010
|
try {
|
|
2378
3011
|
if (this.spans.has(runId)) return;
|
|
2379
3012
|
const eventId = this.getEventId(runId, parentRunId);
|
|
2380
3013
|
const modelId = getName(llm, runName);
|
|
3014
|
+
const prompt = prompts[0] ?? "";
|
|
2381
3015
|
const span = this.traceShipper.startSpan({
|
|
2382
3016
|
name: "llm",
|
|
2383
3017
|
parent: this.getParent(parentRunId),
|
|
2384
3018
|
eventId,
|
|
3019
|
+
// `ai.generateText` classifies the span as an LLM generation at ingest
|
|
3020
|
+
// (a bare `llm`/`chat` operationId maps to INTERNAL and is skipped by
|
|
3021
|
+
// the rich-interaction extractor). `ai.prompt.messages` carries the
|
|
3022
|
+
// per-step trajectory so replay can see the history each step ran on.
|
|
3023
|
+
// A batch is a list of independent prompts; the span describes the
|
|
3024
|
+
// first one, whose response `handleLLMEnd` reports (`generations[0][0]`).
|
|
2385
3025
|
attributes: [
|
|
2386
3026
|
attrString("ai.model.provider", modelId),
|
|
2387
|
-
attrString("ai.operationId", "
|
|
3027
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
3028
|
+
...promptAttributes(capturePrompt(prompt, this.spanMaxChars)),
|
|
3029
|
+
this.promptToolsAttribute(extraParams)
|
|
2388
3030
|
]
|
|
2389
3031
|
});
|
|
2390
3032
|
this.spans.set(runId, span);
|
|
@@ -2392,36 +3034,44 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2392
3034
|
userId: this.userId,
|
|
2393
3035
|
convoId: this.convoId,
|
|
2394
3036
|
eventName: this.eventName,
|
|
2395
|
-
input:
|
|
3037
|
+
input: capText2(prompt, this.eventMaxChars),
|
|
2396
3038
|
properties: buildProperties(tags, metadata),
|
|
2397
3039
|
isPending: true
|
|
2398
3040
|
});
|
|
2399
3041
|
} catch {
|
|
2400
3042
|
}
|
|
2401
3043
|
}
|
|
2402
|
-
async handleChatModelStart(llm, messages, runId, parentRunId,
|
|
3044
|
+
async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
2403
3045
|
try {
|
|
2404
3046
|
if (this.spans.has(runId)) return;
|
|
2405
3047
|
const eventId = this.getEventId(runId, parentRunId);
|
|
2406
3048
|
const modelId = getName(llm, runName);
|
|
3049
|
+
const conversation = messages[0] ?? [];
|
|
2407
3050
|
const span = this.traceShipper.startSpan({
|
|
2408
3051
|
name: "llm",
|
|
2409
3052
|
parent: this.getParent(parentRunId),
|
|
2410
3053
|
eventId,
|
|
3054
|
+
// See handleLLMStart: the full history (historical tool calls and
|
|
3055
|
+
// their results included) goes on the span; the event `input` below
|
|
3056
|
+
// stays the latest human message. LangChain batches are a list of
|
|
3057
|
+
// independent conversations; the span describes the first one, the
|
|
3058
|
+
// same member `handleLLMEnd` reports the response of
|
|
3059
|
+
// (`generations[0][0]`), so history and response stay paired.
|
|
2411
3060
|
attributes: [
|
|
2412
3061
|
attrString("ai.model.provider", modelId),
|
|
2413
|
-
attrString("ai.operationId", "
|
|
3062
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
3063
|
+
...promptAttributes(captureConversation(conversation, this.spanMaxChars)),
|
|
3064
|
+
this.promptToolsAttribute(extraParams)
|
|
2414
3065
|
]
|
|
2415
3066
|
});
|
|
2416
3067
|
this.spans.set(runId, span);
|
|
2417
|
-
const
|
|
2418
|
-
const userMessages = allMessages.filter((m) => {
|
|
3068
|
+
const userMessages = conversation.filter((m) => {
|
|
2419
3069
|
const role = m._getType?.() ?? "unknown";
|
|
2420
3070
|
return role === "human";
|
|
2421
3071
|
});
|
|
2422
|
-
const lastMsg = userMessages.length > 0 ? userMessages[userMessages.length - 1] :
|
|
2423
|
-
const extracted = lastMsg ? extractTextFromContent(lastMsg.content) : void 0;
|
|
2424
|
-
const inputText =
|
|
3072
|
+
const lastMsg = userMessages.length > 0 ? userMessages[userMessages.length - 1] : conversation[conversation.length - 1];
|
|
3073
|
+
const extracted = lastMsg ? extractTextFromContent(lastMsg.content, this.eventMaxChars) : void 0;
|
|
3074
|
+
const inputText = capText2(extracted, this.eventMaxChars);
|
|
2425
3075
|
await this.eventShipper.patch(eventId, {
|
|
2426
3076
|
userId: this.userId,
|
|
2427
3077
|
convoId: this.convoId,
|
|
@@ -2444,7 +3094,7 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2444
3094
|
await this.finalizeEventIfRoot(runId);
|
|
2445
3095
|
return;
|
|
2446
3096
|
}
|
|
2447
|
-
const meta = extractLLMMetadata(output);
|
|
3097
|
+
const meta = extractLLMMetadata(output, this.spanMaxChars);
|
|
2448
3098
|
const {
|
|
2449
3099
|
model,
|
|
2450
3100
|
promptTokens,
|
|
@@ -2452,11 +3102,17 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2452
3102
|
cachedTokens,
|
|
2453
3103
|
reasoningTokens,
|
|
2454
3104
|
finishReason,
|
|
2455
|
-
outputText
|
|
3105
|
+
outputText,
|
|
3106
|
+
toolCalls
|
|
2456
3107
|
} = meta;
|
|
2457
3108
|
this.traceShipper.endSpan(span, {
|
|
2458
3109
|
attributes: [
|
|
2459
3110
|
attrString("ai.response.model", model),
|
|
3111
|
+
attrString("ai.response.text", capText2(outputText, this.spanMaxChars)),
|
|
3112
|
+
// Tool calls requested by this step, with the ids the matching
|
|
3113
|
+
// `ai.toolCall` spans and the next step's history carry.
|
|
3114
|
+
attrString("ai.response.toolCalls", toolCalls?.json),
|
|
3115
|
+
attrString("ai.response.toolCalls.truncated", toolCalls?.truncated ? "true" : void 0),
|
|
2460
3116
|
attrInt("ai.usage.prompt_tokens", promptTokens),
|
|
2461
3117
|
attrInt("ai.usage.completion_tokens", completionTokens),
|
|
2462
3118
|
attrInt("ai.usage.cached_tokens", cachedTokens),
|
|
@@ -2468,9 +3124,8 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2468
3124
|
if (cachedTokens != null) properties["ai.usage.cached_tokens"] = cachedTokens;
|
|
2469
3125
|
if (reasoningTokens != null) properties["ai.usage.thoughts_tokens"] = reasoningTokens;
|
|
2470
3126
|
if (finishReason != null) properties["ai.finish_reason"] = finishReason;
|
|
2471
|
-
const cappedOutput = outputText !== void 0 ? truncate(outputText, CHAIN_TEXT_MAX_LEN) : void 0;
|
|
2472
3127
|
await this.finalizeEventIfRoot(runId, {
|
|
2473
|
-
output:
|
|
3128
|
+
output: capText2(outputText, this.eventMaxChars),
|
|
2474
3129
|
model,
|
|
2475
3130
|
usage: { promptTokens, completionTokens },
|
|
2476
3131
|
properties: Object.keys(properties).length > 0 ? properties : void 0
|
|
@@ -2566,14 +3221,16 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2566
3221
|
try {
|
|
2567
3222
|
const eventId = this.getEventId(runId, parentRunId);
|
|
2568
3223
|
const toolName = getName(tool, runName);
|
|
3224
|
+
const toolCall = parseToolCallInput(input);
|
|
2569
3225
|
const span = this.traceShipper.startSpan({
|
|
2570
3226
|
name: "tool",
|
|
2571
3227
|
parent: this.getParent(parentRunId),
|
|
2572
3228
|
eventId,
|
|
2573
3229
|
operationId: "ai.toolCall",
|
|
2574
3230
|
attributes: [
|
|
3231
|
+
attrString("ai.toolCall.id", toolCall.id),
|
|
2575
3232
|
attrString("ai.toolCall.name", toolName),
|
|
2576
|
-
attrString("
|
|
3233
|
+
attrString("ai.toolCall.args", capText2(toolCall.args, this.spanMaxChars))
|
|
2577
3234
|
]
|
|
2578
3235
|
});
|
|
2579
3236
|
this.spans.set(runId, span);
|
|
@@ -2588,9 +3245,14 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2588
3245
|
try {
|
|
2589
3246
|
const span = this.spans.get(runId);
|
|
2590
3247
|
if (span) {
|
|
2591
|
-
const
|
|
3248
|
+
const { content, toolCallId } = unwrapToolOutput(output);
|
|
3249
|
+
const result = typeof content === "string" ? capText2(content, this.spanMaxChars) : boundedStringify(content, this.spanMaxChars);
|
|
3250
|
+
const hasId = span.attributes.some((attr) => attr?.key === "ai.toolCall.id");
|
|
2592
3251
|
this.traceShipper.endSpan(span, {
|
|
2593
|
-
attributes: [
|
|
3252
|
+
attributes: [
|
|
3253
|
+
attrString("ai.toolCall.id", hasId ? void 0 : toolCallId),
|
|
3254
|
+
attrString("ai.toolCall.result", result)
|
|
3255
|
+
]
|
|
2594
3256
|
});
|
|
2595
3257
|
}
|
|
2596
3258
|
await this.finalizeEventIfRoot(runId);
|
|
@@ -2626,10 +3288,10 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
|
|
|
2626
3288
|
operationId: "ai.toolCall",
|
|
2627
3289
|
attributes: [
|
|
2628
3290
|
attrString("ai.toolCall.name", action.tool),
|
|
2629
|
-
attrString(
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
)
|
|
3291
|
+
attrString(
|
|
3292
|
+
"agent.tool_input",
|
|
3293
|
+
typeof action.toolInput === "string" ? capText2(action.toolInput, this.spanMaxChars) : boundedStringify(action.toolInput, this.spanMaxChars)
|
|
3294
|
+
)
|
|
2633
3295
|
]
|
|
2634
3296
|
});
|
|
2635
3297
|
this.spans.set(`${runId}:agent_action`, span);
|
|
@@ -2662,75 +3324,13 @@ function buildProperties(tags, metadata) {
|
|
|
2662
3324
|
if (metadata) Object.assign(props, metadata);
|
|
2663
3325
|
return props;
|
|
2664
3326
|
}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
if (typeof value === "string") {
|
|
2671
|
-
if (value.length > budget.remaining) {
|
|
2672
|
-
const taken = value.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2673
|
-
budget.remaining = 0;
|
|
2674
|
-
return taken;
|
|
2675
|
-
}
|
|
2676
|
-
budget.remaining -= Math.max(value.length, 1);
|
|
2677
|
-
return value;
|
|
2678
|
-
}
|
|
2679
|
-
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
2680
|
-
budget.remaining -= 8;
|
|
2681
|
-
return value;
|
|
2682
|
-
}
|
|
2683
|
-
if (typeof value !== "object") {
|
|
2684
|
-
budget.remaining -= 8;
|
|
2685
|
-
return value;
|
|
2686
|
-
}
|
|
2687
|
-
if (depth >= MAX_BOUNDED_DEPTH) {
|
|
2688
|
-
budget.remaining -= 16;
|
|
2689
|
-
return `<max depth: ${TRUNCATION_MARKER2}>`;
|
|
2690
|
-
}
|
|
2691
|
-
const withToJson = value;
|
|
2692
|
-
if (typeof withToJson.toJSON === "function") {
|
|
2693
|
-
try {
|
|
2694
|
-
return boundedClone2(withToJson.toJSON(), budget, depth + 1);
|
|
2695
|
-
} catch {
|
|
2696
|
-
}
|
|
2697
|
-
}
|
|
2698
|
-
if (Array.isArray(value)) {
|
|
2699
|
-
const out2 = [];
|
|
2700
|
-
for (const item of value) {
|
|
2701
|
-
if (budget.remaining <= 0) {
|
|
2702
|
-
out2.push(TRUNCATION_MARKER2);
|
|
2703
|
-
break;
|
|
2704
|
-
}
|
|
2705
|
-
out2.push(boundedClone2(item, budget, depth + 1));
|
|
2706
|
-
}
|
|
2707
|
-
return out2;
|
|
2708
|
-
}
|
|
2709
|
-
const out = {};
|
|
2710
|
-
for (const key of Object.keys(value)) {
|
|
2711
|
-
if (budget.remaining <= 0) {
|
|
2712
|
-
out["..."] = TRUNCATION_MARKER2;
|
|
2713
|
-
break;
|
|
2714
|
-
}
|
|
2715
|
-
budget.remaining -= Math.max(key.length, 1);
|
|
2716
|
-
out[key] = boundedClone2(value[key], budget, depth + 1);
|
|
2717
|
-
}
|
|
2718
|
-
return out;
|
|
2719
|
-
}
|
|
2720
|
-
function safeStringify(value, limit = MAX_TEXT_FIELD_CHARS) {
|
|
2721
|
-
try {
|
|
2722
|
-
const pruned = boundedClone2(value, { remaining: limit + TRUNCATION_MARKER2.length + 256 }, 0);
|
|
2723
|
-
return JSON.stringify(pruned) ?? "";
|
|
2724
|
-
} catch {
|
|
2725
|
-
const fallback = String(value);
|
|
2726
|
-
return fallback.length > limit ? fallback.slice(0, limit) : fallback;
|
|
2727
|
-
}
|
|
2728
|
-
}
|
|
2729
|
-
function truncate(str, maxLen) {
|
|
2730
|
-
if (str.length <= maxLen) return str;
|
|
2731
|
-
return str.slice(0, maxLen - 3) + "...";
|
|
3327
|
+
function promptAttributes(capture) {
|
|
3328
|
+
return [
|
|
3329
|
+
attrString("ai.prompt.messages", capture?.json),
|
|
3330
|
+
attrString("ai.prompt.messages.truncated", capture?.truncated ? "true" : void 0)
|
|
3331
|
+
];
|
|
2732
3332
|
}
|
|
2733
|
-
function extractLLMMetadata(output) {
|
|
3333
|
+
function extractLLMMetadata(output, limit) {
|
|
2734
3334
|
const gen = output.generations?.[0]?.[0];
|
|
2735
3335
|
const message = gen?.message;
|
|
2736
3336
|
const responseMeta = message?.response_metadata;
|
|
@@ -2756,7 +3356,7 @@ function extractLLMMetadata(output) {
|
|
|
2756
3356
|
outputDetails?.reasoning ?? usage?.reasoning_tokens ?? usage?.thoughts_tokens
|
|
2757
3357
|
);
|
|
2758
3358
|
const finishReason = generationInfo?.finish_reason ?? responseMeta?.finish_reason ?? responseMeta?.stop_reason;
|
|
2759
|
-
const outputText = gen?.text ?? (typeof message?.content === "string" ? message.content : void 0) ?? (message?.content ? extractTextFromContent(message.content) : void 0);
|
|
3359
|
+
const outputText = gen?.text ?? (typeof message?.content === "string" ? message.content : void 0) ?? (message?.content ? extractTextFromContent(message.content, limit) : void 0);
|
|
2760
3360
|
return {
|
|
2761
3361
|
model,
|
|
2762
3362
|
promptTokens,
|
|
@@ -2764,7 +3364,8 @@ function extractLLMMetadata(output) {
|
|
|
2764
3364
|
cachedTokens,
|
|
2765
3365
|
reasoningTokens,
|
|
2766
3366
|
finishReason,
|
|
2767
|
-
outputText
|
|
3367
|
+
outputText,
|
|
3368
|
+
toolCalls: captureToolCalls(message, limit)
|
|
2768
3369
|
};
|
|
2769
3370
|
}
|
|
2770
3371
|
function asNumber(val) {
|
|
@@ -2776,7 +3377,7 @@ function asNumber(val) {
|
|
|
2776
3377
|
// package.json
|
|
2777
3378
|
var package_default = {
|
|
2778
3379
|
name: "@raindrop-ai/deep-agents",
|
|
2779
|
-
version: "0.1.
|
|
3380
|
+
version: "0.1.4",
|
|
2780
3381
|
description: "Raindrop integration for LangChain Deep Agents",
|
|
2781
3382
|
main: "dist/index.js",
|
|
2782
3383
|
module: "dist/index.mjs",
|
|
@@ -2849,6 +3450,8 @@ var libraryVersion = package_default.version;
|
|
|
2849
3450
|
function createRaindropDeepAgents(opts) {
|
|
2850
3451
|
const writeKey = opts.writeKey;
|
|
2851
3452
|
const enabled = !!writeKey;
|
|
3453
|
+
setMaxTextFieldChars(opts.maxTextFieldChars);
|
|
3454
|
+
const maxChars = eventMaxTextFieldChars();
|
|
2852
3455
|
if (!writeKey) {
|
|
2853
3456
|
console.warn(
|
|
2854
3457
|
"[raindrop-ai/deep-agents] writeKey not provided; telemetry shipping is disabled"
|
|
@@ -2864,7 +3467,8 @@ function createRaindropDeepAgents(opts) {
|
|
|
2864
3467
|
sdkName: "deep-agents",
|
|
2865
3468
|
libraryName,
|
|
2866
3469
|
libraryVersion,
|
|
2867
|
-
appGitContext
|
|
3470
|
+
appGitContext,
|
|
3471
|
+
maxTextFieldChars: maxChars
|
|
2868
3472
|
});
|
|
2869
3473
|
const traceShipper = new TraceShipper2({
|
|
2870
3474
|
writeKey,
|
|
@@ -2875,7 +3479,8 @@ function createRaindropDeepAgents(opts) {
|
|
|
2875
3479
|
sdkName: "deep-agents",
|
|
2876
3480
|
serviceName: "raindrop.deep-agents",
|
|
2877
3481
|
serviceVersion: libraryVersion,
|
|
2878
|
-
appGitContext
|
|
3482
|
+
appGitContext,
|
|
3483
|
+
maxTextFieldChars: maxChars
|
|
2879
3484
|
});
|
|
2880
3485
|
const handler = new RaindropDeepAgentsHandler({
|
|
2881
3486
|
eventShipper,
|
|
@@ -2884,7 +3489,10 @@ function createRaindropDeepAgents(opts) {
|
|
|
2884
3489
|
convoId: opts.convoId,
|
|
2885
3490
|
eventName: opts.eventName,
|
|
2886
3491
|
eventId: opts.eventId,
|
|
2887
|
-
traceChains: opts.traceChains
|
|
3492
|
+
traceChains: opts.traceChains,
|
|
3493
|
+
maxTextFieldChars: maxChars,
|
|
3494
|
+
eventMaxTextFieldChars: maxChars,
|
|
3495
|
+
tools: opts.tools
|
|
2888
3496
|
});
|
|
2889
3497
|
return {
|
|
2890
3498
|
handler,
|
|
@@ -2932,6 +3540,7 @@ function createRaindropDeepAgents(opts) {
|
|
|
2932
3540
|
}
|
|
2933
3541
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2934
3542
|
0 && (module.exports = {
|
|
3543
|
+
PROMPT_TOOLS_ATTRIBUTE,
|
|
2935
3544
|
RaindropDeepAgentsHandler,
|
|
2936
3545
|
createRaindropDeepAgents
|
|
2937
3546
|
});
|