@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.mjs
CHANGED
|
@@ -63,7 +63,7 @@ function evalScopeAttributes() {
|
|
|
63
63
|
return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
// ../core/dist/chunk-
|
|
66
|
+
// ../core/dist/chunk-I6TVJQEC.js
|
|
67
67
|
var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
|
|
68
68
|
function state() {
|
|
69
69
|
const holder = globalThis;
|
|
@@ -2050,6 +2050,158 @@ var TraceShipper = class {
|
|
|
2050
2050
|
}
|
|
2051
2051
|
}
|
|
2052
2052
|
};
|
|
2053
|
+
var PROMPT_TOOLS_ATTRIBUTE = "ai.prompt.tools";
|
|
2054
|
+
function isRecord(value) {
|
|
2055
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2056
|
+
}
|
|
2057
|
+
var JSON_SCHEMA_KEYS = [
|
|
2058
|
+
"type",
|
|
2059
|
+
"properties",
|
|
2060
|
+
"$schema",
|
|
2061
|
+
"$ref",
|
|
2062
|
+
"anyOf",
|
|
2063
|
+
"oneOf",
|
|
2064
|
+
"allOf",
|
|
2065
|
+
"enum",
|
|
2066
|
+
"const",
|
|
2067
|
+
"items",
|
|
2068
|
+
"additionalProperties",
|
|
2069
|
+
"required"
|
|
2070
|
+
];
|
|
2071
|
+
function isJsonSchema(value) {
|
|
2072
|
+
if (!isRecord(value)) return false;
|
|
2073
|
+
if (typeof value["~standard"] === "object") return false;
|
|
2074
|
+
if (isRecord(value._def) || isRecord(value._zod)) return false;
|
|
2075
|
+
if (Object.keys(value).length === 0) return true;
|
|
2076
|
+
return JSON_SCHEMA_KEYS.some((key) => key in value);
|
|
2077
|
+
}
|
|
2078
|
+
function toJsonSchema(value, options) {
|
|
2079
|
+
if (value === void 0 || value === null) return void 0;
|
|
2080
|
+
if (isJsonSchema(value)) return value;
|
|
2081
|
+
if (isRecord(value) && isJsonSchema(value.jsonSchema)) return value.jsonSchema;
|
|
2082
|
+
if (isRecord(value) && isJsonSchema(value.json)) return value.json;
|
|
2083
|
+
if (options == null ? void 0 : options.schema) {
|
|
2084
|
+
try {
|
|
2085
|
+
return options.schema(value);
|
|
2086
|
+
} catch (e) {
|
|
2087
|
+
return void 0;
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
return void 0;
|
|
2091
|
+
}
|
|
2092
|
+
function pickString(value) {
|
|
2093
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2094
|
+
}
|
|
2095
|
+
function functionTool(name, description, schema, options) {
|
|
2096
|
+
const tool = { type: "function", name };
|
|
2097
|
+
const desc = pickString(description);
|
|
2098
|
+
if (desc !== void 0) tool.description = desc;
|
|
2099
|
+
const inputSchema = toJsonSchema(schema, options);
|
|
2100
|
+
if (inputSchema !== void 0) tool.inputSchema = inputSchema;
|
|
2101
|
+
return tool;
|
|
2102
|
+
}
|
|
2103
|
+
function normalizeToolDeclaration(tool, options, fallbackName) {
|
|
2104
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2105
|
+
if (!isRecord(tool)) return void 0;
|
|
2106
|
+
if (tool.type === "provider-defined" || tool.type === "provider") {
|
|
2107
|
+
const name2 = (_b = (_a = pickString(tool.name)) != null ? _a : pickString(tool.id)) != null ? _b : fallbackName;
|
|
2108
|
+
if (name2 === void 0) return void 0;
|
|
2109
|
+
const declaration = { type: "provider-defined", name: name2 };
|
|
2110
|
+
const id = pickString(tool.id);
|
|
2111
|
+
if (id !== void 0) declaration.id = id;
|
|
2112
|
+
if (isRecord(tool.args)) declaration.args = tool.args;
|
|
2113
|
+
return declaration;
|
|
2114
|
+
}
|
|
2115
|
+
if (isRecord(tool.toolSpec)) {
|
|
2116
|
+
const spec = tool.toolSpec;
|
|
2117
|
+
const name2 = (_c = pickString(spec.name)) != null ? _c : fallbackName;
|
|
2118
|
+
if (name2 === void 0) return void 0;
|
|
2119
|
+
return functionTool(name2, spec.description, spec.inputSchema, options);
|
|
2120
|
+
}
|
|
2121
|
+
if (isRecord(tool.function)) {
|
|
2122
|
+
const fn = tool.function;
|
|
2123
|
+
const name2 = (_d = pickString(fn.name)) != null ? _d : fallbackName;
|
|
2124
|
+
if (name2 === void 0) return void 0;
|
|
2125
|
+
return functionTool(name2, fn.description, (_e = fn.parameters) != null ? _e : fn.input_schema, options);
|
|
2126
|
+
}
|
|
2127
|
+
const name = (_g = (_f = pickString(tool.name)) != null ? _f : pickString(tool.id)) != null ? _g : fallbackName;
|
|
2128
|
+
if (name === void 0) return void 0;
|
|
2129
|
+
const type = pickString(tool.type);
|
|
2130
|
+
if (type !== void 0 && type !== "function" && type !== "dynamic" && type !== "custom") {
|
|
2131
|
+
if (!("input_schema" in tool) && !("inputSchema" in tool) && !("parameters" in tool)) {
|
|
2132
|
+
return { type: "provider-defined", id: type, name };
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
return functionTool(
|
|
2136
|
+
name,
|
|
2137
|
+
tool.description,
|
|
2138
|
+
(_j = (_i = (_h = tool.inputSchema) != null ? _h : tool.input_schema) != null ? _i : tool.parameters) != null ? _j : tool.schema,
|
|
2139
|
+
options
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
var NOT_A_GEMINI_GROUP_KEYS = ["name", "id", "type", "function", "toolSpec", "cachePoint"];
|
|
2143
|
+
function isGeminiToolGroup(tool) {
|
|
2144
|
+
if (Array.isArray(tool.functionDeclarations)) return true;
|
|
2145
|
+
const keys = Object.keys(tool);
|
|
2146
|
+
if (keys.length === 0 || NOT_A_GEMINI_GROUP_KEYS.some((key) => key in tool)) return false;
|
|
2147
|
+
return keys.every((key) => isRecord(tool[key]));
|
|
2148
|
+
}
|
|
2149
|
+
function expandGeminiTool(tool, options) {
|
|
2150
|
+
const declarations = [];
|
|
2151
|
+
for (const [key, value] of Object.entries(tool)) {
|
|
2152
|
+
if (key === "functionDeclarations" && Array.isArray(value)) {
|
|
2153
|
+
for (const declaration of value) {
|
|
2154
|
+
const normalized = normalizeToolDeclaration(declaration, options);
|
|
2155
|
+
if (normalized) declarations.push(normalized);
|
|
2156
|
+
}
|
|
2157
|
+
} else if (isRecord(value)) {
|
|
2158
|
+
declarations.push({ type: "provider-defined", id: key, name: key, args: value });
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
return declarations;
|
|
2162
|
+
}
|
|
2163
|
+
function normalizeToolDeclarations(tools, options) {
|
|
2164
|
+
if (tools === void 0 || tools === null) return void 0;
|
|
2165
|
+
if (Array.isArray(tools)) {
|
|
2166
|
+
return tools.flatMap((tool) => {
|
|
2167
|
+
if (isRecord(tool) && isGeminiToolGroup(tool)) {
|
|
2168
|
+
return expandGeminiTool(tool, options);
|
|
2169
|
+
}
|
|
2170
|
+
const declaration = normalizeToolDeclaration(tool, options);
|
|
2171
|
+
return declaration ? [declaration] : [];
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
2174
|
+
if (!isRecord(tools)) return void 0;
|
|
2175
|
+
return Object.entries(tools).flatMap(([key, tool]) => {
|
|
2176
|
+
const declaration = normalizeToolDeclaration(tool, options, key);
|
|
2177
|
+
return declaration ? [declaration] : [];
|
|
2178
|
+
});
|
|
2179
|
+
}
|
|
2180
|
+
function resolvePromptTools(args) {
|
|
2181
|
+
var _a;
|
|
2182
|
+
if (args.override !== void 0) {
|
|
2183
|
+
return (_a = normalizeToolDeclarations(args.override, args.options)) != null ? _a : [];
|
|
2184
|
+
}
|
|
2185
|
+
return normalizeToolDeclarations(args.inferred, args.options);
|
|
2186
|
+
}
|
|
2187
|
+
function promptToolsAttribute(tools) {
|
|
2188
|
+
const values = promptToolsAttributeValue(tools);
|
|
2189
|
+
if (values === void 0) return void 0;
|
|
2190
|
+
return {
|
|
2191
|
+
key: PROMPT_TOOLS_ATTRIBUTE,
|
|
2192
|
+
value: { arrayValue: { values: values.map((stringValue) => ({ stringValue })) } }
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
function promptToolsAttributeValue(tools) {
|
|
2196
|
+
if (tools === void 0) return void 0;
|
|
2197
|
+
return tools.map((tool) => {
|
|
2198
|
+
try {
|
|
2199
|
+
return JSON.stringify(tool);
|
|
2200
|
+
} catch (e) {
|
|
2201
|
+
return JSON.stringify({ type: tool.type, name: tool.name });
|
|
2202
|
+
}
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2053
2205
|
|
|
2054
2206
|
// ../core/dist/index.node.js
|
|
2055
2207
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -2225,7 +2377,475 @@ function installTracingSuppressionHook() {
|
|
|
2225
2377
|
}
|
|
2226
2378
|
installTracingSuppressionHook();
|
|
2227
2379
|
|
|
2380
|
+
// src/conversation.ts
|
|
2381
|
+
import {
|
|
2382
|
+
isAIMessage,
|
|
2383
|
+
isBaseMessage,
|
|
2384
|
+
isChatMessage,
|
|
2385
|
+
isToolMessage
|
|
2386
|
+
} from "@langchain/core/messages";
|
|
2387
|
+
|
|
2388
|
+
// src/truncation.ts
|
|
2389
|
+
var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
|
|
2390
|
+
var DEFAULT_MAX_TEXT_FIELD_CHARS2 = 1e6;
|
|
2391
|
+
var MAX_DEPTH = 12;
|
|
2392
|
+
var configuredMaxTextFieldChars;
|
|
2393
|
+
function setMaxTextFieldChars(limit) {
|
|
2394
|
+
if (limit === void 0) return;
|
|
2395
|
+
if (typeof limit === "number" && Number.isFinite(limit) && limit > 0) {
|
|
2396
|
+
configuredMaxTextFieldChars = Math.floor(limit);
|
|
2397
|
+
} else {
|
|
2398
|
+
console.warn(`[raindrop-ai] maxTextFieldChars=${String(limit)} ignored; must be > 0`);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
function otelEnvLimit() {
|
|
2402
|
+
if (typeof process === "undefined") return void 0;
|
|
2403
|
+
const raw = process.env?.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
|
|
2404
|
+
if (!raw) return void 0;
|
|
2405
|
+
const parsed = Number.parseInt(raw, 10);
|
|
2406
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
2407
|
+
}
|
|
2408
|
+
function eventMaxTextFieldChars() {
|
|
2409
|
+
return configuredMaxTextFieldChars ?? DEFAULT_MAX_TEXT_FIELD_CHARS2;
|
|
2410
|
+
}
|
|
2411
|
+
function spanAttributeLimit(limit) {
|
|
2412
|
+
const env = otelEnvLimit();
|
|
2413
|
+
return env !== void 0 && env < limit ? env : limit;
|
|
2414
|
+
}
|
|
2415
|
+
function effectiveMaxTextFieldChars() {
|
|
2416
|
+
return spanAttributeLimit(eventMaxTextFieldChars());
|
|
2417
|
+
}
|
|
2418
|
+
function truncateToLimit2(text, limit) {
|
|
2419
|
+
if (limit > TRUNCATION_MARKER2.length) {
|
|
2420
|
+
return text.slice(0, limit - TRUNCATION_MARKER2.length) + TRUNCATION_MARKER2;
|
|
2421
|
+
}
|
|
2422
|
+
return text.slice(0, limit);
|
|
2423
|
+
}
|
|
2424
|
+
function capText2(value, limit) {
|
|
2425
|
+
if (typeof value !== "string") return value;
|
|
2426
|
+
const max = limit ?? effectiveMaxTextFieldChars();
|
|
2427
|
+
if (value.length <= max) return value;
|
|
2428
|
+
return truncateToLimit2(value, max);
|
|
2429
|
+
}
|
|
2430
|
+
function boundedClone2(value, budget, depth) {
|
|
2431
|
+
if (budget.remaining <= 0) return TRUNCATION_MARKER2;
|
|
2432
|
+
if (typeof value === "string") {
|
|
2433
|
+
if (value.length > budget.remaining) {
|
|
2434
|
+
const taken = value.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2435
|
+
budget.remaining = 0;
|
|
2436
|
+
return taken;
|
|
2437
|
+
}
|
|
2438
|
+
budget.remaining -= Math.max(value.length, 1);
|
|
2439
|
+
return value;
|
|
2440
|
+
}
|
|
2441
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
2442
|
+
budget.remaining -= 8;
|
|
2443
|
+
return value;
|
|
2444
|
+
}
|
|
2445
|
+
if (typeof value === "bigint") return boundedClone2(value.toString(), budget, depth);
|
|
2446
|
+
if (typeof value !== "object") {
|
|
2447
|
+
budget.remaining -= 1;
|
|
2448
|
+
return value;
|
|
2449
|
+
}
|
|
2450
|
+
if (value instanceof Uint8Array) {
|
|
2451
|
+
const maxBytes = Math.max(0, Math.ceil(budget.remaining * 3 / 4));
|
|
2452
|
+
if (value.byteLength > maxBytes) {
|
|
2453
|
+
const taken = base64Encode(value.subarray(0, maxBytes)) + TRUNCATION_MARKER2;
|
|
2454
|
+
budget.remaining = 0;
|
|
2455
|
+
return taken;
|
|
2456
|
+
}
|
|
2457
|
+
const encoded = base64Encode(value);
|
|
2458
|
+
budget.remaining -= Math.max(encoded.length, 1);
|
|
2459
|
+
return encoded;
|
|
2460
|
+
}
|
|
2461
|
+
if (depth >= MAX_DEPTH) {
|
|
2462
|
+
budget.remaining -= 16;
|
|
2463
|
+
const name = value.constructor?.name ?? "object";
|
|
2464
|
+
return `<max depth: ${name}>`;
|
|
2465
|
+
}
|
|
2466
|
+
const toJSON = value.toJSON;
|
|
2467
|
+
if (typeof toJSON === "function") {
|
|
2468
|
+
budget.remaining -= 2;
|
|
2469
|
+
return boundedClone2(toJSON.call(value), budget, depth + 1);
|
|
2470
|
+
}
|
|
2471
|
+
if (Array.isArray(value)) {
|
|
2472
|
+
budget.remaining -= 2;
|
|
2473
|
+
const out2 = [];
|
|
2474
|
+
for (const item of value) {
|
|
2475
|
+
if (budget.remaining <= 0) {
|
|
2476
|
+
out2.push(TRUNCATION_MARKER2);
|
|
2477
|
+
break;
|
|
2478
|
+
}
|
|
2479
|
+
out2.push(boundedClone2(item, budget, depth + 1));
|
|
2480
|
+
}
|
|
2481
|
+
return out2;
|
|
2482
|
+
}
|
|
2483
|
+
budget.remaining -= 2;
|
|
2484
|
+
const out = {};
|
|
2485
|
+
for (const key in value) {
|
|
2486
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
|
|
2487
|
+
if (budget.remaining <= 0) {
|
|
2488
|
+
out["..."] = TRUNCATION_MARKER2;
|
|
2489
|
+
break;
|
|
2490
|
+
}
|
|
2491
|
+
let cappedKey = key;
|
|
2492
|
+
if (key.length > budget.remaining) {
|
|
2493
|
+
cappedKey = key.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2494
|
+
budget.remaining = 0;
|
|
2495
|
+
out[cappedKey] = TRUNCATION_MARKER2;
|
|
2496
|
+
break;
|
|
2497
|
+
}
|
|
2498
|
+
budget.remaining -= Math.max(key.length, 1);
|
|
2499
|
+
out[cappedKey] = boundedClone2(value[key], budget, depth + 1);
|
|
2500
|
+
}
|
|
2501
|
+
return out;
|
|
2502
|
+
}
|
|
2503
|
+
function boundedStringify(value, limit) {
|
|
2504
|
+
const max = limit ?? effectiveMaxTextFieldChars();
|
|
2505
|
+
try {
|
|
2506
|
+
if (typeof value === "string") {
|
|
2507
|
+
const text2 = JSON.stringify(capText2(value, max));
|
|
2508
|
+
return text2.length <= max ? text2 : truncateToLimit2(text2, max);
|
|
2509
|
+
}
|
|
2510
|
+
const pruned = boundedClone2(value, { remaining: max + TRUNCATION_MARKER2.length + 256 }, 0);
|
|
2511
|
+
const text = JSON.stringify(pruned);
|
|
2512
|
+
if (text === void 0) return void 0;
|
|
2513
|
+
return text.length <= max ? text : truncateToLimit2(text, max);
|
|
2514
|
+
} catch {
|
|
2515
|
+
return void 0;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
// src/conversation.ts
|
|
2520
|
+
var CAPTURE_TRUNCATED_ROLE = "raindrop";
|
|
2521
|
+
var MESSAGE_OVERHEAD = 32;
|
|
2522
|
+
var PART_OVERHEAD = 24;
|
|
2523
|
+
var MAX_DEPTH2 = 12;
|
|
2524
|
+
function isRecord2(value) {
|
|
2525
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2526
|
+
}
|
|
2527
|
+
function stringField(record, key) {
|
|
2528
|
+
const value = record[key];
|
|
2529
|
+
return typeof value === "string" ? value : void 0;
|
|
2530
|
+
}
|
|
2531
|
+
function takeText(text, budget) {
|
|
2532
|
+
if (text.length > budget.remaining) {
|
|
2533
|
+
const kept = text.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2534
|
+
budget.remaining = 0;
|
|
2535
|
+
budget.truncated = true;
|
|
2536
|
+
return kept;
|
|
2537
|
+
}
|
|
2538
|
+
budget.remaining -= Math.max(text.length, 1);
|
|
2539
|
+
return text;
|
|
2540
|
+
}
|
|
2541
|
+
function reserve(text, budget) {
|
|
2542
|
+
if (text !== void 0) budget.remaining -= Math.max(text.length, 1);
|
|
2543
|
+
return text;
|
|
2544
|
+
}
|
|
2545
|
+
function takeValue(value, budget, depth) {
|
|
2546
|
+
if (typeof value === "string") return takeText(value, budget);
|
|
2547
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
2548
|
+
budget.remaining -= 8;
|
|
2549
|
+
return value;
|
|
2550
|
+
}
|
|
2551
|
+
if (typeof value !== "object") {
|
|
2552
|
+
budget.remaining -= 1;
|
|
2553
|
+
return value;
|
|
2554
|
+
}
|
|
2555
|
+
if (depth >= MAX_DEPTH2) {
|
|
2556
|
+
budget.remaining -= TRUNCATION_MARKER2.length;
|
|
2557
|
+
budget.truncated = true;
|
|
2558
|
+
return TRUNCATION_MARKER2;
|
|
2559
|
+
}
|
|
2560
|
+
if ("toJSON" in value && typeof value.toJSON === "function") {
|
|
2561
|
+
return takeValue(value.toJSON(), budget, depth + 1);
|
|
2562
|
+
}
|
|
2563
|
+
if (Array.isArray(value)) {
|
|
2564
|
+
budget.remaining -= 2;
|
|
2565
|
+
const out2 = [];
|
|
2566
|
+
for (const item of value) {
|
|
2567
|
+
if (budget.remaining <= 0) {
|
|
2568
|
+
budget.truncated = true;
|
|
2569
|
+
out2.push(TRUNCATION_MARKER2);
|
|
2570
|
+
break;
|
|
2571
|
+
}
|
|
2572
|
+
out2.push(takeValue(item, budget, depth + 1));
|
|
2573
|
+
}
|
|
2574
|
+
return out2;
|
|
2575
|
+
}
|
|
2576
|
+
budget.remaining -= 2;
|
|
2577
|
+
const out = {};
|
|
2578
|
+
if (!isRecord2(value)) return out;
|
|
2579
|
+
for (const key in value) {
|
|
2580
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
|
|
2581
|
+
if (budget.remaining <= 0) {
|
|
2582
|
+
budget.truncated = true;
|
|
2583
|
+
out["..."] = TRUNCATION_MARKER2;
|
|
2584
|
+
break;
|
|
2585
|
+
}
|
|
2586
|
+
budget.remaining -= Math.max(key.length, 1);
|
|
2587
|
+
out[key] = takeValue(value[key], budget, depth + 1);
|
|
2588
|
+
}
|
|
2589
|
+
return out;
|
|
2590
|
+
}
|
|
2591
|
+
function messageType(message) {
|
|
2592
|
+
return typeof message._getType === "function" ? message._getType() : void 0;
|
|
2593
|
+
}
|
|
2594
|
+
function textPart(text, budget) {
|
|
2595
|
+
return { type: "text", text: takeText(text, budget) };
|
|
2596
|
+
}
|
|
2597
|
+
function joinedText(content, budget) {
|
|
2598
|
+
const texts = [];
|
|
2599
|
+
for (const block of content) {
|
|
2600
|
+
if (budget.remaining <= 0) {
|
|
2601
|
+
budget.truncated = true;
|
|
2602
|
+
texts.push(TRUNCATION_MARKER2);
|
|
2603
|
+
break;
|
|
2604
|
+
}
|
|
2605
|
+
budget.remaining -= 1;
|
|
2606
|
+
if (!isRecord2(block)) continue;
|
|
2607
|
+
const text = stringField(block, "text");
|
|
2608
|
+
if (text !== void 0) texts.push(takeText(text, budget));
|
|
2609
|
+
}
|
|
2610
|
+
return texts.join("\n");
|
|
2611
|
+
}
|
|
2612
|
+
function contentPart(block, budget) {
|
|
2613
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2614
|
+
if (!isRecord2(block)) return takeValue(block, budget, 0);
|
|
2615
|
+
const type = stringField(block, "type");
|
|
2616
|
+
const text = stringField(block, "text");
|
|
2617
|
+
if (type === "text" && text !== void 0) return textPart(text, budget);
|
|
2618
|
+
if (type === "image_url") {
|
|
2619
|
+
const imageUrl = block["image_url"];
|
|
2620
|
+
const url = typeof imageUrl === "string" ? imageUrl : isRecord2(imageUrl) ? stringField(imageUrl, "url") : void 0;
|
|
2621
|
+
if (url !== void 0) return { type: "image", image: takeText(url, budget) };
|
|
2622
|
+
}
|
|
2623
|
+
if (type === "thinking") {
|
|
2624
|
+
const thinking = stringField(block, "thinking");
|
|
2625
|
+
if (thinking !== void 0) return { type: "reasoning", text: takeText(thinking, budget) };
|
|
2626
|
+
}
|
|
2627
|
+
if (type === "image" || type === "file" || type === "audio") {
|
|
2628
|
+
const mediaType = stringField(block, "mime_type");
|
|
2629
|
+
const sourceType = stringField(block, "source_type");
|
|
2630
|
+
const source = block["source"];
|
|
2631
|
+
if (sourceType === "text" && text !== void 0) return textPart(text, budget);
|
|
2632
|
+
const data = sourceType === "url" ? stringField(block, "url") : sourceType === "base64" ? stringField(block, "data") : isRecord2(source) ? stringField(source, "url") ?? stringField(source, "data") : void 0;
|
|
2633
|
+
const sourceMediaType = mediaType ?? (isRecord2(source) ? stringField(source, "media_type") : void 0);
|
|
2634
|
+
if (data !== void 0) {
|
|
2635
|
+
const filename = stringField(block, "filename");
|
|
2636
|
+
return type === "image" ? { type: "image", image: takeText(data, budget), mediaType: reserve(sourceMediaType, budget) } : {
|
|
2637
|
+
type: "file",
|
|
2638
|
+
data: takeText(data, budget),
|
|
2639
|
+
mediaType: reserve(sourceMediaType, budget),
|
|
2640
|
+
filename: reserve(filename, budget)
|
|
2641
|
+
};
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
return takeValue(block, budget, 0);
|
|
2645
|
+
}
|
|
2646
|
+
function contentParts(content, budget, skipToolUseIds) {
|
|
2647
|
+
const parts = [];
|
|
2648
|
+
for (const block of content) {
|
|
2649
|
+
if (budget.remaining <= 0) {
|
|
2650
|
+
budget.truncated = true;
|
|
2651
|
+
parts.push({ type: "text", text: TRUNCATION_MARKER2 });
|
|
2652
|
+
break;
|
|
2653
|
+
}
|
|
2654
|
+
if (isRecord2(block) && (block["type"] === "tool_use" || block["type"] === "tool_call")) {
|
|
2655
|
+
const id = stringField(block, "id");
|
|
2656
|
+
if (id !== void 0 && skipToolUseIds.has(id)) continue;
|
|
2657
|
+
}
|
|
2658
|
+
parts.push(contentPart(block, budget));
|
|
2659
|
+
}
|
|
2660
|
+
return parts;
|
|
2661
|
+
}
|
|
2662
|
+
function assistantMessage(message, budget, toolNames) {
|
|
2663
|
+
const toolCalls = isAIMessage(message) ? message.tool_calls ?? [] : [];
|
|
2664
|
+
if (toolCalls.length === 0 && typeof message.content === "string") {
|
|
2665
|
+
return { role: "assistant", content: takeText(message.content, budget) };
|
|
2666
|
+
}
|
|
2667
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2668
|
+
const callParts = [];
|
|
2669
|
+
for (const call of toolCalls) {
|
|
2670
|
+
if (budget.remaining <= 0) {
|
|
2671
|
+
budget.truncated = true;
|
|
2672
|
+
callParts.push({ type: "text", text: TRUNCATION_MARKER2 });
|
|
2673
|
+
break;
|
|
2674
|
+
}
|
|
2675
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2676
|
+
if (call.id !== void 0) {
|
|
2677
|
+
ids.add(call.id);
|
|
2678
|
+
toolNames.set(call.id, call.name);
|
|
2679
|
+
}
|
|
2680
|
+
callParts.push({
|
|
2681
|
+
type: "tool-call",
|
|
2682
|
+
toolCallId: reserve(call.id, budget),
|
|
2683
|
+
toolName: reserve(call.name, budget),
|
|
2684
|
+
input: takeValue(call.args, budget, 0)
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
const content = typeof message.content === "string" ? message.content.length > 0 ? [textPart(message.content, budget)] : [] : contentParts(message.content, budget, ids);
|
|
2688
|
+
content.push(...callParts);
|
|
2689
|
+
return { role: "assistant", content };
|
|
2690
|
+
}
|
|
2691
|
+
function toolResultOutput(message, budget) {
|
|
2692
|
+
const failed = isToolMessage(message) && message.status === "error";
|
|
2693
|
+
if (typeof message.content === "string") {
|
|
2694
|
+
return { type: failed ? "error-text" : "text", value: takeText(message.content, budget) };
|
|
2695
|
+
}
|
|
2696
|
+
return { type: "content", value: contentParts(message.content, budget, /* @__PURE__ */ new Set()) };
|
|
2697
|
+
}
|
|
2698
|
+
function toolMessage(message, budget, toolNames) {
|
|
2699
|
+
const toolCallId = isToolMessage(message) ? message.tool_call_id : void 0;
|
|
2700
|
+
const toolName = message.name ?? (toolCallId !== void 0 ? toolNames.get(toolCallId) : void 0);
|
|
2701
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2702
|
+
return {
|
|
2703
|
+
role: "tool",
|
|
2704
|
+
content: [{
|
|
2705
|
+
type: "tool-result",
|
|
2706
|
+
toolCallId: reserve(toolCallId, budget),
|
|
2707
|
+
toolName: reserve(toolName, budget),
|
|
2708
|
+
output: toolResultOutput(message, budget)
|
|
2709
|
+
}]
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
function modelMessage(message, budget, toolNames) {
|
|
2713
|
+
budget.remaining -= MESSAGE_OVERHEAD;
|
|
2714
|
+
switch (messageType(message)) {
|
|
2715
|
+
case "system":
|
|
2716
|
+
return {
|
|
2717
|
+
role: "system",
|
|
2718
|
+
content: typeof message.content === "string" ? takeText(message.content, budget) : joinedText(message.content, budget)
|
|
2719
|
+
};
|
|
2720
|
+
case "ai":
|
|
2721
|
+
return assistantMessage(message, budget, toolNames);
|
|
2722
|
+
case "tool":
|
|
2723
|
+
case "function":
|
|
2724
|
+
return toolMessage(message, budget, toolNames);
|
|
2725
|
+
case "generic": {
|
|
2726
|
+
const role = isChatMessage(message) ? message.role : void 0;
|
|
2727
|
+
if (role === "assistant" || role === "system") {
|
|
2728
|
+
return {
|
|
2729
|
+
role,
|
|
2730
|
+
content: typeof message.content === "string" ? takeText(message.content, budget) : joinedText(message.content, budget)
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2733
|
+
return userMessage(message, budget);
|
|
2734
|
+
}
|
|
2735
|
+
default:
|
|
2736
|
+
return userMessage(message, budget);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
function userMessage(message, budget) {
|
|
2740
|
+
return {
|
|
2741
|
+
role: "user",
|
|
2742
|
+
content: typeof message.content === "string" ? takeText(message.content, budget) : contentParts(message.content, budget, /* @__PURE__ */ new Set())
|
|
2743
|
+
};
|
|
2744
|
+
}
|
|
2745
|
+
function truncationRecord(omittedMessages) {
|
|
2746
|
+
return { role: CAPTURE_TRUNCATED_ROLE, truncated: true, marker: TRUNCATION_MARKER2, omittedMessages };
|
|
2747
|
+
}
|
|
2748
|
+
function encodeWithinLimit(items, limit, overflow, convert) {
|
|
2749
|
+
let textBudget = limit;
|
|
2750
|
+
for (let attempt = 0; attempt < 8 && textBudget >= 64; attempt++) {
|
|
2751
|
+
const budget = { remaining: textBudget, truncated: false };
|
|
2752
|
+
const out = [];
|
|
2753
|
+
let omitted = 0;
|
|
2754
|
+
for (let i = 0; i < items.length; i++) {
|
|
2755
|
+
if (overflow === "omit" && budget.remaining <= 0) {
|
|
2756
|
+
omitted = items.length - i;
|
|
2757
|
+
break;
|
|
2758
|
+
}
|
|
2759
|
+
out.push(convert(items[i], budget));
|
|
2760
|
+
}
|
|
2761
|
+
const truncated = budget.truncated || omitted > 0;
|
|
2762
|
+
if (truncated && overflow === "omit") out.push(truncationRecord(omitted));
|
|
2763
|
+
const json2 = JSON.stringify(out);
|
|
2764
|
+
if (json2.length <= limit) return { json: json2, truncated };
|
|
2765
|
+
const excess = json2.length - limit + 128;
|
|
2766
|
+
textBudget = Math.max(textBudget - excess, Math.floor(textBudget / 2));
|
|
2767
|
+
}
|
|
2768
|
+
if (overflow === "keep") return void 0;
|
|
2769
|
+
const json = JSON.stringify([truncationRecord(items.length)]);
|
|
2770
|
+
return json.length <= limit ? { json, truncated: true } : void 0;
|
|
2771
|
+
}
|
|
2772
|
+
function captureConversation(messages, limit) {
|
|
2773
|
+
if (messages.length === 0) return void 0;
|
|
2774
|
+
try {
|
|
2775
|
+
const toolNames = /* @__PURE__ */ new Map();
|
|
2776
|
+
return encodeWithinLimit(
|
|
2777
|
+
messages,
|
|
2778
|
+
limit,
|
|
2779
|
+
"omit",
|
|
2780
|
+
(message, budget) => modelMessage(message, budget, toolNames)
|
|
2781
|
+
);
|
|
2782
|
+
} catch {
|
|
2783
|
+
return void 0;
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
function capturePrompt(prompt, limit) {
|
|
2787
|
+
try {
|
|
2788
|
+
return encodeWithinLimit([prompt], limit, "omit", (text, budget) => {
|
|
2789
|
+
budget.remaining -= MESSAGE_OVERHEAD;
|
|
2790
|
+
return { role: "user", content: takeText(text, budget) };
|
|
2791
|
+
});
|
|
2792
|
+
} catch {
|
|
2793
|
+
return void 0;
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
function captureToolCalls(message, limit) {
|
|
2797
|
+
if (!isRecord2(message) || !Array.isArray(message["tool_calls"])) return void 0;
|
|
2798
|
+
const calls = [];
|
|
2799
|
+
let structural = 0;
|
|
2800
|
+
for (const call of message["tool_calls"]) {
|
|
2801
|
+
structural += PART_OVERHEAD;
|
|
2802
|
+
if (isRecord2(call)) {
|
|
2803
|
+
structural += (stringField(call, "id")?.length ?? 0) + (stringField(call, "name")?.length ?? 0);
|
|
2804
|
+
calls.push(call);
|
|
2805
|
+
}
|
|
2806
|
+
if (structural > limit) return void 0;
|
|
2807
|
+
}
|
|
2808
|
+
if (calls.length === 0) return void 0;
|
|
2809
|
+
try {
|
|
2810
|
+
return encodeWithinLimit(calls, limit, "keep", (call, budget) => {
|
|
2811
|
+
budget.remaining -= PART_OVERHEAD;
|
|
2812
|
+
return {
|
|
2813
|
+
toolCallId: reserve(stringField(call, "id"), budget),
|
|
2814
|
+
toolName: reserve(stringField(call, "name"), budget),
|
|
2815
|
+
input: takeValue(call["args"], budget, 0)
|
|
2816
|
+
};
|
|
2817
|
+
});
|
|
2818
|
+
} catch {
|
|
2819
|
+
return void 0;
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
function parseToolCallInput(input) {
|
|
2823
|
+
try {
|
|
2824
|
+
const parsed = JSON.parse(input);
|
|
2825
|
+
if (isRecord2(parsed) && parsed["type"] === "tool_call" && "args" in parsed) {
|
|
2826
|
+
return { id: stringField(parsed, "id"), args: JSON.stringify(parsed["args"]) };
|
|
2827
|
+
}
|
|
2828
|
+
} catch {
|
|
2829
|
+
}
|
|
2830
|
+
return { args: input };
|
|
2831
|
+
}
|
|
2832
|
+
function unwrapToolOutput(output) {
|
|
2833
|
+
if (isBaseMessage(output)) {
|
|
2834
|
+
return {
|
|
2835
|
+
content: output.content,
|
|
2836
|
+
toolCallId: isToolMessage(output) ? output.tool_call_id : void 0
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
return { content: output };
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2228
2842
|
// src/callback-handler.ts
|
|
2843
|
+
function inferInvocationTools(extraParams) {
|
|
2844
|
+
const params = extraParams?.invocation_params;
|
|
2845
|
+
if (typeof params !== "object" || params === null) return void 0;
|
|
2846
|
+
const record = { ...params };
|
|
2847
|
+
return record.tools ?? record.functions;
|
|
2848
|
+
}
|
|
2229
2849
|
function resolveEventId(source) {
|
|
2230
2850
|
if (typeof source !== "function") return randomUUID();
|
|
2231
2851
|
try {
|
|
@@ -2242,32 +2862,38 @@ function isInternalName(name) {
|
|
|
2242
2862
|
if (name.startsWith("__") && name.endsWith("__")) return true;
|
|
2243
2863
|
return false;
|
|
2244
2864
|
}
|
|
2245
|
-
|
|
2246
|
-
function extractTextFromContent(content) {
|
|
2865
|
+
function extractTextFromContent(content, limit) {
|
|
2247
2866
|
if (content == null) return void 0;
|
|
2248
2867
|
if (typeof content === "string") return content;
|
|
2249
2868
|
if (Array.isArray(content)) {
|
|
2250
2869
|
const parts = [];
|
|
2870
|
+
let length = 0;
|
|
2251
2871
|
for (const part of content) {
|
|
2872
|
+
if (length > limit) break;
|
|
2873
|
+
length += 1;
|
|
2874
|
+
let text;
|
|
2252
2875
|
if (typeof part === "string") {
|
|
2253
|
-
|
|
2876
|
+
text = part;
|
|
2254
2877
|
} else if (part && typeof part === "object") {
|
|
2255
2878
|
const p = part;
|
|
2256
2879
|
if (typeof p.text === "string") {
|
|
2257
|
-
|
|
2880
|
+
text = p.text;
|
|
2258
2881
|
} else if (p.type === "text" && typeof p.content === "string") {
|
|
2259
|
-
|
|
2882
|
+
text = p.content;
|
|
2260
2883
|
}
|
|
2261
2884
|
}
|
|
2885
|
+
if (text === void 0) continue;
|
|
2886
|
+
parts.push(text.length > limit ? text.slice(0, limit + 1) : text);
|
|
2887
|
+
length += Math.max(text.length, 1);
|
|
2262
2888
|
}
|
|
2263
2889
|
if (parts.length > 0) return parts.join("\n");
|
|
2264
|
-
return
|
|
2890
|
+
return boundedStringify(content, limit);
|
|
2265
2891
|
}
|
|
2266
2892
|
if (typeof content === "object") {
|
|
2267
2893
|
const c = content;
|
|
2268
2894
|
if (typeof c.text === "string") return c.text;
|
|
2269
2895
|
if (typeof c.content === "string") return c.content;
|
|
2270
|
-
return
|
|
2896
|
+
return boundedStringify(content, limit);
|
|
2271
2897
|
}
|
|
2272
2898
|
return String(content);
|
|
2273
2899
|
}
|
|
@@ -2286,6 +2912,17 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2286
2912
|
this.eventName = opts.eventName;
|
|
2287
2913
|
this.eventIdSource = opts.eventId;
|
|
2288
2914
|
this.traceChains = opts.traceChains ?? true;
|
|
2915
|
+
this.configuredSpanMaxChars = opts.maxTextFieldChars ?? eventMaxTextFieldChars();
|
|
2916
|
+
this.eventMaxChars = opts.eventMaxTextFieldChars ?? eventMaxTextFieldChars();
|
|
2917
|
+
this.promptTools = opts.tools;
|
|
2918
|
+
}
|
|
2919
|
+
promptToolsAttribute(extraParams) {
|
|
2920
|
+
return promptToolsAttribute(
|
|
2921
|
+
resolvePromptTools({ override: this.promptTools, inferred: inferInvocationTools(extraParams) })
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
get spanMaxChars() {
|
|
2925
|
+
return spanAttributeLimit(this.configuredSpanMaxChars);
|
|
2289
2926
|
}
|
|
2290
2927
|
getEventId(runId, parentRunId) {
|
|
2291
2928
|
const rootId = parentRunId ? this.rootRunIds.get(parentRunId) ?? parentRunId : runId;
|
|
@@ -2346,18 +2983,27 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2346
2983
|
// ---------------------------------------------------------------------------
|
|
2347
2984
|
// LLM events
|
|
2348
2985
|
// ---------------------------------------------------------------------------
|
|
2349
|
-
async handleLLMStart(llm, prompts, runId, parentRunId,
|
|
2986
|
+
async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
2350
2987
|
try {
|
|
2351
2988
|
if (this.spans.has(runId)) return;
|
|
2352
2989
|
const eventId = this.getEventId(runId, parentRunId);
|
|
2353
2990
|
const modelId = getName(llm, runName);
|
|
2991
|
+
const prompt = prompts[0] ?? "";
|
|
2354
2992
|
const span = this.traceShipper.startSpan({
|
|
2355
2993
|
name: "llm",
|
|
2356
2994
|
parent: this.getParent(parentRunId),
|
|
2357
2995
|
eventId,
|
|
2996
|
+
// `ai.generateText` classifies the span as an LLM generation at ingest
|
|
2997
|
+
// (a bare `llm`/`chat` operationId maps to INTERNAL and is skipped by
|
|
2998
|
+
// the rich-interaction extractor). `ai.prompt.messages` carries the
|
|
2999
|
+
// per-step trajectory so replay can see the history each step ran on.
|
|
3000
|
+
// A batch is a list of independent prompts; the span describes the
|
|
3001
|
+
// first one, whose response `handleLLMEnd` reports (`generations[0][0]`).
|
|
2358
3002
|
attributes: [
|
|
2359
3003
|
attrString("ai.model.provider", modelId),
|
|
2360
|
-
attrString("ai.operationId", "
|
|
3004
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
3005
|
+
...promptAttributes(capturePrompt(prompt, this.spanMaxChars)),
|
|
3006
|
+
this.promptToolsAttribute(extraParams)
|
|
2361
3007
|
]
|
|
2362
3008
|
});
|
|
2363
3009
|
this.spans.set(runId, span);
|
|
@@ -2365,36 +3011,44 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2365
3011
|
userId: this.userId,
|
|
2366
3012
|
convoId: this.convoId,
|
|
2367
3013
|
eventName: this.eventName,
|
|
2368
|
-
input:
|
|
3014
|
+
input: capText2(prompt, this.eventMaxChars),
|
|
2369
3015
|
properties: buildProperties(tags, metadata),
|
|
2370
3016
|
isPending: true
|
|
2371
3017
|
});
|
|
2372
3018
|
} catch {
|
|
2373
3019
|
}
|
|
2374
3020
|
}
|
|
2375
|
-
async handleChatModelStart(llm, messages, runId, parentRunId,
|
|
3021
|
+
async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
2376
3022
|
try {
|
|
2377
3023
|
if (this.spans.has(runId)) return;
|
|
2378
3024
|
const eventId = this.getEventId(runId, parentRunId);
|
|
2379
3025
|
const modelId = getName(llm, runName);
|
|
3026
|
+
const conversation = messages[0] ?? [];
|
|
2380
3027
|
const span = this.traceShipper.startSpan({
|
|
2381
3028
|
name: "llm",
|
|
2382
3029
|
parent: this.getParent(parentRunId),
|
|
2383
3030
|
eventId,
|
|
3031
|
+
// See handleLLMStart: the full history (historical tool calls and
|
|
3032
|
+
// their results included) goes on the span; the event `input` below
|
|
3033
|
+
// stays the latest human message. LangChain batches are a list of
|
|
3034
|
+
// independent conversations; the span describes the first one, the
|
|
3035
|
+
// same member `handleLLMEnd` reports the response of
|
|
3036
|
+
// (`generations[0][0]`), so history and response stay paired.
|
|
2384
3037
|
attributes: [
|
|
2385
3038
|
attrString("ai.model.provider", modelId),
|
|
2386
|
-
attrString("ai.operationId", "
|
|
3039
|
+
attrString("ai.operationId", "ai.generateText"),
|
|
3040
|
+
...promptAttributes(captureConversation(conversation, this.spanMaxChars)),
|
|
3041
|
+
this.promptToolsAttribute(extraParams)
|
|
2387
3042
|
]
|
|
2388
3043
|
});
|
|
2389
3044
|
this.spans.set(runId, span);
|
|
2390
|
-
const
|
|
2391
|
-
const userMessages = allMessages.filter((m) => {
|
|
3045
|
+
const userMessages = conversation.filter((m) => {
|
|
2392
3046
|
const role = m._getType?.() ?? "unknown";
|
|
2393
3047
|
return role === "human";
|
|
2394
3048
|
});
|
|
2395
|
-
const lastMsg = userMessages.length > 0 ? userMessages[userMessages.length - 1] :
|
|
2396
|
-
const extracted = lastMsg ? extractTextFromContent(lastMsg.content) : void 0;
|
|
2397
|
-
const inputText =
|
|
3049
|
+
const lastMsg = userMessages.length > 0 ? userMessages[userMessages.length - 1] : conversation[conversation.length - 1];
|
|
3050
|
+
const extracted = lastMsg ? extractTextFromContent(lastMsg.content, this.eventMaxChars) : void 0;
|
|
3051
|
+
const inputText = capText2(extracted, this.eventMaxChars);
|
|
2398
3052
|
await this.eventShipper.patch(eventId, {
|
|
2399
3053
|
userId: this.userId,
|
|
2400
3054
|
convoId: this.convoId,
|
|
@@ -2417,7 +3071,7 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2417
3071
|
await this.finalizeEventIfRoot(runId);
|
|
2418
3072
|
return;
|
|
2419
3073
|
}
|
|
2420
|
-
const meta = extractLLMMetadata(output);
|
|
3074
|
+
const meta = extractLLMMetadata(output, this.spanMaxChars);
|
|
2421
3075
|
const {
|
|
2422
3076
|
model,
|
|
2423
3077
|
promptTokens,
|
|
@@ -2425,11 +3079,17 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2425
3079
|
cachedTokens,
|
|
2426
3080
|
reasoningTokens,
|
|
2427
3081
|
finishReason,
|
|
2428
|
-
outputText
|
|
3082
|
+
outputText,
|
|
3083
|
+
toolCalls
|
|
2429
3084
|
} = meta;
|
|
2430
3085
|
this.traceShipper.endSpan(span, {
|
|
2431
3086
|
attributes: [
|
|
2432
3087
|
attrString("ai.response.model", model),
|
|
3088
|
+
attrString("ai.response.text", capText2(outputText, this.spanMaxChars)),
|
|
3089
|
+
// Tool calls requested by this step, with the ids the matching
|
|
3090
|
+
// `ai.toolCall` spans and the next step's history carry.
|
|
3091
|
+
attrString("ai.response.toolCalls", toolCalls?.json),
|
|
3092
|
+
attrString("ai.response.toolCalls.truncated", toolCalls?.truncated ? "true" : void 0),
|
|
2433
3093
|
attrInt("ai.usage.prompt_tokens", promptTokens),
|
|
2434
3094
|
attrInt("ai.usage.completion_tokens", completionTokens),
|
|
2435
3095
|
attrInt("ai.usage.cached_tokens", cachedTokens),
|
|
@@ -2441,9 +3101,8 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2441
3101
|
if (cachedTokens != null) properties["ai.usage.cached_tokens"] = cachedTokens;
|
|
2442
3102
|
if (reasoningTokens != null) properties["ai.usage.thoughts_tokens"] = reasoningTokens;
|
|
2443
3103
|
if (finishReason != null) properties["ai.finish_reason"] = finishReason;
|
|
2444
|
-
const cappedOutput = outputText !== void 0 ? truncate(outputText, CHAIN_TEXT_MAX_LEN) : void 0;
|
|
2445
3104
|
await this.finalizeEventIfRoot(runId, {
|
|
2446
|
-
output:
|
|
3105
|
+
output: capText2(outputText, this.eventMaxChars),
|
|
2447
3106
|
model,
|
|
2448
3107
|
usage: { promptTokens, completionTokens },
|
|
2449
3108
|
properties: Object.keys(properties).length > 0 ? properties : void 0
|
|
@@ -2539,14 +3198,16 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2539
3198
|
try {
|
|
2540
3199
|
const eventId = this.getEventId(runId, parentRunId);
|
|
2541
3200
|
const toolName = getName(tool, runName);
|
|
3201
|
+
const toolCall = parseToolCallInput(input);
|
|
2542
3202
|
const span = this.traceShipper.startSpan({
|
|
2543
3203
|
name: "tool",
|
|
2544
3204
|
parent: this.getParent(parentRunId),
|
|
2545
3205
|
eventId,
|
|
2546
3206
|
operationId: "ai.toolCall",
|
|
2547
3207
|
attributes: [
|
|
3208
|
+
attrString("ai.toolCall.id", toolCall.id),
|
|
2548
3209
|
attrString("ai.toolCall.name", toolName),
|
|
2549
|
-
attrString("
|
|
3210
|
+
attrString("ai.toolCall.args", capText2(toolCall.args, this.spanMaxChars))
|
|
2550
3211
|
]
|
|
2551
3212
|
});
|
|
2552
3213
|
this.spans.set(runId, span);
|
|
@@ -2561,9 +3222,14 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2561
3222
|
try {
|
|
2562
3223
|
const span = this.spans.get(runId);
|
|
2563
3224
|
if (span) {
|
|
2564
|
-
const
|
|
3225
|
+
const { content, toolCallId } = unwrapToolOutput(output);
|
|
3226
|
+
const result = typeof content === "string" ? capText2(content, this.spanMaxChars) : boundedStringify(content, this.spanMaxChars);
|
|
3227
|
+
const hasId = span.attributes.some((attr) => attr?.key === "ai.toolCall.id");
|
|
2565
3228
|
this.traceShipper.endSpan(span, {
|
|
2566
|
-
attributes: [
|
|
3229
|
+
attributes: [
|
|
3230
|
+
attrString("ai.toolCall.id", hasId ? void 0 : toolCallId),
|
|
3231
|
+
attrString("ai.toolCall.result", result)
|
|
3232
|
+
]
|
|
2567
3233
|
});
|
|
2568
3234
|
}
|
|
2569
3235
|
await this.finalizeEventIfRoot(runId);
|
|
@@ -2599,10 +3265,10 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
|
|
|
2599
3265
|
operationId: "ai.toolCall",
|
|
2600
3266
|
attributes: [
|
|
2601
3267
|
attrString("ai.toolCall.name", action.tool),
|
|
2602
|
-
attrString(
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
)
|
|
3268
|
+
attrString(
|
|
3269
|
+
"agent.tool_input",
|
|
3270
|
+
typeof action.toolInput === "string" ? capText2(action.toolInput, this.spanMaxChars) : boundedStringify(action.toolInput, this.spanMaxChars)
|
|
3271
|
+
)
|
|
2606
3272
|
]
|
|
2607
3273
|
});
|
|
2608
3274
|
this.spans.set(`${runId}:agent_action`, span);
|
|
@@ -2635,75 +3301,13 @@ function buildProperties(tags, metadata) {
|
|
|
2635
3301
|
if (metadata) Object.assign(props, metadata);
|
|
2636
3302
|
return props;
|
|
2637
3303
|
}
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
if (typeof value === "string") {
|
|
2644
|
-
if (value.length > budget.remaining) {
|
|
2645
|
-
const taken = value.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
2646
|
-
budget.remaining = 0;
|
|
2647
|
-
return taken;
|
|
2648
|
-
}
|
|
2649
|
-
budget.remaining -= Math.max(value.length, 1);
|
|
2650
|
-
return value;
|
|
2651
|
-
}
|
|
2652
|
-
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
2653
|
-
budget.remaining -= 8;
|
|
2654
|
-
return value;
|
|
2655
|
-
}
|
|
2656
|
-
if (typeof value !== "object") {
|
|
2657
|
-
budget.remaining -= 8;
|
|
2658
|
-
return value;
|
|
2659
|
-
}
|
|
2660
|
-
if (depth >= MAX_BOUNDED_DEPTH) {
|
|
2661
|
-
budget.remaining -= 16;
|
|
2662
|
-
return `<max depth: ${TRUNCATION_MARKER2}>`;
|
|
2663
|
-
}
|
|
2664
|
-
const withToJson = value;
|
|
2665
|
-
if (typeof withToJson.toJSON === "function") {
|
|
2666
|
-
try {
|
|
2667
|
-
return boundedClone2(withToJson.toJSON(), budget, depth + 1);
|
|
2668
|
-
} catch {
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
if (Array.isArray(value)) {
|
|
2672
|
-
const out2 = [];
|
|
2673
|
-
for (const item of value) {
|
|
2674
|
-
if (budget.remaining <= 0) {
|
|
2675
|
-
out2.push(TRUNCATION_MARKER2);
|
|
2676
|
-
break;
|
|
2677
|
-
}
|
|
2678
|
-
out2.push(boundedClone2(item, budget, depth + 1));
|
|
2679
|
-
}
|
|
2680
|
-
return out2;
|
|
2681
|
-
}
|
|
2682
|
-
const out = {};
|
|
2683
|
-
for (const key of Object.keys(value)) {
|
|
2684
|
-
if (budget.remaining <= 0) {
|
|
2685
|
-
out["..."] = TRUNCATION_MARKER2;
|
|
2686
|
-
break;
|
|
2687
|
-
}
|
|
2688
|
-
budget.remaining -= Math.max(key.length, 1);
|
|
2689
|
-
out[key] = boundedClone2(value[key], budget, depth + 1);
|
|
2690
|
-
}
|
|
2691
|
-
return out;
|
|
2692
|
-
}
|
|
2693
|
-
function safeStringify(value, limit = MAX_TEXT_FIELD_CHARS) {
|
|
2694
|
-
try {
|
|
2695
|
-
const pruned = boundedClone2(value, { remaining: limit + TRUNCATION_MARKER2.length + 256 }, 0);
|
|
2696
|
-
return JSON.stringify(pruned) ?? "";
|
|
2697
|
-
} catch {
|
|
2698
|
-
const fallback = String(value);
|
|
2699
|
-
return fallback.length > limit ? fallback.slice(0, limit) : fallback;
|
|
2700
|
-
}
|
|
2701
|
-
}
|
|
2702
|
-
function truncate(str, maxLen) {
|
|
2703
|
-
if (str.length <= maxLen) return str;
|
|
2704
|
-
return str.slice(0, maxLen - 3) + "...";
|
|
3304
|
+
function promptAttributes(capture) {
|
|
3305
|
+
return [
|
|
3306
|
+
attrString("ai.prompt.messages", capture?.json),
|
|
3307
|
+
attrString("ai.prompt.messages.truncated", capture?.truncated ? "true" : void 0)
|
|
3308
|
+
];
|
|
2705
3309
|
}
|
|
2706
|
-
function extractLLMMetadata(output) {
|
|
3310
|
+
function extractLLMMetadata(output, limit) {
|
|
2707
3311
|
const gen = output.generations?.[0]?.[0];
|
|
2708
3312
|
const message = gen?.message;
|
|
2709
3313
|
const responseMeta = message?.response_metadata;
|
|
@@ -2729,7 +3333,7 @@ function extractLLMMetadata(output) {
|
|
|
2729
3333
|
outputDetails?.reasoning ?? usage?.reasoning_tokens ?? usage?.thoughts_tokens
|
|
2730
3334
|
);
|
|
2731
3335
|
const finishReason = generationInfo?.finish_reason ?? responseMeta?.finish_reason ?? responseMeta?.stop_reason;
|
|
2732
|
-
const outputText = gen?.text ?? (typeof message?.content === "string" ? message.content : void 0) ?? (message?.content ? extractTextFromContent(message.content) : void 0);
|
|
3336
|
+
const outputText = gen?.text ?? (typeof message?.content === "string" ? message.content : void 0) ?? (message?.content ? extractTextFromContent(message.content, limit) : void 0);
|
|
2733
3337
|
return {
|
|
2734
3338
|
model,
|
|
2735
3339
|
promptTokens,
|
|
@@ -2737,7 +3341,8 @@ function extractLLMMetadata(output) {
|
|
|
2737
3341
|
cachedTokens,
|
|
2738
3342
|
reasoningTokens,
|
|
2739
3343
|
finishReason,
|
|
2740
|
-
outputText
|
|
3344
|
+
outputText,
|
|
3345
|
+
toolCalls: captureToolCalls(message, limit)
|
|
2741
3346
|
};
|
|
2742
3347
|
}
|
|
2743
3348
|
function asNumber(val) {
|
|
@@ -2749,7 +3354,7 @@ function asNumber(val) {
|
|
|
2749
3354
|
// package.json
|
|
2750
3355
|
var package_default = {
|
|
2751
3356
|
name: "@raindrop-ai/deep-agents",
|
|
2752
|
-
version: "0.1.
|
|
3357
|
+
version: "0.1.4",
|
|
2753
3358
|
description: "Raindrop integration for LangChain Deep Agents",
|
|
2754
3359
|
main: "dist/index.js",
|
|
2755
3360
|
module: "dist/index.mjs",
|
|
@@ -2822,6 +3427,8 @@ var libraryVersion = package_default.version;
|
|
|
2822
3427
|
function createRaindropDeepAgents(opts) {
|
|
2823
3428
|
const writeKey = opts.writeKey;
|
|
2824
3429
|
const enabled = !!writeKey;
|
|
3430
|
+
setMaxTextFieldChars(opts.maxTextFieldChars);
|
|
3431
|
+
const maxChars = eventMaxTextFieldChars();
|
|
2825
3432
|
if (!writeKey) {
|
|
2826
3433
|
console.warn(
|
|
2827
3434
|
"[raindrop-ai/deep-agents] writeKey not provided; telemetry shipping is disabled"
|
|
@@ -2837,7 +3444,8 @@ function createRaindropDeepAgents(opts) {
|
|
|
2837
3444
|
sdkName: "deep-agents",
|
|
2838
3445
|
libraryName,
|
|
2839
3446
|
libraryVersion,
|
|
2840
|
-
appGitContext
|
|
3447
|
+
appGitContext,
|
|
3448
|
+
maxTextFieldChars: maxChars
|
|
2841
3449
|
});
|
|
2842
3450
|
const traceShipper = new TraceShipper2({
|
|
2843
3451
|
writeKey,
|
|
@@ -2848,7 +3456,8 @@ function createRaindropDeepAgents(opts) {
|
|
|
2848
3456
|
sdkName: "deep-agents",
|
|
2849
3457
|
serviceName: "raindrop.deep-agents",
|
|
2850
3458
|
serviceVersion: libraryVersion,
|
|
2851
|
-
appGitContext
|
|
3459
|
+
appGitContext,
|
|
3460
|
+
maxTextFieldChars: maxChars
|
|
2852
3461
|
});
|
|
2853
3462
|
const handler = new RaindropDeepAgentsHandler({
|
|
2854
3463
|
eventShipper,
|
|
@@ -2857,7 +3466,10 @@ function createRaindropDeepAgents(opts) {
|
|
|
2857
3466
|
convoId: opts.convoId,
|
|
2858
3467
|
eventName: opts.eventName,
|
|
2859
3468
|
eventId: opts.eventId,
|
|
2860
|
-
traceChains: opts.traceChains
|
|
3469
|
+
traceChains: opts.traceChains,
|
|
3470
|
+
maxTextFieldChars: maxChars,
|
|
3471
|
+
eventMaxTextFieldChars: maxChars,
|
|
3472
|
+
tools: opts.tools
|
|
2861
3473
|
});
|
|
2862
3474
|
return {
|
|
2863
3475
|
handler,
|
|
@@ -2904,6 +3516,7 @@ function createRaindropDeepAgents(opts) {
|
|
|
2904
3516
|
};
|
|
2905
3517
|
}
|
|
2906
3518
|
export {
|
|
3519
|
+
PROMPT_TOOLS_ATTRIBUTE,
|
|
2907
3520
|
RaindropDeepAgentsHandler,
|
|
2908
3521
|
createRaindropDeepAgents
|
|
2909
3522
|
};
|