@townco/agent 0.1.113 → 0.1.114

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.
@@ -273,14 +273,12 @@ export class AgentAcpAdapter {
273
273
  "url" in result &&
274
274
  typeof result.url === "string") {
275
275
  // Use the citationId from the tool output if available
276
- let citationId;
277
- if (typeof result.citationId === "number") {
278
- citationId = String(result.citationId);
279
- }
280
- else {
281
- session.sourceCounter++;
282
- citationId = String(session.sourceCounter);
283
- }
276
+ const citationId = typeof result.citationId === "number"
277
+ ? String(result.citationId)
278
+ : (() => {
279
+ session.sourceCounter++;
280
+ return String(session.sourceCounter);
281
+ })();
284
282
  const url = result.url;
285
283
  const title = typeof result.title === "string" ? result.title : "Untitled";
286
284
  const snippet = typeof result.text === "string"
@@ -420,14 +418,11 @@ export class AgentAcpAdapter {
420
418
  if (!docUrl && !docTitle)
421
419
  return null;
422
420
  // Use document_id as the citation ID if available, otherwise use counter
423
- let citationId;
424
- if (docId) {
425
- citationId = docId;
426
- }
427
- else {
428
- session.sourceCounter++;
429
- citationId = String(session.sourceCounter);
430
- }
421
+ const citationId = docId ||
422
+ (() => {
423
+ session.sourceCounter++;
424
+ return String(session.sourceCounter);
425
+ })();
431
426
  // Extract snippet from summary or content
432
427
  let snippet;
433
428
  if (typeof doc.summary === "string") {
@@ -1075,7 +1070,7 @@ export class AgentAcpAdapter {
1075
1070
  }
1076
1071
  logger.info("User message received", {
1077
1072
  sessionId: params.sessionId,
1078
- messagePreview: userMessageText.slice(0, 100),
1073
+ message: userMessageText,
1079
1074
  noSession: this.noSession,
1080
1075
  });
1081
1076
  // Only store messages if session persistence is enabled
@@ -1134,12 +1129,40 @@ export class AgentAcpAdapter {
1134
1129
  // Build ordered content blocks for the assistant response
1135
1130
  const contentBlocks = [];
1136
1131
  let pendingText = "";
1132
+ // Buffer for logging agent response in readable chunks
1133
+ let logBuffer = "";
1134
+ const flushLogBuffer = (force = false) => {
1135
+ if (logBuffer.length === 0)
1136
+ return;
1137
+ if (force) {
1138
+ // Flush everything
1139
+ logger.info("Agent response", {
1140
+ sessionId: params.sessionId,
1141
+ text: logBuffer,
1142
+ });
1143
+ logBuffer = "";
1144
+ }
1145
+ else {
1146
+ // Only flush complete lines (up to and including the last newline)
1147
+ const lastNewline = logBuffer.lastIndexOf("\n");
1148
+ if (lastNewline !== -1) {
1149
+ const completeLines = logBuffer.slice(0, lastNewline + 1);
1150
+ logBuffer = logBuffer.slice(lastNewline + 1);
1151
+ logger.info("Agent response", {
1152
+ sessionId: params.sessionId,
1153
+ text: completeLines,
1154
+ });
1155
+ }
1156
+ }
1157
+ };
1137
1158
  // Helper function to flush pending text as a TextBlock
1138
1159
  const flushPendingText = () => {
1139
1160
  if (pendingText.length > 0) {
1140
1161
  contentBlocks.push({ type: "text", text: pendingText });
1141
1162
  pendingText = "";
1142
1163
  }
1164
+ // Force flush any remaining log buffer when text block completes
1165
+ flushLogBuffer(true);
1143
1166
  };
1144
1167
  // Helper to save cancelled message to session
1145
1168
  const saveCancelledMessage = async () => {
@@ -1332,6 +1355,11 @@ export class AgentAcpAdapter {
1332
1355
  const content = msg.content;
1333
1356
  if (content.type === "text" && typeof content.text === "string") {
1334
1357
  pendingText += content.text;
1358
+ // Buffer for logging - flush on newlines
1359
+ logBuffer += content.text;
1360
+ if (logBuffer.includes("\n")) {
1361
+ flushLogBuffer();
1362
+ }
1335
1363
  }
1336
1364
  }
1337
1365
  // Debug: log if this chunk has tokenUsage in _meta
@@ -1405,28 +1433,20 @@ export class AgentAcpAdapter {
1405
1433
  if (toolCallMsg.rawInput) {
1406
1434
  toolCall.rawInput = toolCallMsg.rawInput;
1407
1435
  }
1436
+ // Log tool call start
1437
+ logger.info("Tool call started", {
1438
+ sessionId: params.sessionId,
1439
+ toolCallId: toolCall.id,
1440
+ tool: toolCall.title,
1441
+ prettyName: toolCall.prettyName,
1442
+ });
1408
1443
  contentBlocks.push(toolCall);
1409
1444
  }
1410
1445
  // Handle tool_call_update - update existing ToolCallBlock
1411
1446
  if ("sessionUpdate" in msg &&
1412
1447
  msg.sessionUpdate === "tool_call_update") {
1413
1448
  const updateMsg = msg;
1414
- logger.info("[SUBAGENT] Adapter received tool_call_update", {
1415
- sessionId: params.sessionId,
1416
- toolCallId: updateMsg.toolCallId,
1417
- status: updateMsg.status,
1418
- hasMeta: !!updateMsg._meta,
1419
- hasSubagentMessages: !!updateMsg._meta?.subagentMessages,
1420
- subagentMessageCount: updateMsg._meta?.subagentMessages?.length ||
1421
- 0,
1422
- });
1423
1449
  const toolCallBlock = contentBlocks.find((block) => block.type === "tool_call" && block.id === updateMsg.toolCallId);
1424
- logger.info("[SUBAGENT] Tool call block lookup result", {
1425
- sessionId: params.sessionId,
1426
- toolCallId: updateMsg.toolCallId,
1427
- found: !!toolCallBlock,
1428
- blockStatus: toolCallBlock?.status,
1429
- });
1430
1450
  if (toolCallBlock) {
1431
1451
  if (updateMsg.status) {
1432
1452
  toolCallBlock.status =
@@ -1446,6 +1466,17 @@ export class AgentAcpAdapter {
1446
1466
  if (toolCallBlock.status === "completed" ||
1447
1467
  toolCallBlock.status === "failed") {
1448
1468
  toolCallBlock.completedAt = Date.now();
1469
+ // Log tool call completion
1470
+ logger.info("Tool call completed", {
1471
+ sessionId: params.sessionId,
1472
+ toolCallId: updateMsg.toolCallId,
1473
+ tool: toolCallBlock.title,
1474
+ status: toolCallBlock.status,
1475
+ durationMs: toolCallBlock.startedAt
1476
+ ? toolCallBlock.completedAt - toolCallBlock.startedAt
1477
+ : undefined,
1478
+ error: toolCallBlock.error,
1479
+ });
1449
1480
  }
1450
1481
  const meta = updateMsg._meta;
1451
1482
  // Update batchId from _meta (comes from tool_call_update after preliminary tool_call)
@@ -1459,31 +1490,11 @@ export class AgentAcpAdapter {
1459
1490
  toolCallBlock.subagentSessionId = meta.subagentSessionId;
1460
1491
  }
1461
1492
  if (meta?.subagentMessages) {
1462
- logger.info("[SUBAGENT] Storing subagent messages for session replay", {
1463
- sessionId: params.sessionId,
1464
- toolCallId: updateMsg.toolCallId,
1465
- messageCount: meta.subagentMessages.length,
1466
- contentPreview: meta.subagentMessages[0]?.content?.substring(0, 100),
1467
- });
1468
1493
  toolCallBlock.subagentMessages = meta.subagentMessages;
1469
- logger.info("[SUBAGENT] Successfully stored messages", {
1470
- sessionId: params.sessionId,
1471
- toolCallId: updateMsg.toolCallId,
1472
- storedCount: toolCallBlock.subagentMessages?.length,
1473
- });
1474
1494
  }
1475
1495
  }
1476
1496
  // Forward tool_call_update with _meta to the client (for subagent connection info, etc.)
1477
1497
  if (updateMsg._meta) {
1478
- logger.info("[SUBAGENT] Forwarding tool_call_update with _meta to client", {
1479
- sessionId: params.sessionId,
1480
- toolCallId: updateMsg.toolCallId,
1481
- status: updateMsg.status,
1482
- hasSubagentMessages: !!updateMsg._meta
1483
- ?.subagentMessages,
1484
- subagentMessageCount: updateMsg._meta?.subagentMessages
1485
- ?.length || 0,
1486
- });
1487
1498
  this.connection.sessionUpdate({
1488
1499
  sessionId: params.sessionId,
1489
1500
  update: {
@@ -1493,10 +1504,6 @@ export class AgentAcpAdapter {
1493
1504
  _meta: updateMsg._meta,
1494
1505
  },
1495
1506
  });
1496
- logger.info("[SUBAGENT] Successfully forwarded to client", {
1497
- sessionId: params.sessionId,
1498
- toolCallId: updateMsg.toolCallId,
1499
- });
1500
1507
  }
1501
1508
  }
1502
1509
  // Handle tool_output - update ToolCallBlock with output content
@@ -181,21 +181,14 @@ export class LangchainAgent {
181
181
  subagentInvCtx.subagentEventEmitter.on("messages", onSubagentMessages);
182
182
  // Helper to check and yield all pending subagent message updates
183
183
  async function* yieldPendingSubagentUpdates() {
184
- _logger.info("[SUBAGENT] yieldPendingSubagentUpdates called", {
185
- sessionId: req.sessionId,
186
- queueLength: subagentMessagesQueue.length,
187
- });
188
184
  while (subagentMessagesQueue.length > 0) {
189
185
  const messagesUpdate = subagentMessagesQueue.shift();
190
186
  if (!messagesUpdate)
191
187
  continue;
192
- _logger.info("[SUBAGENT] Yielding queued subagent messages update", {
188
+ _logger.debug("[SUBAGENT] Yielding queued subagent messages update", {
193
189
  sessionId: req.sessionId,
194
190
  toolCallId: messagesUpdate.toolCallId,
195
191
  messageCount: messagesUpdate.messages.length,
196
- contentPreview: messagesUpdate.messages[0]?.content?.substring(0, 100),
197
- hasContentBlocks: (messagesUpdate.messages[0]?.contentBlocks?.length ?? 0) > 0,
198
- toolCallCount: messagesUpdate.messages[0]?.toolCalls?.length ?? 0,
199
192
  });
200
193
  const updateToYield = {
201
194
  sessionUpdate: "tool_call_update",
@@ -205,17 +198,7 @@ export class LangchainAgent {
205
198
  subagentMessages: messagesUpdate.messages,
206
199
  },
207
200
  };
208
- _logger.info("[SUBAGENT] About to yield update object", {
209
- sessionId: req.sessionId,
210
- toolCallId: messagesUpdate.toolCallId,
211
- updateType: updateToYield.sessionUpdate,
212
- hasMetaSubagentMessages: !!updateToYield._meta?.subagentMessages,
213
- });
214
201
  yield updateToYield;
215
- _logger.info("[SUBAGENT] Successfully yielded update", {
216
- sessionId: req.sessionId,
217
- toolCallId: messagesUpdate.toolCallId,
218
- });
219
202
  }
220
203
  }
221
204
  // Add agent.session_id as a base attribute so it propagates to all child spans
@@ -1330,10 +1313,6 @@ export class LangchainAgent {
1330
1313
  yield* yieldPendingSubagentUpdates();
1331
1314
  // Keep polling for subagent messages after stream ends
1332
1315
  // This ensures we capture messages that arrive after LangChain stream completes
1333
- _logger.info("[SUBAGENT] Starting post-stream polling for subagent messages", {
1334
- sessionId: req.sessionId,
1335
- activeSubagentCount: activeSubagentToolCalls.size,
1336
- });
1337
1316
  const checkInterval = 100; // Check every 100ms
1338
1317
  const maxIdleTime = 5000; // Stop if no messages for 5 seconds (fallback)
1339
1318
  const maxWaitTime = 300000; // Absolute max 5 minutes
@@ -1343,28 +1322,15 @@ export class LangchainAgent {
1343
1322
  // Check if all subagent tool calls have completed
1344
1323
  if (activeSubagentToolCalls.size > 0 &&
1345
1324
  completedSubagentToolCalls.size >= activeSubagentToolCalls.size) {
1346
- _logger.info("[SUBAGENT] All subagent tool calls completed", {
1347
- sessionId: req.sessionId,
1348
- totalSubagents: activeSubagentToolCalls.size,
1349
- completedCount: completedSubagentToolCalls.size,
1350
- });
1351
1325
  break;
1352
1326
  }
1353
1327
  // Check if there are pending messages
1354
1328
  if (subagentMessagesQueue.length > 0) {
1355
- _logger.info("[SUBAGENT] Found pending messages, yielding", {
1356
- sessionId: req.sessionId,
1357
- queueLength: subagentMessagesQueue.length,
1358
- });
1359
1329
  yield* yieldPendingSubagentUpdates();
1360
1330
  lastMessageTime = Date.now();
1361
1331
  }
1362
1332
  // Stop if we haven't seen messages for maxIdleTime (fallback for no subagents)
1363
1333
  if (Date.now() - lastMessageTime > maxIdleTime) {
1364
- _logger.info("[SUBAGENT] No new messages for 5 seconds, finishing", {
1365
- sessionId: req.sessionId,
1366
- hasActiveSubagents: activeSubagentToolCalls.size > 0,
1367
- });
1368
1334
  break;
1369
1335
  }
1370
1336
  // Wait a bit before checking again
@@ -1377,9 +1343,6 @@ export class LangchainAgent {
1377
1343
  }
1378
1344
  // Final yield of any remaining messages
1379
1345
  yield* yieldPendingSubagentUpdates();
1380
- _logger.info("[SUBAGENT] Finished post-stream polling", {
1381
- sessionId: req.sessionId,
1382
- });
1383
1346
  // Now that content streaming is complete, yield all buffered tool call notifications
1384
1347
  yield* flushPendingToolCalls();
1385
1348
  // Clean up subagent event listener from invocation-scoped emitter