{"version":3,"file":"stream.custom.cjs","names":["BytesLineDecoder","SSEDecoder","IterableReadableStream","MessageTupleManager","StreamManager","useControllableThreadId","getToolCallsWithResults"],"sources":["../../src/react/stream.custom.tsx"],"sourcesContent":["/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */\n\n\"use client\";\n\nimport { useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport { EventStreamEvent, StreamManager } from \"../ui/manager.js\";\nimport type {\n  GetUpdateType,\n  GetCustomEventType,\n  GetInterruptType,\n  GetToolCallsType,\n  RunCallbackMeta,\n  GetConfigurableType,\n  UseStreamTransport,\n  UseStreamCustomOptions,\n  CustomSubmitOptions,\n} from \"../ui/types.js\";\nimport type { UseStreamCustom } from \"./types.js\";\nimport { type Message } from \"../types.messages.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport { MessageTupleManager } from \"../ui/messages.js\";\nimport { Interrupt } from \"../schema.js\";\nimport { BytesLineDecoder, SSEDecoder } from \"../utils/sse.js\";\nimport { IterableReadableStream } from \"../utils/stream.js\";\nimport { useControllableThreadId } from \"./thread.js\";\nimport { Command } from \"../types.js\";\nimport type { BagTemplate } from \"../types.template.js\";\n\ninterface FetchStreamTransportOptions {\n  /**\n   * The URL of the API to use.\n   */\n  apiUrl: string;\n\n  /**\n   * Default headers to send with requests.\n   */\n  defaultHeaders?: HeadersInit;\n\n  /**\n   * Specify a custom fetch implementation.\n   */\n  fetch?: typeof fetch | ((...args: any[]) => any); // eslint-disable-line @typescript-eslint/no-explicit-any\n\n  /**\n   * Callback that is called before the request is made.\n   */\n  onRequest?: (\n    url: string,\n    init: RequestInit\n  ) => Promise<RequestInit> | RequestInit;\n}\n\nexport class FetchStreamTransport<\n  StateType extends Record<string, unknown> = Record<string, unknown>,\n  Bag extends BagTemplate = BagTemplate\n> implements UseStreamTransport<StateType, Bag>\n{\n  constructor(private readonly options: FetchStreamTransportOptions) {}\n\n  async stream(payload: {\n    input: GetUpdateType<Bag, StateType> | null | undefined;\n    context: GetConfigurableType<Bag> | undefined;\n    command: Command | undefined;\n    signal: AbortSignal;\n  }): Promise<AsyncGenerator<{ id?: string; event: string; data: unknown }>> {\n    const { signal, ...body } = payload;\n\n    let requestInit: RequestInit = {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application/json\",\n        ...this.options.defaultHeaders,\n      },\n      body: JSON.stringify(body),\n      signal,\n    };\n\n    if (this.options.onRequest) {\n      requestInit = await this.options.onRequest(\n        this.options.apiUrl,\n        requestInit\n      );\n    }\n    const fetchFn = this.options.fetch ?? fetch;\n\n    const response = await fetchFn(this.options.apiUrl, requestInit);\n    if (!response.ok) {\n      throw new Error(`Failed to stream: ${response.statusText}`);\n    }\n\n    const stream = (\n      response.body || new ReadableStream({ start: (ctrl) => ctrl.close() })\n    )\n      .pipeThrough(BytesLineDecoder())\n      .pipeThrough(SSEDecoder());\n\n    return IterableReadableStream.fromReadableStream(stream);\n  }\n}\n\nexport function useStreamCustom<\n  StateType extends Record<string, unknown> = Record<string, unknown>,\n  Bag extends BagTemplate = BagTemplate\n>(\n  options: UseStreamCustomOptions<StateType, Bag>\n): UseStreamCustom<StateType, Bag> {\n  type UpdateType = GetUpdateType<Bag, StateType>;\n  type CustomType = GetCustomEventType<Bag>;\n  type InterruptType = GetInterruptType<Bag>;\n  type ConfigurableType = GetConfigurableType<Bag>;\n  type ToolCallType = GetToolCallsType<StateType>;\n\n  const [messageManager] = useState(() => new MessageTupleManager());\n  const [stream] = useState(\n    () =>\n      new StreamManager<StateType, Bag>(messageManager, {\n        throttle: options.throttle ?? false,\n      })\n  );\n\n  useSyncExternalStore(\n    stream.subscribe,\n    stream.getSnapshot,\n    stream.getSnapshot\n  );\n\n  const [threadId, onThreadId] = useControllableThreadId(options);\n  const threadIdRef = useRef<string | null>(threadId);\n\n  // Cancel the stream if thread ID has changed\n  useEffect(() => {\n    if (threadIdRef.current !== threadId) {\n      threadIdRef.current = threadId;\n      stream.clear();\n    }\n  }, [threadId, stream]);\n\n  const getMessages = (value: StateType): Message[] => {\n    const messagesKey = options.messagesKey ?? \"messages\";\n    return Array.isArray(value[messagesKey])\n      ? (value[messagesKey] as Message[])\n      : [];\n  };\n\n  const setMessages = (current: StateType, messages: Message[]): StateType => {\n    const messagesKey = options.messagesKey ?? \"messages\";\n    return { ...current, [messagesKey]: messages };\n  };\n\n  const historyValues = options.initialValues ?? ({} as StateType);\n\n  const stop = () => stream.stop(historyValues, { onStop: options.onStop });\n\n  const submit = async (\n    values: UpdateType | null | undefined,\n    submitOptions?: CustomSubmitOptions<StateType, ConfigurableType>\n  ) => {\n    let callbackMeta: RunCallbackMeta | undefined;\n    let usableThreadId = threadId;\n\n    stream.setStreamValues(() => {\n      if (submitOptions?.optimisticValues != null) {\n        return {\n          ...historyValues,\n          ...(typeof submitOptions.optimisticValues === \"function\"\n            ? submitOptions.optimisticValues(historyValues)\n            : submitOptions.optimisticValues),\n        };\n      }\n\n      return { ...historyValues };\n    });\n\n    await stream.start(\n      async (signal: AbortSignal) => {\n        if (!usableThreadId) {\n          // generate random thread id\n          usableThreadId = crypto.randomUUID();\n          threadIdRef.current = usableThreadId;\n          onThreadId(usableThreadId);\n        }\n\n        if (!usableThreadId) {\n          throw new Error(\"Failed to obtain valid thread ID.\");\n        }\n\n        return options.transport.stream({\n          input: values,\n          context: submitOptions?.context,\n          command: submitOptions?.command,\n          signal,\n          config: {\n            ...submitOptions?.config,\n            configurable: {\n              thread_id: usableThreadId,\n              ...submitOptions?.config?.configurable,\n            } as unknown as GetConfigurableType<Bag>,\n          },\n        }) as Promise<\n          AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n        >;\n      },\n      {\n        getMessages,\n        setMessages,\n\n        initialValues: {} as StateType,\n        callbacks: options,\n\n        onSuccess: () => undefined,\n        onError(error) {\n          options.onError?.(error, callbackMeta);\n        },\n      }\n    );\n  };\n\n  return {\n    get values() {\n      return stream.values ?? ({} as StateType);\n    },\n\n    error: stream.error,\n    isLoading: stream.isLoading,\n\n    stop,\n    submit,\n\n    get interrupt(): Interrupt<InterruptType> | undefined {\n      if (\n        stream.values != null &&\n        \"__interrupt__\" in stream.values &&\n        Array.isArray(stream.values.__interrupt__)\n      ) {\n        const valueInterrupts = stream.values.__interrupt__;\n        if (valueInterrupts.length === 0) return { when: \"breakpoint\" };\n        if (valueInterrupts.length === 1) return valueInterrupts[0];\n\n        // TODO: fix the typing of interrupts if multiple interrupts are returned\n        return valueInterrupts as Interrupt<InterruptType>;\n      }\n\n      return undefined;\n    },\n\n    get messages(): Message<ToolCallType>[] {\n      if (!stream.values) return [];\n      return getMessages(stream.values);\n    },\n\n    get toolCalls() {\n      if (!stream.values) return [];\n      const msgs = getMessages(stream.values);\n      return getToolCallsWithResults<ToolCallType>(msgs);\n    },\n\n    getToolCalls(message) {\n      if (!stream.values) return [];\n      const msgs = getMessages(stream.values);\n      const allToolCalls = getToolCallsWithResults<ToolCallType>(msgs);\n      return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n    },\n  };\n}\n"],"mappings":"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"}