@wingman-ai/gateway 0.5.0 → 0.5.1

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.
Files changed (30) hide show
  1. package/dist/cli/core/agentInvoker.cjs +351 -12
  2. package/dist/cli/core/agentInvoker.d.ts +18 -1
  3. package/dist/cli/core/agentInvoker.js +319 -4
  4. package/dist/cli/core/outputManager.cjs +22 -1
  5. package/dist/cli/core/outputManager.d.ts +17 -1
  6. package/dist/cli/core/outputManager.js +22 -1
  7. package/dist/cli/types.d.ts +18 -1
  8. package/dist/cli/ui/App.cjs +2 -0
  9. package/dist/cli/ui/App.js +2 -0
  10. package/dist/gateway/server.cjs +1 -0
  11. package/dist/gateway/server.js +1 -0
  12. package/dist/tests/agentInvokerSummarization.test.cjs +139 -0
  13. package/dist/tests/agentInvokerSummarization.test.js +140 -1
  14. package/dist/tests/agentInvokerTokenUsage.test.cjs +124 -0
  15. package/dist/tests/agentInvokerTokenUsage.test.d.ts +1 -0
  16. package/dist/tests/agentInvokerTokenUsage.test.js +118 -0
  17. package/dist/tests/gateway-http-security.test.cjs +20 -0
  18. package/dist/tests/gateway-http-security.test.js +20 -0
  19. package/dist/tests/integration/summarization-e2e.integration.test.cjs +127 -0
  20. package/dist/tests/integration/summarization-e2e.integration.test.d.ts +1 -0
  21. package/dist/tests/integration/summarization-e2e.integration.test.js +121 -0
  22. package/dist/tests/outputManagerContextSummarized.test.cjs +43 -0
  23. package/dist/tests/outputManagerContextSummarized.test.d.ts +1 -0
  24. package/dist/tests/outputManagerContextSummarized.test.js +37 -0
  25. package/dist/webui/assets/index-B6qyPEtp.css +11 -0
  26. package/dist/webui/assets/index-KjBVmiHF.js +215 -0
  27. package/dist/webui/index.html +2 -2
  28. package/package.json +2 -1
  29. package/dist/webui/assets/index-_GQBoNDx.js +0 -215
  30. package/dist/webui/assets/index-tPN3uQMb.css +0 -11
@@ -24,27 +24,35 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
+ chunkSignalsActiveSummarization: ()=>chunkSignalsActiveSummarization,
28
+ resolveAgentMemorySources: ()=>resolveAgentMemorySources,
29
+ emitCompletionAndContinuePostProcessing: ()=>emitCompletionAndContinuePostProcessing,
30
+ buildUserContent: ()=>buildUserContent,
31
+ mergeTokenUsageSnapshots: ()=>mergeTokenUsageSnapshots,
32
+ toWorkspaceAliasVirtualPath: ()=>toWorkspaceAliasVirtualPath,
33
+ detectContextSummarizationTransition: ()=>detectContextSummarizationTransition,
34
+ AgentInvoker: ()=>AgentInvoker,
35
+ configureDeepAgentSummarizationMiddleware: ()=>configureDeepAgentSummarizationMiddleware,
36
+ resolveHumanInTheLoopSettings: ()=>resolveHumanInTheLoopSettings,
37
+ isRootLangGraphTerminalEvent: ()=>isRootLangGraphTerminalEvent,
27
38
  resolveToolRetryMiddlewareSettings: ()=>resolveToolRetryMiddlewareSettings,
28
39
  resolveSummarizationMiddlewareSettings: ()=>resolveSummarizationMiddlewareSettings,
29
- resolveAgentMemorySources: ()=>resolveAgentMemorySources,
40
+ chunkBelongsToSummarizationMiddleware: ()=>chunkBelongsToSummarizationMiddleware,
41
+ recompileDeepAgentWithMiddlewareOverrides: ()=>recompileDeepAgentWithMiddlewareOverrides,
42
+ chunkHasBuiltInSummarizationSignal: ()=>chunkHasBuiltInSummarizationSignal,
30
43
  OUTPUT_VIRTUAL_PATH: ()=>OUTPUT_VIRTUAL_PATH,
31
- emitCompletionAndContinuePostProcessing: ()=>emitCompletionAndContinuePostProcessing,
32
44
  resolveExecutionWorkspace: ()=>resolveExecutionWorkspace,
