@cognipeer/agent-sdk 0.2.5 → 0.2.6

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/dist/index.cjs CHANGED
@@ -142,39 +142,38 @@ function withTools(model, tools) {
142
142
  }
143
143
  function fromLangchainModel(lcModel) {
144
144
  if (!lcModel) throw new Error("fromLangchainModel: model is undefined/null");
145
- const adapted = {
146
- invoke: async (messages, options) => {
147
- const normalizeContent = (content) => {
148
- if (content == null) return content;
149
- if (typeof content === "string") return content;
150
- if (Array.isArray(content)) {
151
- return content.map((part) => {
152
- if (!part || typeof part !== "object") return part;
153
- if (part.type === "text") return { type: "text", text: String(part.text ?? "") };
154
- if (part.type === "image_url") {
155
- const img = part.image_url;
156
- if (typeof img === "string") return { type: "image_url", image_url: { url: img } };
157
- if (img && typeof img === "object") {
158
- if ("url" in img) return { type: "image_url", image_url: img };
159
- if ("base64" in img) {
160
- const media = img.media_type || "image/jpeg";
161
- const dataUrl = `data:${media};base64,${img.base64}`;
162
- const detail = img.detail;
163
- return { type: "image_url", image_url: { url: dataUrl, detail } };
164
- }
165
- }
166
- return part;
145
+ const normalizeContent = (content) => {
146
+ if (content == null) return content;
147
+ if (typeof content === "string") return content;
148
+ if (Array.isArray(content)) {
149
+ return content.map((part) => {
150
+ if (!part || typeof part !== "object") return part;
151
+ if (part.type === "text") return { type: "text", text: String(part.text ?? "") };
152
+ if (part.type === "image_url") {
153
+ const img = part.image_url;
154
+ if (typeof img === "string") return { type: "image_url", image_url: { url: img } };
155
+ if (img && typeof img === "object") {
156
+ if ("url" in img) return { type: "image_url", image_url: img };
157
+ if ("base64" in img) {
158
+ const media = img.media_type || "image/jpeg";
159
+ const dataUrl = `data:${media};base64,${img.base64}`;
160
+ const detail = img.detail;
161
+ return { type: "image_url", image_url: { url: dataUrl, detail } };
167
162
  }
168
- return part;
169
- });
163
+ }
164
+ return part;
170
165
  }
171
- return content;
172
- };
173
- const toLC = (m) => {
174
- if (m._getType || m.lc_serializable) return m;
175
- const role = m.role;
176
- return { role, content: normalizeContent(m.content), name: m.name, tool_calls: m.tool_calls, tool_call_id: m.tool_call_id };
177
- };
166
+ return part;
167
+ });
168
+ }
169
+ return content;
170
+ };
171
+ const toLC = (m) => {
172
+ if (m._getType || m.lc_serializable) return m;
173
+ return { role: m.role, content: normalizeContent(m.content), name: m.name, tool_calls: m.tool_calls, tool_call_id: m.tool_call_id };
174
+ };
175
+ const adapted = {
176
+ invoke: async (messages, options) => {
178
177
  const lcMessages = messages.map(toLC);
179
178
  const response = await lcModel.invoke(lcMessages, options);
180
179
  if (response && typeof response === "object") {
@@ -192,36 +191,6 @@ function fromLangchainModel(lcModel) {
192
191
  },
193
192
  stream: async function* (messages, options) {
194
193
  if (typeof lcModel.stream !== "function") return;
195
- const normalizeContent = (content) => {
196
- if (content == null) return content;
197
- if (typeof content === "string") return content;
198
- if (Array.isArray(content)) {
199
- return content.map((part) => {
200
- if (!part || typeof part !== "object") return part;
201
- if (part.type === "text") return { type: "text", text: String(part.text ?? "") };
202
- if (part.type === "image_url") {
203
- const img = part.image_url;
204
- if (typeof img === "string") return { type: "image_url", image_url: { url: img } };
205
- if (img && typeof img === "object") {
206
- if ("url" in img) return { type: "image_url", image_url: img };
207
- if ("base64" in img) {
208
- const media = img.media_type || "image/jpeg";
209
- const dataUrl = `data:${media};base64,${img.base64}`;
210
- const detail = img.detail;
211
- return { type: "image_url", image_url: { url: dataUrl, detail } };
212
- }
213
- }
214
- return part;
215
- }
216
- return part;
217
- });
218
- }
219
- return content;
220
- };
221
- const toLC = (m) => {
222
- if (m._getType || m.lc_serializable) return m;
223
- return { role: m.role, content: normalizeContent(m.content), name: m.name, tool_calls: m.tool_calls, tool_call_id: m.tool_call_id };
224
- };
225
194
  const lcMessages = messages.map(toLC);
226
195
  for await (const chunk of lcModel.stream(lcMessages, options)) {
227
196
  yield chunk;
@@ -1305,7 +1274,18 @@ function createAgentCoreNode(opts) {
1305
1274
  outputSchema: opts.outputSchema,
1306
1275
  tracing: opts.tracing
1307
1276
  };
1308
- const tools = runtime.tools ?? [];
1277
+ const rawTools = runtime.tools ?? [];
1278
+ const seenNames = /* @__PURE__ */ new Map();
1279
+ const tools = [];
1280
+ for (const t of rawTools) {
1281
+ const tName = t.name ?? t.schema?.title;
1282
+ if (tName && seenNames.has(tName)) {
1283
+ tools[seenNames.get(tName)] = t;
1284
+ } else {
1285
+ if (tName) seenNames.set(tName, tools.length);
1286
+ tools.push(t);
1287
+ }
1288
+ }
1309
1289
  const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(tools) : runtime.model;
1310
1290
  const traceSession = state.ctx?.__traceSession;
1311
1291
  const actorName = runtime.name ?? opts.name ?? "agent";
@@ -1358,26 +1338,6 @@ function createAgentCoreNode(opts) {
1358
1338
  }
1359
1339
  return filteredMsgs;
1360
1340
  };
1361
- const debugToolPairing = (messagesToSend) => {
1362
- try {
1363
- const msgs = Array.isArray(messagesToSend) ? messagesToSend : [];
1364
- const toolUseIds = [];
1365
- const missingResults = [];
1366
- for (let i = 0; i < msgs.length; i++) {
1367
- const m = msgs[i];
1368
- if (m?.role === "assistant") {
1369
- for (const tu of extractToolUses(m)) {
1370
- toolUseIds.push(tu.id);
1371
- const next = msgs[i + 1];
1372
- if (!(next && next.role === "tool" && (next.tool_call_id === tu.id || next.tool_call_id === m?.tool_call_id))) {
1373
- missingResults.push({ id: tu.id, atIndex: i, tool: tu.name });
1374
- }
1375
- }
1376
- }
1377
- }
1378
- } catch (e) {
1379
- }
1380
- };
1381
1341
  const onEvent = state.ctx?.__onEvent;
1382
1342
  const onStream = state.ctx?.__onStream;
1383
1343
  const streamingEnabled = Boolean(state.ctx?.__streaming);
@@ -1408,25 +1368,54 @@ function createAgentCoreNode(opts) {
1408
1368
  const hasContentToolUse = contentArr.some((c) => c?.type === "tool_use" && c?.id);
1409
1369
  const hasAdditionalToolCalls = Array.isArray(m.additional_kwargs?.tool_calls) && m.additional_kwargs.tool_calls.length > 0;
1410
1370
  if (!hasToolCalls && !hasContentToolUse && !hasAdditionalToolCalls) continue;
1411
- if (hasToolCalls) {
1412
- m.tool_calls = m.tool_calls.map((tc) => ({ ...tc }));
1371
+ if (hasToolCalls && hasContentToolUse) {
1372
+ const toolCallIds = new Set(
1373
+ m.tool_calls.filter((tc) => tc?.id).map((tc) => tc.id)
1374
+ );
1375
+ const filtered = contentArr.filter((c) => {
1376
+ if (c?.type === "tool_use" && c?.id && toolCallIds.has(c.id)) return false;
1377
+ return true;
1378
+ });
1379
+ if (filtered.length === 0) {
1380
+ m.content = "";
1381
+ } else if (filtered.length !== contentArr.length) {
1382
+ m.content = filtered.length === 1 && filtered[0]?.type === "text" ? filtered[0].text ?? "" : filtered;
1383
+ }
1413
1384
  }
1414
- if (hasContentToolUse) {
1415
- m.content = contentArr.map(
1416
- (c) => c && typeof c === "object" ? { ...c } : c
1385
+ if (hasAdditionalToolCalls && Array.isArray(m.content)) {
1386
+ const akIds = new Set(
1387
+ m.additional_kwargs.tool_calls.filter((tc) => tc?.id).map((tc) => tc.id)
1417
1388
  );
1389
+ const arr = m.content;
1390
+ const filtered = arr.filter((c) => {
1391
+ if (c?.type === "tool_use" && c?.id && akIds.has(c.id)) return false;
1392
+ return true;
1393
+ });
1394
+ if (filtered.length !== arr.length) {
1395
+ m.content = filtered.length === 0 ? "" : filtered.length === 1 && filtered[0]?.type === "text" ? filtered[0].text ?? "" : filtered;
1396
+ }
1397
+ }
1398
+ if (hasToolCalls) {
1399
+ m.tool_calls = m.tool_calls.map((tc) => ({ ...tc }));
1418
1400
  }
1419
1401
  if (hasAdditionalToolCalls) {
1420
1402
  m.additional_kwargs = { ...m.additional_kwargs };
1421
1403
  m.additional_kwargs.tool_calls = m.additional_kwargs.tool_calls.map((tc) => ({ ...tc }));
1422
1404
  }
1405
+ const remainingContentArr = Array.isArray(m.content) ? m.content : [];
1406
+ const hasRemainingContentToolUse = remainingContentArr.some((c) => c?.type === "tool_use" && c?.id);
1407
+ if (hasRemainingContentToolUse) {
1408
+ m.content = remainingContentArr.map(
1409
+ (c) => c && typeof c === "object" ? { ...c } : c
1410
+ );
1411
+ }
1423
1412
  const idsInMessage = /* @__PURE__ */ new Set();
1424
1413
  if (hasToolCalls) {
1425
1414
  for (const tc of m.tool_calls) {
1426
1415
  if (tc?.id) idsInMessage.add(tc.id);
1427
1416
  }
1428
1417
  }
1429
- if (hasContentToolUse) {
1418
+ if (hasRemainingContentToolUse) {
1430
1419
  for (const c of m.content) {
1431
1420
  if (c?.type === "tool_use" && c?.id) idsInMessage.add(c.id);
1432
1421
  }
@@ -1447,7 +1436,7 @@ function createAgentCoreNode(opts) {
1447
1436
  if (tc.id === id) tc.id = newId;
1448
1437
  }
1449
1438
  }
1450
- if (hasContentToolUse && Array.isArray(m.content)) {
1439
+ if (hasRemainingContentToolUse && Array.isArray(m.content)) {
1451
1440
  for (const c of m.content) {
1452
1441
  if (c?.type === "tool_use" && c.id === id) c.id = newId;
1453
1442
  }
@@ -1485,7 +1474,6 @@ function createAgentCoreNode(opts) {
1485
1474
  const normalizedMessages = ensureUniqueToolCallIds(
1486
1475
  normalizeBedrockToolPairing([...state.messages])
1487
1476
  );
1488
- debugToolPairing(normalizedMessages);
1489
1477
  if (streamingEnabled && typeof modelWithTools.stream === "function") {
1490
1478
  let streamedText = "";
1491
1479
  let streamedMessage;
@@ -2131,7 +2119,9 @@ function resolveToolApprovalState(state, resolution) {
2131
2119
  // src/utils/utilTokens.ts
2132
2120
  function countApproxTokens(text) {
2133
2121
  if (!text) return 0;
2134
- return Math.ceil(text.length / 4);
2122
+ const nonAsciiCount = (text.match(/[^\x00-\x7F]/g) || []).length;
2123
+ const asciiCount = text.length - nonAsciiCount;
2124
+ return Math.ceil(asciiCount / 4 + nonAsciiCount / 1.5);
2135
2125
  }
2136
2126
 
2137
2127
  // src/agent.ts
@@ -2234,7 +2224,8 @@ function createAgent(opts) {
2234
2224
  let result = false;
2235
2225
  try {
2236
2226
  result = onStateChange(state);
2237
- } catch {
2227
+ } catch (err) {
2228
+ console.warn("[agent-sdk] onStateChange callback error:", err);
2238
2229
  result = false;
2239
2230
  }
2240
2231
  if (!result) return false;
@@ -2412,7 +2403,9 @@ function createAgent(opts) {
2412
2403
  if (toolCallsAfter.length > 0) {
2413
2404
  state = { ...state, ...await toolsNode(state) };
2414
2405
  }
2415
- } catch {
2406
+ } catch (err) {
2407
+ const errMsg = err instanceof Error ? err.message : String(err);
2408
+ emit?.({ type: "metadata", error: `Structured output force-finalize failed: ${errMsg}` });
2416
2409
  }
2417
2410
  }
2418
2411
  }
@@ -2430,13 +2423,15 @@ function createAgent(opts) {
2430
2423
  const emit = (e) => {
2431
2424
  try {
2432
2425
  onEvent?.(e);
2433
- } catch {
2426
+ } catch (err) {
2427
+ console.warn("[agent-sdk] onEvent callback error:", err);
2434
2428
  }
2435
2429
  };
2436
2430
  const emitProgress = (progress) => {
2437
2431
  try {
2438
2432
  onProgress?.(progress);
2439
- } catch {
2433
+ } catch (err) {
2434
+ console.warn("[agent-sdk] onProgress callback error:", err);
2440
2435
  }
2441
2436
  emit({ type: "progress", ...progress });
2442
2437
  };
@@ -2946,6 +2941,12 @@ async function applyTokenLimits({
2946
2941
  let total = messages.reduce((acc, m) => acc + countApproxTokens(String(m.content || "")), 0);
2947
2942
  if (total <= budget) return state;
2948
2943
  const newMessages = [...messages];
2944
+ while (total > budget && newMessages.length > 1) {
2945
+ const idx = newMessages.findIndex((m) => m.role !== "system");
2946
+ if (idx === -1) break;
2947
+ const removed = newMessages.splice(idx, 1)[0];
2948
+ total -= countApproxTokens(String(removed.content || ""));
2949
+ }
2949
2950
  return { ...state, messages: newMessages };
2950
2951
  }
2951
2952
  function createContextTools(stateRef, opts) {
@@ -3047,19 +3048,7 @@ function needsSummarization(state, opts, summarizationEnabled) {
3047
3048
  return "";
3048
3049
  }).join("\n");
3049
3050
  const tokenCount = countApproxTokens(allText);
3050
- const needsSum = tokenCount > maxTok;
3051
- if (process.env.DEBUG_SUMMARIZATION) {
3052
- const msgCount = (state.messages || []).length;
3053
- const toolMsgs = (state.messages || []).filter((m) => m.role === "tool");
3054
- const toolDetails = toolMsgs.map((m, i) => {
3055
- const contentStr = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
3056
- return `[${i}] id:${m.tool_call_id?.slice(-8) || "none"} len:${contentStr.length} preview:"${contentStr.slice(0, 30)}..."`;
3057
- });
3058
- console.log(`[Summarization] Messages: ${msgCount}, Tool messages: ${toolMsgs.length}`);
3059
- toolDetails.forEach((d) => console.log(` ${d}`));
3060
- console.log(`[Summarization] Token count: ${tokenCount}, Max: ${maxTok}, Needs summarization: ${needsSum}`);
3061
- }
3062
- return needsSum;
3051
+ return tokenCount > maxTok;
3063
3052
  } catch (e) {
3064
3053
  return false;
3065
3054
  }