{"version":3,"file":"index.cjs","names":["Runnable","OpenAIClient","StructuredTool","sleep"],"sources":["../../../src/experimental/openai_assistant/index.ts"],"sourcesContent":["import {\n  type ClientOptions,\n  type OpenAIChatModelId,\n  OpenAIClient,\n} from \"@langchain/openai\";\nimport { StructuredTool, StructuredToolInterface } from \"@langchain/core/tools\";\nimport { Runnable, RunnableConfig } from \"@langchain/core/runnables\";\nimport { isInteropZodSchema } from \"@langchain/core/utils/types\";\nimport { toJsonSchema } from \"@langchain/core/utils/json_schema\";\nimport { ToolDefinition } from \"@langchain/core/language_models/base\";\nimport { sleep } from \"../../util/time.js\";\nimport type {\n  OpenAIAssistantFinish,\n  OpenAIAssistantAction,\n  OpenAIToolType,\n} from \"./schema.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype ThreadMessage = any;\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype RequiredActionFunctionToolCall = any;\n\ntype ExtractRunOutput<AsAgent extends boolean | undefined> =\n  AsAgent extends true\n    ? OpenAIAssistantFinish | OpenAIAssistantAction[]\n    : ThreadMessage[] | RequiredActionFunctionToolCall[];\n\nexport type OpenAIAssistantRunnableInput<\n  AsAgent extends boolean | undefined = undefined,\n> = {\n  client?: OpenAIClient;\n  clientOptions?: ClientOptions;\n  assistantId: string;\n  pollIntervalMs?: number;\n  asAgent?: AsAgent;\n};\n\nexport class OpenAIAssistantRunnable<\n  AsAgent extends boolean | undefined,\n  // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n  RunInput extends Record<string, any> = Record<string, any>,\n> extends Runnable<RunInput, ExtractRunOutput<AsAgent>> {\n  lc_namespace = [\"langchain\", \"experimental\", \"openai_assistant\"];\n\n  private client: OpenAIClient;\n\n  assistantId: string;\n\n  pollIntervalMs = 1000;\n\n  asAgent?: AsAgent;\n\n  constructor(fields: OpenAIAssistantRunnableInput<AsAgent>) {\n    super(fields);\n    this.client = fields.client ?? new OpenAIClient(fields?.clientOptions);\n    this.assistantId = fields.assistantId;\n    this.asAgent = fields.asAgent ?? this.asAgent;\n  }\n\n  static async createAssistant<AsAgent extends boolean>({\n    model,\n    name,\n    instructions,\n    tools,\n    client,\n    clientOptions,\n    asAgent,\n    pollIntervalMs,\n    fileIds,\n  }: Omit<OpenAIAssistantRunnableInput<AsAgent>, \"assistantId\"> & {\n    model: OpenAIChatModelId;\n    name?: string;\n    instructions?: string;\n    tools?: OpenAIToolType | Array<StructuredTool>;\n    fileIds?: string[];\n  }) {\n    const formattedTools =\n      tools?.map((tool) => {\n        // oxlint-disable-next-line no-instanceof/no-instanceof\n        if (tool instanceof StructuredTool) {\n          return formatToOpenAIAssistantTool(tool);\n        }\n        return tool;\n      }) ?? [];\n    const oaiClient = client ?? new OpenAIClient(clientOptions);\n    const assistant = await oaiClient.beta.assistants.create({\n      name,\n      instructions,\n      tools: formattedTools,\n      model,\n      file_ids: fileIds,\n      // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    } as any);\n\n    return new this({\n      client: oaiClient,\n      assistantId: assistant.id,\n      asAgent,\n      pollIntervalMs,\n    });\n  }\n\n  async invoke(\n    input: RunInput,\n    _options?: RunnableConfig\n  ): Promise<ExtractRunOutput<AsAgent>> {\n    // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    let run: any;\n    if (this.asAgent && input.steps && input.steps.length > 0) {\n      const parsedStepsInput = await this._parseStepsInput(input);\n      run = await this.client.beta.threads.runs.submitToolOutputs(\n        parsedStepsInput.runId,\n        {\n          thread_id: parsedStepsInput.threadId,\n          tool_outputs: parsedStepsInput.toolOutputs,\n        }\n      );\n    } else if (!(\"threadId\" in input)) {\n      const thread = {\n        messages: [\n          {\n            role: \"user\",\n            content: input.content,\n            attachments: input.attachments,\n            metadata: input.messagesMetadata,\n          },\n        ],\n        metadata: input.threadMetadata,\n      };\n      run = await this._createThreadAndRun({\n        ...input,\n        thread,\n      });\n    } else if (!(\"runId\" in input)) {\n      await this.client.beta.threads.messages.create(input.threadId, {\n        content: input.content,\n        role: \"user\",\n        attachments: input.attachments,\n        metadata: input.messagesMetadata,\n        // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n      } as any);\n      run = await this._createRun(input);\n    } else {\n      // Submitting tool outputs to an existing run, outside the AgentExecutor\n      // framework.\n      run = await this.client.beta.threads.runs.submitToolOutputs(input.runId, {\n        thread_id: input.threadId,\n        tool_outputs: input.toolOutputs,\n      });\n    }\n\n    return this._getResponse(run.id, run.thread_id);\n  }\n\n  /**\n   * Delete an assistant.\n   *\n   * @link {https://platform.openai.com/docs/api-reference/assistants/deleteAssistant}\n   * @returns {Promise<AssistantDeleted>}\n   */\n  public async deleteAssistant() {\n    return await this.client.beta.assistants.delete(this.assistantId);\n  }\n\n  /**\n   * Retrieves an assistant.\n   *\n   * @link {https://platform.openai.com/docs/api-reference/assistants/getAssistant}\n   * @returns {Promise<OpenAIClient.Beta.Assistants.Assistant>}\n   */\n  public async getAssistant() {\n    return await this.client.beta.assistants.retrieve(this.assistantId);\n  }\n\n  /**\n   * Modifies an assistant.\n   *\n   * @link {https://platform.openai.com/docs/api-reference/assistants/modifyAssistant}\n   * @returns {Promise<OpenAIClient.Beta.Assistants.Assistant>}\n   */\n  public async modifyAssistant<AsAgent extends boolean>({\n    model,\n    name,\n    instructions,\n    fileIds,\n  }: Omit<OpenAIAssistantRunnableInput<AsAgent>, \"assistantId\" | \"tools\"> & {\n    model?: OpenAIChatModelId;\n    name?: string;\n    instructions?: string;\n    fileIds?: string[];\n  }) {\n    return await this.client.beta.assistants.update(this.assistantId, {\n      name,\n      instructions,\n      model,\n      file_ids: fileIds,\n      // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    } as any);\n  }\n\n  private async _parseStepsInput(input: RunInput): Promise<RunInput> {\n    const {\n      action: { runId, threadId },\n    } = input.steps[input.steps.length - 1];\n    const run = await this._waitForRun(runId, threadId);\n    const toolCalls = run.required_action?.submit_tool_outputs.tool_calls;\n    if (!toolCalls) {\n      return input;\n    }\n    // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    const toolOutputs = toolCalls.flatMap((toolCall: any) => {\n      const matchedAction = (\n        input.steps as {\n          action: OpenAIAssistantAction;\n          observation: string;\n        }[]\n      ).find((step) => step.action.toolCallId === toolCall.id);\n\n      return matchedAction\n        ? [\n            {\n              output: matchedAction.observation,\n              tool_call_id: matchedAction.action.toolCallId,\n            },\n          ]\n        : [];\n    });\n    return { toolOutputs, runId, threadId } as unknown as RunInput;\n  }\n\n  private async _createRun({\n    instructions,\n    model,\n    tools,\n    metadata,\n    threadId,\n  }: RunInput) {\n    const run = this.client.beta.threads.runs.create(threadId, {\n      assistant_id: this.assistantId,\n      instructions,\n      model,\n      tools,\n      metadata,\n    });\n    return run;\n  }\n\n  private async _createThreadAndRun(input: RunInput) {\n    const params: Record<string, unknown> = [\n      \"instructions\",\n      \"model\",\n      \"tools\",\n      \"run_metadata\",\n    ]\n      .filter((key) => key in input)\n      .reduce(\n        (obj, key) => {\n          const newObj = obj;\n          newObj[key] = input[key];\n          return newObj;\n        },\n        {} as Record<string, unknown>\n      );\n    const run = this.client.beta.threads.createAndRun({\n      ...params,\n      thread: input.thread,\n      assistant_id: this.assistantId,\n    });\n    return run;\n  }\n\n  private async _waitForRun(runId: string, threadId: string) {\n    let inProgress = true;\n    // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n    let run = {} as any;\n    while (inProgress) {\n      run = await this.client.beta.threads.runs.retrieve(runId, {\n        thread_id: threadId,\n      });\n      inProgress = [\"in_progress\", \"queued\"].includes(run.status);\n      if (inProgress) {\n        await sleep(this.pollIntervalMs);\n      }\n    }\n    return run;\n  }\n\n  private async _getResponse(\n    runId: string,\n    threadId: string\n  ): Promise<ExtractRunOutput<AsAgent>>;\n\n  private async _getResponse(\n    runId: string,\n    threadId: string\n  ): Promise<\n    | OpenAIAssistantFinish\n    | OpenAIAssistantAction[]\n    | ThreadMessage[]\n    | RequiredActionFunctionToolCall[]\n  > {\n    const run = await this._waitForRun(runId, threadId);\n    if (run.status === \"completed\") {\n      const messages = await this.client.beta.threads.messages.list(threadId, {\n        order: \"desc\",\n      });\n      const newMessages = messages.data.filter((msg) => msg.run_id === runId);\n      if (!this.asAgent) {\n        return newMessages;\n      }\n      const answer = newMessages.flatMap((msg) => msg.content);\n      if (answer.every((item) => item.type === \"text\")) {\n        const answerString = answer\n          .map((item) => item.type === \"text\" && item.text.value)\n          .join(\"\\n\");\n        return {\n          returnValues: {\n            output: answerString,\n            runId,\n            threadId,\n          },\n          log: \"\",\n          runId,\n          threadId,\n        };\n      }\n    } else if (run.status === \"requires_action\") {\n      if (!this.asAgent) {\n        return run.required_action?.submit_tool_outputs.tool_calls ?? [];\n      }\n      const actions: OpenAIAssistantAction[] = [];\n      run.required_action?.submit_tool_outputs.tool_calls.forEach(\n        // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n        (item: any) => {\n          const functionCall = item.function;\n          const args = JSON.parse(functionCall.arguments);\n          actions.push({\n            tool: functionCall.name,\n            toolInput: args,\n            toolCallId: item.id,\n            log: \"\",\n            runId,\n            threadId,\n          });\n        }\n      );\n      return actions;\n    }\n    const runInfo = JSON.stringify(run, null, 2);\n    throw new Error(\n      `Unexpected run status ${run.status}.\\nFull run info:\\n\\n${runInfo}`\n    );\n  }\n}\n\nexport function formatToOpenAIAssistantTool(\n  tool: StructuredToolInterface\n): ToolDefinition {\n  return {\n    type: \"function\",\n    function: {\n      name: tool.name,\n      description: tool.description,\n      parameters: isInteropZodSchema(tool.schema)\n        ? toJsonSchema(tool.schema)\n        : tool.schema,\n    },\n  };\n}\n"],"mappings":"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"}