33
- buildUserContent: ()=>buildUserContent,
34
45
  detectStreamErrorMessage: ()=>detectStreamErrorMessage,
35
- toWorkspaceAliasVirtualPath: ()=>toWorkspaceAliasVirtualPath,
46
+ trackRootLangGraphRunId: ()=>trackRootLangGraphRunId,
36
47
  chunkHasAssistantText: ()=>chunkHasAssistantText,
37
48
  resolveModelRetryMiddlewareSettings: ()=>resolveModelRetryMiddlewareSettings,
38
- AgentInvoker: ()=>AgentInvoker,
39
- configureDeepAgentSummarizationMiddleware: ()=>configureDeepAgentSummarizationMiddleware,
40
49
  WORKDIR_VIRTUAL_PATH: ()=>WORKDIR_VIRTUAL_PATH,
41
50
  detectToolEventContext: ()=>detectToolEventContext,
42
51
  resolveExternalOutputMount: ()=>resolveExternalOutputMount,
43
- resolveHumanInTheLoopSettings: ()=>resolveHumanInTheLoopSettings,
44
- trackRootLangGraphRunId: ()=>trackRootLangGraphRunId,
45
- isRootLangGraphTerminalEvent: ()=>isRootLangGraphTerminalEvent,
52
+ extractTokenUsageSnapshot: ()=>extractTokenUsageSnapshot,
46
53
  selectStreamingFallbackText: ()=>selectStreamingFallbackText,
47
54
  AGENTS_MEMORY_VIRTUAL_PATHS: ()=>AGENTS_MEMORY_VIRTUAL_PATHS,
55
+ estimateContextTokensFromChunk: ()=>estimateContextTokensFromChunk,
48
56
  resolveAgentExecutionWorkspace: ()=>resolveAgentExecutionWorkspace
49
57
  });
50
58
  const external_node_fs_namespaceObject = require("node:fs");
@@ -173,6 +181,13 @@ const configureDeepAgentSummarizationMiddleware = (agent, settings, model)=>{
173
181
  }
174
182
  });
175
183
  };
184
+ const recompileDeepAgentWithMiddlewareOverrides = (agent)=>{
185
+ if (agent && "object" == typeof agent) {
186
+ const maybeWithConfig = agent.withConfig;
187
+ if ("function" == typeof maybeWithConfig) return maybeWithConfig.call(agent, {});
188
+ }
189
+ return agent;
190
+ };
176
191
  const detectToolEventContext = (chunk)=>{
177
192
  if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return null;
178
193
  const eventChunk = chunk;
@@ -183,6 +198,85 @@ const detectToolEventContext = (chunk)=>{
183
198
  toolName
184
199
  };
185
200
  };
201
+ const chunkHasBuiltInSummarizationSignal = (chunk)=>{
202
+ if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return false;
203
+ const eventChunk = chunk;
204
+ if ("on_chain_end" !== eventChunk.event || "SummarizationMiddleware.before_model" !== eventChunk.name) return false;
205
+ const data = eventChunk.data && "object" == typeof eventChunk.data && !Array.isArray(eventChunk.data) ? eventChunk.data : null;
206
+ const output = data?.output && "object" == typeof data.output && !Array.isArray(data.output) ? data.output : null;
207
+ const outputMessages = Array.isArray(output?.messages) ? output.messages : [];
208
+ return outputMessages.some((message)=>{
209
+ if (!message || "object" != typeof message || Array.isArray(message)) return false;
210
+ const messageRecord = message;
211
+ const additionalKwargs = messageRecord.additional_kwargs && "object" == typeof messageRecord.additional_kwargs && !Array.isArray(messageRecord.additional_kwargs) ? messageRecord.additional_kwargs : null;
212
+ return additionalKwargs?.lc_source === "summarization";
213
+ });
214
+ };
215
+ const SUMMARIZATION_MIDDLEWARE_NODE = "summarizationmiddleware.before_model";
216
+ const normalizeNodeMarker = (value)=>{
217
+ if ("string" != typeof value) return null;
218
+ const normalized = value.trim().toLowerCase();
219
+ return normalized.length > 0 ? normalized : null;
220
+ };
221
+ const extractSummarizationNodeCandidate = (value)=>{
222
+ if (!value || "object" != typeof value || Array.isArray(value)) return null;
223
+ const record = value;
224
+ const directCandidates = [
225
+ record.langgraph_node,
226
+ record.langgraphNode,
227
+ record.node,
228
+ record.node_id,
229
+ record.nodeId
230
+ ];
231
+ for (const candidate of directCandidates){
232
+ const normalized = normalizeNodeMarker(candidate);
233
+ if (normalized) return normalized;
234
+ }
235
+ const tagCandidates = [
236
+ record.tags,
237
+ record.ls_tags
238
+ ];
239
+ for (const tags of tagCandidates)if (Array.isArray(tags)) for (const tag of tags){
240
+ if ("string" != typeof tag) continue;
241
+ const normalizedTag = tag.trim().toLowerCase();
242
+ if (normalizedTag) {
243
+ if (normalizedTag === `langgraph_node:${SUMMARIZATION_MIDDLEWARE_NODE}`) return SUMMARIZATION_MIDDLEWARE_NODE;
244
+ if (normalizedTag === `langgraph_node=${SUMMARIZATION_MIDDLEWARE_NODE}`) return SUMMARIZATION_MIDDLEWARE_NODE;
245
+ }
246
+ }
247
+ return null;
248
+ };
249
+ const chunkBelongsToSummarizationMiddleware = (chunk)=>{
250
+ if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return false;
251
+ const eventChunk = chunk;
252
+ const nameNode = normalizeNodeMarker(eventChunk.name);
253
+ if (nameNode === SUMMARIZATION_MIDDLEWARE_NODE) return true;
254
+ const metadataCandidates = [
255
+ eventChunk.metadata,
256
+ eventChunk.data?.metadata,
257
+ eventChunk.data?.chunk,
258
+ eventChunk.data?.message
259
+ ];
260
+ for (const candidate of metadataCandidates){
261
+ const node = extractSummarizationNodeCandidate(candidate);
262
+ if (node === SUMMARIZATION_MIDDLEWARE_NODE) return true;
263
+ }
264
+ return false;
265
+ };
266
+ const SUMMARIZATION_ACTIVE_EVENTS = new Set([
267
+ "on_chat_model_start",
268
+ "on_chat_model_stream",
269
+ "on_chat_model_end",
270
+ "on_llm_start",
271
+ "on_llm_stream",
272
+ "on_llm_end"
273
+ ]);
274
+ const chunkSignalsActiveSummarization = (chunk)=>{
275
+ if (!chunkBelongsToSummarizationMiddleware(chunk)) return false;
276
+ if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return false;
277
+ const eventName = chunk.event;
278
+ return "string" == typeof eventName && SUMMARIZATION_ACTIVE_EVENTS.has(eventName);
279
+ };
186
280
  const chunkHasAssistantText = (chunk)=>{
187
281
  if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return false;
188
282
  const eventChunk = chunk;
@@ -244,6 +338,202 @@ const detectStreamErrorMessage = (chunk)=>{
244
338
  if (null != errorPayload) return String(errorPayload);
245
339
  return eventName;
246
340
  };
341
+ const getFiniteTokenNumber = (value)=>"number" == typeof value && Number.isFinite(value) ? value : 0;
342
+ const asRecord = (value)=>value && "object" == typeof value && !Array.isArray(value) ? value : null;
343
+ const collectTokenUsageSnapshot = (target, payload, visited, depth)=>{
344
+ if (depth > 8 || !payload || "object" != typeof payload) return;
345
+ if (visited.has(payload)) return;
346
+ visited.add(payload);
347
+ const record = payload;
348
+ const directInput = getFiniteTokenNumber(record.input_tokens) || getFiniteTokenNumber(record.inputTokens) || getFiniteTokenNumber(record.prompt_tokens) || getFiniteTokenNumber(record.promptTokens);
349
+ const directOutput = getFiniteTokenNumber(record.output_tokens) || getFiniteTokenNumber(record.outputTokens) || getFiniteTokenNumber(record.completion_tokens) || getFiniteTokenNumber(record.completionTokens);
350
+ const directTotal = getFiniteTokenNumber(record.total_tokens) || getFiniteTokenNumber(record.totalTokens);
351
+ if (directInput > 0) target.inputTokens = Math.max(target.inputTokens, directInput);
352
+ if (directOutput > 0) target.outputTokens = Math.max(target.outputTokens, directOutput);
353
+ if (directTotal > 0) target.totalTokens = Math.max(target.totalTokens, directTotal);
354
+ const nestedCandidates = [
355
+ record.usage,
356
+ record.usage_metadata,
357
+ record.usageMetadata,
358
+ record.tokenUsage,
359
+ record.response_metadata,
360
+ record.responseMetadata,
361
+ record.additional_kwargs,
362
+ record.additionalKwargs,
363
+ record.metadata,
364
+ record.data,
365
+ record.output,
366
+ record.message,
367
+ record.chunk
368
+ ];
369
+ for (const nested of nestedCandidates)collectTokenUsageSnapshot(target, nested, visited, depth + 1);
370
+ };
371
+ const extractTokenUsageSnapshot = (payload)=>{
372
+ const snapshot = {
373
+ inputTokens: 0,
374
+ outputTokens: 0,
375
+ totalTokens: 0
376
+ };
377
+ const visited = new WeakSet();
378
+ collectTokenUsageSnapshot(snapshot, payload, visited, 0);
379
+ if (0 === snapshot.totalTokens) snapshot.totalTokens = snapshot.inputTokens + snapshot.outputTokens;
380
+ if (snapshot.inputTokens <= 0 && snapshot.outputTokens <= 0 && snapshot.totalTokens <= 0) return null;
381
+ return snapshot;
382
+ };
383
+ const getMessageClassName = (message)=>{
384
+ const id = message.id;
385
+ if (Array.isArray(id) && id.length > 0) {
386
+ const tail = id[id.length - 1];
387
+ if ("string" == typeof tail) return tail.trim().toLowerCase();
388
+ }
389
+ const type = "string" == typeof message.type ? message.type : "";
390
+ return type.trim().toLowerCase();
391
+ };
392
+ const getMessageRole = (message)=>{
393
+ const kwargs = asRecord(message.kwargs);
394
+ const additionalKwargs = asRecord(message.additional_kwargs);
395
+ const additionalKwargsCamel = asRecord(message.additionalKwargs);
396
+ const candidates = [
397
+ message.role,
398
+ kwargs?.role,
399
+ additionalKwargs?.role,
400
+ additionalKwargsCamel?.role
401
+ ];
402
+ for (const candidate of candidates)if ("string" == typeof candidate && candidate.trim()) return candidate.trim().toLowerCase();
403
+ return "";
404
+ };
405
+ const isMessageLikeRecord = (value)=>{
406
+ const record = asRecord(value);
407
+ if (!record) return false;
408
+ const role = getMessageRole(record);
409
+ if ("user" === role || "human" === role || "assistant" === role || "ai" === role || "system" === role || "tool" === role) return true;
410
+ const className = getMessageClassName(record);
411
+ if (className.includes("humanmessage") || className.includes("aimessage") || className.includes("toolmessage") || className.includes("systemmessage")) return true;
412
+ return "human" === className || "user" === className || "assistant" === className || "ai" === className || "system" === className || "tool" === className;
413
+ };
414
+ const extractTextFromContent = (content)=>{
415
+ if ("string" == typeof content) return content;
416
+ if (!Array.isArray(content)) return "";
417
+ return content.map((item)=>{
418
+ if ("string" == typeof item) return item;
419
+ const record = asRecord(item);
420
+ if (!record) return "";
421
+ if ("text" === record.type && "string" == typeof record.text) return record.text;
422
+ return "string" == typeof record.text ? record.text : "";
423
+ }).join("");
424
+ };
425
+ const extractMessageContent = (message)=>{
426
+ const kwargs = asRecord(message.kwargs);
427
+ const additionalKwargs = asRecord(message.additional_kwargs);
428
+ const additionalKwargsCamel = asRecord(message.additionalKwargs);
429
+ const candidates = [
430
+ message.content,
431
+ kwargs?.content,
432
+ additionalKwargs?.content,
433
+ additionalKwargsCamel?.content
434
+ ];
435
+ for (const candidate of candidates){
436
+ const extracted = extractTextFromContent(candidate);
437
+ if (extracted.length > 0) return extracted;
438
+ }
439
+ return "";
440
+ };
441
+ const extractToolCalls = (message)=>{
442
+ const kwargs = asRecord(message.kwargs);
443
+ const candidates = [
444
+ message.tool_calls,
445
+ message.toolCalls,
446
+ kwargs?.tool_calls,
447
+ kwargs?.toolCalls
448
+ ];
449
+ for (const candidate of candidates)if (Array.isArray(candidate) && candidate.length > 0) return candidate;
450
+ return [];
451
+ };
452
+ const extractToolCallId = (message)=>{
453
+ const kwargs = asRecord(message.kwargs);
454
+ const candidates = [
455
+ message.tool_call_id,
456
+ message.toolCallId,
457
+ kwargs?.tool_call_id,
458
+ kwargs?.toolCallId
459
+ ];
460
+ for (const candidate of candidates)if ("string" == typeof candidate && candidate.trim()) return candidate.trim();
461
+ return "";
462
+ };
463
+ const isAiMessageRecord = (message)=>{
464
+ const role = getMessageRole(message);
465
+ if ("assistant" === role || "ai" === role) return true;
466
+ const className = getMessageClassName(message);
467
+ return "ai" === className || "assistant" === className || className.includes("aimessage");
468
+ };
469
+ const isToolMessageRecord = (message)=>{
470
+ const role = getMessageRole(message);
471
+ if ("tool" === role) return true;
472
+ const className = getMessageClassName(message);
473
+ return "tool" === className || className.includes("toolmessage");
474
+ };
475
+ const estimateTokensForMessageArray = (messages)=>{
476
+ if (0 === messages.length) return 0;
477
+ let totalChars = 0;
478
+ for (const message of messages){
479
+ let textContent = extractMessageContent(message);
480
+ if (isAiMessageRecord(message)) {
481
+ const toolCalls = extractToolCalls(message);
482
+ if (toolCalls.length > 0) textContent += JSON.stringify(toolCalls);
483
+ }
484
+ if (isToolMessageRecord(message)) textContent += extractToolCallId(message);
485
+ totalChars += textContent.length;
486
+ }
487
+ return Math.ceil(totalChars / 4);
488
+ };
489
+ const collectMessageArraysFromPayload = (target, payload, visited, depth)=>{
490
+ if (depth > 7 || !payload || "object" != typeof payload) return;
491
+ if (visited.has(payload)) return;
492
+ visited.add(payload);
493
+ if (Array.isArray(payload)) {
494
+ const messageRecords = payload.filter(isMessageLikeRecord);
495
+ if (messageRecords.length > 0) target.push(messageRecords);
496
+ for (const item of payload)collectMessageArraysFromPayload(target, item, visited, depth + 1);
497
+ return;
498
+ }
499
+ const record = payload;
500
+ const directMessages = record.messages;
501
+ if (Array.isArray(directMessages)) {
502
+ const messageRecords = directMessages.filter(isMessageLikeRecord);
503
+ if (messageRecords.length > 0) target.push(messageRecords);
504
+ }
505
+ for (const nested of Object.values(record))if (nested && "object" == typeof nested) collectMessageArraysFromPayload(target, nested, visited, depth + 1);
506
+ };
507
+ const estimateContextTokensFromChunk = (chunk)=>{
508
+ const candidates = [];
509
+ collectMessageArraysFromPayload(candidates, chunk, new WeakSet(), 0);
510
+ if (0 === candidates.length) return null;
511
+ let estimate = 0;
512
+ for (const candidate of candidates){
513
+ const tokens = estimateTokensForMessageArray(candidate);
514
+ if (tokens > estimate) estimate = tokens;
515
+ }
516
+ return estimate > 0 ? estimate : null;
517
+ };
518
+ const detectContextSummarizationTransition = ({ thresholdTokens, peakInputTokens, currentInputTokens })=>{
519
+ if (!Number.isFinite(thresholdTokens) || !Number.isFinite(peakInputTokens) || !Number.isFinite(currentInputTokens)) return false;
520
+ if (thresholdTokens <= 0 || peakInputTokens <= 0 || currentInputTokens <= 0) return false;
521
+ if (peakInputTokens < 0.9 * thresholdTokens) return false;
522
+ if (currentInputTokens > 0.65 * thresholdTokens) return false;
523
+ if (currentInputTokens > 0.75 * peakInputTokens) return false;
524
+ return true;
525
+ };
526
+ const mergeTokenUsageSnapshots = (current, next)=>{
527
+ if (!next) return current;
528
+ if (!current) return next;
529
+ const merged = {
530
+ inputTokens: Math.max(current.inputTokens, next.inputTokens),
531
+ outputTokens: Math.max(current.outputTokens, next.outputTokens),
532
+ totalTokens: Math.max(current.totalTokens, next.totalTokens)
533
+ };
534
+ if (0 === merged.totalTokens) merged.totalTokens = merged.inputTokens + merged.outputTokens;
535
+ return merged;
536
+ };
247
537
  const extractStreamEventRecord = (chunk)=>{
248
538
  if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return null;
249
539
  const record = chunk;
@@ -483,7 +773,7 @@ class AgentInvoker {
483
773
  rootDir: outputMount.absolutePath,
484
774
  virtualMode: true
485
775
  });
486
- const standaloneAgent = (0, external_deepagents_namespaceObject.createDeepAgent)({
776
+ let standaloneAgent = (0, external_deepagents_namespaceObject.createDeepAgent)({
487
777
  systemPrompt: targetAgent.systemPrompt,
488
778
  tools: targetAgent.tools,
489
779
  model: targetAgent.model,
@@ -499,10 +789,15 @@ class AgentInvoker {
499
789
  checkpointer: checkpointer
500
790
  });
501
791
  configureDeepAgentSummarizationMiddleware(standaloneAgent, summarizationSettings, targetAgent.model);
792
+ standaloneAgent = recompileDeepAgentWithMiddlewareOverrides(standaloneAgent);
502
793
  this.logger.debug("Agent created, sending message");
503
794
  const userContent = buildUserContent(prompt, attachments, targetAgent.model);
504
795
  if (this.sessionManager && sessionId) {
505
796
  this.logger.debug(`Using streaming with session: ${sessionId}`);
797
+ let streamTokenUsage = null;
798
+ let streamEstimatedContextTokens = 0;
799
+ let contextSummarizationStarted = false;
800
+ let contextSummarizationEmitted = false;
506
801
  const stream = await standaloneAgent.streamEvents({
507
802
  messages: [
508
803
  {
@@ -535,7 +830,32 @@ class AgentInvoker {
535
830
  cancelled: true
536
831
  };
537
832
  }
538
- this.outputManager.emitAgentStream(chunk);
833
+ const chunkTokenUsage = extractTokenUsageSnapshot(chunk);
834
+ streamTokenUsage = mergeTokenUsageSnapshots(streamTokenUsage, chunkTokenUsage);
835
+ const isSummarizationChunk = chunkBelongsToSummarizationMiddleware(chunk);
836
+ const isActiveSummarizationChunk = chunkSignalsActiveSummarization(chunk);
837
+ if (isActiveSummarizationChunk && !contextSummarizationStarted) {
838
+ contextSummarizationStarted = true;
839
+ this.outputManager.emitContextSummarizing();
840
+ }
841
+ if (!isSummarizationChunk) {
842
+ const chunkEstimatedContextTokens = estimateContextTokensFromChunk(chunk);
843
+ if ("number" == typeof chunkEstimatedContextTokens && Number.isFinite(chunkEstimatedContextTokens) && chunkEstimatedContextTokens > streamEstimatedContextTokens) streamEstimatedContextTokens = chunkEstimatedContextTokens;
844
+ this.outputManager.emitAgentStream(chunk, chunkTokenUsage || void 0, streamEstimatedContextTokens > 0 ? streamEstimatedContextTokens : void 0);
845
+ }
846
+ if (!contextSummarizationEmitted && summarizationSettings && chunkHasBuiltInSummarizationSignal(chunk)) {
847
+ if (!contextSummarizationStarted) {
848
+ contextSummarizationStarted = true;
849
+ this.outputManager.emitContextSummarizing();
850
+ }
851
+ contextSummarizationEmitted = true;
852
+ const observedInputTokens = chunkTokenUsage?.inputTokens || 0;
853
+ this.outputManager.emitContextSummarized({
854
+ inputTokens: observedInputTokens,
855
+ peakInputTokens: observedInputTokens,
856
+ thresholdTokens: summarizationSettings.maxTokensBeforeSummary
857
+ });
858
+ }
539
859
  if (isRootLangGraphTerminalEvent(chunk, rootLangGraphRunId)) {
540
860
  this.logger.debug("Detected root LangGraph on_chain_end event; finalizing stream without waiting for iterator shutdown");
541
861
  break;
@@ -550,7 +870,10 @@ class AgentInvoker {
550
870
  };
551
871
  }
552
872
  this.logger.info("Agent streaming completed successfully");
553
- const completionPayload = {
873
+ const completionPayload = streamTokenUsage ? {
874
+ streaming: true,
875
+ tokenUsage: streamTokenUsage
876
+ } : {
554
877
  streaming: true
555
878
  };
556
879
  emitCompletionAndContinuePostProcessing({
@@ -869,12 +1192,20 @@ exports.AgentInvoker = __webpack_exports__.AgentInvoker;
869
1192
  exports.OUTPUT_VIRTUAL_PATH = __webpack_exports__.OUTPUT_VIRTUAL_PATH;
870
1193
  exports.WORKDIR_VIRTUAL_PATH = __webpack_exports__.WORKDIR_VIRTUAL_PATH;
871
1194
  exports.buildUserContent = __webpack_exports__.buildUserContent;
1195
+ exports.chunkBelongsToSummarizationMiddleware = __webpack_exports__.chunkBelongsToSummarizationMiddleware;
872
1196
  exports.chunkHasAssistantText = __webpack_exports__.chunkHasAssistantText;
1197
+ exports.chunkHasBuiltInSummarizationSignal = __webpack_exports__.chunkHasBuiltInSummarizationSignal;
1198
+ exports.chunkSignalsActiveSummarization = __webpack_exports__.chunkSignalsActiveSummarization;
873
1199
  exports.configureDeepAgentSummarizationMiddleware = __webpack_exports__.configureDeepAgentSummarizationMiddleware;
1200
+ exports.detectContextSummarizationTransition = __webpack_exports__.detectContextSummarizationTransition;
874
1201
  exports.detectStreamErrorMessage = __webpack_exports__.detectStreamErrorMessage;
875
1202
  exports.detectToolEventContext = __webpack_exports__.detectToolEventContext;
876
1203
  exports.emitCompletionAndContinuePostProcessing = __webpack_exports__.emitCompletionAndContinuePostProcessing;
1204
+ exports.estimateContextTokensFromChunk = __webpack_exports__.estimateContextTokensFromChunk;
1205
+ exports.extractTokenUsageSnapshot = __webpack_exports__.extractTokenUsageSnapshot;
877
1206
  exports.isRootLangGraphTerminalEvent = __webpack_exports__.isRootLangGraphTerminalEvent;
1207
+ exports.mergeTokenUsageSnapshots = __webpack_exports__.mergeTokenUsageSnapshots;
1208
+ exports.recompileDeepAgentWithMiddlewareOverrides = __webpack_exports__.recompileDeepAgentWithMiddlewareOverrides;
878
1209
  exports.resolveAgentExecutionWorkspace = __webpack_exports__.resolveAgentExecutionWorkspace;
879
1210
  exports.resolveAgentMemorySources = __webpack_exports__.resolveAgentMemorySources;
880
1211
  exports.resolveExecutionWorkspace = __webpack_exports__.resolveExecutionWorkspace;
@@ -892,12 +1223,20 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
892
1223
  "OUTPUT_VIRTUAL_PATH",
893
1224
  "WORKDIR_VIRTUAL_PATH",
894
1225
  "buildUserContent",
1226
+ "chunkBelongsToSummarizationMiddleware",
895
1227
  "chunkHasAssistantText",
1228
+ "chunkHasBuiltInSummarizationSignal",
1229
+ "chunkSignalsActiveSummarization",
896
1230
  "configureDeepAgentSummarizationMiddleware",
1231
+ "detectContextSummarizationTransition",
897
1232
  "detectStreamErrorMessage",
898
1233
  "detectToolEventContext",
899
1234
  "emitCompletionAndContinuePostProcessing",
1235
+ "estimateContextTokensFromChunk",
1236
+ "extractTokenUsageSnapshot",
900
1237
  "isRootLangGraphTerminalEvent",
1238
+ "mergeTokenUsageSnapshots",
1239
+ "recompileDeepAgentWithMiddlewareOverrides",
901
1240
  "resolveAgentExecutionWorkspace",
902
1241
  "resolveAgentMemorySources",
903
1242
  "resolveExecutionWorkspace",
@@ -1,8 +1,8 @@
1
1
  import type { WingmanAgentConfig } from "@/agent/config/agentConfig.js";
2
2
  import { type MCPProxyConfig } from "@/agent/config/mcpClientManager.js";
3
3
  import { type ConnectedNodeTarget } from "@/agent/middleware/additional-messages.js";
4
- import { type TerminalSessionManager } from "@/agent/tools/terminal_session_manager.js";
5
4
  import type { NodeInvokeRequest, NodeInvokeResult } from "@/agent/tools/node_invoke.js";
5
+ import { type TerminalSessionManager } from "@/agent/tools/terminal_session_manager.js";
6
6
  import type { WingmanAgent } from "@/types/agents.js";
7
7
  import type { Logger } from "../../logger.js";
8
8
  import type { WingmanConfigType } from "../config/schema.js";
@@ -114,6 +114,11 @@ export type HumanInTheLoopSettings = {
114
114
  argsSchema?: Record<string, any>;
115
115
  }>;
116
116
  };
117
+ export type TokenUsageSnapshot = {
118
+ inputTokens: number;
119
+ outputTokens: number;
120
+ totalTokens: number;
121
+ };
117
122
  export declare const resolveExecutionWorkspace: (workspace: string, workdir?: string | null) => string;
118
123
  export declare const resolveAgentExecutionWorkspace: (workspace: string, workdir?: string | null, defaultOutputDir?: string | null) => string;
119
124
  export declare const resolveAgentMemorySources: (executionWorkspace: string) => string[];
@@ -124,11 +129,15 @@ export declare const resolveModelRetryMiddlewareSettings: (config: WingmanConfig
124
129
  export declare const resolveToolRetryMiddlewareSettings: (config: WingmanConfigType) => ToolRetryMiddlewareSettings | null;
125
130
  export declare const resolveHumanInTheLoopSettings: (config: WingmanConfigType) => HumanInTheLoopSettings | null;
126
131
  export declare const configureDeepAgentSummarizationMiddleware: (agent: any, settings: SummarizationMiddlewareSettings | null, model?: any) => void;
132
+ export declare const recompileDeepAgentWithMiddlewareOverrides: <T>(agent: T) => T;
127
133
  type ToolEventContext = {
128
134
  event: "on_tool_start" | "on_tool_end" | "on_tool_error";
129
135
  toolName: string;
130
136
  };
131
137
  export declare const detectToolEventContext: (chunk: unknown) => ToolEventContext | null;
138
+ export declare const chunkHasBuiltInSummarizationSignal: (chunk: unknown) => boolean;
139
+ export declare const chunkBelongsToSummarizationMiddleware: (chunk: unknown) => boolean;
140
+ export declare const chunkSignalsActiveSummarization: (chunk: unknown) => boolean;
132
141
  export declare const chunkHasAssistantText: (chunk: unknown) => boolean;
133
142
  export declare const selectStreamingFallbackText: (previousMessages: Array<{
134
143
  role?: unknown;
@@ -138,6 +147,14 @@ export declare const selectStreamingFallbackText: (previousMessages: Array<{
138
147
  content?: unknown;
139
148
  }>) => string | undefined;
140
149
  export declare const detectStreamErrorMessage: (chunk: unknown) => string | undefined;
150
+ export declare const extractTokenUsageSnapshot: (payload: unknown) => TokenUsageSnapshot | null;
151
+ export declare const estimateContextTokensFromChunk: (chunk: unknown) => number | null;
152
+ export declare const detectContextSummarizationTransition: ({ thresholdTokens, peakInputTokens, currentInputTokens, }: {
153
+ thresholdTokens: number;
154
+ peakInputTokens: number;
155
+ currentInputTokens: number;
156
+ }) => boolean;
157
+ export declare const mergeTokenUsageSnapshots: (current: TokenUsageSnapshot | null, next: TokenUsageSnapshot | null) => TokenUsageSnapshot | null;
141
158
  export declare const trackRootLangGraphRunId: (currentRootLangGraphRunId: string | undefined, chunk: unknown) => string | undefined;
142
159
  export declare const isRootLangGraphTerminalEvent: (chunk: unknown, rootLangGraphRunId?: string) => boolean;
143
160
  export declare const emitCompletionAndContinuePostProcessing: (input: {