diff --git a/.embedmeignore b/.embedmeignore new file mode 100644 index 00000000..ca5368c3 --- /dev/null +++ b/.embedmeignore @@ -0,0 +1 @@ +docs/README.md diff --git a/.env.template b/.env.template index ed796c50..d3137938 100644 --- a/.env.template +++ b/.env.template @@ -7,46 +7,56 @@ BEE_FRAMEWORK_LOG_SINGLE_LINE="false" # BEE_FRAMEWORK_INSTRUMENTATION_ENABLED=true # BEE_FRAMEWORK_INSTRUMENTATION_IGNORED_KEYS= -# For WatsonX LLM Adapter +# For Watsonx LLM Adapter +# WATSONX_CHAT_MODEL="" +# WATSONX_EMBEDDING_MODEL="" # WATSONX_API_KEY="" # WATSONX_PROJECT_ID="" -# WATSONX_REGION="us-south" +# WATSONX_SPACE_ID="" +# WATSONX_VERSION="" +# WATSONX_REGION="" # For Ollama LLM Adapter -# OLLAMA_HOST="http://0.0.0.0:11434" -# OLLAMA_MODEL="deepseek-r1:8b" +# OLLAMA_CHAT_MODEL="" +# OLLAMA_EMBEDDING_MODEL="" +# OLLAMA_BASE_URL="" # For OpenAI LLM Adapter +# OPENAI_CHAT_MODEL="" +# OPENAI_EMBEDDING_MODEL="" +# OPENAI_API_ENDPOINT="" # OPENAI_API_KEY="" +# OPENAI_API_HEADERS="" # For Azure OpenAI LLM Adapter -# AZURE_OPENAI_API_VERSION="" -# AZURE_OPENAI_API_DEPLOYMENT="" +# AZURE_OPENAI_CHAT_MODEL="" +# AZURE_OPENAI_EMBEDDING_MODEL="" # AZURE_OPENAI_API_KEY="" # AZURE_OPENAI_API_ENDPOINT="" +# AZURE_OPENAI_API_RESOURCE="" +# AZURE_OPENAI_API_VERSION="" # For Groq LLM Adapter +# GROQ_CHAT_MODEL="" +# GROQ_EMBEDDING_MODEL="" +# GROQ_API_HOST="" # GROQ_API_KEY="" -# For IBM VLLM LLM Adapter -# IBM_VLLM_URL="" -# IBM_VLLM_ROOT_CERT="" -# IBM_VLLM_CERT_CHAIN="" -# IBM_VLLM_PRIVATE_KEY="" - -# For IBM RITS LLM Adapter -# IBM_RITS_URL="" -# IBM_RITS_API_KEY="" -# IBM_RITS_MODEL=ibm-granite/granite-3.0-8b-instruct - -# LLM Provider, used for some of the example agents -# (watsonx/ollama/openai/groq/ibmvllm/ibmrits) -# LLM_BACKEND="ollama" - -# For GCP VertexAI Adapter +# For Google Vertex Adapter +# GOOGLE_VERTEX_CHAT_MODEL="" +# GOOGLE_VERTEX_EMBEDDING_MODEL="" +# GOOGLE_VERTEX_PROJECT="" +# GOOGLE_VERTEX_ENDPOINT="" +# GOOGLE_VERTEX_LOCATION="" # GOOGLE_APPLICATION_CREDENTIALS="" -# GCP_VERTEXAI_PROJECT="" -# GCP_VERTEXAI_LOCATION="" + +# For Amazon Bedrock +# AWS_CHAT_MODEL="" +# AWS_EMBEDDING_MODEL="" +# AWS_ACCESS_KEY_ID="" +# AWS_SECRET_ACCESS_KEY="" +# AWS_REGION="" +# AWS_SESSION_TOKEN="" # Tools # CODE_INTERPRETER_URL="http://127.0.0.1:50081" @@ -63,4 +73,5 @@ BEE_FRAMEWORK_LOG_SINGLE_LINE="false" # ELASTICSEARCH_API_KEY="" ## Third-party services -# TAVILY_API_KEY=your-api-key-here \ No newline at end of file +# TAVILY_API_KEY=your-api-key-here + diff --git a/.github/workflows/examples-tests.yml b/.github/workflows/examples-tests.yml index 6fd4ddc0..0839bee5 100644 --- a/.github/workflows/examples-tests.yml +++ b/.github/workflows/examples-tests.yml @@ -48,7 +48,7 @@ jobs: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} GOOGLE_API_KEY: ${{ secrets.GOOGLE_SEARCH_API_KEY }} GOOGLE_CSE_ID: ${{ secrets.GOOGLE_SEARCH_CSE_ID }} - # TODO: enable WatsonX later + # TODO: enable Watsonx later # WATSONX_API_KEY: ${{ secrets.WATSONX_API_KEY }} # WATSONX_PROJECT_ID: ${{ secrets.WATSONX_PROJECT_ID }} # WATSONX_SPACE_ID: ${{ secrets.WATSONX_SPACE_ID }} diff --git a/.gitignore b/.gitignore index 42e82e55..6c439d3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,3 @@ -scripts/ibm_vllm_generate_protos/dist -scripts/ibm_vllm_generate_protos/dts -scripts/ibm_vllm_generate_protos/types - ### Node template # Logs logs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 01b54124..3e3e4c2a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,26 +59,7 @@ yarn install --immutable yarn prepare ``` -5. **Setup environmental variables:** To run E2E Tests, you should set the following variables in your `.env` file in the repository’s root. - -```bash -# At least one provider API key or an OLLAMA_HOST must be defined! -OPENAI_API_KEY="" -GROQ_API_KEY="" -WATSONX_API_KEY="" -WATSONX_PROJECT_ID="" -OLLAMA_HOST="" -AZURE_OPENAI_API_VERSION="" -AZURE_OPENAI_DEPLOYMENT="" -AZURE_OPENAI_API_KEY="" -AZURE_OPENAI_API_ENDPOINT="" -GOOGLE_APPLICATION_CREDENTIALS="" -GCP_VERTEXAI_PROJECT="" -GCP_VERTEXAI_LOCATION="" - -WATSONX_SPACE_ID="" # optional -WATSONX_DEPLOYMENT_ID="" # optional -``` +5. **Setup environmental variables:** To run E2E Tests, you should set the requisite environmental variables in your `.env` file. 6. **Follow Conventional Commit Messages:** We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) to structure our commit messages. This helps maintain a clean and manageable commit history. Please use the following format: diff --git a/README.md b/README.md index 48281b6a..376c1d53 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,11 @@

Open-source framework for building, deploying, and serving powerful multi-agent workflows at scale.

-🐝 **Bee Agent Framework** is an open-source TypeScript library for building **production-ready multi-agent systems**. Pick from a variety of [🌐 LLM providers](/docs/llms.md#providers-adapters), customize the [πŸ“œ prompt templates](/docs/templates.md), create [πŸ€– agents](/docs/agents.md), equip agents with pre-made [πŸ› οΈ tools](/docs/tools.md), and orchestrate [πŸ€–πŸ€πŸ€– multi-agent workflows](/docs/workflows.md)! πŸͺ„ +🐝 **Bee Agent Framework** is an open-source TypeScript library for building **production-ready multi-agent systems**. Pick from a variety of [🌐 AI Providers](/docs/backend.md), customize the [πŸ“œ prompt templates](/docs/templates.md), create [πŸ€– agents](/docs/agents.md), equip agents with pre-made [πŸ› οΈ tools](/docs/tools.md), and orchestrate [πŸ€–πŸ€πŸ€– multi-agent workflows](/docs/workflows.md)! πŸͺ„ ## Latest updates +- πŸš€ **2025-02-07**: Introduced [Backend](/docs/backend.md) module to simplify working with AI services (chat, embedding). See [migration guide](/docs/migration_guide.md). - 🧠 **2025-01-28**: Added support for [DeepSeek R1](https://api-docs.deepseek.com/news/news250120), check out the [Competitive Analysis Workflow example](https://github.com/i-am-bee/bee-agent-framework/tree/main/examples/workflows/competitive-analysis) - πŸš€ **2025-01-09**: - Introduced [Workflows](/docs/workflows.md), a way of building multi-agent systems. @@ -30,7 +31,7 @@ For a full changelog, see the [releases page](https://github.com/i-am-bee/bee-ag ## Why pick Bee? - βš”οΈ **Battle-tested.** Bee Agent Framework is at the core of [BeeAI](https://iambee.ai), a powerful platform for building chat assistants and custom AI-powered apps. BeeAI is in a closed beta, but already used by hundreds of users. And it's [fully open-source](https://github.com/i-am-bee/bee-ui) too! -- πŸš€ **Production-grade.** In an actual product, you have to reduce token spend through [memory strategies](/docs/memory.md), store and restore the agent state through [(de)serialization](/docs/serialization.md), generate [structured output](/examples/llms/structured.ts), or execute generated code in a [sandboxed environment](https://github.com/i-am-bee/bee-code-interpreter). Leave all that to Bee and focus on building! +- πŸš€ **Production-grade.** In an actual product, you have to reduce token spend through [memory strategies](/docs/memory.md), store and restore the agent state through [(de)serialization](/docs/serialization.md), generate [structured output](/examples/backend/structured.ts), or execute generated code in a [sandboxed environment](https://github.com/i-am-bee/bee-code-interpreter). Leave all that to Bee and focus on building! - πŸ€— **Built for open-source models.** Pick any LLM you want – including small and open-source models. The framework is designed to perform robustly with [Granite](https://www.ibm.com/granite/docs/) and [Llama 3.x](https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct). A full agentic workflow can run on your laptop! - 😒 **Bee cares about the sad path too.** Real-world applications encounter errors and failures. Bee lets you observe the full agent workflow through [events](/docs/emitter.md), collect [telemetry](/docs/instrumentation.md), [log](/docs/logger.md) diagnostic data, and throws clear and well-defined [exceptions](/docs/errors.md). Bees may be insects, but not bugs! - 🌳 **A part of something greater.** Bee isn't just a framework, but a full ecosystem. Use [Bee UI](https://github.com/i-am-bee/bee-ui) to chat with your agents visually. [Bee Observe](https://github.com/i-am-bee/bee-observe) collects and manages telemetry. [Bee Code Interpreter](https://github.com/i-am-bee/bee-code-interpreter) runs generated code safely in a secure sandbox. The Bee ecosystem also integrates with [Model Context Protocol](https://i-am-bee.github.io/bee-agent-framework/#/tools?id=using-the-mcptool-class), allowing interoperability with the wider agent ecosystem! @@ -47,7 +48,7 @@ import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMem import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { AgentWorkflow } from "bee-agent-framework/experimental/workflows/agent"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; +import { Message, Role } from "bee-agent-framework/llms/primitives/message"; import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; const workflow = new AgentWorkflow(); @@ -77,7 +78,7 @@ workflow.addAgent({ const memory = new UnconstrainedMemory(); await memory.add( - BaseMessage.of({ + Message.of({ role: Role.USER, text: "What is the capital of France and what is the current weather there?", meta: { createdAt: new Date() }, @@ -119,16 +120,16 @@ yarn add bee-agent-framework ```ts import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; -const llm = new OllamaChatLLM(); // default is llama3.1 (8B), it is recommended to use 70B model +const llm = new OllamaChatModel("llama3.1"); // default is llama3.1 (8B), it is recommended to use 70B model const agent = new BeeAgent({ llm, // for more explore 'bee-agent-framework/adapters' - memory: new TokenMemory({ llm }), // for more explore 'bee-agent-framework/memory' + memory: new TokenMemory(), // for more explore 'bee-agent-framework/memory' tools: [new DuckDuckGoSearchTool(), new OpenMeteoTool()], // for more explore 'bee-agent-framework/tools' }); @@ -174,22 +175,21 @@ console.log(`Agent πŸ€– : `, response.result.text); The source directory (`src`) provides numerous modules that one can use. -| Name | Description | -| ------------------------------------------------ | ------------------------------------------------------------------------------------------- | -| [**agents**](/docs/agents.md) | Base classes defining the common interface for agent. | -| [**workflows**](/docs/workflows.md) | Build agentic applications in a declarative way via [workflows](/docs/workflows.md). | -| [**llms**](/docs/llms.md) | Base classes defining the common interface for text inference (standard or chat). | -| [**template**](/docs/templates.md) | Prompt Templating system based on `Mustache` with various improvements. | -| [**memory**](/docs/memory.md) | Various types of memories to use with agent. | -| [**tools**](/docs/tools.md) | Tools that an agent can use. | -| [**cache**](/docs/cache.md) | Preset of different caching approaches that can be used together with tools. | -| [**errors**](/docs/errors.md) | Error classes and helpers to catch errors fast. | -| [**adapters**](/docs/llms.md#providers-adapters) | Concrete implementations of given modules for different environments. | -| [**logger**](/docs/logger.md) | Core component for logging all actions within the framework. | -| [**serializer**](/docs/serialization.md) | Core component for the ability to serialize/deserialize modules into the serialized format. | -| [**version**](/docs/version.md) | Constants representing the framework (e.g., latest version) | -| [**emitter**](/docs/emitter.md) | Bringing visibility to the system by emitting events. | -| **internals** | Modules used by other modules within the framework. | +| Name | Description | +| ---------------------------------------- | ------------------------------------------------------------------------------------------- | +| [**agents**](/docs/agents.md) | Base classes defining the common interface for agent. | +| [**workflows**](/docs/workflows.md) | Build agentic applications in a declarative way via [workflows](/docs/workflows.md). | +| [**backend**](/docs/backend.md) | Functionalities that relates to AI models (chat, embedding, image, tool calling, ...) | +| [**template**](/docs/templates.md) | Prompt Templating system based on `Mustache` with various improvements. | +| [**memory**](/docs/memory.md) | Various types of memories to use with agent. | +| [**tools**](/docs/tools.md) | Tools that an agent can use. | +| [**cache**](/docs/cache.md) | Preset of different caching approaches that can be used together with tools. | +| [**errors**](/docs/errors.md) | Error classes and helpers to catch errors fast. | +| [**logger**](/docs/logger.md) | Core component for logging all actions within the framework. | +| [**serializer**](/docs/serialization.md) | Core component for the ability to serialize/deserialize modules into the serialized format. | +| [**version**](/docs/version.md) | Constants representing the framework (e.g., latest version) | +| [**emitter**](/docs/emitter.md) | Bringing visibility to the system by emitting events. | +| **internals** | Modules used by other modules within the framework. | To see more in-depth explanation see [overview](/docs/overview.md). diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 01b54124..3e3e4c2a 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -59,26 +59,7 @@ yarn install --immutable yarn prepare ``` -5. **Setup environmental variables:** To run E2E Tests, you should set the following variables in your `.env` file in the repository’s root. - -```bash -# At least one provider API key or an OLLAMA_HOST must be defined! -OPENAI_API_KEY="" -GROQ_API_KEY="" -WATSONX_API_KEY="" -WATSONX_PROJECT_ID="" -OLLAMA_HOST="" -AZURE_OPENAI_API_VERSION="" -AZURE_OPENAI_DEPLOYMENT="" -AZURE_OPENAI_API_KEY="" -AZURE_OPENAI_API_ENDPOINT="" -GOOGLE_APPLICATION_CREDENTIALS="" -GCP_VERTEXAI_PROJECT="" -GCP_VERTEXAI_LOCATION="" - -WATSONX_SPACE_ID="" # optional -WATSONX_DEPLOYMENT_ID="" # optional -``` +5. **Setup environmental variables:** To run E2E Tests, you should set the requisite environmental variables in your `.env` file. 6. **Follow Conventional Commit Messages:** We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) to structure our commit messages. This helps maintain a clean and manageable commit history. Please use the following format: diff --git a/docs/README.md b/docs/README.md index 48281b6a..376c1d53 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,10 +14,11 @@

Open-source framework for building, deploying, and serving powerful multi-agent workflows at scale.

-🐝 **Bee Agent Framework** is an open-source TypeScript library for building **production-ready multi-agent systems**. Pick from a variety of [🌐 LLM providers](/docs/llms.md#providers-adapters), customize the [πŸ“œ prompt templates](/docs/templates.md), create [πŸ€– agents](/docs/agents.md), equip agents with pre-made [πŸ› οΈ tools](/docs/tools.md), and orchestrate [πŸ€–πŸ€πŸ€– multi-agent workflows](/docs/workflows.md)! πŸͺ„ +🐝 **Bee Agent Framework** is an open-source TypeScript library for building **production-ready multi-agent systems**. Pick from a variety of [🌐 AI Providers](/docs/backend.md), customize the [πŸ“œ prompt templates](/docs/templates.md), create [πŸ€– agents](/docs/agents.md), equip agents with pre-made [πŸ› οΈ tools](/docs/tools.md), and orchestrate [πŸ€–πŸ€πŸ€– multi-agent workflows](/docs/workflows.md)! πŸͺ„ ## Latest updates +- πŸš€ **2025-02-07**: Introduced [Backend](/docs/backend.md) module to simplify working with AI services (chat, embedding). See [migration guide](/docs/migration_guide.md). - 🧠 **2025-01-28**: Added support for [DeepSeek R1](https://api-docs.deepseek.com/news/news250120), check out the [Competitive Analysis Workflow example](https://github.com/i-am-bee/bee-agent-framework/tree/main/examples/workflows/competitive-analysis) - πŸš€ **2025-01-09**: - Introduced [Workflows](/docs/workflows.md), a way of building multi-agent systems. @@ -30,7 +31,7 @@ For a full changelog, see the [releases page](https://github.com/i-am-bee/bee-ag ## Why pick Bee? - βš”οΈ **Battle-tested.** Bee Agent Framework is at the core of [BeeAI](https://iambee.ai), a powerful platform for building chat assistants and custom AI-powered apps. BeeAI is in a closed beta, but already used by hundreds of users. And it's [fully open-source](https://github.com/i-am-bee/bee-ui) too! -- πŸš€ **Production-grade.** In an actual product, you have to reduce token spend through [memory strategies](/docs/memory.md), store and restore the agent state through [(de)serialization](/docs/serialization.md), generate [structured output](/examples/llms/structured.ts), or execute generated code in a [sandboxed environment](https://github.com/i-am-bee/bee-code-interpreter). Leave all that to Bee and focus on building! +- πŸš€ **Production-grade.** In an actual product, you have to reduce token spend through [memory strategies](/docs/memory.md), store and restore the agent state through [(de)serialization](/docs/serialization.md), generate [structured output](/examples/backend/structured.ts), or execute generated code in a [sandboxed environment](https://github.com/i-am-bee/bee-code-interpreter). Leave all that to Bee and focus on building! - πŸ€— **Built for open-source models.** Pick any LLM you want – including small and open-source models. The framework is designed to perform robustly with [Granite](https://www.ibm.com/granite/docs/) and [Llama 3.x](https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct). A full agentic workflow can run on your laptop! - 😒 **Bee cares about the sad path too.** Real-world applications encounter errors and failures. Bee lets you observe the full agent workflow through [events](/docs/emitter.md), collect [telemetry](/docs/instrumentation.md), [log](/docs/logger.md) diagnostic data, and throws clear and well-defined [exceptions](/docs/errors.md). Bees may be insects, but not bugs! - 🌳 **A part of something greater.** Bee isn't just a framework, but a full ecosystem. Use [Bee UI](https://github.com/i-am-bee/bee-ui) to chat with your agents visually. [Bee Observe](https://github.com/i-am-bee/bee-observe) collects and manages telemetry. [Bee Code Interpreter](https://github.com/i-am-bee/bee-code-interpreter) runs generated code safely in a secure sandbox. The Bee ecosystem also integrates with [Model Context Protocol](https://i-am-bee.github.io/bee-agent-framework/#/tools?id=using-the-mcptool-class), allowing interoperability with the wider agent ecosystem! @@ -47,7 +48,7 @@ import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMem import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { AgentWorkflow } from "bee-agent-framework/experimental/workflows/agent"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; +import { Message, Role } from "bee-agent-framework/llms/primitives/message"; import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; const workflow = new AgentWorkflow(); @@ -77,7 +78,7 @@ workflow.addAgent({ const memory = new UnconstrainedMemory(); await memory.add( - BaseMessage.of({ + Message.of({ role: Role.USER, text: "What is the capital of France and what is the current weather there?", meta: { createdAt: new Date() }, @@ -119,16 +120,16 @@ yarn add bee-agent-framework ```ts import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; -const llm = new OllamaChatLLM(); // default is llama3.1 (8B), it is recommended to use 70B model +const llm = new OllamaChatModel("llama3.1"); // default is llama3.1 (8B), it is recommended to use 70B model const agent = new BeeAgent({ llm, // for more explore 'bee-agent-framework/adapters' - memory: new TokenMemory({ llm }), // for more explore 'bee-agent-framework/memory' + memory: new TokenMemory(), // for more explore 'bee-agent-framework/memory' tools: [new DuckDuckGoSearchTool(), new OpenMeteoTool()], // for more explore 'bee-agent-framework/tools' }); @@ -174,22 +175,21 @@ console.log(`Agent πŸ€– : `, response.result.text); The source directory (`src`) provides numerous modules that one can use. -| Name | Description | -| ------------------------------------------------ | ------------------------------------------------------------------------------------------- | -| [**agents**](/docs/agents.md) | Base classes defining the common interface for agent. | -| [**workflows**](/docs/workflows.md) | Build agentic applications in a declarative way via [workflows](/docs/workflows.md). | -| [**llms**](/docs/llms.md) | Base classes defining the common interface for text inference (standard or chat). | -| [**template**](/docs/templates.md) | Prompt Templating system based on `Mustache` with various improvements. | -| [**memory**](/docs/memory.md) | Various types of memories to use with agent. | -| [**tools**](/docs/tools.md) | Tools that an agent can use. | -| [**cache**](/docs/cache.md) | Preset of different caching approaches that can be used together with tools. | -| [**errors**](/docs/errors.md) | Error classes and helpers to catch errors fast. | -| [**adapters**](/docs/llms.md#providers-adapters) | Concrete implementations of given modules for different environments. | -| [**logger**](/docs/logger.md) | Core component for logging all actions within the framework. | -| [**serializer**](/docs/serialization.md) | Core component for the ability to serialize/deserialize modules into the serialized format. | -| [**version**](/docs/version.md) | Constants representing the framework (e.g., latest version) | -| [**emitter**](/docs/emitter.md) | Bringing visibility to the system by emitting events. | -| **internals** | Modules used by other modules within the framework. | +| Name | Description | +| ---------------------------------------- | ------------------------------------------------------------------------------------------- | +| [**agents**](/docs/agents.md) | Base classes defining the common interface for agent. | +| [**workflows**](/docs/workflows.md) | Build agentic applications in a declarative way via [workflows](/docs/workflows.md). | +| [**backend**](/docs/backend.md) | Functionalities that relates to AI models (chat, embedding, image, tool calling, ...) | +| [**template**](/docs/templates.md) | Prompt Templating system based on `Mustache` with various improvements. | +| [**memory**](/docs/memory.md) | Various types of memories to use with agent. | +| [**tools**](/docs/tools.md) | Tools that an agent can use. | +| [**cache**](/docs/cache.md) | Preset of different caching approaches that can be used together with tools. | +| [**errors**](/docs/errors.md) | Error classes and helpers to catch errors fast. | +| [**logger**](/docs/logger.md) | Core component for logging all actions within the framework. | +| [**serializer**](/docs/serialization.md) | Core component for the ability to serialize/deserialize modules into the serialized format. | +| [**version**](/docs/version.md) | Constants representing the framework (e.g., latest version) | +| [**emitter**](/docs/emitter.md) | Bringing visibility to the system by emitting events. | +| **internals** | Modules used by other modules within the framework. | To see more in-depth explanation see [overview](/docs/overview.md). diff --git a/docs/_sidebar.md b/docs/_sidebar.md index db1540a9..390a61e6 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -4,13 +4,14 @@ - [Overview](overview.md) - [Examples](examples.md) - [Tutorials](tutorials.md) + - [Migration Guide](migration_guide.md) - [Changelog](CHANGELOG.md) - Modules - [Agents](agents.md) - [Workflows](workflows.md) - - [LLMs](llms.md) + - [Backend](backend.md) - [Templates](templates.md) - [Memory](memory.md) - [Emitter](emitter.md) diff --git a/docs/agents.md b/docs/agents.md index e1992622..edd97f20 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -47,12 +47,12 @@ In the following example, we will transform the knowledge gained into code. ```ts import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; const agent = new BeeAgent({ - llm: new OllamaChatLLM(), // for more explore 'bee-agent-framework/adapters' + llm: new OllamaChatModel("llama3.1"), // for more explore 'bee-agent-framework/adapters' memory: new UnconstrainedMemory(), // for more explore 'bee-agent-framework/memory' tools: [new OpenMeteoTool()], // for more explore 'bee-agent-framework/tools' }); diff --git a/docs/backend.md b/docs/backend.md new file mode 100644 index 00000000..ff202da6 --- /dev/null +++ b/docs/backend.md @@ -0,0 +1,280 @@ +# Backend + +> [!TIP] +> +> Location for concrete implementations within the framework `bee-agent-framework/adapters/provider/backend`. +> +> Location for base abstraction within the framework `bee-agent-framework/backend`. + +The backend module is an umbrella module that encapsulates a unified way to work with the following functionalities: + +- Chat Models via (`ChatModel` class) +- Embedding Models via (`EmbeddingModel` class) +- Audio Models (coming soon) +- Image Models (coming soon) + +## Providers (implementations) + +The following table depicts supported providers. + +| Name | Chat | Embedding | Dependency | Environment Variables | +| ---------------- | :--: | :-------: | ------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Ollama` | βœ… | βœ… | `ollama-ai-provider` | OLLAMA_CHAT_MODEL
OLLAMA_EMBEDDING_MODEL
OLLAMA_BASE_URL | +| `OpenAI` | βœ… | βœ… | `@ai-sdk/openai` | OPENAI_CHAT_MODEL
OPENAI_EMBEDDING_MODEL
OPENAI_API_ENDPOINT
OPENAI_API_KEY
OPENAI_API_HEADERS | +| `Groq` | βœ… | βœ… | `@ai-sdk/groq` | GROQ_CHAT_MODEL
GROQ_EMBEDDING_MODEL
GROQ_API_HOST
GROQ_API_KEY | +| `Amazon Bedrock` | βœ… | βœ… | `@ai-sdk/amazon-bedrock` | AWS_CHAT_MODEL
AWS_EMBEDDING_MODEL
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_REGION
AWS_SESSION_TOKEN | +| `Google Vertex` | βœ… | βœ… | `@ai-sdk/google-vertex` | GOOGLE_VERTEX_CHAT_MODEL
GOOGLE_VERTEX_EMBEDDING_MODEL
GOOGLE_VERTEX_PROJECT
GOOGLE_VERTEX_ENDPOINT
GOOGLE_VERTEX_LOCATION | +| `Watsonx` | βœ… | βœ… | `@ibm-cloud/watsonx-ai` | WATSONX_CHAT_MODEL
WATSONX_EMBEDDING_MODEL
WATSONX_API_KEY
WATSONX_PROJECT_ID
WATSONX_SPACE_ID
WATSONX_VERSION
WATSONX_REGION | +| `Azure OpenAI` | βœ… | βœ… | `@ai-sdk/azure` | AZURE_OPENAI_CHAT_MODEL
AZURE_OPENAI_EMBEDDING_MODEL
AZURE_OPENAI_API_KEY
AZURE_OPENAI_API_ENDPOINT
AZURE_OPENAI_API_RESOURCE
AZURE_OPENAI_API_VERSION | + +> [!TIP] +> +> If you don't see your provider raise an issue [here](https://github.com/i-am-bee/bee-agent-framework/discussions). Meanwhile, you can use [LangChain adapter](/examples/backend/providers/langchain.ts). + +### Initialization + +```ts +import { Backend } from "bee-agent-framework/backend/core"; + +const backend = await Backend.fromProvider("watsonx"); // use provider's name from the list below, ensure you set all ENVs +console.log(backend.chat.modelId); // uses provider's default model or the one specified via env +console.log(backend.embedding.modelId); // uses provider's default model or the one specified via env +``` + +All providers examples can be found in [examples/backend/providers](/examples/backend/providers). + +## Chat Model + +The `ChatModel` class represents a Chat Large Language Model and can be initiated in one of the following ways. + +```ts +import { ChatModel } from "bee-agent-framework/backend/core"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +console.log(model.providerId); // ollama +console.log(model.modelId); // llama3.1 +``` + +or you can always create the concrete provider's chat model directly + +```ts +import { OpenAIChatModel } from "bee-agent-framework/adapters/openai/chat"; + +const model = new OpenAIChatModel( + "gpt-4o", + { + // optional provider settings + reasoningEffort: "low", + parallelToolCalls: false, + }, + { + // optional provider client settings + baseURL: "your_custom_endpoint", + apiKey: "your_api_key", + compatibility: "compatible", + headers: { + CUSTOM_HEADER: "...", + }, + }, +); +``` + +### Configuration + +```ts +import { ChatModel, UserMessage } from "bee-agent-framework/backend/core"; +import { SlidingCache } from "bee-agent-framework/cache/slidingCache"; + +const model = await ChatModel.fromName("watsonx:ibm/granite-3-8b-instruct"); +model.config({ + parameters: { + maxTokens: 300, + temperature: 0.15, + topP: 1, + frequencyPenalty: 1.1, + topK: 1, + n: 1, + presencePenalty: 1, + seed: 7777, + stopSequences: ["\n\n"], + }, + cache: new SlidingCache({ + size: 25, + }), +}); +``` + +### Generation + +```ts +import { ChatModel, UserMessage } from "bee-agent-framework/backend/core"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +const response = await model.create({ + messages: [new UserMessage("Hello world!")], +}); +console.log(response.getTextContent()); +``` + +> [!NOTE] +> +> Execution parameters (those passed to `model.create({...})`) are superior to ones defined via `config`. + +### Stream + +```ts +import { ChatModel, UserMessage } from "bee-agent-framework/backend/core"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +const response = await model + .create({ + messages: [new UserMessage("Hello world!")], + stream: true, + }) + .observe((emitter) => { + emitter.on("update", ({ value }) => { + console.log("token", value.getTextContent()); + }); + }); + +console.log("Finish Reason:", response.finishReason); +console.log("Token Usage:", response.usage); +``` + +### Structured Generation + + + +```ts +import { ChatModel, UserMessage } from "bee-agent-framework/backend/core"; +import { z } from "zod"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +const response = await model.createStructure({ + schema: z.union([ + z.object({ + firstName: z.string().min(1), + lastName: z.string().min(1), + address: z.string(), + age: z.number().int().min(1), + hobby: z.string(), + }), + z.object({ + error: z.string(), + }), + ]), + messages: [new UserMessage("Generate a profile of a citizen of Europe.")], +}); +console.log(response.object); +``` + +_Source: [examples/backend/structured.ts](/examples/backend/structured.ts)_ + +### Tool Calling + + + +```ts +import "dotenv/config"; +import { + ChatModel, + Message, + SystemMessage, + ToolMessage, + UserMessage, +} from "bee-agent-framework/backend/core"; +import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; +import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; +import { AnyTool, ToolOutput } from "bee-agent-framework/tools/base"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +const tools: AnyTool[] = [new DuckDuckGoSearchTool(), new OpenMeteoTool()]; +const messages: Message[] = [ + new SystemMessage("You are a helpful assistant. Use tools to provide a correct answer."), + new UserMessage("What's the fastest marathon time?"), +]; + +while (true) { + const response = await model.create({ + messages, + tools, + }); + messages.push(...response.messages); + + const toolCalls = response.getToolCalls(); + const toolResults = await Promise.all( + toolCalls.map(async ({ args, toolName, toolCallId }) => { + console.log(`-> running '${toolName}' tool with ${JSON.stringify(args)}`); + const tool = tools.find((tool) => tool.name === toolName)!; + const response: ToolOutput = await tool.run(args as any); + const result = response.getTextContent(); + console.log( + `<- got response from '${toolName}'`, + result.replaceAll(/\s+/g, " ").substring(0, 90).concat(" (truncated)"), + ); + return new ToolMessage({ + type: "tool-result", + result, + isError: false, + toolName, + toolCallId, + }); + }), + ); + messages.push(...toolResults); + + const answer = response.getTextContent(); + if (answer) { + console.info(`Agent: ${answer}`); + break; + } +} +``` + +_Source: [examples/backend/toolCalling.ts](/examples/backend/toolCalling.ts)_ + +## Embedding Model + +The `EmbedingModel` class represents an Embedding Model and can be initiated in one of the following ways. + +```ts +import { EmbedingModel } from "bee-agent-framework/backend/core"; + +const model = await EmbedingModel.fromName("ibm/granite-embedding-107m-multilingual"); +console.log(model.providerId); // watsonx +console.log(model.modelId); // ibm/granite-embedding-107m-multilingual +``` + +or you can always create the concrete provider's embedding model directly + +```ts +import { OpenAIEmbeddingModel } from "bee-agent-framework/adapters/openai/embedding"; + +const model = new OpenAIEmbeddingModel( + "text-embedding-3-large", + { + dimensions: 512, + maxEmbeddingsPerCall: 5, + }, + { + baseURL: "your_custom_endpoint", + compatibility: "compatible", + headers: { + CUSTOM_HEADER: "...", + }, + }, +); +``` + +### Usage + +```ts +import { EmbeddingModel } from "bee-agent-framework/backend/core"; + +const model = await EmbeddingModel.fromName("ollama:nomic-embed-text"); +const response = await model.create({ + values: ["Hello world!", "Hello Bee!"], +}); +console.log(response.values); +console.log(response.embeddings); +``` diff --git a/docs/cache.md b/docs/cache.md index 3b91aec8..b1d3c8fe 100644 --- a/docs/cache.md +++ b/docs/cache.md @@ -104,34 +104,34 @@ _Source: [examples/cache/toolCache.ts](/examples/cache/toolCache.ts)_ ```ts import { SlidingCache } from "bee-agent-framework/cache/slidingCache"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; -const llm = new OllamaChatLLM({ - modelId: "llama3.1", - parameters: { - temperature: 0, - num_predict: 50, - }, +const llm = new OllamaChatModel("llama3.1"); +llm.config({ cache: new SlidingCache({ size: 50, }), + parameters: { + maxTokens: 25, + }, }); console.info(await llm.cache.size()); // 0 -const first = await llm.generate([BaseMessage.of({ role: "user", text: "Who was Alan Turing?" })]); +const first = await llm.create({ + messages: [new UserMessage("Who was Alan Turing?")], +}); // upcoming requests with the EXACTLY same input will be retrieved from the cache console.info(await llm.cache.size()); // 1 -const second = await llm.generate([BaseMessage.of({ role: "user", text: "Who was Alan Turing?" })]); -console.info(first === second); // true +const second = await llm.create({ + messages: [new UserMessage("Who was Alan Turing?")], +}); +console.info(first.getTextContent() === second.getTextContent()); // true +console.info(await llm.cache.size()); // 1 ``` _Source: [examples/cache/llmCache.ts](/examples/cache/llmCache.ts)_ -> [!TIP] -> -> Caching for non-chat LLMs works exactly the same way. - ## Cache types The framework provides multiple out-of-the-box cache implementations. diff --git a/docs/emitter.md b/docs/emitter.md index 7f9c439d..69be79c5 100644 --- a/docs/emitter.md +++ b/docs/emitter.md @@ -81,7 +81,7 @@ _Source: [examples/emitter/advanced.ts](/examples/emitter/advanced.ts)_ ```ts import { Callback, Emitter } from "bee-agent-framework/emitter/emitter"; -import { BaseLLM } from "bee-agent-framework/llms/base"; +import { ChatModel } from "bee-agent-framework/backend/chat"; interface Events { update: Callback<{ data: string }>; @@ -102,7 +102,7 @@ emitter.match("*.*", async (data, event) => {}); // Match events by providing a filter function emitter.match( - (event) => event.creator instanceof BaseLLM, + (event) => event.creator instanceof ChatModel, async (data, event) => {}, ); @@ -164,10 +164,10 @@ Typically, you consume out-of-the-box modules that use the `Emitter` concept on ```ts import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools: [], }); @@ -191,7 +191,7 @@ _Source: [examples/emitter/agentMatchers.ts](/examples/emitter/agentMatchers.ts) > [!IMPORTANT] > -> The `observe` method is also supported on [`Tools`](./tools.md) and [`LLMs`](./llms.md). +> The `observe` method is also supported on [`Tools`](./tools.md) and [`Backend`](./backend.md). > [!TIP] > diff --git a/docs/examples.md b/docs/examples.md index 08f9b89b..3b603313 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -43,7 +43,6 @@ This repository contains examples demonstrating the usage of the Bee Agent Frame - [`decoratorCacheComplex.ts`](/examples/cache/decoratorCacheComplex.ts): Complex cache decorator example - [`fileCache.ts`](/examples/cache/fileCache.ts): File-based caching - [`fileCacheCustomProvider.ts`](/examples/cache/fileCacheCustomProvider.ts): Custom provider for file cache -- [`llmCache.ts`](/examples/cache/llmCache.ts): Caching for language models - [`slidingCache.ts`](/examples/cache/slidingCache.ts): Sliding window cache implementation - [`toolCache.ts`](/examples/cache/toolCache.ts): Caching for tools - [`unconstrainedCache.ts`](/examples/cache/unconstrainedCache.ts): Unconstrained cache example @@ -62,23 +61,17 @@ This repository contains examples demonstrating the usage of the Bee Agent Frame ## LLMs (Language Models) -- [`chat.ts`](/examples/llms/chat.ts): Chat-based language model usage -- [`chatCallback.ts`](/examples/llms/chatCallback.ts): Callbacks for chat models -- [`chatStream.ts`](/examples/llms/chatStream.ts): Streaming with chat models -- [`structured.ts`](/examples/llms/structured.ts): Structured output from language models -- [`text.ts`](/examples/llms/text.ts): Text-based language model usage +- [`chat.ts`](/examples/backend/chat.ts): Chat-based language model usage +- [`chatCallback.ts`](/examples/backend/chatStream.ts): Callbacks for chat models +- [`structured.ts`](/examples/backend/structured.ts): Structured output from language models ### LLM Providers -- [`customChatProvider.ts`](/examples/llms/providers/customChatProvider.ts): Custom chat provider implementation -- [`customProvider.ts`](/examples/llms/providers/customProvider.ts): Custom language model provider -- [`groq.ts`](/examples/llms/providers/groq.ts): Groq language model integration -- [`ibm-vllm.ts`](/examples/llms/providers/ibm-vllm.ts): IBM vLLM integration -- [`langchain.ts`](/examples/llms/providers/langchain.ts): LangChain integration -- [`ollama.ts`](/examples/llms/providers/ollama.ts): Ollama model usage -- [`openai.ts`](/examples/llms/providers/openai.ts): OpenAI integration -- [`watsonx.ts`](/examples/llms/providers/watsonx.ts): WatsonX integration -- [`watsonx_verbose.ts`](/examples/llms/providers/watsonx_verbose.ts): Verbose WatsonX usage +- [`groq.ts`](/examples/backend/providers/groq.ts): Groq language model integration +- [`langchain.ts`](/examples/backend/providers/langchain.ts): LangChain integration +- [`ollama.ts`](/examples/backend/providers/ollama.ts): Ollama model usage +- [`openai.ts`](/examples/backend/providers/openai.ts): OpenAI integration +- [`watsonx.ts`](/examples/backend/providers/watsonx.ts): Watsonx integration ## Logger diff --git a/docs/integrations.md b/docs/integrations.md index 82e99b53..6c72777e 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -7,20 +7,20 @@ Bee Agent Framework is open-source framework for building, deploying, and servin ```ts +import "dotenv/config"; import { DuckDuckGoSearch as LangChainDDG } from "@langchain/community/tools/duckduckgo_search"; -import { ChatMessage as LangChainMessage } from "@langchain/core/messages"; import { createReactAgent as createLangGraphReactAgent } from "@langchain/langgraph/prebuilt"; -import { ChatOllama as LangChainOllamaChat } from "@langchain/ollama"; -import { OllamaChatLLM as BeeOllamaChat } from "bee-agent-framework/adapters/ollama/chat"; -import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { Workflow } from "bee-agent-framework/experimental/workflows/workflow"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { z } from "zod"; +import { createConsoleReader } from "examples/helpers/io.js"; +import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; +import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; +import { ChatOllama as LangChainOllamaChat } from "@langchain/ollama"; import { ReadOnlyMemory } from "bee-agent-framework/memory/base"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; -import "dotenv/config"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { z } from "zod"; +import { Message } from "bee-agent-framework/backend/message"; +import { ChatMessage as LangChainMessage } from "@langchain/core/messages"; +import { ChatModel } from "bee-agent-framework/backend/chat"; const workflow = new Workflow({ schema: z.object({ memory: z.instanceof(ReadOnlyMemory), answer: z.string().default("") }), @@ -30,7 +30,7 @@ const workflow = new Workflow({ })) .addStep("bee", async (state, ctx) => { const beeAgent = new BeeAgent({ - llm: new BeeOllamaChat({ modelId: "llama3.1" }), + llm: await ChatModel.fromName("ollama:llama3.1"), tools: [new DuckDuckGoSearchTool()], memory: state.memory, }); @@ -38,8 +38,7 @@ const workflow = new Workflow({ { prompt: null }, { signal: ctx.signal, execution: { maxIterations: 5 } }, ); - const answer = response.result.text; - return { next: Workflow.END, update: { answer } }; + return { next: Workflow.END, update: { answer: response.result.text } }; }) .addStep("langgraph", async (state, ctx) => { const langGraphAgent = createLangGraphReactAgent({ @@ -54,7 +53,7 @@ const workflow = new Workflow({ }, { signal: ctx.signal, recursionLimit: 5 }, ); - const answer = String(response.messages.at(-1)?.content); + const answer = response.messages.map((msg) => String(msg.content)).join(""); return { next: Workflow.END, update: { answer } }; }); @@ -62,11 +61,11 @@ const memory = new UnconstrainedMemory(); const reader = createConsoleReader(); for await (const { prompt } of reader) { - await memory.add(BaseMessage.of({ role: "user", text: prompt })); + await memory.add(Message.of({ role: "user", text: prompt })); const { result, steps } = await workflow.run({ memory: memory.asReadOnly() }); reader.write(`LLM πŸ€– : `, result.answer); reader.write(`-> solved by `, steps.at(-1)!.name); - await memory.add(BaseMessage.of({ role: "assistant", text: result.answer })); + await memory.add(Message.of({ role: "assistant", text: result.answer })); } ``` diff --git a/docs/llms.md b/docs/llms.md deleted file mode 100644 index 48c4cfa3..00000000 --- a/docs/llms.md +++ /dev/null @@ -1,243 +0,0 @@ -# LLMs (inference) - -> [!TIP] -> -> Location for concrete implementations within the framework `bee-agent-framework/adapters`. -> -> Location for base abstraction within the framework `bee-agent-framework/llms`. - -A Large Language Model (LLM) is an AI designed to understand and generate human-like text. -Trained on extensive text data, LLMs learn language patterns, grammar, context, and basic reasoning to perform tasks like text completion, translation, summarization, and answering questions. - -To unify differences between various APIs, the framework defines a common interfaceβ€”a set of actions that can be performed with it. - -## Providers (adapters) - -| Name | LLM | Chat LLM | Structured output (constrained decoding) | -| ------------------------------------------------------------------------- | -------------------------- | --------------------------------------------- | ---------------------------------------- | -| `WatsonX` | βœ… | ⚠️ (model specific template must be provided) | ❌ | -| `Ollama` | βœ… | βœ… | ⚠️ (JSON only) | -| `OpenAI` | ❌ | βœ… | ⚠️ (JSON schema only) | -| `Azure OpenAI` | ❌ | βœ… | ⚠️ (JSON schema only) | -| `LangChain` | ⚠️ (depends on a provider) | ⚠️ (depends on a provider) | ❌ | -| `Groq` | ❌ | βœ… | ⚠️ (JSON object only) | -| `AWS Bedrock` | ❌ | βœ… | ⚠️ (JSON only) - model specific | -| `VertexAI` | βœ… | βœ… | ⚠️ (JSON only) | -| βž• [Request](https://github.com/i-am-bee/bee-agent-framework/discussions) | | | | - -All providers' examples can be found in [examples/llms/providers](/examples/llms/providers). - -Are you interested in creating your own adapter? Jump to the [adding a new provider](#adding-a-new-provider-adapter) section. - -## Usage - -### Plain text generation - - - -```ts -import "dotenv/config.js"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { WatsonXLLM } from "bee-agent-framework/adapters/watsonx/llm"; - -const llm = new WatsonXLLM({ - modelId: "google/flan-ul2", - projectId: process.env.WATSONX_PROJECT_ID, - apiKey: process.env.WATSONX_API_KEY, - region: process.env.WATSONX_REGION, // (optional) default is us-south - parameters: { - decoding_method: "greedy", - max_new_tokens: 50, - }, -}); - -const reader = createConsoleReader(); -const prompt = await reader.prompt(); -const response = await llm.generate(prompt); -reader.write(`LLM πŸ€– (text) : `, response.getTextContent()); -reader.close(); -``` - -_Source: [examples/llms/text.ts](/examples/llms/text.ts)_ - -> [!NOTE] -> -> The `generate` method returns a class that extends the base [`BaseLLMOutput`](/src/llms/base.ts) class. -> This class allows you to retrieve the response as text using the `getTextContent` method and other useful metadata. - -> [!TIP] -> -> You can enable streaming communication (internally) by passing `{ stream: true }` as a second parameter to the `generate` method. - -### Chat text generation - - - -```ts -import "dotenv/config.js"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; - -const llm = new OllamaChatLLM(); - -const reader = createConsoleReader(); - -for await (const { prompt } of reader) { - const response = await llm.generate([ - BaseMessage.of({ - role: Role.USER, - text: prompt, - }), - ]); - reader.write(`LLM πŸ€– (txt) : `, response.getTextContent()); - reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(response.finalResult)); -} -``` - -_Source: [examples/llms/chat.ts](/examples/llms/chat.ts)_ - -> [!NOTE] -> -> The `generate` method returns a class that extends the base [`ChatLLMOutput`](/src/llms/chat.ts) class. -> This class allows you to retrieve the response as text using the `getTextContent` method and other useful metadata. -> To retrieve all messages (chunks) access the `messages` property (getter). - -> [!TIP] -> -> You can enable streaming communication (internally) by passing `{ stream: true }` as a second parameter to the `generate` method. - -#### Streaming - - - -```ts -import "dotenv/config.js"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; - -const llm = new OllamaChatLLM(); - -const reader = createConsoleReader(); - -for await (const { prompt } of reader) { - for await (const chunk of llm.stream([ - BaseMessage.of({ - role: Role.USER, - text: prompt, - }), - ])) { - reader.write(`LLM πŸ€– (txt) : `, chunk.getTextContent()); - reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(chunk.finalResult)); - } -} -``` - -_Source: [examples/llms/chatStream.ts](/examples/llms/chatStream.ts)_ - -#### Callback (Emitter) - - - -```ts -import "dotenv/config.js"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; - -const llm = new OllamaChatLLM(); - -const reader = createConsoleReader(); - -for await (const { prompt } of reader) { - const response = await llm - .generate( - [ - BaseMessage.of({ - role: Role.USER, - text: prompt, - }), - ], - {}, - ) - .observe((emitter) => - emitter.match("*", (data, event) => { - reader.write(`LLM πŸ€– (event: ${event.name})`, JSON.stringify(data)); - - // if you want to close the stream prematurely, just uncomment the following line - // callbacks.abort() - }), - ); - - reader.write(`LLM πŸ€– (txt) : `, response.getTextContent()); - reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(response.finalResult)); -} -``` - -_Source: [examples/llms/chatCallback.ts](/examples/llms/chatCallback.ts)_ - -### Structured generation - - - -```ts -import "dotenv/config.js"; -import { z } from "zod"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; - -const llm = new OllamaChatLLM(); -const driver = new JsonDriver(llm); -const response = await driver.generate( - z.union([ - z.object({ - firstName: z.string().min(1), - lastName: z.string().min(1), - address: z.string(), - age: z.number().int().min(1), - hobby: z.string(), - }), - z.object({ - error: z.string(), - }), - ]), - [ - BaseMessage.of({ - role: Role.USER, - text: "Generate a profile of a citizen of Europe.", - }), - ], -); -console.info(response); -``` - -_Source: [examples/llms/structured.ts](/examples/llms/structured.ts)_ - -## Adding a new provider (adapter) - -To use an inference provider that is not mentioned in our providers list feel free to [create a request](https://github.com/i-am-bee/bee-agent-framework/discussions). - -If approved and you want to create it on your own, you must do the following things. Let's assume the name of your provider is `Custom.` - -- Base location within the framework: `bee-agent-framework/adapters/custom` - - Text LLM (filename): `llm.ts` ([example implementation](/examples/llms/providers/customProvider.ts)) - - Chat LLM (filename): `chat.ts` ([example implementation](/examples/llms/providers/customChatProvider.ts)) - -> [!IMPORTANT] -> -> If the target provider provides an SDK, use it. - -> [!IMPORTANT] -> -> All provider-related dependencies (if any) must be included in `devDependencies` and `peerDependencies` in the [`package.json`](/package.json). - -> [!TIP] -> -> To simplify work with the target RestAPI feel free to use the helper [`RestfulClient`](/src/internals/fetcher.ts) class. -> The client usage can be seen in the WatsonX LLM Adapter [here](/src/adapters/watsonx/llm.ts). - -> [!TIP] -> -> Parsing environment variables should be done via helper functions (`parseEnv` / `hasEnv` / `getEnv`) that can be found [here](/src/internals/env.ts). diff --git a/docs/logger.md b/docs/logger.md index 3bc394f9..2d453c74 100644 --- a/docs/logger.md +++ b/docs/logger.md @@ -43,10 +43,10 @@ The [Logger](/src/logger/logger.ts) seamlessly integrates with agents in the fra ```ts import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { Logger } from "bee-agent-framework/logger/logger"; import { Emitter } from "bee-agent-framework/emitter/emitter"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; // Set up logging Logger.defaults.pretty = true; @@ -59,12 +59,12 @@ const logger = Logger.root.child({ // Log events emitted during agent execution Emitter.root.match("*.*", (data, event) => { const logLevel = event.path.includes(".run.") ? "trace" : "info"; - logger[logLevel](`Event '${event.path}' triggered by '${event.creator.constructor.name}'.`); + logger[logLevel](`Event '${event.path}' triggered by '${event.creator.constructor.name}'`); }); // Create and run an agent const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools: [], }); diff --git a/docs/memory.md b/docs/memory.md index bd095854..15be94ea 100644 --- a/docs/memory.md +++ b/docs/memory.md @@ -14,23 +14,15 @@ Memory in the context of an agent refers to the system's capability to store, re ```ts import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { AssistantMessage, SystemMessage, UserMessage } from "bee-agent-framework/backend/message"; const memory = new UnconstrainedMemory(); // Single message -await memory.add( - BaseMessage.of({ - role: "system", - text: `You are a helpful assistant.`, - }), -); +await memory.add(new SystemMessage(`You are a helpful assistant.`)); // Multiple messages -await memory.addMany([ - BaseMessage.of({ role: "user", text: `What can you do?` }), - BaseMessage.of({ role: "assistant", text: `Everything!` }), -]); +await memory.addMany([new UserMessage(`What can you do?`), new AssistantMessage(`Everything!`)]); console.info(memory.isEmpty()); // false console.info(memory.messages); // prints all saved messages @@ -45,23 +37,23 @@ _Source: [examples/memory/base.ts](/examples/memory/base.ts)_ ```ts -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const memory = new UnconstrainedMemory(); await memory.addMany([ - BaseMessage.of({ + Message.of({ role: "system", text: `Always respond very concisely.`, }), - BaseMessage.of({ role: "user", text: `Give me first 5 prime numbers.` }), + Message.of({ role: "user", text: `Give me first 5 prime numbers.` }), ]); // Generate response -const llm = new OllamaChatLLM(); -const response = await llm.generate(memory.messages); -await memory.add(BaseMessage.of({ role: "assistant", text: response.getTextContent() })); +const llm = new OllamaChatModel("llama3.1"); +const response = await llm.create({ messages: memory.messages }); +await memory.add(Message.of({ role: "assistant", text: response.getTextContent() })); console.log(`Conversation history`); for (const message of memory) { @@ -82,11 +74,11 @@ _Source: [examples/memory/llmMemory.ts](/examples/memory/llmMemory.ts)_ ```ts import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const agent = new BeeAgent({ memory: new UnconstrainedMemory(), - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), tools: [], }); await agent.run({ prompt: "Hello world!" }); @@ -126,11 +118,11 @@ Unlimited in size. ```ts import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; const memory = new UnconstrainedMemory(); await memory.add( - BaseMessage.of({ + Message.of({ role: "user", text: `Hello world!`, }), @@ -151,7 +143,7 @@ Keeps last `k` entries in the memory. The oldest ones are deleted (unless specif ```ts import { SlidingMemory } from "bee-agent-framework/memory/slidingMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; const memory = new SlidingMemory({ size: 3, // (required) number of messages that can be in the memory at a single moment @@ -162,11 +154,11 @@ const memory = new SlidingMemory({ }, }); -await memory.add(BaseMessage.of({ role: "system", text: "You are a guide through France." })); -await memory.add(BaseMessage.of({ role: "user", text: "What is the capital?" })); -await memory.add(BaseMessage.of({ role: "assistant", text: "Paris" })); -await memory.add(BaseMessage.of({ role: "user", text: "What language is spoken there?" })); // removes the first user's message -await memory.add(BaseMessage.of({ role: "assistant", text: "French" })); // removes the first assistant's message +await memory.add(Message.of({ role: "system", text: "You are a guide through France." })); +await memory.add(Message.of({ role: "user", text: "What is the capital?" })); +await memory.add(Message.of({ role: "assistant", text: "Paris" })); +await memory.add(Message.of({ role: "user", text: "What language is spoken there?" })); // removes the first user's message +await memory.add(Message.of({ role: "assistant", text: "French" })); // removes the first assistant's message console.info(memory.isEmpty()); // false console.log(memory.messages.length); // 3 @@ -184,13 +176,10 @@ If overflow occurs, the oldest message will be removed. ```ts import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { Message } from "bee-agent-framework/backend/message"; -const llm = new OllamaChatLLM(); const memory = new TokenMemory({ - llm, - maxTokens: undefined, // optional (default is inferred from the passed LLM instance), + maxTokens: undefined, // optional (default is 128k), capacityThreshold: 0.75, // maxTokens*capacityThreshold = threshold where we start removing old messages syncThreshold: 0.25, // maxTokens*syncThreshold = threshold where we start to use a real tokenization endpoint instead of guessing the number of tokens handlers: { @@ -202,8 +191,8 @@ const memory = new TokenMemory({ }, }); -await memory.add(BaseMessage.of({ role: "system", text: "You are a helpful assistant." })); -await memory.add(BaseMessage.of({ role: "user", text: "Hello world!" })); +await memory.add(Message.of({ role: "system", text: "You are a helpful assistant." })); +await memory.add(Message.of({ role: "user", text: "Hello world!" })); console.info(memory.isDirty); // is the consumed token count estimated or retrieved via the tokenize endpoint? console.log(memory.tokensUsed); // number of used tokens @@ -220,25 +209,19 @@ Only a single summarization of the conversation is preserved. Summarization is u ```ts -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; import { SummarizeMemory } from "bee-agent-framework/memory/summarizeMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const memory = new SummarizeMemory({ - llm: new OllamaChatLLM({ - modelId: "llama3.1", - parameters: { - temperature: 0, - num_predict: 250, - }, - }), + llm: new OllamaChatModel("llama3.1"), }); await memory.addMany([ - BaseMessage.of({ role: "system", text: "You are a guide through France." }), - BaseMessage.of({ role: "user", text: "What is the capital?" }), - BaseMessage.of({ role: "assistant", text: "Paris" }), - BaseMessage.of({ role: "user", text: "What language is spoken there?" }), + Message.of({ role: "system", text: "You are a guide through France." }), + Message.of({ role: "user", text: "What is the capital?" }), + Message.of({ role: "assistant", text: "Paris" }), + Message.of({ role: "user", text: "What language is spoken there?" }), ]); console.info(memory.isEmpty()); // false @@ -256,19 +239,19 @@ To create your memory implementation, you must implement the `BaseMemory` class. ```ts import { BaseMemory } from "bee-agent-framework/memory/base"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; import { NotImplementedError } from "bee-agent-framework/errors"; export class MyMemory extends BaseMemory { - get messages(): readonly BaseMessage[] { + get messages(): readonly Message[] { throw new NotImplementedError("Method not implemented."); } - add(message: BaseMessage, index?: number): Promise { + add(message: Message, index?: number): Promise { throw new NotImplementedError("Method not implemented."); } - delete(message: BaseMessage): Promise { + delete(message: Message): Promise { throw new NotImplementedError("Method not implemented."); } diff --git a/docs/migration_guide.md b/docs/migration_guide.md new file mode 100644 index 00000000..e4719585 --- /dev/null +++ b/docs/migration_guide.md @@ -0,0 +1,154 @@ +# Migration Guide + +## 0.0.X -> 0.1.0 (2025-02-11) + +### Summary + +- `ChatLLM` class was replaced by `ChatModel` class and embedding functionality has been replaced by `EmbeddingModel` class. +- `BaseMessage` class was replaced by `Message` and its subtypes (`UserMessage`, `AssistantMessage`, `SystemMessage`, `ToolMessage`). +- `TokenMemory` no longer uses `LLM` instance to infer `maxTokens`, user needs to do that manually (if needed). +- Tokenization has been removed. +- Non-Chat LLM class (`LLM`) has been removed. +- The`IBMvLLM` adapter has been removed. +- Parsers were moved from `bee-agent-framework/agents/parsers` to `bee-agent-framework/parsers` + +### Models + +#### Before + +```ts +import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; + +const model = new OllamaChatLLM({ + modelId: "llama3.1", +}); + +const response = await model.generate( + [ + BaseMessage.of({ + role: "user", + text: "Hello Bee!", + }), + ], + { + stream: true, + }, +); +console.log(response.getTextContent()); +``` + +#### Now + +```ts +import { ChatModel, UserMessage } from "bee-agent-framework/backend/core"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +const response = await model.create({ + messages: [new UserMessage("Hello Bee!")], +}); +console.log(response.getTextContent()); +``` + +or you can initiate the provider directly + +```ts +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/chat"; +import { UserMessage } from "bee-agent-framework/backend/core"; + +const model = new OllamaChatModel("llama3.1"); +const response = await model.create({ + messages: [new UserMessage("Hello Bee!")], +}); +console.log(response.getTextContent()); +``` + +More examples can be found in [Backend Documentation Page](/docs/backend.md). + +### Messages + +The `BaseMessage` class was replaced by `Message` and its subtypes (`UserMessage`, `AssistantMessage`, `SystemMessage`, `ToolMessage`). + +#### Before + +```ts +import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +const a = BaseMessage.of({ role: "user", text: "hello", meta: { createdAt: new Date() } }); +``` + +#### Now + +```ts +import { Message } from "bee-agent-framework/backend/core"; + +const a = Message.of({ role: "user", text: "Hello", meta: { createdAt: new Date() } }); +``` + +The new version supports more complex content types. + +```ts +import { UserMessage } from "bee-agent-framework/backend/core"; + +// using a factory function +const msg = new UserMessage({ + type: "file", + data: await fs.promises.readFile("document.txt"), + mimeType: "text/plain", +}); +``` + +```ts +import { UserMessage } from "bee-agent-framework/backend/core"; + +// using a factory function +const msg = new UserMessage({ + type: "file", + data: await fs.promises.readFile("document.txt"), + mimeType: "text/plain", +}); +``` + +```ts +import { UserMessage, AssistantMessage, SystemMessage } from "bee-agent-framework/backend/core"; +const a = new UserMessage("Hello assistant!"); +const b = new AssistantMessage("Hello user!"); +const c = new SystemMessage("You are a helpful assistant."); +``` + +More examples can be found in [Backend Documentation Page](/docs/backend.md). + +### Serialization + +The following methods present in `Serializable` class are now asynchronous. + +- `serialize` +- `deserialize` +- `createSnapshot` +- `loadSnapshot` + +The same applies to the following static methods. + +- `fromSerialized` +- `fromSnapshot` + +#### Before + +```ts +import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; + +const a = new TokenMemory(); +const json = a.serialize(); + +const b = TokenMemory.fromSerialized(json); +``` + +#### Now + +```ts +import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; + +const a = new TokenMemory(); +const json = await a.serialize(); + +const b = await TokenMemory.fromSerialized(json); +``` diff --git a/docs/overview.md b/docs/overview.md index 97ee6860..28d5e21b 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -4,22 +4,21 @@ The source directory (`src`) provides numerous modules that one can use. -| Name | Description | -| -------------------------------------------- | ------------------------------------------------------------------------------------------- | -| [**agents**](./agents.md) | Base classes defining the common interface for agent. | -| [**llms**](./llms.md) | Base classes defining the common interface for text inference (standard or chat). | -| [**template**](./templates.md) | Prompt Templating system based on `Mustache` with various improvements. | -| [**memory**](./memory.md) | Various types of memories to use with agent. | -| [**tools**](./tools.md) | Tools that an agent can use. | -| [**cache**](./cache.md) | Preset of different caching approaches that can be used together with tools. | -| [**errors**](./errors.md) | Base framework error classes used by each module. | -| [**adapters**](./llms.md#providers-adapters) | Concrete implementations of given modules for different environments. | -| [**logger**](./logger.md) | Core component for logging all actions within the framework. | -| [**serializer**](./serialization.md) | Core component for the ability to serialize/deserialize modules into the serialized format. | -| [**version**](./version.md) | Constants representing the framework (e.g., the latest version) | -| [**emitter**](./emitter.md) | Bringing visibility to the system by emitting events. | -| [**instrumentation**](./instrumentation.md) | Integrate monitoring tools into your application. | -| **internals** | Modules used by other modules within the framework. | +| Name | Description | +| ------------------------------------------- | ------------------------------------------------------------------------------------------- | +| [**agents**](./agents.md) | Base classes defining the common interface for agent. | +| [**backend**](/docs/backend.md) | Functionalities that relates to AI models (chat, embedding, image, tool calling, ...) | +| [**template**](./templates.md) | Prompt Templating system based on `Mustache` with various improvements. | +| [**memory**](./memory.md) | Various types of memories to use with agent. | +| [**tools**](./tools.md) | Tools that an agent can use. | +| [**cache**](./cache.md) | Preset of different caching approaches that can be used together with tools. | +| [**errors**](./errors.md) | Base framework error classes used by each module. | +| [**logger**](./logger.md) | Core component for logging all actions within the framework. | +| [**serializer**](./serialization.md) | Core component for the ability to serialize/deserialize modules into the serialized format. | +| [**version**](./version.md) | Constants representing the framework (e.g., the latest version) | +| [**emitter**](./emitter.md) | Bringing visibility to the system by emitting events. | +| [**instrumentation**](./instrumentation.md) | Integrate monitoring tools into your application. | +| **internals** | Modules used by other modules within the framework. | ### Emitter @@ -31,7 +30,7 @@ Moved to a [standalone page](instrumentation.md). ### LLMs -Moved to a [standalone page](llms.md). +Moved to a [standalone page](backend.md). ### Templates diff --git a/docs/serialization.md b/docs/serialization.md index 21a79639..6f09fd6a 100644 --- a/docs/serialization.md +++ b/docs/serialization.md @@ -13,8 +13,8 @@ Serialization is a difficult task, and JavaScript does not provide a magic tool import { Serializer } from "bee-agent-framework/serializer/serializer"; const original = new Date("2024-01-01T00:00:00.000Z"); -const serialized = Serializer.serialize(original); -const deserialized = Serializer.deserialize(serialized); +const serialized = await Serializer.serialize(original); +const deserialized = await Serializer.deserialize(serialized); console.info(deserialized instanceof Date); // true console.info(original.toISOString() === deserialized.toISOString()); // true @@ -42,27 +42,15 @@ See the direct usage on the following memory example. ```ts import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; - -const llm = new OllamaChatLLM(); -const memory = new TokenMemory({ llm }); -await memory.addMany([ - BaseMessage.of({ - role: "user", - text: "What is your name?", - }), -]); - -const serialized = memory.serialize(); -const deserialized = TokenMemory.fromSerialized(serialized); - -await deserialized.add( - BaseMessage.of({ - role: "assistant", - text: "Bee", - }), -); +import { AssistantMessage, UserMessage } from "bee-agent-framework/backend/message"; + +const memory = new TokenMemory(); +await memory.add(new UserMessage("What is your name?")); + +const serialized = await memory.serialize(); +const deserialized = await TokenMemory.fromSerialized(serialized); + +await deserialized.add(new AssistantMessage("Bee")); ``` _Source: [examples/serialization/memory.ts](/examples/serialization/memory.ts)_ @@ -95,8 +83,8 @@ Serializer.register(MyClass, { }); const instance = new MyClass("Bee"); -const serialized = Serializer.serialize(instance); -const deserialized = Serializer.deserialize(serialized); +const serialized = await Serializer.serialize(instance); +const deserialized = await Serializer.deserialize(serialized); console.info(instance); console.info(deserialized); @@ -133,8 +121,8 @@ class MyClass extends Serializable { } const instance = new MyClass("Bee"); -const serialized = instance.serialize(); -const deserialized = MyClass.fromSerialized(serialized); +const serialized = await instance.serialize(); +const deserialized = await MyClass.fromSerialized(serialized); console.info(instance); console.info(deserialized); @@ -152,15 +140,15 @@ _Source: [examples/serialization/customInternal.ts](/examples/serialization/cust ```ts import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { UserMessage } from "bee-agent-framework/backend/message"; // String containing serialized `UnconstrainedMemory` instance with one message in it. -const serialized = `{"__version":"0.0.0","__root":{"__serializer":true,"__class":"Object","__ref":"5","__value":{"target":"UnconstrainedMemory","snapshot":{"__serializer":true,"__class":"Object","__ref":"4","__value":{"messages":{"__serializer":true,"__class":"Array","__ref":"1","__value":[{"__serializer":true,"__class":"BaseMessage","__ref":"2","__value":{"role":"user","text":"Serialization is amazing, isn't?","meta":{"__serializer":true,"__class":"Undefined","__ref":"3"}}}]}}}}}}`; +const serialized = `{"__version":"0.0.0","__root":{"__serializer":true,"__class":"Object","__ref":"18","__value":{"target":"UnconstrainedMemory","snapshot":{"__serializer":true,"__class":"Object","__ref":"17","__value":{"messages":{"__serializer":true,"__class":"Array","__ref":"1","__value":[{"__serializer":true,"__class":"SystemMessage","__ref":"2","__value":{"content":{"__serializer":true,"__class":"Array","__ref":"3","__value":[{"__serializer":true,"__class":"Object","__ref":"4","__value":{"type":"text","text":"You are a helpful assistant."}}]},"meta":{"__serializer":true,"__class":"Object","__ref":"5","__value":{"createdAt":{"__serializer":true,"__class":"Date","__ref":"6","__value":"2025-02-06T14:51:01.459Z"}}},"role":"system"}},{"__serializer":true,"__class":"UserMessage","__ref":"7","__value":{"content":{"__serializer":true,"__class":"Array","__ref":"8","__value":[{"__serializer":true,"__class":"Object","__ref":"9","__value":{"type":"text","text":"Hello!"}}]},"meta":{"__serializer":true,"__class":"Object","__ref":"10","__value":{"createdAt":{"__serializer":true,"__class":"Date","__ref":"11","__value":"2025-02-06T14:51:01.459Z"}}},"role":"user"}},{"__serializer":true,"__class":"AssistantMessage","__ref":"12","__value":{"content":{"__serializer":true,"__class":"Array","__ref":"13","__value":[{"__serializer":true,"__class":"Object","__ref":"14","__value":{"type":"text","text":"Hello, how can I help you?"}}]},"meta":{"__serializer":true,"__class":"Object","__ref":"15","__value":{"createdAt":{"__serializer":true,"__class":"Date","__ref":"16","__value":"2025-02-06T14:51:01.459Z"}}},"role":"assistant"}}]}}}}}}`; -// If `BaseMessage` was not imported the serialization would fail because the `BaseMessage` had no chance to register itself. -const memory = UnconstrainedMemory.fromSerialized(serialized, { +// If `Message` was not imported the serialization would fail because the `Message` had no chance to register itself. +const memory = await UnconstrainedMemory.fromSerialized(serialized, { // this part can be omitted if all classes used in the serialized string are imported (and have `static` register block) or at least one initiated - extraClasses: [BaseMessage], + extraClasses: [UserMessage], }); console.info(memory.messages); ``` diff --git a/docs/tools.md b/docs/tools.md index 0906c056..e4f8b04f 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -98,13 +98,13 @@ _Source: [examples/tools/advanced.ts](/examples/tools/advanced.ts)_ ```ts -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { ArXivTool } from "bee-agent-framework/tools/arxiv"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools: [new ArXivTool()], }); @@ -483,7 +483,7 @@ import { MCPTool } from "bee-agent-framework/tools/mcp"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; // Create MCP Client const client = new Client( @@ -508,7 +508,7 @@ try { // Server usually supports several tools, use the factory for automatic discovery const tools = await MCPTool.fromClient(client); const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools, }); diff --git a/docs/tutorials.md b/docs/tutorials.md index 26df981d..97dff260 100644 --- a/docs/tutorials.md +++ b/docs/tutorials.md @@ -64,7 +64,7 @@ Now, copy and paste the following code into `agent_slack.ts` module. Then, follo import { MCPTool } from "bee-agent-framework/tools/mcp"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; @@ -104,7 +104,7 @@ try { // Create Bee agent const agent = new BeeAgent({ // We're using LLM ran locally via Ollama - llm: new OllamaChatLLM({ modelId: "llama3.1" }), + llm: new OllamaChatModel("llama3.1"), // Besides the Slack tools, we also provide DDG tool for web search tools: [new OpenMeteoTool(), ...filteredSlackTools], memory: new UnconstrainedMemory(), diff --git a/docs/workflows.md b/docs/workflows.md index 57df3728..151e3d22 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -97,25 +97,24 @@ _Source: [examples/workflows/nesting.ts](/examples/workflows/nesting.ts)_ import "dotenv/config"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { z } from "zod"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; +import { Message, UserMessage } from "bee-agent-framework/backend/message"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { ReadOnlyMemory } from "bee-agent-framework/memory/base"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { Workflow } from "bee-agent-framework/experimental/workflows/workflow"; import { createConsoleReader } from "examples/helpers/io.js"; -import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; +import { GroqChatModel } from "bee-agent-framework/adapters/groq/backend/chat"; const schema = z.object({ - answer: z.instanceof(BaseMessage).optional(), + answer: z.instanceof(Message).optional(), memory: z.instanceof(ReadOnlyMemory), }); const workflow = new Workflow({ schema: schema }) .addStep("simpleAgent", async (state) => { const simpleAgent = new BeeAgent({ - llm: new GroqChatLLM(), + llm: new GroqChatModel("llama-3.3-70b-versatile"), tools: [], memory: state.memory, }); @@ -128,18 +127,18 @@ const workflow = new Workflow({ schema: schema }) }; }) .addStrictStep("critique", schema.required(), async (state) => { - const llm = new GroqChatLLM(); - const { parsed: critiqueResponse } = await new JsonDriver(llm).generate( - z.object({ score: z.number().int().min(0).max(100) }), - [ - BaseMessage.of({ + const llm = new GroqChatModel("llama-3.3-70b-versatile"); + const { object: critiqueResponse } = await llm.createStructure({ + schema: z.object({ score: z.number().int().min(0).max(100) }), + messages: [ + Message.of({ role: "system", text: `You are an evaluation assistant who scores the credibility of the last assistant's response. Chitchatting always has a score of 100. If the assistant was unable to answer the user's query, then the score will be 0.`, }), ...state.memory.messages, state.answer, ], - ); + }); reader.write("🧠 Score", critiqueResponse.score.toString()); return { @@ -148,7 +147,7 @@ const workflow = new Workflow({ schema: schema }) }) .addStep("complexAgent", async (state) => { const complexAgent = new BeeAgent({ - llm: new GroqChatLLM(), + llm: new GroqChatModel("llama-3.3-70b-versatile"), tools: [new WikipediaTool(), new OpenMeteoTool()], memory: state.memory, }); @@ -162,11 +161,7 @@ const reader = createConsoleReader(); const memory = new UnconstrainedMemory(); for await (const { prompt } of reader) { - const userMessage = BaseMessage.of({ - role: Role.USER, - text: prompt, - meta: { createdAt: new Date() }, - }); + const userMessage = new UserMessage(prompt); await memory.add(userMessage); const response = await workflow.run({ @@ -191,12 +186,11 @@ import { Workflow } from "bee-agent-framework/experimental/workflows/workflow"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; +import { Message } from "bee-agent-framework/backend/message"; import { isEmpty, pick } from "remeda"; import { LLMTool } from "bee-agent-framework/tools/llm"; import { GoogleSearchTool } from "bee-agent-framework/tools/search/googleSearch"; -import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; +import { GroqChatModel } from "bee-agent-framework/adapters/groq/backend/chat"; const schema = z.object({ input: z.string(), @@ -213,19 +207,18 @@ const workflow = new Workflow({ outputSchema: schema.required({ output: true }), }) .addStep("preprocess", async (state) => { - const llm = new GroqChatLLM(); - const driver = new JsonDriver(llm); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); - const { parsed } = await driver.generate( - schema.pick({ topic: true, notes: true }).or( + const { object: parsed } = await llm.createStructure({ + schema: schema.pick({ topic: true, notes: true }).or( z.object({ error: z .string() .describe("Use when the input query does not make sense or you need clarification."), }), ), - [ - BaseMessage.of({ + messages: [ + Message.of({ role: `user`, text: [ "Your task is to rewrite the user query so that it guides the content planner and editor to craft a blog post that perfectly aligns with the user's needs. Notes should be used only if the user complains about something.", @@ -240,14 +233,14 @@ const workflow = new Workflow({ .join("\n"), }), ], - ); + }); return "error" in parsed ? { update: { output: parsed.error }, next: Workflow.END } : { update: pick(parsed, ["notes", "topic"]) }; }) .addStrictStep("planner", schema.required({ topic: true }), async (state) => { - const llm = new GroqChatLLM(); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); const agent = new BeeAgent({ llm, memory: new UnconstrainedMemory(), @@ -280,54 +273,58 @@ const workflow = new Workflow({ }; }) .addStrictStep("writer", schema.required({ plan: true }), async (state) => { - const llm = new GroqChatLLM(); - const output = await llm.generate([ - BaseMessage.of({ - role: `system`, - text: [ - `You are a Content Writer. Your task is to write a compelling blog post based on the provided context.`, - ``, - `# Context`, - `${state.plan}`, - ``, - `# Objectives`, - `- An engaging introduction`, - `- Insightful body paragraphs (2-3 per section)`, - `- Properly named sections/subtitles`, - `- A summarizing conclusion`, - `- Format: Markdown`, - ``, - ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], - `Ensure the content flows naturally, incorporates SEO keywords, and is well-structured.`, - ].join("\n"), - }), - ]); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); + const output = await llm.create({ + messages: [ + Message.of({ + role: `system`, + text: [ + `You are a Content Writer. Your task is to write a compelling blog post based on the provided context.`, + ``, + `# Context`, + `${state.plan}`, + ``, + `# Objectives`, + `- An engaging introduction`, + `- Insightful body paragraphs (2-3 per section)`, + `- Properly named sections/subtitles`, + `- A summarizing conclusion`, + `- Format: Markdown`, + ``, + ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], + `Ensure the content flows naturally, incorporates SEO keywords, and is well-structured.`, + ].join("\n"), + }), + ], + }); return { update: { draft: output.getTextContent() }, }; }) .addStrictStep("editor", schema.required({ draft: true }), async (state) => { - const llm = new GroqChatLLM(); - const output = await llm.generate([ - BaseMessage.of({ - role: `system`, - text: [ - `You are an Editor. Your task is to transform the following draft blog post to a final version.`, - ``, - `# Draft`, - `${state.draft}`, - ``, - `# Objectives`, - `- Fix Grammatical errors`, - `- Journalistic best practices`, - ``, - ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], - ``, - `IMPORTANT: The final version must not contain any editor's comments.`, - ].join("\n"), - }), - ]); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); + const output = await llm.create({ + messages: [ + Message.of({ + role: `system`, + text: [ + `You are an Editor. Your task is to transform the following draft blog post to a final version.`, + ``, + `# Draft`, + `${state.draft}`, + ``, + `# Objectives`, + `- Fix Grammatical errors`, + `- Journalistic best practices`, + ``, + ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], + ``, + `IMPORTANT: The final version must not contain any editor's comments.`, + ].join("\n"), + }), + ], + }); return { update: { output: output.getTextContent() }, @@ -367,14 +364,11 @@ import { createConsoleReader } from "examples/helpers/io.js"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { AgentWorkflow } from "bee-agent-framework/experimental/workflows/agent"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { WatsonxChatModel } from "bee-agent-framework/adapters/watsonx/backend/chat"; const workflow = new AgentWorkflow(); -const llm = WatsonXChatLLM.fromPreset("meta-llama/llama-3-3-70b-instruct", { - apiKey: process.env.WATSONX_API_KEY, - projectId: process.env.WATSONX_PROJECT_ID, -}); +const llm = new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"); workflow.addAgent({ name: "WeatherForecaster", @@ -400,13 +394,7 @@ const reader = createConsoleReader(); const memory = new UnconstrainedMemory(); for await (const { prompt } of reader) { - await memory.add( - BaseMessage.of({ - role: Role.USER, - text: prompt, - meta: { createdAt: new Date() }, - }), - ); + await memory.add(new UserMessage(prompt, { createdAt: new Date() })); const { result } = await workflow.run(memory.messages).observe((emitter) => { emitter.on("success", (data) => { diff --git a/eslint.config.js b/eslint.config.js index 5e7efd9b..5793df48 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -9,15 +9,11 @@ import stylisticJs from "@stylistic/eslint-plugin-js"; export default tseslint.config( { - ignores: ["node_modules/**", "dist/**", "scripts/ibm_vllm_generate_protos/**"], + ignores: ["node_modules/**", "dist/**"], }, eslint.configs.recommended, ...tseslint.configs.strict, ...tseslint.configs.stylistic, - { - files: ["src/adapters/ibm-vllm/types.ts"], - rules: { "@typescript-eslint/unified-signatures": "off" }, - }, { files: ["**/*.md/**"], languageOptions: { @@ -88,6 +84,7 @@ export default tseslint.config( ignorePattern: /^(?![\s\S]*Copyright \d+ IBM Corp.)[\s\S]+$/u.source, }, ], + "@typescript-eslint/class-literal-property-style": "off", }, }, { diff --git a/examples/README.md b/examples/README.md index 08f9b89b..3b603313 100644 --- a/examples/README.md +++ b/examples/README.md @@ -43,7 +43,6 @@ This repository contains examples demonstrating the usage of the Bee Agent Frame - [`decoratorCacheComplex.ts`](/examples/cache/decoratorCacheComplex.ts): Complex cache decorator example - [`fileCache.ts`](/examples/cache/fileCache.ts): File-based caching - [`fileCacheCustomProvider.ts`](/examples/cache/fileCacheCustomProvider.ts): Custom provider for file cache -- [`llmCache.ts`](/examples/cache/llmCache.ts): Caching for language models - [`slidingCache.ts`](/examples/cache/slidingCache.ts): Sliding window cache implementation - [`toolCache.ts`](/examples/cache/toolCache.ts): Caching for tools - [`unconstrainedCache.ts`](/examples/cache/unconstrainedCache.ts): Unconstrained cache example @@ -62,23 +61,17 @@ This repository contains examples demonstrating the usage of the Bee Agent Frame ## LLMs (Language Models) -- [`chat.ts`](/examples/llms/chat.ts): Chat-based language model usage -- [`chatCallback.ts`](/examples/llms/chatCallback.ts): Callbacks for chat models -- [`chatStream.ts`](/examples/llms/chatStream.ts): Streaming with chat models -- [`structured.ts`](/examples/llms/structured.ts): Structured output from language models -- [`text.ts`](/examples/llms/text.ts): Text-based language model usage +- [`chat.ts`](/examples/backend/chat.ts): Chat-based language model usage +- [`chatCallback.ts`](/examples/backend/chatStream.ts): Callbacks for chat models +- [`structured.ts`](/examples/backend/structured.ts): Structured output from language models ### LLM Providers -- [`customChatProvider.ts`](/examples/llms/providers/customChatProvider.ts): Custom chat provider implementation -- [`customProvider.ts`](/examples/llms/providers/customProvider.ts): Custom language model provider -- [`groq.ts`](/examples/llms/providers/groq.ts): Groq language model integration -- [`ibm-vllm.ts`](/examples/llms/providers/ibm-vllm.ts): IBM vLLM integration -- [`langchain.ts`](/examples/llms/providers/langchain.ts): LangChain integration -- [`ollama.ts`](/examples/llms/providers/ollama.ts): Ollama model usage -- [`openai.ts`](/examples/llms/providers/openai.ts): OpenAI integration -- [`watsonx.ts`](/examples/llms/providers/watsonx.ts): WatsonX integration -- [`watsonx_verbose.ts`](/examples/llms/providers/watsonx_verbose.ts): Verbose WatsonX usage +- [`groq.ts`](/examples/backend/providers/groq.ts): Groq language model integration +- [`langchain.ts`](/examples/backend/providers/langchain.ts): LangChain integration +- [`ollama.ts`](/examples/backend/providers/ollama.ts): Ollama model usage +- [`openai.ts`](/examples/backend/providers/openai.ts): OpenAI integration +- [`watsonx.ts`](/examples/backend/providers/watsonx.ts): Watsonx integration ## Logger diff --git a/examples/agents/bee.ts b/examples/agents/bee.ts index cc955f94..b9503b89 100644 --- a/examples/agents/bee.ts +++ b/examples/agents/bee.ts @@ -11,7 +11,7 @@ import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; Logger.root.level = "silent"; // disable internal logs const logger = new Logger({ name: "app", level: "trace" }); @@ -21,7 +21,7 @@ const logger = new Logger({ name: "app", level: "trace" }); // "granite3.1-dense" // "deepseek-r1:32b" // ensure the model is pulled before running -const llm = new OllamaChatLLM({ modelId: "llama3.1:8b" }); +const llm = new OllamaChatModel("llama3.1"); const codeInterpreterUrl = process.env.CODE_INTERPRETER_URL; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -32,7 +32,7 @@ const localTmpdir = process.env.LOCAL_TMPDIR ?? "./examples/tmp/local"; const agent = new BeeAgent({ llm, - memory: new TokenMemory({ llm }), + memory: new TokenMemory(), tools: [ new DuckDuckGoSearchTool(), // new WebCrawlerTool(), // HTML web page crawler diff --git a/examples/agents/bee_advanced.ts b/examples/agents/bee_advanced.ts index de809387..816aed06 100644 --- a/examples/agents/bee_advanced.ts +++ b/examples/agents/bee_advanced.ts @@ -10,14 +10,12 @@ import { import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { z } from "zod"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; Logger.root.level = "silent"; // disable internal logs const logger = new Logger({ name: "app", level: "trace" }); -const llm = new OllamaChatLLM({ - modelId: "llama3.1", // llama3.1:70b for better performance -}); +const llm = new OllamaChatModel("llama3.1"); const agent = new BeeAgent({ llm, diff --git a/examples/agents/bee_instrumentation.ts b/examples/agents/bee_instrumentation.ts index 2763228c..1caff9eb 100644 --- a/examples/agents/bee_instrumentation.ts +++ b/examples/agents/bee_instrumentation.ts @@ -9,18 +9,16 @@ import { Logger } from "bee-agent-framework/logger/logger"; import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; Logger.root.level = "silent"; // disable internal logs const logger = new Logger({ name: "app", level: "trace" }); -const llm = new OllamaChatLLM({ - modelId: "llama3.1", // llama3.1:70b for better performance -}); +const llm = new OllamaChatModel("llama3.1"); const agent = new BeeAgent({ llm, - memory: new TokenMemory({ llm }), + memory: new TokenMemory(), tools: [ new DuckDuckGoSearchTool(), new WikipediaTool(), diff --git a/examples/agents/bee_reusable.ts b/examples/agents/bee_reusable.ts index 456db628..6d2a4ee8 100644 --- a/examples/agents/bee_reusable.ts +++ b/examples/agents/bee_reusable.ts @@ -1,12 +1,12 @@ import "dotenv/config.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { OpenAIChatLLM } from "bee-agent-framework/adapters/openai/chat"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; // We create an agent let agent = new BeeAgent({ - llm: new OpenAIChatLLM(), + llm: new OllamaChatModel("llama3.1"), tools: [new WikipediaTool()], memory: new UnconstrainedMemory(), }); @@ -20,10 +20,10 @@ const response = await agent.run({ console.info(response.result.text); // We can save (serialize) the agent -const json = agent.serialize(); +const json = await agent.serialize(); // We reinitialize the agent to the exact state he was -agent = BeeAgent.fromSerialized(json); +agent = await BeeAgent.fromSerialized(json); // We continue in our conversation prompt = "When was he born?"; diff --git a/examples/agents/custom_agent.ts b/examples/agents/custom_agent.ts index b569aa0f..89935748 100644 --- a/examples/agents/custom_agent.ts +++ b/examples/agents/custom_agent.ts @@ -1,22 +1,25 @@ import { BaseAgent, BaseAgentRunOptions } from "bee-agent-framework/agents/base"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; +import { + AssistantMessage, + Message, + SystemMessage, + UserMessage, +} from "bee-agent-framework/backend/message"; import { Emitter } from "bee-agent-framework/emitter/emitter"; import { GetRunContext } from "bee-agent-framework/context"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; import { z } from "zod"; -import { PromptTemplate } from "bee-agent-framework/template"; import { AgentMeta } from "bee-agent-framework/agents/types"; -import { ChatLLM, ChatLLMOutput } from "bee-agent-framework/llms/chat"; import { BaseMemory } from "bee-agent-framework/memory/base"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; +import { ChatModel } from "bee-agent-framework/backend/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; interface RunInput { - message: BaseMessage; + message: Message; } interface RunOutput { - message: BaseMessage; + message: Message; state: { thought: string; final_answer: string; @@ -28,35 +31,21 @@ interface RunOptions extends BaseAgentRunOptions { } interface AgentInput { - llm: ChatLLM; + llm: ChatModel; memory: BaseMemory; } export class CustomAgent extends BaseAgent { - protected driver: JsonDriver; public readonly memory: BaseMemory; + protected readonly model: ChatModel; public emitter = Emitter.root.child({ namespace: ["agent", "custom"], creator: this, }); - protected static systemPrompt = new PromptTemplate({ - schema: z.object({ - schema: z.string().min(1), - }), - template: `You are a helpful assistant that generates only valid JSON adhering to the following JSON Schema. - -\`\`\` -{{schema}} -\`\`\` - -IMPORTANT: Every message must be a parsable JSON string without additional output. -`, - }); - constructor(input: AgentInput) { super(); - this.driver = JsonDriver.fromTemplate(CustomAgent.systemPrompt, input.llm); + this.model = input.llm; this.memory = input.memory; } @@ -65,8 +54,8 @@ IMPORTANT: Every message must be a parsable JSON string without additional outpu options: RunOptions, run: GetRunContext, ): Promise { - const response = await this.driver.generate( - z.object({ + const response = await this.model.createStructure({ + schema: z.object({ thought: z .string() .describe("Describe your thought process before coming with a final answer"), @@ -74,22 +63,21 @@ IMPORTANT: Every message must be a parsable JSON string without additional outpu .string() .describe("Here you should provide concise answer to the original question."), }), - [...this.memory.messages, input.message], - { - maxRetries: options?.maxRetries, - options: { signal: run.signal }, - }, - ); - - const result = BaseMessage.of({ - role: Role.ASSISTANT, - text: response.parsed.final_answer, + messages: [ + new SystemMessage("You are a helpful assistant. Always use JSON format for you responses."), + ...this.memory.messages, + input.message, + ], + maxRetries: options?.maxRetries, + abortSignal: run.signal, }); + + const result = new AssistantMessage(response.object.final_answer); await this.memory.add(result); return { message: result, - state: response.parsed, + state: response.object, }; } @@ -104,7 +92,6 @@ IMPORTANT: Every message must be a parsable JSON string without additional outpu createSnapshot() { return { ...super.createSnapshot(), - driver: this.driver, emitter: this.emitter, memory: this.memory, }; @@ -116,10 +103,11 @@ IMPORTANT: Every message must be a parsable JSON string without additional outpu } const agent = new CustomAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("granite3.1-dense"), memory: new UnconstrainedMemory(), }); + const response = await agent.run({ - message: BaseMessage.of({ role: Role.USER, text: "Why is the sky blue?" }), + message: new UserMessage("Why is the sky blue?"), }); console.info(response.state); diff --git a/examples/agents/elasticsearch.ts b/examples/agents/elasticsearch.ts index 1a488ac4..d6449e02 100644 --- a/examples/agents/elasticsearch.ts +++ b/examples/agents/elasticsearch.ts @@ -1,12 +1,12 @@ import "dotenv/config.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OpenAIChatLLM } from "bee-agent-framework/adapters/openai/chat"; +import { OpenAIChatModel } from "bee-agent-framework/adapters/openai/backend/chat"; import { ElasticSearchTool } from "bee-agent-framework/tools/database/elasticsearch"; import { FrameworkError } from "bee-agent-framework/errors"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { createConsoleReader } from "../helpers/io.js"; -const llm = new OpenAIChatLLM(); +const llm = new OpenAIChatModel("gpt-4o"); const elasticSearchTool = new ElasticSearchTool({ connection: { diff --git a/examples/agents/experimental/human.ts b/examples/agents/experimental/human.ts index 98d8c7ef..141cbe7d 100644 --- a/examples/agents/experimental/human.ts +++ b/examples/agents/experimental/human.ts @@ -8,16 +8,14 @@ import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; // Import the HumanTool from the updated file import { HumanTool } from "../../tools/experimental/human.js"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; // Set up logger Logger.root.level = "silent"; // Disable internal logs const logger = new Logger({ name: "app", level: "trace" }); // Initialize LLM (test against llama as requested) -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -const llm = new OllamaChatLLM({ - modelId: "llama3.1", -}); +const llm = new OllamaChatModel("llama3.1"); // Create the console reader once, share it with HumanTool const reader = createConsoleReader(); @@ -25,7 +23,7 @@ const reader = createConsoleReader(); // Initialize BeeAgent with shared reader for HumanTool const agent = new BeeAgent({ llm, - memory: new TokenMemory({ llm }), + memory: new TokenMemory(), tools: [ new OpenMeteoTool(), new HumanTool({ diff --git a/examples/agents/experimental/replan.ts b/examples/agents/experimental/replan.ts index 510103f0..57b9c223 100644 --- a/examples/agents/experimental/replan.ts +++ b/examples/agents/experimental/replan.ts @@ -5,15 +5,12 @@ import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { createConsoleReader } from "examples/helpers/io.js"; import { RePlanAgent } from "bee-agent-framework/agents/experimental/replan/agent"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; +import { WatsonxChatModel } from "bee-agent-framework/adapters/watsonx/backend/chat"; const reader = createConsoleReader(); const agent = new RePlanAgent({ - llm: WatsonXChatLLM.fromPreset("meta-llama/llama-3-3-70b-instruct", { - apiKey: process.env.WATSONX_API_KEY, - projectId: process.env.WATSONX_PROJECT_ID, - }), + llm: new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"), memory: new UnconstrainedMemory(), tools: [new DuckDuckGoSearchTool(), new OpenMeteoTool()], }); diff --git a/examples/agents/experimental/streamlit.ts b/examples/agents/experimental/streamlit.ts index 210743ec..aee6143d 100644 --- a/examples/agents/experimental/streamlit.ts +++ b/examples/agents/experimental/streamlit.ts @@ -3,16 +3,13 @@ import { FrameworkError } from "bee-agent-framework/errors"; import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; import { createConsoleReader } from "examples/helpers/io.js"; import { StreamlitAgent } from "bee-agent-framework/agents/experimental/streamlit/agent"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; +import { WatsonxChatModel } from "bee-agent-framework/adapters/watsonx/backend/chat"; -const llm = WatsonXChatLLM.fromPreset("meta-llama/llama-3-3-70b-instruct", { - apiKey: process.env.WATSONX_API_KEY, - projectId: process.env.WATSONX_PROJECT_ID, -}); +const llm = new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"); const agent = new StreamlitAgent({ llm, - memory: new TokenMemory({ llm }), + memory: new TokenMemory(), }); const reader = createConsoleReader(); diff --git a/examples/agents/granite/README.md b/examples/agents/granite/README.md index 998fda19..dab27449 100644 --- a/examples/agents/granite/README.md +++ b/examples/agents/granite/README.md @@ -53,7 +53,7 @@ The [granite_bee](/examples/agents/granite/granite_bee.ts) example agent is set ```.env LLM_BACKEND=ollama - OLLAMA_HOST={http://0.0.0.0:11434} + OLLAMA_BASE_URL={http://0.0.0.0:11434} ``` 1. Run the [granite_bee](/examples/agents/granite/granite_bee.ts) agent: diff --git a/examples/agents/granite/granite_bee.ts b/examples/agents/granite/granite_bee.ts index 3a3a5ded..2499a92b 100644 --- a/examples/agents/granite/granite_bee.ts +++ b/examples/agents/granite/granite_bee.ts @@ -1,83 +1,17 @@ import "dotenv/config.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { ChatLLM, ChatLLMOutput } from "bee-agent-framework/llms/chat"; -import { getEnv, parseEnv } from "bee-agent-framework/internals/env"; import { FrameworkError } from "bee-agent-framework/errors"; import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; -import { OpenAIChatLLM } from "bee-agent-framework/adapters/openai/chat"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { IBMVllmChatLLM } from "bee-agent-framework/adapters/ibm-vllm/chat"; -import { IBMVllmModel } from "bee-agent-framework/adapters/ibm-vllm/chatPreset"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; -import { Ollama } from "ollama"; -import OpenAI from "openai"; -import { z } from "zod"; import * as process from "node:process"; import { createConsoleReader } from "examples/helpers/io.js"; +import { ChatModel } from "bee-agent-framework/backend/chat"; -const Providers = { - WATSONX: "watsonx", - OLLAMA: "ollama", - IBMVLLM: "ibmvllm", - IBMRITS: "ibmrits", -} as const; -type Provider = (typeof Providers)[keyof typeof Providers]; - -function getChatLLM(provider?: Provider): ChatLLM { - const LLMFactories: Record ChatLLM> = { - [Providers.OLLAMA]: () => - new OllamaChatLLM({ - modelId: getEnv("OLLAMA_MODEL") || "granite3.1-dense:8b", - parameters: { - temperature: 0, - repeat_penalty: 1, - num_predict: 2000, - }, - client: new Ollama({ - host: getEnv("OLLAMA_HOST"), - }), - }), - [Providers.WATSONX]: () => - WatsonXChatLLM.fromPreset(getEnv("WATSONX_MODEL") || "ibm/granite-3-8b-instruct", { - apiKey: getEnv("WATSONX_API_KEY"), - projectId: getEnv("WATSONX_PROJECT_ID"), - region: getEnv("WATSONX_REGION"), - }), - [Providers.IBMVLLM]: () => IBMVllmChatLLM.fromPreset(IBMVllmModel.GRANITE_3_1_8B_INSTRUCT), - [Providers.IBMRITS]: () => - new OpenAIChatLLM({ - client: new OpenAI({ - baseURL: process.env.IBM_RITS_URL, - apiKey: process.env.IBM_RITS_API_KEY, - defaultHeaders: { - RITS_API_KEY: process.env.IBM_RITS_API_KEY, - }, - }), - modelId: getEnv("IBM_RITS_MODEL") || "ibm-granite/granite-3.1-8b-instruct", - parameters: { - temperature: 0, - max_tokens: 2048, - }, - }), - }; - - if (!provider) { - provider = parseEnv("LLM_BACKEND", z.nativeEnum(Providers), Providers.OLLAMA); - } - - const factory = LLMFactories[provider]; - if (!factory) { - throw new Error(`Provider "${provider}" not found.`); - } - return factory(); -} - -const llm = getChatLLM(); +const llm = await ChatModel.fromName("ollama:granite3.1-dense:8b"); const agent = new BeeAgent({ llm, - memory: new TokenMemory({ llm }), + memory: new TokenMemory(), tools: [new OpenMeteoTool(), new DuckDuckGoSearchTool({ maxResults: 3 })], }); @@ -92,7 +26,7 @@ try { execution: { maxIterations: 8, maxRetriesPerStep: 3, - totalMaxRetries: 3, + totalMaxRetries: 2, }, }, ) diff --git a/examples/agents/granite/granite_wiki_bee.ts b/examples/agents/granite/granite_wiki_bee.ts index 6424bab4..782870b1 100644 --- a/examples/agents/granite/granite_wiki_bee.ts +++ b/examples/agents/granite/granite_wiki_bee.ts @@ -2,22 +2,24 @@ import "dotenv/config.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { FrameworkError } from "bee-agent-framework/errors"; import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { z } from "zod"; -import { OllamaLLM } from "bee-agent-framework/adapters/ollama/llm"; import { SimilarityTool } from "bee-agent-framework/tools/similarity"; import { cosineSimilarityMatrix } from "bee-agent-framework/internals/helpers/math"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { splitString } from "bee-agent-framework/internals/helpers/string"; import { AnyTool } from "bee-agent-framework/tools/base"; import { createConsoleReader } from "examples/helpers/io.js"; +import { ChatModel } from "bee-agent-framework/backend/chat"; +import { EmbeddingModel } from "bee-agent-framework/backend/embedding"; // Creates a wikipedia tool that supports information retrieval -function wikipediaRetrivalTool(passageSize: number, overlap: number, maxResults: number): AnyTool { +async function createWikipediaRetrivalTool( + passageSize: number, + overlap: number, + maxResults: number, +): Promise { // LLM to perform text embedding - const embeddingLLM = new OllamaLLM({ - modelId: "nomic-embed-text", - }); + const embeddingLLM = await EmbeddingModel.fromName("ollama:nomic-embed-text"); // Estimate of character per LLM token const charsPerToken = 4; @@ -26,10 +28,9 @@ function wikipediaRetrivalTool(passageSize: number, overlap: number, maxResults: const similarity = new SimilarityTool({ maxResults: maxResults, provider: async (input): Promise<{ score: number }[]> => { - const embeds = await embeddingLLM.embed([ - input.query, - ...input.documents.map((doc) => doc.text), - ]); + const embeds = await embeddingLLM.create({ + values: [input.query, ...input.documents.map((doc) => doc.text)], + }); const similarities = cosineSimilarityMatrix( [embeds.embeddings[0]], // Query embeds.embeddings.slice(1), // Documents @@ -75,18 +76,15 @@ function wikipediaRetrivalTool(passageSize: number, overlap: number, maxResults: } // Agent LLM -const llm = new OllamaChatLLM({ - modelId: "granite3.1-dense:8b", - parameters: { - temperature: 0, - num_predict: 2048, - }, +const llm = await ChatModel.fromName("ollama:granite3.1-dense:8b", { + temperature: 0, + maxTokens: 2048, }); const agent = new BeeAgent({ llm, - memory: new TokenMemory({ llm }), - tools: [wikipediaRetrivalTool(400, 50, 3)], + memory: new TokenMemory(), + tools: [await createWikipediaRetrivalTool(400, 50, 3)], }); const reader = createConsoleReader(); diff --git a/examples/agents/simple.ts b/examples/agents/simple.ts index af4161f5..4b9723cc 100644 --- a/examples/agents/simple.ts +++ b/examples/agents/simple.ts @@ -2,13 +2,13 @@ import "dotenv/config.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; -const llm = new OllamaChatLLM(); +const llm = new OllamaChatModel("llama3.1"); const agent = new BeeAgent({ llm, - memory: new TokenMemory({ llm }), + memory: new TokenMemory(), tools: [new DuckDuckGoSearchTool(), new OpenMeteoTool()], }); diff --git a/examples/agents/sql.ts b/examples/agents/sql.ts index 9bd4160d..bbfa47b3 100644 --- a/examples/agents/sql.ts +++ b/examples/agents/sql.ts @@ -1,19 +1,14 @@ import "dotenv/config.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; import { SQLTool } from "bee-agent-framework/tools/database/sql"; import { FrameworkError } from "bee-agent-framework/errors"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import fs from "node:fs"; import * as path from "node:path"; import os from "node:os"; +import { GroqChatModel } from "bee-agent-framework/adapters/groq/backend/chat"; -const llm = new GroqChatLLM({ - modelId: "llama-3.1-70b-versatile", - parameters: { - temperature: 0, - }, -}); +const llm = new GroqChatModel("llama-3.3-70b-versatile"); const sqlTool = new SQLTool({ provider: "sqlite", diff --git a/examples/backend/backend.ts b/examples/backend/backend.ts new file mode 100644 index 00000000..ca1cc483 --- /dev/null +++ b/examples/backend/backend.ts @@ -0,0 +1,6 @@ +import "dotenv/config.js"; +import { Backend } from "bee-agent-framework/backend/core"; + +const backend = await Backend.fromProvider("ollama"); +console.info(backend.chat.modelId); +console.info(backend.embedding.modelId); diff --git a/examples/backend/chat.ts b/examples/backend/chat.ts new file mode 100644 index 00000000..b96775e1 --- /dev/null +++ b/examples/backend/chat.ts @@ -0,0 +1,16 @@ +import "dotenv/config.js"; +import { createConsoleReader } from "examples/helpers/io.js"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; + +const llm = new OllamaChatModel("llama3.1"); + +const reader = createConsoleReader(); + +for await (const { prompt } of reader) { + const response = await llm.create({ + messages: [new UserMessage(prompt)], + }); + reader.write(`LLM πŸ€– (txt) : `, response.getTextContent()); + reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(response.messages)); +} diff --git a/examples/llms/chatCallback.ts b/examples/backend/chatStream.ts similarity index 58% rename from examples/llms/chatCallback.ts rename to examples/backend/chatStream.ts index 6efb9a14..0aad1820 100644 --- a/examples/llms/chatCallback.ts +++ b/examples/backend/chatStream.ts @@ -1,23 +1,17 @@ import "dotenv/config.js"; import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; -const llm = new OllamaChatLLM(); +const llm = new OllamaChatModel("llama3.1"); const reader = createConsoleReader(); for await (const { prompt } of reader) { const response = await llm - .generate( - [ - BaseMessage.of({ - role: Role.USER, - text: prompt, - }), - ], - {}, - ) + .create({ + messages: [new UserMessage(prompt)], + }) .observe((emitter) => emitter.match("*", (data, event) => { reader.write(`LLM πŸ€– (event: ${event.name})`, JSON.stringify(data)); @@ -28,5 +22,5 @@ for await (const { prompt } of reader) { ); reader.write(`LLM πŸ€– (txt) : `, response.getTextContent()); - reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(response.finalResult)); + reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(response.messages)); } diff --git a/examples/backend/providers/amazon-bedrock.ts b/examples/backend/providers/amazon-bedrock.ts new file mode 100644 index 00000000..58329493 --- /dev/null +++ b/examples/backend/providers/amazon-bedrock.ts @@ -0,0 +1,10 @@ +import "dotenv/config"; +import { AmazonBedrockChatModel } from "bee-agent-framework/adapters/amazon-bedrock/backend/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; + +const llm = new AmazonBedrockChatModel("amazon.titan-text-lite-v1"); + +const response = await llm.create({ + messages: [new UserMessage("Hello world!")], +}); +console.info(response.getTextContent()); diff --git a/examples/backend/providers/azure_openai.ts b/examples/backend/providers/azure_openai.ts new file mode 100644 index 00000000..96c24184 --- /dev/null +++ b/examples/backend/providers/azure_openai.ts @@ -0,0 +1,10 @@ +import "dotenv/config"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { AzureOpenAIChatModel } from "bee-agent-framework/adapters/azure-openai/backend/chat"; + +const llm = new AzureOpenAIChatModel("gpt-4o-mini"); + +const response = await llm.create({ + messages: [new UserMessage("Hello world!")], +}); +console.info(response.getTextContent()); diff --git a/examples/backend/providers/groq.ts b/examples/backend/providers/groq.ts new file mode 100644 index 00000000..cf2e120b --- /dev/null +++ b/examples/backend/providers/groq.ts @@ -0,0 +1,13 @@ +import "dotenv/config"; +import { GroqChatModel } from "bee-agent-framework/adapters/groq/backend/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; + +const llm = new GroqChatModel("gemma2-9b-it"); + +const response = await llm.create({ + messages: [new UserMessage("Hello!")], + temperature: 0.7, + maxTokens: 1024, + topP: 1, +}); +console.info(response.getTextContent()); diff --git a/examples/llms/providers/langchain.ts b/examples/backend/providers/langchain.ts similarity index 59% rename from examples/llms/providers/langchain.ts rename to examples/backend/providers/langchain.ts index 18c53f48..91605fea 100644 --- a/examples/llms/providers/langchain.ts +++ b/examples/backend/providers/langchain.ts @@ -3,24 +3,20 @@ // - @langchain/cohere (or any other provider related package that you would like to use) // List of available providers: https://js.langchain.com/v0.2/docs/integrations/chat/ -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { LangChainChatLLM } from "bee-agent-framework/adapters/langchain/llms/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { LangChainChatModel } from "bee-agent-framework/adapters/langchain/backend/chat"; // @ts-expect-error package not installed import { ChatCohere } from "@langchain/cohere"; console.info("===CHAT==="); -const llm = new LangChainChatLLM( +const llm = new LangChainChatModel( new ChatCohere({ model: "command-r-plus", temperature: 0, }), ); -const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), -]); -console.info(response.messages); +const response = await llm.create({ + messages: [new UserMessage("Hello world!")], +}); console.info(response.getTextContent()); diff --git a/examples/backend/providers/ollama.ts b/examples/backend/providers/ollama.ts new file mode 100644 index 00000000..ce14a528 --- /dev/null +++ b/examples/backend/providers/ollama.ts @@ -0,0 +1,10 @@ +import "dotenv/config.js"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; + +const llm = new OllamaChatModel("llama3.1"); + +const response = await llm.create({ + messages: [new UserMessage("Hello world!")], +}); +console.info(response.getTextContent()); diff --git a/examples/backend/providers/openai.ts b/examples/backend/providers/openai.ts new file mode 100644 index 00000000..431c542c --- /dev/null +++ b/examples/backend/providers/openai.ts @@ -0,0 +1,10 @@ +import "dotenv/config.js"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { OpenAIChatModel } from "bee-agent-framework/adapters/openai/backend/chat"; + +const llm = new OpenAIChatModel("gpt-4o"); + +const response = await llm.create({ + messages: [new UserMessage("Hello world!")], +}); +console.info(response.getTextContent()); diff --git a/examples/backend/providers/vertexai.ts b/examples/backend/providers/vertexai.ts new file mode 100644 index 00000000..3eb23b15 --- /dev/null +++ b/examples/backend/providers/vertexai.ts @@ -0,0 +1,10 @@ +import "dotenv/config.js"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { GoogleVertexChatModel } from "bee-agent-framework/adapters/google-vertex/backend/chat"; + +const llm = new GoogleVertexChatModel("gemini-1.5-flash-001"); + +const response = await llm.create({ + messages: [new UserMessage("Hello world!")], +}); +console.info(response.getTextContent()); diff --git a/examples/backend/providers/watsonx.ts b/examples/backend/providers/watsonx.ts new file mode 100644 index 00000000..33cce5fc --- /dev/null +++ b/examples/backend/providers/watsonx.ts @@ -0,0 +1,10 @@ +import "dotenv/config.js"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { WatsonxChatModel } from "bee-agent-framework/adapters/watsonx/backend/chat"; + +const llm = new WatsonxChatModel("meta-llama/llama-3-1-70b-instruct"); + +const response = await llm.create({ + messages: [new UserMessage("Hello world!")], +}); +console.info(response.getTextContent()); diff --git a/examples/backend/providers/watsonx_debug.ts b/examples/backend/providers/watsonx_debug.ts new file mode 100644 index 00000000..7ca9af70 --- /dev/null +++ b/examples/backend/providers/watsonx_debug.ts @@ -0,0 +1,19 @@ +import "dotenv/config"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { WatsonxChatModel } from "bee-agent-framework/adapters/watsonx/backend/chat"; + +const chatLLM = new WatsonxChatModel("meta-llama/llama-3-1-70b-instruct"); + +// Log every request +chatLLM.emitter.match("*", async (data, event) => { + console.info( + `Time: ${event.createdAt.toISOString().substring(11, 19)}`, + `Event: ${event.name}`, + `Data: ${JSON.stringify(data).substring(0, 128).concat("...")}`, + ); +}); + +const response = await chatLLM.create({ + messages: [new UserMessage("Hello world!")], +}); +console.info(response.messages[0]); diff --git a/examples/backend/structured.ts b/examples/backend/structured.ts new file mode 100644 index 00000000..dd6733c1 --- /dev/null +++ b/examples/backend/structured.ts @@ -0,0 +1,20 @@ +import { ChatModel, UserMessage } from "bee-agent-framework/backend/core"; +import { z } from "zod"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +const response = await model.createStructure({ + schema: z.union([ + z.object({ + firstName: z.string().min(1), + lastName: z.string().min(1), + address: z.string(), + age: z.number().int().min(1), + hobby: z.string(), + }), + z.object({ + error: z.string(), + }), + ]), + messages: [new UserMessage("Generate a profile of a citizen of Europe.")], +}); +console.log(response.object); diff --git a/examples/backend/toolCalling.ts b/examples/backend/toolCalling.ts new file mode 100644 index 00000000..2ef78efa --- /dev/null +++ b/examples/backend/toolCalling.ts @@ -0,0 +1,54 @@ +import "dotenv/config"; +import { + ChatModel, + Message, + SystemMessage, + ToolMessage, + UserMessage, +} from "bee-agent-framework/backend/core"; +import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; +import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; +import { AnyTool, ToolOutput } from "bee-agent-framework/tools/base"; + +const model = await ChatModel.fromName("ollama:llama3.1"); +const tools: AnyTool[] = [new DuckDuckGoSearchTool(), new OpenMeteoTool()]; +const messages: Message[] = [ + new SystemMessage("You are a helpful assistant. Use tools to provide a correct answer."), + new UserMessage("What's the fastest marathon time?"), +]; + +while (true) { + const response = await model.create({ + messages, + tools, + }); + messages.push(...response.messages); + + const toolCalls = response.getToolCalls(); + const toolResults = await Promise.all( + toolCalls.map(async ({ args, toolName, toolCallId }) => { + console.log(`-> running '${toolName}' tool with ${JSON.stringify(args)}`); + const tool = tools.find((tool) => tool.name === toolName)!; + const response: ToolOutput = await tool.run(args as any); + const result = response.getTextContent(); + console.log( + `<- got response from '${toolName}'`, + result.replaceAll(/\s+/g, " ").substring(0, 90).concat(" (truncated)"), + ); + return new ToolMessage({ + type: "tool-result", + result, + isError: false, + toolName, + toolCallId, + }); + }), + ); + messages.push(...toolResults); + + const answer = response.getTextContent(); + if (answer) { + console.info(`Agent: ${answer}`); + break; + } +} diff --git a/examples/cache/llmCache.ts b/examples/cache/llmCache.ts index 312c560d..059444ca 100644 --- a/examples/cache/llmCache.ts +++ b/examples/cache/llmCache.ts @@ -1,21 +1,25 @@ import { SlidingCache } from "bee-agent-framework/cache/slidingCache"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; -const llm = new OllamaChatLLM({ - modelId: "llama3.1", - parameters: { - temperature: 0, - num_predict: 50, - }, +const llm = new OllamaChatModel("llama3.1"); +llm.config({ cache: new SlidingCache({ size: 50, }), + parameters: { + maxTokens: 25, + }, }); console.info(await llm.cache.size()); // 0 -const first = await llm.generate([BaseMessage.of({ role: "user", text: "Who was Alan Turing?" })]); +const first = await llm.create({ + messages: [new UserMessage("Who was Alan Turing?")], +}); // upcoming requests with the EXACTLY same input will be retrieved from the cache console.info(await llm.cache.size()); // 1 -const second = await llm.generate([BaseMessage.of({ role: "user", text: "Who was Alan Turing?" })]); -console.info(first === second); // true +const second = await llm.create({ + messages: [new UserMessage("Who was Alan Turing?")], +}); +console.info(first.getTextContent() === second.getTextContent()); // true +console.info(await llm.cache.size()); // 1 diff --git a/examples/emitter/agentMatchers.ts b/examples/emitter/agentMatchers.ts index 4436edac..72483885 100644 --- a/examples/emitter/agentMatchers.ts +++ b/examples/emitter/agentMatchers.ts @@ -1,9 +1,9 @@ import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools: [], }); diff --git a/examples/emitter/matchers.ts b/examples/emitter/matchers.ts index 3bda3b9e..85e2e39d 100644 --- a/examples/emitter/matchers.ts +++ b/examples/emitter/matchers.ts @@ -1,5 +1,5 @@ import { Callback, Emitter } from "bee-agent-framework/emitter/emitter"; -import { BaseLLM } from "bee-agent-framework/llms/base"; +import { ChatModel } from "bee-agent-framework/backend/chat"; interface Events { update: Callback<{ data: string }>; @@ -20,7 +20,7 @@ emitter.match("*.*", async (data, event) => {}); // Match events by providing a filter function emitter.match( - (event) => event.creator instanceof BaseLLM, + (event) => event.creator instanceof ChatModel, async (data, event) => {}, ); diff --git a/examples/integrations/langgraph.ts b/examples/integrations/langgraph.ts index bfab601f..220b9b26 100644 --- a/examples/integrations/langgraph.ts +++ b/examples/integrations/langgraph.ts @@ -1,17 +1,17 @@ +import "dotenv/config"; import { DuckDuckGoSearch as LangChainDDG } from "@langchain/community/tools/duckduckgo_search"; -import { ChatMessage as LangChainMessage } from "@langchain/core/messages"; import { createReactAgent as createLangGraphReactAgent } from "@langchain/langgraph/prebuilt"; -import { ChatOllama as LangChainOllamaChat } from "@langchain/ollama"; -import { OllamaChatLLM as BeeOllamaChat } from "bee-agent-framework/adapters/ollama/chat"; -import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { Workflow } from "bee-agent-framework/experimental/workflows/workflow"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { z } from "zod"; +import { createConsoleReader } from "examples/helpers/io.js"; +import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; +import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; +import { ChatOllama as LangChainOllamaChat } from "@langchain/ollama"; import { ReadOnlyMemory } from "bee-agent-framework/memory/base"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch"; -import "dotenv/config"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { z } from "zod"; +import { Message } from "bee-agent-framework/backend/message"; +import { ChatMessage as LangChainMessage } from "@langchain/core/messages"; +import { ChatModel } from "bee-agent-framework/backend/chat"; const workflow = new Workflow({ schema: z.object({ memory: z.instanceof(ReadOnlyMemory), answer: z.string().default("") }), @@ -21,7 +21,7 @@ const workflow = new Workflow({ })) .addStep("bee", async (state, ctx) => { const beeAgent = new BeeAgent({ - llm: new BeeOllamaChat({ modelId: "llama3.1" }), + llm: await ChatModel.fromName("ollama:llama3.1"), tools: [new DuckDuckGoSearchTool()], memory: state.memory, }); @@ -29,8 +29,7 @@ const workflow = new Workflow({ { prompt: null }, { signal: ctx.signal, execution: { maxIterations: 5 } }, ); - const answer = response.result.text; - return { next: Workflow.END, update: { answer } }; + return { next: Workflow.END, update: { answer: response.result.text } }; }) .addStep("langgraph", async (state, ctx) => { const langGraphAgent = createLangGraphReactAgent({ @@ -45,7 +44,7 @@ const workflow = new Workflow({ }, { signal: ctx.signal, recursionLimit: 5 }, ); - const answer = String(response.messages.at(-1)?.content); + const answer = response.messages.map((msg) => String(msg.content)).join(""); return { next: Workflow.END, update: { answer } }; }); @@ -53,9 +52,9 @@ const memory = new UnconstrainedMemory(); const reader = createConsoleReader(); for await (const { prompt } of reader) { - await memory.add(BaseMessage.of({ role: "user", text: prompt })); + await memory.add(Message.of({ role: "user", text: prompt })); const { result, steps } = await workflow.run({ memory: memory.asReadOnly() }); reader.write(`LLM πŸ€– : `, result.answer); reader.write(`-> solved by `, steps.at(-1)!.name); - await memory.add(BaseMessage.of({ role: "assistant", text: result.answer })); + await memory.add(Message.of({ role: "assistant", text: result.answer })); } diff --git a/examples/llms/chat.ts b/examples/llms/chat.ts deleted file mode 100644 index 478dbfc9..00000000 --- a/examples/llms/chat.ts +++ /dev/null @@ -1,19 +0,0 @@ -import "dotenv/config.js"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; - -const llm = new OllamaChatLLM(); - -const reader = createConsoleReader(); - -for await (const { prompt } of reader) { - const response = await llm.generate([ - BaseMessage.of({ - role: Role.USER, - text: prompt, - }), - ]); - reader.write(`LLM πŸ€– (txt) : `, response.getTextContent()); - reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(response.finalResult)); -} diff --git a/examples/llms/chatStream.ts b/examples/llms/chatStream.ts deleted file mode 100644 index ba91c3a7..00000000 --- a/examples/llms/chatStream.ts +++ /dev/null @@ -1,20 +0,0 @@ -import "dotenv/config.js"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; - -const llm = new OllamaChatLLM(); - -const reader = createConsoleReader(); - -for await (const { prompt } of reader) { - for await (const chunk of llm.stream([ - BaseMessage.of({ - role: Role.USER, - text: prompt, - }), - ])) { - reader.write(`LLM πŸ€– (txt) : `, chunk.getTextContent()); - reader.write(`LLM πŸ€– (raw) : `, JSON.stringify(chunk.finalResult)); - } -} diff --git a/examples/llms/embed.ts b/examples/llms/embed.ts deleted file mode 100644 index b884fa96..00000000 --- a/examples/llms/embed.ts +++ /dev/null @@ -1,16 +0,0 @@ -import "dotenv/config.js"; -import { OllamaLLM } from "bee-agent-framework/adapters/ollama/llm"; -import { cosineSimilarity } from "bee-agent-framework/internals/helpers/math"; -import { EmbeddingOutput } from "bee-agent-framework/llms/base"; - -const llm = new OllamaLLM({ - modelId: "nomic-embed-text", -}); - -const embed: EmbeddingOutput = await llm.embed(["King", "Queen"]); -console.log(cosineSimilarity(embed.embeddings[0], embed.embeddings[1])); - -const sentences = ["Hard cold rock", "Warm Soft pillow"]; - -const embed1: EmbeddingOutput = await llm.embed(sentences); -console.log(cosineSimilarity(embed1.embeddings[0], embed1.embeddings[1])); diff --git a/examples/llms/instrumentation.ts b/examples/llms/instrumentation.ts deleted file mode 100644 index 8c971e4b..00000000 --- a/examples/llms/instrumentation.ts +++ /dev/null @@ -1,27 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////////////// -/////// RUN THIS EXAMPLE VIA `yarn start:telemetry ./examples/llms/instrumentation.ts` /////////// -////////////////////////////////////////////////////////////////////////////////////////////////// -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { Logger } from "bee-agent-framework/logger/logger"; - -Logger.root.level = "silent"; // disable internal logs -const logger = new Logger({ name: "app", level: "trace" }); - -const llm = new OllamaChatLLM({ - modelId: "llama3.1", // llama3.1:70b for better performance -}); - -const response = await llm.generate([ - BaseMessage.of({ - role: Role.USER, - text: "hello", - }), -]); - -logger.info(`LLM πŸ€– (txt) : ${response.getTextContent()}`); - -// Wait briefly to ensure all telemetry data has been processed -setTimeout(() => { - logger.info("Process exiting after OpenTelemetry flush."); -}, 5_000); // Adjust the delay as needed diff --git a/examples/llms/providers/azure_openai.ts b/examples/llms/providers/azure_openai.ts deleted file mode 100644 index 3f9fc5e4..00000000 --- a/examples/llms/providers/azure_openai.ts +++ /dev/null @@ -1,21 +0,0 @@ -import "dotenv/config"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { OpenAIChatLLM } from "bee-agent-framework/adapters/openai/chat"; - -const llm = new OpenAIChatLLM({ - modelId: "gpt-4o-mini", - azure: true, - parameters: { - max_tokens: 10, - stop: ["post"], - }, -}); - -console.info("Meta", await llm.meta()); -const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), -]); -console.info(response.getTextContent()); diff --git a/examples/llms/providers/bedrock.ts b/examples/llms/providers/bedrock.ts deleted file mode 100644 index 6272dc34..00000000 --- a/examples/llms/providers/bedrock.ts +++ /dev/null @@ -1,22 +0,0 @@ -import "dotenv/config"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { BedrockChatLLM } from "bee-agent-framework/adapters/bedrock/chat"; - -const llm = new BedrockChatLLM({ - region: process.env.AWS_REGION, - modelId: "amazon.titan-text-lite-v1", - parameters: { - temperature: 0.7, - maxTokens: 1024, - topP: 1, - }, -}); - -console.info("meta", await llm.meta()); -const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), -]); -console.info(response.getTextContent()); diff --git a/examples/llms/providers/customChatProvider.ts b/examples/llms/providers/customChatProvider.ts deleted file mode 100644 index c2aba390..00000000 --- a/examples/llms/providers/customChatProvider.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - StreamGenerateOptions, -} from "bee-agent-framework/llms/base"; -import { shallowCopy } from "bee-agent-framework/serializer/utils"; -import type { GetRunContext } from "bee-agent-framework/context"; -import { Emitter } from "bee-agent-framework/emitter/emitter"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "bee-agent-framework/llms/chat"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { sum } from "remeda"; -import { NotImplementedError } from "bee-agent-framework/errors"; - -export class CustomChatLLMOutput extends ChatLLMOutput { - public readonly chunks: BaseMessage[] = []; - - constructor(chunk: BaseMessage) { - super(); - this.chunks.push(chunk); - } - - get messages() { - return this.chunks; - } - - merge(other: CustomChatLLMOutput): void { - this.chunks.push(...other.chunks); - } - - getTextContent(): string { - return this.chunks.map((result) => result.text).join(""); - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { chunks: shallowCopy(this.chunks) }; - } - - loadSnapshot(snapshot: ReturnType): void { - Object.assign(this, snapshot); - } -} - -// Feel free to extend if you want to support additional parameters -type CustomGenerateOptions = GenerateOptions; - -export interface CustomChatLLMInput { - modelId: string; - executionOptions?: ExecutionOptions; - cache?: LLMCache; - parameters?: Record; -} - -type CustomChatLLMEvents = ChatLLMGenerateEvents; - -export class CustomChatLLM extends ChatLLM { - public readonly emitter = Emitter.root.child({ - namespace: ["custom", "llm"], - creator: this, - }); - - constructor(protected readonly input: CustomChatLLMInput) { - super(input.modelId, input.executionOptions, input.cache); - } - - static { - this.register(); - } - - async meta(): Promise { - // TODO: retrieve data about current model from the given provider API - return { tokenLimit: Infinity }; - } - - async embed(input: BaseMessage[][], options?: EmbeddingOptions): Promise { - throw new NotImplementedError(); - } - - async tokenize(input: BaseMessage[]): Promise { - // TODO: retrieve data about current model from the given provider API - return { - tokensCount: sum(input.map((msg) => Math.ceil(msg.text.length / 4))), - }; - } - - protected async _generate( - input: BaseMessage[], - options: Partial, - run: GetRunContext, - ): Promise { - // this method should do non-stream request to the API - // TIP: access inference parameters via `this.input.parameters` and `options` - // TIP: use signal from run.signal - const result = BaseMessage.of({ - role: Role.ASSISTANT, - text: "TODO: response retrieve from the API", - }); - return new CustomChatLLMOutput(result); - } - - protected async *_stream( - input: BaseMessage[], - options: Partial, - run: GetRunContext, - ): AsyncStream { - // this method should do stream request to the API - // TIP: access inference parameters via `this.input.parameters` and `options` - // TIP: use signal from run.signal - for await (const chunk of ["Hel", "oo", "world", "!"]) { - const result = BaseMessage.of({ - role: Role.ASSISTANT, - text: chunk, - }); - yield new CustomChatLLMOutput(result); - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - input: shallowCopy(this.input), - }; - } - - loadSnapshot({ input, ...snapshot }: ReturnType) { - super.loadSnapshot(snapshot); - Object.assign(this, { input }); - } -} diff --git a/examples/llms/providers/customProvider.ts b/examples/llms/providers/customProvider.ts deleted file mode 100644 index d5a1eaf8..00000000 --- a/examples/llms/providers/customProvider.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { LLM, LLMEvents, LLMInput } from "bee-agent-framework/llms/llm"; -import { - AsyncStream, - BaseLLMOutput, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, -} from "bee-agent-framework/llms/base"; -import { shallowCopy } from "bee-agent-framework/serializer/utils"; -import type { GetRunContext } from "bee-agent-framework/context"; -import { Emitter } from "bee-agent-framework/emitter/emitter"; -import { NotImplementedError } from "bee-agent-framework/errors"; - -interface CustomLLMChunk { - text: string; - metadata: Record; -} - -export class CustomLLMOutput extends BaseLLMOutput { - public readonly chunks: CustomLLMChunk[] = []; - - constructor(chunk: CustomLLMChunk) { - super(); - this.chunks.push(chunk); - } - - merge(other: CustomLLMOutput): void { - this.chunks.push(...other.chunks); - } - - getTextContent(): string { - return this.chunks.map((result) => result.text).join(""); - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { chunks: shallowCopy(this.chunks) }; - } - - loadSnapshot(snapshot: ReturnType): void { - Object.assign(this, snapshot); - } -} - -// Feel free to extend if you want to support additional parameters -type CustomGenerateOptions = GenerateOptions; - -export interface CustomLLMInput { - modelId: string; - executionOptions?: ExecutionOptions; - cache?: LLMCache; - parameters?: Record; -} - -type CustomLLMEvents = LLMEvents; - -export class CustomLLM extends LLM { - public readonly emitter = Emitter.root.child({ - namespace: ["custom", "llm"], - creator: this, - }); - - constructor(protected readonly input: CustomLLMInput) { - super(input.modelId, input.executionOptions, input.cache); - } - - static { - this.register(); - } - - async meta(): Promise { - // TODO: retrieve data about current model from the given provider API - return { tokenLimit: Infinity }; - } - - async embed(input: LLMInput[], options?: EmbeddingOptions): Promise { - throw new NotImplementedError(); - } - - async tokenize(input: LLMInput): Promise { - // TODO: retrieve data about current model from the given provider API - return { - tokensCount: Math.ceil(input.length / 4), - }; - } - - protected async _generate( - input: LLMInput, - options: Partial, - run: GetRunContext, - ): Promise { - // this method should do non-stream request to the API - // TIP: access inference parameters via `this.input.parameters` and `options` - // TIP: use signal from run.signal - const result: CustomLLMChunk = { - text: "...", - metadata: {}, - }; - return new CustomLLMOutput(result); - } - - protected async *_stream( - input: LLMInput, - options: Partial, - run: GetRunContext, - ): AsyncStream { - // this method should do stream request to the API - // TIP: access inference parameters via `this.input.parameters` and `options` - // TIP: use signal from run.signal - for await (const chunk of ["Hel", "oo", "world", "!"]) { - const result: CustomLLMChunk = { - text: chunk, - metadata: {}, - }; - yield new CustomLLMOutput(result); - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - input: shallowCopy(this.input), - }; - } - - loadSnapshot({ input, ...snapshot }: ReturnType) { - super.loadSnapshot(snapshot); - Object.assign(this, { input }); - } -} diff --git a/examples/llms/providers/groq.ts b/examples/llms/providers/groq.ts deleted file mode 100644 index 5edec49b..00000000 --- a/examples/llms/providers/groq.ts +++ /dev/null @@ -1,21 +0,0 @@ -import "dotenv/config"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; - -const llm = new GroqChatLLM({ - modelId: "gemma2-9b-it", - parameters: { - temperature: 0.7, - max_tokens: 1024, - top_p: 1, - }, -}); - -console.info("Meta", await llm.meta()); -const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), -]); -console.info(response.getTextContent()); diff --git a/examples/llms/providers/ibm-vllm.ts b/examples/llms/providers/ibm-vllm.ts deleted file mode 100644 index 50480c63..00000000 --- a/examples/llms/providers/ibm-vllm.ts +++ /dev/null @@ -1,44 +0,0 @@ -import "dotenv/config.js"; -import { IBMvLLM } from "bee-agent-framework/adapters/ibm-vllm/llm"; -import { IBMVllmChatLLM } from "bee-agent-framework/adapters/ibm-vllm/chat"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { Client } from "bee-agent-framework/adapters/ibm-vllm/client"; - -const client = new Client(); -{ - console.info("===RAW==="); - const llm = new IBMvLLM({ - client, - modelId: "meta-llama/llama-3-1-70b-instruct", - }); - - console.info("Meta", await llm.meta()); - - const response = await llm.generate("Hello world!", { - stream: false, - }); - console.info(response.text); -} - -{ - console.info("===CHAT==="); - const llm = IBMVllmChatLLM.fromPreset("meta-llama/llama-3-1-70b-instruct", { client }); - - console.info("Meta", await llm.meta()); - - const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), - ]); - console.info(response.messages); -} - -{ - console.info("===EMBEDDING==="); - const llm = new IBMvLLM({ client, modelId: "baai/bge-large-en-v1.5" }); - - const response = await llm.embed([`Hello world!`, `Hello family!`]); - console.info(response); -} diff --git a/examples/llms/providers/ollama.ts b/examples/llms/providers/ollama.ts deleted file mode 100644 index ec7232ee..00000000 --- a/examples/llms/providers/ollama.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { OllamaLLM } from "bee-agent-framework/adapters/ollama/llm"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { Ollama } from "ollama"; - -{ - console.info("===RAW==="); - const llm = new OllamaLLM({ - modelId: "llama3.1", - parameters: { - num_predict: 10, - stop: ["post"], - }, - }); - - console.info("Meta", await llm.meta()); - - const response = await llm.generate("Hello world!", { - stream: true, - }); - console.info(response.finalResult); -} - -{ - console.info("===CHAT==="); - const llm = new OllamaChatLLM({ - modelId: "llama3.1", - parameters: { - num_predict: 10, - temperature: 0, - }, - }); - - console.info("Meta", await llm.meta()); - - const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), - ]); - console.info(response.finalResult); -} - -{ - console.info("===REMOTE OLLAMA==="); - const llm = new OllamaChatLLM({ - modelId: "llama3.1", - client: new Ollama({ - // use the IP for the server you have ollama running on - host: process.env.OLLAMA_HOST || "http://127.0.0.1:11434", - }), - }); - - console.info("Meta", await llm.meta()); - - const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), - ]); - console.info(response.finalResult); -} diff --git a/examples/llms/providers/openai.ts b/examples/llms/providers/openai.ts deleted file mode 100644 index b56d0459..00000000 --- a/examples/llms/providers/openai.ts +++ /dev/null @@ -1,20 +0,0 @@ -import "dotenv/config"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { OpenAIChatLLM } from "bee-agent-framework/adapters/openai/chat"; - -const llm = new OpenAIChatLLM({ - modelId: "gpt-4o", - parameters: { - max_tokens: 10, - stop: ["post"], - }, -}); - -console.info("Meta", await llm.meta()); -const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), -]); -console.info(response.getTextContent()); diff --git a/examples/llms/providers/vertexai.ts b/examples/llms/providers/vertexai.ts deleted file mode 100644 index 8080bf6a..00000000 --- a/examples/llms/providers/vertexai.ts +++ /dev/null @@ -1,47 +0,0 @@ -import "dotenv/config.js"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { VertexAILLM } from "bee-agent-framework/adapters/vertexai/llm"; -import { VertexAIChatLLM } from "bee-agent-framework/adapters/vertexai/chat"; - -const project = process.env.GCP_VERTEXAI_PROJECT; -const location = process.env.GCP_VERTEXAI_LOCATION; - -if (!project || !location) { - throw new Error("No ENVs has been set!"); -} - -{ - console.info("===RAW==="); - const llm = new VertexAILLM({ - modelId: "gemini-1.5-flash-001", - project, - location, - parameters: {}, - }); - - console.info("Meta", await llm.meta()); - - const response = await llm.generate("Hello world!", { - stream: true, - }); - console.info(response.getTextContent()); -} - -{ - console.info("===CHAT==="); - const llm = new VertexAIChatLLM({ - modelId: "gemini-1.5-flash-001", - project, - location, - }); - - console.info("Meta", await llm.meta()); - - const response = await llm.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), - ]); - console.info(response.getTextContent()); -} diff --git a/examples/llms/providers/watsonx.ts b/examples/llms/providers/watsonx.ts deleted file mode 100644 index b390b340..00000000 --- a/examples/llms/providers/watsonx.ts +++ /dev/null @@ -1,23 +0,0 @@ -import "dotenv/config"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; - -const chatLLM = WatsonXChatLLM.fromPreset("meta-llama/llama-3-1-70b-instruct", { - apiKey: process.env.WATSONX_API_KEY, - projectId: process.env.WATSONX_PROJECT_ID, - region: process.env.WATSONX_REGION, // (optional) default is us-south - parameters: { - decoding_method: "greedy", - max_new_tokens: 50, - }, -}); - -console.info("Meta", await chatLLM.meta()); - -const response = await chatLLM.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), -]); -console.info(response.messages[0]); diff --git a/examples/llms/providers/watsonx_debug.ts b/examples/llms/providers/watsonx_debug.ts deleted file mode 100644 index f4989883..00000000 --- a/examples/llms/providers/watsonx_debug.ts +++ /dev/null @@ -1,47 +0,0 @@ -import "dotenv/config"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; - -const chatLLM = WatsonXChatLLM.fromPreset("meta-llama/llama-3-1-70b-instruct", { - apiKey: process.env.WATSONX_API_KEY, - projectId: process.env.WATSONX_PROJECT_ID, - region: process.env.WATSONX_REGION, // (optional) default is us-south - parameters: { - decoding_method: "greedy", - max_new_tokens: 50, - }, -}); - -// Log every request -chatLLM.llm.client.emitter.match("*", async (data, event) => { - console.info( - `Time: ${event.createdAt.toISOString().substring(11, 19)}`, - `Event: ${event.name}`, - `Data: ${JSON.stringify(data).substring(0, 128).concat("...")}`, - ); -}); - -chatLLM.llm.client.emitter.on("fetchStart", async (data, event) => { - console.info(`Fetching ${data.input.url}`); - // You can also change the 'data' object -}); - -chatLLM.llm.client.emitter.on("streamStart", async (data, event) => { - console.info(`Streaming ${data.input.url}`); - // You can also change the 'data' object -}); - -console.info("Meta", await chatLLM.meta()); - -const response = await chatLLM.generate( - [ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), - ], - { - stream: true, - }, -); -console.info(response.messages[0]); diff --git a/examples/llms/providers/watsonx_verbose.ts b/examples/llms/providers/watsonx_verbose.ts deleted file mode 100644 index 95654059..00000000 --- a/examples/llms/providers/watsonx_verbose.ts +++ /dev/null @@ -1,59 +0,0 @@ -import "dotenv/config"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; -import { WatsonXLLM } from "bee-agent-framework/adapters/watsonx/llm"; -import { PromptTemplate } from "bee-agent-framework/template"; -import { z } from "zod"; - -const template = new PromptTemplate({ - schema: z.object({ - messages: z.array(z.record(z.array(z.string()))), - }), - template: `{{#messages}}{{#system}}<|begin_of_text|><|start_header_id|>system<|end_header_id|> - -{{system}}<|eot_id|>{{/system}}{{#user}}<|start_header_id|>user<|end_header_id|> - -{{user}}<|eot_id|>{{/user}}{{#assistant}}<|start_header_id|>assistant<|end_header_id|> - -{{assistant}}<|eot_id|>{{/assistant}}{{#ipython}}<|start_header_id|>ipython<|end_header_id|> - -{{ipython}}<|eot_id|>{{/ipython}}{{/messages}}<|start_header_id|>assistant<|end_header_id|> -`, -}); - -const llm = new WatsonXLLM({ - modelId: "meta-llama/llama-3-1-70b-instruct", - projectId: process.env.WATSONX_PROJECT_ID, - apiKey: process.env.WATSONX_API_KEY, - region: process.env.WATSONX_REGION, // (optional) default is us-south - parameters: { - decoding_method: "greedy", - max_new_tokens: 50, - }, -}); - -const chatLLM = new WatsonXChatLLM({ - llm, - config: { - messagesToPrompt(messages: BaseMessage[]) { - return template.render({ - messages: messages.map((message) => ({ - system: message.role === "system" ? [message.text] : [], - user: message.role === "user" ? [message.text] : [], - assistant: message.role === "assistant" ? [message.text] : [], - ipython: message.role === "ipython" ? [message.text] : [], - })), - }); - }, - }, -}); - -console.info("Meta", await chatLLM.meta()); - -const response = await chatLLM.generate([ - BaseMessage.of({ - role: "user", - text: "Hello world!", - }), -]); -console.info(response.messages[0]); diff --git a/examples/llms/structured.ts b/examples/llms/structured.ts deleted file mode 100644 index 5292a5fd..00000000 --- a/examples/llms/structured.ts +++ /dev/null @@ -1,29 +0,0 @@ -import "dotenv/config.js"; -import { z } from "zod"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; - -const llm = new OllamaChatLLM(); -const driver = new JsonDriver(llm); -const response = await driver.generate( - z.union([ - z.object({ - firstName: z.string().min(1), - lastName: z.string().min(1), - address: z.string(), - age: z.number().int().min(1), - hobby: z.string(), - }), - z.object({ - error: z.string(), - }), - ]), - [ - BaseMessage.of({ - role: Role.USER, - text: "Generate a profile of a citizen of Europe.", - }), - ], -); -console.info(response); diff --git a/examples/llms/text.ts b/examples/llms/text.ts deleted file mode 100644 index ccf1654e..00000000 --- a/examples/llms/text.ts +++ /dev/null @@ -1,20 +0,0 @@ -import "dotenv/config.js"; -import { createConsoleReader } from "examples/helpers/io.js"; -import { WatsonXLLM } from "bee-agent-framework/adapters/watsonx/llm"; - -const llm = new WatsonXLLM({ - modelId: "google/flan-ul2", - projectId: process.env.WATSONX_PROJECT_ID, - apiKey: process.env.WATSONX_API_KEY, - region: process.env.WATSONX_REGION, // (optional) default is us-south - parameters: { - decoding_method: "greedy", - max_new_tokens: 50, - }, -}); - -const reader = createConsoleReader(); -const prompt = await reader.prompt(); -const response = await llm.generate(prompt); -reader.write(`LLM πŸ€– (text) : `, response.getTextContent()); -reader.close(); diff --git a/examples/logger/agent.ts b/examples/logger/agent.ts index 76b1ff76..7cce8dca 100644 --- a/examples/logger/agent.ts +++ b/examples/logger/agent.ts @@ -1,8 +1,8 @@ import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { Logger } from "bee-agent-framework/logger/logger"; import { Emitter } from "bee-agent-framework/emitter/emitter"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; // Set up logging Logger.defaults.pretty = true; @@ -15,12 +15,12 @@ const logger = Logger.root.child({ // Log events emitted during agent execution Emitter.root.match("*.*", (data, event) => { const logLevel = event.path.includes(".run.") ? "trace" : "info"; - logger[logLevel](`Event '${event.path}' triggered by '${event.creator.constructor.name}'.`); + logger[logLevel](`Event '${event.path}' triggered by '${event.creator.constructor.name}'`); }); // Create and run an agent const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools: [], }); diff --git a/examples/memory/agentMemory.ts b/examples/memory/agentMemory.ts index 49bc8813..a6e17ca4 100644 --- a/examples/memory/agentMemory.ts +++ b/examples/memory/agentMemory.ts @@ -1,10 +1,10 @@ import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const agent = new BeeAgent({ memory: new UnconstrainedMemory(), - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), tools: [], }); await agent.run({ prompt: "Hello world!" }); diff --git a/examples/memory/base.ts b/examples/memory/base.ts index d181f735..a3c98fc9 100644 --- a/examples/memory/base.ts +++ b/examples/memory/base.ts @@ -1,21 +1,13 @@ import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { AssistantMessage, SystemMessage, UserMessage } from "bee-agent-framework/backend/message"; const memory = new UnconstrainedMemory(); // Single message -await memory.add( - BaseMessage.of({ - role: "system", - text: `You are a helpful assistant.`, - }), -); +await memory.add(new SystemMessage(`You are a helpful assistant.`)); // Multiple messages -await memory.addMany([ - BaseMessage.of({ role: "user", text: `What can you do?` }), - BaseMessage.of({ role: "assistant", text: `Everything!` }), -]); +await memory.addMany([new UserMessage(`What can you do?`), new AssistantMessage(`Everything!`)]); console.info(memory.isEmpty()); // false console.info(memory.messages); // prints all saved messages diff --git a/examples/memory/custom.ts b/examples/memory/custom.ts index 5c443375..b0bafdbf 100644 --- a/examples/memory/custom.ts +++ b/examples/memory/custom.ts @@ -1,17 +1,17 @@ import { BaseMemory } from "bee-agent-framework/memory/base"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; import { NotImplementedError } from "bee-agent-framework/errors"; export class MyMemory extends BaseMemory { - get messages(): readonly BaseMessage[] { + get messages(): readonly Message[] { throw new NotImplementedError("Method not implemented."); } - add(message: BaseMessage, index?: number): Promise { + add(message: Message, index?: number): Promise { throw new NotImplementedError("Method not implemented."); } - delete(message: BaseMessage): Promise { + delete(message: Message): Promise { throw new NotImplementedError("Method not implemented."); } diff --git a/examples/memory/llmMemory.ts b/examples/memory/llmMemory.ts index 9282aec3..7e767ee8 100644 --- a/examples/memory/llmMemory.ts +++ b/examples/memory/llmMemory.ts @@ -1,20 +1,20 @@ -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const memory = new UnconstrainedMemory(); await memory.addMany([ - BaseMessage.of({ + Message.of({ role: "system", text: `Always respond very concisely.`, }), - BaseMessage.of({ role: "user", text: `Give me first 5 prime numbers.` }), + Message.of({ role: "user", text: `Give me first 5 prime numbers.` }), ]); // Generate response -const llm = new OllamaChatLLM(); -const response = await llm.generate(memory.messages); -await memory.add(BaseMessage.of({ role: "assistant", text: response.getTextContent() })); +const llm = new OllamaChatModel("llama3.1"); +const response = await llm.create({ messages: memory.messages }); +await memory.add(Message.of({ role: "assistant", text: response.getTextContent() })); console.log(`Conversation history`); for (const message of memory) { diff --git a/examples/memory/slidingMemory.ts b/examples/memory/slidingMemory.ts index ada69718..43a0a261 100644 --- a/examples/memory/slidingMemory.ts +++ b/examples/memory/slidingMemory.ts @@ -1,5 +1,5 @@ import { SlidingMemory } from "bee-agent-framework/memory/slidingMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; const memory = new SlidingMemory({ size: 3, // (required) number of messages that can be in the memory at a single moment @@ -10,11 +10,11 @@ const memory = new SlidingMemory({ }, }); -await memory.add(BaseMessage.of({ role: "system", text: "You are a guide through France." })); -await memory.add(BaseMessage.of({ role: "user", text: "What is the capital?" })); -await memory.add(BaseMessage.of({ role: "assistant", text: "Paris" })); -await memory.add(BaseMessage.of({ role: "user", text: "What language is spoken there?" })); // removes the first user's message -await memory.add(BaseMessage.of({ role: "assistant", text: "French" })); // removes the first assistant's message +await memory.add(Message.of({ role: "system", text: "You are a guide through France." })); +await memory.add(Message.of({ role: "user", text: "What is the capital?" })); +await memory.add(Message.of({ role: "assistant", text: "Paris" })); +await memory.add(Message.of({ role: "user", text: "What language is spoken there?" })); // removes the first user's message +await memory.add(Message.of({ role: "assistant", text: "French" })); // removes the first assistant's message console.info(memory.isEmpty()); // false console.log(memory.messages.length); // 3 diff --git a/examples/memory/summarizeMemory.ts b/examples/memory/summarizeMemory.ts index c823d72d..ae8d37c0 100644 --- a/examples/memory/summarizeMemory.ts +++ b/examples/memory/summarizeMemory.ts @@ -1,22 +1,16 @@ -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; import { SummarizeMemory } from "bee-agent-framework/memory/summarizeMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const memory = new SummarizeMemory({ - llm: new OllamaChatLLM({ - modelId: "llama3.1", - parameters: { - temperature: 0, - num_predict: 250, - }, - }), + llm: new OllamaChatModel("llama3.1"), }); await memory.addMany([ - BaseMessage.of({ role: "system", text: "You are a guide through France." }), - BaseMessage.of({ role: "user", text: "What is the capital?" }), - BaseMessage.of({ role: "assistant", text: "Paris" }), - BaseMessage.of({ role: "user", text: "What language is spoken there?" }), + Message.of({ role: "system", text: "You are a guide through France." }), + Message.of({ role: "user", text: "What is the capital?" }), + Message.of({ role: "assistant", text: "Paris" }), + Message.of({ role: "user", text: "What language is spoken there?" }), ]); console.info(memory.isEmpty()); // false diff --git a/examples/memory/tokenMemory.ts b/examples/memory/tokenMemory.ts index c02ff4cf..1ede1114 100644 --- a/examples/memory/tokenMemory.ts +++ b/examples/memory/tokenMemory.ts @@ -1,11 +1,8 @@ import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { Message } from "bee-agent-framework/backend/message"; -const llm = new OllamaChatLLM(); const memory = new TokenMemory({ - llm, - maxTokens: undefined, // optional (default is inferred from the passed LLM instance), + maxTokens: undefined, // optional (default is 128k), capacityThreshold: 0.75, // maxTokens*capacityThreshold = threshold where we start removing old messages syncThreshold: 0.25, // maxTokens*syncThreshold = threshold where we start to use a real tokenization endpoint instead of guessing the number of tokens handlers: { @@ -17,8 +14,8 @@ const memory = new TokenMemory({ }, }); -await memory.add(BaseMessage.of({ role: "system", text: "You are a helpful assistant." })); -await memory.add(BaseMessage.of({ role: "user", text: "Hello world!" })); +await memory.add(Message.of({ role: "system", text: "You are a helpful assistant." })); +await memory.add(Message.of({ role: "user", text: "Hello world!" })); console.info(memory.isDirty); // is the consumed token count estimated or retrieved via the tokenize endpoint? console.log(memory.tokensUsed); // number of used tokens diff --git a/examples/memory/unconstrainedMemory.ts b/examples/memory/unconstrainedMemory.ts index aa5f6ee0..21dee55c 100644 --- a/examples/memory/unconstrainedMemory.ts +++ b/examples/memory/unconstrainedMemory.ts @@ -1,9 +1,9 @@ import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; const memory = new UnconstrainedMemory(); await memory.add( - BaseMessage.of({ + Message.of({ role: "user", text: `Hello world!`, }), diff --git a/examples/serialization/base.ts b/examples/serialization/base.ts index e0ae9046..0258301a 100644 --- a/examples/serialization/base.ts +++ b/examples/serialization/base.ts @@ -1,8 +1,8 @@ import { Serializer } from "bee-agent-framework/serializer/serializer"; const original = new Date("2024-01-01T00:00:00.000Z"); -const serialized = Serializer.serialize(original); -const deserialized = Serializer.deserialize(serialized); +const serialized = await Serializer.serialize(original); +const deserialized = await Serializer.deserialize(serialized); console.info(deserialized instanceof Date); // true console.info(original.toISOString() === deserialized.toISOString()); // true diff --git a/examples/serialization/context.ts b/examples/serialization/context.ts index 77580cf5..5b1f8f64 100644 --- a/examples/serialization/context.ts +++ b/examples/serialization/context.ts @@ -1,12 +1,12 @@ import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { UserMessage } from "bee-agent-framework/backend/message"; // String containing serialized `UnconstrainedMemory` instance with one message in it. -const serialized = `{"__version":"0.0.0","__root":{"__serializer":true,"__class":"Object","__ref":"5","__value":{"target":"UnconstrainedMemory","snapshot":{"__serializer":true,"__class":"Object","__ref":"4","__value":{"messages":{"__serializer":true,"__class":"Array","__ref":"1","__value":[{"__serializer":true,"__class":"BaseMessage","__ref":"2","__value":{"role":"user","text":"Serialization is amazing, isn't?","meta":{"__serializer":true,"__class":"Undefined","__ref":"3"}}}]}}}}}}`; +const serialized = `{"__version":"0.0.0","__root":{"__serializer":true,"__class":"Object","__ref":"18","__value":{"target":"UnconstrainedMemory","snapshot":{"__serializer":true,"__class":"Object","__ref":"17","__value":{"messages":{"__serializer":true,"__class":"Array","__ref":"1","__value":[{"__serializer":true,"__class":"SystemMessage","__ref":"2","__value":{"content":{"__serializer":true,"__class":"Array","__ref":"3","__value":[{"__serializer":true,"__class":"Object","__ref":"4","__value":{"type":"text","text":"You are a helpful assistant."}}]},"meta":{"__serializer":true,"__class":"Object","__ref":"5","__value":{"createdAt":{"__serializer":true,"__class":"Date","__ref":"6","__value":"2025-02-06T14:51:01.459Z"}}},"role":"system"}},{"__serializer":true,"__class":"UserMessage","__ref":"7","__value":{"content":{"__serializer":true,"__class":"Array","__ref":"8","__value":[{"__serializer":true,"__class":"Object","__ref":"9","__value":{"type":"text","text":"Hello!"}}]},"meta":{"__serializer":true,"__class":"Object","__ref":"10","__value":{"createdAt":{"__serializer":true,"__class":"Date","__ref":"11","__value":"2025-02-06T14:51:01.459Z"}}},"role":"user"}},{"__serializer":true,"__class":"AssistantMessage","__ref":"12","__value":{"content":{"__serializer":true,"__class":"Array","__ref":"13","__value":[{"__serializer":true,"__class":"Object","__ref":"14","__value":{"type":"text","text":"Hello, how can I help you?"}}]},"meta":{"__serializer":true,"__class":"Object","__ref":"15","__value":{"createdAt":{"__serializer":true,"__class":"Date","__ref":"16","__value":"2025-02-06T14:51:01.459Z"}}},"role":"assistant"}}]}}}}}}`; -// If `BaseMessage` was not imported the serialization would fail because the `BaseMessage` had no chance to register itself. -const memory = UnconstrainedMemory.fromSerialized(serialized, { +// If `Message` was not imported the serialization would fail because the `Message` had no chance to register itself. +const memory = await UnconstrainedMemory.fromSerialized(serialized, { // this part can be omitted if all classes used in the serialized string are imported (and have `static` register block) or at least one initiated - extraClasses: [BaseMessage], + extraClasses: [UserMessage], }); console.info(memory.messages); diff --git a/examples/serialization/customExternal.ts b/examples/serialization/customExternal.ts index 35f534f3..a6b3d342 100644 --- a/examples/serialization/customExternal.ts +++ b/examples/serialization/customExternal.ts @@ -18,8 +18,8 @@ Serializer.register(MyClass, { }); const instance = new MyClass("Bee"); -const serialized = Serializer.serialize(instance); -const deserialized = Serializer.deserialize(serialized); +const serialized = await Serializer.serialize(instance); +const deserialized = await Serializer.deserialize(serialized); console.info(instance); console.info(deserialized); diff --git a/examples/serialization/customInternal.ts b/examples/serialization/customInternal.ts index 66dcdeea..902a3ac5 100644 --- a/examples/serialization/customInternal.ts +++ b/examples/serialization/customInternal.ts @@ -22,8 +22,8 @@ class MyClass extends Serializable { } const instance = new MyClass("Bee"); -const serialized = instance.serialize(); -const deserialized = MyClass.fromSerialized(serialized); +const serialized = await instance.serialize(); +const deserialized = await MyClass.fromSerialized(serialized); console.info(instance); console.info(deserialized); diff --git a/examples/serialization/memory.ts b/examples/serialization/memory.ts index 2f7de42f..ad336d33 100644 --- a/examples/serialization/memory.ts +++ b/examples/serialization/memory.ts @@ -1,22 +1,10 @@ import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { AssistantMessage, UserMessage } from "bee-agent-framework/backend/message"; -const llm = new OllamaChatLLM(); -const memory = new TokenMemory({ llm }); -await memory.addMany([ - BaseMessage.of({ - role: "user", - text: "What is your name?", - }), -]); +const memory = new TokenMemory(); +await memory.add(new UserMessage("What is your name?")); -const serialized = memory.serialize(); -const deserialized = TokenMemory.fromSerialized(serialized); +const serialized = await memory.serialize(); +const deserialized = await TokenMemory.fromSerialized(serialized); -await deserialized.add( - BaseMessage.of({ - role: "assistant", - text: "Bee", - }), -); +await deserialized.add(new AssistantMessage("Bee")); diff --git a/examples/tools/agent.ts b/examples/tools/agent.ts index 97923428..da508904 100644 --- a/examples/tools/agent.ts +++ b/examples/tools/agent.ts @@ -1,10 +1,10 @@ -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { ArXivTool } from "bee-agent-framework/tools/arxiv"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools: [new ArXivTool()], }); diff --git a/examples/tools/llm.ts b/examples/tools/llm.ts index d27121f5..d9fb4e9b 100644 --- a/examples/tools/llm.ts +++ b/examples/tools/llm.ts @@ -1,19 +1,19 @@ import "dotenv/config"; import { LLMTool } from "bee-agent-framework/tools/llm"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { Tool } from "bee-agent-framework/tools/base"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; +import { Message } from "bee-agent-framework/backend/message"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; const memory = new UnconstrainedMemory(); await memory.addMany([ - BaseMessage.of({ role: "system", text: "You are a helpful assistant." }), - BaseMessage.of({ role: "user", text: "Hello!" }), - BaseMessage.of({ role: "assistant", text: "Hello user. I am here to help you." }), + Message.of({ role: "system", text: "You are a helpful assistant." }), + Message.of({ role: "user", text: "Hello!" }), + Message.of({ role: "assistant", text: "Hello user. I am here to help you." }), ]); const tool = new LLMTool({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), }); const response = await tool diff --git a/examples/tools/mcp.ts b/examples/tools/mcp.ts index f2208b81..41563e27 100644 --- a/examples/tools/mcp.ts +++ b/examples/tools/mcp.ts @@ -3,7 +3,7 @@ import { MCPTool } from "bee-agent-framework/tools/mcp"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; // Create MCP Client const client = new Client( @@ -28,7 +28,7 @@ try { // Server usually supports several tools, use the factory for automatic discovery const tools = await MCPTool.fromClient(client); const agent = new BeeAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), tools, }); diff --git a/examples/tools/openapi.ts b/examples/tools/openapi.ts index 35beebe4..beb29fdb 100644 --- a/examples/tools/openapi.ts +++ b/examples/tools/openapi.ts @@ -1,15 +1,13 @@ import "dotenv/config.js"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { TokenMemory } from "bee-agent-framework/memory/tokenMemory"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { OpenAPITool } from "bee-agent-framework/tools/openapi"; import * as fs from "fs"; import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; +import { ChatModel } from "bee-agent-framework/backend/chat"; -const llm = new OllamaChatLLM({ - modelId: "llama3.1", // llama3.1:70b for better performance -}); +const llm = await ChatModel.fromName("ollama:llama3.1"); const __dirname = dirname(fileURLToPath(import.meta.url)); const openApiSchema = await fs.promises.readFile( @@ -19,7 +17,7 @@ const openApiSchema = await fs.promises.readFile( const agent = new BeeAgent({ llm, - memory: new TokenMemory({ llm }), + memory: new TokenMemory(), tools: [new OpenAPITool({ openApiSchema })], }); diff --git a/examples/workflows/agent.ts b/examples/workflows/agent.ts index 8aaed823..211f3812 100644 --- a/examples/workflows/agent.ts +++ b/examples/workflows/agent.ts @@ -1,25 +1,24 @@ import "dotenv/config"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { z } from "zod"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; +import { Message, UserMessage } from "bee-agent-framework/backend/message"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { ReadOnlyMemory } from "bee-agent-framework/memory/base"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { Workflow } from "bee-agent-framework/experimental/workflows/workflow"; import { createConsoleReader } from "examples/helpers/io.js"; -import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; +import { GroqChatModel } from "bee-agent-framework/adapters/groq/backend/chat"; const schema = z.object({ - answer: z.instanceof(BaseMessage).optional(), + answer: z.instanceof(Message).optional(), memory: z.instanceof(ReadOnlyMemory), }); const workflow = new Workflow({ schema: schema }) .addStep("simpleAgent", async (state) => { const simpleAgent = new BeeAgent({ - llm: new GroqChatLLM(), + llm: new GroqChatModel("llama-3.3-70b-versatile"), tools: [], memory: state.memory, }); @@ -32,18 +31,18 @@ const workflow = new Workflow({ schema: schema }) }; }) .addStrictStep("critique", schema.required(), async (state) => { - const llm = new GroqChatLLM(); - const { parsed: critiqueResponse } = await new JsonDriver(llm).generate( - z.object({ score: z.number().int().min(0).max(100) }), - [ - BaseMessage.of({ + const llm = new GroqChatModel("llama-3.3-70b-versatile"); + const { object: critiqueResponse } = await llm.createStructure({ + schema: z.object({ score: z.number().int().min(0).max(100) }), + messages: [ + Message.of({ role: "system", text: `You are an evaluation assistant who scores the credibility of the last assistant's response. Chitchatting always has a score of 100. If the assistant was unable to answer the user's query, then the score will be 0.`, }), ...state.memory.messages, state.answer, ], - ); + }); reader.write("🧠 Score", critiqueResponse.score.toString()); return { @@ -52,7 +51,7 @@ const workflow = new Workflow({ schema: schema }) }) .addStep("complexAgent", async (state) => { const complexAgent = new BeeAgent({ - llm: new GroqChatLLM(), + llm: new GroqChatModel("llama-3.3-70b-versatile"), tools: [new WikipediaTool(), new OpenMeteoTool()], memory: state.memory, }); @@ -66,11 +65,7 @@ const reader = createConsoleReader(); const memory = new UnconstrainedMemory(); for await (const { prompt } of reader) { - const userMessage = BaseMessage.of({ - role: Role.USER, - text: prompt, - meta: { createdAt: new Date() }, - }); + const userMessage = new UserMessage(prompt); await memory.add(userMessage); const response = await workflow.run({ diff --git a/examples/workflows/competitive-analysis/prompts.ts b/examples/workflows/competitive-analysis/prompts.ts index 882e801d..cdbbd96e 100644 --- a/examples/workflows/competitive-analysis/prompts.ts +++ b/examples/workflows/competitive-analysis/prompts.ts @@ -45,13 +45,7 @@ Key Analysis Points: - Market positioning - Potential impact -Provide concise, actionable insights about the competitor. - -Return JSON with: -{ - "key_insights": ["Critical findings"], - "unique_capabilities": ["Standout features"] -}`, +Provide concise, actionable insights about the competitor.`, }); export const reflectionSchema = z.object({ diff --git a/examples/workflows/competitive-analysis/state.ts b/examples/workflows/competitive-analysis/state.ts index 66f1e3a3..f002a628 100644 --- a/examples/workflows/competitive-analysis/state.ts +++ b/examples/workflows/competitive-analysis/state.ts @@ -1,5 +1,5 @@ -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; import { z } from "zod"; +import { Message } from "bee-agent-framework/backend/message"; export const InputSchema = z.object({ industry: z.string(), @@ -17,7 +17,7 @@ export const StateSchema = z.object({ competitorFindings: z.record(z.string(), z.array(z.string())).default({}), researchLoopCount: z.number().default(0), runningSummary: z.string().optional(), - answer: z.instanceof(BaseMessage).optional(), + answer: z.instanceof(Message).optional(), reflectionFeedback: z.array(z.string()).optional(), reflectionIteration: z.number().default(0), maxReflectionIterations: z.number().default(3), diff --git a/examples/workflows/competitive-analysis/utils.ts b/examples/workflows/competitive-analysis/utils.ts index 5a886291..5ec948b7 100644 --- a/examples/workflows/competitive-analysis/utils.ts +++ b/examples/workflows/competitive-analysis/utils.ts @@ -1,21 +1,12 @@ import { TavilySearchResults } from "@langchain/community/tools/tavily_search"; -import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat"; import { getEnv } from "bee-agent-framework/internals/env"; import "dotenv/config"; -import { Ollama } from "ollama"; import { State } from "./state.js"; import { Steps } from "./workflow.js"; +import { OllamaChatModel } from "bee-agent-framework/adapters/ollama/backend/chat"; export function getChatLLM() { - return new OllamaChatLLM({ - modelId: getEnv("OLLAMA_MODEL") || "deepseek-r1:8b", - parameters: { - temperature: 0, - }, - client: new Ollama({ - host: getEnv("OLLAMA_HOST") || "http://0.0.0.0:11434", - }), - }); + return new OllamaChatModel(getEnv("OLLAMA_CHAT_MODEL") || "deepseek-r1:8b"); } export interface SearchResult { diff --git a/examples/workflows/competitive-analysis/workflow.ts b/examples/workflows/competitive-analysis/workflow.ts index 37928798..74f839da 100644 --- a/examples/workflows/competitive-analysis/workflow.ts +++ b/examples/workflows/competitive-analysis/workflow.ts @@ -1,6 +1,4 @@ import { Workflow } from "bee-agent-framework/experimental/workflows/workflow"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; import { categorizationPromptTemplate, competitorsPromptTemplate, @@ -12,6 +10,7 @@ import { import { State, StateSchema } from "./state.js"; import { deduplicateAndFormatSources, formatSources, getChatLLM, tavilySearch } from "./utils.js"; import { isEmpty, mapValues } from "remeda"; +import { AssistantMessage, SystemMessage } from "bee-agent-framework/backend/message"; export enum Steps { GENERATE_COMPETITORS = "GENERATE_COMPETITORS", @@ -34,21 +33,22 @@ async function generateCompetitors(state: State) { } const llm = getChatLLM(); - const llmJsonMode = new JsonDriver(llm); - const result = await llmJsonMode.generate(competitorsSchema, [ - BaseMessage.of({ - role: Role.SYSTEM, - text: competitorsPromptTemplate.render({ - industry: state.industry, - specifiedCompetitors: undefined, - }), - }), - ]); + const result = await llm.createStructure({ + schema: competitorsSchema, + messages: [ + new SystemMessage( + competitorsPromptTemplate.render({ + industry: state.industry, + specifiedCompetitors: undefined, + }), + ), + ], + }); return { update: { - competitors: result.parsed.competitors, - runningSummary: result.parsed.overview, + competitors: result.object.competitors, + runningSummary: result.object.overview, competitorFindings: mapValues(state.competitors, () => []), }, }; @@ -98,22 +98,23 @@ async function categorizeFindings(state: State) { } const llm = getChatLLM(); - const llmJsonMode = new JsonDriver(llm); - const result = await llmJsonMode.generate(findingsSchema, [ - BaseMessage.of({ - role: Role.SYSTEM, - text: categorizationPromptTemplate.render({ - competitor: state.currentCompetitor, - searchResults: state.webResearchResults[state.webResearchResults.length - 1], - }), - }), - ]); + const result = await llm.createStructure({ + schema: findingsSchema, + messages: [ + new SystemMessage( + categorizationPromptTemplate.render({ + competitor: state.currentCompetitor, + searchResults: state.webResearchResults[state.webResearchResults.length - 1], + }), + ), + ], + }); const updatedFindings = { ...state.competitorFindings, [state.currentCompetitor]: [ - ...(result.parsed.key_insights || []), - ...(result.parsed.unique_capabilities || []), + ...(result.object.key_insights || []), + ...(result.object.unique_capabilities || []), ], }; @@ -142,7 +143,7 @@ ${competitorSections} ${state.sourcesGathered.join("\n")}`; return { - update: { answer: BaseMessage.of({ role: Role.ASSISTANT, text: finalSummary }) }, + update: { answer: new AssistantMessage(finalSummary) }, next: Steps.REFLECTION, }; } @@ -153,21 +154,21 @@ async function reflectAndImprove(state: State) { } const llm = getChatLLM(); - const llmJsonMode = new JsonDriver(llm); - - const result = await llmJsonMode.generate(reflectionSchema, [ - BaseMessage.of({ - role: Role.SYSTEM, - text: reflectionPromptTemplate.render({ - analysis: state.answer.text, - previous_feedback: state.reflectionFeedback, - }), - }), - ]); + const result = await llm.createStructure({ + schema: reflectionSchema, + messages: [ + new SystemMessage( + reflectionPromptTemplate.render({ + analysis: state.answer.text, + previous_feedback: state.reflectionFeedback, + }), + ), + ], + }); - const feedback = [...(result.parsed.critique || []), ...(result.parsed.suggestions || [])]; + const feedback = [...(result.object.critique || []), ...(result.object.suggestions || [])]; - if (result.parsed.should_iterate && state.reflectionIteration < state.maxReflectionIterations) { + if (result.object.should_iterate && state.reflectionIteration < state.maxReflectionIterations) { return { update: { reflectionFeedback: feedback, @@ -177,10 +178,9 @@ async function reflectAndImprove(state: State) { }; } - const finalAnalysis = BaseMessage.of({ - role: Role.ASSISTANT, - text: `${state.answer.text}\n\n## Reflection Notes\n${feedback.map((f) => `* ${f}`).join("\n")}`, - }); + const finalAnalysis = new AssistantMessage( + `${state.answer.text}\n\n## Reflection Notes\n${feedback.map((f) => `* ${f}`).join("\n")}`, + ); return { update: { answer: finalAnalysis }, diff --git a/examples/workflows/contentCreator.ts b/examples/workflows/contentCreator.ts index e25fa499..6958d3a4 100644 --- a/examples/workflows/contentCreator.ts +++ b/examples/workflows/contentCreator.ts @@ -4,12 +4,11 @@ import { Workflow } from "bee-agent-framework/experimental/workflows/workflow"; import { BeeAgent } from "bee-agent-framework/agents/bee/agent"; import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMemory"; import { createConsoleReader } from "examples/helpers/io.js"; -import { BaseMessage } from "bee-agent-framework/llms/primitives/message"; -import { JsonDriver } from "bee-agent-framework/llms/drivers/json"; +import { Message } from "bee-agent-framework/backend/message"; import { isEmpty, pick } from "remeda"; import { LLMTool } from "bee-agent-framework/tools/llm"; import { GoogleSearchTool } from "bee-agent-framework/tools/search/googleSearch"; -import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; +import { GroqChatModel } from "bee-agent-framework/adapters/groq/backend/chat"; const schema = z.object({ input: z.string(), @@ -26,19 +25,18 @@ const workflow = new Workflow({ outputSchema: schema.required({ output: true }), }) .addStep("preprocess", async (state) => { - const llm = new GroqChatLLM(); - const driver = new JsonDriver(llm); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); - const { parsed } = await driver.generate( - schema.pick({ topic: true, notes: true }).or( + const { object: parsed } = await llm.createStructure({ + schema: schema.pick({ topic: true, notes: true }).or( z.object({ error: z .string() .describe("Use when the input query does not make sense or you need clarification."), }), ), - [ - BaseMessage.of({ + messages: [ + Message.of({ role: `user`, text: [ "Your task is to rewrite the user query so that it guides the content planner and editor to craft a blog post that perfectly aligns with the user's needs. Notes should be used only if the user complains about something.", @@ -53,14 +51,14 @@ const workflow = new Workflow({ .join("\n"), }), ], - ); + }); return "error" in parsed ? { update: { output: parsed.error }, next: Workflow.END } : { update: pick(parsed, ["notes", "topic"]) }; }) .addStrictStep("planner", schema.required({ topic: true }), async (state) => { - const llm = new GroqChatLLM(); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); const agent = new BeeAgent({ llm, memory: new UnconstrainedMemory(), @@ -93,54 +91,58 @@ const workflow = new Workflow({ }; }) .addStrictStep("writer", schema.required({ plan: true }), async (state) => { - const llm = new GroqChatLLM(); - const output = await llm.generate([ - BaseMessage.of({ - role: `system`, - text: [ - `You are a Content Writer. Your task is to write a compelling blog post based on the provided context.`, - ``, - `# Context`, - `${state.plan}`, - ``, - `# Objectives`, - `- An engaging introduction`, - `- Insightful body paragraphs (2-3 per section)`, - `- Properly named sections/subtitles`, - `- A summarizing conclusion`, - `- Format: Markdown`, - ``, - ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], - `Ensure the content flows naturally, incorporates SEO keywords, and is well-structured.`, - ].join("\n"), - }), - ]); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); + const output = await llm.create({ + messages: [ + Message.of({ + role: `system`, + text: [ + `You are a Content Writer. Your task is to write a compelling blog post based on the provided context.`, + ``, + `# Context`, + `${state.plan}`, + ``, + `# Objectives`, + `- An engaging introduction`, + `- Insightful body paragraphs (2-3 per section)`, + `- Properly named sections/subtitles`, + `- A summarizing conclusion`, + `- Format: Markdown`, + ``, + ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], + `Ensure the content flows naturally, incorporates SEO keywords, and is well-structured.`, + ].join("\n"), + }), + ], + }); return { update: { draft: output.getTextContent() }, }; }) .addStrictStep("editor", schema.required({ draft: true }), async (state) => { - const llm = new GroqChatLLM(); - const output = await llm.generate([ - BaseMessage.of({ - role: `system`, - text: [ - `You are an Editor. Your task is to transform the following draft blog post to a final version.`, - ``, - `# Draft`, - `${state.draft}`, - ``, - `# Objectives`, - `- Fix Grammatical errors`, - `- Journalistic best practices`, - ``, - ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], - ``, - `IMPORTANT: The final version must not contain any editor's comments.`, - ].join("\n"), - }), - ]); + const llm = new GroqChatModel("llama-3.3-70b-versatile"); + const output = await llm.create({ + messages: [ + Message.of({ + role: `system`, + text: [ + `You are an Editor. Your task is to transform the following draft blog post to a final version.`, + ``, + `# Draft`, + `${state.draft}`, + ``, + `# Objectives`, + `- Fix Grammatical errors`, + `- Journalistic best practices`, + ``, + ...[!isEmpty(state.notes) && ["# Notes", ...state.notes, ""]], + ``, + `IMPORTANT: The final version must not contain any editor's comments.`, + ].join("\n"), + }), + ], + }); return { update: { output: output.getTextContent() }, diff --git a/examples/workflows/multiAgents.ts b/examples/workflows/multiAgents.ts index c38472cf..fd100cbd 100644 --- a/examples/workflows/multiAgents.ts +++ b/examples/workflows/multiAgents.ts @@ -4,14 +4,11 @@ import { createConsoleReader } from "examples/helpers/io.js"; import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { AgentWorkflow } from "bee-agent-framework/experimental/workflows/agent"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { WatsonXChatLLM } from "bee-agent-framework/adapters/watsonx/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { WatsonxChatModel } from "bee-agent-framework/adapters/watsonx/backend/chat"; const workflow = new AgentWorkflow(); -const llm = WatsonXChatLLM.fromPreset("meta-llama/llama-3-3-70b-instruct", { - apiKey: process.env.WATSONX_API_KEY, - projectId: process.env.WATSONX_PROJECT_ID, -}); +const llm = new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"); workflow.addAgent({ name: "WeatherForecaster", @@ -37,13 +34,7 @@ const reader = createConsoleReader(); const memory = new UnconstrainedMemory(); for await (const { prompt } of reader) { - await memory.add( - BaseMessage.of({ - role: Role.USER, - text: prompt, - meta: { createdAt: new Date() }, - }), - ); + await memory.add(new UserMessage(prompt, { createdAt: new Date() })); const { result } = await workflow.run(memory.messages).observe((emitter) => { emitter.on("success", (data) => { diff --git a/examples/workflows/multiAgentsSimple.ts b/examples/workflows/multiAgentsSimple.ts index fe090437..b05532bc 100644 --- a/examples/workflows/multiAgentsSimple.ts +++ b/examples/workflows/multiAgentsSimple.ts @@ -3,8 +3,8 @@ import { UnconstrainedMemory } from "bee-agent-framework/memory/unconstrainedMem import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo"; import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia"; import { AgentWorkflow } from "bee-agent-framework/experimental/workflows/agent"; -import { BaseMessage, Role } from "bee-agent-framework/llms/primitives/message"; -import { GroqChatLLM } from "bee-agent-framework/adapters/groq/chat"; +import { UserMessage } from "bee-agent-framework/backend/message"; +import { WatsonxChatModel } from "bee-agent-framework/adapters/watsonx/backend/chat"; const workflow = new AgentWorkflow(); @@ -12,14 +12,14 @@ workflow.addAgent({ name: "Researcher", instructions: "You are a researcher assistant. Respond only if you can provide a useful answer.", tools: [new WikipediaTool()], - llm: new GroqChatLLM(), + llm: new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"), }); workflow.addAgent({ name: "WeatherForecaster", instructions: "You are a weather assistant. Respond only if you can provide a useful answer.", tools: [new OpenMeteoTool()], - llm: new GroqChatLLM(), + llm: new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"), execution: { maxIterations: 3 }, }); @@ -27,16 +27,14 @@ workflow.addAgent({ name: "Solver", instructions: "Your task is to provide the most useful final answer based on the assistants' responses which all are relevant. Ignore those where assistant do not know.", - llm: new GroqChatLLM(), + llm: new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"), }); const memory = new UnconstrainedMemory(); await memory.add( - BaseMessage.of({ - role: Role.USER, - text: "What is the capital of France and what is the current weather there?", - meta: { createdAt: new Date() }, + new UserMessage("What is the capital of France and what is the current weather there?", { + createdAt: new Date(), }), ); diff --git a/package.json b/package.json index 9b08d51e..a2dadddb 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ }, "scripts": { "clean": "rimraf dist", - "build": "yarn clean && yarn ts:check && NODE_OPTIONS='--max-old-space-size=8192' tsup && cp -r src/adapters/ibm-vllm/proto dist/adapters/ibm-vllm", + "build": "yarn clean && yarn ts:check && NODE_OPTIONS='--max-old-space-size=8192' tsup", "ts:check": "tsc --noEmit && tsc -p tsconfig.examples.json --noEmit", "start": "tsx --tsconfig tsconfig.examples.json", "start:bee": "yarn start -- examples/agents/bee.ts", @@ -162,21 +162,19 @@ "copyright": "./scripts/copyright.sh", "copyright:check": "TYPE=check ./scripts/copyright.sh", "release": "release-it", - "ibm-vllm:generate-types": "./scripts/ibm_vllm_generate_protos/ibm_vllm_generate_protos.sh", "_ensure_env": "cp -n .env.template .env || true" }, "dependencies": { "@ai-zen/node-fetch-event-source": "^2.1.4", "@opentelemetry/api": "^1.9.0", "@streamparser/json": "^0.0.21", + "ai": "^4.1.24", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "duck-duck-scrape": "^2.2.7", "fast-xml-parser": "^4.5.0", "header-generator": "^2.1.57", "joplin-turndown-plugin-gfm": "^1.0.12", - "js-yaml": "^4.1.0", - "json-schema-to-typescript": "^15.0.3", "jsonrepair": "^3.11.1", "mathjs": "^14.0.0", "mustache": "^4.2.0", @@ -195,68 +193,60 @@ "zod-to-json-schema": "^3.23.5" }, "peerDependencies": { - "@aws-sdk/client-bedrock-runtime": "^3.687.0", + "@ai-sdk/amazon-bedrock": "^1.1.5", + "@ai-sdk/azure": "^1.1.2", + "@ai-sdk/google-vertex": "^2.1.6", + "@ai-sdk/groq": "^1.1.6", + "@ai-sdk/openai": "^1.1.2", + "@aws-sdk/client-bedrock-runtime": "^3.706.0", "@elastic/elasticsearch": "^8.0.0", - "@google-cloud/vertexai": "*", "@googleapis/customsearch": "^3.2.0", - "@grpc/grpc-js": "^1.11.3", - "@grpc/proto-loader": "^0.7.13", "@langchain/community": ">=0.2.28", "@langchain/core": ">=0.2.27", "@modelcontextprotocol/sdk": "^1.0.4", "@zilliz/milvus2-sdk-node": "^2.4.9", - "google-auth-library": "*", - "groq-sdk": "^0.7.0", - "ollama": "^0.5.11", - "openai": "^4.67.3", - "openai-chat-tokens": "^0.2.8", + "ollama-ai-provider": "^1.2.0", "sequelize": "^6.37.3", "yaml": "^2.6.1" }, "peerDependenciesMeta": { - "@aws-sdk/client-bedrock-runtime": { + "@ai-sdk/amazon-bedrock": { "optional": true }, - "@elastic/elasticsearch": { + "@ai-sdk/azure": { "optional": true }, - "@google-cloud/vertexai": { - "optional": true - }, - "@googleapis/customsearch": { + "@ai-sdk/google-vertex": { "optional": true }, - "@grpc/grpc-js": { + "@ai-sdk/groq": { "optional": true }, - "@grpc/proto-loader": { + "@ai-sdk/openai": { "optional": true }, - "@langchain/community": { - "optional": true - }, - "@langchain/core": { + "@elastic/elasticsearch": { "optional": true }, - "@modelcontextprotocol/sdk": { + "@googleapis/customsearch": { "optional": true }, - "@zilliz/milvus2-sdk-node": { + "@ibm-cloud/watsonx-ai": { "optional": true }, - "google-auth-library": { + "@langchain/community": { "optional": true }, - "groq-sdk": { + "@langchain/core": { "optional": true }, - "ollama": { + "@modelcontextprotocol/sdk": { "optional": true }, - "openai": { + "@zilliz/milvus2-sdk-node": { "optional": true }, - "openai-chat-tokens": { + "ibm-cloud-sdk-core": { "optional": true }, "sequelize": { @@ -267,20 +257,22 @@ } }, "devDependencies": { - "@aws-sdk/client-bedrock-runtime": "^3.706.0", + "@ai-sdk/amazon-bedrock": "^1.1.5", + "@ai-sdk/azure": "^1.1.2", + "@ai-sdk/google-vertex": "^2.1.6", + "@ai-sdk/groq": "^1.1.6", + "@ai-sdk/openai": "^1.1.2", "@commitlint/cli": "^19.6.0", "@commitlint/config-conventional": "^19.6.0", "@elastic/elasticsearch": "^8.16.2", "@eslint/js": "^9.16.0", "@eslint/markdown": "^6.2.1", - "@google-cloud/vertexai": "^1.9.2", "@googleapis/customsearch": "^3.2.0", - "@grpc/grpc-js": "^1.12.4", - "@grpc/proto-loader": "^0.7.13", - "@langchain/community": "~0.3.17", - "@langchain/core": "~0.3.22", - "@langchain/langgraph": "^0.2.39", - "@langchain/ollama": "^0.1.4", + "@ibm-cloud/watsonx-ai": "^1.4.0", + "@langchain/community": "~0.3.28", + "@langchain/core": "~0.3.37", + "@langchain/langgraph": "^0.2.44", + "@langchain/ollama": "^0.1.5", "@modelcontextprotocol/sdk": "^1.0.4", "@opentelemetry/instrumentation": "^0.56.0", "@opentelemetry/resources": "^1.29.0", @@ -309,16 +301,12 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-unused-imports": "^4.1.4", "glob": "^11.0.0", - "groq-sdk": "^0.9.0", "husky": "^9.1.7", + "ibm-cloud-sdk-core": "^5.1.2", "langchain": "~0.3.6", "linkinator": "^6.1.2", "lint-staged": "^15.2.10", - "ollama": "^0.5.11", - "openai": "^4.76.0", - "openai-chat-tokens": "^0.2.8", - "openapi-fetch": "^0.13.3", - "openapi-typescript": "^7.4.4", + "ollama-ai-provider": "^1.2.0", "picocolors": "^1.1.1", "pino-pretty": "^13.0.0", "pino-test": "^1.1.0", @@ -328,13 +316,11 @@ "sequelize": "^6.37.5", "sqlite3": "^5.1.7", "strip-ansi": "^7.1.0", - "temp-dir": "^3.0.0", - "tsc-files": "^1.1.4", - "tsup": "^8.3.5", + "tsup": "^8.3.6", "tsx": "^4.19.2", - "typescript": "^5.7.2", + "typescript": "^5.7.3", "typescript-eslint": "^8.18.1", - "vite-tsconfig-paths": "^5.1.3", + "vite-tsconfig-paths": "^5.1.4", "vitest": "^2.1.8", "yaml": "^2.6.1" } diff --git a/scripts/ibm_vllm_generate_protos/ibm_vllm_generate_protos.sh b/scripts/ibm_vllm_generate_protos/ibm_vllm_generate_protos.sh deleted file mode 100755 index af15d266..00000000 --- a/scripts/ibm_vllm_generate_protos/ibm_vllm_generate_protos.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -# Copyright 2025 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e - -GRPC_PROTO_PATH="./src/adapters/ibm-vllm/proto" -GRPC_TYPES_PATH="./src/adapters/ibm-vllm/types.ts" - -SCRIPT_DIR="$(dirname "$0")" -OUTPUT_RELATIVE_PATH="dist/merged.d.ts" -GRPC_TYPES_TMP_PATH="types" - -rm -f "$GRPC_TYPES_PATH" - -rm -rf "${SCRIPT_DIR}"/{dist,dts,types} - - -yarn run proto-loader-gen-types \ - --defaults \ - --keepCase \ - --oneofs \ - --longs=Number \ - --enums=String \ - --grpcLib=@grpc/grpc-js \ - --"outDir=${SCRIPT_DIR}/${GRPC_TYPES_TMP_PATH}" \ - "${GRPC_PROTO_PATH}"/*.proto - - -cd "$SCRIPT_DIR" - ENTRY="$(basename "$OUTPUT_RELATIVE_PATH" ".d.ts")" tsup --dts-only - sed -i.bak '$ d' "$OUTPUT_RELATIVE_PATH" - sed -i.bak -E "s/^interface/export interface/" "$OUTPUT_RELATIVE_PATH" - sed -i.bak -E "s/^type/export type/" "$OUTPUT_RELATIVE_PATH" -cd - - -mv "$SCRIPT_DIR/$OUTPUT_RELATIVE_PATH" "$GRPC_TYPES_PATH" -rm -rf "${SCRIPT_DIR}"/{dist,dts,types} - -yarn run lint:fix "${GRPC_TYPES_PATH}" -yarn prettier --write "${GRPC_TYPES_PATH}" -yarn copyright "${GRPC_TYPES_PATH}" diff --git a/scripts/ibm_vllm_generate_protos/package.json b/scripts/ibm_vllm_generate_protos/package.json deleted file mode 100644 index d25b1a7b..00000000 --- a/scripts/ibm_vllm_generate_protos/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "ibm-vllm-proto-types", - "type": "module", - "version": "1.0.0", - "typings": "./types/generation.d.ts" -} diff --git a/scripts/ibm_vllm_generate_protos/tsconfig.proto.json b/scripts/ibm_vllm_generate_protos/tsconfig.proto.json deleted file mode 100644 index 0e4a32c2..00000000 --- a/scripts/ibm_vllm_generate_protos/tsconfig.proto.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "node", - "rootDir": ".", - "baseUrl": ".", - "target": "ESNext", - "module": "ESNext", - "outDir": "dist", - "declaration": true, - "emitDeclarationOnly": true, - "skipLibCheck": true, - "sourceMap": false - } -} diff --git a/scripts/ibm_vllm_generate_protos/tsup.config.ts b/scripts/ibm_vllm_generate_protos/tsup.config.ts deleted file mode 100644 index 565fbc82..00000000 --- a/scripts/ibm_vllm_generate_protos/tsup.config.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { defineConfig } from "tsup"; -import fs from "node:fs"; - -if (!process.env.ENTRY) { - throw new Error(`Entry file was not provided!`); -} -const target = `types/${process.env.ENTRY}.ts`; -await fs.promises.writeFile( - target, - [ - `export { ProtoGrpcType as A } from "./caikit_runtime_Nlp.js"`, - `export { ProtoGrpcType as B } from "./generation.js"`, - ].join("\n"), -); - -export default defineConfig({ - entry: [target], - tsconfig: "./tsconfig.proto.json", - sourcemap: false, - dts: true, - format: ["esm"], - treeshake: true, - legacyOutput: false, - skipNodeModulesBundle: true, - bundle: true, - splitting: false, - silent: false, - clean: true, -}); diff --git a/src/adapters/amazon-bedrock/backend/chat.ts b/src/adapters/amazon-bedrock/backend/chat.ts new file mode 100644 index 00000000..bb71a04e --- /dev/null +++ b/src/adapters/amazon-bedrock/backend/chat.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AmazonBedrockClient, + AmazonBedrockClientSettings, +} from "@/adapters/amazon-bedrock/backend/client.js"; +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import { getEnv } from "@/internals/env.js"; +import { AmazonBedrockProvider } from "@ai-sdk/amazon-bedrock"; + +type AmazonBedrockParameters = Parameters; +export type AmazonBedrockChatModelId = NonNullable; +export type AmazonBedrockChatModelSettings = NonNullable; + +export class AmazonBedrockChatModel extends VercelChatModel { + constructor( + modelId: AmazonBedrockChatModelId = getEnv("AWS_CHAT_MODEL", "meta.llama3-70b-instruct-v1:0"), + settings: AmazonBedrockChatModelSettings = {}, + client?: AmazonBedrockClient | AmazonBedrockClientSettings, + ) { + const model = AmazonBedrockClient.ensure(client).instance.languageModel(modelId, settings); + super(model); + } +} diff --git a/tests/e2e/adapters/ollama/test.ts b/src/adapters/amazon-bedrock/backend/client.ts similarity index 55% rename from tests/e2e/adapters/ollama/test.ts rename to src/adapters/amazon-bedrock/backend/client.ts index 83c7b1d9..897e0d44 100644 --- a/tests/e2e/adapters/ollama/test.ts +++ b/src/adapters/amazon-bedrock/backend/client.ts @@ -14,24 +14,22 @@ * limitations under the License. */ -import { OllamaChatLLM } from "@/adapters/ollama/chat.js"; -import { Ollama } from "ollama"; +import { + createAmazonBedrock, + AmazonBedrockProviderSettings, + AmazonBedrockProvider, +} from "@ai-sdk/amazon-bedrock"; +import { BackendClient } from "@/backend/client.js"; -const host = process.env.OLLAMA_HOST; +export type AmazonBedrockClientSettings = AmazonBedrockProviderSettings; -describe.runIf(Boolean(host))("Ollama LLM", () => { - const createLLM = () => { - return new OllamaChatLLM({ - modelId: "llama3.1", - client: new Ollama({ - host, - }), +export class AmazonBedrockClient extends BackendClient< + AmazonBedrockClientSettings, + AmazonBedrockProvider +> { + protected create(): AmazonBedrockProvider { + return createAmazonBedrock({ + ...this.settings, }); - }; - - it("Retrieves version", async () => { - const llm = createLLM(); - const version = await llm.version(); - expect(version).toBeDefined(); - }); -}); + } +} diff --git a/src/adapters/amazon-bedrock/backend/embedding.ts b/src/adapters/amazon-bedrock/backend/embedding.ts new file mode 100644 index 00000000..c5bb3d89 --- /dev/null +++ b/src/adapters/amazon-bedrock/backend/embedding.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VercelEmbeddingModel } from "@/adapters/vercel/backend/embedding.js"; +import { AmazonBedrockProvider } from "@ai-sdk/amazon-bedrock"; +import { getEnv } from "@/internals/env.js"; +import { + AmazonBedrockClient, + AmazonBedrockClientSettings, +} from "@/adapters/amazon-bedrock/backend/client.js"; + +type Params = Parameters; +export type BedrockEmbeddingModelId = NonNullable; +export type BedrockEmbeddingSettings = NonNullable; + +export class BedrockEmbeddingModel extends VercelEmbeddingModel { + constructor( + modelId: BedrockEmbeddingModelId = getEnv("AWS_EMBEDDING_MODEL", "amazon.titan-embed-text-v1"), + settings: BedrockEmbeddingSettings = {}, + client?: AmazonBedrockClient | AmazonBedrockClientSettings, + ) { + const model = AmazonBedrockClient.ensure(client).instance.embedding(modelId, settings); + super(model); + } +} diff --git a/src/adapters/azure-openai/backend/chat.ts b/src/adapters/azure-openai/backend/chat.ts new file mode 100644 index 00000000..6b1cd660 --- /dev/null +++ b/src/adapters/azure-openai/backend/chat.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import type { + AzureOpenAIProvider as VercelAzureOpenAIProvider, + AzureOpenAIProviderSettings as VercelAzureOpenAIProviderSettings, +} from "@ai-sdk/azure"; +import { AzureOpenAIClient } from "@/adapters/azure-openai/backend/client.js"; +import { getEnv } from "@/internals/env.js"; + +type AzureOpenAIParameters = Parameters; +export type AzureOpenAIChatModelId = NonNullable; +export type AzureOpenAIChatModelSettings = NonNullable; + +export class AzureOpenAIChatModel extends VercelChatModel { + constructor( + modelId: AzureOpenAIChatModelId = getEnv("AZURE_OPENAI_CHAT_MODEL", "gpt-4o"), + settings: AzureOpenAIChatModelSettings = {}, + client?: VercelAzureOpenAIProviderSettings | AzureOpenAIClient, + ) { + const model = AzureOpenAIClient.ensure(client).instance.chat(modelId, settings); + super(model); + } +} diff --git a/src/adapters/azure-openai/backend/client.ts b/src/adapters/azure-openai/backend/client.ts new file mode 100644 index 00000000..ccd14dbf --- /dev/null +++ b/src/adapters/azure-openai/backend/client.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AzureOpenAIProvider, AzureOpenAIProviderSettings, createAzure } from "@ai-sdk/azure"; +import { getEnv } from "@/internals/env.js"; +import { BackendClient } from "@/backend/client.js"; + +export type AzureOpenAIClientSettings = AzureOpenAIProviderSettings; + +export class AzureOpenAIClient extends BackendClient< + AzureOpenAIClientSettings, + AzureOpenAIProvider +> { + protected create(options?: AzureOpenAIClientSettings): AzureOpenAIProvider { + return createAzure({ + ...options, + apiKey: options?.apiKey || getEnv("AZURE_OPENAI_API_KEY"), + baseURL: options?.baseURL || getEnv("AZURE_OPENAI_API_ENDPOINT"), + resourceName: options?.resourceName || getEnv("AZURE_OPENAI_API_RESOURCE"), + apiVersion: options?.apiVersion || getEnv("AZURE_OPENAI_API_VERSION"), + }); + } +} diff --git a/src/adapters/azure-openai/backend/embedding.ts b/src/adapters/azure-openai/backend/embedding.ts new file mode 100644 index 00000000..8945f23c --- /dev/null +++ b/src/adapters/azure-openai/backend/embedding.ts @@ -0,0 +1,41 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VercelEmbeddingModel } from "@/adapters/vercel/backend/embedding.js"; +import { + AzureOpenAIClient, + AzureOpenAIClientSettings, +} from "@/adapters/azure-openai/backend/client.js"; +import { getEnv } from "@/internals/env.js"; +import { AzureOpenAIProvider as VercelAzureOpenAIProviderSettings } from "@ai-sdk/azure"; + +type AzureOpenAIParameters = Parameters; +export type AzureOpenAIEmbeddingModelId = NonNullable; +export type AzureOpenAIEmbeddingModelSettings = Record; + +export class AzureOpenAIEmbeddingModel extends VercelEmbeddingModel { + constructor( + modelId: AzureOpenAIEmbeddingModelId = getEnv( + "AZURE_OPENAI_EMBEDDING_MODEL", + "text-embedding-3-small", + ), + settings: AzureOpenAIEmbeddingModelSettings = {}, + client?: AzureOpenAIClient | AzureOpenAIClientSettings, + ) { + const model = AzureOpenAIClient.ensure(client).instance.textEmbeddingModel(modelId, settings); + super(model); + } +} diff --git a/src/adapters/bedrock/chat.test.ts b/src/adapters/bedrock/chat.test.ts deleted file mode 100644 index 100189f6..00000000 --- a/src/adapters/bedrock/chat.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { BedrockChatLLM } from "@/adapters/bedrock/chat.js"; -import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime"; - -describe("Bedrock ChatLLM", () => { - const getInstance = () => { - return new BedrockChatLLM({ - modelId: "amazon.titan-text-lite-v1", - client: new BedrockRuntimeClient({ region: "us-east-1" }), - }); - }; - - it("Serializes", async () => { - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = BedrockChatLLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); diff --git a/src/adapters/bedrock/chat.ts b/src/adapters/bedrock/chat.ts deleted file mode 100644 index 5cafc808..00000000 --- a/src/adapters/bedrock/chat.ts +++ /dev/null @@ -1,313 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { Emitter } from "@/emitter/emitter.js"; -import type { AwsCredentialIdentity, Provider } from "@aws-sdk/types"; -import { - BedrockRuntimeClient as Client, - InvokeModelCommand, - ConverseCommand, - ConverseCommandOutput, - ConverseStreamCommand, - ContentBlockDeltaEvent, - InferenceConfiguration, - Message as BedrockMessage, - SystemContentBlock as BedrockSystemContentBlock, -} from "@aws-sdk/client-bedrock-runtime"; -import { GetRunContext } from "@/context.js"; -import { Serializer } from "@/serializer/serializer.js"; -import { omitUndefined } from "@/internals/helpers/object.js"; - -type Response = ContentBlockDeltaEvent | ConverseCommandOutput; - -export interface BedrockEmbeddingOptions extends EmbeddingOptions { - body?: Record; -} - -export class ChatBedrockOutput extends ChatLLMOutput { - public readonly responses: Response[]; - - constructor(response: Response) { - super(); - this.responses = [response]; - } - - static { - this.register(); - } - - get messages() { - return this.responses.flatMap((response) => { - if ("delta" in response && response.delta?.text) { - return [ - BaseMessage.of({ - role: Role.ASSISTANT, - text: response.delta.text, - }), - ]; - } else if ("output" in response && response.output?.message?.content) { - return response.output.message.content - .filter((choice) => choice?.text) - .map((choice) => - BaseMessage.of({ - role: Role.ASSISTANT, - text: choice.text!, - }), - ); - } - return []; - }); - } - - getTextContent() { - return this.messages.map((msg) => msg.text).join(""); - } - - merge(other: ChatBedrockOutput) { - this.responses.push(...other.responses); - } - - toString() { - return this.getTextContent(); - } - - createSnapshot() { - return { - responses: shallowCopy(this.responses), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } -} - -interface Input { - modelId?: string; - region?: string; - client?: Client; - credentials?: AwsCredentialIdentity | Provider; - parameters?: InferenceConfiguration; - executionOptions?: ExecutionOptions; - cache?: LLMCache; -} - -export type BedrockChatLLMEvents = ChatLLMGenerateEvents; - -export class BedrockChatLLM extends ChatLLM { - public readonly emitter = Emitter.root.child({ - namespace: ["bedrock", "chat_llm"], - creator: this, - }); - - public readonly client: Client; - public readonly parameters: Partial; - - constructor({ - client, - modelId = "amazon.titan-text-lite-v1", - region = "us-east-1", - credentials, - parameters = { - temperature: 0, - }, - executionOptions = {}, - cache, - }: Input = {}) { - super(modelId, executionOptions, cache); - this.client = client ?? new Client({ region: region, credentials: credentials }); - this.parameters = parameters ?? {}; - } - - static { - this.register(); - Serializer.register(Client, { - toPlain: (value) => ({ - config: { - region: value.config.region, - credentials: value.config.credentials, - }, - }), - fromPlain: (value) => - new Client({ - region: value.config.region, - credentials: value.config.credentials, - }), - }); - } - - async meta(): Promise { - if (this.modelId.includes("titan-text-premier")) { - return { tokenLimit: 3 * 1024 }; - } else if ( - this.modelId.includes("titan-text-express") || - this.modelId.includes("anthropic.claude-v2") || - this.modelId.includes("anthropic.claude-instant-v1") || - this.modelId.includes("anthropic.claude-3-sonnet") || - this.modelId.includes("anthropic.claude-3-haiku") || - this.modelId.includes("anthropic.claude-3-opus") || - this.modelId.includes("meta.llama2") || - this.modelId.includes("cohere.command-text") || - this.modelId.includes("cohere.command-light") - ) { - return { tokenLimit: 4 * 1024 }; - } else if ( - this.modelId.includes("titan-text-lite") || - this.modelId.includes("anthropic.claude-3-5-sonnet") || - this.modelId.includes("anthropic.claude-3-5-haiku") || - this.modelId.includes("meta.llama3-8b") || - this.modelId.includes("meta.llama3-70b") || - this.modelId.includes("ai21.j2") - ) { - return { tokenLimit: 8 * 1024 }; - } else if ( - this.modelId.includes("mistral.mistral-7b") || - this.modelId.includes("mistral.mixtral-8x7b") || - this.modelId.includes("mistral.mistral-small") - ) { - return { tokenLimit: 32 * 1024 }; - } else if ( - this.modelId.includes("meta.llama3-1") || - this.modelId.includes("meta.llama3-2") || - this.modelId.includes("mistral.mistral-large") || - this.modelId.includes("cohere.command-r") - ) { - return { tokenLimit: 128 * 1024 }; - } else if (this.modelId.includes("ai21.jamba")) { - return { tokenLimit: 256 * 1024 }; - } - - return { - tokenLimit: Infinity, - }; - } - - async embed( - input: BaseMessage[][], - options: BedrockEmbeddingOptions = {}, - ): Promise { - const command = new InvokeModelCommand({ - modelId: this.modelId, - contentType: "application/json", - accept: "application/json", - body: JSON.stringify( - omitUndefined({ - inputText: input.flat().map((msg) => msg.text), - ...options?.body, - }), - ), - }); - - const response = await this.client.send(command, { abortSignal: options?.signal }); - const jsonString = new TextDecoder().decode(response.body); - return JSON.parse(jsonString); - } - - async tokenize(input: BaseMessage[]): Promise { - const contentLength = input.reduce((acc, msg) => acc + msg.text.length, 0); - return { tokensCount: Math.ceil(contentLength / 4) }; - } - - protected async _generate( - input: BaseMessage[], - _options: Partial, - run: GetRunContext, - ): Promise { - const { conversation, systemMessage } = this.convertToConverseMessages(input); - const command = new ConverseCommand({ - modelId: this.modelId, - messages: conversation, - system: systemMessage, - ...this.parameters, - }); - const response = await this.client.send(command, { abortSignal: run.signal }); - return new ChatBedrockOutput(response); - } - - protected async *_stream( - input: BaseMessage[], - _options: StreamGenerateOptions | undefined, - run: GetRunContext, - ): AsyncStream { - const { conversation, systemMessage } = this.convertToConverseMessages(input); - const command = new ConverseStreamCommand({ - modelId: this.modelId, - messages: conversation, - system: systemMessage, - ...this.parameters, - }); - const response = await this.client.send(command, { abortSignal: run.signal }); - for await (const chunk of response?.stream || []) { - if (chunk.contentBlockDelta) { - yield new ChatBedrockOutput(chunk.contentBlockDelta); - } - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - client: this.client, - modelId: this.modelId, - parameters: shallowCopy(this.parameters), - }; - } - - protected convertToConverseMessages(messages: BaseMessage[]): { - conversation: BedrockMessage[]; - systemMessage: BedrockSystemContentBlock[]; - } { - const systemMessage: BedrockSystemContentBlock[] = messages - .filter((msg) => msg.role === Role.SYSTEM) - .map((msg) => ({ text: msg.text })); - - const converseMessages: BedrockMessage[] = messages - .filter((msg) => msg.role !== Role.SYSTEM) - .map((msg) => ({ - role: msg.role === Role.USER ? Role.USER : Role.ASSISTANT, - content: [{ text: msg.text }], - })); - - const conversation = converseMessages.reduce( - (messageList, currentMessage) => { - const lastMessage = messageList[messageList.length - 1]; - if (lastMessage && lastMessage !== currentMessage && lastMessage.role === Role.USER) { - lastMessage.content = lastMessage.content!.concat(currentMessage.content!); - } else { - messageList.push(currentMessage); - } - - return messageList; - }, - [], - ); - return { conversation, systemMessage }; - } -} diff --git a/src/adapters/dummy/backend/chat.ts b/src/adapters/dummy/backend/chat.ts new file mode 100644 index 00000000..a6391f0b --- /dev/null +++ b/src/adapters/dummy/backend/chat.ts @@ -0,0 +1,67 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChatModel, + ChatModelEvents, + ChatModelOutput, + ChatModelInput, + ChatModelParameters, +} from "@/backend/chat.js"; +import { GetRunContext } from "@/context.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { NotImplementedError } from "@/errors.js"; + +export class DummyChatModel extends ChatModel { + public readonly emitter = Emitter.root.child({ + namespace: ["backend", "dummy", "chat"], + creator: this, + }); + + constructor( + public readonly modelId = "dummy", + public readonly parameters: ChatModelParameters = {}, + ) { + super(); + } + + get providerId(): string { + return "dummy"; + } + + protected _create(_input: ChatModelInput, _run: GetRunContext): Promise { + throw new NotImplementedError(); + } + + protected _createStream( + _input: ChatModelInput, + _run: GetRunContext, + ): AsyncGenerator { + throw new NotImplementedError(); + } + + createSnapshot() { + return { ...super.createSnapshot(), modelId: this.modelId }; + } + + loadSnapshot(snapshot: ReturnType): void { + Object.assign(this, snapshot); + } + + static { + this.register(); + } +} diff --git a/src/adapters/dummy/backend/embedding.ts b/src/adapters/dummy/backend/embedding.ts new file mode 100644 index 00000000..2b759f37 --- /dev/null +++ b/src/adapters/dummy/backend/embedding.ts @@ -0,0 +1,55 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GetRunContext } from "@/context.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { NotImplementedError } from "@/errors.js"; +import { + EmbeddingModel, + EmbeddingModelEvents, + EmbeddingModelInput, + EmbeddingModelOutput, +} from "@/backend/embedding.js"; + +export class DummyEmbeddingModel extends EmbeddingModel { + public readonly emitter = Emitter.root.child({ + namespace: ["backend", "dummy", "embedding"], + creator: this, + }); + + constructor(public readonly modelId = "dummy") { + super(); + } + + get providerId(): string { + return "dummy"; + } + + protected _create( + _input: EmbeddingModelInput, + _run: GetRunContext, + ): Promise { + throw new NotImplementedError(); + } + + createSnapshot() { + return { ...super.createSnapshot(), modelId: this.modelId }; + } + + loadSnapshot(snapshot: ReturnType): void { + Object.assign(this, snapshot); + } +} diff --git a/src/adapters/google-vertex/backend/chat.ts b/src/adapters/google-vertex/backend/chat.ts new file mode 100644 index 00000000..2ee7db99 --- /dev/null +++ b/src/adapters/google-vertex/backend/chat.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GoogleVertexProvider } from "@ai-sdk/google-vertex"; +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import { + GoogleVertexClient, + GoogleVertexClientSettings, +} from "@/adapters/google-vertex/backend/client.js"; +import { getEnv } from "@/internals/env.js"; + +type GoogleVertexParameters = Parameters; +export type GoogleVertexChatModelId = NonNullable; +export type GoogleVertexChatModelSettings = NonNullable; + +export class GoogleVertexChatModel extends VercelChatModel { + constructor( + modelId: GoogleVertexChatModelId = getEnv("GOOGLE_VERTEX_CHAT_MODEL", "gemini-1.5-pro"), + settings: GoogleVertexChatModelSettings = {}, + client?: GoogleVertexClientSettings | GoogleVertexClient, + ) { + const model = GoogleVertexClient.ensure(client).instance.languageModel(modelId, settings); + super(model); + } +} diff --git a/src/adapters/google-vertex/backend/client.ts b/src/adapters/google-vertex/backend/client.ts new file mode 100644 index 00000000..75dd764b --- /dev/null +++ b/src/adapters/google-vertex/backend/client.ts @@ -0,0 +1,39 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getEnv } from "@/internals/env.js"; +import { + createVertex, + GoogleVertexProvider, + GoogleVertexProviderSettings, +} from "@ai-sdk/google-vertex"; +import { BackendClient } from "@/backend/client.js"; + +export type GoogleVertexClientSettings = GoogleVertexProviderSettings; + +export class GoogleVertexClient extends BackendClient< + GoogleVertexClientSettings, + GoogleVertexProvider +> { + protected create(): GoogleVertexProvider { + return createVertex({ + ...this.settings, + project: this.settings?.project || getEnv("GOOGLE_VERTEX_PROJECT"), + baseURL: this.settings?.baseURL || getEnv("GOOGLE_VERTEX_ENDPOINT"), + location: this.settings?.baseURL || getEnv("GOOGLE_VERTEX_LOCATION"), + }); + } +} diff --git a/src/adapters/google-vertex/backend/embedding.ts b/src/adapters/google-vertex/backend/embedding.ts new file mode 100644 index 00000000..5fa4d0c2 --- /dev/null +++ b/src/adapters/google-vertex/backend/embedding.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GoogleVertexClient, GoogleVertexClientSettings } from "./client.js"; +import { VercelEmbeddingModel } from "@/adapters/vercel/backend/embedding.js"; +import { getEnv } from "@/internals/env.js"; +import { GoogleVertexProvider } from "@ai-sdk/google-vertex"; + +type GoogleVertexParameters = Parameters; +export type GoogleVertexChatModelId = NonNullable; +export type GoogleVertexChatModelSettings = Record; + +export class GoogleVertexEmbeddingModel extends VercelEmbeddingModel { + constructor( + modelId: GoogleVertexChatModelId = getEnv( + "GOOGLE_VERTEX_EMBEDDING_MODEL", + "text-embedding-004", + ), + _settings: GoogleVertexChatModelSettings = {}, + client?: GoogleVertexClient | GoogleVertexClientSettings, + ) { + const model = GoogleVertexClient.ensure(client).instance.textEmbeddingModel(modelId); + super(model); + } +} diff --git a/src/adapters/groq/backend/chat.ts b/src/adapters/groq/backend/chat.ts new file mode 100644 index 00000000..e0c4c730 --- /dev/null +++ b/src/adapters/groq/backend/chat.ts @@ -0,0 +1,39 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import { GroqClient, GroqClientSettings } from "@/adapters/groq/backend/client.js"; +import { getEnv } from "@/internals/env.js"; +import { GroqProvider } from "@ai-sdk/groq"; + +type GroqParameters = Parameters; +export type GroqChatModelId = NonNullable; +export type GroqChatModelSettings = NonNullable; + +export class GroqChatModel extends VercelChatModel { + constructor( + modelId: GroqChatModelId = getEnv("GROQ_CHAT_MODEL", "gemma2-9b-it"), + settings: GroqChatModelSettings = {}, + client?: GroqClientSettings | GroqClient, + ) { + const model = GroqClient.ensure(client).instance.languageModel(modelId, settings); + super(model); + } + + static { + this.register(); + } +} diff --git a/src/llms/llm.ts b/src/adapters/groq/backend/client.ts similarity index 53% rename from src/llms/llm.ts rename to src/adapters/groq/backend/client.ts index 066ab736..2cbfc220 100644 --- a/src/llms/llm.ts +++ b/src/adapters/groq/backend/client.ts @@ -14,19 +14,18 @@ * limitations under the License. */ -import { BaseLLM, BaseLLMOutput, BaseLLMEvents, GenerateOptions } from "./base.js"; -import { Emitter } from "@/emitter/emitter.js"; +import { createGroq, GroqProvider, GroqProviderSettings } from "@ai-sdk/groq"; +import { BackendClient } from "@/backend/client.js"; +import { getEnv } from "@/internals/env.js"; -export type LLMInput = string; +export type GroqClientSettings = GroqProviderSettings; -export type LLMEvents = BaseLLMEvents< - LLMInput, - TOutput ->; - -export abstract class LLM< - TOutput extends BaseLLMOutput, - TGenerateOptions extends GenerateOptions = GenerateOptions, -> extends BaseLLM { - public abstract readonly emitter: Emitter>; +export class GroqClient extends BackendClient { + protected create(settings?: GroqClientSettings): GroqProvider { + return createGroq({ + ...settings, + baseURL: getEnv("GROQ_API_BASE_URL"), + apiKey: getEnv("GROQ_API_KEY"), + }); + } } diff --git a/src/adapters/groq/backend/embedding.ts b/src/adapters/groq/backend/embedding.ts new file mode 100644 index 00000000..b9a55b7c --- /dev/null +++ b/src/adapters/groq/backend/embedding.ts @@ -0,0 +1,39 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VercelEmbeddingModel } from "@/adapters/vercel/backend/embedding.js"; +import { getEnv } from "@/internals/env.js"; +import { GroqClient, GroqClientSettings } from "@/adapters/groq/backend/client.js"; +import { ValueError } from "@/errors.js"; +import { GroqProvider } from "@ai-sdk/groq"; + +type GroqParameters = Parameters; +export type GroqEmbeddingModelId = NonNullable; +export type GroqEmbeddingModelSettings = Record; + +export class GroqEmbeddingModel extends VercelEmbeddingModel { + constructor( + modelId: GroqEmbeddingModelId = getEnv("GROQ_EMBEDDING_MODEL", ""), + _settings: GroqEmbeddingModelSettings = {}, + client?: GroqClientSettings | GroqClient, + ) { + if (!modelId) { + throw new ValueError("Missing modelId!"); + } + const model = GroqClient.ensure(client).instance.textEmbeddingModel(modelId); + super(model); + } +} diff --git a/src/adapters/groq/chat.ts b/src/adapters/groq/chat.ts deleted file mode 100644 index a63f4375..00000000 --- a/src/adapters/groq/chat.ts +++ /dev/null @@ -1,258 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, RoleType } from "@/llms/primitives/message.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { ClientOptions, Groq as Client } from "groq-sdk"; -import { GetRunContext } from "@/context.js"; -import { Serializer } from "@/serializer/serializer.js"; -import { getPropStrict } from "@/internals/helpers/object.js"; -import { ChatCompletionCreateParams } from "groq-sdk/resources/chat/completions"; - -type Parameters = Omit; -type Response = Omit; - -export class ChatGroqOutput extends ChatLLMOutput { - public readonly responses: Response[]; - - constructor(response: Response) { - super(); - this.responses = [response]; - } - - static { - this.register(); - } - - get messages() { - return this.responses - .flatMap((response) => response.choices) - .flatMap((choice) => - BaseMessage.of({ - role: choice.delta.role as RoleType, - text: choice.delta.content!, - }), - ); - } - - getTextContent(): string { - return this.messages.map((msg) => msg.text).join("\n"); - } - - merge(other: ChatGroqOutput): void { - this.responses.push(...other.responses); - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - responses: shallowCopy(this.responses), - }; - } - - loadSnapshot(snapshot: ReturnType): void { - Object.assign(this, snapshot); - } -} - -interface Input { - modelId?: string; - client?: Client; - parameters?: Parameters; - executionOptions?: ExecutionOptions; - cache?: LLMCache; -} - -export type GroqChatLLMEvents = ChatLLMGenerateEvents; - -export class GroqChatLLM extends ChatLLM { - public readonly emitter = Emitter.root.child({ - namespace: ["groq", "chat_llm"], - creator: this, - }); - - public readonly client: Client; - public readonly parameters: Partial; - - constructor({ - client, - modelId = "llama-3.3-70b-versatile", - parameters = { - temperature: 0, - }, - executionOptions = {}, - cache, - }: Input = {}) { - super(modelId, executionOptions, cache); - this.client = client ?? new Client(); - this.parameters = parameters ?? {}; - } - - static { - this.register(); - Serializer.register(Client, { - toPlain: (value) => ({ - options: getPropStrict(value, "_options") as ClientOptions, - }), - fromPlain: (value) => new Client(value.options), - }); - } - - async meta(): Promise { - if ( - this.modelId.includes("gemma") || - this.modelId.includes("llama3") || - this.modelId.includes("llama-guard") || - this.modelId.includes("-preview") || - this.modelId.includes("-specdec") - ) { - return { tokenLimit: 8 * 1024 }; - } else if (this.modelId.includes("llava-v1.5")) { - return { tokenLimit: 4 * 1024 }; - } else if ( - this.modelId.includes("llama-3.1-70b") || - this.modelId.includes("llama-3.1-8b") || - this.modelId.includes("llama-3.3-70b") - ) { - return { tokenLimit: 128 * 1024 }; - } else if (this.modelId.includes("mixtral-8x7b")) { - return { tokenLimit: 32 * 1024 }; - } - - return { - tokenLimit: Infinity, - }; - } - - async embed(input: BaseMessage[][], options?: EmbeddingOptions): Promise { - const { data } = await this.client.embeddings.create( - { - model: this.modelId, - input: input.flatMap((msgs) => msgs.map((msg) => msg.text)) as string[], - encoding_format: "float", - }, - { - signal: options?.signal, - stream: false, - }, - ); - return { embeddings: data.map(({ embedding }) => embedding as number[]) }; - } - - async tokenize(input: BaseMessage[]): Promise { - const contentLength = input.reduce((acc, msg) => acc + msg.text.length, 0); - - return { - tokensCount: Math.ceil(contentLength / 4), - }; - } - - protected _prepareRequest( - input: BaseMessage[], - options: GenerateOptions, - ): ChatCompletionCreateParams { - return { - ...this.parameters, - model: this.modelId, - stream: false, - messages: input.map( - (message) => - ({ - role: message.role, - content: message.text, - }) as Client.Chat.ChatCompletionMessageParam, - ), - ...(options?.guided?.json && { - response_format: { - type: "json_object", - }, - }), - }; - } - - protected async _generate( - input: BaseMessage[], - options: GenerateOptions, - run: GetRunContext, - ): Promise { - const response = await this.client.chat.completions.create( - { - ...this._prepareRequest(input, options), - stream: false, - }, - { - signal: run.signal, - }, - ); - return new ChatGroqOutput({ - id: response.id, - model: response.model, - created: response.created, - system_fingerprint: response.system_fingerprint, - choices: response.choices.map( - (choice) => - ({ - delta: choice.message, - index: choice.index, - logprobs: choice.logprobs, - finish_reason: choice.finish_reason, - }) as Client.Chat.ChatCompletionChunk.Choice, - ), - }); - } - - protected async *_stream( - input: BaseMessage[], - options: Partial, - run: GetRunContext, - ): AsyncStream { - for await (const chunk of await this.client.chat.completions.create( - { - ...this._prepareRequest(input, options), - stream: true, - }, - { - signal: run.signal, - }, - )) { - yield new ChatGroqOutput(chunk); - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - parameters: shallowCopy(this.parameters), - client: this.client, - }; - } -} diff --git a/src/adapters/ibm-vllm/chat.ts b/src/adapters/ibm-vllm/chat.ts deleted file mode 100644 index 225298db..00000000 --- a/src/adapters/ibm-vllm/chat.ts +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { isFunction, isObjectType } from "remeda"; - -import { - IBMvLLM, - IBMvLLMEmbeddingOptions, - IBMvLLMGenerateOptions, - IBMvLLMOutput, - IBMvLLMParameters, -} from "./llm.js"; - -import { Cache } from "@/cache/decoratorCache.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOutput, - LLMCache, - LLMError, - LLMMeta, -} from "@/llms/base.js"; -import { transformAsyncIterable } from "@/internals/helpers/stream.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { IBMVllmChatLLMPreset, IBMVllmChatLLMPresetModel } from "@/adapters/ibm-vllm/chatPreset.js"; -import { Client } from "./client.js"; -import { GetRunContext } from "@/context.js"; - -export class GrpcChatLLMOutput extends ChatLLMOutput { - public readonly raw: IBMvLLMOutput; - - constructor(rawOutput: IBMvLLMOutput) { - super(); - this.raw = rawOutput; - } - - @Cache() - get messages(): BaseMessage[] { - const text = this.raw.getTextContent(); - return [ - BaseMessage.of({ - role: Role.ASSISTANT, - text, - meta: this.raw.meta, - }), - ]; - } - - merge(other: GrpcChatLLMOutput): void { - Cache.getInstance(this, "messages").clear(); - this.raw.merge(other.raw); - } - - getTextContent(): string { - const [message] = this.messages; - return message.text; - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - raw: shallowCopy(this.raw), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } -} - -export interface IBMVllmInputConfig { - messagesToPrompt: (messages: BaseMessage[]) => string; -} - -export interface GrpcChatLLMInput { - llm: IBMvLLM; - config: IBMVllmInputConfig; - cache?: LLMCache; -} - -export type IBMVllmChatEvents = ChatLLMGenerateEvents; - -export class IBMVllmChatLLM extends ChatLLM { - public readonly emitter = new Emitter({ - namespace: ["ibm_vllm", "chat_llm"], - creator: this, - }); - - public readonly llm: IBMvLLM; - protected readonly config: IBMVllmInputConfig; - - constructor({ llm, config, cache }: GrpcChatLLMInput) { - super(llm.modelId, llm.executionOptions, cache); - this.llm = llm; - this.config = config; - } - - static { - this.register(); - } - - async meta(): Promise { - return this.llm.meta(); - } - - async embed(input: BaseMessage[][], options?: IBMvLLMEmbeddingOptions): Promise { - const inputs = input.map((messages) => this.messagesToPrompt(messages)); - return this.llm.embed(inputs, options); - } - - createSnapshot() { - return { - ...super.createSnapshot(), - modelId: this.modelId, - executionOptions: this.executionOptions, - llm: this.llm, - config: shallowCopy(this.config), - }; - } - - async tokenize(messages: BaseMessage[]): Promise { - const prompt = this.messagesToPrompt(messages); - return this.llm.tokenize(prompt); - } - - protected async _generate( - messages: BaseMessage[], - options: IBMvLLMGenerateOptions | undefined, - run: GetRunContext, - ): Promise { - const prompt = this.messagesToPrompt(messages); - // @ts-expect-error protected property - const rawResponse = await this.llm._generate(prompt, options, run); - return new GrpcChatLLMOutput(rawResponse); - } - - protected async *_stream( - messages: BaseMessage[], - options: IBMvLLMGenerateOptions | undefined, - run: GetRunContext, - ): AsyncStream { - const prompt = this.messagesToPrompt(messages); - // @ts-expect-error protected property - const response = this.llm._stream(prompt, options, run); - return yield* transformAsyncIterable(response, (output) => new GrpcChatLLMOutput(output)); - } - - messagesToPrompt(messages: BaseMessage[]) { - return this.config.messagesToPrompt(messages); - } - - static fromPreset( - modelId: IBMVllmChatLLMPresetModel, - overrides?: { - client?: Client; - parameters?: IBMvLLMParameters | ((value: IBMvLLMParameters) => IBMvLLMParameters); - }, - ) { - const presetFactory = IBMVllmChatLLMPreset[modelId]; - if (!presetFactory) { - throw new LLMError(`Model "${modelId}" does not exist in preset.`); - } - - const preset = presetFactory(); - let parameters = preset.base.parameters ?? {}; - if (overrides) { - if (isFunction(overrides.parameters)) { - parameters = overrides.parameters(parameters); - } else if (isObjectType(overrides.parameters)) { - parameters = overrides.parameters; - } - } - - return new IBMVllmChatLLM({ - config: preset.chat, - llm: new IBMvLLM({ - ...preset.base, - ...overrides, - parameters, - modelId, - }), - }); - } -} diff --git a/src/adapters/ibm-vllm/chatPreset.ts b/src/adapters/ibm-vllm/chatPreset.ts deleted file mode 100644 index 887c0d7d..00000000 --- a/src/adapters/ibm-vllm/chatPreset.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LLMChatTemplates } from "@/adapters/shared/llmChatTemplates.js"; -import { IBMVllmInputConfig } from "./chat.js"; -import { IBMvLLMInput } from "./llm.js"; - -interface IBMVllmChatLLMPreset { - chat: IBMVllmInputConfig; - base: IBMvLLMInput; -} - -export const IBMVllmModel = { - LLAMA_3_3_70B_INSTRUCT: "meta-llama/llama-3-3-70b-instruct", - LLAMA_3_1_405B_INSTRUCT_FP8: "meta-llama/llama-3-1-405b-instruct-fp8", - LLAMA_3_1_70B_INSTRUCT: "meta-llama/llama-3-1-70b-instruct", - LLAMA_3_1_8B_INSTRUCT: "meta-llama/llama-3-1-8b-instruct", - GRANITE_3_1_8B_INSTRUCT: "ibm-granite/granite-3-1-8b-instruct", -} as const; -export type IBMVllmModel = (typeof IBMVllmModel)[keyof typeof IBMVllmModel]; - -export const IBMVllmChatLLMPreset = { - [IBMVllmModel.LLAMA_3_3_70B_INSTRUCT]: (): IBMVllmChatLLMPreset => { - const { template, parameters, messagesToPrompt } = LLMChatTemplates.get("llama3.3"); - return { - base: { - modelId: IBMVllmModel.LLAMA_3_3_70B_INSTRUCT, - parameters: { - method: "GREEDY", - stopping: { - stop_sequences: [...parameters.stop_sequence], - include_stop_sequence: false, - max_new_tokens: 2048, - }, - decoding: { - repetition_penalty: 1, - }, - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - [IBMVllmModel.LLAMA_3_1_405B_INSTRUCT_FP8]: (): IBMVllmChatLLMPreset => { - const { template, parameters, messagesToPrompt } = LLMChatTemplates.get("llama3.1"); - return { - base: { - modelId: IBMVllmModel.LLAMA_3_1_70B_INSTRUCT, - parameters: { - method: "GREEDY", - stopping: { - stop_sequences: [...parameters.stop_sequence], - include_stop_sequence: false, - max_new_tokens: 2048, - }, - decoding: { - repetition_penalty: 1, - }, - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - [IBMVllmModel.LLAMA_3_1_70B_INSTRUCT]: (): IBMVllmChatLLMPreset => { - const { template, parameters, messagesToPrompt } = LLMChatTemplates.get("llama3.1"); - return { - base: { - modelId: IBMVllmModel.LLAMA_3_1_70B_INSTRUCT, - parameters: { - method: "GREEDY", - stopping: { - stop_sequences: [...parameters.stop_sequence], - include_stop_sequence: false, - max_new_tokens: 2048, - }, - decoding: { - repetition_penalty: 1, - }, - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - [IBMVllmModel.LLAMA_3_1_8B_INSTRUCT]: (): IBMVllmChatLLMPreset => { - const { template, parameters, messagesToPrompt } = LLMChatTemplates.get("llama3"); - return { - base: { - modelId: IBMVllmModel.LLAMA_3_1_8B_INSTRUCT, - parameters: { - method: "GREEDY", - stopping: { - stop_sequences: [...parameters.stop_sequence], - include_stop_sequence: false, - max_new_tokens: 2048, - }, - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - [IBMVllmModel.GRANITE_3_1_8B_INSTRUCT]: (): IBMVllmChatLLMPreset => { - const { template, parameters, messagesToPrompt } = LLMChatTemplates.get("granite3.1-Instruct"); - return { - base: { - modelId: IBMVllmModel.GRANITE_3_1_8B_INSTRUCT, - parameters: { - method: "GREEDY", - stopping: { - stop_sequences: [...parameters.stop_sequence], - include_stop_sequence: false, - max_new_tokens: 2048, - }, - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, -} as const satisfies Record IBMVllmChatLLMPreset>; - -export type IBMVllmChatLLMPresetModel = keyof typeof IBMVllmChatLLMPreset; diff --git a/src/adapters/ibm-vllm/client.ts b/src/adapters/ibm-vllm/client.ts deleted file mode 100644 index de4f751f..00000000 --- a/src/adapters/ibm-vllm/client.ts +++ /dev/null @@ -1,269 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import grpc, { - CallOptions as GRPCCallOptions, - ClientOptions as GRPCClientOptions, - ClientReadableStream, - ClientUnaryCall, - Metadata, -} from "@grpc/grpc-js"; - -import * as R from "remeda"; -// eslint-disable-next-line no-restricted-imports -import { UnaryCallback } from "@grpc/grpc-js/build/src/client.js"; -import { FrameworkError, ValueError } from "@/errors.js"; -import protoLoader, { Options } from "@grpc/proto-loader"; - -import { - BatchedGenerationRequest, - BatchedGenerationResponse__Output, - BatchedTokenizeRequest, - BatchedTokenizeResponse__Output, - type EmbeddingTasksRequest, - GenerationRequest__Output, - ModelInfoRequest, - ModelInfoResponse__Output, - ProtoGrpcType as GenerationProtoGentypes, - ProtoGrpcType$1 as CaikitProtoGentypes, - SingleGenerationRequest, - EmbeddingResults__Output, - type SubtypeConstructor, -} from "@/adapters/ibm-vllm/types.js"; -import { parseEnv } from "@/internals/env.js"; -import { z } from "zod"; -import { Cache } from "@/cache/decoratorCache.js"; -import { Serializable } from "@/internals/serializable.js"; -import PQueue from "p-queue-compat"; -import { getProp } from "@/internals/helpers/object.js"; - -const GENERATION_PROTO_PATH = new URL("./proto/generation.proto", import.meta.url); -const NLP_PROTO_PATH = new URL("./proto/caikit_runtime_Nlp.proto", import.meta.url); - -interface ClientOptions { - modelRouterSubdomain?: string; - url: string; - credentials: { - rootCert: string; - certChain: string; - privateKey: string; - }; - grpcClientOptions: GRPCClientOptions; - clientShutdownDelay: number; - limits?: { - concurrency?: { - embeddings?: number; - }; - }; -} - -const defaultOptions = { - clientShutdownDelay: 5 * 60 * 1000, - grpcClientOptions: { - // This is needed, otherwise communication to DIPC cluster fails with "Dropped connection" error after +- 50 secs - "grpc.keepalive_time_ms": 25000, - "grpc.max_receive_message_length": 32 * 1024 * 1024, // 32MiB - }, -}; - -const grpcConfig: Options = { - longs: Number, - enums: String, - arrays: true, - objects: true, - oneofs: true, - keepCase: true, - defaults: true, -}; - -const generationPackage = grpc.loadPackageDefinition( - protoLoader.loadSync([GENERATION_PROTO_PATH.pathname], grpcConfig), -) as unknown as GenerationProtoGentypes; - -const embeddingsPackage = grpc.loadPackageDefinition( - protoLoader.loadSync([NLP_PROTO_PATH.pathname], grpcConfig), -) as unknown as CaikitProtoGentypes; - -const GRPC_CLIENT_TTL = 15 * 60 * 1000; - -type CallOptions = GRPCCallOptions & { signal?: AbortSignal }; -type RequiredModel = T & { model_id: string }; - -export class Client extends Serializable { - public readonly options: ClientOptions; - private usedDefaultCredentials = false; - - @Cache({ ttl: GRPC_CLIENT_TTL }) - protected getClient void }>( - modelId: string, - factory: SubtypeConstructor, - ): T { - const modelSpecificUrl = this.options.url.replace(/{model_id}/, modelId.replaceAll("/", "--")); - const client = new factory( - modelSpecificUrl, - grpc.credentials.createSsl( - Buffer.from(this.options.credentials.rootCert), - Buffer.from(this.options.credentials.privateKey), - Buffer.from(this.options.credentials.certChain), - ), - this.options.grpcClientOptions, - ); - setTimeout(() => { - try { - client.close(); - } catch { - /* empty */ - } - }, GRPC_CLIENT_TTL + this.options.clientShutdownDelay).unref(); - return client; - } - - protected getDefaultCredentials() { - this.usedDefaultCredentials = true; - return { - rootCert: parseEnv("IBM_VLLM_ROOT_CERT", z.string()), - privateKey: parseEnv("IBM_VLLM_PRIVATE_KEY", z.string()), - certChain: parseEnv("IBM_VLLM_CERT_CHAIN", z.string()), - }; - } - - constructor(options?: Partial) { - super(); - this.options = { - ...defaultOptions, - ...options, - url: options?.url ?? parseEnv("IBM_VLLM_URL", z.string()), - credentials: options?.credentials ?? this.getDefaultCredentials(), - }; - } - - async modelInfo(request: RequiredModel, options?: CallOptions) { - const client = this.getClient(request.model_id, generationPackage.fmaas.GenerationService); - return this.wrapGrpcCall( - client.modelInfo.bind(client), - )(request, options); - } - - async generate(request: RequiredModel, options?: CallOptions) { - const client = this.getClient(request.model_id, generationPackage.fmaas.GenerationService); - return this.wrapGrpcCall( - client.generate.bind(client), - )(request, options); - } - - async generateStream(request: RequiredModel, options?: CallOptions) { - const client = this.getClient(request.model_id, generationPackage.fmaas.GenerationService); - return this.wrapGrpcStream( - client.generateStream.bind(client), - )(request, options); - } - - async tokenize(request: RequiredModel, options?: CallOptions) { - const client = this.getClient(request.model_id, generationPackage.fmaas.GenerationService); - return this.wrapGrpcCall( - client.tokenize.bind(client), - )(request, options); - } - - async embed(request: RequiredModel, options?: CallOptions) { - const client = this.getClient( - request.model_id, - embeddingsPackage.caikit.runtime.Nlp.NlpService, - ); - return this.queues.embeddings.add( - () => - this.wrapGrpcCall( - client.embeddingTasksPredict.bind(client), - )(request, options), - { throwOnTimeout: true }, - ); - } - - protected wrapGrpcCall( - fn: ( - request: TRequest, - metadata: Metadata, - options: CallOptions, - callback: UnaryCallback, - ) => ClientUnaryCall, - ) { - return (request: TRequest, { signal, ...options }: CallOptions = {}): Promise => { - const metadata = new Metadata(); - const modelId = getProp(request, ["model_id"]); - if (modelId) { - metadata.add("mm-model-id", modelId); - } - - return new Promise((resolve, reject) => { - const call = fn(request, metadata, options, (err, response) => { - signal?.removeEventListener("abort", abortHandler); - if (err) { - reject(err); - } else { - if (response === undefined) { - reject(new FrameworkError("Invalid response from GRPC server")); - } else { - resolve(response); - } - } - }); - const abortHandler = () => call.cancel(); - signal?.addEventListener("abort", abortHandler, { once: true }); - }); - }; - } - - protected wrapGrpcStream( - fn: (request: TRequest, options: CallOptions) => ClientReadableStream, - ) { - return async ( - request: TRequest, - { signal, ...options }: CallOptions = {}, - ): Promise> => { - const stream = fn(request, options); - const abortHandler = () => stream.cancel(); - signal?.addEventListener("abort", abortHandler, { once: true }); - stream.addListener("close", () => signal?.removeEventListener("abort", abortHandler)); - return stream; - }; - } - - createSnapshot() { - if (!this.usedDefaultCredentials) { - throw new ValueError( - "Cannot serialize a client with credentials passed directly. Use environment variables.", - ); - } - return { - options: R.omit(this.options, ["credentials"]), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - this.options.credentials = this.getDefaultCredentials(); - } - - @Cache({ enumerable: false }) - protected get queues() { - return { - embeddings: new PQueue({ - concurrency: this.options.limits?.concurrency?.embeddings ?? 5, - throwOnTimeout: true, - }), - }; - } -} diff --git a/src/adapters/ibm-vllm/llm.ts b/src/adapters/ibm-vllm/llm.ts deleted file mode 100644 index c42f53d3..00000000 --- a/src/adapters/ibm-vllm/llm.ts +++ /dev/null @@ -1,299 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - AsyncStream, - BaseLLMOutput, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - GuidedOptions, - LLMCache, - LLMError, - LLMMeta, -} from "@/llms/base.js"; -import { chunk, isEmpty, isString } from "remeda"; -import type { - DecodingParameters, - SingleGenerationRequest, - EmbeddingTasksRequest, -} from "@/adapters/ibm-vllm/types.js"; -import { LLM, LLMEvents, LLMInput } from "@/llms/llm.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { GenerationResponse__Output } from "@/adapters/ibm-vllm/types.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { FrameworkError, NotImplementedError } from "@/errors.js"; -import { assign, omitUndefined } from "@/internals/helpers/object.js"; -import { ServiceError } from "@grpc/grpc-js"; -import { Client } from "@/adapters/ibm-vllm/client.js"; -import { GetRunContext } from "@/context.js"; -import { BatchedGenerationRequest } from "./types.js"; -import { OmitPrivateKeys } from "@/internals/types.js"; - -function isGrpcServiceError(err: unknown): err is ServiceError { - return ( - err instanceof Error && - err.constructor.name === "Error" && - "code" in err && - typeof err.code === "number" - ); -} - -export class IBMvLLMOutput extends BaseLLMOutput { - constructor( - public text: string, - public readonly meta: Record, - ) { - super(); - } - - static { - this.register(); - } - - merge(other: IBMvLLMOutput): void { - this.text += other.text; - assign(this.meta, other.meta); - } - - getTextContent(): string { - return this.text; - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - text: this.text, - meta: shallowCopy(this.meta), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } -} - -export interface IBMvLLMInput { - client?: Client; - modelId: string; - parameters?: IBMvLLMParameters; - executionOptions?: ExecutionOptions; - cache?: LLMCache; -} - -export type IBMvLLMParameters = NonNullable< - BatchedGenerationRequest["params"] & SingleGenerationRequest["params"] ->; - -export interface IBMvLLMGenerateOptions extends GenerateOptions {} - -export interface IBMvLLMEmbeddingOptions - extends EmbeddingOptions, - Omit, "texts"> { - chunkSize?: number; -} - -export type IBMvLLMEvents = LLMEvents; - -export class IBMvLLM extends LLM { - public readonly emitter = new Emitter({ - namespace: ["ibm_vllm", "llm"], - creator: this, - }); - - public readonly client: Client; - public readonly parameters: Partial; - - constructor({ client, modelId, parameters = {}, executionOptions, cache }: IBMvLLMInput) { - super(modelId, executionOptions, cache); - this.client = client ?? new Client(); - this.parameters = parameters ?? {}; - } - - static { - this.register(); - } - - async meta(): Promise { - const response = await this.client.modelInfo({ model_id: this.modelId }); - return { - tokenLimit: response.max_sequence_length, - }; - } - - async embed( - input: LLMInput[], - { chunkSize, signal, ...options }: IBMvLLMEmbeddingOptions = {}, - ): Promise { - const results = await Promise.all( - chunk(input, chunkSize ?? 100).map(async (texts) => { - const response = await this.client.embed( - { - model_id: this.modelId, - truncate_input_tokens: options?.truncate_input_tokens ?? 512, - texts, - }, - { - signal, - }, - ); - const embeddings = response.results?.vectors.map((vector) => { - const embedding = vector[vector.data]?.values; - if (!embedding) { - throw new LLMError("Missing embedding"); - } - return embedding; - }); - if (embeddings?.length !== texts.length) { - throw new LLMError("Missing embedding"); - } - return embeddings; - }), - ); - return { embeddings: results.flat() }; - } - - async tokenize(input: LLMInput): Promise { - try { - const response = await this.client.tokenize({ - model_id: this.modelId, - requests: [{ text: input }], - }); - const output = response.responses.at(0); - if (!output) { - throw new LLMError("Missing output", [], { context: { response } }); - } - return { - tokens: output.tokens, - tokensCount: output.token_count, - }; - } catch (err) { - throw this._transformError(err); - } - } - - protected async _generate( - input: LLMInput, - options: IBMvLLMGenerateOptions | undefined, - run: GetRunContext, - ): Promise { - try { - const response = await this.client.generate( - { - model_id: this.modelId, - requests: [{ text: input }], - params: this._prepareParameters(options), - }, - { signal: run.signal }, - ); - const output = response.responses.at(0); - if (!output) { - throw new LLMError("Missing output", [], { context: { response } }); - } - - const { text, ...rest } = output; - return new IBMvLLMOutput(text, rest); - } catch (err) { - throw this._transformError(err); - } - } - - protected async *_stream( - input: string, - options: IBMvLLMGenerateOptions | undefined, - run: GetRunContext, - ): AsyncStream { - try { - const stream = await this.client.generateStream( - { - model_id: this.modelId, - request: { text: input }, - params: this._prepareParameters(options), - }, - { signal: run.signal }, - ); - for await (const chunk of stream) { - const typedChunk = chunk as GenerationResponse__Output; - const { text, ...rest } = typedChunk; - if (text.length > 0) { - yield new IBMvLLMOutput(text, rest); - } - } - } catch (err) { - throw this._transformError(err); - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - client: this.client, - modelId: this.modelId, - parameters: shallowCopy(this.parameters), - executionOptions: shallowCopy(this.executionOptions), - }; - } - - loadSnapshot(snapshot: ReturnType) { - super.loadSnapshot(snapshot); - Object.assign(this, snapshot); - } - - protected _transformError(error: Error): Error { - if (error instanceof FrameworkError) { - throw error; - } - if (isGrpcServiceError(error)) { - throw new LLMError("LLM has occurred an error!", [error], { - isRetryable: [8, 4, 14].includes(error.code), - }); - } - return new LLMError("LLM has occurred an error!", [error]); - } - - protected _prepareParameters(overrides?: GenerateOptions): typeof this.parameters { - const guided: DecodingParameters = omitUndefined( - overrides?.guided ? {} : (this.parameters.decoding ?? {}), - ); - const guidedOverride: GuidedOptions = omitUndefined(overrides?.guided ?? {}); - - if (guidedOverride?.choice) { - guided.choice = { ...guided.choice, choices: guidedOverride.choice }; - } else if (guidedOverride?.grammar) { - guided.grammar = guidedOverride.grammar; - } else if (guidedOverride?.json) { - guided.json_schema = isString(guidedOverride.json) - ? guidedOverride.json - : JSON.stringify(guidedOverride.json); - } else if (guidedOverride?.regex) { - guided.regex = guidedOverride.regex; - } else if (!isEmpty(guidedOverride ?? {})) { - throw new NotImplementedError( - `Following types ${Object.keys(overrides!.guided!).join(",")}" for the constraint decoding are not supported!`, - ); - } - - return { - ...this.parameters, - decoding: guided, - }; - } -} diff --git a/src/adapters/ibm-vllm/proto/caikit_data_model_caikit_nlp.proto b/src/adapters/ibm-vllm/proto/caikit_data_model_caikit_nlp.proto deleted file mode 100644 index ca253f57..00000000 --- a/src/adapters/ibm-vllm/proto/caikit_data_model_caikit_nlp.proto +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2025 IBM Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Source: https://github.com/IBM/vllm/blob/main/proto/caikit_data_model_caikit_nlp.proto - -/*------------------------------------------------------------------------------ - * AUTO GENERATED - *----------------------------------------------------------------------------*/ - -syntax = "proto3"; -package caikit_data_model.caikit_nlp; -import "google/protobuf/struct.proto"; -import "caikit_data_model_common.proto"; - - -/*-- MESSAGES ----------------------------------------------------------------*/ - -message EmbeddingResult { - - /*-- fields --*/ - caikit_data_model.common.Vector1D result = 1; - caikit_data_model.common.ProducerId producer_id = 2; - int64 input_token_count = 3; -} - -message EmbeddingResults { - - /*-- fields --*/ - caikit_data_model.common.ListOfVector1D results = 1; - caikit_data_model.common.ProducerId producer_id = 2; - int64 input_token_count = 3; -} - -message ExponentialDecayLengthPenalty { - - /*-- fields --*/ - int64 start_index = 1; - double decay_factor = 2; -} - -message GenerationTrainRecord { - - /*-- fields --*/ - string input = 1; - string output = 2; -} - -message RerankResult { - - /*-- fields --*/ - caikit_data_model.caikit_nlp.RerankScores result = 1; - caikit_data_model.common.ProducerId producer_id = 2; - int64 input_token_count = 3; -} - -message RerankResults { - - /*-- fields --*/ - repeated caikit_data_model.caikit_nlp.RerankScores results = 1; - caikit_data_model.common.ProducerId producer_id = 2; - int64 input_token_count = 3; -} - -message RerankScore { - - /*-- fields --*/ - google.protobuf.Struct document = 1; - int64 index = 2; - double score = 3; - string text = 4; -} - -message RerankScores { - - /*-- fields --*/ - string query = 1; - repeated caikit_data_model.caikit_nlp.RerankScore scores = 2; -} - -message SentenceSimilarityResult { - - /*-- fields --*/ - caikit_data_model.caikit_nlp.SentenceSimilarityScores result = 1; - caikit_data_model.common.ProducerId producer_id = 2; - int64 input_token_count = 3; -} - -message SentenceSimilarityResults { - - /*-- fields --*/ - repeated caikit_data_model.caikit_nlp.SentenceSimilarityScores results = 1; - caikit_data_model.common.ProducerId producer_id = 2; - int64 input_token_count = 3; -} - -message SentenceSimilarityScores { - - /*-- fields --*/ - repeated double scores = 1; -} - -message TuningConfig { - - /*-- fields --*/ - int64 num_virtual_tokens = 1; - string prompt_tuning_init_text = 2; - string prompt_tuning_init_method = 3; - string prompt_tuning_init_source_model = 4; - repeated string output_model_types = 5; -} diff --git a/src/adapters/ibm-vllm/proto/caikit_data_model_common.proto b/src/adapters/ibm-vllm/proto/caikit_data_model_common.proto deleted file mode 100644 index 6265b622..00000000 --- a/src/adapters/ibm-vllm/proto/caikit_data_model_common.proto +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2025 IBM Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Source: https://github.com/IBM/vllm/blob/main/proto/caikit_data_model_common.proto - -/*------------------------------------------------------------------------------ - * AUTO GENERATED - *----------------------------------------------------------------------------*/ - -syntax = "proto3"; -package caikit_data_model.common; - - -/*-- ENUMS -------------------------------------------------------------------*/ - -enum TrainingStatus { - PLACEHOLDER_UNSET = 0; - QUEUED = 1; - RUNNING = 2; - COMPLETED = 3; - CANCELED = 4; - ERRORED = 5; -} - - -/*-- MESSAGES ----------------------------------------------------------------*/ - -message BoolSequence { - - /*-- fields --*/ - repeated bool values = 1; -} - -message ConnectionInfo { - - /*-- nested messages --*/ - - /*-- fields --*/ - string hostname = 1; - optional int64 port = 2; - optional caikit_data_model.common.ConnectionTlsInfo tls = 3; - optional int64 timeout = 4; - map options = 5; -} - -message ConnectionTlsInfo { - - /*-- fields --*/ - optional bool enabled = 1; - optional bool insecure_verify = 2; - optional string ca_file = 3; - optional string cert_file = 4; - optional string key_file = 5; -} - -message Directory { - - /*-- fields --*/ - string dirname = 1; - string extension = 2; -} - -message File { - - /*-- fields --*/ - bytes data = 1; - string filename = 2; - string type = 3; -} - -message FileReference { - - /*-- fields --*/ - string filename = 1; -} - -message FloatSequence { - - /*-- fields --*/ - repeated double values = 1; -} - -message IntSequence { - - /*-- fields --*/ - repeated int64 values = 1; -} - -message ListOfFileReferences { - - /*-- fields --*/ - repeated string files = 1; -} - -message ListOfVector1D { - - /*-- fields --*/ - repeated caikit_data_model.common.Vector1D vectors = 1; -} - -message NpFloat32Sequence { - - /*-- fields --*/ - repeated float values = 1; -} - -message NpFloat64Sequence { - - /*-- fields --*/ - repeated double values = 1; -} - -message ProducerId { - - /*-- fields --*/ - string name = 1; - string version = 2; -} - -message ProducerPriority { - - /*-- fields --*/ - repeated caikit_data_model.common.ProducerId producers = 1; -} - -message PyFloatSequence { - - /*-- fields --*/ - repeated double values = 1; -} - -message S3Base { - - /*-- fields --*/ - string endpoint = 2; - string region = 3; - string bucket = 4; - string accessKey = 5; - string secretKey = 6; - string IAM_id = 7; - string IAM_api_key = 8; -} - -message S3Files { - - /*-- fields --*/ - string endpoint = 2; - string region = 3; - string bucket = 4; - string accessKey = 5; - string secretKey = 6; - string IAM_id = 7; - string IAM_api_key = 8; - repeated string files = 1; -} - -message S3Path { - - /*-- fields --*/ - string endpoint = 2; - string region = 3; - string bucket = 4; - string accessKey = 5; - string secretKey = 6; - string IAM_id = 7; - string IAM_api_key = 8; - string path = 1; -} - -message StrSequence { - - /*-- fields --*/ - repeated string values = 1; -} - -message Vector1D { - - /*-- fields --*/ - - /*-- oneofs --*/ - oneof data { - caikit_data_model.common.PyFloatSequence data_pyfloatsequence = 1; - caikit_data_model.common.NpFloat32Sequence data_npfloat32sequence = 2; - caikit_data_model.common.NpFloat64Sequence data_npfloat64sequence = 3; - } -} diff --git a/src/adapters/ibm-vllm/proto/caikit_data_model_nlp.proto b/src/adapters/ibm-vllm/proto/caikit_data_model_nlp.proto deleted file mode 100644 index 0396927b..00000000 --- a/src/adapters/ibm-vllm/proto/caikit_data_model_nlp.proto +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2025 IBM Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Source: https://github.com/IBM/vllm/blob/main/proto/caikit_data_model_nlp.proto - -/*------------------------------------------------------------------------------ - * AUTO GENERATED - *----------------------------------------------------------------------------*/ - -syntax = "proto3"; -package caikit_data_model.nlp; -import "caikit_data_model_common.proto"; - - -/*-- ENUMS -------------------------------------------------------------------*/ - -enum FinishReason { - NOT_FINISHED = 0; - MAX_TOKENS = 1; - EOS_TOKEN = 2; - CANCELLED = 3; - TIME_LIMIT = 4; - STOP_SEQUENCE = 5; - TOKEN_LIMIT = 6; - ERROR = 7; -} - -enum InputWarningReason { - UNSUITABLE_INPUT = 0; -} - - -/*-- MESSAGES ----------------------------------------------------------------*/ - -message ClassificationResult { - - /*-- fields --*/ - string label = 1; - double score = 2; -} - -message ClassificationResults { - - /*-- fields --*/ - repeated caikit_data_model.nlp.ClassificationResult results = 1; -} - -message ClassificationTrainRecord { - - /*-- fields --*/ - string text = 1; - repeated string labels = 2; -} - -message ClassifiedGeneratedTextResult { - - /*-- fields --*/ - string generated_text = 1; - caikit_data_model.nlp.TextGenTokenClassificationResults token_classification_results = 2; - caikit_data_model.nlp.FinishReason finish_reason = 3; - int64 generated_token_count = 4; - uint64 seed = 5; - int64 input_token_count = 6; - repeated caikit_data_model.nlp.InputWarning warnings = 9; - repeated caikit_data_model.nlp.GeneratedToken tokens = 10; - repeated caikit_data_model.nlp.GeneratedToken input_tokens = 11; -} - -message ClassifiedGeneratedTextStreamResult { - - /*-- fields --*/ - string generated_text = 1; - caikit_data_model.nlp.TextGenTokenClassificationResults token_classification_results = 2; - caikit_data_model.nlp.FinishReason finish_reason = 3; - int64 generated_token_count = 4; - uint64 seed = 5; - int64 input_token_count = 6; - repeated caikit_data_model.nlp.InputWarning warnings = 9; - repeated caikit_data_model.nlp.GeneratedToken tokens = 10; - repeated caikit_data_model.nlp.GeneratedToken input_tokens = 11; - int64 processed_index = 7; - int64 start_index = 8; -} - -message GeneratedTextResult { - - /*-- fields --*/ - string generated_text = 1; - int64 generated_tokens = 2; - caikit_data_model.nlp.FinishReason finish_reason = 3; - caikit_data_model.common.ProducerId producer_id = 4; - int64 input_token_count = 5; - uint64 seed = 6; - repeated caikit_data_model.nlp.GeneratedToken tokens = 7; - repeated caikit_data_model.nlp.GeneratedToken input_tokens = 8; -} - -message GeneratedTextStreamResult { - - /*-- fields --*/ - string generated_text = 1; - repeated caikit_data_model.nlp.GeneratedToken tokens = 2; - caikit_data_model.nlp.TokenStreamDetails details = 3; - caikit_data_model.common.ProducerId producer_id = 4; - repeated caikit_data_model.nlp.GeneratedToken input_tokens = 5; -} - -message GeneratedToken { - - /*-- fields --*/ - string text = 1; - double logprob = 3; -} - -message InputWarning { - - /*-- fields --*/ - caikit_data_model.nlp.InputWarningReason id = 1; - string message = 2; -} - -message TextGenTokenClassificationResults { - - /*-- fields --*/ - repeated caikit_data_model.nlp.TokenClassificationResult input = 10; - repeated caikit_data_model.nlp.TokenClassificationResult output = 20; -} - -message Token { - - /*-- fields --*/ - int64 start = 1; - int64 end = 2; - string text = 3; -} - -message TokenClassificationResult { - - /*-- fields --*/ - int64 start = 1; - int64 end = 2; - string word = 3; - string entity = 4; - string entity_group = 5; - double score = 6; - int64 token_count = 7; -} - -message TokenClassificationResults { - - /*-- fields --*/ - repeated caikit_data_model.nlp.TokenClassificationResult results = 1; -} - -message TokenClassificationStreamResult { - - /*-- fields --*/ - repeated caikit_data_model.nlp.TokenClassificationResult results = 1; - int64 processed_index = 2; - int64 start_index = 3; -} - -message TokenStreamDetails { - - /*-- fields --*/ - caikit_data_model.nlp.FinishReason finish_reason = 1; - uint32 generated_tokens = 2; - uint64 seed = 3; - int64 input_token_count = 4; -} - -message TokenizationResults { - - /*-- fields --*/ - repeated caikit_data_model.nlp.Token results = 1; - int64 token_count = 4; -} - -message TokenizationStreamResult { - - /*-- fields --*/ - repeated caikit_data_model.nlp.Token results = 1; - int64 token_count = 4; - int64 processed_index = 2; - int64 start_index = 3; -} diff --git a/src/adapters/ibm-vllm/proto/caikit_data_model_runtime.proto b/src/adapters/ibm-vllm/proto/caikit_data_model_runtime.proto deleted file mode 100644 index 569057f6..00000000 --- a/src/adapters/ibm-vllm/proto/caikit_data_model_runtime.proto +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2025 IBM Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Source: https://github.com/IBM/vllm/blob/main/proto/caikit_data_model_runtime.proto - -/*------------------------------------------------------------------------------ - * AUTO GENERATED - *----------------------------------------------------------------------------*/ - -syntax = "proto3"; -package caikit_data_model.runtime; -import "google/protobuf/timestamp.proto"; -import "caikit_data_model_common.proto"; - - -/*-- MESSAGES ----------------------------------------------------------------*/ - -message ModelPointer { - - /*-- fields --*/ - string model_id = 1; -} - -message TrainingInfoRequest { - - /*-- fields --*/ - string training_id = 1; -} - -message TrainingJob { - - /*-- fields --*/ - string training_id = 1; - string model_name = 2; -} - -message TrainingStatusResponse { - - /*-- fields --*/ - string training_id = 1; - caikit_data_model.common.TrainingStatus state = 2; - google.protobuf.Timestamp submission_timestamp = 3; - google.protobuf.Timestamp completion_timestamp = 4; - repeated string reasons = 5; -} diff --git a/src/adapters/ibm-vllm/proto/caikit_runtime_Nlp.proto b/src/adapters/ibm-vllm/proto/caikit_runtime_Nlp.proto deleted file mode 100644 index 413e7bbb..00000000 --- a/src/adapters/ibm-vllm/proto/caikit_runtime_Nlp.proto +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2025 IBM Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Source: https://github.com/IBM/vllm/blob/main/proto/caikit_runtime_Nlp.proto - -/*------------------------------------------------------------------------------ - * AUTO GENERATED - *----------------------------------------------------------------------------*/ - -syntax = "proto3"; -package caikit.runtime.Nlp; -import "google/protobuf/struct.proto"; -import "caikit_data_model_caikit_nlp.proto"; -import "caikit_data_model_common.proto"; -import "caikit_data_model_nlp.proto"; -import "caikit_data_model_runtime.proto"; - - -/*-- MESSAGES ----------------------------------------------------------------*/ - -message BidiStreamingTokenClassificationTaskRequest { - - /*-- fields --*/ - string text_stream = 1; - optional double threshold = 2; -} - -message DataStreamSourceGenerationTrainRecord { - - /*-- fields --*/ - - /*-- oneofs --*/ - oneof data_stream { - caikit.runtime.Nlp.DataStreamSourceGenerationTrainRecordJsonData jsondata = 1; - caikit_data_model.common.FileReference file = 2; - caikit_data_model.common.ListOfFileReferences list_of_files = 3; - caikit_data_model.common.Directory directory = 4; - caikit_data_model.common.S3Files s3files = 5; - } -} - -message DataStreamSourceGenerationTrainRecordJsonData { - - /*-- fields --*/ - repeated caikit_data_model.caikit_nlp.GenerationTrainRecord data = 1; -} - -message EmbeddingTaskRequest { - - /*-- fields --*/ - string text = 1; - optional int64 truncate_input_tokens = 2; -} - -message EmbeddingTasksRequest { - - /*-- fields --*/ - repeated string texts = 1; - optional int64 truncate_input_tokens = 2; -} - -message RerankTaskRequest { - - /*-- fields --*/ - string query = 1; - repeated google.protobuf.Struct documents = 2; - optional int64 top_n = 3; - optional int64 truncate_input_tokens = 4; - optional bool return_documents = 5; - optional bool return_query = 6; - optional bool return_text = 7; -} - -message RerankTasksRequest { - - /*-- fields --*/ - repeated string queries = 1; - repeated google.protobuf.Struct documents = 2; - optional int64 top_n = 3; - optional int64 truncate_input_tokens = 4; - optional bool return_documents = 5; - optional bool return_queries = 6; - optional bool return_text = 7; -} - -message SentenceSimilarityTaskRequest { - - /*-- fields --*/ - string source_sentence = 1; - repeated string sentences = 2; - optional int64 truncate_input_tokens = 3; -} - -message SentenceSimilarityTasksRequest { - - /*-- fields --*/ - repeated string source_sentences = 1; - repeated string sentences = 2; - optional int64 truncate_input_tokens = 3; -} - -message ServerStreamingTextGenerationTaskRequest { - - /*-- fields --*/ - string text = 1; - optional int64 max_new_tokens = 2; - optional int64 min_new_tokens = 3; - optional int64 truncate_input_tokens = 4; - optional string decoding_method = 5; - optional int64 top_k = 6; - optional double top_p = 7; - optional double typical_p = 8; - optional double temperature = 9; - optional double repetition_penalty = 10; - optional double max_time = 11; - optional caikit_data_model.caikit_nlp.ExponentialDecayLengthPenalty exponential_decay_length_penalty = 12; - repeated string stop_sequences = 13; - optional uint64 seed = 14; - optional bool preserve_input_text = 15; -} - -message TextClassificationTaskRequest { - - /*-- fields --*/ - string text = 1; -} - -message TextGenerationTaskPeftPromptTuningTrainParameters { - - /*-- fields --*/ - string base_model = 1; - caikit.runtime.Nlp.DataStreamSourceGenerationTrainRecord train_stream = 2; - caikit_data_model.caikit_nlp.TuningConfig tuning_config = 3; - optional caikit.runtime.Nlp.DataStreamSourceGenerationTrainRecord val_stream = 4; - optional string device = 5; - optional string tuning_type = 6; - optional int64 num_epochs = 7; - optional double learning_rate = 8; - optional string verbalizer = 9; - optional int64 batch_size = 10; - optional int64 max_source_length = 11; - optional int64 max_target_length = 12; - optional int64 accumulate_steps = 13; - optional string torch_dtype = 14; - optional bool silence_progress_bars = 15; - optional int64 seed = 16; -} - -message TextGenerationTaskPeftPromptTuningTrainRequest { - - /*-- fields --*/ - string model_name = 1; - caikit_data_model.common.S3Path output_path = 2; - caikit.runtime.Nlp.TextGenerationTaskPeftPromptTuningTrainParameters parameters = 3; -} - -message TextGenerationTaskRequest { - - /*-- fields --*/ - string text = 1; - optional int64 max_new_tokens = 2; - optional int64 min_new_tokens = 3; - optional int64 truncate_input_tokens = 4; - optional string decoding_method = 5; - optional int64 top_k = 6; - optional double top_p = 7; - optional double typical_p = 8; - optional double temperature = 9; - optional double repetition_penalty = 10; - optional double max_time = 11; - optional caikit_data_model.caikit_nlp.ExponentialDecayLengthPenalty exponential_decay_length_penalty = 12; - repeated string stop_sequences = 13; - optional uint64 seed = 14; - optional bool preserve_input_text = 15; -} - -message TextGenerationTaskTextGenerationTrainParameters { - - /*-- fields --*/ - string base_model = 1; - caikit.runtime.Nlp.DataStreamSourceGenerationTrainRecord train_stream = 2; - optional string torch_dtype = 3; - optional int64 max_source_length = 4; - optional int64 max_target_length = 5; - optional int64 batch_size = 6; - optional int64 num_epochs = 7; - optional int64 accumulate_steps = 8; - optional int64 random_seed = 9; - optional double lr = 10; - optional bool use_iterable_dataset = 11; -} - -message TextGenerationTaskTextGenerationTrainRequest { - - /*-- fields --*/ - string model_name = 1; - caikit_data_model.common.S3Path output_path = 2; - caikit.runtime.Nlp.TextGenerationTaskTextGenerationTrainParameters parameters = 3; -} - -message TokenClassificationTaskRequest { - - /*-- fields --*/ - string text = 1; - optional double threshold = 2; -} - -message TokenizationTaskRequest { - - /*-- fields --*/ - string text = 1; -} - - -/*-- SERVICES ----------------------------------------------------------------*/ - -service NlpService { - rpc BidiStreamingTokenClassificationTaskPredict(stream caikit.runtime.Nlp.BidiStreamingTokenClassificationTaskRequest) returns (stream caikit_data_model.nlp.TokenClassificationStreamResult); - rpc EmbeddingTaskPredict(caikit.runtime.Nlp.EmbeddingTaskRequest) returns (caikit_data_model.caikit_nlp.EmbeddingResult); - rpc EmbeddingTasksPredict(caikit.runtime.Nlp.EmbeddingTasksRequest) returns (caikit_data_model.caikit_nlp.EmbeddingResults); - rpc RerankTaskPredict(caikit.runtime.Nlp.RerankTaskRequest) returns (caikit_data_model.caikit_nlp.RerankResult); - rpc RerankTasksPredict(caikit.runtime.Nlp.RerankTasksRequest) returns (caikit_data_model.caikit_nlp.RerankResults); - rpc SentenceSimilarityTaskPredict(caikit.runtime.Nlp.SentenceSimilarityTaskRequest) returns (caikit_data_model.caikit_nlp.SentenceSimilarityResult); - rpc SentenceSimilarityTasksPredict(caikit.runtime.Nlp.SentenceSimilarityTasksRequest) returns (caikit_data_model.caikit_nlp.SentenceSimilarityResults); - rpc ServerStreamingTextGenerationTaskPredict(caikit.runtime.Nlp.ServerStreamingTextGenerationTaskRequest) returns (stream caikit_data_model.nlp.GeneratedTextStreamResult); - rpc TextClassificationTaskPredict(caikit.runtime.Nlp.TextClassificationTaskRequest) returns (caikit_data_model.nlp.ClassificationResults); - rpc TextGenerationTaskPredict(caikit.runtime.Nlp.TextGenerationTaskRequest) returns (caikit_data_model.nlp.GeneratedTextResult); - rpc TokenClassificationTaskPredict(caikit.runtime.Nlp.TokenClassificationTaskRequest) returns (caikit_data_model.nlp.TokenClassificationResults); - rpc TokenizationTaskPredict(caikit.runtime.Nlp.TokenizationTaskRequest) returns (caikit_data_model.nlp.TokenizationResults); -} - -service NlpTrainingService { - rpc TextGenerationTaskPeftPromptTuningTrain(caikit.runtime.Nlp.TextGenerationTaskPeftPromptTuningTrainRequest) returns (caikit_data_model.runtime.TrainingJob); - rpc TextGenerationTaskTextGenerationTrain(caikit.runtime.Nlp.TextGenerationTaskTextGenerationTrainRequest) returns (caikit_data_model.runtime.TrainingJob); -} diff --git a/src/adapters/ibm-vllm/proto/generation.proto b/src/adapters/ibm-vllm/proto/generation.proto deleted file mode 100644 index 14ac3b1b..00000000 --- a/src/adapters/ibm-vllm/proto/generation.proto +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2025 IBM Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Source: https://github.com/IBM/vllm/blob/main/proto/generation.proto - -syntax = "proto3"; -package fmaas; - - -service GenerationService { - // Generates text given a text prompt, for one or more inputs - rpc Generate (BatchedGenerationRequest) returns (BatchedGenerationResponse) {} - // Generates text given a single input prompt, streaming the response - rpc GenerateStream (SingleGenerationRequest) returns (stream GenerationResponse) {} - // Tokenize text - rpc Tokenize (BatchedTokenizeRequest) returns (BatchedTokenizeResponse) {} - // Model info - rpc ModelInfo (ModelInfoRequest) returns (ModelInfoResponse) {} -} - -// ============================================================================================================ -// Generation API - -enum DecodingMethod { - GREEDY = 0; - SAMPLE = 1; -} - -message BatchedGenerationRequest { - string model_id = 1; - // Deprecated in favor of adapter_id - optional string prefix_id = 2; - optional string adapter_id = 4; - repeated GenerationRequest requests = 3; - - Parameters params = 10; -} - -message SingleGenerationRequest { - string model_id = 1; - // Deprecated in favor of adapter_id - optional string prefix_id = 2; - optional string adapter_id = 4; - GenerationRequest request = 3; - - Parameters params = 10; -} - -message BatchedGenerationResponse { - repeated GenerationResponse responses = 1; -} - -message GenerationRequest { - string text = 2; -} - -message GenerationResponse { - uint32 input_token_count = 6; - uint32 generated_token_count = 2; - string text = 4; - StopReason stop_reason = 7; - // The stop sequence encountered, iff stop_reason == STOP_SEQUENCE - string stop_sequence = 11; - // Random seed used, not applicable for greedy requests - uint64 seed = 10; - - // Individual generated tokens and associated details, if requested - repeated TokenInfo tokens = 8; - - // Input tokens and associated details, if requested - repeated TokenInfo input_tokens = 9; -} - -message Parameters { - // The high level decoding approach - DecodingMethod method = 1; - // Parameters related to sampling, applicable only when method == SAMPLING - SamplingParameters sampling = 2; - // Parameters controlling when generation should stop - StoppingCriteria stopping = 3; - // Flags to control what is returned in the response - ResponseOptions response = 4; - // Parameters for conditionally penalizing/boosting - // candidate tokens during decoding - DecodingParameters decoding = 5; - // Truncate to this many input tokens. Can be used to avoid requests - // failing due to input being longer than configured limits. - // Zero means don't truncate. - uint32 truncate_input_tokens = 6; -} - -message DecodingParameters { - message LengthPenalty { - // Start the decay after this number of tokens have been generated - uint32 start_index = 1; - // Factor of exponential decay - float decay_factor = 2; - } - - // Default (0.0) means no penalty (equivalent to 1.0) - // 1.2 is a recommended value - float repetition_penalty = 1; - - // Exponentially increases the score of the EOS token - // once start_index tokens have been generated - optional LengthPenalty length_penalty = 2; - - enum ResponseFormat { - // Plain text, no constraints - TEXT = 0; - // Valid json - JSON = 1; - } - - message StringChoices { - repeated string choices = 1; - } - - // Mutually-exclusive guided decoding options - oneof guided { - // Output will be in the specified format - ResponseFormat format = 3; - // Output will follow the provided JSON schema - string json_schema = 4; - // Output will follow the provided regex pattern - string regex = 5; - // Output will be exactly one of the specified choices - StringChoices choice = 6; - // Output will follow the provided context free grammar - string grammar = 7; - } -} - - -message SamplingParameters { - // Default (0.0) means disabled (equivalent to 1.0) - float temperature = 1; - // Default (0) means disabled - uint32 top_k = 2; - // Default (0) means disabled (equivalent to 1.0) - float top_p = 3; - // Default (0) means disabled (equivalent to 1.0) - float typical_p = 4; - - optional uint64 seed = 5; -} - -message StoppingCriteria { - // Default (0) is currently 20 - uint32 max_new_tokens = 1; - // Default (0) means no minimum - uint32 min_new_tokens = 2; - // Default (0) means no time limit - uint32 time_limit_millis = 3; - repeated string stop_sequences = 4; - // If not specified, default behavior depends on server setting - optional bool include_stop_sequence = 5; - - //more to come -} - -message ResponseOptions { - // Include input text - bool input_text = 1; - // Include list of individual generated tokens - // "Extra" token information is included based on the other flags below - bool generated_tokens = 2; - // Include list of input tokens - // "Extra" token information is included based on the other flags here, - // but only for decoder-only models - bool input_tokens = 3; - // Include logprob for each returned token - // Applicable only if generated_tokens == true and/or input_tokens == true - bool token_logprobs = 4; - // Include rank of each returned token - // Applicable only if generated_tokens == true and/or input_tokens == true - bool token_ranks = 5; - // Include top n candidate tokens at the position of each returned token - // The maximum value permitted is 5, but more may be returned if there is a tie - // for nth place. - // Applicable only if generated_tokens == true and/or input_tokens == true - uint32 top_n_tokens = 6; -} - -enum StopReason { - // Possibly more tokens to be streamed - NOT_FINISHED = 0; - // Maximum requested tokens reached - MAX_TOKENS = 1; - // End-of-sequence token encountered - EOS_TOKEN = 2; - // Request cancelled by client - CANCELLED = 3; - // Time limit reached - TIME_LIMIT = 4; - // Stop sequence encountered - STOP_SEQUENCE = 5; - // Total token limit reached - TOKEN_LIMIT = 6; - // Decoding error - ERROR = 7; -} - -message TokenInfo { - // uint32 id = 1; // TBD - string text = 2; - // The logprob (log of normalized probability), if requested - float logprob = 3; - // One-based rank relative to other tokens, if requested - uint32 rank = 4; - - message TopToken { - // uint32 id = 1; // TBD - string text = 2; - float logprob = 3; - } - - // Top N candidate tokens at this position, if requested - // May or may not include this token - repeated TopToken top_tokens = 5; -} - - -// ============================================================================================================ -// Tokenization API - -message BatchedTokenizeRequest { - string model_id = 1; - repeated TokenizeRequest requests = 2; - bool return_tokens = 3; - bool return_offsets = 4; - - // Zero means don't truncate. - uint32 truncate_input_tokens = 5; -} - -message BatchedTokenizeResponse { - repeated TokenizeResponse responses = 1; -} - -message TokenizeRequest { - string text = 1; -} - -message TokenizeResponse { - message Offset { - uint32 start = 1; - uint32 end = 2; - } - - uint32 token_count = 1; - - // if return_tokens = true - repeated string tokens = 2; - // if return_tokens = true - repeated Offset offsets = 3; -} - - -// ============================================================================================================ -// Model Info API - -message ModelInfoRequest { - string model_id = 1; -} - -message ModelInfoResponse { - enum ModelKind { - DECODER_ONLY = 0; - ENCODER_DECODER = 1; - } - - ModelKind model_kind = 1; - uint32 max_sequence_length = 2; - uint32 max_new_tokens = 3; -} diff --git a/src/adapters/ibm-vllm/types.ts b/src/adapters/ibm-vllm/types.ts deleted file mode 100644 index 3e2b3579..00000000 --- a/src/adapters/ibm-vllm/types.ts +++ /dev/null @@ -1,2133 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as grpc from "@grpc/grpc-js"; -import { - Long, - MethodDefinition, - MessageTypeDefinition, - EnumTypeDefinition, -} from "@grpc/proto-loader"; - -export interface BidiStreamingTokenClassificationTaskRequest { - text_stream?: string; - threshold?: number | string; - _threshold?: "threshold"; -} -export interface BidiStreamingTokenClassificationTaskRequest__Output { - text_stream: string; - threshold?: number; - _threshold: "threshold"; -} - -export interface ClassificationResult { - label?: string; - score?: number | string; -} -export interface ClassificationResult__Output { - label: string; - score: number; -} - -export interface ClassificationResults { - results?: ClassificationResult[]; -} -export interface ClassificationResults__Output { - results: ClassificationResult__Output[]; -} - -export interface PyFloatSequence { - values?: (number | string)[]; -} -export interface PyFloatSequence__Output { - values: number[]; -} - -export interface NpFloat32Sequence { - values?: (number | string)[]; -} -export interface NpFloat32Sequence__Output { - values: number[]; -} - -export interface NpFloat64Sequence { - values?: (number | string)[]; -} -export interface NpFloat64Sequence__Output { - values: number[]; -} - -export interface Vector1D { - data_pyfloatsequence?: PyFloatSequence | null; - data_npfloat32sequence?: NpFloat32Sequence | null; - data_npfloat64sequence?: NpFloat64Sequence | null; - data?: "data_pyfloatsequence" | "data_npfloat32sequence" | "data_npfloat64sequence"; -} -export interface Vector1D__Output { - data_pyfloatsequence?: PyFloatSequence__Output | null; - data_npfloat32sequence?: NpFloat32Sequence__Output | null; - data_npfloat64sequence?: NpFloat64Sequence__Output | null; - data: "data_pyfloatsequence" | "data_npfloat32sequence" | "data_npfloat64sequence"; -} - -export interface ProducerId { - name?: string; - version?: string; -} -export interface ProducerId__Output { - name: string; - version: string; -} - -export interface EmbeddingResult { - result?: Vector1D | null; - producer_id?: ProducerId | null; - input_token_count?: number | string | Long; -} -export interface EmbeddingResult__Output { - result: Vector1D__Output | null; - producer_id: ProducerId__Output | null; - input_token_count: number; -} - -export interface ListOfVector1D { - vectors?: Vector1D[]; -} -export interface ListOfVector1D__Output { - vectors: Vector1D__Output[]; -} - -export interface EmbeddingResults { - results?: ListOfVector1D | null; - producer_id?: ProducerId | null; - input_token_count?: number | string | Long; -} -export interface EmbeddingResults__Output { - results: ListOfVector1D__Output | null; - producer_id: ProducerId__Output | null; - input_token_count: number; -} - -export interface EmbeddingTaskRequest { - text?: string; - truncate_input_tokens?: number | string | Long; - _truncate_input_tokens?: "truncate_input_tokens"; -} -export interface EmbeddingTaskRequest__Output { - text: string; - truncate_input_tokens?: number; - _truncate_input_tokens: "truncate_input_tokens"; -} - -export interface EmbeddingTasksRequest { - texts?: string[]; - truncate_input_tokens?: number | string | Long; - _truncate_input_tokens?: "truncate_input_tokens"; -} -export interface EmbeddingTasksRequest__Output { - texts: string[]; - truncate_input_tokens?: number; - _truncate_input_tokens: "truncate_input_tokens"; -} - -declare const FinishReason: { - readonly NOT_FINISHED: "NOT_FINISHED"; - readonly MAX_TOKENS: "MAX_TOKENS"; - readonly EOS_TOKEN: "EOS_TOKEN"; - readonly CANCELLED: "CANCELLED"; - readonly TIME_LIMIT: "TIME_LIMIT"; - readonly STOP_SEQUENCE: "STOP_SEQUENCE"; - readonly TOKEN_LIMIT: "TOKEN_LIMIT"; - readonly ERROR: "ERROR"; -}; -export type FinishReason = - | "NOT_FINISHED" - | 0 - | "MAX_TOKENS" - | 1 - | "EOS_TOKEN" - | 2 - | "CANCELLED" - | 3 - | "TIME_LIMIT" - | 4 - | "STOP_SEQUENCE" - | 5 - | "TOKEN_LIMIT" - | 6 - | "ERROR" - | 7; -export type FinishReason__Output = (typeof FinishReason)[keyof typeof FinishReason]; - -export interface GeneratedToken { - text?: string; - logprob?: number | string; -} -export interface GeneratedToken__Output { - text: string; - logprob: number; -} - -export interface GeneratedTextResult { - generated_text?: string; - generated_tokens?: number | string | Long; - finish_reason?: FinishReason; - producer_id?: ProducerId | null; - input_token_count?: number | string | Long; - seed?: number | string | Long; - tokens?: GeneratedToken[]; - input_tokens?: GeneratedToken[]; -} -export interface GeneratedTextResult__Output { - generated_text: string; - generated_tokens: number; - finish_reason: FinishReason__Output; - producer_id: ProducerId__Output | null; - input_token_count: number; - seed: number; - tokens: GeneratedToken__Output[]; - input_tokens: GeneratedToken__Output[]; -} - -export interface TokenStreamDetails { - finish_reason?: FinishReason; - generated_tokens?: number; - seed?: number | string | Long; - input_token_count?: number | string | Long; -} -export interface TokenStreamDetails__Output { - finish_reason: FinishReason__Output; - generated_tokens: number; - seed: number; - input_token_count: number; -} - -export interface GeneratedTextStreamResult { - generated_text?: string; - tokens?: GeneratedToken[]; - details?: TokenStreamDetails | null; - producer_id?: ProducerId | null; - input_tokens?: GeneratedToken[]; -} -export interface GeneratedTextStreamResult__Output { - generated_text: string; - tokens: GeneratedToken__Output[]; - details: TokenStreamDetails__Output | null; - producer_id: ProducerId__Output | null; - input_tokens: GeneratedToken__Output[]; -} - -declare const NullValue: { - readonly NULL_VALUE: "NULL_VALUE"; -}; -export type NullValue = "NULL_VALUE" | 0; -export type NullValue__Output = (typeof NullValue)[keyof typeof NullValue]; - -export interface ListValue { - values?: Value[]; -} -export interface ListValue__Output { - values: Value__Output[]; -} - -export interface Value { - nullValue?: NullValue; - numberValue?: number | string; - stringValue?: string; - boolValue?: boolean; - structValue?: Struct | null; - listValue?: ListValue | null; - kind?: "nullValue" | "numberValue" | "stringValue" | "boolValue" | "structValue" | "listValue"; -} -export interface Value__Output { - nullValue?: NullValue__Output; - numberValue?: number; - stringValue?: string; - boolValue?: boolean; - structValue?: Struct__Output | null; - listValue?: ListValue__Output | null; - kind: "nullValue" | "numberValue" | "stringValue" | "boolValue" | "structValue" | "listValue"; -} - -export interface Struct { - fields?: Record; -} -export interface Struct__Output { - fields: Record; -} - -export interface RerankScore { - document?: Struct | null; - index?: number | string | Long; - score?: number | string; - text?: string; -} -export interface RerankScore__Output { - document: Struct__Output | null; - index: number; - score: number; - text: string; -} - -export interface RerankScores { - query?: string; - scores?: RerankScore[]; -} -export interface RerankScores__Output { - query: string; - scores: RerankScore__Output[]; -} - -export interface RerankResult { - result?: RerankScores | null; - producer_id?: ProducerId | null; - input_token_count?: number | string | Long; -} -export interface RerankResult__Output { - result: RerankScores__Output | null; - producer_id: ProducerId__Output | null; - input_token_count: number; -} - -export interface RerankResults { - results?: RerankScores[]; - producer_id?: ProducerId | null; - input_token_count?: number | string | Long; -} -export interface RerankResults__Output { - results: RerankScores__Output[]; - producer_id: ProducerId__Output | null; - input_token_count: number; -} - -export interface RerankTaskRequest { - query?: string; - documents?: Struct[]; - top_n?: number | string | Long; - truncate_input_tokens?: number | string | Long; - return_documents?: boolean; - return_query?: boolean; - return_text?: boolean; - _top_n?: "top_n"; - _truncate_input_tokens?: "truncate_input_tokens"; - _return_documents?: "return_documents"; - _return_query?: "return_query"; - _return_text?: "return_text"; -} -export interface RerankTaskRequest__Output { - query: string; - documents: Struct__Output[]; - top_n?: number; - truncate_input_tokens?: number; - return_documents?: boolean; - return_query?: boolean; - return_text?: boolean; - _top_n: "top_n"; - _truncate_input_tokens: "truncate_input_tokens"; - _return_documents: "return_documents"; - _return_query: "return_query"; - _return_text: "return_text"; -} - -export interface RerankTasksRequest { - queries?: string[]; - documents?: Struct[]; - top_n?: number | string | Long; - truncate_input_tokens?: number | string | Long; - return_documents?: boolean; - return_queries?: boolean; - return_text?: boolean; - _top_n?: "top_n"; - _truncate_input_tokens?: "truncate_input_tokens"; - _return_documents?: "return_documents"; - _return_queries?: "return_queries"; - _return_text?: "return_text"; -} -export interface RerankTasksRequest__Output { - queries: string[]; - documents: Struct__Output[]; - top_n?: number; - truncate_input_tokens?: number; - return_documents?: boolean; - return_queries?: boolean; - return_text?: boolean; - _top_n: "top_n"; - _truncate_input_tokens: "truncate_input_tokens"; - _return_documents: "return_documents"; - _return_queries: "return_queries"; - _return_text: "return_text"; -} - -export interface SentenceSimilarityScores { - scores?: (number | string)[]; -} -export interface SentenceSimilarityScores__Output { - scores: number[]; -} - -export interface SentenceSimilarityResult { - result?: SentenceSimilarityScores | null; - producer_id?: ProducerId | null; - input_token_count?: number | string | Long; -} -export interface SentenceSimilarityResult__Output { - result: SentenceSimilarityScores__Output | null; - producer_id: ProducerId__Output | null; - input_token_count: number; -} - -export interface SentenceSimilarityResults { - results?: SentenceSimilarityScores[]; - producer_id?: ProducerId | null; - input_token_count?: number | string | Long; -} -export interface SentenceSimilarityResults__Output { - results: SentenceSimilarityScores__Output[]; - producer_id: ProducerId__Output | null; - input_token_count: number; -} - -export interface SentenceSimilarityTaskRequest { - source_sentence?: string; - sentences?: string[]; - truncate_input_tokens?: number | string | Long; - _truncate_input_tokens?: "truncate_input_tokens"; -} -export interface SentenceSimilarityTaskRequest__Output { - source_sentence: string; - sentences: string[]; - truncate_input_tokens?: number; - _truncate_input_tokens: "truncate_input_tokens"; -} - -export interface SentenceSimilarityTasksRequest { - source_sentences?: string[]; - sentences?: string[]; - truncate_input_tokens?: number | string | Long; - _truncate_input_tokens?: "truncate_input_tokens"; -} -export interface SentenceSimilarityTasksRequest__Output { - source_sentences: string[]; - sentences: string[]; - truncate_input_tokens?: number; - _truncate_input_tokens: "truncate_input_tokens"; -} - -export interface ExponentialDecayLengthPenalty { - start_index?: number | string | Long; - decay_factor?: number | string; -} -export interface ExponentialDecayLengthPenalty__Output { - start_index: number; - decay_factor: number; -} - -export interface ServerStreamingTextGenerationTaskRequest { - text?: string; - max_new_tokens?: number | string | Long; - min_new_tokens?: number | string | Long; - truncate_input_tokens?: number | string | Long; - decoding_method?: string; - top_k?: number | string | Long; - top_p?: number | string; - typical_p?: number | string; - temperature?: number | string; - repetition_penalty?: number | string; - max_time?: number | string; - exponential_decay_length_penalty?: ExponentialDecayLengthPenalty | null; - stop_sequences?: string[]; - seed?: number | string | Long; - preserve_input_text?: boolean; - _max_new_tokens?: "max_new_tokens"; - _min_new_tokens?: "min_new_tokens"; - _truncate_input_tokens?: "truncate_input_tokens"; - _decoding_method?: "decoding_method"; - _top_k?: "top_k"; - _top_p?: "top_p"; - _typical_p?: "typical_p"; - _temperature?: "temperature"; - _repetition_penalty?: "repetition_penalty"; - _max_time?: "max_time"; - _exponential_decay_length_penalty?: "exponential_decay_length_penalty"; - _seed?: "seed"; - _preserve_input_text?: "preserve_input_text"; -} -export interface ServerStreamingTextGenerationTaskRequest__Output { - text: string; - max_new_tokens?: number; - min_new_tokens?: number; - truncate_input_tokens?: number; - decoding_method?: string; - top_k?: number; - top_p?: number; - typical_p?: number; - temperature?: number; - repetition_penalty?: number; - max_time?: number; - exponential_decay_length_penalty?: ExponentialDecayLengthPenalty__Output | null; - stop_sequences: string[]; - seed?: number; - preserve_input_text?: boolean; - _max_new_tokens: "max_new_tokens"; - _min_new_tokens: "min_new_tokens"; - _truncate_input_tokens: "truncate_input_tokens"; - _decoding_method: "decoding_method"; - _top_k: "top_k"; - _top_p: "top_p"; - _typical_p: "typical_p"; - _temperature: "temperature"; - _repetition_penalty: "repetition_penalty"; - _max_time: "max_time"; - _exponential_decay_length_penalty: "exponential_decay_length_penalty"; - _seed: "seed"; - _preserve_input_text: "preserve_input_text"; -} - -export interface TextClassificationTaskRequest { - text?: string; -} -export interface TextClassificationTaskRequest__Output { - text: string; -} - -export interface TextGenerationTaskRequest { - text?: string; - max_new_tokens?: number | string | Long; - min_new_tokens?: number | string | Long; - truncate_input_tokens?: number | string | Long; - decoding_method?: string; - top_k?: number | string | Long; - top_p?: number | string; - typical_p?: number | string; - temperature?: number | string; - repetition_penalty?: number | string; - max_time?: number | string; - exponential_decay_length_penalty?: ExponentialDecayLengthPenalty | null; - stop_sequences?: string[]; - seed?: number | string | Long; - preserve_input_text?: boolean; - _max_new_tokens?: "max_new_tokens"; - _min_new_tokens?: "min_new_tokens"; - _truncate_input_tokens?: "truncate_input_tokens"; - _decoding_method?: "decoding_method"; - _top_k?: "top_k"; - _top_p?: "top_p"; - _typical_p?: "typical_p"; - _temperature?: "temperature"; - _repetition_penalty?: "repetition_penalty"; - _max_time?: "max_time"; - _exponential_decay_length_penalty?: "exponential_decay_length_penalty"; - _seed?: "seed"; - _preserve_input_text?: "preserve_input_text"; -} -export interface TextGenerationTaskRequest__Output { - text: string; - max_new_tokens?: number; - min_new_tokens?: number; - truncate_input_tokens?: number; - decoding_method?: string; - top_k?: number; - top_p?: number; - typical_p?: number; - temperature?: number; - repetition_penalty?: number; - max_time?: number; - exponential_decay_length_penalty?: ExponentialDecayLengthPenalty__Output | null; - stop_sequences: string[]; - seed?: number; - preserve_input_text?: boolean; - _max_new_tokens: "max_new_tokens"; - _min_new_tokens: "min_new_tokens"; - _truncate_input_tokens: "truncate_input_tokens"; - _decoding_method: "decoding_method"; - _top_k: "top_k"; - _top_p: "top_p"; - _typical_p: "typical_p"; - _temperature: "temperature"; - _repetition_penalty: "repetition_penalty"; - _max_time: "max_time"; - _exponential_decay_length_penalty: "exponential_decay_length_penalty"; - _seed: "seed"; - _preserve_input_text: "preserve_input_text"; -} - -export interface TokenClassificationResult { - start?: number | string | Long; - end?: number | string | Long; - word?: string; - entity?: string; - entity_group?: string; - score?: number | string; - token_count?: number | string | Long; -} -export interface TokenClassificationResult__Output { - start: number; - end: number; - word: string; - entity: string; - entity_group: string; - score: number; - token_count: number; -} - -export interface TokenClassificationResults { - results?: TokenClassificationResult[]; -} -export interface TokenClassificationResults__Output { - results: TokenClassificationResult__Output[]; -} - -export interface TokenClassificationStreamResult { - results?: TokenClassificationResult[]; - processed_index?: number | string | Long; - start_index?: number | string | Long; -} -export interface TokenClassificationStreamResult__Output { - results: TokenClassificationResult__Output[]; - processed_index: number; - start_index: number; -} - -export interface TokenClassificationTaskRequest { - text?: string; - threshold?: number | string; - _threshold?: "threshold"; -} -export interface TokenClassificationTaskRequest__Output { - text: string; - threshold?: number; - _threshold: "threshold"; -} - -export interface Token { - start?: number | string | Long; - end?: number | string | Long; - text?: string; -} -export interface Token__Output { - start: number; - end: number; - text: string; -} - -export interface TokenizationResults { - results?: Token[]; - token_count?: number | string | Long; -} -export interface TokenizationResults__Output { - results: Token__Output[]; - token_count: number; -} - -export interface TokenizationTaskRequest { - text?: string; -} -export interface TokenizationTaskRequest__Output { - text: string; -} - -export interface NlpServiceClient extends grpc.Client { - BidiStreamingTokenClassificationTaskPredict( - metadata: grpc.Metadata, - options?: grpc.CallOptions, - ): grpc.ClientDuplexStream< - BidiStreamingTokenClassificationTaskRequest, - TokenClassificationStreamResult__Output - >; - BidiStreamingTokenClassificationTaskPredict( - options?: grpc.CallOptions, - ): grpc.ClientDuplexStream< - BidiStreamingTokenClassificationTaskRequest, - TokenClassificationStreamResult__Output - >; - bidiStreamingTokenClassificationTaskPredict( - metadata: grpc.Metadata, - options?: grpc.CallOptions, - ): grpc.ClientDuplexStream< - BidiStreamingTokenClassificationTaskRequest, - TokenClassificationStreamResult__Output - >; - bidiStreamingTokenClassificationTaskPredict( - options?: grpc.CallOptions, - ): grpc.ClientDuplexStream< - BidiStreamingTokenClassificationTaskRequest, - TokenClassificationStreamResult__Output - >; - EmbeddingTaskPredict( - argument: EmbeddingTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - EmbeddingTaskPredict( - argument: EmbeddingTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - EmbeddingTaskPredict( - argument: EmbeddingTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - EmbeddingTaskPredict( - argument: EmbeddingTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTaskPredict( - argument: EmbeddingTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTaskPredict( - argument: EmbeddingTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTaskPredict( - argument: EmbeddingTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTaskPredict( - argument: EmbeddingTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - EmbeddingTasksPredict( - argument: EmbeddingTasksRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - EmbeddingTasksPredict( - argument: EmbeddingTasksRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - EmbeddingTasksPredict( - argument: EmbeddingTasksRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - EmbeddingTasksPredict( - argument: EmbeddingTasksRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTasksPredict( - argument: EmbeddingTasksRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTasksPredict( - argument: EmbeddingTasksRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTasksPredict( - argument: EmbeddingTasksRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - embeddingTasksPredict( - argument: EmbeddingTasksRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTaskPredict( - argument: RerankTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTaskPredict( - argument: RerankTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTaskPredict( - argument: RerankTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTaskPredict( - argument: RerankTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTaskPredict( - argument: RerankTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTaskPredict( - argument: RerankTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTaskPredict( - argument: RerankTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTaskPredict( - argument: RerankTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTasksPredict( - argument: RerankTasksRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTasksPredict( - argument: RerankTasksRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTasksPredict( - argument: RerankTasksRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - RerankTasksPredict( - argument: RerankTasksRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTasksPredict( - argument: RerankTasksRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTasksPredict( - argument: RerankTasksRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTasksPredict( - argument: RerankTasksRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - rerankTasksPredict( - argument: RerankTasksRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTaskPredict( - argument: SentenceSimilarityTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - SentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - sentenceSimilarityTasksPredict( - argument: SentenceSimilarityTasksRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - ServerStreamingTextGenerationTaskPredict( - argument: ServerStreamingTextGenerationTaskRequest, - metadata: grpc.Metadata, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - ServerStreamingTextGenerationTaskPredict( - argument: ServerStreamingTextGenerationTaskRequest, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - serverStreamingTextGenerationTaskPredict( - argument: ServerStreamingTextGenerationTaskRequest, - metadata: grpc.Metadata, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - serverStreamingTextGenerationTaskPredict( - argument: ServerStreamingTextGenerationTaskRequest, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - TextClassificationTaskPredict( - argument: TextClassificationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextClassificationTaskPredict( - argument: TextClassificationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextClassificationTaskPredict( - argument: TextClassificationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextClassificationTaskPredict( - argument: TextClassificationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textClassificationTaskPredict( - argument: TextClassificationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textClassificationTaskPredict( - argument: TextClassificationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textClassificationTaskPredict( - argument: TextClassificationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textClassificationTaskPredict( - argument: TextClassificationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskPredict( - argument: TextGenerationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskPredict( - argument: TextGenerationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskPredict( - argument: TextGenerationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskPredict( - argument: TextGenerationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPredict( - argument: TextGenerationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPredict( - argument: TextGenerationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPredict( - argument: TextGenerationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPredict( - argument: TextGenerationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenClassificationTaskPredict( - argument: TokenClassificationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenizationTaskPredict( - argument: TokenizationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenizationTaskPredict( - argument: TokenizationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenizationTaskPredict( - argument: TokenizationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TokenizationTaskPredict( - argument: TokenizationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenizationTaskPredict( - argument: TokenizationTaskRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenizationTaskPredict( - argument: TokenizationTaskRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenizationTaskPredict( - argument: TokenizationTaskRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenizationTaskPredict( - argument: TokenizationTaskRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; -} -export interface NlpServiceDefinition extends grpc.ServiceDefinition { - BidiStreamingTokenClassificationTaskPredict: MethodDefinition< - BidiStreamingTokenClassificationTaskRequest, - TokenClassificationStreamResult, - BidiStreamingTokenClassificationTaskRequest__Output, - TokenClassificationStreamResult__Output - >; - EmbeddingTaskPredict: MethodDefinition< - EmbeddingTaskRequest, - EmbeddingResult, - EmbeddingTaskRequest__Output, - EmbeddingResult__Output - >; - EmbeddingTasksPredict: MethodDefinition< - EmbeddingTasksRequest, - EmbeddingResults, - EmbeddingTasksRequest__Output, - EmbeddingResults__Output - >; - RerankTaskPredict: MethodDefinition< - RerankTaskRequest, - RerankResult, - RerankTaskRequest__Output, - RerankResult__Output - >; - RerankTasksPredict: MethodDefinition< - RerankTasksRequest, - RerankResults, - RerankTasksRequest__Output, - RerankResults__Output - >; - SentenceSimilarityTaskPredict: MethodDefinition< - SentenceSimilarityTaskRequest, - SentenceSimilarityResult, - SentenceSimilarityTaskRequest__Output, - SentenceSimilarityResult__Output - >; - SentenceSimilarityTasksPredict: MethodDefinition< - SentenceSimilarityTasksRequest, - SentenceSimilarityResults, - SentenceSimilarityTasksRequest__Output, - SentenceSimilarityResults__Output - >; - ServerStreamingTextGenerationTaskPredict: MethodDefinition< - ServerStreamingTextGenerationTaskRequest, - GeneratedTextStreamResult, - ServerStreamingTextGenerationTaskRequest__Output, - GeneratedTextStreamResult__Output - >; - TextClassificationTaskPredict: MethodDefinition< - TextClassificationTaskRequest, - ClassificationResults, - TextClassificationTaskRequest__Output, - ClassificationResults__Output - >; - TextGenerationTaskPredict: MethodDefinition< - TextGenerationTaskRequest, - GeneratedTextResult, - TextGenerationTaskRequest__Output, - GeneratedTextResult__Output - >; - TokenClassificationTaskPredict: MethodDefinition< - TokenClassificationTaskRequest, - TokenClassificationResults, - TokenClassificationTaskRequest__Output, - TokenClassificationResults__Output - >; - TokenizationTaskPredict: MethodDefinition< - TokenizationTaskRequest, - TokenizationResults, - TokenizationTaskRequest__Output, - TokenizationResults__Output - >; -} - -export interface S3Path { - path?: string; - endpoint?: string; - region?: string; - bucket?: string; - accessKey?: string; - secretKey?: string; - IAM_id?: string; - IAM_api_key?: string; -} -export interface S3Path__Output { - path: string; - endpoint: string; - region: string; - bucket: string; - accessKey: string; - secretKey: string; - IAM_id: string; - IAM_api_key: string; -} - -export interface GenerationTrainRecord { - input?: string; - output?: string; -} -export interface GenerationTrainRecord__Output { - input: string; - output: string; -} - -export interface DataStreamSourceGenerationTrainRecordJsonData { - data?: GenerationTrainRecord[]; -} -export interface DataStreamSourceGenerationTrainRecordJsonData__Output { - data: GenerationTrainRecord__Output[]; -} - -export interface FileReference { - filename?: string; -} -export interface FileReference__Output { - filename: string; -} - -export interface ListOfFileReferences { - files?: string[]; -} -export interface ListOfFileReferences__Output { - files: string[]; -} - -export interface Directory { - dirname?: string; - extension?: string; -} -export interface Directory__Output { - dirname: string; - extension: string; -} - -export interface S3Files { - files?: string[]; - endpoint?: string; - region?: string; - bucket?: string; - accessKey?: string; - secretKey?: string; - IAM_id?: string; - IAM_api_key?: string; -} -export interface S3Files__Output { - files: string[]; - endpoint: string; - region: string; - bucket: string; - accessKey: string; - secretKey: string; - IAM_id: string; - IAM_api_key: string; -} - -export interface DataStreamSourceGenerationTrainRecord { - jsondata?: DataStreamSourceGenerationTrainRecordJsonData | null; - file?: FileReference | null; - list_of_files?: ListOfFileReferences | null; - directory?: Directory | null; - s3files?: S3Files | null; - data_stream?: "jsondata" | "file" | "list_of_files" | "directory" | "s3files"; -} -export interface DataStreamSourceGenerationTrainRecord__Output { - jsondata?: DataStreamSourceGenerationTrainRecordJsonData__Output | null; - file?: FileReference__Output | null; - list_of_files?: ListOfFileReferences__Output | null; - directory?: Directory__Output | null; - s3files?: S3Files__Output | null; - data_stream: "jsondata" | "file" | "list_of_files" | "directory" | "s3files"; -} - -export interface TuningConfig { - num_virtual_tokens?: number | string | Long; - prompt_tuning_init_text?: string; - prompt_tuning_init_method?: string; - prompt_tuning_init_source_model?: string; - output_model_types?: string[]; -} -export interface TuningConfig__Output { - num_virtual_tokens: number; - prompt_tuning_init_text: string; - prompt_tuning_init_method: string; - prompt_tuning_init_source_model: string; - output_model_types: string[]; -} - -export interface TextGenerationTaskPeftPromptTuningTrainParameters { - base_model?: string; - train_stream?: DataStreamSourceGenerationTrainRecord | null; - tuning_config?: TuningConfig | null; - val_stream?: DataStreamSourceGenerationTrainRecord | null; - device?: string; - tuning_type?: string; - num_epochs?: number | string | Long; - learning_rate?: number | string; - verbalizer?: string; - batch_size?: number | string | Long; - max_source_length?: number | string | Long; - max_target_length?: number | string | Long; - accumulate_steps?: number | string | Long; - torch_dtype?: string; - silence_progress_bars?: boolean; - seed?: number | string | Long; - _val_stream?: "val_stream"; - _device?: "device"; - _tuning_type?: "tuning_type"; - _num_epochs?: "num_epochs"; - _learning_rate?: "learning_rate"; - _verbalizer?: "verbalizer"; - _batch_size?: "batch_size"; - _max_source_length?: "max_source_length"; - _max_target_length?: "max_target_length"; - _accumulate_steps?: "accumulate_steps"; - _torch_dtype?: "torch_dtype"; - _silence_progress_bars?: "silence_progress_bars"; - _seed?: "seed"; -} -export interface TextGenerationTaskPeftPromptTuningTrainParameters__Output { - base_model: string; - train_stream: DataStreamSourceGenerationTrainRecord__Output | null; - tuning_config: TuningConfig__Output | null; - val_stream?: DataStreamSourceGenerationTrainRecord__Output | null; - device?: string; - tuning_type?: string; - num_epochs?: number; - learning_rate?: number; - verbalizer?: string; - batch_size?: number; - max_source_length?: number; - max_target_length?: number; - accumulate_steps?: number; - torch_dtype?: string; - silence_progress_bars?: boolean; - seed?: number; - _val_stream: "val_stream"; - _device: "device"; - _tuning_type: "tuning_type"; - _num_epochs: "num_epochs"; - _learning_rate: "learning_rate"; - _verbalizer: "verbalizer"; - _batch_size: "batch_size"; - _max_source_length: "max_source_length"; - _max_target_length: "max_target_length"; - _accumulate_steps: "accumulate_steps"; - _torch_dtype: "torch_dtype"; - _silence_progress_bars: "silence_progress_bars"; - _seed: "seed"; -} - -export interface TextGenerationTaskPeftPromptTuningTrainRequest { - model_name?: string; - output_path?: S3Path | null; - parameters?: TextGenerationTaskPeftPromptTuningTrainParameters | null; -} -export interface TextGenerationTaskPeftPromptTuningTrainRequest__Output { - model_name: string; - output_path: S3Path__Output | null; - parameters: TextGenerationTaskPeftPromptTuningTrainParameters__Output | null; -} - -export interface TextGenerationTaskTextGenerationTrainParameters { - base_model?: string; - train_stream?: DataStreamSourceGenerationTrainRecord | null; - torch_dtype?: string; - max_source_length?: number | string | Long; - max_target_length?: number | string | Long; - batch_size?: number | string | Long; - num_epochs?: number | string | Long; - accumulate_steps?: number | string | Long; - random_seed?: number | string | Long; - lr?: number | string; - use_iterable_dataset?: boolean; - _torch_dtype?: "torch_dtype"; - _max_source_length?: "max_source_length"; - _max_target_length?: "max_target_length"; - _batch_size?: "batch_size"; - _num_epochs?: "num_epochs"; - _accumulate_steps?: "accumulate_steps"; - _random_seed?: "random_seed"; - _lr?: "lr"; - _use_iterable_dataset?: "use_iterable_dataset"; -} -export interface TextGenerationTaskTextGenerationTrainParameters__Output { - base_model: string; - train_stream: DataStreamSourceGenerationTrainRecord__Output | null; - torch_dtype?: string; - max_source_length?: number; - max_target_length?: number; - batch_size?: number; - num_epochs?: number; - accumulate_steps?: number; - random_seed?: number; - lr?: number; - use_iterable_dataset?: boolean; - _torch_dtype: "torch_dtype"; - _max_source_length: "max_source_length"; - _max_target_length: "max_target_length"; - _batch_size: "batch_size"; - _num_epochs: "num_epochs"; - _accumulate_steps: "accumulate_steps"; - _random_seed: "random_seed"; - _lr: "lr"; - _use_iterable_dataset: "use_iterable_dataset"; -} - -export interface TextGenerationTaskTextGenerationTrainRequest { - model_name?: string; - output_path?: S3Path | null; - parameters?: TextGenerationTaskTextGenerationTrainParameters | null; -} -export interface TextGenerationTaskTextGenerationTrainRequest__Output { - model_name: string; - output_path: S3Path__Output | null; - parameters: TextGenerationTaskTextGenerationTrainParameters__Output | null; -} - -export interface TrainingJob { - training_id?: string; - model_name?: string; -} -export interface TrainingJob__Output { - training_id: string; - model_name: string; -} - -export interface NlpTrainingServiceClient extends grpc.Client { - TextGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskPeftPromptTuningTrain( - argument: TextGenerationTaskPeftPromptTuningTrainRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - TextGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - textGenerationTaskTextGenerationTrain( - argument: TextGenerationTaskTextGenerationTrainRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; -} -export interface NlpTrainingServiceDefinition extends grpc.ServiceDefinition { - TextGenerationTaskPeftPromptTuningTrain: MethodDefinition< - TextGenerationTaskPeftPromptTuningTrainRequest, - TrainingJob, - TextGenerationTaskPeftPromptTuningTrainRequest__Output, - TrainingJob__Output - >; - TextGenerationTaskTextGenerationTrain: MethodDefinition< - TextGenerationTaskTextGenerationTrainRequest, - TrainingJob, - TextGenerationTaskTextGenerationTrainRequest__Output, - TrainingJob__Output - >; -} - -export type SubtypeConstructor$1 any, Subtype> = new ( - ...args: ConstructorParameters -) => Subtype; -export interface ProtoGrpcType$1 { - caikit: { - runtime: { - Nlp: { - BidiStreamingTokenClassificationTaskRequest: MessageTypeDefinition; - DataStreamSourceGenerationTrainRecord: MessageTypeDefinition; - DataStreamSourceGenerationTrainRecordJsonData: MessageTypeDefinition; - EmbeddingTaskRequest: MessageTypeDefinition; - EmbeddingTasksRequest: MessageTypeDefinition; - NlpService: SubtypeConstructor$1 & { - service: NlpServiceDefinition; - }; - NlpTrainingService: SubtypeConstructor$1 & { - service: NlpTrainingServiceDefinition; - }; - RerankTaskRequest: MessageTypeDefinition; - RerankTasksRequest: MessageTypeDefinition; - SentenceSimilarityTaskRequest: MessageTypeDefinition; - SentenceSimilarityTasksRequest: MessageTypeDefinition; - ServerStreamingTextGenerationTaskRequest: MessageTypeDefinition; - TextClassificationTaskRequest: MessageTypeDefinition; - TextGenerationTaskPeftPromptTuningTrainParameters: MessageTypeDefinition; - TextGenerationTaskPeftPromptTuningTrainRequest: MessageTypeDefinition; - TextGenerationTaskRequest: MessageTypeDefinition; - TextGenerationTaskTextGenerationTrainParameters: MessageTypeDefinition; - TextGenerationTaskTextGenerationTrainRequest: MessageTypeDefinition; - TokenClassificationTaskRequest: MessageTypeDefinition; - TokenizationTaskRequest: MessageTypeDefinition; - }; - }; - }; - caikit_data_model: { - caikit_nlp: { - EmbeddingResult: MessageTypeDefinition; - EmbeddingResults: MessageTypeDefinition; - ExponentialDecayLengthPenalty: MessageTypeDefinition; - GenerationTrainRecord: MessageTypeDefinition; - RerankResult: MessageTypeDefinition; - RerankResults: MessageTypeDefinition; - RerankScore: MessageTypeDefinition; - RerankScores: MessageTypeDefinition; - SentenceSimilarityResult: MessageTypeDefinition; - SentenceSimilarityResults: MessageTypeDefinition; - SentenceSimilarityScores: MessageTypeDefinition; - TuningConfig: MessageTypeDefinition; - }; - common: { - BoolSequence: MessageTypeDefinition; - ConnectionInfo: MessageTypeDefinition; - ConnectionTlsInfo: MessageTypeDefinition; - Directory: MessageTypeDefinition; - File: MessageTypeDefinition; - FileReference: MessageTypeDefinition; - FloatSequence: MessageTypeDefinition; - IntSequence: MessageTypeDefinition; - ListOfFileReferences: MessageTypeDefinition; - ListOfVector1D: MessageTypeDefinition; - NpFloat32Sequence: MessageTypeDefinition; - NpFloat64Sequence: MessageTypeDefinition; - ProducerId: MessageTypeDefinition; - ProducerPriority: MessageTypeDefinition; - PyFloatSequence: MessageTypeDefinition; - S3Base: MessageTypeDefinition; - S3Files: MessageTypeDefinition; - S3Path: MessageTypeDefinition; - StrSequence: MessageTypeDefinition; - TrainingStatus: EnumTypeDefinition; - Vector1D: MessageTypeDefinition; - }; - nlp: { - ClassificationResult: MessageTypeDefinition; - ClassificationResults: MessageTypeDefinition; - ClassificationTrainRecord: MessageTypeDefinition; - ClassifiedGeneratedTextResult: MessageTypeDefinition; - ClassifiedGeneratedTextStreamResult: MessageTypeDefinition; - FinishReason: EnumTypeDefinition; - GeneratedTextResult: MessageTypeDefinition; - GeneratedTextStreamResult: MessageTypeDefinition; - GeneratedToken: MessageTypeDefinition; - InputWarning: MessageTypeDefinition; - InputWarningReason: EnumTypeDefinition; - TextGenTokenClassificationResults: MessageTypeDefinition; - Token: MessageTypeDefinition; - TokenClassificationResult: MessageTypeDefinition; - TokenClassificationResults: MessageTypeDefinition; - TokenClassificationStreamResult: MessageTypeDefinition; - TokenStreamDetails: MessageTypeDefinition; - TokenizationResults: MessageTypeDefinition; - TokenizationStreamResult: MessageTypeDefinition; - }; - runtime: { - ModelPointer: MessageTypeDefinition; - TrainingInfoRequest: MessageTypeDefinition; - TrainingJob: MessageTypeDefinition; - TrainingStatusResponse: MessageTypeDefinition; - }; - }; - google: { - protobuf: { - ListValue: MessageTypeDefinition; - NullValue: EnumTypeDefinition; - Struct: MessageTypeDefinition; - Timestamp: MessageTypeDefinition; - Value: MessageTypeDefinition; - }; - }; -} - -export interface GenerationRequest { - text?: string; -} -export interface GenerationRequest__Output { - text: string; -} - -declare const DecodingMethod: { - readonly GREEDY: "GREEDY"; - readonly SAMPLE: "SAMPLE"; -}; -export type DecodingMethod = "GREEDY" | 0 | "SAMPLE" | 1; -export type DecodingMethod__Output = (typeof DecodingMethod)[keyof typeof DecodingMethod]; - -export interface SamplingParameters { - temperature?: number | string; - top_k?: number; - top_p?: number | string; - typical_p?: number | string; - seed?: number | string | Long; - _seed?: "seed"; -} -export interface SamplingParameters__Output { - temperature: number; - top_k: number; - top_p: number; - typical_p: number; - seed?: number; - _seed: "seed"; -} - -export interface StoppingCriteria { - max_new_tokens?: number; - min_new_tokens?: number; - time_limit_millis?: number; - stop_sequences?: string[]; - include_stop_sequence?: boolean; - _include_stop_sequence?: "include_stop_sequence"; -} -export interface StoppingCriteria__Output { - max_new_tokens: number; - min_new_tokens: number; - time_limit_millis: number; - stop_sequences: string[]; - include_stop_sequence?: boolean; - _include_stop_sequence: "include_stop_sequence"; -} - -export interface ResponseOptions { - input_text?: boolean; - generated_tokens?: boolean; - input_tokens?: boolean; - token_logprobs?: boolean; - token_ranks?: boolean; - top_n_tokens?: number; -} -export interface ResponseOptions__Output { - input_text: boolean; - generated_tokens: boolean; - input_tokens: boolean; - token_logprobs: boolean; - token_ranks: boolean; - top_n_tokens: number; -} - -export interface _fmaas_DecodingParameters_LengthPenalty { - start_index?: number; - decay_factor?: number | string; -} -export interface _fmaas_DecodingParameters_LengthPenalty__Output { - start_index: number; - decay_factor: number; -} -declare const _fmaas_DecodingParameters_ResponseFormat: { - readonly TEXT: "TEXT"; - readonly JSON: "JSON"; -}; -export type _fmaas_DecodingParameters_ResponseFormat = "TEXT" | 0 | "JSON" | 1; -export type _fmaas_DecodingParameters_ResponseFormat__Output = - (typeof _fmaas_DecodingParameters_ResponseFormat)[keyof typeof _fmaas_DecodingParameters_ResponseFormat]; -export interface _fmaas_DecodingParameters_StringChoices { - choices?: string[]; -} -export interface _fmaas_DecodingParameters_StringChoices__Output { - choices: string[]; -} -export interface DecodingParameters { - repetition_penalty?: number | string; - length_penalty?: _fmaas_DecodingParameters_LengthPenalty | null; - format?: _fmaas_DecodingParameters_ResponseFormat; - json_schema?: string; - regex?: string; - choice?: _fmaas_DecodingParameters_StringChoices | null; - grammar?: string; - _length_penalty?: "length_penalty"; - guided?: "format" | "json_schema" | "regex" | "choice" | "grammar"; -} -export interface DecodingParameters__Output { - repetition_penalty: number; - length_penalty?: _fmaas_DecodingParameters_LengthPenalty__Output | null; - format?: _fmaas_DecodingParameters_ResponseFormat__Output; - json_schema?: string; - regex?: string; - choice?: _fmaas_DecodingParameters_StringChoices__Output | null; - grammar?: string; - _length_penalty: "length_penalty"; - guided: "format" | "json_schema" | "regex" | "choice" | "grammar"; -} - -export interface Parameters { - method?: DecodingMethod; - sampling?: SamplingParameters | null; - stopping?: StoppingCriteria | null; - response?: ResponseOptions | null; - decoding?: DecodingParameters | null; - truncate_input_tokens?: number; -} -export interface Parameters__Output { - method: DecodingMethod__Output; - sampling: SamplingParameters__Output | null; - stopping: StoppingCriteria__Output | null; - response: ResponseOptions__Output | null; - decoding: DecodingParameters__Output | null; - truncate_input_tokens: number; -} - -export interface BatchedGenerationRequest { - model_id?: string; - prefix_id?: string; - requests?: GenerationRequest[]; - adapter_id?: string; - params?: Parameters | null; - _prefix_id?: "prefix_id"; - _adapter_id?: "adapter_id"; -} -export interface BatchedGenerationRequest__Output { - model_id: string; - prefix_id?: string; - requests: GenerationRequest__Output[]; - adapter_id?: string; - params: Parameters__Output | null; - _prefix_id: "prefix_id"; - _adapter_id: "adapter_id"; -} - -declare const StopReason: { - readonly NOT_FINISHED: "NOT_FINISHED"; - readonly MAX_TOKENS: "MAX_TOKENS"; - readonly EOS_TOKEN: "EOS_TOKEN"; - readonly CANCELLED: "CANCELLED"; - readonly TIME_LIMIT: "TIME_LIMIT"; - readonly STOP_SEQUENCE: "STOP_SEQUENCE"; - readonly TOKEN_LIMIT: "TOKEN_LIMIT"; - readonly ERROR: "ERROR"; -}; -export type StopReason = - | "NOT_FINISHED" - | 0 - | "MAX_TOKENS" - | 1 - | "EOS_TOKEN" - | 2 - | "CANCELLED" - | 3 - | "TIME_LIMIT" - | 4 - | "STOP_SEQUENCE" - | 5 - | "TOKEN_LIMIT" - | 6 - | "ERROR" - | 7; -export type StopReason__Output = (typeof StopReason)[keyof typeof StopReason]; - -export interface _fmaas_TokenInfo_TopToken { - text?: string; - logprob?: number | string; -} -export interface _fmaas_TokenInfo_TopToken__Output { - text: string; - logprob: number; -} -export interface TokenInfo { - text?: string; - logprob?: number | string; - rank?: number; - top_tokens?: _fmaas_TokenInfo_TopToken[]; -} -export interface TokenInfo__Output { - text: string; - logprob: number; - rank: number; - top_tokens: _fmaas_TokenInfo_TopToken__Output[]; -} - -export interface GenerationResponse { - generated_token_count?: number; - text?: string; - input_token_count?: number; - stop_reason?: StopReason; - tokens?: TokenInfo[]; - input_tokens?: TokenInfo[]; - seed?: number | string | Long; - stop_sequence?: string; -} -export interface GenerationResponse__Output { - generated_token_count: number; - text: string; - input_token_count: number; - stop_reason: StopReason__Output; - tokens: TokenInfo__Output[]; - input_tokens: TokenInfo__Output[]; - seed: number; - stop_sequence: string; -} - -export interface BatchedGenerationResponse { - responses?: GenerationResponse[]; -} -export interface BatchedGenerationResponse__Output { - responses: GenerationResponse__Output[]; -} - -export interface TokenizeRequest { - text?: string; -} -export interface TokenizeRequest__Output { - text: string; -} - -export interface BatchedTokenizeRequest { - model_id?: string; - requests?: TokenizeRequest[]; - return_tokens?: boolean; - return_offsets?: boolean; - truncate_input_tokens?: number; -} -export interface BatchedTokenizeRequest__Output { - model_id: string; - requests: TokenizeRequest__Output[]; - return_tokens: boolean; - return_offsets: boolean; - truncate_input_tokens: number; -} - -export interface _fmaas_TokenizeResponse_Offset { - start?: number; - end?: number; -} -export interface _fmaas_TokenizeResponse_Offset__Output { - start: number; - end: number; -} -export interface TokenizeResponse { - token_count?: number; - tokens?: string[]; - offsets?: _fmaas_TokenizeResponse_Offset[]; -} -export interface TokenizeResponse__Output { - token_count: number; - tokens: string[]; - offsets: _fmaas_TokenizeResponse_Offset__Output[]; -} - -export interface BatchedTokenizeResponse { - responses?: TokenizeResponse[]; -} -export interface BatchedTokenizeResponse__Output { - responses: TokenizeResponse__Output[]; -} - -export interface ModelInfoRequest { - model_id?: string; -} -export interface ModelInfoRequest__Output { - model_id: string; -} - -declare const _fmaas_ModelInfoResponse_ModelKind: { - readonly DECODER_ONLY: "DECODER_ONLY"; - readonly ENCODER_DECODER: "ENCODER_DECODER"; -}; -export type _fmaas_ModelInfoResponse_ModelKind = "DECODER_ONLY" | 0 | "ENCODER_DECODER" | 1; -export type _fmaas_ModelInfoResponse_ModelKind__Output = - (typeof _fmaas_ModelInfoResponse_ModelKind)[keyof typeof _fmaas_ModelInfoResponse_ModelKind]; -export interface ModelInfoResponse { - model_kind?: _fmaas_ModelInfoResponse_ModelKind; - max_sequence_length?: number; - max_new_tokens?: number; -} -export interface ModelInfoResponse__Output { - model_kind: _fmaas_ModelInfoResponse_ModelKind__Output; - max_sequence_length: number; - max_new_tokens: number; -} - -export interface SingleGenerationRequest { - model_id?: string; - prefix_id?: string; - request?: GenerationRequest | null; - adapter_id?: string; - params?: Parameters | null; - _prefix_id?: "prefix_id"; - _adapter_id?: "adapter_id"; -} -export interface SingleGenerationRequest__Output { - model_id: string; - prefix_id?: string; - request: GenerationRequest__Output | null; - adapter_id?: string; - params: Parameters__Output | null; - _prefix_id: "prefix_id"; - _adapter_id: "adapter_id"; -} - -export interface GenerationServiceClient extends grpc.Client { - Generate( - argument: BatchedGenerationRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - Generate( - argument: BatchedGenerationRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - Generate( - argument: BatchedGenerationRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - Generate( - argument: BatchedGenerationRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - generate( - argument: BatchedGenerationRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - generate( - argument: BatchedGenerationRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - generate( - argument: BatchedGenerationRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - generate( - argument: BatchedGenerationRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - GenerateStream( - argument: SingleGenerationRequest, - metadata: grpc.Metadata, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - GenerateStream( - argument: SingleGenerationRequest, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - generateStream( - argument: SingleGenerationRequest, - metadata: grpc.Metadata, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - generateStream( - argument: SingleGenerationRequest, - options?: grpc.CallOptions, - ): grpc.ClientReadableStream; - ModelInfo( - argument: ModelInfoRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - ModelInfo( - argument: ModelInfoRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - ModelInfo( - argument: ModelInfoRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - ModelInfo( - argument: ModelInfoRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - modelInfo( - argument: ModelInfoRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - modelInfo( - argument: ModelInfoRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - modelInfo( - argument: ModelInfoRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - modelInfo( - argument: ModelInfoRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - Tokenize( - argument: BatchedTokenizeRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - Tokenize( - argument: BatchedTokenizeRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - Tokenize( - argument: BatchedTokenizeRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - Tokenize( - argument: BatchedTokenizeRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenize( - argument: BatchedTokenizeRequest, - metadata: grpc.Metadata, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenize( - argument: BatchedTokenizeRequest, - metadata: grpc.Metadata, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenize( - argument: BatchedTokenizeRequest, - options: grpc.CallOptions, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; - tokenize( - argument: BatchedTokenizeRequest, - callback: grpc.requestCallback, - ): grpc.ClientUnaryCall; -} -export interface GenerationServiceDefinition extends grpc.ServiceDefinition { - Generate: MethodDefinition< - BatchedGenerationRequest, - BatchedGenerationResponse, - BatchedGenerationRequest__Output, - BatchedGenerationResponse__Output - >; - GenerateStream: MethodDefinition< - SingleGenerationRequest, - GenerationResponse, - SingleGenerationRequest__Output, - GenerationResponse__Output - >; - ModelInfo: MethodDefinition< - ModelInfoRequest, - ModelInfoResponse, - ModelInfoRequest__Output, - ModelInfoResponse__Output - >; - Tokenize: MethodDefinition< - BatchedTokenizeRequest, - BatchedTokenizeResponse, - BatchedTokenizeRequest__Output, - BatchedTokenizeResponse__Output - >; -} - -export type SubtypeConstructor any, Subtype> = new ( - ...args: ConstructorParameters -) => Subtype; -export interface ProtoGrpcType { - fmaas: { - BatchedGenerationRequest: MessageTypeDefinition; - BatchedGenerationResponse: MessageTypeDefinition; - BatchedTokenizeRequest: MessageTypeDefinition; - BatchedTokenizeResponse: MessageTypeDefinition; - DecodingMethod: EnumTypeDefinition; - DecodingParameters: MessageTypeDefinition; - GenerationRequest: MessageTypeDefinition; - GenerationResponse: MessageTypeDefinition; - GenerationService: SubtypeConstructor & { - service: GenerationServiceDefinition; - }; - ModelInfoRequest: MessageTypeDefinition; - ModelInfoResponse: MessageTypeDefinition; - Parameters: MessageTypeDefinition; - ResponseOptions: MessageTypeDefinition; - SamplingParameters: MessageTypeDefinition; - SingleGenerationRequest: MessageTypeDefinition; - StopReason: EnumTypeDefinition; - StoppingCriteria: MessageTypeDefinition; - TokenInfo: MessageTypeDefinition; - TokenizeRequest: MessageTypeDefinition; - TokenizeResponse: MessageTypeDefinition; - }; -} diff --git a/src/adapters/langchain/backend/chat.ts b/src/adapters/langchain/backend/chat.ts new file mode 100644 index 00000000..bbd5fa09 --- /dev/null +++ b/src/adapters/langchain/backend/chat.ts @@ -0,0 +1,160 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChatModel, + ChatModelEmitter, + ChatModelFinishReason, + ChatModelInput, + ChatModelObjectInput, + ChatModelObjectOutput, + ChatModelOutput, + ChatModelParameters, + ChatModelUsage, +} from "@/backend/chat.js"; +import { RunContext } from "@/context.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { + BaseChatModel, + BaseChatModelCallOptions, +} from "@langchain/core/language_models/chat_models"; +import { AIMessageChunk, BaseMessageLike } from "@langchain/core/messages"; +import { AssistantMessage, Message } from "@/backend/message.js"; +import { ValueError } from "@/errors.js"; + +export class LangChainChatModel extends ChatModel { + public readonly emitter: ChatModelEmitter; + + constructor( + protected readonly lcLLM: BaseChatModel, + public readonly parameters: ChatModelParameters = {}, + ) { + super(); + this.emitter = Emitter.root.child({ + namespace: ["backend", "langchain", "chat"], + creator: this, + }); + } + + get modelId(): string { + return this.lcLLM._modelType(); + } + + get providerId() { + return "langchain"; + } + + protected async _create(input: ChatModelInput, run: RunContext): Promise { + const preparedInput = this.prepareInput(input, run); + const response = this.lcLLM.bindTools + ? await this.lcLLM + .bindTools(input.tools ?? []) + .invoke(preparedInput.messages, preparedInput.options) + : await this.lcLLM.invoke(preparedInput.messages, preparedInput.options); + + return this.prepareOutput(response); + } + + protected async *_createStream( + input: ChatModelInput, + run: RunContext, + ): AsyncGenerator { + const preparedInput = this.prepareInput(input, run); + + const stream = this.lcLLM.bindTools + ? await this.lcLLM + .bindTools(input.tools ?? []) + .stream(preparedInput.messages, preparedInput.options) + : await this.lcLLM.stream(preparedInput.messages, preparedInput.options); + + for await (const response of stream) { + const chunk = this.prepareOutput(response); + yield chunk; + } + } + + protected prepareInput(input: ChatModelInput, run: RunContext) { + const messages: BaseMessageLike[] = input.messages.map((msg) => ({ + role: msg.role, + content: msg.content, + type: msg.role, + // TODO + })); + + const options: BaseChatModelCallOptions = { + runId: run.runId, + stop: input.stopSequences, + signal: run.signal, + tool_choice: input.toolChoice, + }; + + return { messages, options }; + } + + protected prepareOutput(output: AIMessageChunk) { + const messages: Message[] = []; + if (typeof output.content === "string") { + messages.push(new AssistantMessage(output.content)); + } else { + messages.push( + new AssistantMessage( + output.content.map((message) => { + if (message.type === "text") { + return { type: "text", text: message.text }; + } else if (message.type === "image_url") { + return { type: "text", text: message.image_url.toString() }; + } else { + throw new ValueError(`Unknown message type "${message.type}"`); + } + }), + ), + ); + } + + const usage: ChatModelUsage = { + totalTokens: output.usage_metadata?.total_tokens ?? 0, + promptTokens: output.usage_metadata?.input_tokens ?? 0, + completionTokens: output.usage_metadata?.output_tokens ?? 0, + }; + + const stop: ChatModelFinishReason = output.response_metadata.stop_sequence || "stop"; + + return new ChatModelOutput(messages, usage, stop); + } + + protected async _createStructure( + input: ChatModelObjectInput, + run: RunContext, + ): Promise> { + const { messages, options } = this.prepareInput(input, run); + const object = this.lcLLM + .withStructuredOutput(input.schema, { + method: "jsonSchema", + strict: false, + }) + .invoke(messages, options); + + return { object: object as T }; + } + + createSnapshot() { + return { ...super.createSnapshot(), emitter: this.emitter, lcLLM: this.lcLLM }; + } + + loadSnapshot(snapshot: ReturnType): void { + Object.assign(this, snapshot); + } +} diff --git a/src/adapters/langchain/backend/embedding.ts b/src/adapters/langchain/backend/embedding.ts new file mode 100644 index 00000000..74c0f09a --- /dev/null +++ b/src/adapters/langchain/backend/embedding.ts @@ -0,0 +1,73 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + EmbeddingModel, + EmbeddingModelEvents, + EmbeddingModelInput, + EmbeddingModelOutput, +} from "@/backend/embedding.js"; +import { RunContext } from "@/context.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { Embeddings as LCEmbeddingModel } from "@langchain/core/embeddings"; +import { signalRace } from "@/internals/helpers/promise.js"; + +export class LangChainEmbeddingModel extends EmbeddingModel { + public readonly emitter: Emitter; + + constructor(protected readonly lcEmbedding: LCEmbeddingModel) { + super(); + this.emitter = Emitter.root.child({ + namespace: ["langchain", "backend", "embedding"], + creator: this, + }); + } + + get modelId(): string { + return "langchain"; // TODO + } + + get providerId(): string { + return "langchain"; + } + + protected async _create( + input: EmbeddingModelInput, + run: RunContext, + ): Promise { + const embeddings = await signalRace( + () => this.lcEmbedding.embedDocuments(input.values), + run.signal, + ); + + return { + values: input.values.slice(), + embeddings, + usage: { tokens: undefined }, + }; + } + + createSnapshot() { + return { + ...super.createSnapshot(), + lcEmbedding: this.lcEmbedding, + }; + } + + loadSnapshot(snapshot: ReturnType) { + Object.assign(this, snapshot); + } +} diff --git a/src/adapters/langchain/llms/chat.ts b/src/adapters/langchain/llms/chat.ts deleted file mode 100644 index cc4be994..00000000 --- a/src/adapters/langchain/llms/chat.ts +++ /dev/null @@ -1,221 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, -} from "@/llms/base.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { - BaseChatModel, - BaseChatModelCallOptions, -} from "@langchain/core/language_models/chat_models"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, Role, RoleType } from "@/llms/primitives/message.js"; -import { - BaseMessageChunk, - BaseMessage as LCBaseMessage, - ChatMessage as LCMChatMessage, - MessageContentComplex, - MessageContentText, - MessageType, -} from "@langchain/core/messages"; -import { Cache } from "@/cache/decoratorCache.js"; -import { getProp, omitUndefined } from "@/internals/helpers/object.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { GetRunContext } from "@/context.js"; -import { NotImplementedError } from "@/errors.js"; - -export class LangChainChatLLMOutput extends ChatLLMOutput { - constructor( - public messages: BaseMessage[], - public meta: Record = {}, - ) { - super(); - } - - static { - this.register(); - } - - merge(other: LangChainChatLLMOutput): void { - this.messages.push(...other.messages); - Object.assign(this.meta, omitUndefined(other.meta)); - } - - getTextContent(): string { - return this.messages.map((msg) => msg.text).join(""); - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - messages: shallowCopy(this.messages), - meta: shallowCopy(this.meta), - }; - } - - loadSnapshot(snapshot: ReturnType): void { - Object.assign(this, snapshot); - } -} - -export type LangChainChatLLMParameters = Record; -type MergedCallOptions = { lc: T } & GenerateOptions; - -export type LangChainChatLLMEvents = ChatLLMGenerateEvents; - -export class LangChainChatLLM< - CallOptions extends BaseChatModelCallOptions, - OutputMessageType extends BaseMessageChunk, -> extends ChatLLM> { - public readonly emitter = Emitter.root.child({ - namespace: ["langchain", "chat_llm"], - creator: this, - }); - public readonly parameters: any; - - constructor( - public readonly lcLLM: BaseChatModel, - protected modelMeta?: LLMMeta, - executionOptions?: ExecutionOptions, - cache?: LLMCache, - ) { - super(lcLLM._modelType(), executionOptions, cache); - this.parameters = lcLLM.invocationParams(); - } - - static { - this.register(); - } - - async meta() { - if (this.modelMeta) { - return this.modelMeta; - } - - return { - tokenLimit: Infinity, - }; - } - - // eslint-disable-next-line unused-imports/no-unused-vars - async embed(input: BaseMessage[][], options?: EmbeddingOptions): Promise { - throw new NotImplementedError(); - } - - async tokenize(input: BaseMessage[]): Promise { - return { - tokensCount: await this.lcLLM.getNumTokens(input), - }; - } - - @Cache() - protected get mappers() { - const roleMapper = new Map([ - ["system", Role.SYSTEM], - ["assistant", Role.ASSISTANT], - ["ai", Role.ASSISTANT], - ["generic", Role.ASSISTANT], - ["function", Role.ASSISTANT], - ["tool", Role.ASSISTANT], - ["human", Role.USER], - ["tool", Role.ASSISTANT], - ]); - - return { - toLCMessage(message: BaseMessage): LCBaseMessage { - return new LCMChatMessage({ - role: message.role, - content: message.text, - response_metadata: message.meta, - }); - }, - fromLCMessage(message: LCBaseMessage | LCMChatMessage): BaseMessage { - const role: string = getProp(message, ["role"], message._getType()); - const text: string = - typeof message.content === "string" - ? message.content - : message.content - .filter( - (msg: MessageContentComplex): msg is MessageContentText => msg.type === "text", - ) - .map((msg: MessageContentText) => msg.text) - .join("\n"); - - return BaseMessage.of({ - role: roleMapper.has(role) ? roleMapper.get(role)! : Role.ASSISTANT, - text, - }); - }, - }; - } - - protected async _generate( - input: BaseMessage[], - options: MergedCallOptions, - run: GetRunContext, - ): Promise { - const lcMessages = input.map((msg) => this.mappers.toLCMessage(msg)); - const response = await this.lcLLM.invoke(lcMessages, { - ...options?.lc, - signal: run.signal, - }); - - return new LangChainChatLLMOutput( - [this.mappers.fromLCMessage(response)], - response.response_metadata, - ); - } - - protected async *_stream( - input: BaseMessage[], - options: MergedCallOptions, - run: GetRunContext, - ): AsyncStream { - const lcMessages = input.map((msg) => this.mappers.toLCMessage(msg)); - const response = this.lcLLM._streamResponseChunks(lcMessages, { - ...options?.lc, - signal: run.signal, - }); - for await (const chunk of response) { - yield new LangChainChatLLMOutput( - [this.mappers.fromLCMessage(chunk.message)], - chunk.message.response_metadata, - ); - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - modelId: this.modelId, - modelMeta: this.modelMeta, - parameters: shallowCopy(this.parameters), - executionOptions: shallowCopy(this.executionOptions), - lcLLM: JSON.stringify(this.lcLLM.toJSON()), - }; - } -} diff --git a/src/adapters/langchain/llms/llm.ts b/src/adapters/langchain/llms/llm.ts deleted file mode 100644 index 0177b13a..00000000 --- a/src/adapters/langchain/llms/llm.ts +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LLM, LLMEvents, LLMInput } from "@/llms/llm.js"; -import { BaseLLM as LCBaseLLM } from "@langchain/core/language_models/llms"; -import { - AsyncStream, - BaseLLMOutput, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { assign } from "@/internals/helpers/object.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { GetRunContext } from "@/context.js"; -import { NotImplementedError } from "@/errors.js"; - -export class LangChainLLMOutput extends BaseLLMOutput { - constructor( - public text: string, - public readonly meta: Record, - ) { - super(); - } - - static { - this.register(); - } - - merge(other: LangChainLLMOutput): void { - this.text += other.text; - assign(this.meta, other.meta); - } - - getTextContent(): string { - return this.text; - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - text: this.text, - meta: shallowCopy(this.meta), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } -} - -export type LangChainLLMEvents = LLMEvents; - -export class LangChainLLM extends LLM { - public readonly emitter = Emitter.root.child({ - namespace: ["langchain", "llm"], - creator: this, - }); - protected readonly parameters: any; - - constructor( - public readonly lcLLM: LCBaseLLM, - private modelMeta?: LLMMeta, - executionOptions?: ExecutionOptions, - cache?: LLMCache, - ) { - super(lcLLM._modelType(), executionOptions, cache); - this.parameters = lcLLM.invocationParams(); - } - - static { - this.register(); - } - - async meta() { - if (this.modelMeta) { - return this.modelMeta; - } - - return { - tokenLimit: Infinity, - }; - } - - // eslint-disable-next-line unused-imports/no-unused-vars - async embed(input: LLMInput[], options?: EmbeddingOptions): Promise { - throw new NotImplementedError(); - } - - async tokenize(input: LLMInput): Promise { - return { - tokensCount: await this.lcLLM.getNumTokens(input), - }; - } - - protected async _generate( - input: LLMInput, - _options: Partial, - run: GetRunContext, - ): Promise { - const { generations } = await this.lcLLM.generate([input], { - signal: run.signal, - }); - return new LangChainLLMOutput(generations[0][0].text, generations[0][0].generationInfo || {}); - } - - protected async *_stream( - input: string, - _options: StreamGenerateOptions | undefined, - run: GetRunContext, - ): AsyncStream { - const response = this.lcLLM._streamResponseChunks(input, { - signal: run.signal, - }); - for await (const chunk of response) { - yield new LangChainLLMOutput(chunk.text, chunk.generationInfo || {}); - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - modelId: this.modelId, - modelMeta: this.modelMeta, - parameters: shallowCopy(this.parameters), - executionOptions: shallowCopy(this.executionOptions), - lcLLM: JSON.stringify(this.lcLLM.toJSON()), - }; - } -} diff --git a/src/adapters/langchain/tools.test.ts b/src/adapters/langchain/tools.test.ts index 5388903d..dfd57448 100644 --- a/src/adapters/langchain/tools.test.ts +++ b/src/adapters/langchain/tools.test.ts @@ -44,8 +44,8 @@ describe("Langchain Tools", () => { tool: lcTool, }); - const serialized = instance.serialize(); - const deserialized = LangChainTool.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await LangChainTool.fromSerialized(serialized); verifyDeserialization(instance, deserialized, undefined, [], ["tool.schema"]); }); }); diff --git a/src/adapters/ollama/backend/chat.ts b/src/adapters/ollama/backend/chat.ts new file mode 100644 index 00000000..3a342d75 --- /dev/null +++ b/src/adapters/ollama/backend/chat.ts @@ -0,0 +1,44 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import { OllamaProvider } from "ollama-ai-provider"; +import { OllamaClient, OllamaClientSettings } from "@/adapters/ollama/backend/client.js"; +import { getEnv } from "@/internals/env.js"; + +type OllamaParameters = Parameters; +export type OllamaChatModelId = NonNullable; +export type OllamaChatModelSettings = NonNullable; + +export class OllamaChatModel extends VercelChatModel { + readonly supportsToolStreaming = false; + + constructor( + modelId: OllamaChatModelId = getEnv("OLLAMA_CHAT_MODEL", "llama3.1:8b"), + settings: OllamaChatModelSettings = {}, + client?: OllamaClient | OllamaClientSettings, + ) { + const model = OllamaClient.ensure(client).instance.chat(modelId, { + ...settings, + structuredOutputs: true, // otherwise breaks generated structure + }); + super(model); + } + + static { + this.register(); + } +} diff --git a/src/adapters/vertexai/llm.test.ts b/src/adapters/ollama/backend/client.ts similarity index 51% rename from src/adapters/vertexai/llm.test.ts rename to src/adapters/ollama/backend/client.ts index a5f31b1c..51843f69 100644 --- a/src/adapters/vertexai/llm.test.ts +++ b/src/adapters/ollama/backend/client.ts @@ -14,22 +14,17 @@ * limitations under the License. */ -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { VertexAILLM } from "@/adapters/vertexai/llm.js"; +import { getEnv } from "@/internals/env.js"; +import { createOllama, OllamaProvider, OllamaProviderSettings } from "ollama-ai-provider"; +import { BackendClient } from "@/backend/client.js"; -describe("VertexAI LLM", () => { - const getInstance = () => { - return new VertexAILLM({ - modelId: "gemini-1.5-flash-001", - location: "us-central1", - project: "systemInstruction", - }); - }; +export type OllamaClientSettings = OllamaProviderSettings; - it("Serializes", async () => { - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = VertexAILLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); +export class OllamaClient extends BackendClient { + protected create(settings?: OllamaClientSettings): OllamaProvider { + return createOllama({ + ...settings, + baseURL: getEnv("OLLAMA_BASE_URL"), + }); + } +} diff --git a/src/adapters/ollama/backend/embedding.ts b/src/adapters/ollama/backend/embedding.ts new file mode 100644 index 00000000..8b668124 --- /dev/null +++ b/src/adapters/ollama/backend/embedding.ts @@ -0,0 +1,35 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OllamaProvider } from "ollama-ai-provider"; +import { OllamaClient, OllamaClientSettings } from "@/adapters/ollama/backend/client.js"; +import { VercelEmbeddingModel } from "@/adapters/vercel/backend/embedding.js"; +import { getEnv } from "@/internals/env.js"; + +type OllamaParameters = Parameters; +export type OllamaEmbeddingModelId = NonNullable; +export type OllamaEmbeddingModelSettings = NonNullable; + +export class OllamaEmbeddingModel extends VercelEmbeddingModel { + constructor( + modelId: OllamaEmbeddingModelId = getEnv("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text"), + settings: OllamaEmbeddingModelSettings = {}, + client?: OllamaClient | OllamaClientSettings, + ) { + const model = OllamaClient.ensure(client).instance.embedding(modelId, settings); + super(model); + } +} diff --git a/src/adapters/ollama/chat.ts b/src/adapters/ollama/chat.ts deleted file mode 100644 index f00066e9..00000000 --- a/src/adapters/ollama/chat.ts +++ /dev/null @@ -1,249 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMOutputError, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { ChatRequest, ChatResponse, Config, Ollama as Client, Options as Parameters } from "ollama"; -import { signalRace } from "@/internals/helpers/promise.js"; -import { GetRunContext } from "@/context.js"; -import { Cache } from "@/cache/decoratorCache.js"; -import { customMerge, getPropStrict } from "@/internals/helpers/object.js"; -import { safeSum } from "@/internals/helpers/number.js"; -import { - extractModelMeta, - registerClient, - retrieveFormat, - retrieveVersion, -} from "@/adapters/ollama/shared.js"; -import { getEnv } from "@/internals/env.js"; -import { OllamaEmbeddingOptions } from "@/adapters/ollama/llm.js"; - -export class OllamaChatLLMOutput extends ChatLLMOutput { - public readonly results: ChatResponse[]; - - constructor(response: ChatResponse) { - super(); - this.results = [response]; - } - - static { - this.register(); - } - - get messages() { - return this.results.flatMap((response) => - BaseMessage.of({ - role: response.message.role, - text: response.message.content, - }), - ); - } - - getTextContent(): string { - return this.finalResult.message.content; - } - - @Cache() - get finalResult(): Readonly { - if (this.results.length === 0) { - throw new LLMOutputError("No chunks to get final result from!"); - } - - return customMerge(this.results, { - message: (value, oldValue) => ({ - role: value.role ?? oldValue.role, - content: `${oldValue?.content ?? ""}${value?.content ?? ""}`, - images: [...(oldValue?.images ?? []), ...(value?.images ?? [])] as string[], - tool_calls: [...(oldValue?.tool_calls ?? []), ...(value?.tool_calls ?? [])], - }), - total_duration: (value, oldValue) => value ?? oldValue, - load_duration: (value, oldValue) => value ?? oldValue, - model: (value, oldValue) => value ?? oldValue, - done: (value, oldValue) => value ?? oldValue, - done_reason: (value, oldValue) => value ?? oldValue, - created_at: (value, oldValue) => value ?? oldValue, - eval_duration: (value, oldValue) => value ?? oldValue, - prompt_eval_duration: (value, oldValue) => value ?? oldValue, - prompt_eval_count: safeSum, - eval_count: safeSum, - }); - } - - merge(other: OllamaChatLLMOutput): void { - Cache.getInstance(this, "finalResult").clear(); - this.results.push(...other.results); - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - results: shallowCopy(this.results), - }; - } - - loadSnapshot(snapshot: ReturnType): void { - Object.assign(this, snapshot); - } -} - -interface Input { - modelId: string; - client?: Client; - parameters?: Partial; - executionOptions?: ExecutionOptions; - cache?: LLMCache; -} - -export type OllamaChatLLMEvents = ChatLLMGenerateEvents; - -export class OllamaChatLLM extends ChatLLM { - public readonly emitter = Emitter.root.child({ - namespace: ["ollama", "chat_llm"], - creator: this, - }); - - public readonly client: Client; - public readonly parameters: Partial; - - constructor( - { client, modelId, parameters, executionOptions = {}, cache }: Input = { - modelId: "llama3.1", - }, - ) { - super(modelId, executionOptions, cache); - this.client = client ?? new Client({ fetch, host: getEnv("OLLAMA_HOST") }); - this.parameters = parameters ?? { - temperature: 0, - repeat_penalty: 1.0, - num_predict: 2048, - }; - } - - static { - this.register(); - registerClient(); - } - - async meta() { - const model = await this.client.show({ - model: this.modelId, - }); - - return extractModelMeta(model); - } - - async embed( - input: BaseMessage[][], - options: OllamaEmbeddingOptions = {}, - ): Promise { - const response = await this.client.embed({ - model: this.modelId, - input: input.flatMap((messages) => messages).flatMap((msg) => msg.text), - options: options?.options, - truncate: options?.truncate, - }); - return { embeddings: response.embeddings }; - } - - async tokenize(input: BaseMessage[]): Promise { - const contentLength = input.reduce((acc, msg) => acc + msg.text.length, 0); - - return { - tokensCount: Math.ceil(contentLength / 4), - }; - } - - @Cache() - async version() { - const config = getPropStrict(this.client, "config") as Config; - return retrieveVersion(config.host, config.fetch); - } - - protected async _generate( - input: BaseMessage[], - options: GenerateOptions, - run: GetRunContext, - ): Promise { - const response = await signalRace( - async () => - this.client.chat({ - ...(await this.prepareParameters(input, options)), - stream: false, - }), - run.signal, - () => this.client.abort(), - ); - - return new OllamaChatLLMOutput(response); - } - - protected async *_stream( - input: BaseMessage[], - options: Partial, - run: GetRunContext, - ): AsyncStream { - for await (const chunk of await this.client.chat({ - ...(await this.prepareParameters(input, options)), - stream: true, - })) { - if (run.signal.aborted) { - break; - } - yield new OllamaChatLLMOutput(chunk); - } - run.signal.throwIfAborted(); - } - - protected async prepareParameters( - input: BaseMessage[], - overrides?: GenerateOptions, - ): Promise { - return { - model: this.modelId, - messages: input.map((msg) => ({ - role: msg.role, - content: msg.text, - })), - options: this.parameters, - format: retrieveFormat(await this.version(), overrides?.guided), - }; - } - - createSnapshot() { - return { - ...super.createSnapshot(), - modelId: this.modelId, - parameters: shallowCopy(this.parameters), - executionOptions: shallowCopy(this.executionOptions), - client: this.client, - }; - } -} diff --git a/src/adapters/ollama/llm.test.ts b/src/adapters/ollama/llm.test.ts deleted file mode 100644 index 92e57e71..00000000 --- a/src/adapters/ollama/llm.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { OllamaLLM } from "@/adapters/ollama/llm.js"; -import { OllamaChatLLM } from "@/adapters/ollama/chat.js"; - -describe("Ollama LLM", () => { - const getInstance = () => { - return new OllamaLLM({ - modelId: "llama3.1", - }); - }; - - it("Serializes", async () => { - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = OllamaLLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); - -describe("Ollama ChatLLM", () => { - const getInstance = () => { - return new OllamaChatLLM({ - modelId: "llama3.1", - }); - }; - - it("Serializes", async () => { - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = OllamaChatLLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); diff --git a/src/adapters/ollama/llm.ts b/src/adapters/ollama/llm.ts deleted file mode 100644 index 5425b52b..00000000 --- a/src/adapters/ollama/llm.ts +++ /dev/null @@ -1,233 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LLM, LLMEvents, LLMInput } from "@/llms/llm.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { - AsyncStream, - BaseLLMOutput, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - LLMOutputError, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { - Config, - GenerateRequest, - GenerateResponse, - Ollama as Client, - Options as Parameters, -} from "ollama"; -import { GetRunContext } from "@/context.js"; -import { Cache } from "@/cache/decoratorCache.js"; -import { safeSum } from "@/internals/helpers/number.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { signalRace } from "@/internals/helpers/promise.js"; -import { customMerge, getPropStrict } from "@/internals/helpers/object.js"; -import { - extractModelMeta, - registerClient, - retrieveFormat, - retrieveVersion, -} from "@/adapters/ollama/shared.js"; -import { getEnv } from "@/internals/env.js"; - -interface Input { - modelId: string; - client?: Client; - parameters?: Partial; - executionOptions?: ExecutionOptions; - cache?: LLMCache; -} - -export interface OllamaEmbeddingOptions extends EmbeddingOptions { - options?: Partial; - truncate?: boolean; -} - -export class OllamaLLMOutput extends BaseLLMOutput { - public readonly results: GenerateResponse[]; - - constructor(result: GenerateResponse) { - super(); - this.results = [result]; - } - - static { - this.register(); - } - - getTextContent(): string { - return this.finalResult.response; - } - - @Cache() - get finalResult(): Readonly { - if (this.results.length === 0) { - throw new LLMOutputError("No chunks to get final result from!"); - } - - return customMerge(this.results, { - response: (value = "", oldValue = "") => oldValue + value, - total_duration: (value, oldValue) => value ?? oldValue, - load_duration: (value, oldValue) => value ?? oldValue, - model: (value, oldValue) => value ?? oldValue, - done: (value, oldValue) => value ?? oldValue, - done_reason: (value, oldValue) => value ?? oldValue, - created_at: (value, oldValue) => value ?? oldValue, - eval_duration: (value, oldValue) => value ?? oldValue, - prompt_eval_duration: (value, oldValue) => value ?? oldValue, - prompt_eval_count: safeSum, - eval_count: safeSum, - context: (value, oldValue) => [...(value || []), ...(oldValue || [])], - }); - } - - merge(other: OllamaLLMOutput): void { - Cache.getInstance(this, "finalResult").clear(); - this.results.push(...other.results); - } - - createSnapshot() { - return { - results: shallowCopy(this.results), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } - - toString(): string { - return this.getTextContent(); - } -} - -export type OllamaLLMEvents = LLMEvents; - -export class OllamaLLM extends LLM { - public readonly emitter = Emitter.root.child({ - namespace: ["ollama", "llm"], - creator: this, - }); - - public readonly client: Client; - public readonly parameters: Partial; - - static { - this.register(); - registerClient(); - } - - constructor({ client, modelId, parameters, executionOptions = {}, cache }: Input) { - super(modelId, executionOptions, cache); - this.client = client ?? new Client({ host: getEnv("OLLAMA_HOST") }); - this.parameters = parameters ?? {}; - } - - protected async _generate( - input: LLMInput, - options: GenerateOptions, - run: GetRunContext, - ): Promise { - const response = await signalRace( - async () => - this.client.generate({ - ...(await this.prepareParameters(input, options)), - stream: false, - }), - run.signal, - () => this.client.abort(), - ); - - return new OllamaLLMOutput(response); - } - - protected async *_stream( - input: LLMInput, - options: Partial, - run: GetRunContext, - ): AsyncStream { - for await (const chunk of await this.client.generate({ - ...(await this.prepareParameters(input, options)), - stream: true, - })) { - if (run.signal.aborted) { - break; - } - yield new OllamaLLMOutput(chunk); - } - run.signal.throwIfAborted(); - } - - @Cache() - async version() { - const config = getPropStrict(this.client, "config") as Config; - return retrieveVersion(config.host, config.fetch); - } - - async meta(): Promise { - const model = await this.client.show({ - model: this.modelId, - }); - - return extractModelMeta(model); - } - - async embed(input: LLMInput[], options: OllamaEmbeddingOptions = {}): Promise { - const response = await this.client.embed({ - model: this.modelId, - input: input, - options: options?.options, - truncate: options?.truncate, - }); - return { embeddings: response.embeddings }; - } - - async tokenize(input: LLMInput): Promise { - return { - tokensCount: Math.ceil(input.length / 4), - }; - } - - protected async prepareParameters( - input: LLMInput, - overrides?: GenerateOptions, - ): Promise { - return { - model: this.modelId, - prompt: input, - raw: true, - options: this.parameters, - format: retrieveFormat(await this.version(), overrides?.guided), - }; - } - - createSnapshot() { - return { - ...super.createSnapshot(), - modelId: this.modelId, - executionOptions: shallowCopy(this.executionOptions), - parameters: shallowCopy(this.parameters), - client: this.client, - }; - } -} diff --git a/src/adapters/ollama/shared.ts b/src/adapters/ollama/shared.ts deleted file mode 100644 index 3a8bee3c..00000000 --- a/src/adapters/ollama/shared.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Serializer } from "@/serializer/serializer.js"; -import { Config, Ollama as Client, ShowResponse } from "ollama"; -import { getPropStrict } from "@/internals/helpers/object.js"; -import { GuidedOptions, LLMMeta } from "@/llms/base.js"; -import { Comparator, compareVersion } from "@/internals/helpers/string.js"; -import { isString } from "remeda"; - -export function registerClient() { - Serializer.register(Client, { - toPlain: (value) => ({ - config: getPropStrict(value, "config") as Config, - fetch: getPropStrict(value, "fetch"), - }), - fromPlain: (value) => - new Client({ - fetch: value.fetch ?? value.config.fetch, - host: value.config.host, - proxy: value.config.proxy, - }), - }); -} - -export async function retrieveVersion( - baseUrl: string, - client: typeof fetch = fetch, -): Promise { - const url = new URL("/api/version", baseUrl); - const response = await client(url); - if (!response.ok) { - throw new Error(`Could not retrieve Ollama API version.`); - } - const data = await response.json(); - return data.version; -} - -export function retrieveFormat( - version: string | number, - guided?: GuidedOptions, -): string | object | undefined { - if (!guided?.json) { - return undefined; - } - - if (compareVersion(String(version), Comparator.GTE, "0.5.0")) { - return isString(guided.json) ? JSON.parse(guided.json) : guided.json; - } else { - return "json"; - } -} - -export function extractModelMeta(response: ShowResponse): LLMMeta { - const tokenLimit = Object.entries(response.model_info) - .find(([k]) => k.includes("context_length") || k.includes("max_sequence_length")) - ?.at(1); - - return { - tokenLimit: tokenLimit || Infinity, - }; -} diff --git a/src/adapters/openai/backend/chat.ts b/src/adapters/openai/backend/chat.ts new file mode 100644 index 00000000..0a01b413 --- /dev/null +++ b/src/adapters/openai/backend/chat.ts @@ -0,0 +1,35 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OpenAIProvider } from "@ai-sdk/openai"; +import { OpenAIClient, OpenAIClientSettings } from "@/adapters/openai/backend/client.js"; +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import { getEnv } from "@/internals/env.js"; + +type OpenAIParameters = Parameters; +export type OpenAIChatModelId = NonNullable; +export type OpenAIChatModelSettings = NonNullable; + +export class OpenAIChatModel extends VercelChatModel { + constructor( + modelId: OpenAIChatModelId = getEnv("OPENAI_CHAT_MODEL", "gpt-4o"), + settings: OpenAIChatModelSettings = {}, + client?: OpenAIClient | OpenAIClientSettings, + ) { + const model = OpenAIClient.ensure(client).instance.chat(modelId, settings); + super(model); + } +} diff --git a/src/adapters/openai/backend/client.ts b/src/adapters/openai/backend/client.ts new file mode 100644 index 00000000..2678ef15 --- /dev/null +++ b/src/adapters/openai/backend/client.ts @@ -0,0 +1,49 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createOpenAI, OpenAIProvider, OpenAIProviderSettings } from "@ai-sdk/openai"; +import { getEnv, parseEnv } from "@/internals/env.js"; +import { z } from "zod"; +import { BackendClient } from "@/backend/client.js"; + +export type OpenAIClientSettings = OpenAIProviderSettings; + +export class OpenAIClient extends BackendClient { + protected create(): OpenAIProvider { + const extraHeaders = parseEnv( + "OPENAI_API_HEADERS", + z.preprocess((value) => { + return Object.fromEntries( + String(value || "") + .split(",") + .filter((pair) => pair.includes("=")) + .map((pair) => pair.split("=")), + ); + }, z.record(z.string())), + ); + + return createOpenAI({ + ...this.settings, + compatibility: "compatible", + apiKey: this.settings?.apiKey || getEnv("OPENAI_API_KEY"), + baseURL: this.settings?.baseURL || getEnv("OPENAI_API_ENDPOINT"), + headers: { + ...extraHeaders, + ...this.settings?.headers, + }, + }); + } +} diff --git a/src/adapters/openai/backend/embedding.ts b/src/adapters/openai/backend/embedding.ts new file mode 100644 index 00000000..8d3e1171 --- /dev/null +++ b/src/adapters/openai/backend/embedding.ts @@ -0,0 +1,35 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OpenAIClient } from "@/adapters/openai/backend/client.js"; +import { OpenAIProvider, OpenAIProviderSettings } from "@ai-sdk/openai"; +import { VercelEmbeddingModel } from "@/adapters/vercel/backend/embedding.js"; +import { getEnv } from "@/internals/env.js"; + +type OpenAIParameters = Parameters; +export type OpenAIEmbeddingModelId = NonNullable; +export type OpenAIEmbeddingModelSettings = NonNullable; + +export class OpenAIEmbeddingModel extends VercelEmbeddingModel { + constructor( + modelId: OpenAIEmbeddingModelId = getEnv("OPENAI_EMBEDDING_MODEL", "text-embedding-3-small"), + settings: OpenAIEmbeddingModelSettings = {}, + client?: OpenAIProviderSettings | OpenAIClient, + ) { + const model = OpenAIClient.ensure(client).instance.embedding(modelId, settings); + super(model); + } +} diff --git a/src/adapters/openai/chat.test.ts b/src/adapters/openai/chat.test.ts deleted file mode 100644 index f7bbe74c..00000000 --- a/src/adapters/openai/chat.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { OpenAIChatLLM } from "@/adapters/openai/chat.js"; -import { OpenAI, AzureOpenAI } from "openai"; - -describe("AzureOpenAI ChatLLM", () => { - const getInstance = () => { - return new OpenAIChatLLM({ - modelId: "gpt-4o", - client: new AzureOpenAI(), - }); - }; - - it("Serializes", async () => { - process.env["OPENAI_BASE_URL"] = "http://dummy/"; - process.env["AZURE_OPENAI_API_KEY"] = "123"; - process.env["OPENAI_API_VERSION"] = "version 1"; - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = OpenAIChatLLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); - -describe("OpenAI ChatLLM", () => { - const getInstance = () => { - return new OpenAIChatLLM({ - modelId: "gpt-4o", - client: new OpenAI({ - apiKey: "123", - }), - }); - }; - - it("Serializes", async () => { - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = OpenAIChatLLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); diff --git a/src/adapters/openai/chat.ts b/src/adapters/openai/chat.ts deleted file mode 100644 index f6d5566d..00000000 --- a/src/adapters/openai/chat.ts +++ /dev/null @@ -1,321 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, RoleType } from "@/llms/primitives/message.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { ClientOptions, OpenAI, AzureOpenAI, AzureClientOptions } from "openai"; -import { GetRunContext } from "@/context.js"; -import { promptTokensEstimate } from "openai-chat-tokens"; -import { Serializer } from "@/serializer/serializer.js"; -import { getProp, getPropStrict } from "@/internals/helpers/object.js"; -import { isString } from "remeda"; -import type { - ChatCompletionChunk, - ChatCompletionCreateParams, - ChatCompletionMessageParam, - ChatCompletionSystemMessageParam, - ChatCompletionUserMessageParam, - ChatCompletionAssistantMessageParam, - ChatModel, - EmbeddingCreateParams, -} from "openai/resources/index"; - -type Parameters = Omit; -type Response = Omit; - -export class OpenAIChatLLMOutput extends ChatLLMOutput { - public readonly responses: Response[]; - - constructor(response: Response) { - super(); - this.responses = [response]; - } - - static { - this.register(); - } - - get messages() { - return this.responses - .flatMap((response) => response.choices) - .flatMap((choice) => - BaseMessage.of({ - role: choice.delta.role as RoleType, - text: choice.delta.content!, - }), - ); - } - - getTextContent(): string { - return this.messages.map((msg) => msg.text).join("\n"); - } - - merge(other: OpenAIChatLLMOutput): void { - this.responses.push(...other.responses); - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - responses: shallowCopy(this.responses), - }; - } - - loadSnapshot(snapshot: ReturnType): void { - Object.assign(this, snapshot); - } -} - -interface Input { - modelId?: ChatModel; - client?: OpenAI | AzureOpenAI; - clientOptions?: ClientOptions | AzureClientOptions; - parameters?: Partial; - executionOptions?: ExecutionOptions; - cache?: LLMCache; - azure?: boolean; -} - -export type OpenAIChatLLMEvents = ChatLLMGenerateEvents; -export interface OpenAIEmbeddingOptions - extends EmbeddingOptions, - Omit {} - -export class OpenAIChatLLM extends ChatLLM { - public readonly emitter = Emitter.root.child({ - namespace: ["openai", "chat_llm"], - creator: this, - }); - - public readonly client: OpenAI | AzureOpenAI; - public readonly parameters: Partial; - - constructor({ - client, - modelId, - parameters, - executionOptions = {}, - clientOptions = {}, - cache, - azure, - }: Input = {}) { - super(modelId || "gpt-4o-mini", executionOptions, cache); - if (client) { - this.client = client; - } else if (azure) { - this.client = new AzureOpenAI({ - baseURL: process.env.AZURE_OPENAI_API_BASE_URL, - endpoint: process.env.AZURE_OPENAI_API_ENDPOINT, - apiVersion: process.env.AZURE_OPENAI_API_VERSION, - deployment: process.env.AZURE_OPENAI_API_DEPLOYMENT, - ...clientOptions, - }); - } else { - this.client = new OpenAI(clientOptions); - } - this.parameters = parameters ?? { temperature: 0 }; - } - - static { - this.register(); - Serializer.register(AzureOpenAI, { - toPlain: (value) => ({ - azureADTokenProvider: getPropStrict(value, "_azureADTokenProvider"), - apiVersion: getPropStrict(value, "apiVersion"), - deployment: getPropStrict(value, "_deployment"), - }), - fromPlain: (value) => new AzureOpenAI(value.azureADTokenProvider), - }); - Serializer.register(OpenAI, { - toPlain: (value) => ({ - options: getPropStrict(value, "_options") as ClientOptions, - }), - fromPlain: (value) => new OpenAI(value.options), - }); - } - - async meta(): Promise { - if ( - this.modelId.includes("gpt-4o") || - this.modelId.includes("gpt-4-turbo") || - this.modelId.includes("gpt-4-0125-preview") || - this.modelId.includes("gpt-4-1106-preview") - ) { - return { tokenLimit: 128 * 1024 }; - } else if (this.modelId.includes("gpt-4")) { - return { tokenLimit: 8 * 1024 }; - } else if (this.modelId.includes("gpt-3.5-turbo")) { - return { tokenLimit: 16 * 1024 }; - } else if (this.modelId.includes("gpt-3.5")) { - return { tokenLimit: 8 * 1024 }; - } - - return { - tokenLimit: Infinity, - }; - } - - async embed( - input: BaseMessage[][], - options: OpenAIEmbeddingOptions = {}, - ): Promise { - const response = await this.client.embeddings.create( - { - ...options, - model: this.modelId, - input: input.flatMap((messages) => messages).flatMap((msg) => msg.text), - }, - { signal: options?.signal }, - ); - const embeddings = response.data.map((data) => data.embedding); - return { embeddings }; - } - - async tokenize(input: BaseMessage[]): Promise { - const tokensCount = promptTokensEstimate({ - messages: input.map( - (msg) => - ({ - role: msg.role, - content: msg.text, - }) as ChatCompletionMessageParam, - ), - }); - - return { - tokensCount, - }; - } - - protected _prepareRequest( - input: BaseMessage[], - options?: GenerateOptions, - ): ChatCompletionCreateParams { - type OpenAIMessage = - | ChatCompletionSystemMessageParam - | ChatCompletionUserMessageParam - | ChatCompletionAssistantMessageParam; - - return { - ...this.parameters, - model: this.modelId, - stream: false, - messages: input.map( - (message): OpenAIMessage => ({ - role: message.role as OpenAIMessage["role"], - content: message.text, - }), - ), - - response_format: (() => { - if (options?.guided?.json) { - const schema = isString(options.guided.json) - ? JSON.parse(options.guided.json) - : options.guided.json; - - // OpenAI requires that 'properties' must be defined when type equals 'object' - if (getProp(schema, ["type"]) === "object" && !getProp(schema, ["properties"])) { - schema.properties = {}; - } - - return { - type: "json_schema", - json_schema: { - name: "schema", - schema, - }, - }; - } - })(), - }; - } - - protected async _generate( - input: BaseMessage[], - options: Partial, - run: GetRunContext, - ): Promise { - const response = await this.client.chat.completions.create( - { - ...this._prepareRequest(input, options), - stream: false, - }, - { - signal: run.signal, - }, - ); - - return new OpenAIChatLLMOutput({ - id: response.id, - model: response.model, - created: response.created, - usage: response.usage, - service_tier: response.service_tier, - system_fingerprint: response.system_fingerprint, - choices: response.choices.map( - (choice) => - ({ - delta: choice.message, - index: 1, - logprobs: choice.logprobs, - finish_reason: choice.finish_reason, - }) as ChatCompletionChunk.Choice, - ), - }); - } - - protected async *_stream( - input: BaseMessage[], - options: StreamGenerateOptions | undefined, - run: GetRunContext, - ): AsyncStream { - for await (const chunk of await this.client.chat.completions.create( - { - ...this._prepareRequest(input, options), - stream: true, - }, - { - signal: run.signal, - }, - )) { - yield new OpenAIChatLLMOutput(chunk); - } - } - - createSnapshot() { - return { - ...super.createSnapshot(), - parameters: shallowCopy(this.parameters), - client: this.client, - }; - } -} diff --git a/src/adapters/shared/llmChatTemplates.ts b/src/adapters/shared/llmChatTemplates.ts deleted file mode 100644 index f02543d8..00000000 --- a/src/adapters/shared/llmChatTemplates.ts +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { PromptTemplate } from "@/template.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; -import { ValueError } from "@/errors.js"; -import { isDefined, mapToObj, pickBy } from "remeda"; -import { z } from "zod"; -import { toBoundedFunction } from "@/serializer/utils.js"; - -export type LLMChatPromptTemplate = PromptTemplate.infer<{ messages: Record[] }>; - -export interface LLMChatTemplate { - template: LLMChatPromptTemplate; - messagesToPrompt: (template: LLMChatPromptTemplate) => (messages: BaseMessage[]) => string; - parameters: { - stop_sequence: string[]; - }; -} - -export function messagesToPromptFactory(rolesOverride: Record = {}) { - const roles: Record = pickBy( - { - system: "system", - user: "user", - assistant: "assistant", - ...rolesOverride, - }, - isDefined, - ); - - return (template: LLMChatPromptTemplate) => { - return toBoundedFunction( - (messages: BaseMessage[]) => { - return template.render({ - messages: messages.map((message) => - Object.fromEntries( - Object.entries(roles).map(([key, role]) => - message.role === role ? [key, [message.text]] : [key, []], - ), - ), - ), - }); - }, - [ - { - name: "template", - value: template, - }, - { - name: "roles", - value: roles, - }, - ], - ); - }; -} - -export function templateSchemaFactory(roles: readonly string[]) { - return z.object({ - messages: z.array(z.object(mapToObj(roles, (role) => [role, z.array(z.string())] as const))), - }); -} - -const llama31: LLMChatTemplate = { - template: new PromptTemplate({ - schema: templateSchemaFactory(["system", "user", "assistant", "ipython"] as const), - template: `{{#messages}}{{#system}}<|begin_of_text|><|start_header_id|>system<|end_header_id|> - -{{system}}<|eot_id|>{{/system}}{{#user}}<|start_header_id|>user<|end_header_id|> - -{{user}}<|eot_id|>{{/user}}{{#assistant}}<|start_header_id|>assistant<|end_header_id|> - -{{assistant}}<|eot_id|>{{/assistant}}{{#ipython}}<|start_header_id|>ipython<|end_header_id|> - -{{ipython}}<|eot_id|>{{/ipython}}{{/messages}}<|start_header_id|>assistant<|end_header_id|> - -`, - }), - messagesToPrompt: messagesToPromptFactory({ ipython: "ipython" }), - parameters: { - stop_sequence: ["<|eot_id|>"], - }, -}; - -const llama33: LLMChatTemplate = llama31; - -const llama3: LLMChatTemplate = { - template: new PromptTemplate({ - schema: templateSchemaFactory(["system", "user", "assistant"] as const), - template: `{{#messages}}{{#system}}<|begin_of_text|><|start_header_id|>system<|end_header_id|> - -{{system}}<|eot_id|>{{/system}}{{#user}}<|start_header_id|>user<|end_header_id|> - -{{user}}<|eot_id|>{{/user}}{{#assistant}}<|start_header_id|>assistant<|end_header_id|> - -{{assistant}}<|eot_id|>{{/assistant}}{{/messages}}<|start_header_id|>assistant<|end_header_id|> -`, - }), - messagesToPrompt: messagesToPromptFactory(), - parameters: { - stop_sequence: ["<|eot_id|>"], - }, -}; - -const granite31Instruct: LLMChatTemplate = { - template: new PromptTemplate({ - schema: templateSchemaFactory([ - "system", - "user", - "assistant", - "tools", - "tool_call", - "tool_response", - ] as const), - template: `{{#messages}}{{#system}}<|start_of_role|>system<|end_of_role|> -{{system}}<|end_of_text|> -{{ end }}{{/system}}{{#tools}}<|start_of_role|>tools<|end_of_role|> -{{tools}}<|end_of_text|> -{{ end }}{{/tools}}{{#user}}<|start_of_role|>user<|end_of_role|> -{{user}}<|end_of_text|> -{{ end }}{{/user}}{{#assistant}}<|start_of_role|>assistant<|end_of_role|> -{{assistant}}<|end_of_text|> -{{ end }}{{/assistant}}{{#tool_call}}<|start_of_role|>assistant<|end_of_role|><|tool_call|> -{{tool_call}}<|end_of_text|> -{{ end }}{{/tool_call}}{{#tool_response}}<|start_of_role|>tool_response<|end_of_role|> -{{tool_response}}<|end_of_text|> -{{ end }}{{/tool_response}}{{/messages}}<|start_of_role|>assistant<|end_of_role|> -`, - }), - messagesToPrompt: messagesToPromptFactory({ - tools: "tools", - tool_response: "tool_response", - tool_call: "tool_call", - }), - parameters: { - stop_sequence: ["<|end_of_text|>"], - }, -}; - -export class LLMChatTemplates { - protected static readonly registry = { - "llama3.3": llama33, - "llama3.1": llama31, - "llama3": llama3, - "granite3.1-Instruct": granite31Instruct, - }; - - static register(model: string, template: LLMChatTemplate, override = false) { - if (model in this.registry && !override) { - throw new ValueError(`Template for model '${model}' already exists!`); - } - this.registry[model as keyof typeof this.registry] = template; - } - - static has(model: string): boolean { - return Boolean(model && model in this.registry); - } - - static get(model: keyof typeof LLMChatTemplates.registry): LLMChatTemplate; - // eslint-disable-next-line @typescript-eslint/unified-signatures - static get(model: string): LLMChatTemplate; - static get(model: string): LLMChatTemplate { - if (!this.has(model)) { - throw new ValueError(`Template for model '${model}' not found!`, [], { - context: { - validModels: Object.keys(this.registry), - }, - }); - } - return this.registry[model as keyof typeof this.registry]; - } -} diff --git a/src/adapters/vercel/backend/chat.ts b/src/adapters/vercel/backend/chat.ts new file mode 100644 index 00000000..716e8cd2 --- /dev/null +++ b/src/adapters/vercel/backend/chat.ts @@ -0,0 +1,214 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChatModelInput, + ChatModel, + ChatModelOutput, + ChatModelEvents, + ChatModelObjectInput, + ChatModelObjectOutput, +} from "@/backend/chat.js"; +import { + CoreAssistantMessage, + CoreMessage, + CoreToolMessage, + generateObject, + generateText, + jsonSchema, + LanguageModelV1, + streamText, +} from "ai"; +import { Emitter } from "@/emitter/emitter.js"; +import { AssistantMessage, Message, ToolMessage } from "@/backend/message.js"; +import { GetRunContext } from "@/context.js"; +import { ValueError } from "@/errors.js"; +import { isEmpty, mapToObj, toCamelCase } from "remeda"; +import { FullModelName } from "@/backend/utils.js"; +import { ChatModelError } from "@/backend/errors.js"; + +export abstract class VercelChatModel< + M extends LanguageModelV1 = LanguageModelV1, +> extends ChatModel { + public readonly emitter: Emitter; + public readonly supportsToolStreaming: boolean = true; + + constructor(private readonly model: M) { + super(); + if (!this.modelId) { + throw new ValueError("No modelId has been provided!"); + } + this.emitter = Emitter.root.child({ + namespace: ["backend", this.providerId, "chat"], + creator: this, + }); + } + + get modelId(): string { + return this.model.modelId; + } + + get providerId(): string { + const provider = this.model.provider.split(".")[0].split("-")[0]; + return toCamelCase(provider); + } + + protected async _create(input: ChatModelInput, _run: GetRunContext) { + const { + finishReason, + usage, + response: { messages }, + } = await generateText(await this.transformInput(input)); + + return new ChatModelOutput(this.transformMessages(messages), usage, finishReason); + } + + protected async _createStructure( + { schema, ...input }: ChatModelObjectInput, + run: GetRunContext, + ): Promise> { + const response = await generateObject({ + temperature: 0, + ...(await this.transformInput(input)), + schema, + abortSignal: run.signal, + model: this.model, + output: "object", + mode: "json", + }); + + return { object: response.object }; + } + + async *_createStream(input: ChatModelInput, run: GetRunContext) { + if (!this.supportsToolStreaming && !isEmpty(input.tools ?? [])) { + const response = await this._create(input, run); + yield response; + return; + } + + const { fullStream, usage, finishReason, response } = streamText({ + ...(await this.transformInput(input)), + abortSignal: run.signal, + }); + + let lastChunk: ChatModelOutput | null = null; + for await (const event of fullStream) { + let message: Message; + switch (event.type) { + case "text-delta": + message = new AssistantMessage(event.textDelta); + break; + case "tool-call": + message = new AssistantMessage({ + type: event.type, + toolCallId: event.toolCallId, + toolName: event.toolName, + args: event.args, + }); + break; + case "error": + throw new ChatModelError("Unhandled error", [event.error as Error]); + case "step-finish": + case "step-start": + continue; + case "tool-result": + message = new ToolMessage({ + type: event.type, + toolCallId: event.toolCallId, + toolName: event.toolName, + result: event.result, + }); + break; + case "tool-call-streaming-start": + case "tool-call-delta": + continue; + case "finish": + continue; + default: + throw new Error(`Unhandled event "${event.type}"`); + } + lastChunk = new ChatModelOutput([message]); + yield lastChunk; + } + + if (!lastChunk) { + throw new ChatModelError("No chunks have been received!"); + } + lastChunk.usage = await usage; + lastChunk.finishReason = await finishReason; + await response; + } + + protected async transformInput( + input: ChatModelInput, + ): Promise>>[0]> { + const tools = await Promise.all( + (input.tools ?? []).map(async (tool) => ({ + name: tool.name, + description: tool.description, + parameters: jsonSchema(await tool.getInputJsonSchema()), + })), + ); + + const messages = input.messages.map((msg): CoreMessage => { + if (msg instanceof AssistantMessage) { + return { role: "assistant", content: msg.content }; + } else if (msg instanceof ToolMessage) { + return { role: "tool", content: msg.content }; + } + return { role: msg.role as "user" | "system", content: msg.text }; + }); + + return { + ...this.parameters, + ...input, + model: this.model, + tools: mapToObj(tools, ({ name, ...tool }) => [name, tool]), + messages, + }; + } + + protected transformMessages(messages: (CoreAssistantMessage | CoreToolMessage)[]): Message[] { + return messages.flatMap((msg) => { + if (msg.role === "tool") { + return new ToolMessage(msg.content, msg.experimental_providerMetadata); + } + return new AssistantMessage(msg.content, msg.experimental_providerMetadata); + }); + } + + createSnapshot() { + return { + ...super.createSnapshot(), + providerId: this.providerId, + modelId: this.modelId, + supportsToolStreaming: this.supportsToolStreaming, + }; + } + + async loadSnapshot({ providerId, modelId, ...snapshot }: ReturnType) { + const instance = await ChatModel.fromName(`${providerId}:${modelId}` as FullModelName); + if (!(instance instanceof VercelChatModel)) { + throw new Error("Incorrect deserialization!"); + } + instance.destroy(); + Object.assign(this, { + ...snapshot, + model: instance.model, + }); + } +} diff --git a/src/adapters/vercel/backend/embedding.ts b/src/adapters/vercel/backend/embedding.ts new file mode 100644 index 00000000..a64476ac --- /dev/null +++ b/src/adapters/vercel/backend/embedding.ts @@ -0,0 +1,85 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + EmbeddingModel, + EmbeddingModelInput, + EmbeddingModelOutput, + EmbeddingModelEvents, +} from "@/backend/embedding.js"; +import { embedMany, EmbeddingModel as Model } from "ai"; +import { Emitter } from "@/emitter/emitter.js"; +import { GetRunContext } from "@/context.js"; +import { toCamelCase } from "remeda"; +import { FullModelName } from "@/backend/utils.js"; + +type InternalEmbeddingModel = Model; + +export class VercelEmbeddingModel< + R extends InternalEmbeddingModel = InternalEmbeddingModel, +> extends EmbeddingModel { + public readonly emitter: Emitter; + + constructor(public readonly model: R) { + super(); + this.emitter = Emitter.root.child({ + namespace: ["backend", this.providerId, "embedding"], + creator: this, + }); + } + + get modelId(): string { + return this.model.modelId; + } + + get providerId(): string { + const provider = this.model.provider.split(".")[0].split("-")[0]; + return toCamelCase(provider); + } + + protected async _create( + input: EmbeddingModelInput, + run: GetRunContext, + ): Promise { + return embedMany({ + model: this.model, + values: input.values, + abortSignal: run.signal, + }); + } + + createSnapshot() { + return { + ...super.createSnapshot(), + providerId: this.providerId, + modelId: this.model, + }; + } + + async loadSnapshot({ providerId, modelId, ...snapshot }: ReturnType) { + const instance = await VercelEmbeddingModel.fromName( + `${providerId}:${modelId}` as FullModelName, + ); + if (!(instance instanceof VercelEmbeddingModel)) { + throw new Error("Incorrect deserialization!"); + } + instance.destroy(); + Object.assign(this, { + ...snapshot, + model: instance.model, + }); + } +} diff --git a/src/adapters/vertexai/chat.test.ts b/src/adapters/vertexai/chat.test.ts deleted file mode 100644 index 24f957e4..00000000 --- a/src/adapters/vertexai/chat.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { VertexAIChatLLM } from "@/adapters/vertexai/chat.js"; - -describe("VertexAI ChatLLM", () => { - const getInstance = () => { - return new VertexAIChatLLM({ - modelId: "gemini-1.5-flash-001", - location: "us-central1", - project: "systemInstruction", - }); - }; - - it("Serializes", async () => { - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = VertexAIChatLLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); diff --git a/src/adapters/vertexai/chat.ts b/src/adapters/vertexai/chat.ts deleted file mode 100644 index 9a32ba49..00000000 --- a/src/adapters/vertexai/chat.ts +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - AsyncStream, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import type { GetRunContext } from "@/context.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { VertexAI, BaseModelParams as Params } from "@google-cloud/vertexai"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { signalRace } from "@/internals/helpers/promise.js"; -import { processContentResponse, registerVertexAI, createModel } from "./utils.js"; -import { NotImplementedError } from "@/errors.js"; - -export class VertexAIChatLLMOutput extends ChatLLMOutput { - public readonly chunks: BaseMessage[] = []; - - constructor(chunk: BaseMessage) { - super(); - this.chunks.push(chunk); - } - - get messages() { - return this.chunks; - } - - merge(other: VertexAIChatLLMOutput): void { - this.chunks.push(...other.chunks); - } - - getTextContent(): string { - return this.chunks.map((result) => result.text).join(""); - } - - toString() { - return this.getTextContent(); - } - - createSnapshot() { - return { chunks: shallowCopy(this.chunks) }; - } - - loadSnapshot(snapshot: typeof this.createSnapshot): void { - Object.assign(this, snapshot); - } -} - -export interface VertexAIChatLLMInput { - modelId: string; - project: string; - location: string; - client?: VertexAI; - executionOptions?: ExecutionOptions; - cache?: LLMCache; - parameters?: Params; -} - -export type VertexAIChatLLMEvents = ChatLLMGenerateEvents; - -export class VertexAIChatLLM extends ChatLLM { - public readonly emitter = Emitter.root.child({ - namespace: ["vertexai", "llm"], - creator: this, - }); - - protected client: VertexAI; - protected parameters?: Params; - - constructor(protected readonly input: VertexAIChatLLMInput) { - super(input.modelId, input.executionOptions, input.cache); - this.parameters = input.parameters; - this.client = new VertexAI({ project: input.project, location: input.location }); - } - - static { - this.register(); - registerVertexAI(); - } - - async meta(): Promise { - return { tokenLimit: Infinity }; - } - - // eslint-disable-next-line unused-imports/no-unused-vars - async embed(input: BaseMessage[][], options?: EmbeddingOptions): Promise { - throw new NotImplementedError(); - } - - async tokenize(input: BaseMessage[]): Promise { - const generativeModel = createModel(this.client, this.modelId); - const response = await generativeModel.countTokens({ - contents: input.map((msg) => ({ parts: [{ text: msg.text }], role: msg.role })), - }); - return { - tokensCount: response.totalTokens, - }; - } - - protected async _generate( - input: BaseMessage[], - options: GenerateOptions, - run: GetRunContext, - ): Promise { - const generativeModel = createModel( - this.client, - this.modelId, - options.guided?.json, - this.parameters, - ); - const response = await signalRace( - () => - generativeModel.generateContent({ - contents: input.map((msg) => ({ parts: [{ text: msg.text }], role: msg.role })), - }), - run.signal, - ); - const result = BaseMessage.of({ - role: Role.ASSISTANT, - text: processContentResponse(response.response), - }); - return new VertexAIChatLLMOutput(result); - } - - protected async *_stream( - input: BaseMessage[], - options: Partial, - run: GetRunContext, - ): AsyncStream { - const generativeModel = createModel( - this.client, - this.modelId, - options?.guided?.json, - this.parameters, - ); - const chat = generativeModel.startChat(); - const response = await chat.sendMessageStream(input.map((msg) => msg.text)); - for await (const chunk of response.stream) { - if (options?.signal?.aborted) { - break; - } - const result = BaseMessage.of({ - role: Role.ASSISTANT, - text: processContentResponse(chunk), - }); - yield new VertexAIChatLLMOutput(result); - } - run.signal.throwIfAborted(); - } - - createSnapshot() { - return { - ...super.createSnapshot(), - input: shallowCopy(this.input), - client: this.client, - parameters: this.parameters, - }; - } -} diff --git a/src/adapters/vertexai/llm.ts b/src/adapters/vertexai/llm.ts deleted file mode 100644 index 14ae46e4..00000000 --- a/src/adapters/vertexai/llm.ts +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LLM, LLMEvents, LLMInput } from "@/llms/llm.js"; -import { - AsyncStream, - BaseLLMOutput, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMMeta, - StreamGenerateOptions, -} from "@/llms/base.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import type { GetRunContext } from "@/context.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { VertexAI, BaseModelParams as Params } from "@google-cloud/vertexai"; -import { Role } from "@/llms/primitives/message.js"; -import { signalRace } from "@/internals/helpers/promise.js"; -import { processContentResponse, getTokenCount, registerVertexAI, createModel } from "./utils.js"; -import { NotImplementedError } from "@/errors.js"; - -interface VertexAILLMChunk { - text: string; - metadata: Record; -} - -export class VertexAILLMOutput extends BaseLLMOutput { - public readonly chunks: VertexAILLMChunk[] = []; - - constructor(chunk: VertexAILLMChunk) { - super(); - this.chunks.push(chunk); - } - - merge(other: VertexAILLMOutput): void { - this.chunks.push(...other.chunks); - } - - getTextContent(): string { - return this.chunks.map((result) => result.text).join(""); - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { chunks: shallowCopy(this.chunks) }; - } - - loadSnapshot(snapshot: ReturnType): void { - Object.assign(this, snapshot); - } -} - -export interface VertexAILLMInput { - modelId: string; - project: string; - location: string; - client?: VertexAI; - executionOptions?: ExecutionOptions; - cache?: LLMCache; - parameters?: Params; -} - -export type VertexAILLMEvents = LLMEvents; - -export class VertexAILLM extends LLM { - public readonly emitter = Emitter.root.child({ - namespace: ["vertexai", "llm"], - creator: this, - }); - - protected client: VertexAI; - protected parameters?: Params; - - constructor(protected readonly input: VertexAILLMInput) { - super(input.modelId, input.executionOptions, input.cache); - this.parameters = input.parameters; - this.client = - input.client ?? new VertexAI({ project: input.project, location: input.location }); - } - - static { - this.register(); - registerVertexAI(); - } - - async meta(): Promise { - return { tokenLimit: Infinity }; - } - - // eslint-disable-next-line unused-imports/no-unused-vars - async embed(input: LLMInput[], options?: EmbeddingOptions): Promise { - throw new NotImplementedError(); - } - - async tokenize(input: LLMInput): Promise { - const generativeModel = createModel(this.client, this.modelId); - const response = await generativeModel.countTokens({ - contents: [{ parts: [{ text: input }], role: Role.USER }], - }); - return { - tokensCount: response.totalTokens, - }; - } - - protected async _generate( - input: LLMInput, - options: GenerateOptions, - run: GetRunContext, - ): Promise { - const generativeModel = createModel( - this.client, - this.modelId, - options.guided?.json, - this.parameters, - ); - const responses = await signalRace(() => generativeModel.generateContent(input), run.signal); - const result: VertexAILLMChunk = { - text: processContentResponse(responses.response), - metadata: { tokenCount: getTokenCount(responses.response) }, - }; - return new VertexAILLMOutput(result); - } - - protected async *_stream( - input: LLMInput, - options: Partial, - run: GetRunContext, - ): AsyncStream { - const generativeModel = createModel( - this.client, - this.modelId, - options?.guided?.json, - this.parameters, - ); - const response = await generativeModel.generateContentStream(input); - for await (const chunk of response.stream) { - if (options?.signal?.aborted) { - break; - } - const result: VertexAILLMChunk = { - text: processContentResponse(chunk), - metadata: { tokenCount: getTokenCount(chunk) }, - }; - yield new VertexAILLMOutput(result); - } - run.signal.throwIfAborted(); - } - - createSnapshot() { - return { - ...super.createSnapshot(), - input: shallowCopy(this.input), - client: this.client, - parameters: this.parameters, - }; - } - - loadSnapshot({ input, ...snapshot }: ReturnType) { - super.loadSnapshot(snapshot); - Object.assign(this, { input }); - } -} diff --git a/src/adapters/vertexai/utils.ts b/src/adapters/vertexai/utils.ts deleted file mode 100644 index f19e029e..00000000 --- a/src/adapters/vertexai/utils.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { isString } from "remeda"; -import { Serializer } from "@/serializer/serializer.js"; -import { - VertexAI, - GenerativeModel, - ModelParams, - BaseModelParams as Params, -} from "@google-cloud/vertexai"; -import { getPropStrict } from "@/internals/helpers/object.js"; -import { GenerateContentResponse } from "@google-cloud/vertexai"; - -export function processContentResponse(response: GenerateContentResponse): string { - return ( - response.candidates - ?.flatMap((candidate) => - candidate.content.parts.filter((part) => part.text).map((part) => part.text!), - ) - .join() || "Empty" - ); -} - -export function getTokenCount(response: GenerateContentResponse): number { - return response.usageMetadata?.totalTokenCount ?? Infinity; -} - -export function registerVertexAI() { - Serializer.register(VertexAI, { - toPlain: (value) => ({ - project: getPropStrict(value, "project"), - location: getPropStrict(value, "location"), - }), - fromPlain: (value) => { - return new VertexAI({ project: value.project, location: value.location }); - }, - }); -} - -export function createModel( - client: VertexAI, - modelId: string, - schema?: string | Record, - params?: Params, -): GenerativeModel { - const modelParams: ModelParams = { model: modelId, ...params }; - if (schema) { - const schemaJson = isString(schema) ? JSON.parse(schema) : schema; - modelParams.generationConfig = { - ...modelParams.generationConfig, - responseSchema: schemaJson, - responseMimeType: "application/json", - }; - } - return client.getGenerativeModel(modelParams); -} diff --git a/src/adapters/watsonx/backend/chat.ts b/src/adapters/watsonx/backend/chat.ts new file mode 100644 index 00000000..cc4b5505 --- /dev/null +++ b/src/adapters/watsonx/backend/chat.ts @@ -0,0 +1,197 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChatModel, ChatModelEmitter, ChatModelInput, ChatModelOutput } from "@/backend/chat.js"; +import { WatsonxClient, WatsonxClientSettings } from "@/adapters/watsonx/backend/client.js"; +import { findLast, isEmpty, isTruthy } from "remeda"; +import WatsonxAiMlVml_v1, { + TextChatMessages, + TextChatParameterTools, + TextChatParams, + TextChatResultChoice, + TextChatUsage, +} from "@ibm-cloud/watsonx-ai/dist/watsonx-ai-ml/vml_v1.js"; +import { shallowCopy } from "@/serializer/utils.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { GetRunContext } from "@/context.js"; +import { AssistantMessage, Message, SystemMessage, ToolMessage } from "@/backend/message.js"; +import { ToolCallPart } from "ai"; +import Type = WatsonxAiMlVml_v1.TextChatResponseFormat.Constants.Type; +import { parseBrokenJson } from "@/internals/helpers/schema.js"; +import { getEnv } from "@/internals/env.js"; + +export class WatsonxChatModel extends ChatModel { + protected readonly client: WatsonxClient; + public readonly emitter: ChatModelEmitter = Emitter.root.child({ + namespace: ["backend", "watsonx", "chat"], + creator: this, + }); + + get providerId() { + return "watsonx"; + } + + constructor( + public readonly modelId = getEnv("WATSONX_CHAT_MODEL", "ibm/granite-3-8b-instruct"), + client?: WatsonxClient | WatsonxClientSettings, + ) { + super(); + this.client = WatsonxClient.ensure(client); + } + + protected async _create(input: ChatModelInput) { + // TODO: support abortion (https://github.com/IBM/watsonx-ai-node-sdk/issues/3) + const { result } = await this.client.instance.textChat(await this.prepareInput(input)); + const { messages, finishReason, usage } = this.extractOutput(result.choices, result.usage); + return new ChatModelOutput(messages, usage, finishReason); + } + + async *_createStream(input: ChatModelInput, run: GetRunContext) { + const stream = await this.client.instance.textChatStream({ + ...(await this.prepareInput(input)), + returnObject: true, + }); + for await (const raw of stream) { + if (run.signal.aborted) { + stream.controller.abort(run.signal.aborted); + break; + } + const { messages, finishReason, usage } = this.extractOutput( + raw.data.choices.map(({ delta, ...choice }) => ({ ...choice, message: delta })), + raw.data.usage, + ); + yield new ChatModelOutput(messages, usage, finishReason); + } + } + + protected extractOutput(choices: TextChatResultChoice[], usage?: TextChatUsage) { + return { + finishReason: findLast(choices, (choice) => Boolean(choice?.finish_reason)) + ?.finish_reason as ChatModelOutput["finishReason"], + usage: usage + ? { + completionTokens: usage.completion_tokens ?? 0, + promptTokens: usage.prompt_tokens ?? 0, + totalTokens: usage.total_tokens ?? 0, + } + : undefined, + messages: choices + .flatMap(({ message }) => { + const messages: Message[] = []; + if (message?.content) { + const msg = new AssistantMessage({ type: "text", text: message.content }); + // msg.role = message.role || msg.role; + messages.push(msg); + } + if (message?.tool_calls) { + const msg = new AssistantMessage( + message.tool_calls.map( + (call): ToolCallPart => ({ + type: "tool-call", + toolCallId: call.id, + toolName: call.function.name, + args: parseBrokenJson(call.function.arguments), + }), + ), + ); + // msg.role = message.role || msg.role; + messages.push(msg); + } + if (message?.refusal) { + const msg = new AssistantMessage({ type: "text", text: message.refusal }); + // msg.role = message.role || msg.role; + messages.push(msg); + } + return messages; + }) + .filter(isTruthy), + }; + } + + protected async prepareInput(input: ChatModelInput): Promise { + const tools: TextChatParameterTools[] = await Promise.all( + (input.tools ?? []).map(async (tool) => ({ + type: "function", + function: { + name: tool.name, + description: tool.description, + parameters: await tool.getInputJsonSchema(), + }, + })), + ); + + return { + ...this.parameters, + modelId: this.modelId, + messages: input.messages.flatMap((message): TextChatMessages[] => { + if (message instanceof ToolMessage) { + return message.content.map((content) => ({ + role: "tool", + content: JSON.stringify(content.result), + tool_call_id: content.toolCallId, + })); + } else if (message instanceof SystemMessage) { + return message.content.map((content) => ({ + role: "system", + content: content.text, + })); + } else if (message instanceof AssistantMessage) { + return message.content.map((content) => ({ + role: "assistant", + ...(content.type === "text" && { + content: content.text, + }), + ...(content.type === "tool-call" && { + id: content.toolCallId, + type: "function", + function: { + name: content.toolName, + arguments: JSON.stringify(content.args), + }, + }), + })); + } else { + return [message.toPlain()]; + } + }), + spaceId: this.client.spaceId, + projectId: this.client.projectId, + tools: isEmpty(tools) ? undefined : tools, + maxTokens: input.maxTokens ?? this.parameters.maxTokens, + topP: input.topP ?? this.parameters.topP, + frequencyPenalty: input.frequencyPenalty ?? this.parameters.frequencyPenalty, + temperature: input.temperature ?? this.parameters.temperature, + n: input.topK ?? this.parameters.topK, + presencePenalty: input.presencePenalty ?? this.parameters.presencePenalty, + ...(input.responseFormat?.type === "object-json" && { + responseFormat: { type: Type.JSON_OBJECT }, + }), + }; + } + + createSnapshot() { + return { + ...super.createSnapshot(), + modelId: this.modelId, + parameters: shallowCopy(this.parameters), + client: this.client, + }; + } + + loadSnapshot(snapshot: ReturnType) { + Object.assign(this, snapshot); + } +} diff --git a/src/adapters/watsonx/backend/client.ts b/src/adapters/watsonx/backend/client.ts new file mode 100644 index 00000000..b3108e2a --- /dev/null +++ b/src/adapters/watsonx/backend/client.ts @@ -0,0 +1,68 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { WatsonXAI } from "@ibm-cloud/watsonx-ai"; +import { getEnv } from "@/internals/env.js"; +import { IamAuthenticator, UserOptions } from "ibm-cloud-sdk-core"; +import { BackendClient } from "@/backend/client.js"; + +export interface WatsonxClientSettings extends Pick { + spaceId?: string; + baseUrl?: string; + region?: string; + projectId?: string; + apiKey?: string; +} + +export class WatsonxClient extends BackendClient { + constructor(settings: WatsonxClientSettings) { + const region = settings?.region || getEnv("WATSONX_REGION"); + const baseUrl = + settings?.baseUrl || getEnv("WATSONX_BASE_URL") || `https://${region}.ml.cloud.ibm.com`; + + const projectId = settings?.projectId || getEnv("WATSONX_PROJECT_ID"); + const spaceId = projectId ? undefined : settings?.spaceId || getEnv("WATSONX_SPACE_ID"); + const version = settings?.version || getEnv("WATSONX_VERSION") || "2024-05-31"; + + super({ + ...settings, + baseUrl, + projectId, + spaceId, + version, + }); + } + get spaceId() { + return this.settings.spaceId; + } + + get projectId() { + return this.settings.projectId; + } + + protected create() { + return WatsonXAI.newInstance({ + version: this.settings.version, + serviceUrl: this.settings.baseUrl, + authenticator: + this.settings?.authenticator || + new IamAuthenticator({ + apikey: getEnv("WATSONX_API_KEY", this.settings?.apiKey ?? ""), + url: "https://iam.cloud.ibm.com", + }), + }); + } +} diff --git a/src/adapters/watsonx/backend/embedding.ts b/src/adapters/watsonx/backend/embedding.ts new file mode 100644 index 00000000..16702aff --- /dev/null +++ b/src/adapters/watsonx/backend/embedding.ts @@ -0,0 +1,89 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { WatsonxClient, WatsonxClientSettings } from "@/adapters/watsonx/backend/client.js"; +import { + EmbeddingModel, + EmbeddingModelInput, + EmbeddingModelOutput, + EmbeddingModelEvents, +} from "@/backend/embedding.js"; +import { EmbeddingParameters as WXEmbeddingParameters } from "@ibm-cloud/watsonx-ai/dist/watsonx-ai-ml/vml_v1.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { getEnv } from "@/internals/env.js"; + +export type WatsonxEmbeddingModelParameters = WXEmbeddingParameters; + +export class WatsonxEmbeddingModel extends EmbeddingModel { + protected readonly client: WatsonxClient; + public readonly emitter: Emitter; + + get providerId() { + return "watsonx"; + } + + constructor( + public readonly modelId: string = getEnv( + "WATSONX_EMBEDDING_MODEL", + "ibm/granite-embedding-107m-multilingual", + ), + public readonly parameters: WatsonxEmbeddingModelParameters = {}, + client?: WatsonxClient | WatsonxClientSettings, + ) { + super(); + this.client = WatsonxClient.ensure(client); + this.emitter = Emitter.root.child({ + namespace: ["backend", "watsonx", "embedding"], + creator: this, + }); + } + + protected async _create(input: EmbeddingModelInput): Promise { + const response = await this.client.instance.embedText({ + modelId: this.modelId, + spaceId: this.client.spaceId, + projectId: this.client.projectId, + inputs: input.values, + parameters: { + return_options: { input_text: true }, + ...this.parameters, + }, + }); + + const embeddings = response.result.results.map((e) => e.embedding); + const values = response.result.results.map((e, i) => e.input || input.values.at(i)!); + + return { + embeddings, + values, + usage: { + tokens: response.result.input_token_count, + }, + }; + } + + createSnapshot() { + return { + ...super.createSnapshot(), + modelId: this.modelId, + client: this.client, + }; + } + + loadSnapshot(snapshot: ReturnType): void { + Object.assign(this, snapshot); + } +} diff --git a/src/adapters/watsonx/chat.ts b/src/adapters/watsonx/chat.ts deleted file mode 100644 index 71e04baf..00000000 --- a/src/adapters/watsonx/chat.ts +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { AsyncStream, EmbeddingOptions, EmbeddingOutput, LLMCache, LLMError } from "@/llms/base.js"; -import { - WatsonXLLM, - WatsonXLLMGenerateOptions, - WatsonXLLMParameters, - WatsonXLLMOutput, - WatsonXLLMInput, -} from "@/adapters/watsonx/llm.js"; -import { ChatLLM, ChatLLMGenerateEvents, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { Cache } from "@/cache/decoratorCache.js"; -import { transformAsyncIterable } from "@/internals/helpers/stream.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { GetRunContext } from "@/context.js"; -import { isFunction, isObjectType } from "remeda"; -import { WatsonXChatLLMPreset, WatsonXChatLLMPresetModel } from "@/adapters/watsonx/chatPreset.js"; - -export class WatsonXChatLLMOutput extends ChatLLMOutput { - public readonly raw: WatsonXLLMOutput; - - constructor(rawOutput: WatsonXLLMOutput) { - super(); - this.raw = rawOutput; - } - - @Cache() - get messages(): BaseMessage[] { - const text = this.raw.getTextContent(); - return [ - BaseMessage.of({ - role: Role.ASSISTANT, - text, - meta: this.raw.meta, - }), - ]; - } - - merge(other: WatsonXChatLLMOutput): void { - Cache.getInstance(this, "messages").clear(); - this.raw.merge(other.raw); - } - - getTextContent(): string { - const [message] = this.messages; - return message.text; - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot() { - return { - raw: shallowCopy(this.raw), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } -} - -export interface WatsonXChatLLMInputConfig { - messagesToPrompt: (messages: BaseMessage[]) => string; -} - -export interface WatsonXChatLLMInput { - llm: WatsonXLLM; - config: WatsonXChatLLMInputConfig; - cache?: LLMCache; -} - -export type WatsonXChatLLMEvents = ChatLLMGenerateEvents; - -export class WatsonXChatLLM extends ChatLLM { - public readonly emitter = Emitter.root.child({ - namespace: ["watsonx", "chat_llm"], - creator: this, - }); - - public readonly llm: WatsonXLLM; - protected readonly config: WatsonXChatLLMInputConfig; - public readonly parameters: WatsonXLLMParameters; - - constructor({ llm, config, cache }: WatsonXChatLLMInput) { - super(llm.modelId, llm.executionOptions, cache); - this.parameters = llm.parameters ?? {}; - this.llm = llm; - this.config = config; - } - - static { - this.register(); - } - - async meta() { - return this.llm.meta(); - } - - async embed(input: BaseMessage[][], options?: EmbeddingOptions): Promise { - const inputs = input.map((messages) => this.messagesToPrompt(messages)); - return this.llm.embed(inputs, options); - } - - createSnapshot() { - return { - ...super.createSnapshot(), - modelId: this.modelId, - parameters: this.parameters, - executionOptions: this.executionOptions, - llm: this.llm, - config: shallowCopy(this.config), - }; - } - - loadSnapshot(data: ReturnType): void { - super.loadSnapshot(data); - } - - async tokenize(messages: BaseMessage[]) { - const prompt = this.messagesToPrompt(messages); - return this.llm.tokenize(prompt); - } - - protected async _generate( - messages: BaseMessage[], - options: WatsonXLLMGenerateOptions | undefined, - run: GetRunContext, - ): Promise { - const prompt = this.messagesToPrompt(messages); - // @ts-expect-error protected property - const rawResponse = await this.llm._generate(prompt, options, run); - return new WatsonXChatLLMOutput(rawResponse); - } - - protected async *_stream( - messages: BaseMessage[], - options: WatsonXLLMGenerateOptions | undefined, - run: GetRunContext, - ): AsyncStream { - const prompt = this.messagesToPrompt(messages); - // @ts-expect-error protected property - const response = this.llm._stream(prompt, options, run); - return yield* transformAsyncIterable(response, (output) => new WatsonXChatLLMOutput(output)); - } - - messagesToPrompt(messages: BaseMessage[]) { - return this.config.messagesToPrompt(messages); - } - - static fromPreset( - modelId: WatsonXChatLLMPresetModel, - overrides: Omit & { - parameters?: WatsonXLLMParameters | ((value: WatsonXLLMParameters) => WatsonXLLMParameters); - }, - ) { - const preset = WatsonXChatLLMPreset[modelId]?.(); - if (!preset) { - throw new LLMError(`Model "${modelId}" does not exist in preset.`); - } - - let parameters = preset.base.parameters ?? {}; - if (isFunction(overrides?.parameters)) { - parameters = overrides?.parameters(parameters); - } else if (isObjectType(overrides?.parameters)) { - parameters = overrides?.parameters; - } - - return new WatsonXChatLLM({ - config: preset.chat, - llm: new WatsonXLLM({ - ...preset.base, - ...overrides, - parameters, - modelId, - }), - }); - } -} diff --git a/src/adapters/watsonx/chatPreset.ts b/src/adapters/watsonx/chatPreset.ts deleted file mode 100644 index dcab5aa0..00000000 --- a/src/adapters/watsonx/chatPreset.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LLMChatTemplates } from "@/adapters/shared/llmChatTemplates.js"; -import { WatsonXLLMInput } from "@/adapters/watsonx/llm.js"; -import { WatsonXChatLLMInputConfig } from "@/adapters/watsonx/chat.js"; - -interface WatsonXChatLLMPreset { - chat: WatsonXChatLLMInputConfig; - base: Omit; -} - -export const WatsonXChatLLMPreset = { - "meta-llama/llama-3-3-70b-instruct": (): WatsonXChatLLMPreset => { - const { template, messagesToPrompt, parameters } = LLMChatTemplates.get("llama3.3"); - - return { - base: { - parameters: { - decoding_method: "greedy", - include_stop_sequence: false, - max_new_tokens: 2048, - repetition_penalty: 1, - stop_sequences: [...parameters.stop_sequence], - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - "ibm/granite-3-8b-instruct": (): WatsonXChatLLMPreset => { - const { template, parameters, messagesToPrompt } = LLMChatTemplates.get("granite3.1-Instruct"); - return { - base: { - parameters: { - decoding_method: "greedy", - max_new_tokens: 2048, - include_stop_sequence: false, - stop_sequences: [...parameters.stop_sequence], - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - "ibm/granite-3-2b-instruct"() { - return WatsonXChatLLMPreset["ibm/granite-3-8b-instruct"](); - }, - "meta-llama/llama-3-1-70b-instruct": (): WatsonXChatLLMPreset => { - const { template, messagesToPrompt, parameters } = LLMChatTemplates.get("llama3.1"); - - return { - base: { - parameters: { - decoding_method: "greedy", - include_stop_sequence: false, - max_new_tokens: 2048, - repetition_penalty: 1, - stop_sequences: [...parameters.stop_sequence], - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - "meta-llama/llama-3-1-405b-instruct"() { - return WatsonXChatLLMPreset["meta-llama/llama-3-1-70b-instruct"](); - }, - "meta-llama/llama-3-1-8b-instruct"() { - return WatsonXChatLLMPreset["meta-llama/llama-3-1-70b-instruct"](); - }, - "meta-llama/llama-3-70b-instruct": (): WatsonXChatLLMPreset => { - const { template, messagesToPrompt, parameters } = LLMChatTemplates.get("llama3"); - - return { - base: { - parameters: { - decoding_method: "greedy", - max_new_tokens: 1500, - include_stop_sequence: false, - stop_sequences: [...parameters.stop_sequence], - }, - }, - chat: { - messagesToPrompt: messagesToPrompt(template), - }, - }; - }, - "meta-llama/llama-3-8b-instruct"() { - return WatsonXChatLLMPreset["meta-llama/llama-3-70b-instruct"](); - }, -} as const; - -export type WatsonXChatLLMPresetModel = keyof typeof WatsonXChatLLMPreset; diff --git a/src/adapters/watsonx/llm.ts b/src/adapters/watsonx/llm.ts deleted file mode 100644 index ad774dc3..00000000 --- a/src/adapters/watsonx/llm.ts +++ /dev/null @@ -1,487 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LLM, LLMEvents, LLMInput } from "@/llms/llm.js"; -import { - AsyncStream, - BaseLLMOutput, - BaseLLMTokenizeOutput, - EmbeddingOptions, - EmbeddingOutput, - ExecutionOptions, - GenerateOptions, - LLMCache, - LLMError, - LLMFatalError, - LLMMeta, - LLMOutputError, -} from "@/llms/base.js"; -import * as R from "remeda"; -import { FrameworkError, ValueError } from "@/errors.js"; -import { Cache, CacheFn } from "@/cache/decoratorCache.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { safeSum } from "@/internals/helpers/number.js"; -import { getProp, omitUndefined } from "@/internals/helpers/object.js"; -import { createURLParams, RestfulClient, RestfulClientError } from "@/internals/fetcher.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { GetRunContext } from "@/context.js"; -import { getEnv } from "@/internals/env.js"; - -export interface WatsonXLLMOutputMeta { - model_id: string; - created_at: string; -} - -export interface WatsonXLLMOutputResult { - generated_text: string; - generated_token_count: number; - input_token_count: number; - stop_reason?: string; -} - -export interface WatsonXLLMOutputConstructor { - meta: WatsonXLLMOutputMeta; - results: WatsonXLLMOutputResult[]; - system: Record[]>; -} - -export class WatsonXLLMOutput extends BaseLLMOutput { - public readonly meta: WatsonXLLMOutputMeta; - public readonly results: WatsonXLLMOutputResult[]; - - constructor(content: WatsonXLLMOutputConstructor) { - super(); - this.meta = content.meta; - this.results = content.results; - } - - static { - this.register(); - } - - getTextContent(): string { - return this.finalResult.generated_text; - } - - @Cache() - get finalResult(): Readonly { - if (this.results.length === 0) { - throw new LLMOutputError("No chunks to get final result from!"); - } - - const processors: { - [K in keyof WatsonXLLMOutputResult]: ( - value: WatsonXLLMOutputResult[K], - oldValue: WatsonXLLMOutputResult[K], - ) => WatsonXLLMOutputResult[K]; - } = { - generated_text: (value = "", oldValue = "") => oldValue + value, - input_token_count: safeSum, - generated_token_count: safeSum, - stop_reason: (value, oldValue) => value ?? oldValue, - }; - - const finalResult = {} as WatsonXLLMOutputResult; - for (const next of this.results) { - for (const [key, value] of R.entries(next)) { - const oldValue = finalResult[key]; - // @ts-expect-error weak typing due to generated types - finalResult[key] = (processors[key] ?? takeFirst)(value, oldValue); - } - } - - return finalResult; - } - - merge(other: WatsonXLLMOutput): void { - Cache.getInstance(this, "finalResult").clear(); - - this.results.push(...other.results); - Object.assign(this.meta, omitUndefined(other.meta)); - } - - createSnapshot() { - return { - results: shallowCopy(this.results), - meta: shallowCopy(this.meta), - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } - - toString(): string { - return this.getTextContent(); - } -} - -export interface WatsonXLLMParameters extends GenerateOptions { - [key: string]: any; - decoding_method?: "sample" | "greedy"; - length_penalty?: { - decay_factor?: number; - start_index?: number; - }; - max_new_tokens?: number; - min_new_tokens?: number; - random_seed?: number; - stop_sequences?: string[]; - temperature?: number; - time_limit?: number; - top_k?: number; - top_p?: number; - repetition_penalty?: number; - truncate_input_tokens?: number; - return_options?: { - input_text?: boolean; - generated_tokens?: boolean; - input_tokens?: boolean; - token_logprobs?: boolean; - token_ranks?: boolean; - top_n_tokens?: boolean; - }; - include_stop_sequence?: boolean; - typical_p?: number; - prompt_variables?: Record; -} -export type WatsonXLLMModerations = Record; - -export interface WatsonXLLMGenerateOptions extends GenerateOptions { - parameters?: WatsonXLLMParameters; - moderations?: WatsonXLLMModerations; -} - -export interface WatsonXLLMInput { - modelId: string; - projectId?: string; - spaceId?: string; - deploymentId?: string; - version?: string; - apiKey?: string; - accessToken?: string; - baseUrl?: string; - authBaseUrl?: string; - region?: string; - parameters?: WatsonXLLMParameters; - moderations?: WatsonXLLMModerations; - executionOptions?: ExecutionOptions; - transform?: WatsonXLLMTransformFn; - cache?: LLMCache; -} - -type WatsonXLLMTransformFn = (body: Record) => Record; - -function createApiClient({ - deploymentId, - apiKey, - baseUrl, - authBaseUrl = "https://iam.cloud.ibm.com", - region, - accessToken, - version = "2023-05-02", - projectId, - spaceId, -}: WatsonXLLMInput) { - region = region || getEnv("WATSONX_REGION") || "us-south"; - - const paths = (() => { - const pathPrefix = deploymentId ? `/ml/v1/deployments/${deploymentId}` : "/ml/v1"; - const queryParams = createURLParams({ - version, - }); - - return { - generate: `${pathPrefix}/text/generation?${queryParams}`, - generate_stream: `${pathPrefix}/text/generation_stream?${queryParams}`, - tokenization: `/ml/v1/text/tokenization?${queryParams}`, - models: `/ml/v1/foundation_model_specs?${queryParams}`, - deployment: deploymentId - ? `/ml/v4/deployments/${deploymentId}?${createURLParams({ version, project_id: projectId, space_id: projectId ? undefined : spaceId })}` - : "not_defined_endpoint", - embeddings: "/ml/v1/text/embeddings", - }; - })(); - - if (accessToken && apiKey) { - throw new ValueError(`Use either "accessToken" or "apiKey".`); - } else if (!accessToken && !apiKey) { - accessToken = getEnv("WATSONX_ACCESS_TOKEN"); - apiKey = accessToken ? undefined : getEnv("WATSONX_API_KEY"); - } - - if (!accessToken && !apiKey) { - throw new ValueError( - [ - `Neither "accessToken" nor "apiKey" has been provided.`, - `Either set them directly or put them in ENV ("WATSONX_ACCESS_TOKEN" / "WATSONX_API_KEY")`, - ].join("\n"), - ); - } - - const getHeaders = CacheFn.create(async () => { - const getAccessToken = async () => { - if (accessToken) { - return { ttl: Infinity, token: accessToken }; - } - - const response = await fetch(new URL("/identity/token", authBaseUrl), { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - body: createURLParams({ - grant_type: "urn:ibm:params:oauth:grant-type:apikey", - apikey: apiKey, - }), - }); - - if (!response.ok) { - throw new RestfulClientError("Failed to retrieve an API token.", [], { - context: response, - }); - } - - const data = await response.json(); - if (!data?.access_token) { - throw new RestfulClientError("Access Token was not found in the response."); - } - return { ttl: (data.expires_in - 60) * 1000, token: data.access_token as string }; - }; - - const response = await getAccessToken(); - getHeaders.updateTTL(response.ttl); - return new Headers({ - "Authorization": `Bearer ${response.token}`, - "Accept": "application/json", - "Content-Type": "application/json", - }); - }); - - return new RestfulClient({ - baseUrl: baseUrl || `https://${region}.ml.cloud.ibm.com`, - paths, - headers: getHeaders, - }); -} - -export type WatsonXLLMEvents = LLMEvents; - -export class WatsonXLLM extends LLM { - public readonly emitter = Emitter.root.child({ - namespace: ["watsonx", "llm"], - creator: this, - }); - - public readonly client; - protected projectId; - protected deploymentId; - protected spaceId; - protected transform: WatsonXLLMTransformFn; - public readonly moderations; - public readonly parameters: WatsonXLLMParameters; - - constructor(input: WatsonXLLMInput) { - super(input.modelId, input.executionOptions, input.cache); - this.projectId = input.projectId; - this.spaceId = input.spaceId; - this.deploymentId = input.deploymentId; - this.moderations = input.moderations; - this.transform = input.transform ?? ((input) => input); - this.client = createApiClient(input); - this.parameters = input.parameters ?? {}; - } - - static { - this.register(); - } - - @Cache() - async meta(): Promise { - let modelId = this.modelId; - if (this.deploymentId) { - const { entity } = await this.client.fetch("deployment"); - modelId = entity.base_model_id ?? modelId; - } - - if (!modelId) { - throw new LLMFatalError(`Cannot retrieve metadata for model '${modelId ?? "undefined"}'`); - } - - const { - resources: [model], - } = await this.client.fetch("models", { - searchParams: createURLParams({ - filters: `modelid_${modelId}`, - limit: "1", - }), - }); - - return { - tokenLimit: model?.model_limits?.max_sequence_length ?? Infinity, - }; - } - - async embed(input: LLMInput[], options?: EmbeddingOptions): Promise { - const response: { results: { embedding: number[] }[] } = await this.client.fetch("embeddings", { - method: "POST", - searchParams: new URLSearchParams({ version: "2023-10-25" }), - body: JSON.stringify({ - inputs: input, - model_id: this.modelId, - project_id: this.projectId, - parameters: { - truncate_input_tokens: 512, - }, - }), - signal: options?.signal, - }); - if (response.results?.length !== input.length) { - throw new Error("Missing embedding"); - } - const embeddings = response.results.map((result) => result.embedding); - return { embeddings }; - } - - createSnapshot() { - return { - ...super.createSnapshot(), - modelId: this.modelId, - spaceId: this.spaceId, - deploymentId: this.deploymentId, - projectId: this.projectId, - parameters: shallowCopy(this.parameters), - moderations: shallowCopy(this.moderations), - executionOptions: shallowCopy(this.executionOptions), - transform: this.transform, - client: this.client, - }; - } - - loadSnapshot(snapshot: ReturnType): void { - super.loadSnapshot(snapshot); - } - - protected _transformError(error: Error): Error { - if (error instanceof FrameworkError) { - throw error; - } - if (error?.name === "HttpError") { - throw new LLMError("LLM has occurred an error!", [error], { - isRetryable: [408, 425, 429, 500, 503].includes(getProp(error, ["status_code", 500])), - }); - } - return new LLMError("LLM has occurred an error!", [error]); - } - - async tokenize(input: LLMInput): Promise { - try { - const { result } = await this.client.fetch("tokenization", { - method: "POST", - body: JSON.stringify({ - input, - model_id: this.modelId, - project_id: this.projectId, - space_id: this.projectId ? undefined : this.spaceId, - parameters: { - return_tokens: true, - }, - }), - }); - - return { - tokensCount: result.token_count, - tokens: result.tokens, - }; - } catch (e) { - throw this._transformError(e); - } - } - - protected async _generate( - input: LLMInput, - options: WatsonXLLMGenerateOptions | undefined, - run: GetRunContext, - ): Promise { - try { - const response = await this.client.fetch("generate", { - method: "POST", - body: JSON.stringify( - this.transform({ - input, - ...(!this.deploymentId && { - model_id: this.modelId, - project_id: this.projectId, - space_id: this.projectId ? undefined : this.spaceId, - }), - parameters: options?.parameters ?? this.parameters, - moderations: options?.moderations ?? this.moderations, - }), - ), - signal: run.signal, - }); - return this._rawResponseToOutput(response); - } catch (e) { - throw this._transformError(e); - } - } - - protected async *_stream( - input: LLMInput, - options: WatsonXLLMGenerateOptions | undefined, - run: GetRunContext, - ): AsyncStream { - try { - const response = this.client.stream("generate_stream", { - method: "POST", - body: JSON.stringify( - this.transform({ - input, - ...(!this.deploymentId && { - model_id: this.modelId, - project_id: this.projectId, - space_id: this.projectId ? undefined : this.spaceId, - }), - parameters: options?.parameters ?? this.parameters, - moderations: options?.moderations ?? this.moderations, - }), - ), - signal: run.signal, - }); - - for await (const msg of response) { - const content = JSON.parse(msg.data); - yield this._rawResponseToOutput(content); - } - } catch (e) { - throw this._transformError(e); - } - } - - protected _rawResponseToOutput(raw: any) { - return new WatsonXLLMOutput({ - results: raw.results ?? [], - meta: R.pickBy( - { - model_id: raw.model_id, - created_at: raw.created_at!, - }, - R.isDefined, - ), - system: raw.system ?? [], - }); - } -} diff --git a/src/agents/base.ts b/src/agents/base.ts index 9c517b74..bcfc12b2 100644 --- a/src/agents/base.ts +++ b/src/agents/base.ts @@ -91,7 +91,7 @@ export abstract class BaseAgent< } createSnapshot() { - return { isRunning: false }; + return { isRunning: false, emitter: this.emitter }; } loadSnapshot(snapshot: ReturnType) { diff --git a/src/agents/bee/agent.ts b/src/agents/bee/agent.ts index 8065a696..21637059 100644 --- a/src/agents/bee/agent.ts +++ b/src/agents/bee/agent.ts @@ -17,8 +17,7 @@ import { BaseAgent } from "@/agents/base.js"; import { AnyTool } from "@/tools/base.js"; import { BaseMemory } from "@/memory/base.js"; -import { ChatLLM, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; +import { AssistantMessage, Message, UserMessage } from "@/backend/message.js"; import { AgentMeta } from "@/agents/types.js"; import { Emitter } from "@/emitter/emitter.js"; import { @@ -37,13 +36,14 @@ import { GraniteRunner } from "@/agents/bee/runners/granite/runner.js"; import { DeepThinkRunner } from "@/agents/bee/runners/deep-think/runner.js"; import { ValueError } from "@/errors.js"; import { DefaultRunner } from "@/agents/bee/runners/default/runner.js"; +import { ChatModel } from "@/backend/chat.js"; export type BeeTemplateFactory = ( template: BeeAgentTemplates[K], ) => BeeAgentTemplates[K]; export interface BeeInput { - llm: ChatLLM; + llm: ChatModel; tools: AnyTool[]; memory: BaseMemory; meta?: Omit; @@ -51,6 +51,7 @@ export interface BeeInput { [K in keyof BeeAgentTemplates]: BeeAgentTemplates[K] | BeeTemplateFactory; }>; execution?: BeeAgentExecutionConfig; + stream?: boolean; } export class BeeAgent extends BaseAgent { @@ -134,7 +135,7 @@ export class BeeAgent extends BaseAgent JSON.stringify(call)), toolOutput: [output], finalAnswer: [state.final_answer].filter(R.isTruthy), }), - meta: { success }, - }), + { success }, + ), ); assign(state, { tool_output: output }); @@ -170,12 +170,8 @@ export class BeeAgent extends BaseAgent { if (update.key === "tool_output") { await memory.add( - BaseMessage.of({ - role: "user", - text: update.value, - meta: { success: meta.success }, - }), + new UserMessage(update.value, { success: meta.success, createdAt: new Date() }), ); } }, @@ -81,14 +76,7 @@ export class DeepThinkRunner extends DefaultRunner { protected createParser(tools: AnyTool[]) { const { parser } = super.createParser(tools); - const parserRegex = isEmpty(tools) - ? new RegExp(`.+?\\n\\nFinal Answer: [\\s\\S]+`) - : new RegExp( - `.+?\\n\\n(?:Final Answer: [\\s\\S]+|Tool Name: (${tools.map((tool) => tool.name).join("|")})\\nTool Input: \\{.*\\})`, - ); - return { - parserRegex, parser: parser.fork((nodes, options) => ({ options: { ...options, diff --git a/src/agents/bee/runners/default/runner.spec.ts b/src/agents/bee/runners/default/runner.spec.ts index cdea62d0..c8e90ad4 100644 --- a/src/agents/bee/runners/default/runner.spec.ts +++ b/src/agents/bee/runners/default/runner.spec.ts @@ -16,7 +16,7 @@ import { DefaultRunner } from "@/agents/bee/runners/default/runner.js"; import { UnconstrainedMemory } from "@/memory/unconstrainedMemory.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; +import { AssistantMessage, Role, UserMessage } from "@/backend/message.js"; import { BaseMemory } from "@/memory/base.js"; import { BeeUserPrompt } from "@/agents/bee/prompts.js"; import { zip } from "remeda"; @@ -43,14 +43,8 @@ describe("Bee Agent Runner", () => { const createMemory = async () => { const memory = new UnconstrainedMemory(); await memory.addMany([ - BaseMessage.of({ - role: Role.USER, - text: "What is your name?", - }), - BaseMessage.of({ - role: Role.ASSISTANT, - text: "I am Bee", - }), + new UserMessage("What is your name?"), + new AssistantMessage("I am Bee"), ]); return memory; }; @@ -75,9 +69,7 @@ describe("Bee Agent Runner", () => { const instance = await createInstance(memory, prompt); const memory2 = await createMemory(); - await memory2.add( - BaseMessage.of({ role: Role.USER, text: prompt, meta: { createdAt: new Date() } }), - ); + await memory2.add(new UserMessage(prompt, { createdAt: new Date() })); const instance2 = await createInstance(memory2, null); expect(instance.memory.messages).toEqual(instance2.memory.messages); }); @@ -93,22 +85,10 @@ describe("Bee Agent Runner", () => { ])("Correctly formats user input", async (template: typeof BeeUserPrompt) => { const memory = new UnconstrainedMemory(); await memory.addMany([ - BaseMessage.of({ - role: Role.USER, - text: "What is your name?", - }), - BaseMessage.of({ - role: Role.ASSISTANT, - text: "Bee", - }), - BaseMessage.of({ - role: Role.USER, - text: "Who are you?", - }), - BaseMessage.of({ - role: Role.ASSISTANT, - text: "I am a helpful assistant.", - }), + new UserMessage("What is your name?"), + new AssistantMessage("Bee"), + new UserMessage("Who are you?"), + new AssistantMessage("I am a helpful assistant."), ]); const prompt = "What can you do for me?"; @@ -127,10 +107,7 @@ describe("Bee Agent Runner", () => { await instance.init({ prompt }); for (const [a, b] of zip( - [ - ...memory.messages.filter((msg) => msg.role === Role.USER), - BaseMessage.of({ role: Role.USER, text: prompt }), - ], + [...memory.messages.filter((msg) => msg.role === Role.USER), new UserMessage(prompt)], instance.memory.messages.filter((msg) => msg.role === Role.USER), )) { expect(template.render({ input: a.text, meta: undefined })).toStrictEqual(b.text); diff --git a/src/agents/bee/runners/default/runner.ts b/src/agents/bee/runners/default/runner.ts index 17d5a47d..f4c96aeb 100644 --- a/src/agents/bee/runners/default/runner.ts +++ b/src/agents/bee/runners/default/runner.ts @@ -31,11 +31,11 @@ import { } from "@/agents/bee/prompts.js"; import { AnyTool, Tool, ToolError, ToolInputValidationError, ToolOutput } from "@/tools/base.js"; import { FrameworkError } from "@/errors.js"; -import { isEmpty, isTruthy, last } from "remeda"; -import { LinePrefixParser, LinePrefixParserError } from "@/agents/parsers/linePrefix.js"; -import { JSONParserField, ZodParserField } from "@/agents/parsers/field.js"; +import { isTruthy, last } from "remeda"; +import { LinePrefixParser, LinePrefixParserError } from "@/parsers/linePrefix.js"; +import { JSONParserField, ZodParserField } from "@/parsers/field.js"; import { z } from "zod"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; +import { AssistantMessage, Role, SystemMessage, UserMessage } from "@/backend/message.js"; import { TokenMemory } from "@/memory/tokenMemory.js"; import { getProp } from "@/internals/helpers/object.js"; import { BaseMemory } from "@/memory/base.js"; @@ -43,6 +43,8 @@ import { Cache } from "@/cache/decoratorCache.js"; import { shallowCopy } from "@/serializer/utils.js"; export class DefaultRunner extends BaseRunner { + protected useNativeToolCalling = false; + @Cache({ enumerable: false }) public get defaultTemplates() { return { @@ -75,22 +77,14 @@ export class DefaultRunner extends BaseRunner { // Prevent hanging on EOT if (error.reason === LinePrefixParserError.Reason.NoDataReceived) { await this.memory.add( - BaseMessage.of({ - role: Role.ASSISTANT, - text: "\n", - meta: { - [tempMessageKey]: true, - }, + new AssistantMessage("\n", { + [tempMessageKey]: true, }), ); } else { await this.memory.add( - BaseMessage.of({ - role: Role.USER, - text: this.templates.schemaError.render({}), - meta: { - [tempMessageKey]: true, - }, + new UserMessage(this.templates.schemaError.render({}), { + [tempMessageKey]: true, }), ); } @@ -100,14 +94,13 @@ export class DefaultRunner extends BaseRunner { const tools = this.input.tools.slice(); await emitter.emit("start", { meta, tools, memory: this.memory }); - const { parser, parserRegex } = this.createParser(tools); - const llmOutput = await this.input.llm - .generate(this.memory.messages.slice(), { - signal, - stream: true, - guided: { - regex: parserRegex.source, - }, + const { parser } = this.createParser(tools); + const raw = await this.input.llm + .create({ + messages: this.memory.messages.slice(), + tools: this.useNativeToolCalling ? tools : undefined, + abortSignal: signal, + stream: this.input.stream !== false, }) .observe((llmEmitter) => { parser.emitter.on("update", async ({ value, key, field }) => { @@ -149,7 +142,7 @@ export class DefaultRunner extends BaseRunner { return { state: parser.finalState, - raw: llmOutput, + raw, }; }, config: { @@ -277,13 +270,7 @@ export class DefaultRunner extends BaseRunner { user: { message: ({ prompt }: BeeRunInput) => prompt !== null || this.input.memory.isEmpty() - ? BaseMessage.of({ - role: Role.USER, - text: prompt || this.templates.userEmpty.render({}), - meta: { - createdAt: new Date(), - }, - }) + ? new UserMessage(prompt || this.templates.userEmpty.render({})) : undefined, }, system: { @@ -305,24 +292,23 @@ export class DefaultRunner extends BaseRunner { }, }, message: async () => - BaseMessage.of({ - role: Role.SYSTEM, - text: this.templates.system.render({ + new SystemMessage( + this.templates.system.render({ tools: await self.system.variables.tools(), instructions: undefined, createdAt: new Date().toISOString(), }), - meta: { + { createdAt: new Date(), }, - }), + ), }, }; return self; } protected async initMemory({ prompt }: BeeRunInput): Promise { - const { memory: history, llm } = this.input; + const { memory: history } = this.input; const prevConversation = [...history.messages, this.renderers.user.message({ prompt })] .filter(isTruthy) @@ -339,17 +325,12 @@ export class DefaultRunner extends BaseRunner { }, }); - return BaseMessage.of({ - role: Role.USER, - text, - meta: message.meta, - }); + return new UserMessage(text, message.meta); } return message; }); const memory = new TokenMemory({ - llm, capacityThreshold: 0.85, syncThreshold: 0.5, handlers: { @@ -380,12 +361,6 @@ export class DefaultRunner extends BaseRunner { } protected createParser(tools: AnyTool[]) { - const parserRegex = isEmpty(tools) - ? new RegExp(`Thought: .+\\nFinal Answer: [\\s\\S]+`) - : new RegExp( - `Thought: .+\\n(?:Final Answer: [\\s\\S]+|Function Name: (${tools.map((tool) => tool.name).join("|")})\\nFunction Input: \\{.*\\}\\nFunction Output:)`, - ); - const parser = new LinePrefixParser( { thought: { @@ -443,7 +418,6 @@ export class DefaultRunner extends BaseRunner { return { parser, - parserRegex, } as const; } } diff --git a/src/agents/bee/runners/granite/runner.ts b/src/agents/bee/runners/granite/runner.ts index 2ac8b26d..78fec77a 100644 --- a/src/agents/bee/runners/granite/runner.ts +++ b/src/agents/bee/runners/granite/runner.ts @@ -14,12 +14,10 @@ * limitations under the License. */ -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { isEmpty } from "remeda"; +import { ToolMessage } from "@/backend/message.js"; import type { AnyTool } from "@/tools/base.js"; import { DefaultRunner } from "@/agents/bee/runners/default/runner.js"; -import { BaseMemory } from "@/memory/base.js"; -import type { BeeParserInput, BeeRunInput, BeeRunOptions } from "@/agents/bee/types.js"; +import type { BeeParserInput, BeeRunOptions } from "@/agents/bee/types.js"; import { BeeAgent, BeeInput } from "@/agents/bee/agent.js"; import type { GetRunContext } from "@/context.js"; import { @@ -35,6 +33,8 @@ import { BeeToolNoResultsPrompt, BeeUserEmptyPrompt } from "@/agents/bee/prompts import { Cache } from "@/cache/decoratorCache.js"; export class GraniteRunner extends DefaultRunner { + protected useNativeToolCalling = true; + @Cache({ enumerable: false }) public get defaultTemplates() { return { @@ -60,14 +60,19 @@ export class GraniteRunner extends DefaultRunner { run.emitter.on( "update", - async ({ update, meta, memory }) => { + async ({ update, meta, memory, data }) => { if (update.key === "tool_output") { await memory.add( - BaseMessage.of({ - role: "tool_response", - text: update.value, - meta: { success: meta.success }, - }), + new ToolMessage( + { + type: "tool-result", + result: update.value!, + toolName: data.tool_name!, + isError: !meta.success, + toolCallId: "DUMMY_ID", + }, + { success: meta.success }, + ), ); } }, @@ -77,39 +82,10 @@ export class GraniteRunner extends DefaultRunner { ); } - protected async initMemory(input: BeeRunInput): Promise { - const memory = await super.initMemory(input); - - if (!isEmpty(this.input.tools)) { - const index = memory.messages.findIndex((msg) => msg.role === Role.SYSTEM) + 1; - await memory.add( - BaseMessage.of({ - role: "tools", - text: JSON.stringify( - (await this.renderers.system.variables.tools()).map((tool) => ({ - name: tool.name, - description: tool.description, - schema: JSON.parse(tool.schema), - })), - null, - 4, - ), - }), - index, - ); - } - return memory; - } - protected createParser(tools: AnyTool[]) { const { parser } = super.createParser(tools); return { - parserRegex: isEmpty(tools) - ? new RegExp(`Thought: .+\\nFinal Answer: [\\s\\S]+`) - : new RegExp( - `Thought: .+\\n(?:Final Answer: [\\s\\S]+|Tool Name: (${tools.map((tool) => tool.name).join("|")})\\nTool Input: \\{.*\\})`, - ), parser: parser.fork((nodes, options) => ({ options, nodes: { diff --git a/src/agents/bee/types.ts b/src/agents/bee/types.ts index 3bc41d3d..3777b926 100644 --- a/src/agents/bee/types.ts +++ b/src/agents/bee/types.ts @@ -14,9 +14,8 @@ * limitations under the License. */ -import { ChatLLMOutput } from "@/llms/chat.js"; import { BaseMemory } from "@/memory/base.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; +import { Message } from "@/backend/message.js"; import { Callback } from "@/emitter/types.js"; import { AnyTool, BaseToolRunOptions, ToolError, ToolOutput } from "@/tools/base.js"; import { @@ -30,22 +29,23 @@ import { BeeUserEmptyPrompt, BeeUserPrompt, } from "@/agents/bee/prompts.js"; -import { LinePrefixParser } from "@/agents/parsers/linePrefix.js"; -import { JSONParserField, ZodParserField } from "@/agents/parsers/field.js"; +import { LinePrefixParser } from "@/parsers/linePrefix.js"; +import { JSONParserField, ZodParserField } from "@/parsers/field.js"; import { NonUndefined } from "@/internals/types.js"; +import { ChatModelOutput } from "@/backend/chat.js"; export interface BeeRunInput { prompt: string | null; } export interface BeeRunOutput { - result: BaseMessage; + result: Message; iterations: BeeAgentRunIteration[]; memory: BaseMemory; } export interface BeeAgentRunIteration { - raw: ChatLLMOutput; + raw: ChatModelOutput; state: BeeIterationResult; } @@ -73,7 +73,7 @@ export interface BeeCallbacks { error?: Callback<{ error: Error; meta: BeeMeta }>; retry?: Callback<{ meta: BeeMeta }>; success?: Callback<{ - data: BaseMessage; + data: Message; iterations: BeeAgentRunIteration[]; memory: BaseMemory; meta: BeeMeta; diff --git a/src/agents/experimental/replan/agent.ts b/src/agents/experimental/replan/agent.ts index 23bb90c3..88f0a775 100644 --- a/src/agents/experimental/replan/agent.ts +++ b/src/agents/experimental/replan/agent.ts @@ -18,25 +18,23 @@ import { Callback } from "@/emitter/types.js"; import { Emitter } from "@/emitter/emitter.js"; import { AgentError, BaseAgent, BaseAgentRunOptions } from "@/agents/base.js"; import { GetRunContext } from "@/context.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; +import { AssistantMessage, Message, UserMessage } from "@/backend/message.js"; import { createRePlanOutputSchema, RePlanState, - RePlanSystemPrompt, RePlanAssistantPrompt, } from "@/agents/experimental/replan/prompts.js"; import { BaseMemory } from "@/memory/base.js"; import { UnconstrainedMemory } from "@/memory/unconstrainedMemory.js"; -import { JsonDriver } from "@/llms/drivers/json.js"; import { AnyTool, Tool } from "@/tools/base.js"; -import { AnyChatLLM } from "@/llms/chat.js"; +import { ChatModel } from "@/backend/chat.js"; export interface RePlanRunInput { prompt: string | null; } export interface RePlanRunOutput { - message: BaseMessage; + message: Message; intermediateMemory: BaseMemory; } @@ -57,7 +55,7 @@ export interface RePlanEvents { interface Input { memory: BaseMemory; tools: AnyTool[]; - llm: AnyChatLLM; + llm: ChatModel; } export class RePlanAgent extends BaseAgent { @@ -76,34 +74,25 @@ export class RePlanAgent extends BaseAgent { context: GetRunContext, ): Promise { if (input.prompt !== null) { - await this.memory.add( - BaseMessage.of({ - role: Role.USER, - text: input.prompt, - }), - ); + await this.memory.add(new UserMessage(input.prompt)); } const runner = await this.createRunner(context); - let finalMessage: BaseMessage | undefined = undefined; + let finalMessage: Message | undefined = undefined; while (!finalMessage) { const state = await runner.run(); if (state.nextStep.type === "message") { - finalMessage = BaseMessage.of({ - role: Role.USER, - text: state.nextStep.message, - }); + finalMessage = new UserMessage(state.nextStep.message); } else if (state.nextStep.type === "tool") { const toolResults = await runner.tools(state.nextStep.calls); await runner.memory.add( - BaseMessage.of({ - role: Role.ASSISTANT, - text: RePlanAssistantPrompt.render({ + new AssistantMessage( + RePlanAssistantPrompt.render({ results: JSON.stringify(toolResults), }), - }), + ), ); } } @@ -121,19 +110,15 @@ export class RePlanAgent extends BaseAgent { await memory.addMany(this.memory.messages); const run = async (): Promise => { - const driver = JsonDriver.fromTemplate(RePlanSystemPrompt, this.input.llm); const schema = await createRePlanOutputSchema(this.input.tools); - const response = await driver.generate(schema.json, memory.messages, { - options: { signal: context.signal }, + const response = await this.input.llm.createStructure({ + schema: schema.definition, + abortSignal: context.signal, + messages: memory.messages, }); - await memory.add( - BaseMessage.of({ - role: Role.ASSISTANT, - text: response.raw.getTextContent(), - }), - ); - await context.emitter.emit("update", { state: response.parsed }); - return response.parsed; + await memory.add(new AssistantMessage(JSON.stringify(response))); + await context.emitter.emit("update", { state: response.object }); + return response.object; }; const tools = async (calls: RePlanToolCall[]) => { diff --git a/src/agents/experimental/streamlit/agent.test.ts b/src/agents/experimental/streamlit/agent.test.ts index af48397b..2d28440d 100644 --- a/src/agents/experimental/streamlit/agent.test.ts +++ b/src/agents/experimental/streamlit/agent.test.ts @@ -14,19 +14,19 @@ * limitations under the License. */ -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { StreamlitAgent } from "@/agents/experimental/streamlit/agent.js"; +import { OllamaChatModel } from "@/adapters/ollama/backend/chat.js"; +import { StreamlitAgent } from "./agent.js"; import { UnconstrainedMemory } from "@/memory/unconstrainedMemory.js"; -import { OllamaChatLLM } from "@/adapters/ollama/chat.js"; +import { verifyDeserialization } from "@tests/e2e/utils.js"; describe("Streamlit agent", () => { it("Serializes", async () => { const instance = new StreamlitAgent({ - llm: new OllamaChatLLM(), + llm: new OllamaChatModel("llama3.1"), memory: new UnconstrainedMemory(), }); - const serialized = instance.serialize(); - const deserialized = StreamlitAgent.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await StreamlitAgent.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/src/agents/experimental/streamlit/agent.ts b/src/agents/experimental/streamlit/agent.ts index abfc389d..e004f485 100644 --- a/src/agents/experimental/streamlit/agent.ts +++ b/src/agents/experimental/streamlit/agent.ts @@ -19,19 +19,18 @@ import { AgentMeta } from "@/agents/types.js"; import { GetRunContext } from "@/context.js"; import { Callback, Emitter } from "@/emitter/emitter.js"; import { BaseMemory } from "@/memory/base.js"; -import { ChatLLM, ChatLLMOutput } from "@/llms/chat.js"; import { isTruthy, last } from "remeda"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; +import { AssistantMessage, Message, Role, SystemMessage, UserMessage } from "@/backend/message.js"; import { StreamlitAgentSystemPrompt, StreamlitAgentTemplates, } from "@/agents/experimental/streamlit/prompts.js"; -import { BaseLLMOutput } from "@/llms/base.js"; import { TokenMemory } from "@/memory/tokenMemory.js"; import { findFirstPair } from "@/internals/helpers/string.js"; +import { ChatModel, ChatModelOutput } from "@/backend/chat.js"; export interface StreamlitAgentInput { - llm: ChatLLM; + llm: ChatModel; memory: BaseMemory; templates?: Partial; } @@ -54,7 +53,7 @@ interface Result { export interface StreamlitRunOutput { result: Result; - message: BaseMessage; + message: Message; memory: BaseMemory; } @@ -64,7 +63,7 @@ export interface StreamlitEvents { state: Readonly<{ content: string; }>; - chunk: BaseLLMOutput; + chunk: ChatModelOutput; }>; } @@ -102,19 +101,24 @@ export class StreamlitAgent extends BaseAgent { + emitter.on("newToken", async ({ value: chunk }) => { + const delta = chunk.getTextContent(); + if (delta) { + content += delta; + await run.emitter.emit("newToken", { delta, state: { content }, chunk }); + } + }); + }); + const result = this.parse(content || raw.getTextContent()); - const assistantMessage = BaseMessage.of({ - role: Role.ASSISTANT, - text: content, - }); + const assistantMessage = new AssistantMessage(content); await this.memory.addMany([userMessage, assistantMessage].filter(isTruthy)); return { @@ -125,26 +129,18 @@ export class StreamlitAgent extends BaseAgent, "chat">, + ): Promise { + return new Backend( + await asyncProperties({ + chat: ChatModel.fromName(input.chat), + embedding: EmbeddingModel.fromName(input.embedding || "dummy"), + }), + ); + } + + static async fromProvider(provider: ProviderName): Promise { + return await this.fromName({ + chat: provider, + embedding: provider, + }); + } + + createSnapshot() { + return { chat: this.chat, embedding: this.embedding }; + } + + loadSnapshot(snapshot: ReturnType) { + Object.assign(this, snapshot); + } +} diff --git a/src/backend/chat.ts b/src/backend/chat.ts new file mode 100644 index 00000000..eb0846d5 --- /dev/null +++ b/src/backend/chat.ts @@ -0,0 +1,405 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Serializable } from "@/internals/serializable.js"; +import { shallowCopy } from "@/serializer/utils.js"; +import { customMerge } from "@/internals/helpers/object.js"; +import { takeBigger } from "@/internals/helpers/number.js"; +import { Callback } from "@/emitter/types.js"; +import { FrameworkError } from "@/errors.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { GetRunContext, RunContext } from "@/context.js"; +import { INSTRUMENTATION_ENABLED } from "@/instrumentation/config.js"; +import { createTelemetryMiddleware } from "@/instrumentation/create-telemetry-middleware.js"; +import { doNothing, isFunction } from "remeda"; +import { ObjectHashKeyFn } from "@/cache/decoratorCache.js"; +import { Task } from "promise-based-task"; +import { NullCache } from "@/cache/nullCache.js"; +import { BaseCache } from "@/cache/base.js"; +import { FullModelName, loadModel, parseModel } from "@/backend/utils.js"; +import { ProviderName } from "@/backend/constants.js"; +import { AnyTool } from "@/tools/base.js"; +import { AssistantMessage, Message, SystemMessage, UserMessage } from "@/backend/message.js"; +import { + JSONSchema7, + LanguageModelV1FunctionTool, + LanguageModelV1ProviderDefinedTool, + LanguageModelV1ToolChoice, +} from "@ai-sdk/provider"; +import { ChatModelError } from "@/backend/errors.js"; +import { z } from "zod"; +import { + createSchemaValidator, + parseBrokenJson, + toJsonSchema, +} from "@/internals/helpers/schema.js"; +import { Retryable } from "@/internals/helpers/retryable.js"; +import type { ValidateFunction } from "ajv"; +import { PromptTemplate } from "@/template.js"; +import { toAsyncGenerator } from "@/internals/helpers/promise.js"; +import { Serializer } from "@/serializer/serializer.js"; + +export interface ChatModelParameters { + maxTokens?: number; + topP?: number; + frequencyPenalty?: number; + temperature?: number; + topK?: number; + n?: number; + presencePenalty?: number; + seed?: number; + stopSequences?: string[]; +} + +export interface ChatModelObjectInput extends ChatModelParameters { + schema: z.ZodSchema; + messages: Message[]; + abortSignal?: AbortSignal; + maxRetries?: number; +} + +export interface ChatModelObjectOutput { + object: T; +} + +export interface ChatModelInput extends ChatModelParameters { + tools?: AnyTool[]; + abortSignal?: AbortSignal; + stopSequences?: string[]; + responseFormat?: + | { + type: "regular"; + tools?: (LanguageModelV1FunctionTool | LanguageModelV1ProviderDefinedTool)[]; + toolChoice?: LanguageModelV1ToolChoice; + } + | { + type: "object-json"; + schema?: JSONSchema7; + name?: string; + description?: string; + } + | { + type: "object-tool"; + tool: LanguageModelV1FunctionTool; + }; + toolChoice?: never; // TODO + messages: Message[]; +} + +export type ChatModelFinishReason = + | "stop" + | "length" + | "content-filter" + | "tool-calls" + | "error" + | "other" + | "unknown"; + +export interface ChatModelUsage { + promptTokens: number; + completionTokens: number; + totalTokens: number; +} + +export interface ChatModelEvents { + newToken?: Callback<{ value: ChatModelOutput; callbacks: { abort: () => void } }>; + success?: Callback<{ value: ChatModelOutput }>; + start?: Callback<{ input: ChatModelInput }>; + error?: Callback<{ input: ChatModelInput; error: FrameworkError }>; + finish?: Callback; +} + +export type ChatModelEmitter> = Emitter< + ChatModelEvents & Omit +>; + +export type ChatModelCache = BaseCache>; +export type ConfigFn = (value: T) => T; +export interface ChatConfig { + cache?: ChatModelCache | ConfigFn; + parameters?: ChatModelParameters | ConfigFn; +} + +export abstract class ChatModel extends Serializable { + public abstract readonly emitter: Emitter; + public cache: ChatModelCache = new NullCache(); + public parameters: ChatModelParameters = {}; + + abstract get modelId(): string; + abstract get providerId(): string; + + create(input: ChatModelInput & { stream?: boolean }) { + input = shallowCopy(input); + + return RunContext.enter( + this, + { params: [input] as const, signal: input?.abortSignal }, + async (run) => { + const cacheEntry = await this.createCacheAccessor(input); + + try { + await run.emitter.emit("start", { input }); + const chunks: ChatModelOutput[] = []; + + const generator = + cacheEntry.value ?? + (input.stream + ? this._createStream(input, run) + : toAsyncGenerator(this._create(input, run))); + + const controller = new AbortController(); + for await (const value of generator) { + chunks.push(value); + await run.emitter.emit("newToken", { + value, + callbacks: { abort: () => controller.abort() }, + }); + if (controller.signal.aborted) { + break; + } + } + + cacheEntry.resolve(chunks); + const result = ChatModelOutput.fromChunks(chunks); + await run.emitter.emit("success", { value: result }); + return result; + } catch (error) { + await run.emitter.emit("error", { input, error }); + await cacheEntry.reject(error); + if (error instanceof ChatModelError) { + throw error; + } else { + throw new ChatModelError(`LLM has occurred an error.`, [error]); + } + } finally { + await run.emitter.emit("finish", null); + } + }, + ).middleware(INSTRUMENTATION_ENABLED ? createTelemetryMiddleware() : doNothing()); + } + + createStructure(input: ChatModelObjectInput) { + return RunContext.enter( + this, + { params: [input] as const, signal: input?.abortSignal }, + async (run) => { + return await this._createStructure(input, run); + }, + ); + } + + config({ cache, parameters }: ChatConfig): void { + if (cache) { + this.cache = isFunction(cache) ? cache(this.cache) : cache; + } + if (parameters) { + this.parameters = isFunction(parameters) ? parameters(this.parameters) : parameters; + } + } + + static async fromName(name: FullModelName | ProviderName, options?: ChatModelParameters) { + const { providerId, modelId = "" } = parseModel(name); + const Target = await loadModel(providerId, "chat"); + return new Target(modelId, options); + } + + protected abstract _create( + input: ChatModelInput, + run: GetRunContext, + ): Promise; + protected abstract _createStream( + input: ChatModelInput, + run: GetRunContext, + ): AsyncGenerator; + + protected async _createStructure( + input: ChatModelObjectInput, + run: GetRunContext, + ): Promise> { + const { schema, ...options } = input; + const jsonSchema = toJsonSchema(schema); + + const systemTemplate = new PromptTemplate({ + schema: z.object({ + schema: z.string().min(1), + }), + template: `You are a helpful assistant that generates only valid JSON adhering to the following JSON Schema. + +\`\`\` +{{schema}} +\`\`\` + +IMPORTANT: You MUST answer with a JSON object that matches the JSON schema above.`, + }); + + const messages: Message[] = [ + new SystemMessage(systemTemplate.render({ schema: JSON.stringify(jsonSchema, null, 2) })), + ...input.messages, + ]; + + const errorTemplate = new PromptTemplate({ + schema: z.object({ + errors: z.string(), + expected: z.string(), + received: z.string(), + }), + template: `Generated object does not match the expected JSON schema! + +Validation Errors: {{errors}}`, + }); + + return new Retryable>({ + executor: async () => { + const response = await this._create( + { + ...options, + messages, + responseFormat: { type: "object-json" }, + }, + run, + ); + + const textResponse = response.getTextContent(); + const object: T = parseBrokenJson(textResponse, { pair: ["{", "}"] }); + const validator = createSchemaValidator(schema) as ValidateFunction; + + const success = validator(object); + if (!success) { + const context = { + expected: JSON.stringify(jsonSchema), + received: textResponse, + errors: JSON.stringify(validator.errors ?? []), + }; + + messages.push(new UserMessage(errorTemplate.render(context))); + throw new ChatModelError(`LLM did not produce a valid output.`, [], { + context, + }); + } + + return { object }; + }, + config: { + signal: run.signal, + maxRetries: input?.maxRetries || 1, + }, + }).get(); + } + + createSnapshot() { + return { cache: this.cache, emitter: this.emitter, parameters: shallowCopy(this.parameters) }; + } + + destroy() { + this.emitter.destroy(); + } + + protected async createCacheAccessor({ + abortSignal: _, + messages, + tools = [], + ...input + }: ChatModelInput) { + const key = ObjectHashKeyFn({ + ...input, + messages: await Serializer.serialize(messages.map((msg) => msg.toPlain())), + tools: await Serializer.serialize(tools), + }); + const value = await this.cache.get(key); + const isNew = value === undefined; + + let task: Task | null = null; + if (isNew) { + task = new Task(); + await this.cache.set(key, task); + } + + return { + key, + value, + resolve: (value: T2[]) => { + task?.resolve?.(value); + }, + reject: async (error: Error) => { + task?.reject?.(error); + if (isNew) { + await this.cache.delete(key); + } + }, + }; + } +} + +export class ChatModelOutput extends Serializable { + constructor( + public readonly messages: Message[], + public usage?: ChatModelUsage, + public finishReason?: ChatModelFinishReason, + ) { + super(); + } + + static fromChunks(chunks: ChatModelOutput[]) { + const final = new ChatModelOutput([]); + chunks.forEach((cur) => final.merge(cur)); + return final; + } + + merge(other: ChatModelOutput) { + this.messages.push(...other.messages); + this.finishReason = other.finishReason; + if (this.usage && other.usage) { + this.usage = customMerge([this.usage, other.usage], { + totalTokens: takeBigger, + promptTokens: takeBigger, + completionTokens: takeBigger, + }); + } else if (other.usage) { + this.usage = shallowCopy(other.usage); + } + } + + getToolCalls() { + return this.messages + .filter((r) => r instanceof AssistantMessage) + .flatMap((r) => r.getToolCalls()) + .filter(Boolean); + } + + getTextContent(): string { + return this.messages + .filter((r) => r instanceof AssistantMessage) + .flatMap((r) => r.text) + .filter(Boolean) + .join(""); + } + + toString() { + return this.getTextContent(); + } + + createSnapshot() { + return { + messages: shallowCopy(this.messages), + usage: shallowCopy(this.usage), + finishReason: this.finishReason, + }; + } + + loadSnapshot(snapshot: ReturnType) { + Object.assign(this, snapshot); + } +} diff --git a/src/backend/client.ts b/src/backend/client.ts new file mode 100644 index 00000000..d61425c6 --- /dev/null +++ b/src/backend/client.ts @@ -0,0 +1,52 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Serializable } from "@/internals/serializable.js"; +import { shallowCopy } from "@/serializer/utils.js"; + +export abstract class BackendClient extends Serializable { + public readonly instance: T; + protected readonly settings: P; + + constructor(settings: P) { + super(); + this.settings = settings; + this.instance = this.create(); + } + + protected abstract create(): T; + + createSnapshot() { + return { + settings: shallowCopy(this.settings), + }; + } + + loadSnapshot(snapshot: ReturnType) { + Object.assign(this, snapshot); + Object.assign(this, { instance: this.create() }); + } + + static ensure>( + this: new (settings: P2) => R, + settings?: P2 | R, + ): R { + if (settings && settings instanceof this) { + return settings; + } + return new this(settings as P2); + } +} diff --git a/src/backend/constants.ts b/src/backend/constants.ts new file mode 100644 index 00000000..a4386bb5 --- /dev/null +++ b/src/backend/constants.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const BackendProviders = { + OpenAI: { name: "OpenAI", module: "openai", aliases: ["openai"] as string[] }, + Azure: { name: "Azure", module: "azure", aliases: ["microsoft", "microsoft-azure"] as string[] }, + Watsonx: { name: "Watsonx", module: "watsonx", aliases: ["watsonx", "ibm"] as string[] }, + Ollama: { name: "Ollama", module: "ollama", aliases: [] as string[] }, + GoogleVertex: { + name: "GoogleVertex", + module: "google-vertex", + aliases: ["google", "vertex"] as string[], + }, + Bedrock: { + name: "Bedrock", + module: "amazon-bedrock", + aliases: ["amazon", "bedrock"] as string[], + }, + Groq: { name: "Groq", module: "groq", aliases: [] as string[] }, + Dummy: { name: "Dummy", module: "dummy", aliases: [] as string[] }, +} as const; + +export type ProviderName = (typeof BackendProviders)[keyof typeof BackendProviders]["module"]; +export type ProviderHumanName = (typeof BackendProviders)[keyof typeof BackendProviders]["name"]; +export type ProviderDef = (typeof BackendProviders)[keyof typeof BackendProviders]; diff --git a/src/backend/core.ts b/src/backend/core.ts new file mode 100644 index 00000000..0d9839b4 --- /dev/null +++ b/src/backend/core.ts @@ -0,0 +1,21 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from "./backend.js"; +export * from "./chat.js"; +export * from "./embedding.js"; +export * from "./message.js"; +export * from "./errors.js"; diff --git a/src/backend/embedding.ts b/src/backend/embedding.ts new file mode 100644 index 00000000..b45a28e8 --- /dev/null +++ b/src/backend/embedding.ts @@ -0,0 +1,104 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Serializable } from "@/internals/serializable.js"; +import { Callback } from "@/emitter/types.js"; +import { FrameworkError } from "@/errors.js"; +import { Emitter } from "@/emitter/emitter.js"; +import { shallowCopy } from "@/serializer/utils.js"; +import { GetRunContext, RunContext } from "@/context.js"; +import { pRetry } from "@/internals/helpers/retry.js"; +import { FullModelName, loadModel, parseModel } from "@/backend/utils.js"; +import { ProviderName } from "@/backend/constants.js"; +import { EmbeddingModelError } from "@/backend/errors.js"; + +export interface EmbeddingModelInput { + values: string[]; + abortSignal?: AbortSignal; + maxRetries?: number; +} + +export interface EmbeddingModelOutput { + values: string[]; + embeddings: number[][]; + usage: { tokens?: number }; +} + +export interface EmbeddingModelEvents { + success?: Callback<{ value: EmbeddingModelOutput }>; + start?: Callback<{ input: EmbeddingModelInput }>; + error?: Callback<{ input: EmbeddingModelInput; error: FrameworkError }>; + finish?: Callback; +} + +export type EmbeddingModelEmitter> = Emitter< + EmbeddingModelEvents & Omit +>; + +export abstract class EmbeddingModel extends Serializable { + public abstract readonly emitter: Emitter; + + abstract get modelId(): string; + abstract get providerId(): string; + + create(input: EmbeddingModelInput) { + input = shallowCopy(input); + + return RunContext.enter( + this, + { params: [input] as const, signal: input?.abortSignal }, + async (run) => { + try { + await run.emitter.emit("start", { input }); + const result: EmbeddingModelOutput = await pRetry(() => this._create(input, run), { + retries: input.maxRetries || 0, + signal: run.signal, + }); + await run.emitter.emit("success", { value: result }); + return result; + } catch (error) { + await run.emitter.emit("error", { input, error }); + if (error instanceof EmbeddingModelError) { + throw error; + } else { + throw new EmbeddingModelError(`LLM has occurred an error.`, [error]); + } + } finally { + await run.emitter.emit("finish", null); + } + }, + ); + } + + static async fromName(name: FullModelName | ProviderName) { + const { providerId, modelId = "" } = parseModel(name); + const Target = await loadModel(providerId, "embedding"); + return new Target(modelId); + } + + protected abstract _create( + input: EmbeddingModelInput, + run: GetRunContext, + ): Promise; + + createSnapshot() { + return { emitter: this.emitter }; + } + + destroy() { + this.emitter.destroy(); + } +} diff --git a/src/adapters/groq/chat.test.ts b/src/backend/errors.ts similarity index 50% rename from src/adapters/groq/chat.test.ts rename to src/backend/errors.ts index c4098223..d4d58ff8 100644 --- a/src/adapters/groq/chat.test.ts +++ b/src/backend/errors.ts @@ -14,24 +14,10 @@ * limitations under the License. */ -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { GroqChatLLM } from "@/adapters/groq/chat.js"; -import { Groq } from "groq-sdk"; +import { FrameworkError } from "@/errors.js"; -describe("Groq ChatLLM", () => { - const getInstance = () => { - return new GroqChatLLM({ - modelId: "gemma2-9b-it", - client: new Groq({ - apiKey: "123", - }), - }); - }; +export class BackendError extends FrameworkError {} - it("Serializes", async () => { - const instance = getInstance(); - const serialized = instance.serialize(); - const deserialized = GroqChatLLM.fromSerialized(serialized); - verifyDeserialization(instance, deserialized); - }); -}); +export class ChatModelError extends BackendError {} + +export class EmbeddingModelError extends BackendError {} diff --git a/src/backend/message.ts b/src/backend/message.ts new file mode 100644 index 00000000..921d69fb --- /dev/null +++ b/src/backend/message.ts @@ -0,0 +1,215 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Serializable } from "@/internals/serializable.js"; +import { shallowCopy } from "@/serializer/utils.js"; +import { FilePart, ImagePart, TextPart, ToolCallPart, ToolResultPart } from "ai"; +import { z } from "zod"; +import { ValueError } from "@/errors.js"; + +export type MessageRole = "user" | "system" | "tool" | "assistant"; +export type MessageContentPart = TextPart | ToolCallPart | ImagePart | FilePart | ToolResultPart; + +export interface MessageMeta { + [key: string]: any; + createdAt?: Date; +} + +export interface MessageInput { + role: MessageRole; + text: string; // TODO + meta?: MessageMeta; +} + +function isText(content: MessageContentPart): content is TextPart { + return content.type === "text"; +} +function isImage(content: MessageContentPart): content is ImagePart { + return content.type === "image"; +} +function isFile(content: MessageContentPart): content is FilePart { + return content.type === "file"; +} +function isToolCall(content: MessageContentPart): content is ToolCallPart { + return content.type === "tool-call"; +} +function isToolResult(content: MessageContentPart): content is ToolResultPart { + return content.type === "tool-result"; +} + +export abstract class Message< + T extends MessageContentPart = MessageContentPart, + R extends string = MessageRole | string, +> extends Serializable { + public abstract readonly role: R; + public readonly content: T[]; + + constructor( + content: T | T[] | string, + public readonly meta: MessageMeta = {}, + ) { + super(); + if (!meta?.createdAt) { + meta.createdAt = new Date(); + } + if (typeof content === "string") { + this.content = [this.fromString(content)]; + } else { + this.content = Array.isArray(content) ? content : [content]; + } + } + + protected abstract fromString(input: string): T; + + static of({ role, text, meta }: MessageInput): Message { + if (role === "user") { + return new UserMessage(text, meta); + } else if (role === "assistant") { + return new AssistantMessage(text, meta); + } else if (role === "system") { + return new SystemMessage(text, meta); + } else if (role === "tool") { + return new ToolMessage(text, meta); + } else { + return new CustomMessage(role, text, meta); + } + } + + get text() { + return this.getTexts() + .map((c) => c.text) + .join(""); + } + + getTexts() { + return this.content.filter(isText) as TextPart[]; + } + + createSnapshot() { + return { content: shallowCopy(this.content), meta: shallowCopy(this.meta), role: this.role }; + } + + loadSnapshot(snapshot: ReturnType) { + Object.assign(this, snapshot); + } + + toPlain() { + return { role: this.role, content: shallowCopy(this.content) } as const; + } + + [Symbol.iterator](): Iterator { + return this.content[Symbol.iterator](); + } +} + +export class AssistantMessage extends Message { + public readonly role = "assistant"; + + static { + this.register(); + } + + getToolCalls() { + return this.content.filter(isToolCall); + } + + protected fromString(text: string): TextPart { + return { type: "text", text }; + } +} + +export class ToolMessage extends Message { + public readonly role = "tool"; + + static { + this.register(); + } + + getToolResults() { + return this.content.filter(isToolResult); + } + + protected fromString(text: string): ToolResultPart { + const { success, data } = z + .object({ + type: z.literal("tool-result"), + result: z.any(), + toolName: z.string(), + toolCallId: z.string(), + }) + .safeParse(text); + + if (!success) { + throw new ValueError(`ToolMessage cannot be created from '${text}'!`); + } + + return data as ToolResultPart; + } +} + +export class SystemMessage extends Message { + public readonly role: MessageRole = "system"; + + static { + this.register(); + } + + protected fromString(text: string): TextPart { + return { type: "text", text }; + } +} + +export class UserMessage extends Message { + public readonly role = "user"; + + static { + this.register(); + } + + getImages() { + return this.content.filter(isImage); + } + + getFiles() { + return this.content.filter(isFile); + } + + protected fromString(text: string): TextPart { + return { type: "text", text }; + } +} + +export const Role = { + ASSISTANT: "assistant", + SYSTEM: "system", + USER: "user", +} as const; + +export class CustomMessage extends Message { + public role: string; + + constructor(role: string, content: MessageContentPart | string, meta: MessageMeta = {}) { + super(content, meta); + if (!role) { + throw new ValueError(`Role "${role}" must be specified!`); + } + this.role = role; + } + + protected fromString(input: string): MessageContentPart { + return { type: "text", text: input }; + } +} diff --git a/src/backend/utils.ts b/src/backend/utils.ts new file mode 100644 index 00000000..b0bd1ad1 --- /dev/null +++ b/src/backend/utils.ts @@ -0,0 +1,48 @@ +/** + * Copyright 2025 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ValueError } from "@/errors.js"; +import { ClassConstructor } from "@/internals/types.js"; +import { BackendProviders, ProviderDef, ProviderName } from "@/backend/constants.js"; +import { capitalize } from "remeda"; + +export type FullModelName = `${ProviderName}:${string}`; + +function findProviderDef(value: string): ProviderDef | null { + return ( + Object.values(BackendProviders).find( + (p) => p.name === value || p.module === value || p.aliases.includes(value), + ) ?? null + ); +} + +export function parseModel(name: string) { + const [providerId, modelId] = name.split(":") as [ProviderName, string]; + const providerDef = findProviderDef(providerId); + if (!providerDef) { + throw new ValueError("Model does not contain provider name!"); + } + return { providerId, modelId, providerDef }; +} + +export async function loadModel( + name: ProviderName | FullModelName, + type: "embedding" | "chat", +): Promise> { + const { providerDef } = parseModel(name); + const module = await import(`bee-agent-framework/adapters/${providerDef.module}/backend/${type}`); + return module[`${providerDef.name}${capitalize(type)}Model`]; +} diff --git a/src/cache/fileCache.ts b/src/cache/fileCache.ts index 5da7ee0a..0494a964 100644 --- a/src/cache/fileCache.ts +++ b/src/cache/fileCache.ts @@ -39,7 +39,7 @@ export class FileCache extends BaseCache { } static async fromProvider(provider: BaseCache, input: Input) { - await fs.promises.writeFile(input.fullPath, provider.serialize()); + await fs.promises.writeFile(input.fullPath, await provider.serialize()); return new FileCache(input); } @@ -54,7 +54,7 @@ export class FileCache extends BaseCache { const serialized = await fs.promises.readFile(this.input.fullPath, "utf8"); const { target, snapshot } = await Serializer.deserialize(serialized); const Target = Serializer.getFactory(target).ref as SerializableClass>; - const instance = Target.fromSnapshot(snapshot); + const instance = await Target.fromSnapshot(snapshot); if (!(instance instanceof BaseCache)) { throw new TypeError("Provided file does not serialize any instance of BaseCache class."); } @@ -75,7 +75,7 @@ export class FileCache extends BaseCache { protected async save() { const provider = await this.getProvider(); - return await fs.promises.writeFile(this.input.fullPath, provider.serialize()); + return await fs.promises.writeFile(this.input.fullPath, await provider.serialize()); } async size() { diff --git a/src/cache/nullCache.test.ts b/src/cache/nullCache.test.ts index 71b80080..9a785580 100644 --- a/src/cache/nullCache.test.ts +++ b/src/cache/nullCache.test.ts @@ -31,8 +31,8 @@ describe("NullCache", () => { it("Serializes", async () => { const instance = new NullCache(); await instance.set("1", 1); - const serialized = instance.serialize(); - const deserialized = NullCache.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await NullCache.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/src/cache/slidingCache.test.ts b/src/cache/slidingCache.test.ts index f43cebed..04a2a169 100644 --- a/src/cache/slidingCache.test.ts +++ b/src/cache/slidingCache.test.ts @@ -66,8 +66,8 @@ describe("SlidingCache", () => { await instance.set("1", 1); await instance.set("2", 2); await instance.set("3", 3); - const serialized = instance.serialize(); - const deserialized = SlidingCache.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await SlidingCache.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/src/cache/unconstrainedCache.test.ts b/src/cache/unconstrainedCache.test.ts index b8484a77..bf56c06b 100644 --- a/src/cache/unconstrainedCache.test.ts +++ b/src/cache/unconstrainedCache.test.ts @@ -39,8 +39,8 @@ describe("UnconstrainedCache", () => { it("Serializes", async () => { const instance = new UnconstrainedCache(); await instance.set("1", 1); - const serialized = instance.serialize(); - const deserialized = UnconstrainedCache.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await UnconstrainedCache.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/src/context.ts b/src/context.ts index 3fd1a4b5..d245b569 100644 --- a/src/context.ts +++ b/src/context.ts @@ -24,6 +24,7 @@ import { Serializable } from "@/internals/serializable.js"; import { executeSequentially, LazyPromise } from "@/internals/helpers/promise.js"; import { FrameworkError } from "@/errors.js"; import { shallowCopy } from "@/serializer/utils.js"; +import { isAsyncIterable } from "@/internals/helpers/stream.js"; export interface RunInstance { emitter: Emitter; @@ -73,6 +74,16 @@ export class Run extends LazyPromise { await super.before(); await executeSequentially(this.tasks.splice(0, Infinity)); } + + // @ts-expect-error too complex + async *[Symbol.asyncIterator](): R extends AsyncIterable ? AsyncIterator : never { + const response = await this.then(); + if (isAsyncIterable(response)) { + yield* response; + } else { + throw new Error("Result is not iterable!"); + } + } } export interface RunContextInput

{ diff --git a/src/emitter/emitter.ts b/src/emitter/emitter.ts index 066f3c51..d0ccd9a7 100644 --- a/src/emitter/emitter.ts +++ b/src/emitter/emitter.ts @@ -246,7 +246,7 @@ export class Emitter>> extends Serializa createdAt: new Date(), source: this, creator: this.creator!, - context: Object.assign({}, this.context, {}), // TODO: use createInStone + context: Object.assign({}, this.context, {}), trace: shallowCopy(this.trace), // TODO }; } diff --git a/src/experimental/workflows/agent.ts b/src/experimental/workflows/agent.ts index 4f3b22fa..e696ea26 100644 --- a/src/experimental/workflows/agent.ts +++ b/src/experimental/workflows/agent.ts @@ -16,9 +16,8 @@ import { BeeAgent } from "@/agents/bee/agent.js"; import { Workflow, WorkflowRunOptions } from "@/experimental/workflows/workflow.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; +import { AssistantMessage, Message } from "@/backend/message.js"; import { AnyTool } from "@/tools/base.js"; -import { AnyChatLLM } from "@/llms/chat.js"; import { BaseMemory, ReadOnlyMemory } from "@/memory/base.js"; import { z } from "zod"; import { UnconstrainedMemory } from "@/memory/unconstrainedMemory.js"; @@ -30,12 +29,13 @@ import { BeeRunOutput, } from "@/agents/bee/types.js"; import { isFunction, randomString } from "remeda"; +import { ChatModel } from "@/backend/chat.js"; type AgentInstance = BaseAgent; type AgentFactory = (memory: ReadOnlyMemory) => AgentInstance | Promise; interface AgentFactoryInput { name: string; - llm: AnyChatLLM; + llm: ChatModel; instructions?: string; tools?: AnyTool[]; execution?: BeeAgentExecutionConfig; @@ -45,10 +45,10 @@ export class AgentWorkflow { protected readonly workflow; static readonly schema = z.object({ - messages: z.array(z.instanceof(BaseMessage)).min(1), + messages: z.array(z.instanceof(Message)).min(1), finalAnswer: z.string().optional(), - newMessages: z.array(z.instanceof(BaseMessage)).default([]), + newMessages: z.array(z.instanceof(Message)).default([]), }); constructor(name = "AgentWorkflow") { @@ -59,7 +59,7 @@ export class AgentWorkflow { }); } - run(messages: BaseMessage[], options: WorkflowRunOptions = {}) { + run(messages: Message[], options: WorkflowRunOptions = {}) { return this.workflow.run( { messages, @@ -68,14 +68,17 @@ export class AgentWorkflow { ); } - addAgent(agent: AgentInstance | AgentFactory | AgentFactoryInput) { + addAgent(agent: AgentFactory | AgentFactoryInput): this; + addAgent(agent: AgentInstance): Promise; + addAgent(agent: AgentInstance | AgentFactory | AgentFactoryInput): this | Promise { if (agent instanceof BaseAgent) { - const clone = agent.clone(); - const factory: AgentFactory = (memory) => { - clone.memory = memory; - return clone; - }; - return this._add(clone.meta.name, factory); + return agent.clone().then((clone) => { + const factory: AgentFactory = (memory) => { + clone.memory = memory; + return clone; + }; + return this._add(clone.meta.name, factory); + }); } const name = agent.name || `Agent${randomString(4)}`; @@ -120,10 +123,9 @@ export class AgentWorkflow { update: { finalAnswer: result.text, newMessages: state.newMessages.concat( - BaseMessage.of({ - ...result, - text: [`Assistant Name: ${name}`, `Assistant Response: ${result.text}`].join("\n"), - }), + new AssistantMessage( + [`Assistant Name: ${name}`, `Assistant Response: ${result.text}`].join("\n"), + ), ), }, }; diff --git a/src/instrumentation/create-telemetry-middleware.ts b/src/instrumentation/create-telemetry-middleware.ts index 3092f83d..3154257c 100644 --- a/src/instrumentation/create-telemetry-middleware.ts +++ b/src/instrumentation/create-telemetry-middleware.ts @@ -21,10 +21,8 @@ import { getErrorSafe } from "./helpers/get-error-safe.js"; import { findLast, isDeepEqual, isEmpty } from "remeda"; import type { BeeCallbacks } from "@/agents/bee/types.js"; import type { InferCallbackValue } from "@/emitter/types.js"; -import { type BaseLLMEvents } from "@/llms/base.js"; import { FrameworkError } from "@/errors.js"; import { Version } from "@/version.js"; -import { Role } from "@/llms/primitives/message.js"; import type { GetRunContext, RunInstance } from "@/context.js"; import type { GeneratedResponse, FrameworkSpan } from "./types.js"; import { activeTracesMap, buildTraceTree } from "./tracer.js"; @@ -35,6 +33,8 @@ import type { BeeAgent } from "@/agents/bee/agent.js"; import { instrumentationLogger } from "./logger.js"; import { BaseAgent } from "@/agents/base.js"; import { assertLLMWithMessagesToPromptFn } from "./helpers/utils.js"; +import { Role } from "@/backend/message.js"; +import { ChatModelEvents } from "@/backend/chat.js"; export function createTelemetryMiddleware() { return (context: GetRunContext) => { @@ -73,12 +73,12 @@ export function createTelemetryMiddleware() { const idNameManager = new IdNameManager(); - const newTokenEventName: keyof BaseLLMEvents = `newToken`; + const newTokenEventName: keyof ChatModelEvents = `newToken`; const partialUpdateEventName: keyof BeeCallbacks = "partialUpdate"; - const successEventName: keyof BaseLLMEvents = `success`; - const finishEventName: keyof BaseLLMEvents = `finish`; - const startEventName: keyof BaseLLMEvents = `start`; - const errorEventName: keyof BaseLLMEvents = `error`; + const successEventName: keyof ChatModelEvents = `success`; + const finishEventName: keyof ChatModelEvents = `finish`; + const startEventName: keyof ChatModelEvents = `start`; + const errorEventName: keyof ChatModelEvents = `error`; const eventsIterationsMap = new Map>(); @@ -281,9 +281,8 @@ export function createTelemetryMiddleware() { // Read rawPrompt from llm input only for supported adapters and create the custom event with it emitter.match( (event) => assertLLMWithMessagesToPromptFn(event.creator) && event.name === startEventName, - ({ input }: InferCallbackValue, meta) => { + (_, meta) => { if (assertLLMWithMessagesToPromptFn(meta.creator) && meta.trace) { - const rawPrompt = meta.creator.messagesToPrompt(input); // create a custom path to prevent event duplication const path = `${meta.path}.custom`; @@ -304,7 +303,7 @@ export function createTelemetryMiddleware() { startedAt: convertDateToPerformance(meta.createdAt), ...(parentSpanId && { parent: { id: parentSpanId } }), data: { - rawPrompt, + rawPrompt: undefined, creator: meta.creator.createSnapshot(), }, }), diff --git a/src/instrumentation/helpers/utils.ts b/src/instrumentation/helpers/utils.ts index ebee25a9..d4854f2f 100644 --- a/src/instrumentation/helpers/utils.ts +++ b/src/instrumentation/helpers/utils.ts @@ -14,16 +14,8 @@ * limitations under the License. */ -import { BaseLLM } from "@/llms/base.js"; -import { isFunction } from "remeda"; -import type { LLMChatTemplate } from "@/adapters/shared/llmChatTemplates.js"; +import { ChatModel } from "@/backend/chat.js"; -export function assertLLMWithMessagesToPromptFn(instance: object): instance is BaseLLM & { - messagesToPrompt: LLMChatTemplate["messagesToPrompt"]; -} { - return Boolean( - instance instanceof BaseLLM && - "messagesToPrompt" in instance && - isFunction(instance.messagesToPrompt), - ); +export function assertLLMWithMessagesToPromptFn(instance: object): instance is ChatModel { + return Boolean(instance && instance instanceof ChatModel); } diff --git a/src/internals/env.ts b/src/internals/env.ts index d6dabb30..df8d3a5b 100644 --- a/src/internals/env.ts +++ b/src/internals/env.ts @@ -14,15 +14,21 @@ * limitations under the License. */ -import { z } from "zod"; +import { z, ZodSchema } from "zod"; import { FrameworkError } from "@/errors.js"; import { getProp } from "@/internals/helpers/object.js"; -export function getEnv(key: string) { - return getProp(process.env, [key], undefined); +export function getEnv(key: string, fallback?: never): string | undefined; +export function getEnv(key: string, fallback: string): string; +export function getEnv(key: string, fallback?: string) { + return getProp(process.env, [key], fallback); } -export function parseEnv(key: string, schema: z.ZodType, defaultValue?: T): T { +export function parseEnv( + key: string, + schema: T, + defaultValue?: string, +): z.output { const value = getEnv(key) ?? defaultValue; const result = schema.safeParse(value); if (!result.success) { diff --git a/src/internals/helpers/number.ts b/src/internals/helpers/number.ts index 9cf99461..581688eb 100644 --- a/src/internals/helpers/number.ts +++ b/src/internals/helpers/number.ts @@ -20,6 +20,10 @@ export function safeSum(...numbers: (number | undefined | null)[]): number { return R.sum(numbers?.filter(R.isNonNullish) || [0]); } +export function takeBigger(...numbers: (number | undefined | null)[]): number { + return Math.max(...(numbers?.filter(R.isNonNullish) || [0])) || 0; +} + export function ensureRange(value: number, options: { min?: number; max?: number }): number { return Math.max(options.min ?? -Infinity, Math.min(value, options.max ?? Infinity)); } diff --git a/src/internals/helpers/object.ts b/src/internals/helpers/object.ts index fd42ff43..0907cd02 100644 --- a/src/internals/helpers/object.ts +++ b/src/internals/helpers/object.ts @@ -133,8 +133,10 @@ export function customMerge>( } export function mapObj(obj: T) { - return function (fn: (key: K, value: T[K]) => T[K]): T { - const updated: T = Object.assign({}, obj); + return function ( + fn: (key: K, value: T[K]) => R, + ): Record { + const updated = {} as Record; for (const pair of Object.entries(obj)) { const [key, value] = pair as [K, T[K]]; updated[key] = fn(key, value); diff --git a/src/internals/helpers/promise.ts b/src/internals/helpers/promise.ts index 41f37b27..c19bf04d 100644 --- a/src/internals/helpers/promise.ts +++ b/src/internals/helpers/promise.ts @@ -160,3 +160,7 @@ export async function executeSequentially(tasks: (() => Promise)[]): Promis await task(); } } + +export async function* toAsyncGenerator(promise: T): AsyncGenerator> { + yield await promise; +} diff --git a/src/internals/helpers/stream.ts b/src/internals/helpers/stream.ts index fc1807fb..4a46121f 100644 --- a/src/internals/helpers/stream.ts +++ b/src/internals/helpers/stream.ts @@ -24,3 +24,7 @@ export async function* transformAsyncIterable( } return next.value; } + +export function isAsyncIterable(value: any): value is AsyncIterable { + return Boolean(value && Symbol.asyncIterator in value); +} diff --git a/src/internals/serializable.ts b/src/internals/serializable.ts index fd690d79..512da69d 100644 --- a/src/internals/serializable.ts +++ b/src/internals/serializable.ts @@ -15,8 +15,7 @@ */ import { Serializer } from "@/serializer/serializer.js"; -import { ClassConstructor, PromiseOrPlain } from "@/internals/types.js"; -import * as R from "remeda"; +import { ClassConstructor } from "@/internals/types.js"; import { extractClassName } from "@/serializer/utils.js"; import { SerializerError } from "@/serializer/error.js"; import { Cache } from "@/cache/decoratorCache.js"; @@ -29,41 +28,41 @@ interface SerializableStructure { snapshot: T; } -interface DeserializeOptions { +export interface DeserializeOptions { extraClasses?: SerializableClass[]; } export abstract class Serializable { - abstract createSnapshot(): T; - abstract loadSnapshot(snapshot: T): void; + abstract createSnapshot(): T | Promise; + abstract loadSnapshot(snapshot: T): void | Promise; constructor() { Object.getPrototypeOf(this).constructor.register(); Cache.init(this); } - protected static register(this: SerializableClass, aliases?: string[]) { + public static register(this: SerializableClass, aliases?: string[]) { Serializer.registerSerializable(this, undefined, aliases); } - clone(this: T): T { - const snapshot = this.createSnapshot(); + async clone(this: T): Promise { + const snapshot = await this.createSnapshot(); - const target = Object.create(this.constructor.prototype); - target.loadSnapshot(snapshot); + const target = Object.create(this.constructor.prototype) as T; + await target.loadSnapshot(snapshot); return target; } - serialize(): string { - const snapshot = this.createSnapshot(); - return Serializer.serialize>({ + async serialize(): Promise { + const snapshot = await this.createSnapshot(); + return await Serializer.serialize>({ target: extractClassName(this), snapshot, }); } - protected deserialize(value: string, options?: DeserializeOptions): T { - const { __root } = Serializer.deserializeWithMeta>( + protected async deserialize(value: string, options?: DeserializeOptions): Promise { + const { __root } = await Serializer.deserializeWithMeta>( value, options?.extraClasses, ); @@ -84,29 +83,25 @@ export abstract class Serializable { return __root.snapshot; } - static fromSnapshot( - this: new (...args: any[]) => T extends Serializable

? T : never, + static async fromSnapshot>( + this: new (...args: any[]) => T, state: P, - ): T { + ): Promise { const target = Object.create(this.prototype); - target.loadSnapshot(state); + await target.loadSnapshot(state); Cache.init(target); return target; } - static fromSerialized( + static async fromSerialized( this: abstract new (...args: any[]) => T, serialized: string, options: DeserializeOptions = {}, - ): PromiseOrPlain { + ): Promise { const target = Object.create(this.prototype) as T; - const state = target.deserialize(serialized, options); - const load = target.loadSnapshot(state); + const state = await target.deserialize(serialized, options); + await target.loadSnapshot(state); Cache.init(target); - - return (R.isPromise(load) ? load.then(() => target) : target) as PromiseOrPlain< - T, - T["loadSnapshot"] - >; + return target; } } diff --git a/src/internals/types.ts b/src/internals/types.ts index 251afe14..d6e442f0 100644 --- a/src/internals/types.ts +++ b/src/internals/types.ts @@ -117,3 +117,16 @@ export type AnyVoid = Promise | unknown; export type OmitPrivateKeys = { [K in keyof T as K extends `_${string}` ? never : K]: T[K]; }; + +type MergeElements = A extends never ? B : B extends never ? A : A | B; +export type MergeArrays = A extends [] + ? B + : B extends [] + ? A + : [MergeElements, Head>, ...MergeArrays, Tail>]; + +export type MergeFunctions = ( + ...args: MergeArrays, Parameters> +) => MergeElements, ReturnType>; + +export type WithoutLast = T extends [...infer A, any] ? A : []; diff --git a/src/llms/base.test.ts b/src/llms/base.test.ts deleted file mode 100644 index 30d528b9..00000000 --- a/src/llms/base.test.ts +++ /dev/null @@ -1,254 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - BaseLLMTokenizeOutput, - AsyncStream, - BaseLLMOutput, - GenerateOptions, - BaseLLM, - BaseLLMEvents, - EmbeddingOptions, - EmbeddingOutput, - StreamGenerateOptions, -} from "./base.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { UnconstrainedCache } from "@/cache/unconstrainedCache.js"; -import { setTimeout } from "node:timers/promises"; -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { NotImplementedError } from "@/errors.js"; - -describe("BaseLLM", () => { - class DummyOutput extends BaseLLMOutput { - constructor(public content: string) { - super(); - } - - merge(other: DummyOutput) { - this.content += other.content; - } - - getTextContent(): string { - return this.content; - } - - toString(): string { - return this.getTextContent(); - } - - createSnapshot(): unknown { - return { content: this.content }; - } - - loadSnapshot(snapshot: unknown) { - Object.assign(this, snapshot); - } - } - - class DummyLLM extends BaseLLM { - public throwErrorCount = 0; - - public readonly emitter = Emitter.root.child({ - namespace: ["dummy", "llm"], - creator: this, - }); - - async meta() { - return { tokenLimit: 4096 }; - } - - // eslint-disable-next-line unused-imports/no-unused-vars - async embed(input: string[], options?: EmbeddingOptions): Promise { - throw new NotImplementedError(); - } - - // eslint-disable-next-line unused-imports/no-unused-vars - tokenize(input: string): Promise { - throw new NotImplementedError(); - } - - protected async _generate( - input: string, - options: Partial, - ): Promise { - options?.signal?.throwIfAborted(); - await setTimeout(200); - if (this.throwErrorCount > 0) { - this.throwErrorCount--; - throw new Error("Error has occurred"); - } - return new DummyOutput(input); - } - - protected async *_stream( - input: string, - options: Partial, - ): AsyncStream { - for (const chunk of input.split(",")) { - if (options?.signal?.aborted) { - break; - } - await setTimeout(100); - yield new DummyOutput(chunk); - } - } - - createSnapshot() { - return { ...super.createSnapshot(), throwErrorCount: this.throwErrorCount }; - } - } - - it("Stops generating", async () => { - const model = new DummyLLM("my-model"); - - const chunks: string[] = []; - await model - .generate("1,2,3,4,5", { - stream: true, - }) - .observe((emitter) => - emitter.registerCallbacks({ - newToken: ({ value, callbacks: { abort } }) => { - chunks.push(value.getTextContent()); - if (value.getTextContent() === "3") { - abort(); - } - }, - }), - ); - expect(chunks.join(",")).toBe("1,2,3"); - }); - - describe("Caching", () => { - let model: DummyLLM; - beforeEach(() => { - model = new DummyLLM("my-model", {}, new UnconstrainedCache()); - }); - - const generate = async (input: unknown[], options?: GenerateOptions) => { - const chunks: string[] = []; - const events: string[] = []; - - await model.generate(input.join(","), options).observe((emitter) => { - emitter.registerCallbacks({ - newToken: ({ value }) => { - chunks.push(value.getTextContent()); - }, - }); - emitter.match("*.*", (_, event) => { - events.push(event.path); - }); - }); - - return { chunks, events }; - }; - - it("Handles streaming", async () => { - const [a, b] = await Promise.all([ - generate([1, 2, 3], { - stream: true, - }), - generate([1, 2, 3], { - stream: true, - }), - ]); - expect(a).toEqual(b); - await expect(model.cache.size()).resolves.toBe(1); - }); - - it("Handles non-streaming", async () => { - const [c, d] = await Promise.all([ - generate([1, 2, 3], { - stream: false, - }), - generate([1, 2, 3], { - stream: false, - }), - ]); - expect(c).toEqual(d); - await expect(model.cache.size()).resolves.toBe(1); - }); - - it("Correctly generates cache keys", async () => { - await expect(model.cache.size()).resolves.toBe(0); - - await generate(["a"]); - await expect(model.cache.size()).resolves.toBe(1); - - await generate(["a"], {}); - await expect(model.cache.size()).resolves.toBe(1); - await generate(["a"], { signal: AbortSignal.timeout(1000) }); - await expect(model.cache.size()).resolves.toBe(1); - - await generate(["a"], { stream: false }); - await expect(model.cache.size()).resolves.toBe(2); - - await generate(["a"], { stream: true }); - await expect(model.cache.size()).resolves.toBe(3); - await generate(["a"], { signal: AbortSignal.timeout(1500), stream: true }); - await expect(model.cache.size()).resolves.toBe(3); - - await generate(["a"], { guided: { regex: /.+/.source } }); - await expect(model.cache.size()).resolves.toBe(4); - await generate(["a"], { guided: { regex: /.+/.source } }); - await expect(model.cache.size()).resolves.toBe(4); - }); - - it("Clears cache", async () => { - await generate(["a"]); - await expect(model.cache.size()).resolves.toBe(1); - await model.cache.clear(); - await expect(model.cache.size()).resolves.toBe(0); - }); - - it("Ignores rejected values", async () => { - vi.useRealTimers(); - - model.throwErrorCount = 1; - for (const promise of await Promise.allSettled([ - setTimeout(0, model.generate("Test")), - setTimeout(0, model.generate("Test")), - setTimeout(0, model.generate("Test")), - ])) { - expect(promise).property("status").to.eq("rejected"); - } - await expect(model.cache.size()).resolves.toBe(0); - - await expect(model.generate("Test")).resolves.toBeTruthy(); - await expect(model.cache.size()).resolves.toBe(1); - }); - - it("Serializes with non-empty cache", async () => { - await expect(model.generate("Test")).resolves.toBeTruthy(); - await expect(model.cache.size()).resolves.toBe(1); - - const serialized = model.serialize(); - const deserialized = DummyLLM.fromSerialized(serialized); - verifyDeserialization(model, deserialized); - - await expect(deserialized.cache.size()).resolves.toBe(1); - await expect(deserialized.generate("Test")).resolves.toBeTruthy(); - await expect(deserialized.cache.size()).resolves.toBe(1); - }); - }); - - it("Serializes", () => { - const model = new DummyLLM("my-model"); - const serialized = model.serialize(); - const deserialized = DummyLLM.fromSerialized(serialized); - verifyDeserialization(model, deserialized); - }); -}); diff --git a/src/llms/base.ts b/src/llms/base.ts deleted file mode 100644 index a55f4669..00000000 --- a/src/llms/base.ts +++ /dev/null @@ -1,355 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { FrameworkError } from "@/errors.js"; -import { Serializable } from "@/internals/serializable.js"; -import { createAbortController } from "@/internals/helpers/cancellation.js"; -import { OneOf } from "@/internals/types.js"; -import { Emitter } from "@/emitter/emitter.js"; -import { GetRunContext, RunContext } from "@/context.js"; -import { Callback } from "@/emitter/types.js"; -import { shallowCopy } from "@/serializer/utils.js"; -import { pRetry } from "@/internals/helpers/retry.js"; -import { emitterToGenerator } from "@/internals/helpers/promise.js"; -import { BaseCache } from "@/cache/base.js"; -import { NullCache } from "@/cache/nullCache.js"; -import { ObjectHashKeyFn } from "@/cache/decoratorCache.js"; -import { doNothing, omit } from "remeda"; -import { Task } from "promise-based-task"; -import { INSTRUMENTATION_ENABLED } from "@/instrumentation/config.js"; -import { createTelemetryMiddleware } from "@/instrumentation/create-telemetry-middleware.js"; - -export interface BaseLLMEvents { - newToken?: Callback<{ value: TOutput; callbacks: { abort: () => void } }>; - success?: Callback<{ value: TOutput }>; - start?: Callback<{ input: TInput; options: unknown }>; - error?: Callback<{ input: TInput; error: FrameworkError; options: unknown }>; - finish?: Callback; -} - -/** - * @deprecated Use BaseLLMEvents instead - */ -export type GenerateCallbacks = BaseLLMEvents; - -export type GuidedOptions = OneOf< - [ - { - json?: string | Record; - }, - { - regex?: string; - }, - { - choice?: string[]; - }, - { - grammar?: string; - }, - { - decoding_backend?: string; - }, - { - whitespace_pattern?: string; - }, - ] ->; - -export interface GenerateOptions { - stream?: boolean; - signal?: AbortSignal; - guided?: GuidedOptions; -} - -export interface InternalGenerateOptions { - signal?: AbortSignal; -} - -export interface StreamGenerateOptions { - signal?: AbortSignal; - guided?: GuidedOptions; -} - -export type AsyncStream = AsyncGenerator; - -export class LLMError extends FrameworkError {} -export class LLMFatalError extends LLMError { - constructor(message: string, errors?: Error[]) { - super(message, errors, { - isRetryable: false, - isFatal: true, - }); - } -} -export class LLMOutputError extends LLMFatalError {} - -export interface BaseLLMTokenizeOutput { - tokensCount: number; - tokens?: string[]; -} - -export abstract class BaseLLMOutput extends Serializable { - mergeImmutable(this: T, other: T): T { - const newInstance = this.clone() as T; - newInstance.merge(other); - return newInstance; - } - - abstract merge(other: BaseLLMOutput): void; - - abstract getTextContent(): string; - - abstract toString(): string; -} - -export interface ExecutionOptions { - maxRetries?: number; -} - -export interface EmbeddingOptions { - signal?: AbortSignal; -} - -export interface EmbeddingOutput { - embeddings: number[][]; -} - -export interface LLMMeta { - tokenLimit: number; -} - -export type LLMCache = BaseCache>; - -export abstract class BaseLLM< - TInput, - TOutput extends BaseLLMOutput, - TGenerateOptions extends GenerateOptions = GenerateOptions, -> extends Serializable { - public abstract readonly emitter: Emitter>; - - constructor( - public readonly modelId: string, - public readonly executionOptions: ExecutionOptions = {}, - public readonly cache: LLMCache = new NullCache(), - ) { - super(); - } - - abstract meta(): Promise; - - abstract embed(input: TInput[], options?: EmbeddingOptions): Promise; - - abstract tokenize(input: TInput): Promise; - - generate(input: TInput, options: Partial = {}) { - input = shallowCopy(input); - options = shallowCopy(options); - - return RunContext.enter( - this, - { params: [input, options] as const, signal: options?.signal }, - async (run) => { - const cacheEntry = await this.createCacheAccessor(input, options); - - try { - await run.emitter.emit("start", { input, options }); - - if (options?.stream) { - const chunks: TOutput[] = []; - const controller = createAbortController(options?.signal); - - const tokenEmitter = run.emitter.child({ groupId: "tokens" }); - for await (const chunk of cacheEntry.value ?? - this._stream( - input, - { - ...options, - signal: controller.signal, - }, - run, - )) { - if (controller.signal.aborted) { - continue; - } - - chunks.push(chunk); - await tokenEmitter.emit("newToken", { - value: chunk, - callbacks: { abort: () => controller.abort() }, - }); - } - - const result = this._mergeChunks(chunks); - await run.emitter.emit("success", { value: result }); - cacheEntry.resolve(chunks); - return result; - } - - const result: TOutput = - cacheEntry?.value?.at(0) || - (await pRetry(() => this._generate(input, options, run), { - retries: this.executionOptions.maxRetries || 0, - ...options, - signal: run.signal, - })); - await run.emitter.emit("success", { value: result }); - cacheEntry.resolve([result]); - return result; - } catch (error) { - await run.emitter.emit("error", { input, error, options }); - await cacheEntry.reject(error); - if (error instanceof LLMError) { - throw error; - } else { - throw new LLMError(`LLM has occurred an error.`, [error]); - } - } finally { - await run.emitter.emit("finish", null); - } - }, - ).middleware(INSTRUMENTATION_ENABLED ? createTelemetryMiddleware() : doNothing()); - } - - async *stream(input: TInput, options: Partial = {}): AsyncStream { - input = shallowCopy(input); - options = shallowCopy(options); - - return yield* emitterToGenerator(async ({ emit }) => { - return RunContext.enter( - this, - { params: [input, options] as const, signal: options?.signal }, - async (run) => { - const cacheEntry = await this.createCacheAccessor(input, options); - - try { - await run.emitter.emit("start", { input, options }); - - const tokenEmitter = run.emitter.child({ groupId: "tokens" }); - const chunks: TOutput[] = []; - const controller = createAbortController(options?.signal); - - for await (const chunk of cacheEntry.value || - this._stream(input, { ...options, signal: controller.signal }, run)) { - if (controller.signal.aborted) { - continue; - } - - chunks.push(chunk); - await tokenEmitter.emit("newToken", { - value: chunk, - callbacks: { abort: () => controller.abort() }, - }); - emit(chunk); - } - const result = this._mergeChunks(chunks); - await run.emitter.emit("success", { value: result }); - cacheEntry.resolve(chunks); - } catch (error) { - await run.emitter.emit("error", { input, error, options }); - await cacheEntry.reject(error); - if (error instanceof LLMError) { - throw error; - } else { - throw new LLMError(`LLM has occurred an error.`, [error]); - } - } finally { - await run.emitter.emit("finish", null); - } - }, - ).middleware(INSTRUMENTATION_ENABLED ? createTelemetryMiddleware() : doNothing()); - }); - } - - protected abstract _generate( - input: TInput, - options: Partial, - run: GetRunContext, - ): Promise; - - protected abstract _stream( - input: TInput, - options: Partial, - run: GetRunContext, - ): AsyncStream; - - protected _mergeChunks(chunks: TOutput[]): TOutput { - if (chunks.length === 0) { - throw new LLMOutputError("Cannot merge empty chunks!"); - } - return chunks.reduce((prev, cur) => prev.mergeImmutable(cur)); - } - - static cast>( - this: new (...args: any[]) => T, - value: unknown, - ): asserts value is T {} - - static castInput( - this: new (...args: any[]) => BaseLLM, - value: unknown, - ): asserts value is A {} - - static castOutput>( - this: new (...args: any[]) => T, - value: BaseLLMOutput, - ): asserts value is InferLLMOutput {} - - createSnapshot() { - return { - modelId: this.modelId, - executionOptions: shallowCopy(this.executionOptions), - emitter: this.emitter, - cache: this.cache, - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } - - protected async createCacheAccessor( - input: TInput, - options: Partial | Partial, - ...extra: any[] - ) { - const key = ObjectHashKeyFn(input, omit(options ?? {}, ["signal"]), ...extra); - const value = await this.cache.get(key); - const isNew = value === undefined; - - let task: Task | null = null; - if (isNew) { - task = new Task(); - await this.cache.set(key, task); - } - - return { - key, - value, - resolve: (value: T2 | T2[]) => { - task?.resolve?.(Array.isArray(value) ? value : [value]); - }, - reject: async (error: Error) => { - task?.reject?.(error); - if (isNew) { - await this.cache.delete(key); - } - }, - }; - } -} - -export type AnyLLM = BaseLLM; -export type InferLLMOutput = T extends BaseLLM ? A : never; diff --git a/src/llms/chat.ts b/src/llms/chat.ts deleted file mode 100644 index 82c108d9..00000000 --- a/src/llms/chat.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BaseLLM, BaseLLMOutput, BaseLLMEvents, GenerateOptions } from "@/llms/base.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; -import { Emitter } from "@/emitter/emitter.js"; - -export type ChatLLMGenerateEvents = BaseLLMEvents< - BaseMessage[], - TOutput ->; - -export abstract class ChatLLMOutput extends BaseLLMOutput { - abstract get messages(): readonly BaseMessage[]; -} - -export abstract class ChatLLM< - TOutput extends ChatLLMOutput, - TGenerateOptions extends GenerateOptions = GenerateOptions, -> extends BaseLLM { - public abstract readonly emitter: Emitter>; -} - -export type AnyChatLLM = ChatLLM; diff --git a/src/llms/drivers/base.ts b/src/llms/drivers/base.ts deleted file mode 100644 index 0a8edc03..00000000 --- a/src/llms/drivers/base.ts +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createSchemaValidator, toJsonSchema } from "@/internals/helpers/schema.js"; -import { GenerateOptions, LLMError } from "@/llms/base.js"; -import { ChatLLM, ChatLLMOutput } from "@/llms/chat.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { Retryable } from "@/internals/helpers/retryable.js"; -import { PromptTemplate } from "@/template.js"; -import { SchemaObject } from "ajv"; -import { TypeOf, z, ZodTypeAny } from "zod"; -import { Serializable } from "@/internals/serializable.js"; - -export interface GenerateSchemaInput { - maxRetries?: number; - options?: T; -} - -export interface DriverResponse { - raw: ChatLLMOutput; - parsed: T extends ZodTypeAny ? TypeOf : T; - messages: BaseMessage[]; -} - -export abstract class BaseDriver< - TGenerateOptions extends GenerateOptions = GenerateOptions, -> extends Serializable { - protected abstract template: PromptTemplate.infer<{ schema: string }>; - protected errorTemplate = new PromptTemplate({ - schema: z.object({ - errors: z.string(), - expected: z.string(), - received: z.string(), - }), - template: `Generated response does not match the expected schema! -Validation Errors: "{{errors}}"`, - }); - - constructor(protected readonly llm: ChatLLM) { - super(); - } - - protected abstract parseResponse(textResponse: string): unknown; - protected abstract schemaToString(schema: SchemaObject): Promise | string; - - // eslint-disable-next-line unused-imports/no-unused-vars - protected guided(schema: SchemaObject): GenerateOptions["guided"] | undefined { - return undefined; - } - - async generate( - schema: T extends ZodTypeAny ? T : SchemaObject, - input: BaseMessage[], - { maxRetries = 3, options }: GenerateSchemaInput = {}, - ): Promise> { - const jsonSchema = toJsonSchema(schema); - const validator = createSchemaValidator(jsonSchema); - const schemaString = await this.schemaToString(jsonSchema); - - const messages: BaseMessage[] = [ - BaseMessage.of({ - role: Role.SYSTEM, - text: this.template.render({ schema: schemaString }), - }), - ...input, - ]; - - return new Retryable({ - executor: async () => { - const raw = await this.llm.generate(messages, { - guided: this.guided(jsonSchema), - ...options, - } as TGenerateOptions); - const textResponse = raw.getTextContent(); - let parsed: any; - - try { - parsed = this.parseResponse(textResponse); - } catch (error) { - throw new LLMError(`Failed to parse the generated response.`, [], { - isFatal: false, - isRetryable: true, - context: { error: (error as Error).message, received: textResponse }, - }); - } - - const success = validator(parsed); - if (!success) { - const context = { - expected: schemaString, - received: textResponse, - errors: JSON.stringify(validator.errors ?? []), - }; - - messages.push( - BaseMessage.of({ - role: Role.USER, - text: this.errorTemplate.render(context), - }), - ); - throw new LLMError( - "Failed to generate a structured response adhering to the provided schema.", - [], - { - isFatal: false, - isRetryable: true, - context, - }, - ); - } - return { - raw: raw, - parsed: parsed, - messages, - }; - }, - config: { - signal: options?.signal, - maxRetries, - }, - }).get(); - } - - createSnapshot() { - return { - template: this.template, - errorTemplate: this.errorTemplate, - }; - } - - loadSnapshot(snapshot: ReturnType) { - Object.assign(this, snapshot); - } -} diff --git a/src/llms/drivers/json.ts b/src/llms/drivers/json.ts deleted file mode 100644 index d147cea0..00000000 --- a/src/llms/drivers/json.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { parseBrokenJson } from "@/internals/helpers/schema.js"; -import { GenerateOptions } from "@/llms/base.js"; -import { PromptTemplate } from "@/template.js"; -import { BaseDriver } from "@/llms/drivers/base.js"; -import { SchemaObject } from "ajv"; -import { z } from "zod"; - -export class JsonDriver< - TGenerateOptions extends GenerateOptions = GenerateOptions, -> extends BaseDriver { - protected template = new PromptTemplate({ - schema: z.object({ - schema: z.string(), - }), - template: `You are a helpful assistant that generates only valid JSON adhering to the following JSON Schema. - -\`\`\` -{{schema}} -\`\`\` - -IMPORTANT: Every message must be a parsable JSON string without additional output. -`, - }); - - static { - this.register(); - } - - static fromTemplate( - template: T, - ...parameters: ConstructorParameters - ) { - const driver = new JsonDriver(...parameters); - driver.template = template; - return driver; - } - - protected parseResponse(textResponse: string): unknown { - return parseBrokenJson(textResponse); - } - - protected schemaToString(schema: SchemaObject): string { - return JSON.stringify(schema, null, 2); - } - - protected guided(schema: SchemaObject) { - return { json: schema } as const; - } -} diff --git a/src/llms/drivers/typescript.ts b/src/llms/drivers/typescript.ts deleted file mode 100644 index 40fd373d..00000000 --- a/src/llms/drivers/typescript.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { parseBrokenJson } from "@/internals/helpers/schema.js"; -import { GenerateOptions } from "@/llms/base.js"; -import { PromptTemplate } from "@/template.js"; -import { BaseDriver } from "@/llms/drivers/base.js"; -import * as jsonSchemaToTypescript from "json-schema-to-typescript"; -import { SchemaObject } from "ajv"; -import { z } from "zod"; - -export class TypescriptDriver< - TGenerateOptions extends GenerateOptions = GenerateOptions, -> extends BaseDriver { - protected template = new PromptTemplate({ - schema: z.object({ - schema: z.string(), - }), - template: `You are a helpful assistant that generates only valid JSON adhering to the following TypeScript type. - -\`\`\` -{{schema}} -\`\`\` - -IMPORTANT: Every message must be a parsable JSON string without additional output. -`, - }); - - static { - this.register(); - } - - protected parseResponse(textResponse: string): unknown { - return parseBrokenJson(textResponse); - } - - protected async schemaToString(schema: SchemaObject): Promise { - return await jsonSchemaToTypescript.compile(schema, "Output"); - } - - protected guided(schema: SchemaObject) { - return { json: schema } as const; - } -} diff --git a/src/llms/drivers/yaml.ts b/src/llms/drivers/yaml.ts deleted file mode 100644 index 1be072cc..00000000 --- a/src/llms/drivers/yaml.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { GenerateOptions } from "@/llms/base.js"; -import { PromptTemplate } from "@/template.js"; -import { BaseDriver } from "@/llms/drivers/base.js"; -import yaml from "js-yaml"; -import { SchemaObject } from "ajv"; -import { z } from "zod"; - -export class YamlDriver< - TGenerateOptions extends GenerateOptions = GenerateOptions, -> extends BaseDriver { - protected template = new PromptTemplate({ - schema: z.object({ - schema: z.string(), - }), - template: `You are a helpful assistant that generates only valid YAML adhering to the following schema. - -\`\`\` -{{schema}} -\`\`\` - -IMPORTANT: Every message must be a parsable YAML string without additional output. -`, - }); - - static { - this.register(); - } - - protected parseResponse(textResponse: string): unknown { - return yaml.load(textResponse); - } - - protected schemaToString(schema: SchemaObject): string { - return yaml.dump(schema); - } -} diff --git a/src/llms/primitives/message.ts b/src/llms/primitives/message.ts deleted file mode 100644 index 2b6e25de..00000000 --- a/src/llms/primitives/message.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { EnumLowerCaseValue } from "@/internals/types.js"; -import { Serializable } from "@/internals/serializable.js"; -import { shallowCopy } from "@/serializer/utils.js"; - -export const Role = { - ASSISTANT: "assistant", - SYSTEM: "system", - USER: "user", -} as const; - -export type RoleType = EnumLowerCaseValue | string; - -export interface BaseMessageMeta { - [key: string]: any; - createdAt?: Date; -} - -export interface BaseMessageInput { - role: RoleType; - text: string; - meta?: BaseMessageMeta; -} - -export class BaseMessage extends Serializable { - constructor( - public readonly role: RoleType, - public readonly text: string, - public readonly meta?: BaseMessageMeta, - ) { - super(); - } - - static { - this.register(); - } - - static of({ role, text, meta }: BaseMessageInput) { - return new BaseMessage(role, text, meta); - } - - createSnapshot() { - return { - role: this.role, - text: this.text, - meta: shallowCopy(this.meta), - }; - } - - loadSnapshot(state: ReturnType) { - return Object.assign(this, state); - } -} diff --git a/src/logger/logger.test.ts b/src/logger/logger.test.ts index f49e476c..c41170a8 100644 --- a/src/logger/logger.test.ts +++ b/src/logger/logger.test.ts @@ -85,7 +85,7 @@ describe("Logger", () => { ]); }); - it("Serializes", () => { + it("Serializes", async () => { const instance = new Logger({ name: "Root", bindings: { @@ -94,8 +94,8 @@ describe("Logger", () => { }); instance.level = "fatal"; - const serialized = instance.serialize(); - const deserialized = Logger.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await Logger.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/src/memory/base.ts b/src/memory/base.ts index 9b6983ce..89949d55 100644 --- a/src/memory/base.ts +++ b/src/memory/base.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { BaseMessage } from "@/llms/primitives/message.js"; +import { Message } from "@/backend/message.js"; import { FrameworkError, FrameworkErrorOptions } from "@/errors.js"; import { Serializable } from "@/internals/serializable.js"; @@ -30,14 +30,14 @@ export class MemoryFatalError extends MemoryError { } export abstract class BaseMemory extends Serializable { - abstract get messages(): readonly BaseMessage[]; + abstract get messages(): readonly Message[]; - abstract add(message: BaseMessage, index?: number): Promise; + abstract add(message: Message, index?: number): Promise; - abstract delete(message: BaseMessage): Promise; + abstract delete(message: Message): Promise; abstract reset(): void; - async addMany(messages: Iterable | AsyncIterable, start?: number) { + async addMany(messages: Iterable | AsyncIterable, start?: number) { let counter = 0; for await (const msg of messages) { await this.add(msg, start === undefined ? undefined : start + counter); @@ -45,13 +45,13 @@ export abstract class BaseMemory extends Serializable } } - async deleteMany(messages: Iterable | AsyncIterable) { + async deleteMany(messages: Iterable | AsyncIterable) { for await (const msg of messages) { await this.delete(msg); } } - async splice(start: number, deleteCount: number, ...items: BaseMessage[]) { + async splice(start: number, deleteCount: number, ...items: Message[]) { const total = this.messages.length; start = start < 0 ? Math.max(total + start, 0) : start; @@ -90,14 +90,14 @@ export class ReadOnlyMemory extends BaseMemor } // eslint-disable-next-line unused-imports/no-unused-vars - async add(message: BaseMessage, index?: number) {} + async add(message: Message, index?: number) {} // eslint-disable-next-line unused-imports/no-unused-vars - async delete(message: BaseMessage) { + async delete(message: Message) { return false; } - get messages(): readonly BaseMessage[] { + get messages(): readonly Message[] { return this.source.messages; } diff --git a/src/memory/slidingMemory.test.ts b/src/memory/slidingMemory.test.ts index 93fe8629..27a89286 100644 --- a/src/memory/slidingMemory.test.ts +++ b/src/memory/slidingMemory.test.ts @@ -14,16 +14,16 @@ * limitations under the License. */ -import { BaseMessage, Role } from "@/llms/primitives/message.js"; import { verifyDeserialization } from "@tests/e2e/utils.js"; import { SlidingMemory } from "@/memory/slidingMemory.js"; +import { Message, UserMessage } from "@/backend/message.js"; describe("Sliding Memory", () => { it("Removes old messages", async () => { const instance = new SlidingMemory({ size: 2, }); - await instance.addMany(["A", "B", "C"].map((text) => BaseMessage.of({ role: "user", text }))); + await instance.addMany(["A", "B", "C"].map((text) => Message.of({ role: "user", text }))); expect(Array.from(instance).map((msg) => msg.text)).toStrictEqual(["B", "C"]); }); @@ -34,8 +34,8 @@ describe("Sliding Memory", () => { removalSelector: (messages) => messages.find((msg) => msg.role !== "system")!, }, }); - await instance.add(BaseMessage.of({ role: "system", text: "You are a helpful assistant." })); - await instance.addMany(["A", "B", "C"].map((text) => BaseMessage.of({ role: "user", text }))); + await instance.add(Message.of({ role: "system", text: "You are a helpful assistant." })); + await instance.addMany(["A", "B", "C"].map((text) => new UserMessage(text))); expect(Array.from(instance).map((msg) => msg.text)).toStrictEqual([ "You are a helpful assistant.", "C", @@ -61,11 +61,8 @@ describe("Sliding Memory", () => { }, }, }); - await instance.addMany( - ["user", "assistant", "user", "assistant", "user", "user"].map((role, i) => - BaseMessage.of({ role, text: `${i + 1}` }), - ), - ); + const roles = ["user", "assistant", "user", "assistant", "user", "user"] as const; + await instance.addMany(roles.map((role, i) => Message.of({ role, text: `${i + 1}` }))); expect(Array.from(instance).map((msg) => msg.text)).toStrictEqual(["3", "4", "5", "6"]); }); @@ -73,14 +70,9 @@ describe("Sliding Memory", () => { const instance = new SlidingMemory({ size: 5, }); - await instance.add( - BaseMessage.of({ - text: "Hello!", - role: Role.USER, - }), - ); - const serialized = instance.serialize(); - const deserialized = SlidingMemory.fromSerialized(serialized); + await instance.add(new UserMessage("Hello!")); + const serialized = await instance.serialize(); + const deserialized = await SlidingMemory.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/src/memory/slidingMemory.ts b/src/memory/slidingMemory.ts index 40624027..0a6445c9 100644 --- a/src/memory/slidingMemory.ts +++ b/src/memory/slidingMemory.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { BaseMessage } from "@/llms/primitives/message.js"; +import { Message } from "@/backend/message.js"; import { BaseMemory, MemoryFatalError } from "@/memory/base.js"; import { shallowCopy } from "@/serializer/utils.js"; import { filter, forEach, isTruthy, pipe } from "remeda"; @@ -23,7 +23,7 @@ import { RequiredNested } from "@/internals/types.js"; import { ensureRange } from "@/internals/helpers/number.js"; export interface Handlers { - removalSelector: (messages: BaseMessage[]) => BaseMessage | BaseMessage[]; + removalSelector: (messages: Message[]) => Message | Message[]; } export interface SlidingWindowMemoryInput { @@ -32,7 +32,7 @@ export interface SlidingWindowMemoryInput { } export class SlidingMemory extends BaseMemory { - public readonly messages: BaseMessage[] = []; + public readonly messages: Message[] = []; public readonly config: RequiredNested; constructor(config: SlidingWindowMemoryInput) { @@ -41,7 +41,7 @@ export class SlidingMemory extends BaseMemory { ...config, handlers: { removalSelector: - config.handlers?.removalSelector ?? ((messages: BaseMessage[]) => [messages[0]]), + config.handlers?.removalSelector ?? ((messages: Message[]) => [messages[0]]), }, }; } @@ -51,7 +51,7 @@ export class SlidingMemory extends BaseMemory { this.register(aliases); } - async add(message: BaseMessage, index?: number) { + async add(message: Message, index?: number) { const { size, handlers } = this.config; const isOverflow = () => this.messages.length + 1 > size; @@ -83,7 +83,7 @@ export class SlidingMemory extends BaseMemory { this.messages.splice(index, 0, message); } - async delete(message: BaseMessage) { + async delete(message: Message) { return removeFromArray(this.messages, message); } diff --git a/src/memory/summarizeMemory.ts b/src/memory/summarizeMemory.ts index c47a0c90..0bd9e974 100644 --- a/src/memory/summarizeMemory.ts +++ b/src/memory/summarizeMemory.ts @@ -14,15 +14,15 @@ * limitations under the License. */ -import { BaseMessage, Role } from "@/llms/primitives/message.js"; +import { AssistantMessage, Message, SystemMessage } from "@/backend/message.js"; import { BaseMemory } from "@/memory/base.js"; import { PromptTemplate } from "@/template.js"; import { shallowCopy } from "@/serializer/utils.js"; import { z } from "zod"; -import { ChatLLM, ChatLLMOutput } from "@/llms/chat.js"; +import { ChatModel } from "@/backend/chat.js"; export interface SummarizeMemoryInput { - llm: ChatLLM; + llm: ChatModel; template?: typeof SummarizeMemoryTemplate; } @@ -51,42 +51,35 @@ export class SummarizeMemory extends BaseMemory { this.register(); } - get messages(): BaseMessage[] { + get messages(): Message[] { const currentSummary = this.summary; if (!currentSummary) { return []; } - return [ - BaseMessage.of({ - role: Role.ASSISTANT, - text: currentSummary, - }), - ]; + return [new AssistantMessage(currentSummary)]; } // eslint-disable-next-line unused-imports/no-unused-vars - async delete(message: BaseMessage) { + async delete(message: Message) { return false; } - async add(message: BaseMessage, _index?: number) { - const response = await this.llm.generate([ - BaseMessage.of({ - role: Role.SYSTEM, - text: this.template.render({ - summary: this.summary, - }), - }), - BaseMessage.of({ - role: Role.ASSISTANT, - text: `New lines of conversation: + async add(message: Message, _index?: number) { + const response = await this.llm.create({ + messages: [ + new SystemMessage( + this.template.render({ + summary: this.summary, + }), + ), + new AssistantMessage(`New lines of conversation: ${message.role}: ${message.text} New summary: -`, - }), - ]); +`), + ], + }); this.summary = response.getTextContent(); } diff --git a/src/memory/tokenMemory.test.ts b/src/memory/tokenMemory.test.ts index 0635eb5a..7b2e9f0a 100644 --- a/src/memory/tokenMemory.test.ts +++ b/src/memory/tokenMemory.test.ts @@ -15,10 +15,9 @@ */ import { TokenMemory } from "@/memory/tokenMemory.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import * as R from "remeda"; +import { Message, UserMessage } from "@/backend/message.js"; import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { OllamaChatLLM } from "@/adapters/ollama/chat.js"; +import { sum } from "remeda"; describe("Token Memory", () => { const getInstance = (config: { @@ -27,21 +26,13 @@ describe("Token Memory", () => { syncThreshold: number; maxTokens: number; }) => { - const llm = new OllamaChatLLM(); - - const estimateLLM = (msg: BaseMessage) => Math.ceil(msg.text.length * config.llmFactor); - const estimateLocal = (msg: BaseMessage) => Math.ceil(msg.text.length * config.localFactor); - - vi.spyOn(llm, "tokenize").mockImplementation(async (messages: BaseMessage[]) => ({ - tokensCount: R.sum(messages.map(estimateLLM)), - })); - return new TokenMemory({ - llm, maxTokens: config.maxTokens, syncThreshold: config.syncThreshold, handlers: { - estimate: estimateLocal, + estimate: (msg) => Math.ceil(msg.text.length * config.localFactor), + tokenize: async (msgs) => + sum(msgs.map((msg) => Math.ceil(msg.text.length * config.llmFactor))), }, }); }; @@ -54,10 +45,10 @@ describe("Token Memory", () => { syncThreshold: 0.5, }); await instance.addMany([ - BaseMessage.of({ role: Role.USER, text: "A" }), - BaseMessage.of({ role: Role.USER, text: "B" }), - BaseMessage.of({ role: Role.USER, text: "C" }), - BaseMessage.of({ role: Role.USER, text: "D" }), + new UserMessage("A"), + new UserMessage("B"), + new UserMessage("C"), + new UserMessage("D"), ]); expect(instance.stats()).toMatchObject({ isDirty: false, @@ -79,12 +70,12 @@ describe("Token Memory", () => { messagesCount: 0, }); await instance.addMany([ - BaseMessage.of({ role: Role.USER, text: "A" }), - BaseMessage.of({ role: Role.USER, text: "B" }), - BaseMessage.of({ role: Role.USER, text: "C" }), - BaseMessage.of({ role: Role.USER, text: "D" }), - BaseMessage.of({ role: Role.USER, text: "E" }), - BaseMessage.of({ role: Role.USER, text: "F" }), + new UserMessage("A"), + new UserMessage("B"), + new UserMessage("C"), + new UserMessage("D"), + new UserMessage("E"), + new UserMessage("F"), ]); expect(instance.stats()).toMatchObject({ isDirty: true, @@ -107,13 +98,13 @@ describe("Token Memory", () => { syncThreshold: 1, }); await instance.add( - BaseMessage.of({ + Message.of({ text: "Hello!", - role: Role.USER, + role: "user", }), ); - const serialized = instance.serialize(); - const deserialized = TokenMemory.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await TokenMemory.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/src/memory/tokenMemory.ts b/src/memory/tokenMemory.ts index 183c826d..fd9b5f5f 100644 --- a/src/memory/tokenMemory.ts +++ b/src/memory/tokenMemory.ts @@ -14,22 +14,25 @@ * limitations under the License. */ -import { BaseMessage } from "@/llms/primitives/message.js"; import { BaseMemory, MemoryFatalError } from "@/memory/base.js"; -import { ChatLLM, ChatLLMOutput } from "@/llms/chat.js"; import * as R from "remeda"; import { shallowCopy } from "@/serializer/utils.js"; import { removeFromArray } from "@/internals/helpers/array.js"; -import { sum } from "remeda"; +import { map, sum } from "remeda"; import { ensureRange } from "@/internals/helpers/number.js"; +import { Message } from "@/backend/message.js"; export interface Handlers { - estimate: (messages: BaseMessage) => number; - removalSelector: (messages: BaseMessage[]) => BaseMessage; + estimate: (messages: Message) => number; + tokenize: (messages: Message[]) => Promise; + removalSelector: (messages: Message[]) => Message; } +const simpleEstimate: Handlers["estimate"] = (msg: Message) => Math.ceil(msg.text.length / 4); +const simpleTokenize: Handlers["tokenize"] = async (msgs: Message[]) => + sum(map(msgs, simpleEstimate)); // TODO + export interface TokenMemoryInput { - llm: ChatLLM; maxTokens?: number; syncThreshold?: number; capacityThreshold?: number; @@ -42,18 +45,16 @@ interface TokenByMessage { } export class TokenMemory extends BaseMemory { - public readonly messages: BaseMessage[] = []; + public readonly messages: Message[] = []; - protected llm: ChatLLM; protected threshold; protected syncThreshold; protected maxTokens: number | null = null; - protected tokensByMessage = new WeakMap(); + protected tokensByMessage = new WeakMap(); public readonly handlers: Handlers; - constructor(config: TokenMemoryInput) { + constructor(config: TokenMemoryInput = {}) { super(); - this.llm = config.llm; this.maxTokens = config.maxTokens ?? null; this.threshold = config.capacityThreshold ?? 0.75; this.syncThreshold = config.syncThreshold ?? 0.25; @@ -61,6 +62,7 @@ export class TokenMemory extends BaseMemory { ...config?.handlers, estimate: config?.handlers?.estimate || ((msg) => Math.ceil((msg.role.length + msg.text.length) / 4)), + tokenize: config?.handlers?.tokenize || simpleTokenize, removalSelector: config.handlers?.removalSelector || ((messages) => messages[0]), }; if (!R.clamp({ min: 0, max: 1 })(this.threshold)) { @@ -80,10 +82,10 @@ export class TokenMemory extends BaseMemory { return this.messages.some((msg) => this.tokensByMessage.get(msg)?.dirty !== false); } - async add(message: BaseMessage, index?: number) { + async add(message: Message, index?: number) { if (this.maxTokens === null) { - const meta = await this.llm.meta(); - this.maxTokens = Math.ceil((meta.tokenLimit ?? Infinity) * this.threshold); + // TODO: improve + this.maxTokens = 128_000; } const meta = this.tokensByMessage.has(message) @@ -115,7 +117,7 @@ export class TokenMemory extends BaseMemory { } } - async delete(message: BaseMessage) { + async delete(message: Message) { return removeFromArray(this.messages, message); } @@ -124,8 +126,8 @@ export class TokenMemory extends BaseMemory { this.messages.map(async (msg) => { const cache = this.tokensByMessage.get(msg); if (cache?.dirty !== false) { - const result = await this.llm.tokenize([msg]); - this.tokensByMessage.set(msg, { tokensCount: result.tokensCount, dirty: false }); + const tokensCount = await this.handlers.tokenize([msg]); + this.tokensByMessage.set(msg, { tokensCount, dirty: false }); } return msg; }), @@ -153,15 +155,14 @@ export class TokenMemory extends BaseMemory { createSnapshot() { return { - llm: this.llm, - maxTokens: this.maxTokens, threshold: this.threshold, syncThreshold: this.syncThreshold, messages: shallowCopy(this.messages), handlers: shallowCopy(this.handlers), + maxTokens: this.maxTokens, tokensByMessage: this.messages .map((message) => [message, this.tokensByMessage.get(message)]) - .filter(([_, value]) => value !== undefined) as [BaseMessage, number][], + .filter(([_, value]) => value !== undefined) as [Message, number][], }; } diff --git a/src/memory/unconstrainedMemory.test.ts b/src/memory/unconstrainedMemory.test.ts index 0f2664ac..1c0cabd9 100644 --- a/src/memory/unconstrainedMemory.test.ts +++ b/src/memory/unconstrainedMemory.test.ts @@ -15,10 +15,12 @@ */ import { UnconstrainedMemory } from "@/memory/unconstrainedMemory.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; +import { Message } from "@/backend/message.js"; describe("Unconstrained Memory", () => { - const createMessage = (i: number) => BaseMessage.of({ role: "user", text: `${i}` }); + const date = new Date(); + const createMessage = (i: number) => + Message.of({ role: "user", text: `${i}`, meta: { createdAt: new Date(date) } }); it("Splices", async () => { const memory = new UnconstrainedMemory(); diff --git a/src/memory/unconstrainedMemory.ts b/src/memory/unconstrainedMemory.ts index 888cab50..09d65f31 100644 --- a/src/memory/unconstrainedMemory.ts +++ b/src/memory/unconstrainedMemory.ts @@ -14,25 +14,25 @@ * limitations under the License. */ -import { BaseMessage } from "@/llms/primitives/message.js"; import { BaseMemory } from "@/memory/base.js"; import { shallowCopy } from "@/serializer/utils.js"; import { removeFromArray } from "@/internals/helpers/array.js"; import { ensureRange } from "@/internals/helpers/number.js"; +import { Message } from "@/backend/message.js"; export class UnconstrainedMemory extends BaseMemory { - public messages: BaseMessage[] = []; + public messages: Message[] = []; static { this.register(); } - async add(message: BaseMessage, index?: number) { + async add(message: Message, index?: number) { index = ensureRange(index ?? this.messages.length, { min: 0, max: this.messages.length }); this.messages.splice(index, 0, message); } - async delete(message: BaseMessage) { + async delete(message: Message) { return removeFromArray(this.messages, message); } diff --git a/src/agents/parsers/errors.ts b/src/parsers/errors.ts similarity index 100% rename from src/agents/parsers/errors.ts rename to src/parsers/errors.ts diff --git a/src/agents/parsers/field.test.ts b/src/parsers/field.test.ts similarity index 97% rename from src/agents/parsers/field.test.ts rename to src/parsers/field.test.ts index 87af4594..54131b5d 100644 --- a/src/agents/parsers/field.test.ts +++ b/src/parsers/field.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { JSONParserField, ZodParserField } from "@/agents/parsers/field.js"; +import { JSONParserField, ZodParserField } from "@/parsers/field.js"; import { z } from "zod"; import { splitString } from "@/internals/helpers/string.js"; diff --git a/src/agents/parsers/field.ts b/src/parsers/field.ts similarity index 100% rename from src/agents/parsers/field.ts rename to src/parsers/field.ts diff --git a/src/agents/parsers/linePrefix.test.ts b/src/parsers/linePrefix.test.ts similarity index 98% rename from src/agents/parsers/linePrefix.test.ts rename to src/parsers/linePrefix.test.ts index e9d5c1b7..564a6d85 100644 --- a/src/agents/parsers/linePrefix.test.ts +++ b/src/parsers/linePrefix.test.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { LinePrefixParser, LinePrefixParserError } from "@/agents/parsers/linePrefix.js"; +import { LinePrefixParser, LinePrefixParserError } from "@/parsers/linePrefix.js"; import { z } from "zod"; -import { JSONParserField, ZodParserField } from "@/agents/parsers/field.js"; +import { JSONParserField, ZodParserField } from "@/parsers/field.js"; import { splitString } from "@/internals/helpers/string.js"; import { ValueError } from "@/errors.js"; diff --git a/src/agents/parsers/linePrefix.ts b/src/parsers/linePrefix.ts similarity index 98% rename from src/agents/parsers/linePrefix.ts rename to src/parsers/linePrefix.ts index 9234cddb..146e86b6 100644 --- a/src/agents/parsers/linePrefix.ts +++ b/src/parsers/linePrefix.ts @@ -20,12 +20,12 @@ import { ValueError } from "@/errors.js"; import { Serializable } from "@/internals/serializable.js"; import { shallowCopy } from "@/serializer/utils.js"; import { Cache } from "@/cache/decoratorCache.js"; -import { ParserField } from "@/agents/parsers/field.js"; +import { ParserField } from "@/parsers/field.js"; import { Callback, InferCallbackValue } from "@/emitter/types.js"; import { ZodError } from "zod"; import { ValueOf } from "@/internals/types.js"; -import { LinePrefixParserError } from "@/agents/parsers/errors.js"; -export * from "@/agents/parsers/errors.js"; +import { LinePrefixParserError } from "@/parsers/errors.js"; +export * from "@/parsers/errors.js"; export interface ParserNode> { prefix: string; @@ -407,7 +407,7 @@ export class LinePrefixParser>> extends Serializabl } loadSnapshot(snapshot: ReturnType) { - return Object.assign(this, snapshot); + Object.assign(this, snapshot); } } diff --git a/src/serializer/serializer.test.ts b/src/serializer/serializer.test.ts index 5b63580d..a698c43c 100644 --- a/src/serializer/serializer.test.ts +++ b/src/serializer/serializer.test.ts @@ -18,7 +18,7 @@ import { Serializer } from "@/serializer/serializer.js"; import * as R from "remeda"; import { FrameworkError } from "@/errors.js"; import { AgentError } from "@/agents/base.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; +import { Message, UserMessage } from "@/backend/message.js"; import { beforeEach, expect, vi } from "vitest"; import { verifyDeserialization } from "@tests/e2e/utils.js"; import { SerializerError } from "@/serializer/error.js"; @@ -70,9 +70,9 @@ describe("Serializer", () => { { a: { b: { c: { d: { e: { f: { g: { e: { h: { value: 1, name: "X" } } } } } } } } }, }, - ])("Handles basics '%s'", (value) => { - const json = Serializer.serialize(value); - const deserialized = Serializer.deserialize(json); + ])("Handles basics '%s'", async (value) => { + const json = await Serializer.serialize(value); + const deserialized = await Serializer.deserialize(json); if (R.isFunction(value)) { expect(String(deserialized)).toStrictEqual(String(value)); @@ -81,7 +81,7 @@ describe("Serializer", () => { } }); - it("Handles various function definitions", () => { + it("Handles various function definitions", async () => { const inputs = { value: 10, a(input: unknown) { @@ -129,8 +129,8 @@ describe("Serializer", () => { y: (a: string) => (b: string) => a + b, } as const; - const serialized = Serializer.serialize(inputs); - const deserialized: typeof inputs = Serializer.deserialize(serialized); + const serialized = await Serializer.serialize(inputs); + const deserialized: typeof inputs = await Serializer.deserialize(serialized); expect(deserialized).toMatchInlineSnapshot(` { "a": [Function], @@ -171,27 +171,27 @@ describe("Serializer", () => { } }); - it("Handles circular dependencies", () => { + it("Handles circular dependencies", async () => { const a = { name: "A" }; const b = { name: "B" }; Object.assign(a, { b }); Object.assign(b, { a }); const input = { a, b }; - const json = Serializer.serialize(input); - const deserialized = Serializer.deserialize(json); + const json = await Serializer.serialize(input); + const deserialized = await Serializer.deserialize(json); expect(deserialized).toStrictEqual(input); }); - it("Preserves references", () => { + it("Preserves references", async () => { const a = { name: "A" }; const b = { name: "B", a }; const c = { name: "C", a, b }; const d = { name: "C", a, b, c }; const input = { a, b, c, d }; - const json = Serializer.serialize(input); - const deserialized = Serializer.deserialize(json); + const json = await Serializer.serialize(input); + const deserialized = await Serializer.deserialize(json); expect([b.a, c.a, d.a].every((v) => v === a)).toBeTruthy(); expect([c.b, d.b].every((v) => v === b)).toBeTruthy(); @@ -199,13 +199,13 @@ describe("Serializer", () => { expect(deserialized).toStrictEqual(input); }); - it("Handles self referencing", () => { + it("Handles self referencing", async () => { const a = { name: "A" }; Object.assign(a, { a, b: a, c: a }); const input = { a }; - const json = Serializer.serialize(input); - const deserialized = Serializer.deserialize(json); + const json = await Serializer.serialize(input); + const deserialized = await Serializer.deserialize(json); expect(deserialized).toStrictEqual(input); expect(deserialized.a === deserialized.a.a).toBeTruthy(); @@ -219,12 +219,12 @@ describe("Serializer", () => { __root: { message: { __value: { - role: "system", - text: "a", + role: "user", + content: [{ type: "text", text: "a" }], meta: { __value: {}, __serializer: true, __class: "Object", __ref: "2" }, }, __serializer: true, - __class: "BaseMessage", + __class: "UserMessage", __ref: "1", }, }, @@ -232,39 +232,43 @@ describe("Serializer", () => { beforeEach(() => { vi.unstubAllEnvs(); - Serializer.deregister(BaseMessage); + Serializer.deregister(UserMessage); }); - it("Automatically registers serializable classes", () => { - expect(Serializer.hasFactory("BaseMessage")).toBe(false); - const message = BaseMessage.of({ role: "system", text: "a", meta: {} }); + it("Automatically registers serializable classes", async () => { + expect(Serializer.hasFactory("UserMessage")).toBe(false); + const message = Message.of({ + role: "user", + text: "a", + meta: { createdAt: new Date("2025-01-01") }, + }); const input = { message }; - const json = Serializer.serialize(input); - const deserialized = Serializer.deserialize(json); + const json = await Serializer.serialize(input); + const deserialized = await Serializer.deserialize(json); expect(deserialized).toStrictEqual(input); }); it("Allows to re-register same class", () => { - expect(Serializer.hasFactory("BaseMessage")).toBe(false); - Serializer.registerSerializable(BaseMessage); - expect(Serializer.hasFactory("BaseMessage")).toBe(true); - Serializer.registerSerializable(BaseMessage); + expect(Serializer.hasFactory("UserMessage")).toBe(false); + Serializer.registerSerializable(UserMessage); + expect(Serializer.hasFactory("UserMessage")).toBe(true); + Serializer.registerSerializable(UserMessage); }); - it("Throws when required class is not present", () => { - expect(() => Serializer.deserialize(json)).toThrowError(SerializerError); + it("Throws when required class is not present", async () => { + await expect(Serializer.deserialize(json)).rejects.toThrowError(SerializerError); }); - it("Parses when class is registered", () => { - Serializer.registerSerializable(BaseMessage); - expect(() => Serializer.deserialize(json)).not.toThrowError(); + it("Parses when class is registered", async () => { + Serializer.registerSerializable(UserMessage); + await expect(Serializer.deserialize(json)).resolves.toBeTruthy(); }); - it("Parses when class is passed as external parameter.", () => { - expect(() => Serializer.deserialize(json, [BaseMessage])).not.toThrowError(); + it("Parses when class is passed as external parameter.", async () => { + await expect(Serializer.deserialize(json, [UserMessage])).resolves.toBeTruthy(); }); - it("Handles bounded functions", () => { + it("Handles bounded functions", async () => { const a = 1; const b = 2; @@ -283,13 +287,13 @@ describe("Serializer", () => { ); for (let i = 0; i < 5; ++i) { - const serialized = Serializer.serialize(fn); - fn = Serializer.deserialize(serialized); + const serialized = await Serializer.serialize(fn); + fn = await Serializer.deserialize(serialized); expect(fn(3)).toBe(6); } }); - it("Handles self factory references", () => { + it("Handles self factory references", async () => { class A { static secret = 42; } @@ -305,10 +309,12 @@ describe("Serializer", () => { toPlain: (instance) => ({ target: instance.target }), fromPlain: (plain) => new B(plain.target), }); - expect(Serializer.deserialize(Serializer.serialize(new B(A))).target.secret).toBe(42); + expect( + (await Serializer.deserialize(await Serializer.serialize(new B(A)))).target.secret, + ).toBe(42); }); - it("Handles aliases", () => { + it("Handles aliases", async () => { const Name = { new: "MyClass", old: "MyOldClass", @@ -343,10 +349,10 @@ describe("Serializer", () => { [], ); - const [a, b] = [ + const [a, b] = await Promise.all([ Serializer.deserialize(getSerialized(Name.new)), Serializer.deserialize(getSerialized(Name.old)), - ]; + ]); verifyDeserialization(a, b); }); }); diff --git a/src/serializer/serializer.ts b/src/serializer/serializer.ts index ea92e058..cd7199fa 100644 --- a/src/serializer/serializer.ts +++ b/src/serializer/serializer.ts @@ -50,9 +50,9 @@ import { hasMinLength } from "@/internals/helpers/array.js"; export interface SerializeFactory { ref: ClassConstructor | NamedFunction; createEmpty?: () => A; - updateInstance?: (instance: A, update: A) => void; - toPlain: (value: A) => B; - fromPlain: (value: B) => A; + updateInstance?: (instance: A, update: A) => void | Promise; + toPlain: (value: A) => B | Promise; + fromPlain: (value: B, ref: ClassConstructor | NamedFunction) => A | Promise; } export class Serializer { @@ -154,7 +154,7 @@ export class Serializer { return Serializer.factories.has(clsName); } - static serialize(rawData: T): string { + static async serialize(rawData: T): Promise { const output = Serializer._createOutputBuilder(); const getRefId = (() => { let id = 0; @@ -187,7 +187,7 @@ export class Serializer { }; })(); - const toSerializable = (rawValue: unknown): SerializerNode | unknown => { + const toSerializable = async (rawValue: unknown): Promise => { if (seen.has(rawValue)) { return seen.get(rawValue); } @@ -202,7 +202,7 @@ export class Serializer { return rawValue; } - const snapshot = isSelfRef ? SerializerSelfRefIdentifier : factory.toPlain(rawValue); + const snapshot = isSelfRef ? SerializerSelfRefIdentifier : await factory.toPlain(rawValue); assertValidSnapshot(snapshot, factory); const result: SerializerNode = { @@ -214,7 +214,7 @@ export class Serializer { seen.set(rawValue, result); for (const node of traverseWithUpdate(snapshot)) { - const newValue = toSerializable(node.value); + const newValue = await toSerializable(node.value); if (newValue !== node.value) { node.update(newValue); } @@ -223,24 +223,24 @@ export class Serializer { }; const root: RootNode = { __version: Version, __root: rawData }; - traverseObject(root, ({ value, path }) => { - const content = toSerializable(value); + await traverseObject(root, async ({ value, path }) => { + const content = await toSerializable(value); output.update(path, content); }); return output.toJSON(); } /** @internal */ - static deserializeWithMeta( + static async deserializeWithMeta( raw: string, extraClasses?: SerializableClass[], - ): RootNode { + ): Promise> { extraClasses?.forEach((ref) => Serializer.registerSerializable(ref)); const output = Serializer._createOutputBuilder>(); const instances = new Map(); - const toDeserialize = (contentRaw: unknown) => { + const toDeserialize = async (contentRaw: unknown) => { if (isSerializerNode(contentRaw)) { const clsName = String(contentRaw.__class); const factory = Serializer.getFactory(clsName); @@ -262,9 +262,9 @@ export class Serializer { return data; } - const traverseNested = () => { + const traverseNested = async () => { for (const node of traverseWithUpdate(rawData)) { - const newValue = toDeserialize(node.value); + const newValue = await toDeserialize(node.value); if (newValue !== node.value) { node.update(newValue); } @@ -274,9 +274,10 @@ export class Serializer { // Handle circular dependencies const placeholder = new RefPlaceholder(contentRaw, factory); instances.set(contentRaw.__ref!, placeholder); - traverseNested(); - instances.set(contentRaw.__ref!, placeholder.final); - return placeholder.final; + await traverseNested(); + const final = await placeholder.final(); + instances.set(contentRaw.__ref!, final); + return final; } return contentRaw; }; @@ -286,18 +287,21 @@ export class Serializer { throw new SerializerError("Provided data cannot be deserialized due to malformed format!"); } - traverseObject( + await traverseObject( root, - ({ value: contentRaw, path }) => { - output.update(path, toDeserialize(contentRaw)); + async ({ value: contentRaw, path }) => { + output.update(path, await toDeserialize(contentRaw)); }, (_obj) => isSerializerNode(_obj), ); return output.get(); } - static deserialize(raw: string, extraClasses?: SerializableClass[]): T { - const response = Serializer.deserializeWithMeta(raw, extraClasses); + static async deserialize( + raw: string, + extraClasses?: SerializableClass[], + ): Promise { + const response = await Serializer.deserializeWithMeta(raw, extraClasses); return response.__root; } @@ -345,7 +349,7 @@ Serializer.register(Task, { return task; }, createEmpty: () => new Task(), - updateInstance: (instance, value) => { + updateInstance: async (instance, value) => { instance.resolve(value); }, }); diff --git a/src/serializer/utils.ts b/src/serializer/utils.ts index d4d9e273..a309ecbc 100644 --- a/src/serializer/utils.ts +++ b/src/serializer/utils.ts @@ -18,13 +18,13 @@ import * as R from "remeda"; import { SafeWeakSet } from "@/internals/helpers/weakRef.js"; import { AnyConstructable, AnyFn, ClassConstructor, NamedFunction } from "@/internals/types.js"; import { SerializeFactory } from "@/serializer/serializer.js"; -import { Cache } from "@/cache/decoratorCache.js"; import { getProp, hasProp } from "@/internals/helpers/object.js"; import { isDirectInstanceOf } from "@/internals/helpers/prototype.js"; import { SerializerError } from "@/serializer/error.js"; export const SerializerSelfRefIdentifier = "__self_ref"; export const SerializerRefIdentifier = "__ref"; +export class ClassConstructorPlaceholder {} export class RefPlaceholder { private static EmptyPlaceholder = Symbol(); private partialResult: T = RefPlaceholder.EmptyPlaceholder as T; @@ -48,14 +48,13 @@ export class RefPlaceholder { return this.partialResult; } - @Cache() - get final() { - const finalInstance = this.factory.fromPlain(this.node.__value); + async final() { + const finalInstance = await this.factory.fromPlain(this.node.__value, this.factory.ref); if (this.partialResult === RefPlaceholder.EmptyPlaceholder) { return finalInstance; } - this.factory.updateInstance!(this.partialResult, finalInstance); + await this.factory.updateInstance!(this.partialResult, finalInstance); return this.partialResult; } } @@ -127,15 +126,15 @@ export function primitiveToSerializableClass(value: unknown) { return ClassByValueType[type]; } -type TraverseObjectFn = (el: { key: string; path: readonly string[]; value: any }) => void; -export function traverseObject( +type TraverseObjectFn = (el: { key: string; path: readonly string[]; value: any }) => Promise; +export async function traverseObject( obj: unknown, handler: TraverseObjectFn, stopFn?: (_obj: unknown) => boolean, ) { const seen = new SafeWeakSet(); - const traverse = (_obj: unknown, path: readonly string[] = []) => { + const traverse = async (_obj: unknown, path: readonly string[] = []) => { if (!R.isPlainObject(_obj) || seen.has(_obj)) { return; } @@ -146,9 +145,8 @@ export function traverseObject( } for (const [key, value] of Object.entries(_obj)) { - traverse(value, path.concat(key)); - - handler({ + await traverse(value, path.concat(key)); + await handler({ key, value, path: path.concat(key), @@ -156,7 +154,7 @@ export function traverseObject( } }; - return traverse(obj, []); + return await traverse(obj, []); } export function isSerializationRequired(factory: ClassConstructor | NamedFunction) { diff --git a/src/template.test.ts b/src/template.test.ts index e80161f5..0f51ac78 100644 --- a/src/template.test.ts +++ b/src/template.test.ts @@ -181,9 +181,9 @@ describe("Prompt Template", () => { }); }; - it("Clones", () => { + it("Clones", async () => { const template = createTemplate(); - const cloned = template.clone(); + const cloned = await template.clone(); expect(cloned).toEqual(template); }); diff --git a/src/tools/base.test.ts b/src/tools/base.test.ts index 9969257d..0015429f 100644 --- a/src/tools/base.test.ts +++ b/src/tools/base.test.ts @@ -571,7 +571,7 @@ describe("Base Tool", () => { `); }); - it("Serializes", () => { + it("Serializes", async () => { const tool = new DynamicTool({ name: toolDef.name, description: toolDef.description, @@ -588,8 +588,8 @@ describe("Base Tool", () => { }, }); - const serialized = tool.serialize(); - const deserialized = DynamicTool.fromSerialized(serialized); + const serialized = await tool.serialize(); + const deserialized = await DynamicTool.fromSerialized(serialized); verifyDeserialization(tool, deserialized); }); }); diff --git a/src/tools/base.ts b/src/tools/base.ts index 90dd0f33..435246e8 100644 --- a/src/tools/base.ts +++ b/src/tools/base.ts @@ -173,15 +173,6 @@ export interface ToolEvents< finish: Callback; } -/** - * @deprecated Use ToolEmitter instead - */ -export type CustomToolEmitter< - A extends Record, - B extends ToolOutput, - C = Record, -> = Emitter & Omit>; - export type ToolEmitter< A extends Record, B extends ToolOutput, diff --git a/src/tools/database/elasticsearch.test.ts b/src/tools/database/elasticsearch.test.ts index c5afa7ce..72f39975 100644 --- a/src/tools/database/elasticsearch.test.ts +++ b/src/tools/database/elasticsearch.test.ts @@ -103,8 +103,8 @@ describe("ElasticSearchTool", () => { Task.resolve(new JSONToolOutput([{ index: "index1", detail: "sample" }])), ); - const serialized = elasticSearchTool.serialize(); - const deserializedTool = ElasticSearchTool.fromSerialized(serialized); + const serialized = await elasticSearchTool.serialize(); + const deserializedTool = await ElasticSearchTool.fromSerialized(serialized); expect(await deserializedTool.cache.get("connection")).toStrictEqual( await elasticSearchTool.cache.get("connection"), diff --git a/src/tools/llm.ts b/src/tools/llm.ts index 90f8eddb..fcc321a3 100644 --- a/src/tools/llm.ts +++ b/src/tools/llm.ts @@ -27,14 +27,14 @@ import { z } from "zod"; import { GetRunContext } from "@/context.js"; import { Emitter } from "@/emitter/emitter.js"; import { PromptTemplate } from "@/template.js"; -import { BaseMessage, Role } from "@/llms/primitives/message.js"; import { getProp } from "@/internals/helpers/object.js"; import type { BaseMemory } from "@/memory/base.js"; -import type { AnyChatLLM } from "@/llms/chat.js"; import { toCamelCase } from "remeda"; +import { Role, SystemMessage, UserMessage } from "@/backend/message.js"; +import { ChatModel } from "@/backend/chat.js"; export interface LLMToolInput extends BaseToolOptions { - llm: AnyChatLLM; + llm: ChatModel; name?: string; description?: string; template?: typeof LLMTool.template; @@ -85,21 +85,21 @@ The Task: {{task}}`, } const template = this.options?.template ?? LLMTool.template; - const output = await this.input.llm.generate([ - BaseMessage.of({ - role: Role.SYSTEM, - text: template.render({ - task: input.task, - }), - }), - ...memory.messages.filter((msg) => msg.role !== Role.SYSTEM), - BaseMessage.of({ - role: Role.USER, - text: template.render({ - task: input.task, - }), - }), - ]); + const output = await this.input.llm.create({ + messages: [ + new SystemMessage( + template.render({ + task: input.task, + }), + ), + ...memory.messages.filter((msg) => msg.role !== Role.SYSTEM), + new UserMessage( + template.render({ + task: input.task, + }), + ), + ], + }); return new StringToolOutput(output.getTextContent()); } diff --git a/src/tools/openapi.test.ts b/src/tools/openapi.test.ts index 8d6e67c4..c4868ecf 100644 --- a/src/tools/openapi.test.ts +++ b/src/tools/openapi.test.ts @@ -71,11 +71,11 @@ describe("OpenAPI Tool", () => { vi.clearAllTimers(); }); - it("Serializes", () => { + it("Serializes", async () => { const tool = new OpenAPITool({ openApiSchema }); - const serialized = tool.serialize(); - const deserialized = OpenAPITool.fromSerialized(serialized); + const serialized = await tool.serialize(); + const deserialized = await OpenAPITool.fromSerialized(serialized); verifyDeserialization(tool, deserialized); }); }); diff --git a/src/tools/python/python.test.ts b/src/tools/python/python.test.ts index 2ecb727d..64c664d9 100644 --- a/src/tools/python/python.test.ts +++ b/src/tools/python/python.test.ts @@ -68,8 +68,8 @@ describe("PythonTool", () => { it("serializes", async () => { const tool = getPythonTool(); - const serialized = tool.serialize(); - const deserializedTool = PythonTool.fromSerialized(serialized); + const serialized = await tool.serialize(); + const deserializedTool = await PythonTool.fromSerialized(serialized); verifyDeserialization(tool, deserializedTool); }); }); diff --git a/src/tools/python/python.ts b/src/tools/python/python.ts index 84e12c43..27707723 100644 --- a/src/tools/python/python.ts +++ b/src/tools/python/python.ts @@ -23,8 +23,6 @@ import { ToolInput, } from "@/tools/base.js"; import { z } from "zod"; -import { BaseLLMOutput } from "@/llms/base.js"; -import { LLM } from "@/llms/llm.js"; import { PromptTemplate } from "@/template.js"; import { filter, isIncludedIn, map, pipe, unique, uniqueBy } from "remeda"; import { PythonFile, PythonStorage } from "@/tools/python/storage.js"; @@ -35,6 +33,8 @@ import { RunContext } from "@/context.js"; import { hasMinLength } from "@/internals/helpers/array.js"; import { Emitter } from "@/emitter/emitter.js"; import { shallowCopy } from "@/serializer/utils.js"; +import { ChatModel } from "@/backend/chat.js"; +import { UserMessage } from "@/backend/message.js"; export interface CodeInterpreterOptions { url: string; @@ -44,7 +44,7 @@ export interface CodeInterpreterOptions { export interface PythonToolOptions extends BaseToolOptions { codeInterpreter: CodeInterpreterOptions; preprocess?: { - llm: LLM; + llm: ChatModel; promptTemplate: PromptTemplate.infer<{ input: string }>; }; storage: PythonStorage; @@ -135,9 +135,9 @@ export class PythonTool extends Tool { const getSourceCode = async () => { if (this.preprocess) { const { llm, promptTemplate } = this.preprocess; - const response = await llm.generate(promptTemplate.render({ input: input.code }), { - signal: run.signal, - stream: false, + const response = await llm.create({ + messages: [new UserMessage(promptTemplate.render({ input: input.code }))], + abortSignal: run.signal, }); return response.getTextContent().trim(); } diff --git a/src/tools/search/duckDuckGoSearch.test.ts b/src/tools/search/duckDuckGoSearch.test.ts index 5b3a7ab5..501441c1 100644 --- a/src/tools/search/duckDuckGoSearch.test.ts +++ b/src/tools/search/duckDuckGoSearch.test.ts @@ -113,8 +113,8 @@ describe("DuckDuckGoSearch Tool", () => { ), ); await tool.cache!.set("B", Task.resolve(new DuckDuckGoSearchToolOutput([]))); - const serialized = tool.serialize(); - const deserialized = DuckDuckGoSearchTool.fromSerialized(serialized); + const serialized = await tool.serialize(); + const deserialized = await DuckDuckGoSearchTool.fromSerialized(serialized); expect(await tool.cache.get("A")).toStrictEqual(await deserialized.cache.get("A")); verifyDeserialization(tool, deserialized); }); diff --git a/src/tools/search/googleSearch.test.ts b/src/tools/search/googleSearch.test.ts index 5b5fe18a..a6460530 100644 --- a/src/tools/search/googleSearch.test.ts +++ b/src/tools/search/googleSearch.test.ts @@ -131,8 +131,8 @@ describe("GoogleCustomSearch Tool", () => { ); await tool.cache!.set("B", Task.resolve(new GoogleSearchToolOutput([]))); - const serialized = tool.serialize(); - const deserialized = GoogleSearchTool.fromSerialized(serialized); + const serialized = await tool.serialize(); + const deserialized = await GoogleSearchTool.fromSerialized(serialized); expect(await tool.cache.get("A")).toStrictEqual(await deserialized.cache.get("A")); verifyDeserialization(tool, deserialized); }); diff --git a/src/tools/search/wikipedia.test.ts b/src/tools/search/wikipedia.test.ts index 79c71f1c..ade694b4 100644 --- a/src/tools/search/wikipedia.test.ts +++ b/src/tools/search/wikipedia.test.ts @@ -85,8 +85,8 @@ describe("Wikipedia", () => { }, }); await instance.run({ query: "Prague" }); - const serialized = instance.serialize(); - const deserialized = WikipediaTool.fromSerialized(serialized); + const serialized = await instance.serialize(); + const deserialized = await WikipediaTool.fromSerialized(serialized); verifyDeserialization(instance, deserialized); }); }); diff --git a/tests/e2e/adapters/bedrock/chat.test.ts b/tests/e2e/adapters/bedrock/chat.test.ts deleted file mode 100644 index 88fe53b7..00000000 --- a/tests/e2e/adapters/bedrock/chat.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BedrockChatLLM } from "@/adapters/bedrock/chat.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; - -describe.runIf([process.env.AWS_REGION].every((env) => Boolean(env)))("Bedrock Chat LLM", () => { - it("Embeds", async () => { - const llm = new BedrockChatLLM({ - region: process.env.AWS_REGION, - modelId: "amazon.titan-embed-text-v1", - }); - - const response = await llm.embed([ - [BaseMessage.of({ role: "user", text: `Hello world!` })], - [BaseMessage.of({ role: "user", text: `Hello family!` })], - ]); - expect(response.embeddings.length).toBe(2); - expect(response.embeddings[0].length).toBe(512); - expect(response.embeddings[1].length).toBe(512); - }); -}); diff --git a/tests/e2e/adapters/groq/chat.test.ts b/tests/e2e/adapters/groq/chat.test.ts deleted file mode 100644 index 724d2cb6..00000000 --- a/tests/e2e/adapters/groq/chat.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { GroqChatLLM } from "@/adapters/groq/chat.js"; - -const apiKey = process.env.GROQ_API_KEY; - -describe.runIf(Boolean(apiKey))("Adapter Groq Chat LLM", () => { - const createChatLLM = (modelId = "llama3-8b-8192") => { - const model = new GroqChatLLM({ - modelId, - parameters: { - temperature: 0, - max_tokens: 1024, - top_p: 1, - }, - }); - return new GroqChatLLM(model); - }; - - it("Generates", async () => { - const conversation = [ - BaseMessage.of({ - role: Role.SYSTEM, - text: `You are a helpful and respectful and honest assistant. Your answer should be short and concise.`, - }), - ]; - const llm = createChatLLM(); - - for (const { question, answer } of [ - { - question: `What is the coldest continent? Response must be a single word without any punctuation.`, - answer: "Antarctica", - }, - { - question: - "What is the most common typical animal that lives there? Response must be a single word without any punctuation.", - answer: "Penguin", - }, - ]) { - conversation.push( - BaseMessage.of({ - role: Role.USER, - text: question, - }), - ); - const response = await llm.generate(conversation); - expect(response.messages.length).toBeGreaterThan(0); - expect(response.getTextContent()).toBe(answer); - conversation.push( - BaseMessage.of({ - role: Role.ASSISTANT, - text: response.getTextContent(), - }), - ); - } - }); - - // Embedding model does not available right now - it.skip("Embeds", async () => { - const llm = createChatLLM("nomic-embed-text-v1_5"); - const response = await llm.embed([ - [BaseMessage.of({ role: "user", text: `Hello world!` })], - [BaseMessage.of({ role: "user", text: `Hello family!` })], - ]); - expect(response.embeddings.length).toBe(2); - expect(response.embeddings[0].length).toBe(1024); - expect(response.embeddings[1].length).toBe(1024); - }); -}); diff --git a/tests/e2e/adapters/ibm-vllm/chat.test.ts b/tests/e2e/adapters/ibm-vllm/chat.test.ts deleted file mode 100644 index d7fef3cb..00000000 --- a/tests/e2e/adapters/ibm-vllm/chat.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BaseMessage } from "@/llms/primitives/message.js"; -import { expect } from "vitest"; -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { IBMVllmChatLLM } from "@/adapters/ibm-vllm/chat.js"; - -describe.runIf( - [ - process.env.IBM_VLLM_URL, - process.env.IBM_VLLM_ROOT_CERT, - process.env.IBM_VLLM_PRIVATE_KEY, - process.env.IBM_VLLM_CERT_CHAIN, - ].every((env) => Boolean(env)), -)("IBM Chat vLLM", () => { - const createChatLLM = () => { - return IBMVllmChatLLM.fromPreset("meta-llama/llama-3-1-70b-instruct", { - parameters: { - method: "GREEDY", - stopping: { - min_new_tokens: 5, - max_new_tokens: 50, - }, - }, - }); - }; - - it("Generates", async () => { - const conversation = [ - BaseMessage.of({ - role: "system", - text: `You are a helpful and respectful and honest assistant. Your answer should be short and concise.`, - }), - ]; - const llm = createChatLLM(); - - for (const { question, answer } of [ - { question: `What is the coldest continent?`, answer: "arctica" }, - { question: "What is the most common typical animal that lives there?", answer: "penguin" }, - ]) { - conversation.push( - BaseMessage.of({ - role: "user", - text: question, - }), - ); - const response = await llm.generate(conversation); - - const newMessages = response.messages; - expect(newMessages).toHaveLength(1); - expect(newMessages[0].text.toLowerCase()).toContain(answer.toLowerCase()); - conversation.push(...newMessages); - } - }); - - it("Serializes", () => { - const llm = createChatLLM(); - const serialized = llm.serialize(); - const deserialized = IBMVllmChatLLM.fromSerialized(serialized); - verifyDeserialization(llm, deserialized); - }); -}); diff --git a/tests/e2e/adapters/ibm-vllm/llm.test.ts b/tests/e2e/adapters/ibm-vllm/llm.test.ts deleted file mode 100644 index 25474661..00000000 --- a/tests/e2e/adapters/ibm-vllm/llm.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { IBMvLLM, IBMvLLMOutput } from "@/adapters/ibm-vllm/llm.js"; -import { IBMVllmModel } from "@/adapters/ibm-vllm/chatPreset.js"; - -describe.runIf( - [ - process.env.IBM_VLLM_URL, - process.env.IBM_VLLM_ROOT_CERT, - process.env.IBM_VLLM_PRIVATE_KEY, - process.env.IBM_VLLM_CERT_CHAIN, - ].every((env) => Boolean(env)), -)("IBM vLLM", () => { - const createLLM = (modelId: string = IBMVllmModel.LLAMA_3_1_70B_INSTRUCT) => { - return new IBMvLLM({ modelId }); - }; - - it("Meta", async () => { - const llm = createLLM(); - const response = await llm.meta(); - expect(response.tokenLimit).toBeGreaterThan(0); - }); - - it("Generates", async () => { - const llm = createLLM(); - const response = await llm.generate("Hello world!"); - expect(response).toBeInstanceOf(IBMvLLMOutput); - }); - - it("Streams", async () => { - const llm = createLLM(); - for await (const chunk of llm.stream("Hello world!")) { - expect(chunk).toBeInstanceOf(IBMvLLMOutput); - expect(chunk.text).toBeTruthy(); - } - }); - - it("Embeds", async () => { - const llm = createLLM("baai/bge-large-en-v1.5"); - const response = await llm.embed([`Hello world!`, `Hello family!`]); - expect(response.embeddings.length).toBe(2); - expect(response.embeddings[0].length).toBe(1024); - expect(response.embeddings[1].length).toBe(1024); - }); - - it("Serializes", () => { - const llm = createLLM(); - const serialized = llm.serialize(); - const deserialized = IBMvLLM.fromSerialized(serialized); - verifyDeserialization(llm, deserialized); - }); -}); diff --git a/tests/e2e/adapters/langchain/chat.test.ts b/tests/e2e/adapters/langchain/chat.test.ts deleted file mode 100644 index 43731106..00000000 --- a/tests/e2e/adapters/langchain/chat.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { ChatOpenAI } from "@langchain/openai"; -import { LangChainChatLLM } from "@/adapters/langchain/llms/chat.js"; - -const apiKey = process.env.OPENAI_API_KEY; - -describe.runIf(Boolean(apiKey))("Adapter LangChain Chat LLM", () => { - const createChatLLM = () => { - const model = new ChatOpenAI({ - temperature: 0, - apiKey, - }); - return new LangChainChatLLM(model); - }; - - it("Generates", async () => { - const conversation = [ - BaseMessage.of({ - role: Role.SYSTEM, - text: `You are a helpful and respectful and honest assistant. Your answer should be short and concise.`, - }), - ]; - const llm = createChatLLM(); - - for (const { question, answer } of [ - { - question: `What is the coldest continent? Response must be a single word.`, - answer: "Antarctica", - }, - { - question: - "What is the most common typical animal that lives there? Response must be a single word.", - answer: "Penguin", - }, - ]) { - conversation.push( - BaseMessage.of({ - role: Role.USER, - text: question, - }), - ); - const response = await llm.generate(conversation); - expect(response.messages.length).toBeGreaterThan(0); - expect(response.getTextContent()).toBe(answer); - conversation.push( - BaseMessage.of({ - role: Role.ASSISTANT, - text: response.getTextContent(), - }), - ); - } - }); -}); diff --git a/tests/e2e/adapters/ollama/chat.test.ts b/tests/e2e/adapters/ollama/chat.test.ts deleted file mode 100644 index 789b0ebc..00000000 --- a/tests/e2e/adapters/ollama/chat.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BaseMessage, Role } from "@/llms/primitives/message.js"; -import { OllamaChatLLM } from "@/adapters/ollama/chat.js"; -import { Ollama } from "ollama"; -import { toJsonSchema } from "@/internals/helpers/schema.js"; -import { z } from "zod"; -import { Comparator, compareVersion } from "@/internals/helpers/string.js"; - -const host = process.env.OLLAMA_HOST; - -describe.runIf(Boolean(host))("Ollama Chat LLM", () => { - const createChatLLM = (maxTokens?: number) => { - return new OllamaChatLLM({ - modelId: "llama3.1", - parameters: { - temperature: 0, - num_predict: maxTokens, - }, - client: new Ollama({ - host, - }), - }); - }; - - it("Generates", async () => { - const conversation = [ - BaseMessage.of({ - role: Role.SYSTEM, - text: `You are a helpful and respectful and honest assistant. Your name is Bee.`, - }), - ]; - const llm = createChatLLM(5); - const response = await llm.generate([ - ...conversation, - BaseMessage.of({ - role: "user", - text: "What is your name? Just output the name without any additional comment.", - }), - ]); - expect(response.getTextContent()).includes("Bee"); - }); - - it("Leverages structured output", async () => { - const llm = createChatLLM(); - const version = await llm.version(); - - if (compareVersion(version, Comparator.LT, "0.5.0")) { - // eslint-disable-next-line no-console - console.warn(`Structured output is not available in the current version (${version})`); - return; - } - - const response = await llm.generate( - [ - BaseMessage.of({ - role: "user", - text: "Generate a valid JSON object.", - }), - ], - { - stream: false, - guided: { - json: toJsonSchema( - z - .object({ - a: z.literal("a"), - b: z.literal("b"), - c: z.literal("c"), - }) - .strict(), - ), - }, - }, - ); - expect(response.getTextContent()).toMatchInlineSnapshot(`"{"a": "a", "b": "b", "c": "c"}"`); - }); - - it("Retrieves version", async () => { - const llm = createChatLLM(); - const version = await llm.version(); - expect(version).toBeDefined(); - }); -}); diff --git a/tests/e2e/adapters/vertexai/chat.test.ts b/tests/e2e/adapters/vertexai/chat.test.ts deleted file mode 100644 index e9d5c9b8..00000000 --- a/tests/e2e/adapters/vertexai/chat.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BaseMessage } from "@/llms/primitives/message.js"; -import { expect } from "vitest"; -import { VertexAIChatLLM } from "@/adapters/vertexai/chat.js"; -import { getEnv } from "@/internals/env.js"; - -const project = getEnv("GCP_VERTEXAI_PROJECT"); -const location = getEnv("GCP_VERTEXAI_LOCATION"); - -describe.runIf(Boolean(project && location && getEnv("GOOGLE_APPLICATION_CREDENTIALS")))( - "GCP Vertex AI", - () => { - const createChatLLM = () => { - return new VertexAIChatLLM({ - modelId: "gemini-1.5-flash-001", - project: process.env.GCP_VERTEXAI_PROJECT ?? "dummy", - location: "us-central1", - }); - }; - - it("Generates", async () => { - const conversation = [ - BaseMessage.of({ - role: "user", - text: `You are a helpful and respectful and honest assistant. Your answer should be short and concise.`, - }), - ]; - const llm = createChatLLM(); - - for (const { question, answer } of [ - { question: `What is the coldest continent?`, answer: "arctica" }, - { question: "What is the most common typical animal that lives there?", answer: "penguin" }, - ]) { - conversation.push( - BaseMessage.of({ - role: "user", - text: question, - }), - ); - const response = await llm.generate(conversation); - - const newMessages = response.messages; - expect(newMessages).toHaveLength(1); - expect(newMessages[0].text.toLowerCase()).toContain(answer.toLowerCase()); - conversation.push(...newMessages); - } - }); - }, -); diff --git a/tests/e2e/adapters/vertexai/llm.test.ts b/tests/e2e/adapters/vertexai/llm.test.ts deleted file mode 100644 index 245529b9..00000000 --- a/tests/e2e/adapters/vertexai/llm.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { VertexAILLM, VertexAILLMOutput } from "@/adapters/vertexai/llm.js"; -import { getEnv } from "@/internals/env.js"; - -const project = getEnv("GCP_VERTEXAI_PROJECT"); -const location = getEnv("GCP_VERTEXAI_LOCATION"); - -describe.runIf(Boolean(project && location && getEnv("GOOGLE_APPLICATION_CREDENTIALS")))( - "GCP Vertex AI", - () => { - const createLLM = () => { - return new VertexAILLM({ - modelId: "gemini-1.5-flash-001", - project: project, - location: location, - }); - }; - - it("Meta", async () => { - const llm = createLLM(); - const response = await llm.meta(); - expect(response.tokenLimit).toBeGreaterThan(0); - }); - - it("Generates", async () => { - const llm = createLLM(); - const response = await llm.generate("Hello world!"); - expect(response).toBeInstanceOf(VertexAILLMOutput); - }); - - it("Streams", async () => { - const llm = createLLM(); - for await (const chunk of llm.stream("Hello world!")) { - expect(chunk).toBeInstanceOf(VertexAILLMOutput); - expect(chunk.toString()).toBeTruthy(); - } - }); - }, -); diff --git a/tests/e2e/adapters/watsonx/chat.test.ts b/tests/e2e/adapters/watsonx/chat.test.ts deleted file mode 100644 index 7ceb4373..00000000 --- a/tests/e2e/adapters/watsonx/chat.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BaseMessage } from "@/llms/primitives/message.js"; -import { expect } from "vitest"; -import { verifyDeserialization } from "@tests/e2e/utils.js"; -import { WatsonXChatLLM } from "@/adapters/watsonx/chat.js"; - -const apiKey = process.env.WATSONX_API_KEY!; -const projectId = process.env.WATSONX_PROJECT_ID!; - -describe.runIf(Boolean(apiKey && projectId))("WatsonX Chat LLM", () => { - const createChatLLM = () => { - return WatsonXChatLLM.fromPreset("meta-llama/llama-3-1-70b-instruct", { - apiKey, - projectId, - parameters: { - decoding_method: "greedy", - min_new_tokens: 5, - max_new_tokens: 50, - }, - }); - }; - - it("Generates", async () => { - const conversation = [ - BaseMessage.of({ - role: "system", - text: `You are a helpful and respectful and honest assistant. Your answer should be short and concise.`, - }), - ]; - const llm = createChatLLM(); - - for (const { question, answer } of [ - { question: `What is the coldest continent?`, answer: "arctica" }, - { question: "What is the most common typical animal that lives there?", answer: "penguin" }, - ]) { - conversation.push( - BaseMessage.of({ - role: "user", - text: question, - }), - ); - const response = await llm.generate(conversation); - - const newMessages = response.messages; - expect(newMessages).toHaveLength(1); - expect(newMessages[0].text.toLowerCase()).toContain(answer.toLowerCase()); - conversation.push(...newMessages); - } - }); - - it("Serializes", () => { - const llm = createChatLLM(); - const serialized = llm.serialize(); - const deserialized = WatsonXChatLLM.fromSerialized(serialized); - verifyDeserialization(llm, deserialized); - }); -}); diff --git a/tests/e2e/adapters/watsonx/llm.test.ts b/tests/e2e/adapters/watsonx/llm.test.ts deleted file mode 100644 index 75f5042e..00000000 --- a/tests/e2e/adapters/watsonx/llm.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright 2025 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { WatsonXLLM, WatsonXLLMOutput } from "@/adapters/watsonx/llm.js"; -import { verifyDeserialization } from "@tests/e2e/utils.js"; - -const apiKey = process.env.WATSONX_API_KEY!; -const projectId = process.env.WATSONX_PROJECT_ID!; -const spaceId = process.env.WATSONX_SPACE_ID; -const deploymentId = process.env.WATSONX_DEPLOYMENT_ID; - -describe.runIf(Boolean(apiKey && projectId))("WatsonX SDK LLM", () => { - const createLLM = () => { - return new WatsonXLLM({ - apiKey, - projectId, - modelId: "google/flan-ul2", - spaceId, - deploymentId, - ...(deploymentId && { - transform: ({ input, ...body }) => ({ - ...body, - parameters: { - ...body?.parameters, - prompt_variables: { ...body?.parameters?.prompt_variables, name: input }, - }, - }), - }), - }); - }; - - it("Meta", async () => { - const llm = createLLM(); - const response = await llm.meta(); - expect(response.tokenLimit).toBeGreaterThan(0); - }); - - it("Generates", async () => { - const llm = createLLM(); - const response = await llm.generate("Hello world!"); - expect(response).toBeInstanceOf(WatsonXLLMOutput); - }); - - it("Streams", async () => { - const llm = createLLM(); - for await (const chunk of llm.stream("Hello world!")) { - expect(chunk).toBeInstanceOf(WatsonXLLMOutput); - expect(chunk.finalResult).toBeTruthy(); - } - }); - - it("Serializes", () => { - const llm = createLLM(); - const serialized = llm.serialize(); - const deserialized = WatsonXLLM.fromSerialized(serialized); - verifyDeserialization(llm, deserialized); - }); -}); diff --git a/tests/e2e/agents/bee.test.ts b/tests/e2e/agents/bee.test.ts index 31043355..06cae141 100644 --- a/tests/e2e/agents/bee.test.ts +++ b/tests/e2e/agents/bee.test.ts @@ -19,7 +19,7 @@ import { beforeEach, expect, vi } from "vitest"; import { Logger } from "@/logger/logger.js"; import { BeeAgent } from "@/agents/bee/agent.js"; import { UnconstrainedMemory } from "@/memory/unconstrainedMemory.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; +import { Message } from "@/backend/message.js"; import { createCallbackRegister } from "@tests/e2e/utils.js"; import { omitEmptyValues } from "@/internals/helpers/object.js"; import * as process from "node:process"; @@ -104,7 +104,7 @@ describe.runIf(Boolean(googleSearchApiKey && googleSearchCseId))("Bee Agent", () emitter.registerCallbacks({ success: callbacks.create("success", { check: ({ data }) => { - expect(data).toBeInstanceOf(BaseMessage); + expect(data).toBeInstanceOf(Message); expect(Object.keys(omitEmptyValues(data)).length).toBeGreaterThan(0); }, }), diff --git a/tests/e2e/agents/streamlit.test.ts b/tests/e2e/agents/streamlit.test.ts index 85d2dd29..068fd82e 100644 --- a/tests/e2e/agents/streamlit.test.ts +++ b/tests/e2e/agents/streamlit.test.ts @@ -20,9 +20,9 @@ import { UnconstrainedMemory } from "@/memory/unconstrainedMemory.js"; import { createCallbackRegister } from "@tests/e2e/utils.js"; import { createChatLLM } from "@tests/utils/llmFactory.js"; import { StreamlitAgent } from "@/agents/experimental/streamlit/agent.js"; -import { BaseLLMOutput } from "@/llms/base.js"; import { BaseMemory } from "@/memory/base.js"; -import { BaseMessage } from "@/llms/primitives/message.js"; +import { Message } from "@/backend/message.js"; +import { ChatModelOutput } from "@/backend/chat.js"; describe("Streamlit Agent", () => { const createAgent = () => { @@ -54,7 +54,7 @@ describe("Streamlit Agent", () => { expect(value).toBeTruthy(); expect(value.delta).toBeTypeOf("string"); expect(value.state).toBeTypeOf("object"); - expect(value.chunk).toBeInstanceOf(BaseLLMOutput); + expect(value.chunk).toBeInstanceOf(ChatModelOutput); }, }), }); @@ -67,7 +67,7 @@ describe("Streamlit Agent", () => { } expect(response.memory).toBeInstanceOf(BaseMemory); - expect(response.message).toBeInstanceOf(BaseMessage); + expect(response.message).toBeInstanceOf(Message); expect(response.result.raw).toBeTypeOf("string"); expect(response.result.blocks.length).toBeGreaterThanOrEqual(2); diff --git a/tests/e2e/utils.ts b/tests/e2e/utils.ts index 945c7d85..f01b798a 100644 --- a/tests/e2e/utils.ts +++ b/tests/e2e/utils.ts @@ -26,13 +26,11 @@ import { Callback } from "@/emitter/types.js"; import { RunContext } from "@/context.js"; import { Emitter } from "@/emitter/emitter.js"; import { toJsonSchema } from "@/internals/helpers/schema.js"; -import { OpenAI } from "openai"; -import { Groq } from "groq-sdk"; import { customsearch_v1 } from "@googleapis/customsearch"; import { LangChainTool } from "@/adapters/langchain/tools.js"; import { Client as esClient } from "@elastic/elasticsearch"; -import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime"; -import { VertexAI } from "@google-cloud/vertexai"; +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import { isWeakKey } from "@/internals/helpers/weakRef.js"; interface CallbackOptions { required?: boolean; @@ -76,7 +74,15 @@ export function verifyDeserialization( parent?: any, path: string[] = [], ignoredPaths: string[] = [], + seen = new WeakSet(), ) { + if (isWeakKey(ref)) { + if (seen.has(ref)) { + return; + } + seen.add(ref); + } + if (R.isPromise(ref) || R.isPromise(deserialized)) { throw new TypeError('Value passed to "verifyDeserialization" is promise (forgotten await)!'); } @@ -91,7 +97,7 @@ export function verifyDeserialization( new Set( Object.entries(instance) .filter(([key, value]) => !verifyDeserialization.isIgnored(key, value, instance)) - .map(([key, _]) => key) + .map(([key, _]) => String(key)) .sort(), ); @@ -99,7 +105,7 @@ export function verifyDeserialization( const keysB = getNonIgnoredKeys(deserialized); expect(keysB).toStrictEqual(refKeys); - for (const key of refKeys.values()) { + for (const key of Array.from(refKeys.values())) { const fullPath = path.concat(key).join("."); if (ignoredPaths.includes(fullPath)) { continue; @@ -115,7 +121,7 @@ export function verifyDeserialization( target = toJsonSchema(target); } Serializer.findFactory(target); - verifyDeserialization(value, target, parent, path.concat(key), ignoredPaths); + verifyDeserialization(value, target, parent, path.concat(key), ignoredPaths, seen); } } else { expect(deserialized).toStrictEqual(ref); @@ -129,8 +135,6 @@ verifyDeserialization.ignoredClasses = [ RunContext, Emitter, esClient, - BedrockRuntimeClient, - VertexAI, ] as ClassConstructor[]; verifyDeserialization.isIgnored = (key: string, value: unknown, parent?: any) => { if (verifyDeserialization.ignoredKeys.has(key)) { @@ -144,7 +148,7 @@ verifyDeserialization.isIgnored = (key: string, value: unknown, parent?: any) => return true; } - if (parent && (parent instanceof OpenAI || parent instanceof Groq)) { + if (parent && parent instanceof VercelChatModel) { try { Serializer.findFactory(value); return false; diff --git a/tests/examples/examples.test.ts b/tests/examples/examples.test.ts index 713ae241..1dceb58b 100644 --- a/tests/examples/examples.test.ts +++ b/tests/examples/examples.test.ts @@ -40,9 +40,7 @@ const exclude: string[] = [ "examples/workflows/competitive-analysis/**/*.ts", "examples/playground/**/*.ts", // prevents 'Too many requests' error on Free Tier - "examples/llms/providers/watsonx_verbose.ts", !getEnv("WATSONX_API_KEY") && [ - "examples/llms/text.ts", "examples/llms/providers/watson*.ts", "examples/agents/experimental/replan.ts", "examples/agents/experimental/streamlit.ts", @@ -59,10 +57,6 @@ const exclude: string[] = [ "examples/llms/providers/openai.ts", ], !getEnv("AZURE_OPENAI_API_KEY") && ["examples/llms/providers/azure_openai.ts"], - !getEnv("IBM_VLLM_URL") && [ - "examples/llms/providers/ibm-vllm.ts", - "examples/agents/granite/chat.ts", - ], !getEnv("COHERE_API_KEY") && ["examples/llms/providers/langchain.ts"], !getEnv("CODE_INTERPRETER_URL") && ["examples/tools/custom/python.ts"], !getEnv("ELASTICSEARCH_NODE") && ["examples/agents/elasticsearch.ts"], diff --git a/tests/utils/llmFactory.ts b/tests/utils/llmFactory.ts index a55b62df..83e10117 100644 --- a/tests/utils/llmFactory.ts +++ b/tests/utils/llmFactory.ts @@ -14,31 +14,25 @@ * limitations under the License. */ -import { ChatLLM, ChatLLMOutput } from "@/llms/chat.js"; import process from "node:process"; -import { OpenAIChatLLM } from "@/adapters/openai/chat.js"; -import { WatsonXChatLLM } from "@/adapters/watsonx/chat.js"; -import { GroqChatLLM } from "@/adapters/groq/chat.js"; -import { OllamaChatLLM } from "@/adapters/ollama/chat.js"; -import { Ollama } from "ollama"; import { Agent, Dispatcher } from "undici"; +import { OpenAIChatModel } from "@/adapters/openai/backend/chat.js"; +import { OllamaChatModel } from "@/adapters/ollama/backend/chat.js"; +import { WatsonxChatModel } from "@/adapters/watsonx/backend/chat.js"; +import { ChatModel } from "@/backend/chat.js"; +import { GroqChatModel } from "@/adapters/groq/backend/chat.js"; +import { AzureOpenAIChatModel } from "@/adapters/azure-openai/backend/chat.js"; -export function createChatLLM(): ChatLLM { +export function createChatLLM(): ChatModel { if (process.env.OPENAI_API_KEY) { - return new OpenAIChatLLM({ modelId: "gpt-4o" }); + return new OpenAIChatModel("gpt-4o"); } else if (process.env.AZURE_OPENAI_API_KEY) { - return new OpenAIChatLLM({ modelId: "gpt-4o", azure: true }); + return new AzureOpenAIChatModel("gpt-4o"); } else if (process.env.WATSONX_API_KEY && process.env.WATSONX_PROJECT_ID) { - return WatsonXChatLLM.fromPreset("meta-llama/llama-3-70b-instruct", { - projectId: process.env.WATSONX_PROJECT_ID, - region: process.env.WATSONX_REGION, - }); + return new WatsonxChatModel("meta-llama/llama-3-3-70b-instruct"); } else if (process.env.GROQ_API_KEY) { - return new GroqChatLLM({ - modelId: `llama-3.1-70b-versatile`, - parameters: { temperature: 0 }, - }); - } else if (process.env.OLLAMA_HOST) { + return new GroqChatModel(`llama-3.3-70b-versatile`); + } else if (process.env.OLLAMA_BASE_URL) { // the undici definition of RequestInit does not extend the default // fetch RequestInit so we can't use its type directly. Define // and interface that adds the field we need to the default fetch @@ -46,13 +40,12 @@ export function createChatLLM(): ChatLLM { interface UndiciRequestInit extends RequestInit { dispatcher: Dispatcher; } - return new OllamaChatLLM({ - modelId: process.env.OLLAMA_MODEL ?? "llama3.1:8b", - parameters: { - temperature: 0, - }, - client: new Ollama({ - host: process.env.OLLAMA_HOST, + + return new OllamaChatModel( + "llama3.1:8b", + {}, + { + baseURL: process.env.OLLAMA_BASE_URL, fetch: (input, init?) => { const someInit = init || {}; const requestInit: UndiciRequestInit = { @@ -61,8 +54,8 @@ export function createChatLLM(): ChatLLM { }; return fetch(input, requestInit); }, - }), - }); + }, + ); } else { throw new Error("No API key for any LLM provider has been provided. Cannot run test case."); } diff --git a/tsconfig.json b/tsconfig.json index 6a162b7c..f2b651ec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,6 +26,7 @@ "skipLibCheck": true, "paths": { "@/*": ["./src/*"], + "bee-agent-framework/*": ["./src/*"], "@tests/*": ["./tests/*"] }, "useUnknownInCatchVariables": false diff --git a/yarn.lock b/yarn.lock index e8c06a19..45a9feef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,200 @@ __metadata: version: 8 cacheKey: 10c0 +"@ai-sdk/amazon-bedrock@npm:^1.1.5": + version: 1.1.5 + resolution: "@ai-sdk/amazon-bedrock@npm:1.1.5" + dependencies: + "@ai-sdk/provider": "npm:1.0.6" + "@ai-sdk/provider-utils": "npm:2.1.5" + "@aws-sdk/client-bedrock-runtime": "npm:^3.663.0" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/e6a572bb92c9fdb8cf459c148daa62edb7e6d49815cf5fa1676b1117af42a0a183bbeca0acffbd515819180de0c274c03b9f7a3591e133e6679f1e492ab257d4 + languageName: node + linkType: hard + +"@ai-sdk/anthropic@npm:1.1.5": + version: 1.1.5 + resolution: "@ai-sdk/anthropic@npm:1.1.5" + dependencies: + "@ai-sdk/provider": "npm:1.0.6" + "@ai-sdk/provider-utils": "npm:2.1.5" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/f6fb7b7b74c30e250b6eb08b2db949dd635fac0fd82999dbdfcbc5a063dfed63dfe271df4dd09c99bd44f7949f06805150c23046329ea8c51156abea2483b604 + languageName: node + linkType: hard + +"@ai-sdk/azure@npm:^1.1.2": + version: 1.1.2 + resolution: "@ai-sdk/azure@npm:1.1.2" + dependencies: + "@ai-sdk/openai": "npm:1.1.2" + "@ai-sdk/provider": "npm:1.0.6" + "@ai-sdk/provider-utils": "npm:2.1.2" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/4518dd75f323377757b7a1aa5ddd2dadbdb58af5a382e3c827c44bdbc043cc07e0f2cad37749518d6046045fba1b365c33120fa14b99ecba10fa18bb8257ca77 + languageName: node + linkType: hard + +"@ai-sdk/google-vertex@npm:^2.1.6": + version: 2.1.6 + resolution: "@ai-sdk/google-vertex@npm:2.1.6" + dependencies: + "@ai-sdk/anthropic": "npm:1.1.5" + "@ai-sdk/google": "npm:1.1.6" + "@ai-sdk/provider": "npm:1.0.6" + "@ai-sdk/provider-utils": "npm:2.1.5" + google-auth-library: "npm:^9.15.0" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/1b3cf12d8b744da52066f6db3bb9f400c5a4d73661461c0a62550b66f16891ad31d4f579a7f552290d91834cc731a86a96e17bfc96bbdc4c1e9761fd7d7c9b55 + languageName: node + linkType: hard + +"@ai-sdk/google@npm:1.1.6": + version: 1.1.6 + resolution: "@ai-sdk/google@npm:1.1.6" + dependencies: + "@ai-sdk/provider": "npm:1.0.6" + "@ai-sdk/provider-utils": "npm:2.1.5" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/ca562bf5e103d773947f6fbb783ec739114e208d0252e7ade4627043d69494622d08279023dc904b15448b0efdd64a8f28052b8dea68a00b9894b9785a954569 + languageName: node + linkType: hard + +"@ai-sdk/groq@npm:^1.1.6": + version: 1.1.6 + resolution: "@ai-sdk/groq@npm:1.1.6" + dependencies: + "@ai-sdk/provider": "npm:1.0.6" + "@ai-sdk/provider-utils": "npm:2.1.5" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/3580db63e62fe57c712221a3201eb0013bc8365b117df20815076c92343b00c7fe95751f8613122d00bd64b1403422dd14352e441cf11a8548110cc9f18e8717 + languageName: node + linkType: hard + +"@ai-sdk/openai@npm:1.1.2, @ai-sdk/openai@npm:^1.1.2": + version: 1.1.2 + resolution: "@ai-sdk/openai@npm:1.1.2" + dependencies: + "@ai-sdk/provider": "npm:1.0.6" + "@ai-sdk/provider-utils": "npm:2.1.2" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/ad5d1a918197a5ac48bb42b1939e2313896ec60180f9810e330b90912257f9b74724fe8df4a971475df15de89a8c82422f406f4a86d825b1c644993652a903c1 + languageName: node + linkType: hard + +"@ai-sdk/provider-utils@npm:2.1.2": + version: 2.1.2 + resolution: "@ai-sdk/provider-utils@npm:2.1.2" + dependencies: + "@ai-sdk/provider": "npm:1.0.6" + eventsource-parser: "npm:^3.0.0" + nanoid: "npm:^3.3.8" + secure-json-parse: "npm:^2.7.0" + peerDependencies: + zod: ^3.0.0 + peerDependenciesMeta: + zod: + optional: true + checksum: 10c0/55404b9ba83262c5d4511f099835a10c1b04ce64f0ac554fa6afb8024da2e14754b5990c77aa357ff3ea4e916c863158a734b92af8dfd89886419f0786a307f6 + languageName: node + linkType: hard + +"@ai-sdk/provider-utils@npm:2.1.5, @ai-sdk/provider-utils@npm:^2.0.0": + version: 2.1.5 + resolution: "@ai-sdk/provider-utils@npm:2.1.5" + dependencies: + "@ai-sdk/provider": "npm:1.0.6" + eventsource-parser: "npm:^3.0.0" + nanoid: "npm:^3.3.8" + secure-json-parse: "npm:^2.7.0" + peerDependencies: + zod: ^3.0.0 + peerDependenciesMeta: + zod: + optional: true + checksum: 10c0/6ec33c1f9cc6bb38a7634cdb1b43f49d78ddcb92a8daa4b65193f3309b5a7ad35b134e2d5e82b8576917079a3f8e3b83b5505151cd259ec747ba27458db58356 + languageName: node + linkType: hard + +"@ai-sdk/provider-utils@npm:2.1.6": + version: 2.1.6 + resolution: "@ai-sdk/provider-utils@npm:2.1.6" + dependencies: + "@ai-sdk/provider": "npm:1.0.7" + eventsource-parser: "npm:^3.0.0" + nanoid: "npm:^3.3.8" + secure-json-parse: "npm:^2.7.0" + peerDependencies: + zod: ^3.0.0 + peerDependenciesMeta: + zod: + optional: true + checksum: 10c0/dacf9640c0ab2da69157d08c7db47f9ac82aa140780ad18d03b802a88ec9e81ce6f0626cb6f7139086013c5850f829f74e81783a6fe1e6a7e08d090f08479179 + languageName: node + linkType: hard + +"@ai-sdk/provider@npm:1.0.6, @ai-sdk/provider@npm:^1.0.0": + version: 1.0.6 + resolution: "@ai-sdk/provider@npm:1.0.6" + dependencies: + json-schema: "npm:^0.4.0" + checksum: 10c0/251c8cd4fa53b89dcf751d0faba5482762d88fcc5ffe1cdb660327c14817a4d94206317e95e6e69fc4ae3071001191b5c418b4b9e1212d6a554a90114db216fc + languageName: node + linkType: hard + +"@ai-sdk/provider@npm:1.0.7": + version: 1.0.7 + resolution: "@ai-sdk/provider@npm:1.0.7" + dependencies: + json-schema: "npm:^0.4.0" + checksum: 10c0/92d0a3cd4d577ca8028d7b8fb3c2b4b837be10fced5d66dbe67fe415b678d2ff039d32721b71b88389568729e707b35df81172908e2584f2e24ff20fcdcdeb65 + languageName: node + linkType: hard + +"@ai-sdk/react@npm:1.1.10": + version: 1.1.10 + resolution: "@ai-sdk/react@npm:1.1.10" + dependencies: + "@ai-sdk/provider-utils": "npm:2.1.6" + "@ai-sdk/ui-utils": "npm:1.1.10" + swr: "npm:^2.2.5" + throttleit: "npm:2.1.0" + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + zod: ^3.0.0 + peerDependenciesMeta: + react: + optional: true + zod: + optional: true + checksum: 10c0/bdfe767a3c4b9e82fdb3327dd1672922451b5276474be998decad0a6abd89ff7f784dadeffd14db2631c5b5eb34ff7467a391597ca9ff735ba958715c82ab463 + languageName: node + linkType: hard + +"@ai-sdk/ui-utils@npm:1.1.10": + version: 1.1.10 + resolution: "@ai-sdk/ui-utils@npm:1.1.10" + dependencies: + "@ai-sdk/provider": "npm:1.0.7" + "@ai-sdk/provider-utils": "npm:2.1.6" + zod-to-json-schema: "npm:^3.24.1" + peerDependencies: + zod: ^3.0.0 + peerDependenciesMeta: + zod: + optional: true + checksum: 10c0/d48a7d0ae5149792d7607ad43c8be34aa47ac955aaef8b115ea29df4acc7785bae56bee5a7fa326581224022d8f819239035576983270701b72253566793da71 + languageName: node + linkType: hard + "@ai-zen/node-fetch-event-source@npm:^2.1.4": version: 2.1.4 resolution: "@ai-zen/node-fetch-event-source@npm:2.1.4" @@ -14,17 +208,6 @@ __metadata: languageName: node linkType: hard -"@apidevtools/json-schema-ref-parser@npm:^11.5.5": - version: 11.7.0 - resolution: "@apidevtools/json-schema-ref-parser@npm:11.7.0" - dependencies: - "@jsdevtools/ono": "npm:^7.1.3" - "@types/json-schema": "npm:^7.0.15" - js-yaml: "npm:^4.1.0" - checksum: 10c0/0ae9ced2953918a14b17874dc0515d3367a95197d58d869f44e756223e23eb9996283e21cb7ef1c7e016ae94467920b4aca705e0ea3d61a61455431572ad4ab5 - languageName: node - linkType: hard - "@aws-crypto/crc32@npm:5.2.0": version: 5.2.0 resolution: "@aws-crypto/crc32@npm:5.2.0" @@ -82,427 +265,371 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-bedrock-runtime@npm:^3.706.0": - version: 3.706.0 - resolution: "@aws-sdk/client-bedrock-runtime@npm:3.706.0" +"@aws-sdk/client-bedrock-runtime@npm:^3.663.0": + version: 3.738.0 + resolution: "@aws-sdk/client-bedrock-runtime@npm:3.738.0" dependencies: "@aws-crypto/sha256-browser": "npm:5.2.0" "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/client-sso-oidc": "npm:3.699.0" - "@aws-sdk/client-sts": "npm:3.699.0" - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/credential-provider-node": "npm:3.699.0" - "@aws-sdk/middleware-host-header": "npm:3.696.0" - "@aws-sdk/middleware-logger": "npm:3.696.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.696.0" - "@aws-sdk/middleware-user-agent": "npm:3.696.0" - "@aws-sdk/region-config-resolver": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@aws-sdk/util-endpoints": "npm:3.696.0" - "@aws-sdk/util-user-agent-browser": "npm:3.696.0" - "@aws-sdk/util-user-agent-node": "npm:3.696.0" - "@smithy/config-resolver": "npm:^3.0.12" - "@smithy/core": "npm:^2.5.3" - "@smithy/eventstream-serde-browser": "npm:^3.0.13" - "@smithy/eventstream-serde-config-resolver": "npm:^3.0.10" - "@smithy/eventstream-serde-node": "npm:^3.0.12" - "@smithy/fetch-http-handler": "npm:^4.1.1" - "@smithy/hash-node": "npm:^3.0.10" - "@smithy/invalid-dependency": "npm:^3.0.10" - "@smithy/middleware-content-length": "npm:^3.0.12" - "@smithy/middleware-endpoint": "npm:^3.2.3" - "@smithy/middleware-retry": "npm:^3.0.27" - "@smithy/middleware-serde": "npm:^3.0.10" - "@smithy/middleware-stack": "npm:^3.0.10" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/node-http-handler": "npm:^3.3.1" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/smithy-client": "npm:^3.4.4" - "@smithy/types": "npm:^3.7.1" - "@smithy/url-parser": "npm:^3.0.10" - "@smithy/util-base64": "npm:^3.0.0" - "@smithy/util-body-length-browser": "npm:^3.0.0" - "@smithy/util-body-length-node": "npm:^3.0.0" - "@smithy/util-defaults-mode-browser": "npm:^3.0.27" - "@smithy/util-defaults-mode-node": "npm:^3.0.27" - "@smithy/util-endpoints": "npm:^2.1.6" - "@smithy/util-middleware": "npm:^3.0.10" - "@smithy/util-retry": "npm:^3.0.10" - "@smithy/util-stream": "npm:^3.3.1" - "@smithy/util-utf8": "npm:^3.0.0" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/credential-provider-node": "npm:3.738.0" + "@aws-sdk/middleware-host-header": "npm:3.734.0" + "@aws-sdk/middleware-logger": "npm:3.734.0" + "@aws-sdk/middleware-recursion-detection": "npm:3.734.0" + "@aws-sdk/middleware-user-agent": "npm:3.734.0" + "@aws-sdk/region-config-resolver": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@aws-sdk/util-endpoints": "npm:3.734.0" + "@aws-sdk/util-user-agent-browser": "npm:3.734.0" + "@aws-sdk/util-user-agent-node": "npm:3.734.0" + "@smithy/config-resolver": "npm:^4.0.1" + "@smithy/core": "npm:^3.1.1" + "@smithy/eventstream-serde-browser": "npm:^4.0.1" + "@smithy/eventstream-serde-config-resolver": "npm:^4.0.1" + "@smithy/eventstream-serde-node": "npm:^4.0.1" + "@smithy/fetch-http-handler": "npm:^5.0.1" + "@smithy/hash-node": "npm:^4.0.1" + "@smithy/invalid-dependency": "npm:^4.0.1" + "@smithy/middleware-content-length": "npm:^4.0.1" + "@smithy/middleware-endpoint": "npm:^4.0.2" + "@smithy/middleware-retry": "npm:^4.0.3" + "@smithy/middleware-serde": "npm:^4.0.1" + "@smithy/middleware-stack": "npm:^4.0.1" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/node-http-handler": "npm:^4.0.2" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/smithy-client": "npm:^4.1.2" + "@smithy/types": "npm:^4.1.0" + "@smithy/url-parser": "npm:^4.0.1" + "@smithy/util-base64": "npm:^4.0.0" + "@smithy/util-body-length-browser": "npm:^4.0.0" + "@smithy/util-body-length-node": "npm:^4.0.0" + "@smithy/util-defaults-mode-browser": "npm:^4.0.3" + "@smithy/util-defaults-mode-node": "npm:^4.0.3" + "@smithy/util-endpoints": "npm:^3.0.1" + "@smithy/util-middleware": "npm:^4.0.1" + "@smithy/util-retry": "npm:^4.0.1" + "@smithy/util-stream": "npm:^4.0.2" + "@smithy/util-utf8": "npm:^4.0.0" "@types/uuid": "npm:^9.0.1" tslib: "npm:^2.6.2" uuid: "npm:^9.0.1" - checksum: 10c0/5c413ac62f50f4a0ce85de624eca25cd2a072cd2731e22c2e29b14b1a60ba89ad108d4eb5999d9fa5d8b6c22514e802160a7afa6b3cd6b132ab7c270df0b6f00 + checksum: 10c0/0a31df92fb42f014f3373db91a5aca819ad9432fb16e880a1f95b76fddef9371c82ebca084b7a84e3f71b831a0edea2233c89c8f680cc7e6e27712ea105e262e languageName: node linkType: hard -"@aws-sdk/client-sso-oidc@npm:3.699.0": - version: 3.699.0 - resolution: "@aws-sdk/client-sso-oidc@npm:3.699.0" +"@aws-sdk/client-sso@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/client-sso@npm:3.734.0" dependencies: "@aws-crypto/sha256-browser": "npm:5.2.0" "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/credential-provider-node": "npm:3.699.0" - "@aws-sdk/middleware-host-header": "npm:3.696.0" - "@aws-sdk/middleware-logger": "npm:3.696.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.696.0" - "@aws-sdk/middleware-user-agent": "npm:3.696.0" - "@aws-sdk/region-config-resolver": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@aws-sdk/util-endpoints": "npm:3.696.0" - "@aws-sdk/util-user-agent-browser": "npm:3.696.0" - "@aws-sdk/util-user-agent-node": "npm:3.696.0" - "@smithy/config-resolver": "npm:^3.0.12" - "@smithy/core": "npm:^2.5.3" - "@smithy/fetch-http-handler": "npm:^4.1.1" - "@smithy/hash-node": "npm:^3.0.10" - "@smithy/invalid-dependency": "npm:^3.0.10" - "@smithy/middleware-content-length": "npm:^3.0.12" - "@smithy/middleware-endpoint": "npm:^3.2.3" - "@smithy/middleware-retry": "npm:^3.0.27" - "@smithy/middleware-serde": "npm:^3.0.10" - "@smithy/middleware-stack": "npm:^3.0.10" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/node-http-handler": "npm:^3.3.1" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/smithy-client": "npm:^3.4.4" - "@smithy/types": "npm:^3.7.1" - "@smithy/url-parser": "npm:^3.0.10" - "@smithy/util-base64": "npm:^3.0.0" - "@smithy/util-body-length-browser": "npm:^3.0.0" - "@smithy/util-body-length-node": "npm:^3.0.0" - "@smithy/util-defaults-mode-browser": "npm:^3.0.27" - "@smithy/util-defaults-mode-node": "npm:^3.0.27" - "@smithy/util-endpoints": "npm:^2.1.6" - "@smithy/util-middleware": "npm:^3.0.10" - "@smithy/util-retry": "npm:^3.0.10" - "@smithy/util-utf8": "npm:^3.0.0" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/middleware-host-header": "npm:3.734.0" + "@aws-sdk/middleware-logger": "npm:3.734.0" + "@aws-sdk/middleware-recursion-detection": "npm:3.734.0" + "@aws-sdk/middleware-user-agent": "npm:3.734.0" + "@aws-sdk/region-config-resolver": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@aws-sdk/util-endpoints": "npm:3.734.0" + "@aws-sdk/util-user-agent-browser": "npm:3.734.0" + "@aws-sdk/util-user-agent-node": "npm:3.734.0" + "@smithy/config-resolver": "npm:^4.0.1" + "@smithy/core": "npm:^3.1.1" + "@smithy/fetch-http-handler": "npm:^5.0.1" + "@smithy/hash-node": "npm:^4.0.1" + "@smithy/invalid-dependency": "npm:^4.0.1" + "@smithy/middleware-content-length": "npm:^4.0.1" + "@smithy/middleware-endpoint": "npm:^4.0.2" + "@smithy/middleware-retry": "npm:^4.0.3" + "@smithy/middleware-serde": "npm:^4.0.1" + "@smithy/middleware-stack": "npm:^4.0.1" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/node-http-handler": "npm:^4.0.2" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/smithy-client": "npm:^4.1.2" + "@smithy/types": "npm:^4.1.0" + "@smithy/url-parser": "npm:^4.0.1" + "@smithy/util-base64": "npm:^4.0.0" + "@smithy/util-body-length-browser": "npm:^4.0.0" + "@smithy/util-body-length-node": "npm:^4.0.0" + "@smithy/util-defaults-mode-browser": "npm:^4.0.3" + "@smithy/util-defaults-mode-node": "npm:^4.0.3" + "@smithy/util-endpoints": "npm:^3.0.1" + "@smithy/util-middleware": "npm:^4.0.1" + "@smithy/util-retry": "npm:^4.0.1" + "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - peerDependencies: - "@aws-sdk/client-sts": ^3.699.0 - checksum: 10c0/b4d277fe4a7af3934b7528e8379901ae56ab9b9d3b6ed019d0a89f22ce2f8430edbe77ef1ced413216b378e517e32a625f3c4a4e8d6ef2bc58baefb6bc5e96d9 + checksum: 10c0/8098f0516c31ee1cb0f7c82932d8bcfd4a6f85f1945c0d022402c72c40c389a04b50888543e7de43a3c8db00203bbd00d3d13a9570f37f5e4fe8253085f72df8 languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/client-sso@npm:3.696.0" +"@aws-sdk/core@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/core@npm:3.734.0" dependencies: - "@aws-crypto/sha256-browser": "npm:5.2.0" - "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/middleware-host-header": "npm:3.696.0" - "@aws-sdk/middleware-logger": "npm:3.696.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.696.0" - "@aws-sdk/middleware-user-agent": "npm:3.696.0" - "@aws-sdk/region-config-resolver": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@aws-sdk/util-endpoints": "npm:3.696.0" - "@aws-sdk/util-user-agent-browser": "npm:3.696.0" - "@aws-sdk/util-user-agent-node": "npm:3.696.0" - "@smithy/config-resolver": "npm:^3.0.12" - "@smithy/core": "npm:^2.5.3" - "@smithy/fetch-http-handler": "npm:^4.1.1" - "@smithy/hash-node": "npm:^3.0.10" - "@smithy/invalid-dependency": "npm:^3.0.10" - "@smithy/middleware-content-length": "npm:^3.0.12" - "@smithy/middleware-endpoint": "npm:^3.2.3" - "@smithy/middleware-retry": "npm:^3.0.27" - "@smithy/middleware-serde": "npm:^3.0.10" - "@smithy/middleware-stack": "npm:^3.0.10" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/node-http-handler": "npm:^3.3.1" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/smithy-client": "npm:^3.4.4" - "@smithy/types": "npm:^3.7.1" - "@smithy/url-parser": "npm:^3.0.10" - "@smithy/util-base64": "npm:^3.0.0" - "@smithy/util-body-length-browser": "npm:^3.0.0" - "@smithy/util-body-length-node": "npm:^3.0.0" - "@smithy/util-defaults-mode-browser": "npm:^3.0.27" - "@smithy/util-defaults-mode-node": "npm:^3.0.27" - "@smithy/util-endpoints": "npm:^2.1.6" - "@smithy/util-middleware": "npm:^3.0.10" - "@smithy/util-retry": "npm:^3.0.10" - "@smithy/util-utf8": "npm:^3.0.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/core": "npm:^3.1.1" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/signature-v4": "npm:^5.0.1" + "@smithy/smithy-client": "npm:^4.1.2" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-middleware": "npm:^4.0.1" + fast-xml-parser: "npm:4.4.1" tslib: "npm:^2.6.2" - checksum: 10c0/e96c907c3385ea183181eb7dbdceb01c2b96a220f67bf6147b9a116aa197ceb2860fa54667405a7f60f365ee1c056b7039ff1ac236815894b675ee76c52862f3 + checksum: 10c0/1f301a3a1fa8172bacf881482bdbf10ac8212d9c6e1b726df66958994a8eaec7202f2d795e8668ae23ec4563067db4e4068ea8496a436426dd38ebd0f76d0f3e languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.699.0": - version: 3.699.0 - resolution: "@aws-sdk/client-sts@npm:3.699.0" +"@aws-sdk/credential-provider-env@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.734.0" dependencies: - "@aws-crypto/sha256-browser": "npm:5.2.0" - "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/client-sso-oidc": "npm:3.699.0" - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/credential-provider-node": "npm:3.699.0" - "@aws-sdk/middleware-host-header": "npm:3.696.0" - "@aws-sdk/middleware-logger": "npm:3.696.0" - "@aws-sdk/middleware-recursion-detection": "npm:3.696.0" - "@aws-sdk/middleware-user-agent": "npm:3.696.0" - "@aws-sdk/region-config-resolver": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@aws-sdk/util-endpoints": "npm:3.696.0" - "@aws-sdk/util-user-agent-browser": "npm:3.696.0" - "@aws-sdk/util-user-agent-node": "npm:3.696.0" - "@smithy/config-resolver": "npm:^3.0.12" - "@smithy/core": "npm:^2.5.3" - "@smithy/fetch-http-handler": "npm:^4.1.1" - "@smithy/hash-node": "npm:^3.0.10" - "@smithy/invalid-dependency": "npm:^3.0.10" - "@smithy/middleware-content-length": "npm:^3.0.12" - "@smithy/middleware-endpoint": "npm:^3.2.3" - "@smithy/middleware-retry": "npm:^3.0.27" - "@smithy/middleware-serde": "npm:^3.0.10" - "@smithy/middleware-stack": "npm:^3.0.10" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/node-http-handler": "npm:^3.3.1" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/smithy-client": "npm:^3.4.4" - "@smithy/types": "npm:^3.7.1" - "@smithy/url-parser": "npm:^3.0.10" - "@smithy/util-base64": "npm:^3.0.0" - "@smithy/util-body-length-browser": "npm:^3.0.0" - "@smithy/util-body-length-node": "npm:^3.0.0" - "@smithy/util-defaults-mode-browser": "npm:^3.0.27" - "@smithy/util-defaults-mode-node": "npm:^3.0.27" - "@smithy/util-endpoints": "npm:^2.1.6" - "@smithy/util-middleware": "npm:^3.0.10" - "@smithy/util-retry": "npm:^3.0.10" - "@smithy/util-utf8": "npm:^3.0.0" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/bdc7bc373fc518570d8d034b6e1af033c2bf272217c79ebe3e1ec3f928c5b73b4b71f6b7d0be9a95db1f909cdcbe8b5a52776f4f2290d63a78bd05ece7d9abe0 + checksum: 10c0/27071ce049fc6c73a65478f2dbbe9de21a5d4558a93d8c9ea4b9101b41323cbde012614ef7f87467e6f05515afa8cf5fc556a579b359ce83ebbf786493ee94fc languageName: node linkType: hard -"@aws-sdk/core@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/core@npm:3.696.0" +"@aws-sdk/credential-provider-http@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/credential-provider-http@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/core": "npm:^2.5.3" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/signature-v4": "npm:^4.2.2" - "@smithy/smithy-client": "npm:^3.4.4" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-middleware": "npm:^3.0.10" - fast-xml-parser: "npm:4.4.1" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/fetch-http-handler": "npm:^5.0.1" + "@smithy/node-http-handler": "npm:^4.0.2" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/smithy-client": "npm:^4.1.2" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-stream": "npm:^4.0.2" tslib: "npm:^2.6.2" - checksum: 10c0/4a96a3e29bf6e0dcd82d8160633eb4b8a488d821a8e59c1033c79a8e0d32b2f82e241e1cf94599f48836800549e342a410318b18e055851741ddf7d5d3ad4606 - languageName: node - linkType: hard - -"@aws-sdk/credential-provider-env@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/credential-provider-env@npm:3.696.0" - dependencies: - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/types": "npm:^3.7.1" + checksum: 10c0/60edc09a92f91049bd61f3b51700ceeaa1c429d1e41e25a39560bbe56f1f0623a3a475577e265d89552f31c6d6388acda5e073f3a111692b27f07c0ad824b613 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-ini@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.734.0" + dependencies: + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/credential-provider-env": "npm:3.734.0" + "@aws-sdk/credential-provider-http": "npm:3.734.0" + "@aws-sdk/credential-provider-process": "npm:3.734.0" + "@aws-sdk/credential-provider-sso": "npm:3.734.0" + "@aws-sdk/credential-provider-web-identity": "npm:3.734.0" + "@aws-sdk/nested-clients": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/credential-provider-imds": "npm:^4.0.1" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/shared-ini-file-loader": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/e16987ca343f9dbae2560d0d016ca005f36b27fb094f8d32b99954d0a2874aa8230f924f2dab2a0e0aebc7ee9eda6881c5f6e928d89dc759f70a7658363e20be + checksum: 10c0/f7b4824875088754a09b5afc9efe5424b56d061eb3af98052be8d7e62c9b1530c4de213e2353ca2f85eb312aec16a54ad550530f41ca626eeaf86ce694b9ece0 languageName: node linkType: hard -"@aws-sdk/credential-provider-http@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/credential-provider-http@npm:3.696.0" +"@aws-sdk/credential-provider-node@npm:3.738.0": + version: 3.738.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.738.0" dependencies: - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/fetch-http-handler": "npm:^4.1.1" - "@smithy/node-http-handler": "npm:^3.3.1" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/smithy-client": "npm:^3.4.4" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-stream": "npm:^3.3.1" + "@aws-sdk/credential-provider-env": "npm:3.734.0" + "@aws-sdk/credential-provider-http": "npm:3.734.0" + "@aws-sdk/credential-provider-ini": "npm:3.734.0" + "@aws-sdk/credential-provider-process": "npm:3.734.0" + "@aws-sdk/credential-provider-sso": "npm:3.734.0" + "@aws-sdk/credential-provider-web-identity": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/credential-provider-imds": "npm:^4.0.1" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/shared-ini-file-loader": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/383dd45600b0edbcc52c8e1101485569e631fb218f1776bbd4971e43a54be0adef458cb096d06d944353675136d2043da588424c78fff1c4eeeaf5229eb6774d + checksum: 10c0/c9ab6582ddc536113fe7e037179f3d145b7c42d661f5f118967227a519e7a51368307a2a5edb7d7768187ca5768d147bf0026be51c6bfff9c78ff6fba03b7407 languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.699.0": - version: 3.699.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.699.0" +"@aws-sdk/credential-provider-process@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.734.0" dependencies: - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/credential-provider-env": "npm:3.696.0" - "@aws-sdk/credential-provider-http": "npm:3.696.0" - "@aws-sdk/credential-provider-process": "npm:3.696.0" - "@aws-sdk/credential-provider-sso": "npm:3.699.0" - "@aws-sdk/credential-provider-web-identity": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/credential-provider-imds": "npm:^3.2.6" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/shared-ini-file-loader": "npm:^3.1.10" - "@smithy/types": "npm:^3.7.1" - tslib: "npm:^2.6.2" - peerDependencies: - "@aws-sdk/client-sts": ^3.699.0 - checksum: 10c0/1efb837da910ce4e8a43574f2fdceb82daecefbb7f3853d7ec97059a80a7193cf579d185d4f4b1ef67cb378db9c5d4d3058a252a75fd6a32caad257c6602765e - languageName: node - linkType: hard - -"@aws-sdk/credential-provider-node@npm:3.699.0": - version: 3.699.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.699.0" - dependencies: - "@aws-sdk/credential-provider-env": "npm:3.696.0" - "@aws-sdk/credential-provider-http": "npm:3.696.0" - "@aws-sdk/credential-provider-ini": "npm:3.699.0" - "@aws-sdk/credential-provider-process": "npm:3.696.0" - "@aws-sdk/credential-provider-sso": "npm:3.699.0" - "@aws-sdk/credential-provider-web-identity": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/credential-provider-imds": "npm:^3.2.6" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/shared-ini-file-loader": "npm:^3.1.10" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/shared-ini-file-loader": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/d2e690eb839d906409da293af7918ab20210c25428985f019b161b3cbf5deca681d4cc397c7d5a929aeaa0b90be8dbe3282bd5a9b17969c2e6ddb5c08d66e5c4 + checksum: 10c0/059beffaf6c6d880234c57935356918e3456d85348165ca42028c89e5aff86f6e87a8d4ad11b2d5fc04a22178c86daff3a59ffd02a7fdc2bd2ecf0829de981b1 languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.696.0" +"@aws-sdk/credential-provider-sso@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.734.0" dependencies: - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/shared-ini-file-loader": "npm:^3.1.10" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/client-sso": "npm:3.734.0" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/token-providers": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/shared-ini-file-loader": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/61741aa3d9cbbc88ea31bad7b7e8253aa4a0860eef215ff8d9a8196cdaa7ca8fa3bb438500c558abc9ce78b9490c540b12180acee21a7a9276491344931c5279 + checksum: 10c0/7a09107ef25574ce1f54261e6827a609d538a5d84c00a29e0381ee090fc372b012d288b8b6a074ec95a9557e098778799fbdd4a1bff105099da064041a0e8d39 languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.699.0": - version: 3.699.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.699.0" +"@aws-sdk/credential-provider-web-identity@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.734.0" dependencies: - "@aws-sdk/client-sso": "npm:3.696.0" - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/token-providers": "npm:3.699.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/shared-ini-file-loader": "npm:^3.1.10" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/nested-clients": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/be78a04f971d716b24e4bb9ce5ecec8ed8ffe9fdeebb07d4e6138c1b833529b5260d7381af8460b00f1659eb26018bffa51c9955b24a327374dd79c2fb2ce0ab + checksum: 10c0/6985306744419084580beb22877ef2fbdea4d341d6e1ef1255513b06370f4cde9d6ffc6b71394375a03687db3d7fef8c486250ff0116bbea2eba89cc513fa675 languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.696.0" +"@aws-sdk/middleware-host-header@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.734.0" dependencies: - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - peerDependencies: - "@aws-sdk/client-sts": ^3.696.0 - checksum: 10c0/a983867c72a6c8a1fd397f8051f4b6e64f5cac1ff5afff1b2d00815096d6c819d9ad155f4724cb27ebe3c13714eeb22cc545533f4ccaaa63980308b8bef2fa4c + checksum: 10c0/56e8501c3beda2961ebba56f1146849594edafa0d33ce2bdb04b62df9732d1218ffe89882333d87d76079798dc575af1756db4d7270916d8d83f8d9ef7c4798e languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.696.0" +"@aws-sdk/middleware-logger@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/middleware-logger@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/793c61a6af5533872888d9ee1b6765e06bd9716a9b1e497fb53b39da0bdbde2c379601ddf29bd2120cc520241143bae7763691f476f81721c290ee4e71264b6e + checksum: 10c0/dc690e546d0411929ff5888cd2dad56b7583f160ce4339f24d4963b9d11022f06da76d5f96c56d2ff2624493885254200788c763f113c26695875b8a229ee9a1 languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/middleware-logger@npm:3.696.0" +"@aws-sdk/middleware-recursion-detection@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/978145de80cb21a59d525fe9611d78e513df506e29123c39d425dd7c77043f9b57f05f03edde33864d9494a7ce76b7e2a48ec38ee4cee213b470ff1cd11c229f + checksum: 10c0/e46e5f99895a4370141b3439c58b94670fddd01d18bbda43a621cb0a5f2bb3384db66757f16da49815af52d29f2cfb8c5d12e273853ad34c919f4f71d078572f languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.696.0" +"@aws-sdk/middleware-user-agent@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@aws-sdk/util-endpoints": "npm:3.734.0" + "@smithy/core": "npm:^3.1.1" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/20db668ef267c62134e241511a6a5a49cbcacbf4eb28eb8fede903086e38bdc3d6d5277f5faae4bb0b3a5123a2f1c116b219c3c48d4b8aa49c12e97707736d51 + checksum: 10c0/aecda461346fc272d440ee9557588bb7379020ee5ffead61ca1e905f1ccdcd009d6aee53b364a6f9278f2a092608ca86c0650f02fb14f28f2ba99a34dd4af136 languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.696.0" +"@aws-sdk/nested-clients@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/nested-clients@npm:3.734.0" dependencies: - "@aws-sdk/core": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@aws-sdk/util-endpoints": "npm:3.696.0" - "@smithy/core": "npm:^2.5.3" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/types": "npm:^3.7.1" + "@aws-crypto/sha256-browser": "npm:5.2.0" + "@aws-crypto/sha256-js": "npm:5.2.0" + "@aws-sdk/core": "npm:3.734.0" + "@aws-sdk/middleware-host-header": "npm:3.734.0" + "@aws-sdk/middleware-logger": "npm:3.734.0" + "@aws-sdk/middleware-recursion-detection": "npm:3.734.0" + "@aws-sdk/middleware-user-agent": "npm:3.734.0" + "@aws-sdk/region-config-resolver": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@aws-sdk/util-endpoints": "npm:3.734.0" + "@aws-sdk/util-user-agent-browser": "npm:3.734.0" + "@aws-sdk/util-user-agent-node": "npm:3.734.0" + "@smithy/config-resolver": "npm:^4.0.1" + "@smithy/core": "npm:^3.1.1" + "@smithy/fetch-http-handler": "npm:^5.0.1" + "@smithy/hash-node": "npm:^4.0.1" + "@smithy/invalid-dependency": "npm:^4.0.1" + "@smithy/middleware-content-length": "npm:^4.0.1" + "@smithy/middleware-endpoint": "npm:^4.0.2" + "@smithy/middleware-retry": "npm:^4.0.3" + "@smithy/middleware-serde": "npm:^4.0.1" + "@smithy/middleware-stack": "npm:^4.0.1" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/node-http-handler": "npm:^4.0.2" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/smithy-client": "npm:^4.1.2" + "@smithy/types": "npm:^4.1.0" + "@smithy/url-parser": "npm:^4.0.1" + "@smithy/util-base64": "npm:^4.0.0" + "@smithy/util-body-length-browser": "npm:^4.0.0" + "@smithy/util-body-length-node": "npm:^4.0.0" + "@smithy/util-defaults-mode-browser": "npm:^4.0.3" + "@smithy/util-defaults-mode-node": "npm:^4.0.3" + "@smithy/util-endpoints": "npm:^3.0.1" + "@smithy/util-middleware": "npm:^4.0.1" + "@smithy/util-retry": "npm:^4.0.1" + "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/3af4fc987d3a3cfa9036c67f60fb939a02d801ccb2781ea0be653896dfb34382c4c895a2e3ce2c48f2db547aea09d871217d77c814331251faf10b5a472974f7 + checksum: 10c0/55877c3f8cac486183c2cfad34a650a4459c85d07ae08c804e9e64ad731d7607cd783156cf5646736c7026f44d3c4e76335bb42cc37fcf91cc98195b273fbd84 languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.696.0" +"@aws-sdk/region-config-resolver@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-config-provider": "npm:^3.0.0" - "@smithy/util-middleware": "npm:^3.0.10" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-config-provider": "npm:^4.0.0" + "@smithy/util-middleware": "npm:^4.0.1" tslib: "npm:^2.6.2" - checksum: 10c0/bc8765735dcd888a73336d1c0cac75fec0303446f2cd97c7818cec89d5d9f7e4b98705de1e751a47abbc3442d9237169dc967f175be27d9f828e65acb6c2d23a + checksum: 10c0/c1e026dcbe9d7529ec5efee979a868d0c868287d68e7e219bd730d887ab1ccf17ef48516477e57325fef55543217496bcfe7ba6d17d9ecad98cf8cf18d5ced63 languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.699.0": - version: 3.699.0 - resolution: "@aws-sdk/token-providers@npm:3.699.0" +"@aws-sdk/token-providers@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/token-providers@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/property-provider": "npm:^3.1.9" - "@smithy/shared-ini-file-loader": "npm:^3.1.10" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/nested-clients": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/shared-ini-file-loader": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - peerDependencies: - "@aws-sdk/client-sso-oidc": ^3.699.0 - checksum: 10c0/f69d005aff7e85d04930374651edb75937cadab5baaa365044bf1318207b208d7cf857142fdbb8e66055fb92043140531945986346661bc82322b7307b109d56 + checksum: 10c0/65a3696a930229d54a90e971158f399f3760200dfe080d1a4abc0cc6ceb130968036a9f2809be58ed0d35cd82357d32adfdbc391f3ed2ed89c4e0dcd114cb0de languageName: node linkType: hard -"@aws-sdk/types@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/types@npm:3.696.0" +"@aws-sdk/types@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/types@npm:3.734.0" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/3721939d5dd2a68fa4aee89d56b4817dd6c020721e2b2ea5b702968e7055826eb37e1924bc298007686304bf9bb6623bfec26b5cfd0663f2dba9d1b48437bb91 + checksum: 10c0/74313849619b8bce9e6a52c70fcdaa212574a443503c78bccdba77cdc7bc66b8cecefe461852e0bab7376cc2ec3e1891730b1a027be63efb47394115c8ddb856 languageName: node linkType: hard @@ -516,15 +643,15 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/util-endpoints@npm:3.696.0" +"@aws-sdk/util-endpoints@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/util-endpoints@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-endpoints": "npm:^2.1.6" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-endpoints": "npm:^3.0.1" tslib: "npm:^2.6.2" - checksum: 10c0/b32822b5f6924b8e3f88c7269afb216d07eccb338627a366ff3f94d98e7f5e4a9448dcf7c5ac97fc31fd0dfec5dfec52bbbeda65d84edd33fd509ed1dbfb1993 + checksum: 10c0/655d51da2fc57679be0e7c243cf2876f802c3d10df431cd56c00ec19de584d073c3838f2b917fb4b4d8c4e7d61a49af69c1b7135b8371619ae2339a793117005 languageName: node linkType: hard @@ -537,37 +664,37 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-browser@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.696.0" +"@aws-sdk/util-user-agent-browser@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.734.0" dependencies: - "@aws-sdk/types": "npm:3.696.0" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/types": "npm:^4.1.0" bowser: "npm:^2.11.0" tslib: "npm:^2.6.2" - checksum: 10c0/e72e35b21e6945d8a3cc46f92a5a6509842fe5439c2b1628f72d1f0932398d4aae2648c8a1779e2936aa4f4720047344790dc533f334ae18b20a43443d4a7b93 + checksum: 10c0/7fc8c5e29f3219f8abf1d0cff73dd6bb34f32a235473843e50f61375b1c05f4c49269cd956c9e4623c87c025e1eeef9fc699ae3389665459721bc11e00c25ead languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.696.0": - version: 3.696.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.696.0" +"@aws-sdk/util-user-agent-node@npm:3.734.0": + version: 3.734.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.734.0" dependencies: - "@aws-sdk/middleware-user-agent": "npm:3.696.0" - "@aws-sdk/types": "npm:3.696.0" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/types": "npm:^3.7.1" + "@aws-sdk/middleware-user-agent": "npm:3.734.0" + "@aws-sdk/types": "npm:3.734.0" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" peerDependencies: aws-crt: ">=1.0.0" peerDependenciesMeta: aws-crt: optional: true - checksum: 10c0/9dd7ef236ff13552f559d0e78bfffe424032dc4040306808542a2eedbe80801ae05389c415b770461b6b39a0b35cdbebf97e673e6f7132e05121708acee3db83 + checksum: 10c0/bae227776ede8d0c85193e257ac6e69b07f1ba94481544036fcdbdd633069fd7ebc19a0141c1e168ef58fc2c267da15a511e498552902ca15eac1a5240841f6e languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.22.13": +"@babel/code-frame@npm:^7.0.0": version: 7.24.7 resolution: "@babel/code-frame@npm:7.24.7" dependencies: @@ -623,6 +750,13 @@ __metadata: languageName: node linkType: hard +"@cfworker/json-schema@npm:^4.0.2": + version: 4.1.0 + resolution: "@cfworker/json-schema@npm:4.1.0" + checksum: 10c0/a7917d197ad9d5deb48a4d800ab41b3de5fe856745c164c5a4ed914263a0a11b08cf1b11040eb325e756e8f9418b07511109df856281dd10bf288f743d4fb3e6 + languageName: node + linkType: hard + "@colors/colors@npm:1.6.0, @colors/colors@npm:^1.6.0": version: 1.6.0 resolution: "@colors/colors@npm:1.6.0" @@ -1477,15 +1611,6 @@ __metadata: languageName: node linkType: hard -"@google-cloud/vertexai@npm:^1.9.2": - version: 1.9.2 - resolution: "@google-cloud/vertexai@npm:1.9.2" - dependencies: - google-auth-library: "npm:^9.1.0" - checksum: 10c0/d380fb9a1857019acdec6da99ab307bc3a9fe2d096138bf7ff7dc4dcc3c69ab8722a512a4ea365ac6c3311b808e230ecbddfd4ec949d98a69d22878a6bb002c5 - languageName: node - linkType: hard - "@googleapis/customsearch@npm:^3.2.0": version: 3.2.0 resolution: "@googleapis/customsearch@npm:3.2.0" @@ -1495,7 +1620,7 @@ __metadata: languageName: node linkType: hard -"@grpc/grpc-js@npm:^1.12.1, @grpc/grpc-js@npm:^1.12.4": +"@grpc/grpc-js@npm:^1.12.1": version: 1.12.5 resolution: "@grpc/grpc-js@npm:1.12.5" dependencies: @@ -1581,6 +1706,18 @@ __metadata: languageName: node linkType: hard +"@ibm-cloud/watsonx-ai@npm:^1.4.0": + version: 1.4.0 + resolution: "@ibm-cloud/watsonx-ai@npm:1.4.0" + dependencies: + "@langchain/textsplitters": "npm:^0.1.0" + "@types/node": "npm:^18.0.0" + extend: "npm:3.0.2" + ibm-cloud-sdk-core: "npm:^5.0.2" + checksum: 10c0/1833e07188e3b650de355334f9fff2216477c7c610aee7b69e005a86b77a5ec92e5a5ce8c92a1903a7a76001ebefa99e0d02fd2c82730b78cf968bc410d205d1 + languageName: node + linkType: hard + "@inquirer/figures@npm:^1.0.3": version: 1.0.7 resolution: "@inquirer/figures@npm:1.0.7" @@ -1651,24 +1788,17 @@ __metadata: languageName: node linkType: hard -"@jsdevtools/ono@npm:^7.1.3": - version: 7.1.3 - resolution: "@jsdevtools/ono@npm:7.1.3" - checksum: 10c0/a9f7e3e8e3bc315a34959934a5e2f874c423cf4eae64377d3fc9de0400ed9f36cb5fd5ebce3300d2e8f4085f557c4a8b591427a583729a87841fda46e6c216b9 - languageName: node - linkType: hard - -"@langchain/community@npm:~0.3.17": - version: 0.3.17 - resolution: "@langchain/community@npm:0.3.17" +"@langchain/community@npm:~0.3.28": + version: 0.3.28 + resolution: "@langchain/community@npm:0.3.28" dependencies: - "@langchain/openai": "npm:>=0.2.0 <0.4.0" + "@langchain/openai": "npm:>=0.2.0 <0.5.0" binary-extensions: "npm:^2.2.0" expr-eval: "npm:^2.0.2" flat: "npm:^5.0.2" js-yaml: "npm:^4.1.0" langchain: "npm:>=0.2.3 <0.3.0 || >=0.3.4 <0.4.0" - langsmith: "npm:^0.2.8" + langsmith: "npm:>=0.2.8 <0.4.0" uuid: "npm:^10.0.0" zod: "npm:^3.22.3" zod-to-json-schema: "npm:^3.22.5" @@ -1701,6 +1831,7 @@ __metadata: "@google-cloud/storage": ^6.10.1 || ^7.7.0 "@gradientai/nodejs-sdk": ^1.2.0 "@huggingface/inference": ^2.6.4 + "@huggingface/transformers": ^3.2.3 "@ibm-cloud/watsonx-ai": "*" "@lancedb/lancedb": ^0.12.0 "@langchain/core": ">=0.2.21 <0.4.0" @@ -1730,11 +1861,10 @@ __metadata: "@upstash/ratelimit": ^1.1.3 || ^2.0.3 "@upstash/redis": ^1.20.6 "@upstash/vector": ^1.1.1 - "@vercel/kv": ^0.2.3 - "@vercel/postgres": ^0.5.0 + "@vercel/kv": "*" + "@vercel/postgres": "*" "@writerai/writer-sdk": ^0.40.2 "@xata.io/client": ^0.28.0 - "@xenova/transformers": ^2.17.2 "@zilliz/milvus2-sdk-node": ">=2.3.5" apify-client: ^2.7.1 assemblyai: ^4.6.0 @@ -1755,6 +1885,7 @@ __metadata: duck-duck-scrape: ^2.2.5 epub2: ^3.0.1 faiss-node: ^0.5.1 + fast-xml-parser: "*" firebase-admin: ^11.9.0 || ^12.0.0 google-auth-library: "*" googleapis: "*" @@ -1795,9 +1926,9 @@ __metadata: voy-search: 0.6.2 weaviate-ts-client: "*" web-auth-library: ^1.0.3 + word-extractor: "*" ws: ^8.14.2 - youtube-transcript: ^1.0.6 - youtubei.js: ^9.1.0 + youtubei.js: "*" peerDependenciesMeta: "@arcjet/redact": optional: true @@ -1853,6 +1984,8 @@ __metadata: optional: true "@huggingface/inference": optional: true + "@huggingface/transformers": + optional: true "@lancedb/lancedb": optional: true "@layerup/layerup-security": @@ -1915,8 +2048,6 @@ __metadata: optional: true "@xata.io/client": optional: true - "@xenova/transformers": - optional: true "@zilliz/milvus2-sdk-node": optional: true apify-client: @@ -1957,6 +2088,8 @@ __metadata: optional: true faiss-node: optional: true + fast-xml-parser: + optional: true firebase-admin: optional: true google-auth-library: @@ -2033,43 +2166,44 @@ __metadata: optional: true web-auth-library: optional: true - ws: + word-extractor: optional: true - youtube-transcript: + ws: optional: true youtubei.js: optional: true - checksum: 10c0/cc240ca938e39c75248224484c9b5aeb6be9619758c9ffa174f3100ea63b5aa7397a39ac92c14e13a682156001b91483c09d602623c710d436dea17ad5faf78d + checksum: 10c0/387b4ff9da7dc48bca5ae84d4e8b2b0d241b8c5c45418a6aaa771de81b57a7e682b79821563c14f61608449930085ff16e7d8f9132850128fc2e3edaf9158751 languageName: node linkType: hard -"@langchain/core@npm:~0.3.22": - version: 0.3.22 - resolution: "@langchain/core@npm:0.3.22" +"@langchain/core@npm:~0.3.37": + version: 0.3.37 + resolution: "@langchain/core@npm:0.3.37" dependencies: + "@cfworker/json-schema": "npm:^4.0.2" ansi-styles: "npm:^5.0.0" camelcase: "npm:6" decamelize: "npm:1.2.0" js-tiktoken: "npm:^1.0.12" - langsmith: "npm:^0.2.8" + langsmith: "npm:>=0.2.8 <0.4.0" mustache: "npm:^4.2.0" p-queue: "npm:^6.6.2" p-retry: "npm:4" uuid: "npm:^10.0.0" zod: "npm:^3.22.4" zod-to-json-schema: "npm:^3.22.3" - checksum: 10c0/99050e331a71a568476195b458c1980f5a3361bc286e6031497aaa7075444ac1e319be51d34822f06c7fba22c0bb230c63e3dbab918e21f9ddeb90cc82b11e0e + checksum: 10c0/528af86ebd991cabd5e3c23b7361e410cdcb569bc20c0882db9edc92e8835c827cd2e61820729442a2d23f0de4022b772f86af243db1a5927642853f14c1e859 languageName: node linkType: hard -"@langchain/langgraph-checkpoint@npm:~0.0.13": - version: 0.0.13 - resolution: "@langchain/langgraph-checkpoint@npm:0.0.13" +"@langchain/langgraph-checkpoint@npm:~0.0.15": + version: 0.0.15 + resolution: "@langchain/langgraph-checkpoint@npm:0.0.15" dependencies: uuid: "npm:^10.0.0" peerDependencies: "@langchain/core": ">=0.2.31 <0.4.0" - checksum: 10c0/32ca419c76d7e5110230cfc23c2682e2207a862c763ac9a035c7d919a7e02286721dfec8ef03931b43f848943ba9125a1e09eccdbb00c74b06a0408bf6940391 + checksum: 10c0/2cf9ed958b3d849478ed44037c6d18638d180a2fbd367d212a4785e8cf59e8931a3419754080f20150b425777b219f24ea69720368273485923ccc198f81699a languageName: node linkType: hard @@ -2085,33 +2219,33 @@ __metadata: languageName: node linkType: hard -"@langchain/langgraph@npm:^0.2.39": - version: 0.2.39 - resolution: "@langchain/langgraph@npm:0.2.39" +"@langchain/langgraph@npm:^0.2.44": + version: 0.2.44 + resolution: "@langchain/langgraph@npm:0.2.44" dependencies: - "@langchain/langgraph-checkpoint": "npm:~0.0.13" + "@langchain/langgraph-checkpoint": "npm:~0.0.15" "@langchain/langgraph-sdk": "npm:~0.0.32" uuid: "npm:^10.0.0" zod: "npm:^3.23.8" peerDependencies: "@langchain/core": ">=0.2.36 <0.3.0 || >=0.3.9 < 0.4.0" - checksum: 10c0/1b6e7774efc929d182b0c19fcc43eb573a9ea0fc7b37d92d9894e186b51290b27a01b0e98f9e406e256271e6b46d16926b83fcfe4de1f045cf8913111d1dcd65 + checksum: 10c0/1a24dde3831704917abfdcd94117cfb84bbb039c2324c47b4a7d37c476c03c5ca93f7f6b9239dfe5707bdc877982a624cda2112154ea4fa7f376c6f6dcb154ef languageName: node linkType: hard -"@langchain/ollama@npm:^0.1.4": - version: 0.1.4 - resolution: "@langchain/ollama@npm:0.1.4" +"@langchain/ollama@npm:^0.1.5": + version: 0.1.5 + resolution: "@langchain/ollama@npm:0.1.5" dependencies: ollama: "npm:^0.5.9" uuid: "npm:^10.0.0" peerDependencies: "@langchain/core": ">=0.2.21 <0.4.0" - checksum: 10c0/713fadb9785255aac8354a92942922294129c590c31a44a843fcf9cd09bd99bef168bbd7a8bfd4bae75af21a2148711b2c7ba0a155864008c6cfd97b31d87185 + checksum: 10c0/dba0d6f06815f34441b4525329171cfac1db6ac387256dae50d5a2e2a09095be942b11b92aed1bb148cdbdcd80af58da18facae640eb4d2142d16cae3bbdd381 languageName: node linkType: hard -"@langchain/openai@npm:>=0.1.0 <0.4.0, @langchain/openai@npm:>=0.2.0 <0.4.0": +"@langchain/openai@npm:>=0.1.0 <0.4.0": version: 0.3.11 resolution: "@langchain/openai@npm:0.3.11" dependencies: @@ -2125,7 +2259,21 @@ __metadata: languageName: node linkType: hard -"@langchain/textsplitters@npm:>=0.0.0 <0.2.0": +"@langchain/openai@npm:>=0.2.0 <0.5.0": + version: 0.4.2 + resolution: "@langchain/openai@npm:0.4.2" + dependencies: + js-tiktoken: "npm:^1.0.12" + openai: "npm:^4.77.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.22.3" + peerDependencies: + "@langchain/core": ">=0.3.29 <0.4.0" + checksum: 10c0/0a17803c9a74e3b95f77a86e45705e32f0a76fdc9bbdb6d17f64ff6fa052356bc7067f0dccb57479087f236434f4aebf6731618c616331cab3bf48bf55a376c3 + languageName: node + linkType: hard + +"@langchain/textsplitters@npm:>=0.0.0 <0.2.0, @langchain/textsplitters@npm:^0.1.0": version: 0.1.0 resolution: "@langchain/textsplitters@npm:0.1.0" dependencies: @@ -2357,7 +2505,7 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/api@npm:1.x, @opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.9.0": +"@opentelemetry/api@npm:1.9.0, @opentelemetry/api@npm:1.x, @opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.9.0": version: 1.9.0 resolution: "@opentelemetry/api@npm:1.9.0" checksum: 10c0/9aae2fe6e8a3a3eeb6c1fdef78e1939cf05a0f37f8a4fae4d6bf2e09eb1e06f966ece85805626e01ba5fab48072b94f19b835449e58b6d26720ee19a58298add @@ -2868,44 +3016,6 @@ __metadata: languageName: node linkType: hard -"@redocly/ajv@npm:^8.11.2": - version: 8.11.2 - resolution: "@redocly/ajv@npm:8.11.2" - dependencies: - fast-deep-equal: "npm:^3.1.1" - json-schema-traverse: "npm:^1.0.0" - require-from-string: "npm:^2.0.2" - uri-js-replace: "npm:^1.0.1" - checksum: 10c0/249ca2e237f7b1248ee1018ba1ad3a739cb9f16e5f7fe821875948806980d65246c79ef7d5e7bd8db773c120e2cd5ce15aa47883893608e1965ca4d45c5572f4 - languageName: node - linkType: hard - -"@redocly/config@npm:^0.17.0": - version: 0.17.1 - resolution: "@redocly/config@npm:0.17.1" - checksum: 10c0/47dca7970d921d8f128422fbc14cdf2e74e4c3bb76b1ce3ce8e33e2c90d39b1c7ca96c84c108a23e6abae30120b1b761a0abc70d631590e8a78831b2335b942b - languageName: node - linkType: hard - -"@redocly/openapi-core@npm:^1.25.9": - version: 1.25.15 - resolution: "@redocly/openapi-core@npm:1.25.15" - dependencies: - "@redocly/ajv": "npm:^8.11.2" - "@redocly/config": "npm:^0.17.0" - colorette: "npm:^1.2.0" - https-proxy-agent: "npm:^7.0.4" - js-levenshtein: "npm:^1.1.6" - js-yaml: "npm:^4.1.0" - lodash.isequal: "npm:^4.5.0" - minimatch: "npm:^5.0.1" - node-fetch: "npm:^2.6.1" - pluralize: "npm:^8.0.0" - yaml-ast-parser: "npm:0.0.43" - checksum: 10c0/e7ae4b7b8d0fd84bda1c69e528f5c565d2651543c497aee850b889f7684a859376c98fe98cf78e6b1de9b077fd3407cd7bb1cca5a83d407cad27ad94472d0d04 - languageName: node - linkType: hard - "@release-it/conventional-changelog@npm:^8.0.2": version: 8.0.2 resolution: "@release-it/conventional-changelog@npm:8.0.2" @@ -3244,145 +3354,145 @@ __metadata: languageName: node linkType: hard -"@smithy/abort-controller@npm:^3.1.8": - version: 3.1.8 - resolution: "@smithy/abort-controller@npm:3.1.8" +"@smithy/abort-controller@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/abort-controller@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/ba62148955592036502880ac68a3fd1d4b0b70e3ace36ef9f1d0f507287795875598e2b9823ab6cdf542dcdb9fe75b57872694fc4a8108f7ab71938426a1c89c + checksum: 10c0/1ecd5c3454ced008463e6de826c294f31f6073ba91e22e443e0269ee0854d9376f73ea756b3acf77aa806a9a98e8b2568ce2e7f15ddf0a7816c99b7deefeef57 languageName: node linkType: hard -"@smithy/config-resolver@npm:^3.0.12": - version: 3.0.12 - resolution: "@smithy/config-resolver@npm:3.0.12" +"@smithy/config-resolver@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/config-resolver@npm:4.0.1" dependencies: - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-config-provider": "npm:^3.0.0" - "@smithy/util-middleware": "npm:^3.0.10" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-config-provider": "npm:^4.0.0" + "@smithy/util-middleware": "npm:^4.0.1" tslib: "npm:^2.6.2" - checksum: 10c0/01686446680e1a0e98051034671813f2ea78664ee8a6b22811a12fb937c1ac5b67b63ab9a6ae5995c61991344fbacebc906189cd063512ef1c1bdfb6c491941d + checksum: 10c0/4ec3486deb3017607ed1b9a42b4b806b78e2c7a00f6dd51b98ccb82d9f7506b206bd9412ec0d2a05e95bc2ac3fbbafe55b1ffce9faccc4086f837645f3f7e64d languageName: node linkType: hard -"@smithy/core@npm:^2.5.3, @smithy/core@npm:^2.5.4": - version: 2.5.4 - resolution: "@smithy/core@npm:2.5.4" - dependencies: - "@smithy/middleware-serde": "npm:^3.0.10" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-body-length-browser": "npm:^3.0.0" - "@smithy/util-middleware": "npm:^3.0.10" - "@smithy/util-stream": "npm:^3.3.1" - "@smithy/util-utf8": "npm:^3.0.0" +"@smithy/core@npm:^3.1.1, @smithy/core@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/core@npm:3.1.2" + dependencies: + "@smithy/middleware-serde": "npm:^4.0.2" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-body-length-browser": "npm:^4.0.0" + "@smithy/util-middleware": "npm:^4.0.1" + "@smithy/util-stream": "npm:^4.0.2" + "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/b966d6a7136cc9575370a75ad380fc27b85e83dd6615c04a413a3ef7ef2a496adb1a7e46b8daa256cfaf5993c4d14957834a1dfd416a3bb16402d6012229e2a0 + checksum: 10c0/971f6459041a088a9f571f5264e958c6b252f9d56aee210a2a4d4e6a2932a1f8754e48c37ef7c04c2c5e4073465cd6a2be255240c1bd45c30c7ff0669250f382 languageName: node linkType: hard -"@smithy/credential-provider-imds@npm:^3.2.6, @smithy/credential-provider-imds@npm:^3.2.7": - version: 3.2.7 - resolution: "@smithy/credential-provider-imds@npm:3.2.7" +"@smithy/credential-provider-imds@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/credential-provider-imds@npm:4.0.1" dependencies: - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/property-provider": "npm:^3.1.10" - "@smithy/types": "npm:^3.7.1" - "@smithy/url-parser": "npm:^3.0.10" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/url-parser": "npm:^4.0.1" tslib: "npm:^2.6.2" - checksum: 10c0/c0f1d0c439f26d046ef130057ea1727cb06cab96054ed23202d6eb7eaec3e5d8ef96380b69fbdec505c569e5f2b56ed68ba8c687f47d7d99607c30e5f6e469c1 + checksum: 10c0/76b5d82dfd2924f2b7a701fa159af54d3e9b16a644a210e3a74e5a3776bb28c2ffbdd342ed3f2bb1d2adf401e8144e84614523b1fad245b43e319e1d01fa1652 languageName: node linkType: hard -"@smithy/eventstream-codec@npm:^3.1.9": - version: 3.1.9 - resolution: "@smithy/eventstream-codec@npm:3.1.9" +"@smithy/eventstream-codec@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/eventstream-codec@npm:4.0.1" dependencies: "@aws-crypto/crc32": "npm:5.2.0" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-hex-encoding": "npm:^3.0.0" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-hex-encoding": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/857761ffcf4cb6296dcb28763417b2e8f8ab2001f2fbf26ae169a6a57b4e095af380d81361ce1eddaacd664c99205071f1fb4ad4e6c4949022e7e86a6dd51590 + checksum: 10c0/439262fddae863cadad83cc468418294d1d998134619dd67e2836cc93bbfa5b01448e852516046f03b62d0edcd558014b755b1fb0d71b9317268d5c3a5e55bbd languageName: node linkType: hard -"@smithy/eventstream-serde-browser@npm:^3.0.13": - version: 3.0.13 - resolution: "@smithy/eventstream-serde-browser@npm:3.0.13" +"@smithy/eventstream-serde-browser@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/eventstream-serde-browser@npm:4.0.1" dependencies: - "@smithy/eventstream-serde-universal": "npm:^3.0.12" - "@smithy/types": "npm:^3.7.1" + "@smithy/eventstream-serde-universal": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/ca3b37dbb3a4e8ea04e101c6555cc75b517544397b8d4daf5b6ba31ed38aa0ccb439d84b081e3660e9bcad7a9f9faa4e8fc006c145da6355635bcbd8fec80204 + checksum: 10c0/4766a8a735085dea1ed9aad486fa70cb04908a31843d4e698a28accc373a6dc80bc8abe9834d390f347326458c03424afbd7f7f9e59a66970b839de3d44940e1 languageName: node linkType: hard -"@smithy/eventstream-serde-config-resolver@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/eventstream-serde-config-resolver@npm:3.0.10" +"@smithy/eventstream-serde-config-resolver@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/eventstream-serde-config-resolver@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/0b5c4bc240ee092b2e5d968ceba54b7a1cd41a13dceb88fb7c4cb809debfa29b2b40addbdd19e4ca9ecd499f1947fbd06e2eeeb3e132f0b23250b37cef1a8903 + checksum: 10c0/4ba8bba39392025389c610ce984b612adfe0ed2b37f926e6ce2acafaf178d04aec395924ff37d2ad9534a28652fc64c4938b66b4bd1d2ff695ac8fcdcc4d356e languageName: node linkType: hard -"@smithy/eventstream-serde-node@npm:^3.0.12": - version: 3.0.12 - resolution: "@smithy/eventstream-serde-node@npm:3.0.12" +"@smithy/eventstream-serde-node@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/eventstream-serde-node@npm:4.0.1" dependencies: - "@smithy/eventstream-serde-universal": "npm:^3.0.12" - "@smithy/types": "npm:^3.7.1" + "@smithy/eventstream-serde-universal": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/7ec4b2d18992fd56be8fbd598ede7db1990512bfcc6f1a75b04dcd919d1aa328578c404ebde68779fd175259ee69044198ecd8c244d89e66e9cb05ffb9c14468 + checksum: 10c0/ed451ed4483ca62cb450a7540e43ba99b816e32da7bd306d14ea49dd3ceb8a37f791578a0e5d21caf9b9f75c36c69e025c7add117cf8b0510ad3ef32ac38b08c languageName: node linkType: hard -"@smithy/eventstream-serde-universal@npm:^3.0.12": - version: 3.0.12 - resolution: "@smithy/eventstream-serde-universal@npm:3.0.12" +"@smithy/eventstream-serde-universal@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/eventstream-serde-universal@npm:4.0.1" dependencies: - "@smithy/eventstream-codec": "npm:^3.1.9" - "@smithy/types": "npm:^3.7.1" + "@smithy/eventstream-codec": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/5247673c34cba51e9764503812e693dce9653b5c2341b02b9f500ff0ee00f3f47e7041ac10085b2ee916d340e24f6e346fa5a0fdc9820fd952bcc5d88f487178 + checksum: 10c0/8a1261fca8df7559bf78234f961903281b8602ffdbe0ff25f506cba25f013e4bb93bd8380703224fe63aeaf66e13bfebbdaf8083f38628750fc5f3c4ee07dff8 languageName: node linkType: hard -"@smithy/fetch-http-handler@npm:^4.1.1": - version: 4.1.1 - resolution: "@smithy/fetch-http-handler@npm:4.1.1" +"@smithy/fetch-http-handler@npm:^5.0.1": + version: 5.0.1 + resolution: "@smithy/fetch-http-handler@npm:5.0.1" dependencies: - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/querystring-builder": "npm:^3.0.10" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-base64": "npm:^3.0.0" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/querystring-builder": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-base64": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/e6307dfdb621a5481e7b263e2ad0a6c4b54982504c0c1ed8e2cd12d0b9b09dd99d0a7e4ebff9d8f30f1935bae24945f44cef98eca42ad119e4f1f23507ebb081 + checksum: 10c0/5123f6119de50d4c992ebf29b769382d7000db4ed8f564680c5727e2a8beb71664198eb2eaf7cb6152ab777f654d54cf9bff5a4658e1cfdeef2987eeea7f1149 languageName: node linkType: hard -"@smithy/hash-node@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/hash-node@npm:3.0.10" +"@smithy/hash-node@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/hash-node@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" - "@smithy/util-buffer-from": "npm:^3.0.0" - "@smithy/util-utf8": "npm:^3.0.0" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-buffer-from": "npm:^4.0.0" + "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/1134872f7c4ba2c35583bd0932bf0b8cb99f5f24e79235660a5e0e0914c1d587c0ee7d44d5d4a8c0ed0c77249fc3a154d28a994dc2f42e27cf212d2052a5d0bd + checksum: 10c0/d84be63a2c8a4aafa3b9f23ae76c9cf92a31fa7c49c85930424da1335259b29f6333c5c82d2e7bf689549290ffd0d995043c9ea6f05b0b2a8dfad1f649eac43f languageName: node linkType: hard -"@smithy/invalid-dependency@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/invalid-dependency@npm:3.0.10" +"@smithy/invalid-dependency@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/invalid-dependency@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/98bae16110f3f895991c1bd0a4291d9c900380b159c6d50d7327bd5161469f63510209ea3b08cfb0a12a66dfd9de8a1dc1ac71708b68f97c06b4ee6a2cde60b7 + checksum: 10c0/74bebdffb6845f6060eed482ad6e921df66af90d2f8c63f39a3bb334fa68a3e3aa8bd5cd7aa5f65628857e235e113895433895db910ba290633daa0df5725eb7 languageName: node linkType: hard @@ -3395,192 +3505,192 @@ __metadata: languageName: node linkType: hard -"@smithy/is-array-buffer@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/is-array-buffer@npm:3.0.0" +"@smithy/is-array-buffer@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/is-array-buffer@npm:4.0.0" dependencies: tslib: "npm:^2.6.2" - checksum: 10c0/44710d94b9e6655ebc02169c149ea2bc5d5b9e509b6b39511cfe61bac571412290f4b9c743d61e395822f014021fcb709dbb533f2f717c1ac2d5a356696c22fd + checksum: 10c0/ae393fbd5944d710443cd5dd225d1178ef7fb5d6259c14f3e1316ec75e401bda6cf86f7eb98bfd38e5ed76e664b810426a5756b916702cbd418f0933e15e7a3b languageName: node linkType: hard -"@smithy/middleware-content-length@npm:^3.0.12": - version: 3.0.12 - resolution: "@smithy/middleware-content-length@npm:3.0.12" +"@smithy/middleware-content-length@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/middleware-content-length@npm:4.0.1" dependencies: - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/types": "npm:^3.7.1" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/6d8db9bc97e3c09133ec9dc3114ca3e9ad3db5c234a2e109c3010e8661b488b08b8b2066bb2cd13da11d6ccffb9bbfbec1fa1552386d6e0d8d433b5041a6978b + checksum: 10c0/3dfbfe658cc8636e9e923a10151a32c6234897c4a86856e55fe4fadc322b3f3e977e50d15553afcb34cadb213de2d95a82af9c8f735e758f4dc21a031e8ecb17 languageName: node linkType: hard -"@smithy/middleware-endpoint@npm:^3.2.3, @smithy/middleware-endpoint@npm:^3.2.4": - version: 3.2.4 - resolution: "@smithy/middleware-endpoint@npm:3.2.4" - dependencies: - "@smithy/core": "npm:^2.5.4" - "@smithy/middleware-serde": "npm:^3.0.10" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/shared-ini-file-loader": "npm:^3.1.11" - "@smithy/types": "npm:^3.7.1" - "@smithy/url-parser": "npm:^3.0.10" - "@smithy/util-middleware": "npm:^3.0.10" +"@smithy/middleware-endpoint@npm:^4.0.2, @smithy/middleware-endpoint@npm:^4.0.3": + version: 4.0.3 + resolution: "@smithy/middleware-endpoint@npm:4.0.3" + dependencies: + "@smithy/core": "npm:^3.1.2" + "@smithy/middleware-serde": "npm:^4.0.2" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/shared-ini-file-loader": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/url-parser": "npm:^4.0.1" + "@smithy/util-middleware": "npm:^4.0.1" tslib: "npm:^2.6.2" - checksum: 10c0/3d7f6322e26cc05e0ecdfa19a7fdf422fdddc2816b109a84a76b947e688c2a1c03e08a43434f660cc568b00114628b5b0f50b45a6b6bf95501aeb7d55cdef461 + checksum: 10c0/9248c2faedb2249c9bd70cedd3fb07be6b739b3ac544a87a9be22c9e61795fcff420f53b81f223d7b0d83156dad2acfe10e614a3d92bffebf57bd93252533d31 languageName: node linkType: hard -"@smithy/middleware-retry@npm:^3.0.27": - version: 3.0.28 - resolution: "@smithy/middleware-retry@npm:3.0.28" - dependencies: - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/service-error-classification": "npm:^3.0.10" - "@smithy/smithy-client": "npm:^3.4.5" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-middleware": "npm:^3.0.10" - "@smithy/util-retry": "npm:^3.0.10" +"@smithy/middleware-retry@npm:^4.0.3": + version: 4.0.4 + resolution: "@smithy/middleware-retry@npm:4.0.4" + dependencies: + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/service-error-classification": "npm:^4.0.1" + "@smithy/smithy-client": "npm:^4.1.3" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-middleware": "npm:^4.0.1" + "@smithy/util-retry": "npm:^4.0.1" tslib: "npm:^2.6.2" uuid: "npm:^9.0.1" - checksum: 10c0/e2d4cf85a161ca711d4a6e9be420d2e9ae387d21d10ed68db2dbba9a5a76fdf6df03a16bfd9309075ea846661a7c292d073ad444cee82367a4389b12f543facc + checksum: 10c0/d15fecaca5758f0877cecd7de8f9434450850ada42e1e4ac871a181b90e4186dc6d6a912e5e7a4778bf637673823b24922de11cd4e3bbfb75036eef8152bb918 languageName: node linkType: hard -"@smithy/middleware-serde@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/middleware-serde@npm:3.0.10" +"@smithy/middleware-serde@npm:^4.0.1, @smithy/middleware-serde@npm:^4.0.2": + version: 4.0.2 + resolution: "@smithy/middleware-serde@npm:4.0.2" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/407ddbbf856c54ba5592b76aeeadc5a09a679614e8eaac91b8d662b6bd7e9cf16b60190eb15254befd34311ac137260c00433ac9126a734c6c60a256e55c0e69 + checksum: 10c0/b1efee86ecc37a063bdfdb89cf691c9b9627502473f2caa0c964c0648f7b550b7a49755a9b13cdfc11aebf1641cf3ae6f8b5f1895a20241960504936da9b3138 languageName: node linkType: hard -"@smithy/middleware-stack@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/middleware-stack@npm:3.0.10" +"@smithy/middleware-stack@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/middleware-stack@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/badcc1d275f7fd4957b6bce4e917060f971a4199e717cde7d3b4909be5d40e61c93328e2968e6885b4e8f7f5772e84ac743ddcc80031ab52efb47a3a3168beb0 + checksum: 10c0/b7f710e263e37a8c80c8d31c7d8fe5f66dec2955cde412054eefcc8df53905e1e2e53a01fd7930eb82c82a3a28eadd00e69f07dfc6e793b1d9272db58a982e9b languageName: node linkType: hard -"@smithy/node-config-provider@npm:^3.1.11": - version: 3.1.11 - resolution: "@smithy/node-config-provider@npm:3.1.11" +"@smithy/node-config-provider@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/node-config-provider@npm:4.0.1" dependencies: - "@smithy/property-provider": "npm:^3.1.10" - "@smithy/shared-ini-file-loader": "npm:^3.1.11" - "@smithy/types": "npm:^3.7.1" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/shared-ini-file-loader": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/b80a6d3f96979696499b27155c3e075f139fa6be6a2ea9688735bd1802f22bb41be4545dac9ea4db51519d22c6fb469e5bfad9063e2fa2b8771130d2f2d611a7 + checksum: 10c0/f8d3b1fe91eeba41426ec57d62cfbeaed027650b5549fb2ba5bc889c1cfb7880d4fdb5a484d231b3fb2a9c9023c1f4e8907a5d18d75b3787481cde9f87c4d9cb languageName: node linkType: hard -"@smithy/node-http-handler@npm:^3.3.1": - version: 3.3.1 - resolution: "@smithy/node-http-handler@npm:3.3.1" +"@smithy/node-http-handler@npm:^4.0.2": + version: 4.0.2 + resolution: "@smithy/node-http-handler@npm:4.0.2" dependencies: - "@smithy/abort-controller": "npm:^3.1.8" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/querystring-builder": "npm:^3.0.10" - "@smithy/types": "npm:^3.7.1" + "@smithy/abort-controller": "npm:^4.0.1" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/querystring-builder": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/32bb521a6cc7692ee33a362256661dbdccedfe448f116595bf6870f5c4343e3152daf5f9ae0b43d4a888016ea9161375858046f141513fb1d6c61545572712fc + checksum: 10c0/6a3446dcf3bf006cf55b065edfbe7636f2aa13073f2937e224890902de44b191a5214dce4cb61e98b1ad53889bdbb35386e8810a338bc75ea3743f8d4550a2ad languageName: node linkType: hard -"@smithy/property-provider@npm:^3.1.10, @smithy/property-provider@npm:^3.1.9": - version: 3.1.10 - resolution: "@smithy/property-provider@npm:3.1.10" +"@smithy/property-provider@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/property-provider@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/8dfcf30565b00287fd3c5ad2784f5c820264251dc9d1ac7334a224e40eb3eac4762a6198961d3e261bbcc738fc0c7c88ebd1007761e994569342f339ff503e1e + checksum: 10c0/43960a6bdf25944e1cc9d4ee83bf45ab5641f7e2068c46d5015166c0f035b1752e03847d7c15d3c013f5f0467441c9c5a8d6a0428f5401988035867709e4dea3 languageName: node linkType: hard -"@smithy/protocol-http@npm:^4.1.7": - version: 4.1.7 - resolution: "@smithy/protocol-http@npm:4.1.7" +"@smithy/protocol-http@npm:^5.0.1": + version: 5.0.1 + resolution: "@smithy/protocol-http@npm:5.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/1d5bf3e3ae9b3c7b58934163f56364228a42d50dcc64c83855be846d46f4954ed36b1bc3d949cd24bb5da3787d9b787637cffa5e3fdbbe8e1932e05ea14eace6 + checksum: 10c0/87b157cc86c23f7199acad237e5e0cc309b18a2a4162dfd8f99609f6cca403f832b645535e58173e2933b4d96ec71f2df16d04e1bdcf52b7b0fcbdbc0067de93 languageName: node linkType: hard -"@smithy/querystring-builder@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/querystring-builder@npm:3.0.10" +"@smithy/querystring-builder@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/querystring-builder@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" - "@smithy/util-uri-escape": "npm:^3.0.0" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-uri-escape": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/3a95519ee41f195c3b56978803d50ba2b5b2ce46fc0de063442cdab347528cd0e3c3d5cd0361bc33ceeec1893198cb3246c201026c3917349e0fb908ca8c3fb0 + checksum: 10c0/21f39e3a79458d343f3dec76b38598c49a34a3c4d1d3c23b6c8895eae2b610fb3c704f995a1730599ef7a881216ea064a25bb7dc8abe5bb1ee50dc6078ad97a4 languageName: node linkType: hard -"@smithy/querystring-parser@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/querystring-parser@npm:3.0.10" +"@smithy/querystring-parser@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/querystring-parser@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/e57c15087246e6a50348d557b670ded987ed5d88d4279a0a4896828d2be9fb2949f6b6c8656e5be45282c25cfa2fe62fe7fd9bd159ac30177f5b99181a5f4b74 + checksum: 10c0/10e5aba13fbb9a602299fb92f02142e291ab5c7cd221e0ca542981414533e081abdd7442de335f2267ee4a9ff8eba4d7ba848455df50d2771f0ddb8b7d8f9d8b languageName: node linkType: hard -"@smithy/service-error-classification@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/service-error-classification@npm:3.0.10" +"@smithy/service-error-classification@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/service-error-classification@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" - checksum: 10c0/9b9d5e0436d168f6a3290edb008292e2cc28ec7d2d9227858aff7c9c70d732336b71898eb0cb7fa76ea04c0180ec3afaf7930c92e881efd4b91023d7d8919044 + "@smithy/types": "npm:^4.1.0" + checksum: 10c0/de015fd140bf4e97da34a2283ce73971eb3b3aae53a257000dce0c99b8974a5e76bae9e517545ef58bd00ca8094c813cd1bcf0696c2c51e731418e2a769c744f languageName: node linkType: hard -"@smithy/shared-ini-file-loader@npm:^3.1.10, @smithy/shared-ini-file-loader@npm:^3.1.11": - version: 3.1.11 - resolution: "@smithy/shared-ini-file-loader@npm:3.1.11" +"@smithy/shared-ini-file-loader@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/shared-ini-file-loader@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/7479713932f00a6b85380fa8012ad893bb61e7ea614976e0ab2898767ff7dc91bb1dd813a4ec72e4850d6b10296f11032cd5dd916970042be376c19d0d3954b6 + checksum: 10c0/0f0173dbe61c8dac6847cc2c5115db5f1292c956c7f0559ce7bc8e5ed196a4b102977445ee1adb72206a15226a1098cdea01e92aa8ce19f4343f1135e7d37bcf languageName: node linkType: hard -"@smithy/signature-v4@npm:^4.2.2": - version: 4.2.3 - resolution: "@smithy/signature-v4@npm:4.2.3" - dependencies: - "@smithy/is-array-buffer": "npm:^3.0.0" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-hex-encoding": "npm:^3.0.0" - "@smithy/util-middleware": "npm:^3.0.10" - "@smithy/util-uri-escape": "npm:^3.0.0" - "@smithy/util-utf8": "npm:^3.0.0" +"@smithy/signature-v4@npm:^5.0.1": + version: 5.0.1 + resolution: "@smithy/signature-v4@npm:5.0.1" + dependencies: + "@smithy/is-array-buffer": "npm:^4.0.0" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-hex-encoding": "npm:^4.0.0" + "@smithy/util-middleware": "npm:^4.0.1" + "@smithy/util-uri-escape": "npm:^4.0.0" + "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/7cecc9c73cb863e15c4517601a2a1e82b3728fbe174c533d807beb54f59f66792891c82955d874baa27640201d719b6ea63497b376e4c7cd09d5d52ea36fe3fc + checksum: 10c0/a7f118642c9641f813098faad355fc5b54ae215fec589fb238d72d44149248c02e32dcfe034000f151ab665450542df88c70d269f9a3233e01a905ec03512514 languageName: node linkType: hard -"@smithy/smithy-client@npm:^3.4.4, @smithy/smithy-client@npm:^3.4.5": - version: 3.4.5 - resolution: "@smithy/smithy-client@npm:3.4.5" - dependencies: - "@smithy/core": "npm:^2.5.4" - "@smithy/middleware-endpoint": "npm:^3.2.4" - "@smithy/middleware-stack": "npm:^3.0.10" - "@smithy/protocol-http": "npm:^4.1.7" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-stream": "npm:^3.3.1" +"@smithy/smithy-client@npm:^4.1.2, @smithy/smithy-client@npm:^4.1.3": + version: 4.1.3 + resolution: "@smithy/smithy-client@npm:4.1.3" + dependencies: + "@smithy/core": "npm:^3.1.2" + "@smithy/middleware-endpoint": "npm:^4.0.3" + "@smithy/middleware-stack": "npm:^4.0.1" + "@smithy/protocol-http": "npm:^5.0.1" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-stream": "npm:^4.0.2" tslib: "npm:^2.6.2" - checksum: 10c0/b9a56e20133d29ab2339d4d3b7b28601b7a98b899a7b0a5371c2c698c48e60c733fdad42fe1dec096c48a9de10d79de170f6eaa98a1bc1bd0c18a4b63c545e0d + checksum: 10c0/d02044c4ff9e5e6d4c9fbc04b18c4718b1394c72ea5a926e2b6ea47da10a69b87dc27cd48da6c1a0272cc3f4c797591b4016d01bbba1b26397aab404231eda6c languageName: node linkType: hard @@ -3593,52 +3703,52 @@ __metadata: languageName: node linkType: hard -"@smithy/types@npm:^3.7.1": - version: 3.7.1 - resolution: "@smithy/types@npm:3.7.1" +"@smithy/types@npm:^4.1.0": + version: 4.1.0 + resolution: "@smithy/types@npm:4.1.0" dependencies: tslib: "npm:^2.6.2" - checksum: 10c0/c82ad86087b6e0d2261f581a8cca1694a0af31458d7789ff5d8787973b4940a6d035082005dfc87857f266ee9cb512f7eb80535917e6dd6eb3d7d70c45d0f9aa + checksum: 10c0/d8817145ea043c5b29783df747ed47c3a1c584fd9d02bbdb609d38b7cb4dded1197ac214ae112744c86abe0537a314dae0edbc0e752bb639ef2d9fb84c67a9d9 languageName: node linkType: hard -"@smithy/url-parser@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/url-parser@npm:3.0.10" +"@smithy/url-parser@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/url-parser@npm:4.0.1" dependencies: - "@smithy/querystring-parser": "npm:^3.0.10" - "@smithy/types": "npm:^3.7.1" + "@smithy/querystring-parser": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/29c9d03ee86936ffb3bdcbb84ce14b7dacaadb2e61b5ed78ee91dfacb98e42048c70c718077347f0f39bce676168ba5fc1f1a8b19988f89f735c0b5e17cdc77a + checksum: 10c0/fc969b55857b3bcdc920f54bbb9b0c88b5c7695ac7100bea1c7038fd4c9a09ebe0fbb38c4839d39acea28da0d8cb4fea71ffbf362d8aec295acbb94c1b45fc86 languageName: node linkType: hard -"@smithy/util-base64@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-base64@npm:3.0.0" +"@smithy/util-base64@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-base64@npm:4.0.0" dependencies: - "@smithy/util-buffer-from": "npm:^3.0.0" - "@smithy/util-utf8": "npm:^3.0.0" + "@smithy/util-buffer-from": "npm:^4.0.0" + "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/5c05c3505bd1ac4c1e04ec0e22ad1c9e0c61756945735861614f9e46146369a1a112dd0895602475822c18b8f1fe0cc3fb9e45c99a4e7fb03308969c673cf043 + checksum: 10c0/ad18ec66cc357c189eef358d96876b114faf7086b13e47e009b265d0ff80cec046052500489c183957b3a036768409acdd1a373e01074cc002ca6983f780cffc languageName: node linkType: hard -"@smithy/util-body-length-browser@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-body-length-browser@npm:3.0.0" +"@smithy/util-body-length-browser@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-body-length-browser@npm:4.0.0" dependencies: tslib: "npm:^2.6.2" - checksum: 10c0/cfb595e814334fe7bb78e8381141cc7364f66bff0c1d672680f4abb99361ef66fbdb9468fa1dbabcd5753254b2b05c59c907fa9d600b36e6e4b8423eccf412f7 + checksum: 10c0/574a10934024a86556e9dcde1a9776170284326c3dfcc034afa128cc5a33c1c8179fca9cfb622ef8be5f2004316cc3f427badccceb943e829105536ec26306d9 languageName: node linkType: hard -"@smithy/util-body-length-node@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-body-length-node@npm:3.0.0" +"@smithy/util-body-length-node@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-body-length-node@npm:4.0.0" dependencies: tslib: "npm:^2.6.2" - checksum: 10c0/6f779848e7c81051364cf6e40ed61034a06fa8df3480398528baae54d9b69622abc7d068869e33dbe51fef2bbc6fda3f548ac59644a0f10545a54c87bc3a4391 + checksum: 10c0/e91fd3816767606c5f786166ada26440457fceb60f96653b3d624dcf762a8c650e513c275ff3f647cb081c63c283cc178853a7ed9aa224abc8ece4eeeef7a1dd languageName: node linkType: hard @@ -3652,116 +3762,116 @@ __metadata: languageName: node linkType: hard -"@smithy/util-buffer-from@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-buffer-from@npm:3.0.0" +"@smithy/util-buffer-from@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-buffer-from@npm:4.0.0" dependencies: - "@smithy/is-array-buffer": "npm:^3.0.0" + "@smithy/is-array-buffer": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/b10fb81ef34f95418f27c9123c2c1774e690dd447e8064184688c553156bdec46d2ba1b1ae3bad7edd2b58a5ef32ac569e1ad814b36e7ee05eba10526d329983 + checksum: 10c0/be7cd33b6cb91503982b297716251e67cdca02819a15797632091cadab2dc0b4a147fff0709a0aa9bbc0b82a2644a7ed7c8afdd2194d5093cee2e9605b3a9f6f languageName: node linkType: hard -"@smithy/util-config-provider@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-config-provider@npm:3.0.0" +"@smithy/util-config-provider@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-config-provider@npm:4.0.0" dependencies: tslib: "npm:^2.6.2" - checksum: 10c0/a2c25eac31223eddea306beff2bb3c32e8761f8cb50e8cb2a9d61417a5040e9565dc715a655787e99a37465fdd35bbd0668ff36e06043a5f6b7be48a76974792 + checksum: 10c0/cd9498d5f77a73aadd575084bcb22d2bb5945bac4605d605d36f2efe3f165f2b60f4dc88b7a62c2ed082ffa4b2c2f19621d0859f18399edbc2b5988d92e4649f languageName: node linkType: hard -"@smithy/util-defaults-mode-browser@npm:^3.0.27": - version: 3.0.28 - resolution: "@smithy/util-defaults-mode-browser@npm:3.0.28" +"@smithy/util-defaults-mode-browser@npm:^4.0.3": + version: 4.0.4 + resolution: "@smithy/util-defaults-mode-browser@npm:4.0.4" dependencies: - "@smithy/property-provider": "npm:^3.1.10" - "@smithy/smithy-client": "npm:^3.4.5" - "@smithy/types": "npm:^3.7.1" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/smithy-client": "npm:^4.1.3" + "@smithy/types": "npm:^4.1.0" bowser: "npm:^2.11.0" tslib: "npm:^2.6.2" - checksum: 10c0/bba460478f70ef25312d3e5408e0caa5feaf0b2af11aedcfd9e4719874884b507edd2503790d938e22fff5387f1dd63cd33c920dddf16cb3e6a6588575be5522 + checksum: 10c0/20c23f94a50d807abaa7dc00e5ec6adb3179672fc967018075e88b5c725ae8d87d8569c9987108b022b856428d55a7abb667d478f8756ad57159d7e65651d3b6 languageName: node linkType: hard -"@smithy/util-defaults-mode-node@npm:^3.0.27": - version: 3.0.28 - resolution: "@smithy/util-defaults-mode-node@npm:3.0.28" - dependencies: - "@smithy/config-resolver": "npm:^3.0.12" - "@smithy/credential-provider-imds": "npm:^3.2.7" - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/property-provider": "npm:^3.1.10" - "@smithy/smithy-client": "npm:^3.4.5" - "@smithy/types": "npm:^3.7.1" +"@smithy/util-defaults-mode-node@npm:^4.0.3": + version: 4.0.4 + resolution: "@smithy/util-defaults-mode-node@npm:4.0.4" + dependencies: + "@smithy/config-resolver": "npm:^4.0.1" + "@smithy/credential-provider-imds": "npm:^4.0.1" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/property-provider": "npm:^4.0.1" + "@smithy/smithy-client": "npm:^4.1.3" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/6b49892d58d9c38e92e9b82ca7cdc2c9627f56fb3bc62ddef9bb5f197c38df1b7089c73c2256281888aba48a0ddd9319eb86a616af7ab40342f07aea1136dd47 + checksum: 10c0/90c213b09c694f1f2d71b147dbbd398be7283a30b0071e85ec968713073e4d5a4cac283426682ee2c09ee50a279a9a6f7f738c45887ba8005eb3a0d4f33d2b11 languageName: node linkType: hard -"@smithy/util-endpoints@npm:^2.1.6": - version: 2.1.6 - resolution: "@smithy/util-endpoints@npm:2.1.6" +"@smithy/util-endpoints@npm:^3.0.1": + version: 3.0.1 + resolution: "@smithy/util-endpoints@npm:3.0.1" dependencies: - "@smithy/node-config-provider": "npm:^3.1.11" - "@smithy/types": "npm:^3.7.1" + "@smithy/node-config-provider": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/a1cd8cc912fb67ee07e6095990f3b237b2e53f73e493b2aaa85af904c4ce73ce739a68e4d3330a37b8c96cd00b6845205b836ee4ced97cf622413a34b913adc2 + checksum: 10c0/fed80f300e6a6e69873e613cdd12f640d33a19fc09a41e3afd536f7ea36f7785edd96fbd0402b6980a0e5dfc9bcb8b37f503d522b4ef317f31f4fd0100c466ff languageName: node linkType: hard -"@smithy/util-hex-encoding@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-hex-encoding@npm:3.0.0" +"@smithy/util-hex-encoding@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-hex-encoding@npm:4.0.0" dependencies: tslib: "npm:^2.6.2" - checksum: 10c0/d2fa7270853cc8f22c4f4635c72bf52e303731a68a3999e3ea9da1d38b6bf08c0f884e7d20b65741e3bc68bb3821e1abd1c3406d7a3dce8fc02df019aea59162 + checksum: 10c0/70dbb3aa1a79aff3329d07a66411ff26398df338bdd8a6d077b438231afe3dc86d9a7022204baddecd8bc633f059d5c841fa916d81dd7447ea79b64148f386d2 languageName: node linkType: hard -"@smithy/util-middleware@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/util-middleware@npm:3.0.10" +"@smithy/util-middleware@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/util-middleware@npm:4.0.1" dependencies: - "@smithy/types": "npm:^3.7.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/01bbbd31044ab742985acac36aa61e240db16ed7dfa22b73779877eb5db0af14351883506fb34d2ee964598d72f4998d79409c271a62310647fb28faccd855a2 + checksum: 10c0/1dd2b058f392fb6788809f14c2c1d53411f79f6e9f88b515ffd36792f9f5939fe4af96fb5b0486a3d0cd30181783b7a5393dce2e8b83ba62db7c6d3af6572eff languageName: node linkType: hard -"@smithy/util-retry@npm:^3.0.10": - version: 3.0.10 - resolution: "@smithy/util-retry@npm:3.0.10" +"@smithy/util-retry@npm:^4.0.1": + version: 4.0.1 + resolution: "@smithy/util-retry@npm:4.0.1" dependencies: - "@smithy/service-error-classification": "npm:^3.0.10" - "@smithy/types": "npm:^3.7.1" + "@smithy/service-error-classification": "npm:^4.0.1" + "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/ac1dcfd2e4ea1a4f99a42447b7fd8e4ea21589dfd87e9bc6a7bdf1d26e1f93ec71aa4cfde5e024b00d9b713b889f9db20a8d81b9e3ccdbe6f72bedb6269f01b8 + checksum: 10c0/93ef89572651b8a30b9a648292660ae9532508ec6d2577afc62e1d9125fe6d14086e0f70a2981bf9f12256b41a57152368b5ed839cdd2df47ba78dd005615173 languageName: node linkType: hard -"@smithy/util-stream@npm:^3.3.1": - version: 3.3.1 - resolution: "@smithy/util-stream@npm:3.3.1" - dependencies: - "@smithy/fetch-http-handler": "npm:^4.1.1" - "@smithy/node-http-handler": "npm:^3.3.1" - "@smithy/types": "npm:^3.7.1" - "@smithy/util-base64": "npm:^3.0.0" - "@smithy/util-buffer-from": "npm:^3.0.0" - "@smithy/util-hex-encoding": "npm:^3.0.0" - "@smithy/util-utf8": "npm:^3.0.0" +"@smithy/util-stream@npm:^4.0.2": + version: 4.0.2 + resolution: "@smithy/util-stream@npm:4.0.2" + dependencies: + "@smithy/fetch-http-handler": "npm:^5.0.1" + "@smithy/node-http-handler": "npm:^4.0.2" + "@smithy/types": "npm:^4.1.0" + "@smithy/util-base64": "npm:^4.0.0" + "@smithy/util-buffer-from": "npm:^4.0.0" + "@smithy/util-hex-encoding": "npm:^4.0.0" + "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/dafaf4448e69cd65eda2bc7c43a48e945905808f635397e290b4e19cff2705ab444f1798829ca48b9a9efe4b7e569180eb6275ca42d04ce5abcf2dc9443f9c67 + checksum: 10c0/f9c9afc51189e4d3d33e119fd639970e7abbb598c50ce20f493a2656a469177be4e8a52aa9b8c42ce1f86dd5d71333364a18d179e515e6cc7d28d636cc985f55 languageName: node linkType: hard -"@smithy/util-uri-escape@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-uri-escape@npm:3.0.0" +"@smithy/util-uri-escape@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-uri-escape@npm:4.0.0" dependencies: tslib: "npm:^2.6.2" - checksum: 10c0/b8d831348412cfafd9300069e74a12e0075b5e786d7ef6a210ba4ab576001c2525653eec68b71dfe6d7aef71c52f547404c4f0345c0fb476a67277f9d44b1156 + checksum: 10c0/23984624060756adba8aa4ab1693fe6b387ee5064d8ec4dfd39bb5908c4ee8b9c3f2dc755da9b07505d8e3ce1338c1867abfa74158931e4728bf3cfcf2c05c3d languageName: node linkType: hard @@ -3775,13 +3885,13 @@ __metadata: languageName: node linkType: hard -"@smithy/util-utf8@npm:^3.0.0": - version: 3.0.0 - resolution: "@smithy/util-utf8@npm:3.0.0" +"@smithy/util-utf8@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-utf8@npm:4.0.0" dependencies: - "@smithy/util-buffer-from": "npm:^3.0.0" + "@smithy/util-buffer-from": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/b568ed84b4770d2ae9b632eb85603765195a791f045af7f47df1369dc26b001056f4edf488b42ca1cd6d852d0155ad306a0d6531e912cb4e633c0d87abaa8899 + checksum: 10c0/28a5a5372cbf0b3d2e32dd16f79b04c2aec6f704cf13789db922e9686fde38dde0171491cfa4c2c201595d54752a319faaeeed3c325329610887694431e28c98 languageName: node linkType: hard @@ -3954,6 +4064,13 @@ __metadata: languageName: node linkType: hard +"@tokenizer/token@npm:^0.3.0": + version: 0.3.0 + resolution: "@tokenizer/token@npm:0.3.0" + checksum: 10c0/7ab9a822d4b5ff3f5bca7f7d14d46bdd8432528e028db4a52be7fbf90c7f495cc1af1324691dda2813c6af8dc4b8eb29de3107d4508165f9aa5b53e7d501f155 + languageName: node + linkType: hard + "@tootallnate/once@npm:1": version: 1.1.2 resolution: "@tootallnate/once@npm:1.1.2" @@ -3991,7 +4108,7 @@ __metadata: languageName: node linkType: hard -"@types/debug@npm:^4.0.0, @types/debug@npm:^4.1.8": +"@types/debug@npm:^4.0.0, @types/debug@npm:^4.1.12, @types/debug@npm:^4.1.8": version: 4.1.12 resolution: "@types/debug@npm:4.1.12" dependencies: @@ -4000,6 +4117,13 @@ __metadata: languageName: node linkType: hard +"@types/diff-match-patch@npm:^1.0.36": + version: 1.0.36 + resolution: "@types/diff-match-patch@npm:1.0.36" + checksum: 10c0/0bad011ab138baa8bde94e7815064bb881f010452463272644ddbbb0590659cb93f7aa2776ff442c6721d70f202839e1053f8aa62d801cc4166f7a3ea9130055 + languageName: node + linkType: hard + "@types/eslint-config-prettier@npm:^6.11.3": version: 6.11.3 resolution: "@types/eslint-config-prettier@npm:6.11.3" @@ -4075,7 +4199,7 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:*, @types/lodash@npm:^4.17.7": +"@types/lodash@npm:*": version: 4.17.7 resolution: "@types/lodash@npm:4.17.7" checksum: 10c0/40c965b5ffdcf7ff5c9105307ee08b782da228c01b5c0529122c554c64f6b7168fc8f11dc79aa7bae4e67e17efafaba685dc3a47e294dbf52a65ed2b67100561 @@ -4149,6 +4273,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^18.0.0": + version: 18.19.74 + resolution: "@types/node@npm:18.19.74" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10c0/365d9cc2af934965aa6a8471e24ae80add815c15dc094e42a320c57c1ea5416032f0b7ef6f23e32174c34811fbb8d89ea8eaa1396548610fbb8ba317b6e93fbf + languageName: node + linkType: hard + "@types/node@npm:^18.11.18": version: 18.19.45 resolution: "@types/node@npm:18.19.45" @@ -4167,6 +4300,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:~10.14.19": + version: 10.14.22 + resolution: "@types/node@npm:10.14.22" + checksum: 10c0/2f44a76ec0e23e542142c1af62257ce4ff97e3f7cb82aa8db9919aca6b823644200bd145cf0b783d530865a2acf4cd9bb72bb0b15c17cbb2df117b2eae9b8f86 + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.1": version: 2.4.4 resolution: "@types/normalize-package-data@npm:2.4.4" @@ -4211,6 +4351,13 @@ __metadata: languageName: node linkType: hard +"@types/tough-cookie@npm:^4.0.0": + version: 4.0.5 + resolution: "@types/tough-cookie@npm:4.0.5" + checksum: 10c0/68c6921721a3dcb40451543db2174a145ef915bc8bcbe7ad4e59194a0238e776e782b896c7a59f4b93ac6acefca9161fccb31d1ce3b3445cb6faa467297fb473 + languageName: node + linkType: hard + "@types/triple-beam@npm:^1.3.2": version: 1.3.5 resolution: "@types/triple-beam@npm:1.3.5" @@ -4582,6 +4729,28 @@ __metadata: languageName: node linkType: hard +"ai@npm:^4.1.24": + version: 4.1.24 + resolution: "ai@npm:4.1.24" + dependencies: + "@ai-sdk/provider": "npm:1.0.7" + "@ai-sdk/provider-utils": "npm:2.1.6" + "@ai-sdk/react": "npm:1.1.10" + "@ai-sdk/ui-utils": "npm:1.1.10" + "@opentelemetry/api": "npm:1.9.0" + jsondiffpatch: "npm:0.6.0" + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + zod: ^3.0.0 + peerDependenciesMeta: + react: + optional: true + zod: + optional: true + checksum: 10c0/3f6890bcb1ea5335db4a0852edab94c5235821b28b8ae78bddd634c808b97b1722ce55ac2e0b9f9d0f4a7386a43f2026d850e27a8ac371fcfcf114fa0a3ecea6 + languageName: node + linkType: hard + "ajv-formats@npm:^3.0.1": version: 3.0.1 resolution: "ajv-formats@npm:3.0.1" @@ -4629,7 +4798,7 @@ __metadata: languageName: node linkType: hard -"ansi-colors@npm:^4.1.1, ansi-colors@npm:^4.1.3": +"ansi-colors@npm:^4.1.1": version: 4.1.3 resolution: "ansi-colors@npm:4.1.3" checksum: 10c0/ec87a2f59902f74e61eada7f6e6fe20094a628dab765cfdbd03c3477599368768cffccdb5d3bb19a1b6c99126783a143b1fee31aab729b31ffe5836c7e5e28b9 @@ -4851,7 +5020,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.4.0": +"axios@npm:1.7.4, axios@npm:^1.4.0": version: 1.7.4 resolution: "axios@npm:1.7.4" dependencies: @@ -4862,6 +5031,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:1.7.9": + version: 1.7.9 + resolution: "axios@npm:1.7.9" + dependencies: + follow-redirects: "npm:^1.15.6" + form-data: "npm:^4.0.0" + proxy-from-env: "npm:^1.1.0" + checksum: 10c0/b7a41e24b59fee5f0f26c1fc844b45b17442832eb3a0fb42dd4f1430eb4abc571fe168e67913e8a1d91c993232bd1d1ab03e20e4d1fee8c6147649b576fc1b0b + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -4887,21 +5067,23 @@ __metadata: version: 0.0.0-use.local resolution: "bee-agent-framework@workspace:." dependencies: + "@ai-sdk/amazon-bedrock": "npm:^1.1.5" + "@ai-sdk/azure": "npm:^1.1.2" + "@ai-sdk/google-vertex": "npm:^2.1.6" + "@ai-sdk/groq": "npm:^1.1.6" + "@ai-sdk/openai": "npm:^1.1.2" "@ai-zen/node-fetch-event-source": "npm:^2.1.4" - "@aws-sdk/client-bedrock-runtime": "npm:^3.706.0" "@commitlint/cli": "npm:^19.6.0" "@commitlint/config-conventional": "npm:^19.6.0" "@elastic/elasticsearch": "npm:^8.16.2" "@eslint/js": "npm:^9.16.0" "@eslint/markdown": "npm:^6.2.1" - "@google-cloud/vertexai": "npm:^1.9.2" "@googleapis/customsearch": "npm:^3.2.0" - "@grpc/grpc-js": "npm:^1.12.4" - "@grpc/proto-loader": "npm:^0.7.13" - "@langchain/community": "npm:~0.3.17" - "@langchain/core": "npm:~0.3.22" - "@langchain/langgraph": "npm:^0.2.39" - "@langchain/ollama": "npm:^0.1.4" + "@ibm-cloud/watsonx-ai": "npm:^1.4.0" + "@langchain/community": "npm:~0.3.28" + "@langchain/core": "npm:~0.3.37" + "@langchain/langgraph": "npm:^0.2.44" + "@langchain/ollama": "npm:^0.1.5" "@modelcontextprotocol/sdk": "npm:^1.0.4" "@opentelemetry/api": "npm:^1.9.0" "@opentelemetry/instrumentation": "npm:^0.56.0" @@ -4925,6 +5107,7 @@ __metadata: "@types/object-hash": "npm:^3.0.6" "@types/turndown": "npm:^5.0.5" "@zilliz/milvus2-sdk-node": "npm:^2.5.1" + ai: "npm:^4.1.24" ajv: "npm:^8.17.1" ajv-formats: "npm:^3.0.1" docsify-cli: "npm:^4.4.4" @@ -4936,12 +5119,10 @@ __metadata: eslint-plugin-unused-imports: "npm:^4.1.4" fast-xml-parser: "npm:^4.5.0" glob: "npm:^11.0.0" - groq-sdk: "npm:^0.9.0" header-generator: "npm:^2.1.57" husky: "npm:^9.1.7" + ibm-cloud-sdk-core: "npm:^5.1.2" joplin-turndown-plugin-gfm: "npm:^1.0.12" - js-yaml: "npm:^4.1.0" - json-schema-to-typescript: "npm:^15.0.3" jsonrepair: "npm:^3.11.1" langchain: "npm:~0.3.6" linkinator: "npm:^6.1.2" @@ -4949,11 +5130,7 @@ __metadata: mathjs: "npm:^14.0.0" mustache: "npm:^4.2.0" object-hash: "npm:^3.0.0" - ollama: "npm:^0.5.11" - openai: "npm:^4.76.0" - openai-chat-tokens: "npm:^0.2.8" - openapi-fetch: "npm:^0.13.3" - openapi-typescript: "npm:^7.4.4" + ollama-ai-provider: "npm:^1.2.0" p-queue-compat: "npm:^1.0.227" p-throttle: "npm:^7.0.0" picocolors: "npm:^1.1.1" @@ -4971,49 +5148,49 @@ __metadata: string-comparison: "npm:^1.3.0" string-strip-html: "npm:^13.4.8" strip-ansi: "npm:^7.1.0" - temp-dir: "npm:^3.0.0" - tsc-files: "npm:^1.1.4" - tsup: "npm:^8.3.5" + tsup: "npm:^8.3.6" tsx: "npm:^4.19.2" turndown: "npm:^7.2.0" - typescript: "npm:^5.7.2" + typescript: "npm:^5.7.3" typescript-eslint: "npm:^8.18.1" - vite-tsconfig-paths: "npm:^5.1.3" + vite-tsconfig-paths: "npm:^5.1.4" vitest: "npm:^2.1.8" wikipedia: "npm:^2.1.2" yaml: "npm:^2.6.1" zod: "npm:^3.23.8" zod-to-json-schema: "npm:^3.23.5" peerDependencies: - "@aws-sdk/client-bedrock-runtime": ^3.687.0 + "@ai-sdk/amazon-bedrock": ^1.1.5 + "@ai-sdk/azure": ^1.1.2 + "@ai-sdk/google-vertex": ^2.1.6 + "@ai-sdk/groq": ^1.1.6 + "@ai-sdk/openai": ^1.1.2 + "@aws-sdk/client-bedrock-runtime": ^3.706.0 "@elastic/elasticsearch": ^8.0.0 - "@google-cloud/vertexai": "*" "@googleapis/customsearch": ^3.2.0 - "@grpc/grpc-js": ^1.11.3 - "@grpc/proto-loader": ^0.7.13 "@langchain/community": ">=0.2.28" "@langchain/core": ">=0.2.27" "@modelcontextprotocol/sdk": ^1.0.4 "@zilliz/milvus2-sdk-node": ^2.4.9 - google-auth-library: "*" - groq-sdk: ^0.7.0 - ollama: ^0.5.11 - openai: ^4.67.3 - openai-chat-tokens: ^0.2.8 + ollama-ai-provider: ^1.2.0 sequelize: ^6.37.3 yaml: ^2.6.1 peerDependenciesMeta: - "@aws-sdk/client-bedrock-runtime": + "@ai-sdk/amazon-bedrock": optional: true - "@elastic/elasticsearch": + "@ai-sdk/azure": optional: true - "@google-cloud/vertexai": + "@ai-sdk/google-vertex": optional: true - "@googleapis/customsearch": + "@ai-sdk/groq": optional: true - "@grpc/grpc-js": + "@ai-sdk/openai": optional: true - "@grpc/proto-loader": + "@elastic/elasticsearch": + optional: true + "@googleapis/customsearch": + optional: true + "@ibm-cloud/watsonx-ai": optional: true "@langchain/community": optional: true @@ -5023,15 +5200,7 @@ __metadata: optional: true "@zilliz/milvus2-sdk-node": optional: true - google-auth-library: - optional: true - groq-sdk: - optional: true - ollama: - optional: true - openai: - optional: true - openai-chat-tokens: + ibm-cloud-sdk-core: optional: true sequelize: optional: true @@ -5301,7 +5470,7 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:6": +"camelcase@npm:6, camelcase@npm:^6.3.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 @@ -5423,13 +5592,6 @@ __metadata: languageName: node linkType: hard -"change-case@npm:^5.4.4": - version: 5.4.4 - resolution: "change-case@npm:5.4.4" - checksum: 10c0/2a9c2b9c9ad6ab2491105aaf506db1a9acaf543a18967798dcce20926c6a173aa63266cb6189f3086e3c14bf7ae1f8ea4f96ecc466fcd582310efa00372f3734 - languageName: node - linkType: hard - "character-entities@npm:^2.0.0": version: 2.0.2 resolution: "character-entities@npm:2.0.2" @@ -5685,13 +5847,6 @@ __metadata: languageName: node linkType: hard -"colorette@npm:^1.2.0": - version: 1.4.0 - resolution: "colorette@npm:1.4.0" - checksum: 10c0/4955c8f7daafca8ae7081d672e4bd89d553bd5782b5846d5a7e05effe93c2f15f7e9c0cb46f341b59f579a39fcf436241ff79594899d75d5f3460c03d607fe9e - languageName: node - linkType: hard - "colorette@npm:^2.0.20, colorette@npm:^2.0.7": version: 2.0.20 resolution: "colorette@npm:2.0.20" @@ -5889,6 +6044,15 @@ __metadata: languageName: node linkType: hard +"console-table-printer@npm:^2.12.1": + version: 2.12.1 + resolution: "console-table-printer@npm:2.12.1" + dependencies: + simple-wcswidth: "npm:^1.0.1" + checksum: 10c0/8f28e9c0ae5df77f5d60da3da002ecd95ebe1812b0b9e0a6d2795c81b5121b39774f32506bccf68830a838ca4d8fbb2ab8824e729dba2c5e30cdeb9df4dd5f2b + languageName: node + linkType: hard + "content-type@npm:^1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" @@ -6356,7 +6520,7 @@ __metadata: languageName: node linkType: hard -"dequal@npm:^2.0.0": +"dequal@npm:^2.0.0, dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 @@ -6386,6 +6550,13 @@ __metadata: languageName: node linkType: hard +"diff-match-patch@npm:^1.0.5": + version: 1.0.5 + resolution: "diff-match-patch@npm:1.0.5" + checksum: 10c0/142b6fad627b9ef309d11bd935e82b84c814165a02500f046e2773f4ea894d10ed3017ac20454900d79d4a0322079f5b713cf0986aaf15fce0ec4a2479980c86 + languageName: node + linkType: hard + "docsify-cli@npm:^4.4.4": version: 4.4.4 resolution: "docsify-cli@npm:4.4.4" @@ -6505,7 +6676,7 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:^16.4.7": +"dotenv@npm:^16.4.5, dotenv@npm:^16.4.7": version: 16.4.7 resolution: "dotenv@npm:16.4.7" checksum: 10c0/be9f597e36a8daf834452daa1f4cc30e5375a5968f98f46d89b16b983c567398a330580c88395069a77473943c06b877d1ca25b4afafcdd6d4adb549e8293462 @@ -7224,6 +7395,13 @@ __metadata: languageName: node linkType: hard +"eventsource-parser@npm:^3.0.0": + version: 3.0.0 + resolution: "eventsource-parser@npm:3.0.0" + checksum: 10c0/74ded91ff93330bd95243bd5a8fc61c805ea1843dd7ffac8e8ac36287fff419a7eec21b2fadf50d4e554ce0506de72f47928513e3c5b886fa4613fd49ef0024f + languageName: node + linkType: hard + "execa@npm:8.0.0": version: 8.0.0 resolution: "execa@npm:8.0.0" @@ -7303,7 +7481,7 @@ __metadata: languageName: node linkType: hard -"extend@npm:^3.0.2": +"extend@npm:3.0.2, extend@npm:^3.0.2": version: 3.0.2 resolution: "extend@npm:3.0.2" checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 @@ -7451,6 +7629,17 @@ __metadata: languageName: node linkType: hard +"file-type@npm:16.5.4": + version: 16.5.4 + resolution: "file-type@npm:16.5.4" + dependencies: + readable-web-to-node-stream: "npm:^3.0.0" + strtok3: "npm:^6.2.4" + token-types: "npm:^4.1.1" + checksum: 10c0/a6c9ab8bc05bc9c212bec239fb0d5bf59ddc9b3912f00c4ef44622e67ae4e553a1cc8372e9e595e14859035188eb305d05d488fa3c5c2a2ad90bb7745b3004ef + languageName: node + linkType: hard + "file-uri-to-path@npm:1.0.0": version: 1.0.0 resolution: "file-uri-to-path@npm:1.0.0" @@ -7599,7 +7788,7 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.0": +"form-data@npm:4.0.0, form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" dependencies: @@ -8051,9 +8240,9 @@ __metadata: languageName: node linkType: hard -"google-auth-library@npm:^9.1.0": - version: 9.15.0 - resolution: "google-auth-library@npm:9.15.0" +"google-auth-library@npm:^9.15.0": + version: 9.15.1 + resolution: "google-auth-library@npm:9.15.1" dependencies: base64-js: "npm:^1.3.0" ecdsa-sig-formatter: "npm:^1.0.11" @@ -8061,7 +8250,7 @@ __metadata: gcp-metadata: "npm:^6.1.0" gtoken: "npm:^7.0.0" jws: "npm:^4.0.0" - checksum: 10c0/f5a9a46e939147b181bac9b254f11dd8c2d05c15a65c9d3f2180252bef21c12af37d9893bc3caacafd226d6531a960535dbb5222ef869143f393c6a97639cc06 + checksum: 10c0/6eef36d9a9cb7decd11e920ee892579261c6390104b3b24d3e0f3889096673189fe2ed0ee43fd563710e2560de98e63ad5aa4967b91e7f4e69074a422d5f7b65 languageName: node linkType: hard @@ -8142,21 +8331,6 @@ __metadata: languageName: node linkType: hard -"groq-sdk@npm:^0.9.0": - version: 0.9.0 - resolution: "groq-sdk@npm:0.9.0" - dependencies: - "@types/node": "npm:^18.11.18" - "@types/node-fetch": "npm:^2.6.4" - abort-controller: "npm:^3.0.0" - agentkeepalive: "npm:^4.2.1" - form-data-encoder: "npm:1.7.2" - formdata-node: "npm:^4.3.2" - node-fetch: "npm:^2.6.7" - checksum: 10c0/be8f5ed868098acf325acfc286a83ceb16b835952ba747df567b90ed491283d22b009aa5a4890a7a38167f8ab954d89aae57b5f906c19279273c519101f95c62 - languageName: node - linkType: hard - "gtoken@npm:^7.0.0": version: 7.1.0 resolution: "gtoken@npm:7.1.0" @@ -8359,7 +8533,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.4": +"https-proxy-agent@npm:^7.0.1": version: 7.0.6 resolution: "https-proxy-agent@npm:7.0.6" dependencies: @@ -8411,6 +8585,52 @@ __metadata: languageName: node linkType: hard +"ibm-cloud-sdk-core@npm:^5.0.2": + version: 5.1.1 + resolution: "ibm-cloud-sdk-core@npm:5.1.1" + dependencies: + "@types/debug": "npm:^4.1.12" + "@types/node": "npm:~10.14.19" + "@types/tough-cookie": "npm:^4.0.0" + axios: "npm:1.7.4" + camelcase: "npm:^6.3.0" + debug: "npm:^4.3.4" + dotenv: "npm:^16.4.5" + extend: "npm:3.0.2" + file-type: "npm:16.5.4" + form-data: "npm:4.0.0" + isstream: "npm:0.1.2" + jsonwebtoken: "npm:^9.0.2" + mime-types: "npm:2.1.35" + retry-axios: "npm:^2.6.0" + tough-cookie: "npm:^4.1.3" + checksum: 10c0/f167948f28b77e43589a7909504b22b653800c87d7fa644b10e3eceee097e11d32081ec55decbcbf86e30936c63d2d3324e743853851f7eb632bd312c37bb242 + languageName: node + linkType: hard + +"ibm-cloud-sdk-core@npm:^5.1.2": + version: 5.1.2 + resolution: "ibm-cloud-sdk-core@npm:5.1.2" + dependencies: + "@types/debug": "npm:^4.1.12" + "@types/node": "npm:~10.14.19" + "@types/tough-cookie": "npm:^4.0.0" + axios: "npm:1.7.9" + camelcase: "npm:^6.3.0" + debug: "npm:^4.3.4" + dotenv: "npm:^16.4.5" + extend: "npm:3.0.2" + file-type: "npm:16.5.4" + form-data: "npm:4.0.0" + isstream: "npm:0.1.2" + jsonwebtoken: "npm:^9.0.2" + mime-types: "npm:2.1.35" + retry-axios: "npm:^2.6.0" + tough-cookie: "npm:^4.1.3" + checksum: 10c0/0a55170232b66b6a24899d8f1aa10251aedead6f38f1173a4f12ca3140a2358f214ac5659905184e27e869d0910478d5d016d3ab4dc5a875621b6145c203e6ed + languageName: node + linkType: hard + "iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -8429,7 +8649,7 @@ __metadata: languageName: node linkType: hard -"ieee754@npm:^1.1.13": +"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": version: 1.2.1 resolution: "ieee754@npm:1.2.1" checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb @@ -8493,13 +8713,6 @@ __metadata: languageName: node linkType: hard -"index-to-position@npm:^0.1.2": - version: 0.1.2 - resolution: "index-to-position@npm:0.1.2" - checksum: 10c0/7c91bde8bafc22684b74a7a24915bee4691cba48352ddb4ebe3b20a3a87bc0fa7a05f586137245ca8f92222a11f341f7631ff7f38cd78a523505d2d02dbfa257 - languageName: node - linkType: hard - "infer-owner@npm:^1.0.4": version: 1.0.4 resolution: "infer-owner@npm:1.0.4" @@ -8898,6 +9111,13 @@ __metadata: languageName: node linkType: hard +"isstream@npm:0.1.2": + version: 0.1.2 + resolution: "isstream@npm:0.1.2" + checksum: 10c0/a6686a878735ca0a48e0d674dd6d8ad31aedfaf70f07920da16ceadc7577b46d67179a60b313f2e6860cb097a2c2eb3cbd0b89e921ae89199a59a17c3273d66f + languageName: node + linkType: hard + "issue-parser@npm:7.0.1": version: 7.0.1 resolution: "issue-parser@npm:7.0.1" @@ -8967,14 +9187,7 @@ __metadata: languageName: node linkType: hard -"js-levenshtein@npm:^1.1.6": - version: 1.1.6 - resolution: "js-levenshtein@npm:1.1.6" - checksum: 10c0/14045735325ea1fd87f434a74b11d8a14380f090f154747e613529c7cff68b5ee607f5230fa40665d5fb6125a3791f4c223f73b9feca754f989b059f5c05864f - languageName: node - linkType: hard - -"js-tiktoken@npm:^1.0.12, js-tiktoken@npm:^1.0.7": +"js-tiktoken@npm:^1.0.12": version: 1.0.14 resolution: "js-tiktoken@npm:1.0.14" dependencies: @@ -9052,25 +9265,6 @@ __metadata: languageName: node linkType: hard -"json-schema-to-typescript@npm:^15.0.3": - version: 15.0.3 - resolution: "json-schema-to-typescript@npm:15.0.3" - dependencies: - "@apidevtools/json-schema-ref-parser": "npm:^11.5.5" - "@types/json-schema": "npm:^7.0.15" - "@types/lodash": "npm:^4.17.7" - is-glob: "npm:^4.0.3" - js-yaml: "npm:^4.1.0" - lodash: "npm:^4.17.21" - minimist: "npm:^1.2.8" - prettier: "npm:^3.2.5" - tinyglobby: "npm:^0.2.9" - bin: - json2ts: dist/src/cli.js - checksum: 10c0/b972ceb85c9491a08964669ba878b2f12ba27ef14d4ac0444dac6c9479f91e635b1a6a3bf491a8b36cba6409edbdb2730a8f30db6106305e344f5bce0bf1a76d - languageName: node - linkType: hard - "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -9085,6 +9279,13 @@ __metadata: languageName: node linkType: hard +"json-schema@npm:^0.4.0": + version: 0.4.0 + resolution: "json-schema@npm:0.4.0" + checksum: 10c0/d4a637ec1d83544857c1c163232f3da46912e971d5bf054ba44fdb88f07d8d359a462b4aec46f2745efbc57053365608d88bc1d7b1729f7b4fc3369765639ed3 + languageName: node + linkType: hard + "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" @@ -9099,6 +9300,19 @@ __metadata: languageName: node linkType: hard +"jsondiffpatch@npm:0.6.0": + version: 0.6.0 + resolution: "jsondiffpatch@npm:0.6.0" + dependencies: + "@types/diff-match-patch": "npm:^1.0.36" + chalk: "npm:^5.3.0" + diff-match-patch: "npm:^1.0.5" + bin: + jsondiffpatch: bin/jsondiffpatch.js + checksum: 10c0/f7822e48a8ef8b9f7c6024cc59b7d3707a9fe6d84fd776d169de5a1803ad551ffe7cfdc7587f3900f224bc70897355884ed43eb1c8ccd02e7f7b43a7ebcfed4f + languageName: node + linkType: hard + "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -9147,6 +9361,35 @@ __metadata: languageName: node linkType: hard +"jsonwebtoken@npm:^9.0.2": + version: 9.0.2 + resolution: "jsonwebtoken@npm:9.0.2" + dependencies: + jws: "npm:^3.2.2" + lodash.includes: "npm:^4.3.0" + lodash.isboolean: "npm:^3.0.3" + lodash.isinteger: "npm:^4.0.4" + lodash.isnumber: "npm:^3.0.3" + lodash.isplainobject: "npm:^4.0.6" + lodash.isstring: "npm:^4.0.1" + lodash.once: "npm:^4.0.0" + ms: "npm:^2.1.1" + semver: "npm:^7.5.4" + checksum: 10c0/d287a29814895e866db2e5a0209ce730cbc158441a0e5a70d5e940eb0d28ab7498c6bf45029cc8b479639bca94056e9a7f254e2cdb92a2f5750c7f358657a131 + languageName: node + linkType: hard + +"jwa@npm:^1.4.1": + version: 1.4.1 + resolution: "jwa@npm:1.4.1" + dependencies: + buffer-equal-constant-time: "npm:1.0.1" + ecdsa-sig-formatter: "npm:1.0.11" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/5c533540bf38702e73cf14765805a94027c66a0aa8b16bc3e89d8d905e61a4ce2791e87e21be97d1293a5ee9d4f3e5e47737e671768265ca4f25706db551d5e9 + languageName: node + linkType: hard + "jwa@npm:^2.0.0": version: 2.0.0 resolution: "jwa@npm:2.0.0" @@ -9158,6 +9401,16 @@ __metadata: languageName: node linkType: hard +"jws@npm:^3.2.2": + version: 3.2.2 + resolution: "jws@npm:3.2.2" + dependencies: + jwa: "npm:^1.4.1" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/e770704533d92df358adad7d1261fdecad4d7b66fa153ba80d047e03ca0f1f73007ce5ed3fbc04d2eba09ba6e7e6e645f351e08e5ab51614df1b0aa4f384dfff + languageName: node + linkType: hard + "jws@npm:^4.0.0": version: 4.0.0 resolution: "jws@npm:4.0.0" @@ -9330,6 +9583,26 @@ __metadata: languageName: node linkType: hard +"langsmith@npm:>=0.2.8 <0.4.0": + version: 0.3.3 + resolution: "langsmith@npm:0.3.3" + dependencies: + "@types/uuid": "npm:^10.0.0" + chalk: "npm:^4.1.2" + console-table-printer: "npm:^2.12.1" + p-queue: "npm:^6.6.2" + p-retry: "npm:4" + semver: "npm:^7.6.3" + uuid: "npm:^10.0.0" + peerDependencies: + openai: "*" + peerDependenciesMeta: + openai: + optional: true + checksum: 10c0/9ecb2b27d16fd753ca4ddbc29f3b0bced325b983e35945165939526327164acd67098578212a14926703de98e9f1e538672cf817977610db95c56b7afa3a364f + languageName: node + linkType: hard + "langsmith@npm:^0.2.0": version: 0.2.5 resolution: "langsmith@npm:0.2.5" @@ -9554,6 +9827,20 @@ __metadata: languageName: node linkType: hard +"lodash.includes@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.includes@npm:4.3.0" + checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b + languageName: node + linkType: hard + +"lodash.isboolean@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isboolean@npm:3.0.3" + checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7 + languageName: node + linkType: hard + "lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" @@ -9561,6 +9848,20 @@ __metadata: languageName: node linkType: hard +"lodash.isinteger@npm:^4.0.4": + version: 4.0.4 + resolution: "lodash.isinteger@npm:4.0.4" + checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7 + languageName: node + linkType: hard + +"lodash.isnumber@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isnumber@npm:3.0.3" + checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d + languageName: node + linkType: hard + "lodash.isplainobject@npm:^4.0.6": version: 4.0.6 resolution: "lodash.isplainobject@npm:4.0.6" @@ -9596,6 +9897,13 @@ __metadata: languageName: node linkType: hard +"lodash.once@npm:^4.0.0": + version: 4.1.1 + resolution: "lodash.once@npm:4.1.1" + checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04 + languageName: node + linkType: hard + "lodash.snakecase@npm:^4.1.1": version: 4.1.1 resolution: "lodash.snakecase@npm:4.1.1" @@ -10507,15 +10815,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^5.0.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/3defdfd230914f22a8da203747c42ee3c405c39d4d37ffda284dac5e45b7e1f6c49aa8be606509002898e73091ff2a3bbfc59c2c6c71d4660609f63aa92f98e3 - languageName: node - linkType: hard - "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -10727,7 +11026,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.7": +"nanoid@npm:^3.3.7, nanoid@npm:^3.3.8": version: 3.3.8 resolution: "nanoid@npm:3.3.8" bin: @@ -10824,7 +11123,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.6, node-fetch@npm:^2.6.7, node-fetch@npm:^2.6.9": +"node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.6, node-fetch@npm:^2.6.7, node-fetch@npm:^2.6.9": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: @@ -10983,12 +11282,19 @@ __metadata: languageName: node linkType: hard -"ollama@npm:^0.5.11": - version: 0.5.11 - resolution: "ollama@npm:0.5.11" +"ollama-ai-provider@npm:^1.2.0": + version: 1.2.0 + resolution: "ollama-ai-provider@npm:1.2.0" dependencies: - whatwg-fetch: "npm:^3.6.20" - checksum: 10c0/9f8bb6715144fac2d423121f29bf7697e3c2132c6696574e2f2de63de8dfa95ac3ed435f3abf35cece6ef07c309065cbf722cead1bee1eda3541b095745f64bf + "@ai-sdk/provider": "npm:^1.0.0" + "@ai-sdk/provider-utils": "npm:^2.0.0" + partial-json: "npm:0.1.7" + peerDependencies: + zod: ^3.0.0 + peerDependenciesMeta: + zod: + optional: true + checksum: 10c0/d8db4e3e764de179cc04d2ee460118c468a9417ab20a2d13980862ff4df08ab7d41449dad4c49b1c6cd04f3b16517e0b3304365f64b73e90c008b01b4ec40e4b languageName: node linkType: hard @@ -11092,15 +11398,6 @@ __metadata: languageName: node linkType: hard -"openai-chat-tokens@npm:^0.2.8": - version: 0.2.8 - resolution: "openai-chat-tokens@npm:0.2.8" - dependencies: - js-tiktoken: "npm:^1.0.7" - checksum: 10c0/b415fda706b408f29b4584998990f29ad7f80f2ac1e84179a0976742ba8a80859fedeae5745a9bfe73443d95960b77328610074952ad198a18bc0e5c0ceb5b7b - languageName: node - linkType: hard - "openai@npm:^4.68.0": version: 4.68.1 resolution: "openai@npm:4.68.1" @@ -11123,9 +11420,9 @@ __metadata: languageName: node linkType: hard -"openai@npm:^4.76.0": - version: 4.77.4 - resolution: "openai@npm:4.77.4" +"openai@npm:^4.77.0": + version: 4.81.0 + resolution: "openai@npm:4.81.0" dependencies: "@types/node": "npm:^18.11.18" "@types/node-fetch": "npm:^2.6.4" @@ -11135,22 +11432,16 @@ __metadata: formdata-node: "npm:^4.3.2" node-fetch: "npm:^2.6.7" peerDependencies: + ws: ^8.18.0 zod: ^3.23.8 peerDependenciesMeta: + ws: + optional: true zod: optional: true bin: openai: bin/cli - checksum: 10c0/cd63a98ce77fb528d12745962b66b229d0ec5243c19d2796933df540b0732a3c323c205575fcfa096ecfa8e39d84e058f8942c45b5655df571bece1d7ffa7301 - languageName: node - linkType: hard - -"openapi-fetch@npm:^0.13.3": - version: 0.13.3 - resolution: "openapi-fetch@npm:0.13.3" - dependencies: - openapi-typescript-helpers: "npm:^0.0.15" - checksum: 10c0/4d66bcc9e3f74fac7b1df1139436f7c53623f1df3e39991eb39ee5dece34b960d3b090998e86d20dd5c14dff84f2f776d776826fc41f12be1121881905a89ef2 + checksum: 10c0/71606ff69e6a77d56c2e0c9716f3cdea536cb79b41a57e0487d022851b0cd25defd3d31b9db9c60e5b447ed44973ccd822d926b1ba09430423b94709758816a0 languageName: node linkType: hard @@ -11161,31 +11452,6 @@ __metadata: languageName: node linkType: hard -"openapi-typescript-helpers@npm:^0.0.15": - version: 0.0.15 - resolution: "openapi-typescript-helpers@npm:0.0.15" - checksum: 10c0/5eb68d487b787e3e31266470b1a310726549dd45a1079655ab18066ab291b0b3c343fdf629991013706a2329b86964f8798d56ef0272b94b931fe6c19abd7a88 - languageName: node - linkType: hard - -"openapi-typescript@npm:^7.4.4": - version: 7.4.4 - resolution: "openapi-typescript@npm:7.4.4" - dependencies: - "@redocly/openapi-core": "npm:^1.25.9" - ansi-colors: "npm:^4.1.3" - change-case: "npm:^5.4.4" - parse-json: "npm:^8.1.0" - supports-color: "npm:^9.4.0" - yargs-parser: "npm:^21.1.1" - peerDependencies: - typescript: ^5.x - bin: - openapi-typescript: bin/cli.js - checksum: 10c0/bdaa32bca608565b472fbb74654bc82c4e0d41b288165a9beb8e2ddee39395577e70f249d26cc5761212f2ea20d666d779831b0c9efc4ac38c4730c6918c7f34 - languageName: node - linkType: hard - "opencollective-postinstall@npm:^2.0.2": version: 2.0.3 resolution: "opencollective-postinstall@npm:2.0.3" @@ -11524,17 +11790,6 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^8.1.0": - version: 8.1.0 - resolution: "parse-json@npm:8.1.0" - dependencies: - "@babel/code-frame": "npm:^7.22.13" - index-to-position: "npm:^0.1.2" - type-fest: "npm:^4.7.1" - checksum: 10c0/39a49acafc1c41a763df2599a826eb77873a44b098a5f2ba548843229b334a16ff9d613d0381328e58031b0afaabc18ed2a01337a6522911ac7a81828df58bcb - languageName: node - linkType: hard - "parse-path@npm:^7.0.0": version: 7.0.0 resolution: "parse-path@npm:7.0.0" @@ -11560,6 +11815,13 @@ __metadata: languageName: node linkType: hard +"partial-json@npm:0.1.7": + version: 0.1.7 + resolution: "partial-json@npm:0.1.7" + checksum: 10c0/cd5f994c3a5ca903918c028a6947ebc1d46459234c1c57c7ab98e234d8dca49cb46b05a71889ee422b39d1f66b95c59a5ce3a6ae06966aca95a8960ad20c12d2 + languageName: node + linkType: hard + "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" @@ -11643,6 +11905,13 @@ __metadata: languageName: node linkType: hard +"peek-readable@npm:^4.1.0": + version: 4.1.0 + resolution: "peek-readable@npm:4.1.0" + checksum: 10c0/f9b81ce3eed185cc9ebbf7dff0b6e130dd6da7b05f1802bbf726a78e4d84990b0a65f8e701959c50eb1124cc2ad352205147954bf39793faba29bb00ce742a44 + languageName: node + linkType: hard + "pg-connection-string@npm:^2.6.1": version: 2.7.0 resolution: "pg-connection-string@npm:2.7.0" @@ -11770,13 +12039,6 @@ __metadata: languageName: node linkType: hard -"pluralize@npm:^8.0.0": - version: 8.0.0 - resolution: "pluralize@npm:8.0.0" - checksum: 10c0/2044cfc34b2e8c88b73379ea4a36fc577db04f651c2909041b054c981cd863dd5373ebd030123ab058d194ae615d3a97cfdac653991e499d10caf592e8b3dc33 - languageName: node - linkType: hard - "postcss-load-config@npm:^6.0.1": version: 6.0.1 resolution: "postcss-load-config@npm:6.0.1" @@ -11847,7 +12109,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.2.5, prettier@npm:^3.4.2": +"prettier@npm:^3.4.2": version: 3.4.2 resolution: "prettier@npm:3.4.2" bin: @@ -11958,6 +12220,15 @@ __metadata: languageName: node linkType: hard +"psl@npm:^1.1.33": + version: 1.15.0 + resolution: "psl@npm:1.15.0" + dependencies: + punycode: "npm:^2.3.1" + checksum: 10c0/d8d45a99e4ca62ca12ac3c373e63d80d2368d38892daa40cfddaa1eb908be98cd549ac059783ef3a56cfd96d57ae8e2fd9ae53d1378d90d42bc661ff924e102a + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.0 resolution: "pump@npm:3.0.0" @@ -11968,7 +12239,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0": +"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 @@ -12002,6 +12273,13 @@ __metadata: languageName: node linkType: hard +"querystringify@npm:^2.1.1": + version: 2.2.0 + resolution: "querystringify@npm:2.2.0" + checksum: 10c0/3258bc3dbdf322ff2663619afe5947c7926a6ef5fb78ad7d384602974c467fadfc8272af44f5eb8cddd0d011aae8fabf3a929a8eee4b86edcc0a21e6bd10f9aa + languageName: node + linkType: hard + "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -12122,6 +12400,15 @@ __metadata: languageName: node linkType: hard +"readable-web-to-node-stream@npm:^3.0.0": + version: 3.0.2 + resolution: "readable-web-to-node-stream@npm:3.0.2" + dependencies: + readable-stream: "npm:^3.6.0" + checksum: 10c0/533d5cd1580232a2c753e52a245be13fc552e6f82c5053a8a8da7ea1063d73a34f936a86b3d4433cdb4a13dd683835cfc87f230936cb96d329a1e28b6040f42e + languageName: node + linkType: hard + "readdirp@npm:^4.0.1": version: 4.0.2 resolution: "readdirp@npm:4.0.2" @@ -12272,6 +12559,13 @@ __metadata: languageName: node linkType: hard +"requires-port@npm:^1.0.0": + version: 1.0.0 + resolution: "requires-port@npm:1.0.0" + checksum: 10c0/b2bfdd09db16c082c4326e573a82c0771daaf7b53b9ce8ad60ea46aa6e30aaf475fe9b164800b89f93b748d2c234d8abff945d2551ba47bf5698e04cd7713267 + languageName: node + linkType: hard + "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" @@ -12362,6 +12656,15 @@ __metadata: languageName: node linkType: hard +"retry-axios@npm:^2.6.0": + version: 2.6.0 + resolution: "retry-axios@npm:2.6.0" + peerDependencies: + axios: "*" + checksum: 10c0/da951029dacaf9eba56b2714dd97941381e15d670d22aaa39effc13e0793b392da6b0e7b4ba36539c957d40b859bc6c46d64f85097ba625da196218074aeacf7 + languageName: node + linkType: hard + "retry@npm:0.13.1, retry@npm:^0.13.1": version: 0.13.1 resolution: "retry@npm:0.13.1" @@ -12617,7 +12920,7 @@ __metadata: languageName: node linkType: hard -"secure-json-parse@npm:^2.4.0": +"secure-json-parse@npm:^2.4.0, secure-json-parse@npm:^2.7.0": version: 2.7.0 resolution: "secure-json-parse@npm:2.7.0" checksum: 10c0/f57eb6a44a38a3eeaf3548228585d769d788f59007454214fab9ed7f01fbf2e0f1929111da6db28cf0bcc1a2e89db5219a59e83eeaec3a54e413a0197ce879e4 @@ -12881,6 +13184,13 @@ __metadata: languageName: node linkType: hard +"simple-wcswidth@npm:^1.0.1": + version: 1.0.1 + resolution: "simple-wcswidth@npm:1.0.1" + checksum: 10c0/2befead4c97134424aa3fba593a81daa9934fd61b9e4c65374b57ac5eecc2f2be1984b017bbdbc919923e19b77f2fcbdb94434789b9643fa8c3fde3a2a6a4b6f + languageName: node + linkType: hard + "slash@npm:^5.1.0": version: 5.1.0 resolution: "slash@npm:5.1.0" @@ -13292,6 +13602,16 @@ __metadata: languageName: node linkType: hard +"strtok3@npm:^6.2.4": + version: 6.3.0 + resolution: "strtok3@npm:6.3.0" + dependencies: + "@tokenizer/token": "npm:^0.3.0" + peek-readable: "npm:^4.1.0" + checksum: 10c0/8f1483a2a6758404502f2fc431586fcf37d747b10b125596ab5ec92319c247dd1195f82ba0bc2eaa582db3d807b5cca4b67ff61411756fec6622d051f8e255c2 + languageName: node + linkType: hard + "stubborn-fs@npm:^1.2.5": version: 1.2.5 resolution: "stubborn-fs@npm:1.2.5" @@ -13342,13 +13662,6 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^9.4.0": - version: 9.4.0 - resolution: "supports-color@npm:9.4.0" - checksum: 10c0/6c24e6b2b64c6a60e5248490cfa50de5924da32cf09ae357ad8ebbf305cc5d2717ba705a9d4cb397d80bbf39417e8fdc8d7a0ce18bd0041bf7b5b456229164e4 - languageName: node - linkType: hard - "supports-preserve-symlinks-flag@npm:^1.0.0": version: 1.0.0 resolution: "supports-preserve-symlinks-flag@npm:1.0.0" @@ -13356,6 +13669,18 @@ __metadata: languageName: node linkType: hard +"swr@npm:^2.2.5": + version: 2.3.0 + resolution: "swr@npm:2.3.0" + dependencies: + dequal: "npm:^2.0.3" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/192497881013654bc82d2787b60ad0701113e8ae41c511dfa8d55bcf58582657a92a4cb2854d4ea2ceaa1055e67e58daf9bd98ada2786a3035ba12898da578f1 + languageName: node + linkType: hard + "table-layout@npm:^4.1.0": version: 4.1.1 resolution: "table-layout@npm:4.1.1" @@ -13405,13 +13730,6 @@ __metadata: languageName: node linkType: hard -"temp-dir@npm:^3.0.0": - version: 3.0.0 - resolution: "temp-dir@npm:3.0.0" - checksum: 10c0/a86978a400984cd5f315b77ebf3fe53bb58c61f192278cafcb1f3fb32d584a21dc8e08b93171d7874b7cc972234d3455c467306cc1bfc4524b622e5ad3bfd671 - languageName: node - linkType: hard - "term-size@npm:^2.1.0": version: 2.2.1 resolution: "term-size@npm:2.2.1" @@ -13460,6 +13778,13 @@ __metadata: languageName: node linkType: hard +"throttleit@npm:2.1.0": + version: 2.1.0 + resolution: "throttleit@npm:2.1.0" + checksum: 10c0/1696ae849522cea6ba4f4f3beac1f6655d335e51b42d99215e196a718adced0069e48deaaf77f7e89f526ab31de5b5c91016027da182438e6f9280be2f3d5265 + languageName: node + linkType: hard + "through@npm:>=2.2.7 <3": version: 2.3.8 resolution: "through@npm:2.3.8" @@ -13565,6 +13890,16 @@ __metadata: languageName: node linkType: hard +"token-types@npm:^4.1.1": + version: 4.2.1 + resolution: "token-types@npm:4.2.1" + dependencies: + "@tokenizer/token": "npm:^0.3.0" + ieee754: "npm:^1.2.1" + checksum: 10c0/e9a4a139deba9515770cd7ac36a8f53f953b9d035d309e88a66d706760dba0df420753f2b8bdee6b9f3cbff8d66b24e69571e8dea27baa7b378229ab1bcca399 + languageName: node + linkType: hard + "toposort-class@npm:^1.0.1": version: 1.0.1 resolution: "toposort-class@npm:1.0.1" @@ -13572,6 +13907,18 @@ __metadata: languageName: node linkType: hard +"tough-cookie@npm:^4.1.3": + version: 4.1.4 + resolution: "tough-cookie@npm:4.1.4" + dependencies: + psl: "npm:^1.1.33" + punycode: "npm:^2.1.1" + universalify: "npm:^0.2.0" + url-parse: "npm:^1.5.3" + checksum: 10c0/aca7ff96054f367d53d1e813e62ceb7dd2eda25d7752058a74d64b7266fd07be75908f3753a32ccf866a2f997604b414cfb1916d6e7f69bc64d9d9939b0d6c45 + languageName: node + linkType: hard + "tr46@npm:^1.0.1": version: 1.0.1 resolution: "tr46@npm:1.0.1" @@ -13620,17 +13967,6 @@ __metadata: languageName: node linkType: hard -"tsc-files@npm:^1.1.4": - version: 1.1.4 - resolution: "tsc-files@npm:1.1.4" - peerDependencies: - typescript: ">=3" - bin: - tsc-files: cli.js - checksum: 10c0/f7bc34c736e58dbd50c8f5fcd075704ad7f48efa670aaf388b7bee3386b8a2e6bef17cab5e6f8ff95bff7c2e1fa3baecb498576333b649c4258a9779dda3e708 - languageName: node - linkType: hard - "tsconfck@npm:^3.0.3": version: 3.1.1 resolution: "tsconfck@npm:3.1.1" @@ -13659,9 +13995,9 @@ __metadata: languageName: node linkType: hard -"tsup@npm:^8.3.5": - version: 8.3.5 - resolution: "tsup@npm:8.3.5" +"tsup@npm:^8.3.6": + version: 8.3.6 + resolution: "tsup@npm:8.3.6" dependencies: bundle-require: "npm:^5.0.0" cac: "npm:^6.7.14" @@ -13696,7 +14032,7 @@ __metadata: bin: tsup: dist/cli-default.js tsup-node: dist/cli-node.js - checksum: 10c0/7794953cbc784b7c8f14c4898d36a293b815b528d3098c2416aeaa2b4775dc477132cd12f75f6d32737dfd15ba10139c73f7039045352f2ba1ea7e5fe6fe3773 + checksum: 10c0/b8669bba2aafb8831832d7638792a20a101778a07ba971ea36fca47c27e7095fe0c91d29669d2fc0d17941138bc87245de1d0c4e5abf0ce5dfec7bf9eb76a5bd languageName: node linkType: hard @@ -13792,13 +14128,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^4.7.1": - version: 4.25.0 - resolution: "type-fest@npm:4.25.0" - checksum: 10c0/1187b30d74e72f4b0b44a3493d2c1c2a9dc46423961c8250bd1535e976c4b8afc3916f6b4b90d7f56ed5b2f36d1645b05c318b4915fe4909a8a66890bda1d68d - languageName: node - linkType: hard - "typed-function@npm:^4.2.1": version: 4.2.1 resolution: "typed-function@npm:4.2.1" @@ -13836,23 +14165,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.7.2": - version: 5.7.2 - resolution: "typescript@npm:5.7.2" +"typescript@npm:^5.7.3": + version: 5.7.3 + resolution: "typescript@npm:5.7.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/a873118b5201b2ef332127ef5c63fb9d9c155e6fdbe211cbd9d8e65877283797cca76546bad742eea36ed7efbe3424a30376818f79c7318512064e8625d61622 + checksum: 10c0/b7580d716cf1824736cc6e628ab4cd8b51877408ba2be0869d2866da35ef8366dd6ae9eb9d0851470a39be17cbd61df1126f9e211d8799d764ea7431d5435afa languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.7.2#optional!builtin": - version: 5.7.2 - resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=5adc0c" +"typescript@patch:typescript@npm%3A^5.7.3#optional!builtin": + version: 5.7.3 + resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin::version=5.7.3&hash=5adc0c" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/c891ccf04008bc1305ba34053db951f8a4584b4a1bf2f68fd972c4a354df3dc5e62c8bfed4f6ac2d12e5b3b1c49af312c83a651048f818cd5b4949d17baacd79 + checksum: 10c0/3b56d6afa03d9f6172d0b9cdb10e6b1efc9abc1608efd7a3d2f38773d5d8cfb9bbc68dfb72f0a7de5e8db04fc847f4e4baeddcd5ad9c9feda072234f0d788896 languageName: node linkType: hard @@ -14012,6 +14341,13 @@ __metadata: languageName: node linkType: hard +"universalify@npm:^0.2.0": + version: 0.2.0 + resolution: "universalify@npm:0.2.0" + checksum: 10c0/cedbe4d4ca3967edf24c0800cfc161c5a15e240dac28e3ce575c689abc11f2c81ccc6532c8752af3b40f9120fb5e454abecd359e164f4f6aa44c29cd37e194fe + languageName: node + linkType: hard + "universalify@npm:^2.0.0": version: 2.0.1 resolution: "universalify@npm:2.0.1" @@ -14079,13 +14415,6 @@ __metadata: languageName: node linkType: hard -"uri-js-replace@npm:^1.0.1": - version: 1.0.1 - resolution: "uri-js-replace@npm:1.0.1" - checksum: 10c0/0be6c972c84c316e29667628ce7b4ce4de7fc77cec9a514f70c4a3336eea8d1d783c71c9988ac5da333f0f6a85a04a7ae05a3c4aa43af6cd07b7a4d85c8d9f11 - languageName: node - linkType: hard - "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -14111,6 +14440,16 @@ __metadata: languageName: node linkType: hard +"url-parse@npm:^1.5.3": + version: 1.5.10 + resolution: "url-parse@npm:1.5.10" + dependencies: + querystringify: "npm:^2.1.1" + requires-port: "npm:^1.0.0" + checksum: 10c0/bd5aa9389f896974beb851c112f63b466505a04b4807cea2e5a3b7092f6fbb75316f0491ea84e44f66fed55f1b440df5195d7e3a8203f64fcefa19d182f5be87 + languageName: node + linkType: hard + "url-template@npm:^2.0.8": version: 2.0.8 resolution: "url-template@npm:2.0.8" @@ -14118,6 +14457,15 @@ __metadata: languageName: node linkType: hard +"use-sync-external-store@npm:^1.4.0": + version: 1.4.0 + resolution: "use-sync-external-store@npm:1.4.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/ec011a5055962c0f6b509d6e78c0b143f8cd069890ae370528753053c55e3b360d3648e76cfaa854faa7a59eb08d6c5fb1015e60ffde9046d32f5b2a295acea5 + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -14198,9 +14546,9 @@ __metadata: languageName: node linkType: hard -"vite-tsconfig-paths@npm:^5.1.3": - version: 5.1.3 - resolution: "vite-tsconfig-paths@npm:5.1.3" +"vite-tsconfig-paths@npm:^5.1.4": + version: 5.1.4 + resolution: "vite-tsconfig-paths@npm:5.1.4" dependencies: debug: "npm:^4.1.1" globrex: "npm:^0.1.2" @@ -14210,7 +14558,7 @@ __metadata: peerDependenciesMeta: vite: optional: true - checksum: 10c0/fb7480efa31fd50439f4a12c91bc953e5cc09d69fdc7eeb6ffff7cc796bc2c1f2c617c3abfdcbf5d7414848076cea9deb60bc002142f93b6e3131e5458760710 + checksum: 10c0/6228f23155ea25d92b1e1702284cf8dc52ad3c683c5ca691edd5a4c82d2913e7326d00708cef1cbfde9bb226261df0e0a12e03ef1d43b6a92d8f02b483ef37e3 languageName: node linkType: hard @@ -14646,13 +14994,6 @@ __metadata: languageName: node linkType: hard -"yaml-ast-parser@npm:0.0.43": - version: 0.0.43 - resolution: "yaml-ast-parser@npm:0.0.43" - checksum: 10c0/4d2f1e761067b2c6abdd882279a406f879258787af470a6d4a659cb79cb2ab056b870b25f1f80f46ed556e8b499d611d247806376f53edf3412f72c0a8ea2e98 - languageName: node - linkType: hard - "yaml@npm:^2.2.1, yaml@npm:~2.5.0": version: 2.5.0 resolution: "yaml@npm:2.5.0" @@ -14754,7 +15095,7 @@ __metadata: languageName: node linkType: hard -"zod-to-json-schema@npm:^3.22.3, zod-to-json-schema@npm:^3.22.5": +"zod-to-json-schema@npm:^3.22.3, zod-to-json-schema@npm:^3.22.5, zod-to-json-schema@npm:^3.24.1": version: 3.24.1 resolution: "zod-to-json-schema@npm:3.24.1" peerDependencies: