diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..7dfe042
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,31 @@
+## Summary
+
+
+
+## Type of change
+
+- [ ] Bug fix
+- [ ] New provider / API surface
+- [ ] Refactor
+- [ ] Documentation
+- [ ] Tests / CI
+- [ ] Other
+
+## Checklist
+
+- [ ] Builds with the package’s supported Xcode/Swift versions
+- [ ] Tests added or updated when behavior changes
+- [ ] No secrets or API keys committed
+- [ ] Docs updated if products, targets, public API, or dependencies changed:
+ - [ ] `README.md`
+ - [ ] `docs/ARCHITECTURE.md` (graph / tables)
+ - [ ] `CHANGELOG.md` (`[Unreleased]`)
+- [ ] Layering respected (providers → `LargeLanguageModels` → `CoreMI`; avoid new provider→provider deps)
+
+## Test plan
+
+
+
+## Related issues
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..2896a4f
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,12 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [Unreleased]
+
+### Added
+
+- Added architecture documentation in `docs/ARCHITECTURE.md`.
+- Added contribution guidelines in `CONTRIBUTING.md`.
+- Improved `README.md` with architecture, dependency graph, and documentation links.
+- Added repository research and agent workflow guidance to `CONTRIBUTING.md`.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..0e562b8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,78 @@
+# Contributing
+
+Thanks for contributing to AI.
+
+## Prerequisites
+
+- Xcode 15.4+ (Swift 5.10 toolchain)
+- Apple platform SDKs supported by this package
+
+## Getting Started
+
+1. Fork the repository and create a feature branch.
+2. Make focused changes with clear commit messages.
+3. Run tests locally:
+
+```bash
+swift test
+```
+
+4. Update documentation when behavior, APIs, or architecture changes.
+5. Open a pull request with a clear summary and test notes.
+
+## Pull Request Checklist
+
+- [ ] Changes are scoped to one topic
+- [ ] Public API changes are documented
+- [ ] Tests pass locally (`swift test`)
+- [ ] README/docs/changelog updated when needed
+
+## Repository Research Plan
+
+When working in this repository, start by identifying the layer and capability you are changing before touching code.
+
+1. Map the affected API surface:
+ - `Sources/CoreMI`
+ - `Sources/LargeLanguageModels`
+ - `Sources/AI`
+ - the specific provider target under `Sources/`
+2. Inventory shared abstractions and extension points involved in the change:
+ - request handling
+ - model identifiers
+ - chat/completions
+ - embeddings
+ - audio, file, structured output, and tool-calling support
+3. Compare provider parity for that capability to avoid introducing one-off patterns.
+4. Audit the relevant tests under `Tests/` by capability as well as by provider.
+5. Update docs when package products, imports, architecture, or behavior change.
+6. Run `swift test` for code changes and record any notable validation steps in the pull request.
+
+## Agent / Workflow Roles
+
+Use focused ownership when splitting work across contributors or automation:
+
+- **Architecture**: owns module boundaries, `Package.swift`, and `docs/ARCHITECTURE.md`.
+- **Core abstractions**: owns `CoreMI` and `LargeLanguageModels` protocols, shared request/response behavior, and compatibility across providers.
+- **Provider**: owns one provider target at a time and aligns provider-specific APIs with shared abstractions.
+- **Test**: expands coverage in `Tests/`, adds reusable fixtures/helpers, and verifies `swift test`.
+- **Docs**: keeps `README.md`, `CONTRIBUTING.md`, `docs/ARCHITECTURE.md`, and `CHANGELOG.md` aligned with code changes.
+- **Release / governance**: checks change scope, public API impact, dependency layering, and pull request hygiene.
+
+Recommended workflow:
+
+1. Scope work to one layer or one provider.
+2. Review architecture or shared abstraction impact first.
+3. Implement the provider or core change.
+4. Update tests for behavior changes.
+5. Update docs for API, product, or architecture changes.
+6. Run `swift test`.
+7. Review for consistency with neighboring providers before merging.
+
+## Reporting Issues
+
+When filing a bug, include:
+
+- Steps to reproduce
+- Expected vs actual behavior
+- Platform and Xcode/Swift versions
+- Relevant logs or sample payloads
diff --git a/Package.resolved b/Package.resolved
index 1aaa850..07dab8b 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -1,5 +1,5 @@
{
- "originHash" : "24eb1da3856f86e40bb6b87db2d4707a7cf68fd47d732dcbb9ec4d0aa614626d",
+ "originHash" : "2572cb6f07a6ae0395beb608bb9286d4ef1f1dee043e4886367aa794452e4a55",
"pins" : [
{
"identity" : "corepersistence",
@@ -42,7 +42,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections",
"state" : {
- "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
+ "revision" : "ff27e3678ddb895ebf917ce513f3105395078dae",
"version" : "1.1.4"
}
},
@@ -51,7 +51,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
- "revision" : "0687f71944021d616d34d922343dcef086855920",
+ "revision" : "60e8eb850721b5a6eebbd973b39f450a16553bd9",
"version" : "600.0.1"
}
},
diff --git a/README.md b/README.md
index cf435ef..abb9f56 100644
--- a/README.md
+++ b/README.md
@@ -1,68 +1,100 @@
-> [!IMPORTANT]
+> 🕴️[!IMPORTANT]
> This package is presently in its alpha stage of development (2026-03-04).
----
+#### Supported Platforms
-
+SPM platforms from [`Package.swift`](Package.swift): **iOS 16+**, **macOS 13+**, **tvOS 16+**, **visionOS 1+**, **watchOS 9+**.
-#### Supported Platforms
-
+
-
+
-
+
-
+
-
+
+Also targets **visionOS** (badge art not yet in `Images/`).
+
# AI
The definitive, open-source Swift framework for interfacing with generative AI.
-[Installation](#installation)\
-[Usage](#usage)
-
-* [Import the framework](#import-the-framework)
-* [Initialize an AI Client](#initialize-an-ai-client)
-* [LLM Clients Abstraction](#llm-clients-abstraction)
-* [Supported Models](#supported-models)
-* [Completions](#completions)
- * [Basic Completions](#basic-completions)
- * [Vision: Image-to-Text](#vision-image-to-text)
- * [Function Calling](#function-calling)
-* [DALLE-3 Image Generation](#dalle-3-image-generation)
-* [Audio](#audio)
- * [Audio Transcription: Whisper](#audio-transcription-whisper)
- * [Audio Generation: OpenAI](#audio-generation-openai)
- * [Audio Generation: ElevenLabs](#audio-generation-elevenlabs)
-* [Text Embeddings](#text-embeddings)
-
-[Roadmap](#roadmap) \
-[Acknowledgements](#acknowledgements) \
-[License](#license)
+## Documentation
+
+- [Architecture](docs/ARCHITECTURE.md)
+- [Contributing](CONTRIBUTING.md)
+- [Changelog](CHANGELOG.md)
+
+## Table of Contents
+
+- [Architecture Overview](#architecture-overview)
+- [Dependencies](#dependencies)
+- [Installation](#installation)
+- [Usage](#usage)
+ - [Import the framework](#import-the-framework)
+ - [Initialize an AI Client](#initialize-an-ai-client)
+ - [LLM Clients Abstraction](#llm-clients-abstraction)
+ - [Supported Models](#supported-models)
+ - [Completions](#completions)
+ - [Basic Completions](#basic-completions)
+ - [Vision: Image-to-Text](#vision-image-to-text)
+ - [Function Calling](#function-calling)
+ - [DALLE-3 Image Generation](#dalle-3-image-generation)
+ - [Audio](#audio)
+ - [Audio Transcription: Whisper](#audio-transcription-whisper)
+ - [Audio Generation: OpenAI](#audio-generation-openai)
+ - [Audio Generation: ElevenLabs](#audio-generation-elevenlabs)
+ - [Text Embeddings](#text-embeddings)
+- [Roadmap](#roadmap)
+- [Acknowledgements](#acknowledgements)
+- [License](#license)
+
+## Architecture Overview
+
+This package is organized as a Swift Package Manager workspace with layered modules:
+
+- `CoreMI` provides shared core abstractions used across providers.
+- `LargeLanguageModels` builds common LLM request/response functionality on top of `CoreMI`.
+- Provider modules (`OpenAI`, `Anthropic`, `Mistral`, `Groq`, `ElevenLabs`, etc.) implement vendor-specific APIs.
+- `AI` is the umbrella product that re-exports the main modules for one-stop integration.
+
+### Component Dependency Graph
+
+A full dependency graph generated from `Package.swift` target dependencies is available in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#component-dependency-graph).
+
+## Dependencies
+
+External package dependencies declared in `Package.swift`:
+
+- [`CorePersistence`](https://github.com/vmanot/CorePersistence)
+- [`Merge`](https://github.com/vmanot/Merge)
+- [`NetworkKit`](https://github.com/vmanot/NetworkKit)
+- [`Swallow`](https://github.com/vmanot/Swallow)
+- [`SwiftUIX`](https://github.com/SwiftUIX/SwiftUIX)
# Installation
@@ -74,6 +106,179 @@ The definitive, open-source Swift framework for interfacing with generative AI.
4. Choose the version you'd like to install.
5. Click `Add Package`.
+Or add the dependency in `Package.swift`:
+
+```swift
+dependencies: [
+ .package(url: "https://github.com/PreternaturalAI/AI.git", branch: "main")
+]
+```
+
+Then link the `AI` product (umbrella) or a standalone product such as `OpenAI`, `Anthropic`, or `Perplexity` (see [Architecture](#architecture)).
+
+# Architecture
+
+The package is organized in layers. Provider SDKs implement shared protocols (`LLMRequestHandling`, embeddings, TTS, and so on) defined in the core modules.
+
+| Layer | Modules | Responsibility |
+|-------|---------|----------------|
+| Umbrella module | `AI` | `@_exported` re-exports **CoreMI**, **LargeLanguageModels**, **OpenAI** (and Swallow macros client). Other bundled modules still need their own `import`. |
+| Umbrella product | `AI` library | SPM product that **links** core + Anthropic, Cohere, ElevenLabs, Groq, HuggingFace, Jina, Mistral, Ollama, OpenAI, and the `AI` module |
+| Providers | `OpenAI`, `Anthropic`, `Mistral`, `Groq`, `Ollama`, `Perplexity`, `Cohere`, `Jina`, `VoyageAI`, `TogetherAI`, `ElevenLabs`, `PlayHT`, `Rime`, `HumeAI`, `NeetsAI`, `_Gemini`, `HuggingFace`, … | API clients and model types |
+| LLM abstractions | `LargeLanguageModels` | `AbstractLLM`, `PromptLiteral`, chat/function-calling, embeddings protocols |
+| Foundations | `CoreMI` | Request handling, model identifiers, service credentials, ASR/TTS bases |
+| External | Swallow, Merge, NetworkKit, CorePersistence, SwiftUIX | Shared infrastructure (see [Dependencies](#dependencies)) |
+
+`import AI` is enough for OpenAI + shared LLM types. For other clients linked by the product, add e.g. `import Anthropic` or `import Groq`. Providers shipped only as standalone products (`Perplexity`, `_Gemini`, `VoyageAI`, …) require linking that product.
+
+### Component dependency graph
+
+Graph of **package targets** as declared in [`Package.swift`](Package.swift) (external packages shown once at the bottom). For products, tests, and design notes, see **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)**.
+
+```mermaid
+flowchart TB
+ subgraph umbrella [Umbrella]
+ AI
+ end
+
+ subgraph providers [Provider targets]
+ OpenAI
+ Anthropic
+ Mistral
+ Groq
+ Ollama
+ Perplexity
+ Cohere
+ Jina
+ VoyageAI
+ TogetherAI
+ ElevenLabs
+ PlayHT
+ Rime
+ HumeAI
+ NeetsAI
+ Gemini["_Gemini"]
+ HuggingFace
+ end
+
+ subgraph core [Core targets]
+ LargeLanguageModels
+ CoreMI
+ end
+
+ subgraph external [External packages]
+ Swallow
+ Merge
+ NetworkKit
+ CorePersistence
+ SwiftUIX
+ end
+
+ AI --> CoreMI
+ AI --> LargeLanguageModels
+ AI --> OpenAI
+ AI --> Anthropic
+ AI --> Mistral
+ AI --> Groq
+ AI --> Ollama
+ AI --> Cohere
+ AI --> ElevenLabs
+ AI --> HuggingFace
+ AI --> Jina
+
+ OpenAI --> LargeLanguageModels
+ Anthropic --> LargeLanguageModels
+ Mistral --> LargeLanguageModels
+ Groq --> LargeLanguageModels
+ Ollama --> LargeLanguageModels
+ Perplexity --> LargeLanguageModels
+ Perplexity --> OpenAI
+ Cohere --> LargeLanguageModels
+ Jina --> LargeLanguageModels
+ VoyageAI --> LargeLanguageModels
+ TogetherAI --> LargeLanguageModels
+ ElevenLabs --> LargeLanguageModels
+ PlayHT --> LargeLanguageModels
+ Rime --> LargeLanguageModels
+ HumeAI --> LargeLanguageModels
+ NeetsAI --> LargeLanguageModels
+ Gemini --> LargeLanguageModels
+ HuggingFace --> CoreMI
+
+ LargeLanguageModels --> CoreMI
+ LargeLanguageModels --> CorePersistence
+ LargeLanguageModels --> Merge
+ LargeLanguageModels --> NetworkKit
+ LargeLanguageModels --> Swallow
+ LargeLanguageModels --> SwiftUIX
+
+ CoreMI --> CorePersistence
+ CoreMI --> Merge
+ CoreMI --> Swallow
+```
+
+**Notes**
+
+- Most providers also depend on `CoreMI`, `CorePersistence`, `Merge`, `NetworkKit`, and `Swallow` directly (edges omitted above for readability where they already flow through `LargeLanguageModels`).
+- **OpenAI** and **Anthropic** depend on `LargeLanguageModels` + networking stack, not on `CoreMI` directly in `Package.swift`.
+- **Perplexity** is the only provider that depends on another provider target (`OpenAI`).
+- **HuggingFace** depends on `CoreMI` + `Swallow` only (hub/tokenizer helpers, not the full LLM stack).
+- The `AI` **product** does **not** link every target (for example `_Gemini`, `Perplexity`, `PlayHT`, `Rime`, `TogetherAI`, `VoyageAI`, `HumeAI`, `NeetsAI` are separate products).
+- The `AI` **module** re-exports only CoreMI, LargeLanguageModels, and OpenAI among first-party modules (`Sources/AI/module.swift`).
+
+### Protocol capabilities (from source)
+
+Which shared protocols have an explicit client conformance today:
+
+| Target | `LLMRequestHandling` | `TextEmbeddingsRequestHandling` | Notes |
+|--------|:--------------------:|:-------------------------------:|-------|
+| OpenAI | yes | yes | Also images, Whisper, speech, assistants |
+| Anthropic | yes | | |
+| Mistral | yes | yes | |
+| Groq | yes | | |
+| Ollama | yes | | |
+| Perplexity | yes | | Depends on OpenAI target |
+| Cohere | | yes | |
+| Jina | | yes | |
+| VoyageAI | | yes | |
+| TogetherAI, ElevenLabs, PlayHT, Rime, HumeAI, NeetsAI, _Gemini, HuggingFace | | | Provider-specific client APIs / hub helpers (see `Sources/`) |
+
+Full layering detail: **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)**. Docs index: **[docs/README.md](docs/README.md)**.
+
+# Dependencies
+
+### External Swift packages
+
+| Package | Repository | Role |
+|---------|------------|------|
+| Swallow | [vmanot/Swallow](https://github.com/vmanot/Swallow) | Extensions, macros client, diagnostics |
+| Merge | [vmanot/Merge](https://github.com/vmanot/Merge) | Concurrency / async utilities |
+| NetworkKit | [vmanot/NetworkKit](https://github.com/vmanot/NetworkKit) | HTTP client & API specifications |
+| CorePersistence | [vmanot/CorePersistence](https://github.com/vmanot/CorePersistence) | Persistence & schema helpers (e.g. JSONSchema) |
+| SwiftUIX | [SwiftUIX/SwiftUIX](https://github.com/SwiftUIX/SwiftUIX) | SwiftUI extensions |
+
+Transitive pins (see [`Package.resolved`](Package.resolved)) include **SwiftAPI**, **swift-collections**, and **swift-syntax**.
+
+### SPM products you can link
+
+Exact product names from `Package.swift`:
+
+| Product | Targets exposed | Use when |
+|---------|-----------------|----------|
+| `AI` | CoreMI, LargeLanguageModels, Anthropic, Cohere, ElevenLabs, Groq, HuggingFace, Jina, Mistral, Ollama, OpenAI, AI | Default multi-provider app dependency |
+| `OpenAI` | OpenAI | OpenAI-only |
+| `Anthropic` | Anthropic | Anthropic-only |
+| `Perplexity` | Perplexity | Perplexity (pulls OpenAI transitively) |
+| `TogetherAI` | TogetherAI | Together AI |
+| `VoyageAI` | VoyageAI | Voyage embeddings |
+| `PlayHT` | PlayHT | PlayHT voice |
+| `Rime` | Rime | Rime voice |
+| `HumeAI` | HumeAI | Hume |
+| `NeetsAI` | NeetsAI | Neets |
+| `_Gemini` | _Gemini | Google Gemini client |
+
+There is **no** standalone SPM product today for `CoreMI`, `LargeLanguageModels`, `Cohere`, `Groq`, `HuggingFace`, `Jina`, `Mistral`, `Ollama`, or `ElevenLabs` — consume them via the `AI` product (or add a product in `Package.swift` if you need a leaner slice).
+
# Usage
## Import the framework
@@ -551,14 +756,76 @@ let embeddings = try await LLMManager.client.textEmbeddings(
return embeddings.data.first?.embedding.description
```
+# Documentation
+
+| Document | Contents |
+|----------|----------|
+| **[docs/README.md](docs/README.md)** | Documentation index |
+| **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** | Full architecture, products vs targets, Mermaid graph, protocol matrix, tests |
+| **[CONTRIBUTING.md](CONTRIBUTING.md)** | Dev setup, coding guidelines, how to add a provider |
+| **[CHANGELOG.md](CHANGELOG.md)** | Release notes and unreleased changes |
+| **[LICENSE](LICENSE)** | MIT License text |
+
+API behavior is illustrated in the [Usage](#usage) sections above; protocol details live in `Sources/LargeLanguageModels` and `Sources/CoreMI`.
+
# Roadmap
-- [x] OpenAI
+Status reflects modules present in this repository (`Sources/` + `Package.swift`). Checked items ship as package targets; depth of feature coverage varies by provider.
+
+### Core
+
+- [x] `CoreMI` — request handling, model identifiers, services, ASR/TTS foundations
+- [x] `LargeLanguageModels` — `AbstractLLM`, prompts, function calling, embeddings protocols
+- [x] `AI` umbrella product
+
+### LLM & multimodal providers
+
+- [x] OpenAI (chat, vision, tools, images, Whisper, speech)
- [x] Anthropic
- [x] Mistral
+- [x] Groq
- [x] Ollama
-- [ ] Perplexity
-- [ ] Groq
+- [x] Perplexity
+- [x] TogetherAI
+- [x] `_Gemini` (Google Gemini client; standalone product)
+- [ ] Broader parity matrix (streaming, tools, vision) across every LLM provider
+
+### Embeddings & hub
+
+- [x] OpenAI embeddings
+- [x] Cohere
+- [x] Jina
+- [x] VoyageAI
+- [x] Hugging Face hub helpers / tokenizer resources
+
+### Voice & speech
+
+- [x] ElevenLabs
+- [x] PlayHT
+- [x] Rime
+- [x] HumeAI
+- [x] NeetsAI
+- [x] OpenAI TTS / Whisper
+
+### Project hygiene
+
+- [x] Architecture & dependency documentation
+- [x] Contributing guide, docs index, PR template & changelog
+- [ ] Register missing test targets (Ollama, Rime, TogetherAI folder)
+- [ ] visionOS badge artwork under `Images/`
+- [ ] Tagged semantic releases with automated changelog sections
+
+# Contributing
+
+Contributions are welcome. Please read **[CONTRIBUTING.md](CONTRIBUTING.md)** for:
+
+- Environment and build requirements
+- PR expectations and testing notes
+- Steps to add or extend a provider without breaking layering rules
+
+# Changelog
+
+See **[CHANGELOG.md](CHANGELOG.md)** for user-visible changes. The package is in **alpha**; expect API evolution between releases.
# Acknowledgements
@@ -567,4 +834,4 @@ return embeddings.data.first?.embedding.description
# License
-This package is licensed under the MIT License.
+This package is licensed under the [MIT License](LICENSE).
diff --git a/Sources/LargeLanguageModels/Intramodular/LLMs/Agents/LLMAgentPipeline.swift b/Sources/LargeLanguageModels/Intramodular/LLMs/Agents/LLMAgentPipeline.swift
new file mode 100644
index 0000000..b83e9a1
--- /dev/null
+++ b/Sources/LargeLanguageModels/Intramodular/LLMs/Agents/LLMAgentPipeline.swift
@@ -0,0 +1,148 @@
+//
+// Copyright (c) Vatsal Manot
+//
+
+import Foundation
+import Swallow
+
+// MARK: - Stage protocol
+
+/// A single stage in an LLM-driven agent pipeline.
+///
+/// Each stage receives a plain-text input, processes it with an LLM using
+/// its ``systemPrompt``, and returns a plain-text output that feeds the next stage.
+public protocol LLMAgentStage: Sendable {
+ /// A human-readable label for this stage (e.g. `"Observer"`).
+ var stageName: String { get }
+
+ /// The system prompt that instructs the LLM on how to behave in this stage.
+ var systemPrompt: String { get }
+
+ /// Process `input` using `llm` and return the stage's output.
+ func process(input: String, using llm: any LLMRequestHandling) async throws -> String
+}
+
+extension LLMAgentStage {
+ public func process(input: String, using llm: any LLMRequestHandling) async throws -> String {
+ let messages: [AbstractLLM.ChatMessage] = [
+ .system(systemPrompt),
+ .user(input),
+ ]
+ let completion = try await llm.complete(messages)
+ return try completion.toString()
+ }
+}
+
+// MARK: - Built-in stages
+
+extension AbstractLLM {
+ /// Observes raw input (events, signals, changes) and describes what is happening.
+ public struct ObserverStage: LLMAgentStage {
+ public let stageName: String = "Observer"
+ public let systemPrompt: String
+
+ public init(
+ systemPrompt: String = """
+ You are an observer agent. Given raw input data, events, or signals, \
+ clearly describe what is happening. Be concise and factual.
+ """
+ ) {
+ self.systemPrompt = systemPrompt
+ }
+ }
+
+ /// Analyses observations to discover meaning, patterns, and predictions.
+ public struct ResearchStage: LLMAgentStage {
+ public let stageName: String = "Research"
+ public let systemPrompt: String
+
+ public init(
+ systemPrompt: String = """
+ You are a research agent. Given an observation, analyse its meaning, \
+ identify patterns, and make predictions. Provide a concise analytical summary.
+ """
+ ) {
+ self.systemPrompt = systemPrompt
+ }
+ }
+
+ /// Takes research results and produces a concrete decision or action recommendation.
+ public struct DecisionStage: LLMAgentStage {
+ public let stageName: String = "Decision"
+ public let systemPrompt: String
+
+ public init(
+ systemPrompt: String = """
+ You are a decision agent. Given research findings, produce a clear, \
+ actionable decision or recommendation. Be direct and specific.
+ """
+ ) {
+ self.systemPrompt = systemPrompt
+ }
+ }
+}
+
+// MARK: - Pipeline result
+
+extension AbstractLLM {
+ /// The output produced by each stage of an ``AgentPipeline`` run.
+ public struct AgentPipelineResult: Sendable {
+ /// Raw input passed into the pipeline.
+ public let input: String
+ /// Output from the ``ObserverStage``: what is happening.
+ public let observation: String
+ /// Output from the ``ResearchStage``: what it means.
+ public let research: String
+ /// Output from the ``DecisionStage``: what to do.
+ public let decision: String
+ }
+}
+
+// MARK: - Pipeline
+
+extension AbstractLLM {
+ /// A sequential Observer → Research → Decision agent pipeline.
+ ///
+ /// Each stage's output becomes the next stage's input, mirroring the
+ /// Reality → Observation → Intelligence → Decision flow.
+ ///
+ /// ```swift
+ /// let pipeline = AbstractLLM.AgentPipeline(llm: myLLM)
+ /// let result = try await pipeline.run(input: "Server CPU spiked to 98% at 03:00 UTC")
+ /// print(result.decision) // "Scale out the web tier by two instances …"
+ /// ```
+ public struct AgentPipeline: Sendable {
+ public let observer: any LLMAgentStage
+ public let researcher: any LLMAgentStage
+ public let decisionMaker: any LLMAgentStage
+ public let llm: any LLMRequestHandling
+
+ public init(
+ observer: any LLMAgentStage = ObserverStage(),
+ researcher: any LLMAgentStage = ResearchStage(),
+ decisionMaker: any LLMAgentStage = DecisionStage(),
+ llm: any LLMRequestHandling
+ ) {
+ self.observer = observer
+ self.researcher = researcher
+ self.decisionMaker = decisionMaker
+ self.llm = llm
+ }
+
+ /// Run the full Observer → Research → Decision pipeline on `input`.
+ ///
+ /// - Parameter input: The raw reality input (events, signals, data).
+ /// - Returns: An ``AgentPipelineResult`` containing each stage's output.
+ public func run(input: String) async throws -> AgentPipelineResult {
+ let observation = try await observer.process(input: input, using: llm)
+ let research = try await researcher.process(input: observation, using: llm)
+ let decision = try await decisionMaker.process(input: research, using: llm)
+ return AgentPipelineResult(
+ input: input,
+ observation: observation,
+ research: research,
+ decision: decision
+ )
+ }
+ }
+}
diff --git a/Sources/LargeLanguageModels/Intramodular/LLMs/Logging/FailedLLMResponseStore.swift b/Sources/LargeLanguageModels/Intramodular/LLMs/Logging/FailedLLMResponseStore.swift
new file mode 100644
index 0000000..8ddad34
--- /dev/null
+++ b/Sources/LargeLanguageModels/Intramodular/LLMs/Logging/FailedLLMResponseStore.swift
@@ -0,0 +1,108 @@
+//
+// Copyright (c) Vatsal Manot
+//
+
+import Foundation
+import Swallow
+
+extension AbstractLLM {
+ /// A record of a chat completion request that resulted in an error.
+ ///
+ /// These records can be exported and used to improve prompts or to build a
+ /// fine-tuning dataset that corrects known failure modes.
+ public struct FailedChatResponse: Codable, Hashable, Identifiable, Sendable {
+ public let id: UUID
+ public let timestamp: Date
+ public let modelIdentifier: ModelIdentifier?
+ public let prompt: [AbstractLLM.ChatMessage]
+ public let errorDescription: String
+
+ public init(
+ id: UUID = UUID(),
+ timestamp: Date = Date(),
+ modelIdentifier: ModelIdentifier? = nil,
+ prompt: [AbstractLLM.ChatMessage],
+ errorDescription: String
+ ) {
+ self.id = id
+ self.timestamp = timestamp
+ self.modelIdentifier = modelIdentifier
+ self.prompt = prompt
+ self.errorDescription = errorDescription
+ }
+ }
+}
+
+/// A thread-safe store for chat completion requests that resulted in errors.
+///
+/// Accumulated entries can be exported as JSONL for use in fine-tuning
+/// pipelines that teach models to handle or avoid past failure patterns.
+public actor FailedLLMResponseStore {
+ /// The shared, process-wide failed-response store.
+ public static let shared = FailedLLMResponseStore()
+
+ private var _entries: [AbstractLLM.FailedChatResponse] = []
+
+ public init() {}
+
+ /// All recorded failed responses, in chronological order.
+ public var entries: [AbstractLLM.FailedChatResponse] {
+ _entries
+ }
+
+ /// Append a new failed-response record.
+ public func record(_ entry: AbstractLLM.FailedChatResponse) {
+ _entries.append(entry)
+ }
+
+ /// Remove all recorded entries.
+ public func clear() {
+ _entries.removeAll()
+ }
+
+ /// Export all entries as a JSONL string.
+ ///
+ /// Each line is a JSON object representing one ``AbstractLLM/FailedChatResponse``.
+ /// The output is suitable for ingestion by fine-tuning pipelines that use
+ /// the JSONL format (e.g. OpenAI fine-tuning, Axolotl, Unsloth).
+ public func exportAsJSONL() throws -> String {
+ let encoder = JSONEncoder()
+ encoder.outputFormatting = []
+ encoder.dateEncodingStrategy = .iso8601
+ return try _entries
+ .map { try String(decoding: encoder.encode($0), as: UTF8.self) }
+ .joined(separator: "\n")
+ }
+}
+
+// MARK: - LLMRequestHandling integration
+
+extension LLMRequestHandling {
+ /// Complete a chat prompt, automatically recording any failure in `store`.
+ ///
+ /// On failure the record is appended to `store` and then the error is
+ /// rethrown so normal error-handling still applies.
+ ///
+ /// - Parameters:
+ /// - prompt: The chat prompt to complete.
+ /// - parameters: Completion parameters.
+ /// - store: The ``FailedLLMResponseStore`` to append failures to.
+ public func complete(
+ prompt: AbstractLLM.ChatPrompt,
+ parameters: AbstractLLM.ChatCompletionParameters,
+ recordingFailuresIn store: FailedLLMResponseStore
+ ) async throws -> AbstractLLM.ChatCompletion {
+ do {
+ return try await complete(prompt: prompt, parameters: parameters)
+ } catch {
+ let modelID = try? prompt.context.modelIdentifier?._oneValue
+ let entry = AbstractLLM.FailedChatResponse(
+ modelIdentifier: modelID,
+ prompt: prompt.messages,
+ errorDescription: error.localizedDescription
+ )
+ await store.record(entry)
+ throw error
+ }
+ }
+}
diff --git a/Sources/LargeLanguageModels/Intramodular/LLMs/Logging/LLMErrorLogger.swift b/Sources/LargeLanguageModels/Intramodular/LLMs/Logging/LLMErrorLogger.swift
new file mode 100644
index 0000000..34c7f14
--- /dev/null
+++ b/Sources/LargeLanguageModels/Intramodular/LLMs/Logging/LLMErrorLogger.swift
@@ -0,0 +1,94 @@
+//
+// Copyright (c) Vatsal Manot
+//
+
+import Foundation
+import Swallow
+
+extension AbstractLLM {
+ /// A record of an error that occurred during an LLM request.
+ public struct ErrorLogEntry: Codable, Hashable, Identifiable, Sendable {
+ public let id: UUID
+ public let timestamp: Date
+ public let modelIdentifier: ModelIdentifier?
+ public let promptDescription: String
+ public let errorDescription: String
+
+ public init(
+ id: UUID = UUID(),
+ timestamp: Date = Date(),
+ modelIdentifier: ModelIdentifier? = nil,
+ promptDescription: String,
+ errorDescription: String
+ ) {
+ self.id = id
+ self.timestamp = timestamp
+ self.modelIdentifier = modelIdentifier
+ self.promptDescription = promptDescription
+ self.errorDescription = errorDescription
+ }
+ }
+}
+
+/// A thread-safe logger for errors that occur during LLM requests.
+///
+/// Errors accumulated here can be reviewed to improve prompt design or to
+/// identify patterns in failures. Use
+/// ``LLMRequestHandling/complete(_:parameters:loggingErrorsTo:)`` to
+/// automatically capture failures from any `LLMRequestHandling` call.
+public actor LLMErrorLogger {
+ /// The shared, process-wide error logger.
+ public static let shared = LLMErrorLogger()
+
+ private var _entries: [AbstractLLM.ErrorLogEntry] = []
+
+ public init() {}
+
+ /// All recorded error entries, in chronological order.
+ public var entries: [AbstractLLM.ErrorLogEntry] {
+ _entries
+ }
+
+ /// Append a new entry to the log.
+ public func log(_ entry: AbstractLLM.ErrorLogEntry) {
+ _entries.append(entry)
+ }
+
+ /// Remove all recorded entries.
+ public func clear() {
+ _entries.removeAll()
+ }
+}
+
+// MARK: - LLMRequestHandling integration
+
+extension LLMRequestHandling {
+ /// Complete a prompt, automatically logging any thrown error to `logger`.
+ ///
+ /// On failure the entry is logged and then the error is rethrown so normal
+ /// error-handling still applies.
+ ///
+ /// - Parameters:
+ /// - prompt: The prompt to complete.
+ /// - parameters: Completion parameters.
+ /// - logger: The ``LLMErrorLogger`` to append failures to.
+ /// Defaults to ``LLMErrorLogger/shared``.
+ public func complete(
+ _ prompt: Prompt,
+ parameters: Prompt.CompletionParameters,
+ loggingErrorsTo logger: LLMErrorLogger
+ ) async throws -> Prompt.Completion {
+ do {
+ return try await complete(prompt: prompt, parameters: parameters)
+ } catch {
+ let modelID = try? prompt.context.modelIdentifier?._oneValue
+ let entry = AbstractLLM.ErrorLogEntry(
+ modelIdentifier: modelID,
+ promptDescription: String(describing: prompt),
+ errorDescription: error.localizedDescription
+ )
+ await logger.log(entry)
+ throw error
+ }
+ }
+}
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
new file mode 100644
index 0000000..913a99c
--- /dev/null
+++ b/docs/ARCHITECTURE.md
@@ -0,0 +1,100 @@
+# Architecture
+
+This document summarizes the package architecture as defined in `Package.swift`.
+
+## Module Layers
+
+1. **Core layer**
+ - `CoreMI`
+2. **LLM abstraction layer**
+ - `LargeLanguageModels`
+3. **Provider layer**
+ - `Anthropic`, `Cohere`, `ElevenLabs`, `Groq`, `HuggingFace`, `HumeAI`, `Jina`, `Mistral`, `NeetsAI`, `Ollama`, `OpenAI`, `Perplexity`, `PlayHT`, `Rime`, `TogetherAI`, `VoyageAI`, `_Gemini`
+4. **Umbrella layer**
+ - `AI`
+
+## Component Dependency Graph
+
+In this graph, `CorePersistence`, `Merge`, `NetworkKit`, `Swallow`, and `SwiftUIX` are external package dependencies (not targets in this repository).
+
+```mermaid
+graph TD
+ CoreMI --> CorePersistence
+ CoreMI --> Merge
+ CoreMI --> Swallow
+
+ LargeLanguageModels --> CoreMI
+ LargeLanguageModels --> CorePersistence
+ LargeLanguageModels --> Merge
+ LargeLanguageModels --> NetworkKit
+ LargeLanguageModels --> Swallow
+ LargeLanguageModels --> SwiftUIX
+
+ Anthropic --> LargeLanguageModels
+ OpenAI --> LargeLanguageModels
+ HuggingFace --> CoreMI
+ HuggingFace --> Swallow
+
+ Cohere --> CoreMI
+ Cohere --> LargeLanguageModels
+ ElevenLabs --> CoreMI
+ ElevenLabs --> LargeLanguageModels
+ Groq --> CoreMI
+ Groq --> LargeLanguageModels
+ HumeAI --> CoreMI
+ HumeAI --> LargeLanguageModels
+ Jina --> CoreMI
+ Jina --> LargeLanguageModels
+ Mistral --> CoreMI
+ Mistral --> LargeLanguageModels
+ NeetsAI --> CoreMI
+ NeetsAI --> LargeLanguageModels
+ Ollama --> CoreMI
+ Ollama --> LargeLanguageModels
+ PlayHT --> CoreMI
+ PlayHT --> LargeLanguageModels
+ Rime --> CoreMI
+ Rime --> LargeLanguageModels
+ TogetherAI --> CoreMI
+ TogetherAI --> LargeLanguageModels
+ VoyageAI --> CoreMI
+ VoyageAI --> LargeLanguageModels
+ _Gemini --> CoreMI
+ _Gemini --> LargeLanguageModels
+
+ Perplexity --> OpenAI
+ Perplexity --> CoreMI
+ Perplexity --> LargeLanguageModels
+
+ AI --> CoreMI
+ AI --> LargeLanguageModels
+ AI --> Anthropic
+ AI --> Cohere
+ AI --> ElevenLabs
+ AI --> Groq
+ AI --> HuggingFace
+ AI --> Jina
+ AI --> Mistral
+ AI --> Ollama
+ AI --> OpenAI
+
+ AI -. standalone product .-> HumeAI
+ AI -. standalone product .-> NeetsAI
+ AI -. standalone product .-> Perplexity
+ AI -. standalone product .-> PlayHT
+ AI -. standalone product .-> Rime
+ AI -. standalone product .-> TogetherAI
+ AI -. standalone product .-> VoyageAI
+ AI -. standalone product .-> _Gemini
+```
+> Note: The `AI` umbrella target currently depends on `CoreMI`, `LargeLanguageModels`, `Anthropic`, `Cohere`, `ElevenLabs`, `Groq`, `HuggingFace`, `Jina`, `Mistral`, `Ollama`, and `OpenAI`. Other provider modules in this repository are distributed as standalone products and are not re-exported by `AI` in `Package.swift`.
+
+> Note: `HuggingFace` intentionally differs from most provider modules: in `Package.swift` it depends on `CoreMI` and `Swallow`, and does not depend on `LargeLanguageModels`.
+
+## External Dependencies
+
+- `CorePersistence`
+- `Merge`
+- `NetworkKit`
+- `Swallow`
+- `SwiftUIX`
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..5e24f4c
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,31 @@
+# Documentation
+
+Guides for the **AI** Swift package ([PreternaturalAI/AI](https://github.com/PreternaturalAI/AI)).
+
+| Document | Audience | Description |
+|----------|----------|-------------|
+| [../README.md](../README.md) | Everyone | Install, usage examples, architecture summary, dependency graph, roadmap |
+| [ARCHITECTURE.md](ARCHITECTURE.md) | Contributors & integrators | Layers, products vs targets, Mermaid graphs, protocol matrix, tests |
+| [../CONTRIBUTING.md](../CONTRIBUTING.md) | Contributors | Setup, PR process, adding providers |
+| [../CHANGELOG.md](../CHANGELOG.md) | Everyone | Notable changes |
+| [../LICENSE](../LICENSE) | Everyone | MIT |
+
+## Quick orientation
+
+```text
+Package.swift products, targets, external deps
+Sources/CoreMI foundations (requests, model IDs, services)
+Sources/LargeLanguageModels AbstractLLM, prompts, embeddings protocols
+Sources/ vendor clients
+Sources/AI umbrella module (selective @_exported imports)
+Tests/ parallel test targets (see ARCHITECTURE.md for gaps)
+docs/ long-form documentation (this folder)
+```
+
+## Keeping docs honest
+
+When you change `Package.swift` or add a provider:
+
+1. Update the dependency graph and tables in [ARCHITECTURE.md](ARCHITECTURE.md).
+2. Mirror user-facing bits in [../README.md](../README.md) (products, roadmap, import notes).
+3. Note the change under `[Unreleased]` in [../CHANGELOG.md](../CHANGELOG.md).