# Migrating from 0.23.0 to 0.23.1

> **Note:** the "New import" column has been updated to the **current** flat
> layout. The 0.23.1 release split each endpoint into `{endpoint}/{endpoint.py,
> models.py}` subdirectories; those were later collapsed back into a single
> `{endpoint}.py` holding both the `Endpoint` subclass and its request models,
> and each provider package now lazily re-exports its endpoints — so
> `from lionagi.providers.openai import OpenaiChatEndpoint` also works. Two
> symbols were renamed after 0.23.1 (`OpenrouterChatEndpoint` →
> `OpenRouterEndpoint`, `DeepseekChatRequest` → `DeepseekChatCompletionsRequest`);
> the column reflects the current names. See
> [providers.md](../reference/providers.md) for the current structure.

0.23.1 is backward-compatible for `iModel()` and `Branch` usage. Import paths for
provider internals changed.

---

## Breaking: Provider import paths

The monolithic `service/connections/providers/` and `service/third_party/` modules are
replaced by a per-company, per-endpoint layout under `lionagi/providers/`.

```bash
grep -rn "from lionagi.service.connections.providers\|from lionagi.service.third_party" \
     --include="*.py" .
```

| Old import | New import |
|---|---|
| `from lionagi.service.connections.providers.oai_ import OpenaiChatEndpoint` | `from lionagi.providers.openai.chat import OpenaiChatEndpoint` |
| `from lionagi.service.connections.providers.oai_ import OpenaiResponseEndpoint` | `from lionagi.providers.openai.response import OpenaiResponseEndpoint` |
| `from lionagi.service.connections.providers.oai_ import OpenrouterChatEndpoint` | `from lionagi.providers.openrouter.chat import OpenRouterEndpoint` |
| `from lionagi.service.connections.providers.oai_ import GroqChatEndpoint` | `from lionagi.providers.groq.chat import GroqChatEndpoint` |
| `from lionagi.service.connections.providers.oai_ import GeminiChatEndpoint` | `from lionagi.providers.google.chat import GeminiChatEndpoint` |
| `from lionagi.service.connections.providers.oai_ import DeepseekChatEndpoint` | `from lionagi.providers.deepseek.chat import DeepseekChatEndpoint` |
| `from lionagi.service.connections.providers.anthropic_ import AnthropicMessagesEndpoint` | `from lionagi.providers.anthropic.messages import AnthropicMessagesEndpoint` |
| `from lionagi.service.connections.providers.ollama_ import OllamaChatEndpoint` | `from lionagi.providers.ollama.chat import OllamaChatEndpoint` |
| `from lionagi.service.connections.providers.perplexity_ import PerplexityChatEndpoint` | `from lionagi.providers.perplexity.chat import PerplexityChatEndpoint` |
| `from lionagi.service.connections.providers.exa_ import ExaSearchEndpoint` | `from lionagi.providers.exa.search import ExaSearchEndpoint` |
| `from lionagi.service.connections.providers.tavily_ import TavilySearchEndpoint` | `from lionagi.providers.tavily.search import TavilySearchEndpoint` |
| `from lionagi.service.connections.providers.firecrawl_ import FirecrawlScrapeEndpoint` | `from lionagi.providers.firecrawl.scrape import FirecrawlScrapeEndpoint` |
| `from lionagi.service.third_party.openai_models import OpenAIChatCompletionsRequest` | `from lionagi.providers.openai.chat import OpenAIChatCompletionsRequest` |
| `from lionagi.service.third_party.anthropic_models import CreateMessageRequest` | `from lionagi.providers.anthropic.messages import CreateMessageRequest` |
| `from lionagi.service.third_party.exa_models import ExaSearchRequest` | `from lionagi.providers.exa.search import ExaSearchRequest` |
| `from lionagi.service.third_party.deepseek_models import DeepseekChatRequest` | `from lionagi.providers.deepseek.chat import DeepseekChatCompletionsRequest` |
| `from lionagi.service.third_party.pplx_models import PerplexityChatRequest` | `from lionagi.providers.perplexity.chat import PerplexityChatRequest` |
| `from lionagi.service.third_party.tavily_models import TavilySearchRequest` | `from lionagi.providers.tavily.search import TavilySearchRequest` |
| `from lionagi.service.third_party.firecrawl_models import FirecrawlScrapeRequest` | `from lionagi.providers.firecrawl.scrape import FirecrawlScrapeRequest` |

Pattern: `lionagi.service.connections.providers.{slug}` and
`lionagi.service.third_party.{slug}_models` both collapse to
`lionagi.providers.{company}.{endpoint}` — one module per endpoint holding the
`Endpoint` subclass and its request models.

---

## New: Provider registry

`EndpointRegistry` replaces the internal lookup table in `match_endpoint.py`. Endpoints
self-register via decorator at import time.

```python
from lionagi.service.connections.registry import EndpointRegistry, register_endpoint

@register_endpoint(provider="acme", endpoint="chat", base_url="https://api.acme.io/v1")
class AcmeChatEndpoint(Endpoint):
    ...
```

`match_endpoint()` still works and delegates to the registry — no call-site changes needed
unless you were monkey-patching the old lookup dict.

---

## New: AgenticEndpoint (renamed from CLIEndpoint)

`CLIEndpoint` is now `AgenticEndpoint`. The old name is kept as an alias in
`cli_endpoint.py` but will be removed in a future release.

```bash
grep -rn "CLIEndpoint" --include="*.py" .
```

```python
# before
from lionagi.service.connections import CLIEndpoint

# after
from lionagi.service.connections import AgenticEndpoint
```

Both names resolve to the same class today. Migrate at your convenience.

---

## New: Note model

Lightweight nested-dict wrapper used internally by flow operations.

```python
from lionagi.models.note import Note

n = Note(content={"a": {"b": 1}})
n["a", "b"]          # 1
n["a", "b"] = 2
n.pop(("a", "b"))
```

Opt-in for user code. No existing APIs changed.

---

## New: AG2 GroupChat (optional dependency)

```bash
pip install lionagi[ag2]
```

```python
from lionagi.providers.ag2.groupchat import AG2GroupChatEndpoint

ep = AG2GroupChatEndpoint(agents=[...], max_round=10)
```

Only installed when the `ag2` extra is requested.

---

## New: nested utilities

```python
from lionagi.libs.nested import nget, nset, npop, flatten, unflatten, deep_update

data = {"a": {"b": [1, 2, 3]}}
nget(data, ["a", "b", 0])          # 1
nset(data, ["a", "c"], 42)
npop(data, ["a", "b"])
flat = flatten(data)               # {"a|b": ..., "a|c": 42}
deep_update(data, {"a": {"d": 0}}) # merges, does not overwrite siblings
```

---

## Changelog

Full details: [`../../CHANGELOG.md`](../../CHANGELOG.md) — `[0.23.1]` entry.
