{"version":3,"file":"finalize-events.mjs","names":[],"sources":["../src/finalize-events.ts"],"sourcesContent":["import { BaseEvent, EventType, RunErrorEvent } from \"@ag-ui/client\";\nimport { randomUUID } from \"./utils\";\n\ninterface FinalizeRunOptions {\n  stopRequested?: boolean;\n  interruptionMessage?: string;\n}\n\nconst defaultStopMessage = \"Run stopped by user\";\nconst defaultAbruptEndMessage = \"Run ended without emitting a terminal event\";\n\nexport function finalizeRunEvents(\n  events: BaseEvent[],\n  options: FinalizeRunOptions = {},\n): BaseEvent[] {\n  const { stopRequested = false, interruptionMessage } = options;\n\n  const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;\n  const resolvedAbruptMessage =\n    interruptionMessage && interruptionMessage !== defaultStopMessage\n      ? interruptionMessage\n      : defaultAbruptEndMessage;\n\n  const appended: BaseEvent[] = [];\n\n  const openMessageIds = new Set<string>();\n  const openToolCalls = new Map<\n    string,\n    {\n      hasEnd: boolean;\n      hasResult: boolean;\n    }\n  >();\n\n  for (const event of events) {\n    switch (event.type) {\n      case EventType.TEXT_MESSAGE_START: {\n        const messageId = (event as { messageId?: string }).messageId;\n        if (typeof messageId === \"string\") {\n          openMessageIds.add(messageId);\n        }\n        break;\n      }\n      case EventType.TEXT_MESSAGE_END: {\n        const messageId = (event as { messageId?: string }).messageId;\n        if (typeof messageId === \"string\") {\n          openMessageIds.delete(messageId);\n        }\n        break;\n      }\n      case EventType.TOOL_CALL_START: {\n        const toolCallId = (event as { toolCallId?: string }).toolCallId;\n        if (typeof toolCallId === \"string\") {\n          openToolCalls.set(toolCallId, {\n            hasEnd: false,\n            hasResult: false,\n          });\n        }\n        break;\n      }\n      case EventType.TOOL_CALL_END: {\n        const toolCallId = (event as { toolCallId?: string }).toolCallId;\n        const info = toolCallId ? openToolCalls.get(toolCallId) : undefined;\n        if (info) {\n          info.hasEnd = true;\n        }\n        break;\n      }\n      case EventType.TOOL_CALL_RESULT: {\n        const toolCallId = (event as { toolCallId?: string }).toolCallId;\n        const info = toolCallId ? openToolCalls.get(toolCallId) : undefined;\n        if (info) {\n          info.hasResult = true;\n        }\n        break;\n      }\n      default:\n        break;\n    }\n  }\n\n  const hasRunFinished = events.some(\n    (event) => event.type === EventType.RUN_FINISHED,\n  );\n  const hasRunError = events.some(\n    (event) => event.type === EventType.RUN_ERROR,\n  );\n  const hasTerminalEvent = hasRunFinished || hasRunError;\n  const terminalEventMissing = !hasTerminalEvent;\n\n  for (const messageId of openMessageIds) {\n    const endEvent = {\n      type: EventType.TEXT_MESSAGE_END,\n      messageId,\n    } as BaseEvent;\n    events.push(endEvent);\n    appended.push(endEvent);\n  }\n\n  for (const [toolCallId, info] of openToolCalls) {\n    if (!info.hasEnd) {\n      const endEvent = {\n        type: EventType.TOOL_CALL_END,\n        toolCallId,\n      } as BaseEvent;\n      events.push(endEvent);\n      appended.push(endEvent);\n    }\n\n    if (terminalEventMissing && !info.hasResult) {\n      const resultEvent = {\n        type: EventType.TOOL_CALL_RESULT,\n        toolCallId,\n        messageId: `${toolCallId ?? randomUUID()}-result`,\n        role: \"tool\",\n        content: JSON.stringify(\n          stopRequested\n            ? {\n                status: \"stopped\",\n                reason: \"stop_requested\",\n                message: resolvedStopMessage,\n              }\n            : {\n                status: \"error\",\n                reason: \"missing_terminal_event\",\n                message: resolvedAbruptMessage,\n              },\n        ),\n      } as BaseEvent;\n      events.push(resultEvent);\n      appended.push(resultEvent);\n    }\n  }\n\n  if (terminalEventMissing) {\n    if (stopRequested) {\n      const finishedEvent = {\n        type: EventType.RUN_FINISHED,\n      } as BaseEvent;\n      events.push(finishedEvent);\n      appended.push(finishedEvent);\n    } else {\n      const errorEvent: RunErrorEvent = {\n        type: EventType.RUN_ERROR,\n        message: resolvedAbruptMessage,\n        code: \"INCOMPLETE_STREAM\",\n      };\n      events.push(errorEvent);\n      appended.push(errorEvent);\n    }\n  }\n\n  return appended;\n}\n"],"mappings":";;;;AAQA,MAAM,qBAAqB;AAC3B,MAAM,0BAA0B;AAEhC,SAAgB,kBACd,QACA,UAA8B,EAAE,EACnB;CACb,MAAM,EAAE,gBAAgB,OAAO,wBAAwB;CAEvD,MAAM,sBAAsB,uBAAuB;CACnD,MAAM,wBACJ,uBAAuB,wBAAwB,qBAC3C,sBACA;CAEN,MAAM,WAAwB,EAAE;CAEhC,MAAM,iCAAiB,IAAI,KAAa;CACxC,MAAM,gCAAgB,IAAI,KAMvB;AAEH,MAAK,MAAM,SAAS,OAClB,SAAQ,MAAM,MAAd;EACE,KAAK,UAAU,oBAAoB;GACjC,MAAM,YAAa,MAAiC;AACpD,OAAI,OAAO,cAAc,SACvB,gBAAe,IAAI,UAAU;AAE/B;;EAEF,KAAK,UAAU,kBAAkB;GAC/B,MAAM,YAAa,MAAiC;AACpD,OAAI,OAAO,cAAc,SACvB,gBAAe,OAAO,UAAU;AAElC;;EAEF,KAAK,UAAU,iBAAiB;GAC9B,MAAM,aAAc,MAAkC;AACtD,OAAI,OAAO,eAAe,SACxB,eAAc,IAAI,YAAY;IAC5B,QAAQ;IACR,WAAW;IACZ,CAAC;AAEJ;;EAEF,KAAK,UAAU,eAAe;GAC5B,MAAM,aAAc,MAAkC;GACtD,MAAM,OAAO,aAAa,cAAc,IAAI,WAAW,GAAG;AAC1D,OAAI,KACF,MAAK,SAAS;AAEhB;;EAEF,KAAK,UAAU,kBAAkB;GAC/B,MAAM,aAAc,MAAkC;GACtD,MAAM,OAAO,aAAa,cAAc,IAAI,WAAW,GAAG;AAC1D,OAAI,KACF,MAAK,YAAY;AAEnB;;EAEF,QACE;;CAIN,MAAM,iBAAiB,OAAO,MAC3B,UAAU,MAAM,SAAS,UAAU,aACrC;CACD,MAAM,cAAc,OAAO,MACxB,UAAU,MAAM,SAAS,UAAU,UACrC;CAED,MAAM,uBAAuB,EADJ,kBAAkB;AAG3C,MAAK,MAAM,aAAa,gBAAgB;EACtC,MAAM,WAAW;GACf,MAAM,UAAU;GAChB;GACD;AACD,SAAO,KAAK,SAAS;AACrB,WAAS,KAAK,SAAS;;AAGzB,MAAK,MAAM,CAAC,YAAY,SAAS,eAAe;AAC9C,MAAI,CAAC,KAAK,QAAQ;GAChB,MAAM,WAAW;IACf,MAAM,UAAU;IAChB;IACD;AACD,UAAO,KAAK,SAAS;AACrB,YAAS,KAAK,SAAS;;AAGzB,MAAI,wBAAwB,CAAC,KAAK,WAAW;GAC3C,MAAM,cAAc;IAClB,MAAM,UAAU;IAChB;IACA,WAAW,GAAG,cAAc,YAAY,CAAC;IACzC,MAAM;IACN,SAAS,KAAK,UACZ,gBACI;KACE,QAAQ;KACR,QAAQ;KACR,SAAS;KACV,GACD;KACE,QAAQ;KACR,QAAQ;KACR,SAAS;KACV,CACN;IACF;AACD,UAAO,KAAK,YAAY;AACxB,YAAS,KAAK,YAAY;;;AAI9B,KAAI,qBACF,KAAI,eAAe;EACjB,MAAM,gBAAgB,EACpB,MAAM,UAAU,cACjB;AACD,SAAO,KAAK,cAAc;AAC1B,WAAS,KAAK,cAAc;QACvB;EACL,MAAM,aAA4B;GAChC,MAAM,UAAU;GAChB,SAAS;GACT,MAAM;GACP;AACD,SAAO,KAAK,WAAW;AACvB,WAAS,KAAK,WAAW;;AAI7B,QAAO"}