diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..7dfe0424 --- /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/.github/agents/my-agent.agent.md b/.github/agents/my-agent.agent.md new file mode 100644 index 00000000..8ff8aa88 --- /dev/null +++ b/.github/agents/my-agent.agent.md @@ -0,0 +1,13 @@ +--- +# Fill in the fields below to create a basic custom agent for your repository. +# The Copilot CLI can be used for local testing: https://gh.io/customagents/cli +# To make this agent available, merge this file into the default repository branch. +# For format details, see: https://gh.io/customagents/config + +name: +description: +--- + +# My Agent + +Describe what your agent does here. diff --git a/.github/dependabot.ymlv b/.github/dependabot.ymlv new file mode 100644 index 00000000..5990d9c6 --- /dev/null +++ b/.github/dependabot.ymlv @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/apisec-scan.yml b/.github/workflows/apisec-scan.yml new file mode 100644 index 00000000..2c24a929 --- /dev/null +++ b/.github/workflows/apisec-scan.yml @@ -0,0 +1,71 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# APIsec addresses the critical need to secure APIs before they reach production. +# APIsec provides the industry’s only automated and continuous API testing platform that uncovers security vulnerabilities and logic flaws in APIs. +# Clients rely on APIsec to evaluate every update and release, ensuring that no APIs go to production with vulnerabilities. + +# How to Get Started with APIsec.ai +# 1. Schedule a demo at https://www.apisec.ai/request-a-demo . +# +# 2. Register your account at https://cloud.apisec.ai/#/signup . +# +# 3. Register your API . See the video (https://www.youtube.com/watch?v=MK3Xo9Dbvac) to get up and running with APIsec quickly. +# +# 4. Get GitHub Actions scan attributes from APIsec Project -> Configurations -> Integrations -> CI-CD -> GitHub Actions +# +# apisec-run-scan +# +# This action triggers the on-demand scans for projects registered in APIsec. +# If your GitHub account allows code scanning alerts, you can then upload the sarif file generated by this action to show the scan findings. +# Else you can view the scan results from the project home page in APIsec Platform. +# The link to view the scan results is also displayed on the console on successful completion of action. + +# This is a starter workflow to help you get started with APIsec-Scan Actions + +name: APIsec + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + # Customize trigger events based on your DevSecOps processes. + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '27 1 * * 5' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + + +permissions: + contents: read + +jobs: + + Trigger_APIsec_scan: + permissions: + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + runs-on: ubuntu-latest + + steps: + - name: APIsec scan + uses: apisec-inc/apisec-run-scan@025432089674a28ba8fb55f8ab06c10215e772ea + with: + # The APIsec username with which the scans will be executed + apisec-username: ${{ secrets.apisec_username }} + # The Password of the APIsec user with which the scans will be executed + apisec-password: ${{ secrets.apisec_password}} + # The name of the project for security scan + apisec-project: "VAmPI" + # The name of the sarif format result file The file is written only if this property is provided. + sarif-result-file: "apisec-results.sarif" + - name: Import results + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: ./apisec-results.sarif diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..55f1a7dc --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,99 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '15 21 * * 5' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: swift + build-mode: autobuild + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - name: Run manual build steps + if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/preternatural-build.yml b/.github/workflows/preternatural-build.yml index 181b18eb..2726ed3e 100644 --- a/.github/workflows/preternatural-build.yml +++ b/.github/workflows/preternatural-build.yml @@ -5,14 +5,21 @@ on: pull_request: branches: [ main ] workflow_dispatch: - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - jobs: - build: - uses: PreternaturalAI/preternatural-github-actions/.github/workflows/preternatural-build.yml@main - with: - xcode-version: '16' - configurations: '["debug"]' \ No newline at end of file + preternatural-build: + name: Build (Xcode ${{ matrix.xcode }}) + runs-on: ghcr.io/cirruslabs/macos-runner:sequoia + strategy: + matrix: + xcode: ['16.2', '16.3'] + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Run Preternatural Build + uses: PreternaturalAI/preternatural-github-actions/preternatural-build@main + with: + xcode-version: ${{ matrix.xcode }} + configurations: '["debug"]' \ No newline at end of file diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml new file mode 100644 index 00000000..21ae770f --- /dev/null +++ b/.github/workflows/swift.yml @@ -0,0 +1,22 @@ +# This workflow will build a Swift project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift + +name: Swift + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + - name: Build + run: swift build -v + - name: Run tests + run: swift test -v diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..2896a4fd --- /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 00000000..e0088389 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,123 @@ +--- +layout: default +--- + +# Contributing to Open Source Guides + +Thanks for checking out the Open Source Guides! We're excited to hear and learn from you. Your experiences will benefit others who read and use these guides. + +We've put together the following guidelines to help you figure out where you can best be helpful. + +## Table of Contents + +0. [Types of contributions we're looking for](#types-of-contributions-were-looking-for) +0. [Ground rules & expectations](#ground-rules--expectations) +0. [How to contribute](#how-to-contribute) +0. [Style guide](#style-guide) +0. [Setting up your environment](#setting-up-your-environment) +0. [Community](#community) + +## Types of contributions we're looking for + +There are many ways you can directly contribute to the guides (in descending order of need): + +* Fix editorial inconsistencies or inaccuracies +* [Translate guides into other languages](docs/translations.md) + +Interested in contributing to this Open Source Guide? Read on! + +## Ground rules & expectations + +Before we get started, here are a few things we expect from you (and that you should expect from others): + +* Be kind and thoughtful in your conversations around this project. We all come from different backgrounds and projects, which means we likely have different perspectives on "how open source is done." Try to listen to others rather than convince them that your way is correct. +* Open Source Guides are released with a [Contributor Code of Conduct](./CODE_OF_CONDUCT.md). By participating in this project, you agree to abide by its terms. +* Please ensure that your contribution passes all tests if you open a pull request. If there are test failures, you will need to address them before we can merge your contribution. +* When adding content, please consider if it is widely valuable. Please don't add references or links to things you or your employer have created, as others will do so if they appreciate it. + +## How to contribute + +If you'd like to contribute, start by searching through the [pull requests](https://github.com/github/opensource.guide/pulls) to see whether someone else has raised a similar idea or question. + +If you don't see your idea listed, and you think it fits into the goals of this guide, open a pull request. + +## 💡 Quick Tip for Beginners + +1. Always create a new branch for your changes. +2. Write clear commit messages. +3. Test your changes locally before submitting a PR. +4. Follow the style guide. +5. Be patient during reviews. + +## Style guide + +If you're writing content, see the [style guide](./docs/styleguide.md) to help your prose match the rest of the guides. + +## Setting up your environment + +This site is powered by [Jekyll](https://jekyllrb.com/). Running it on your local machine requires a working [Ruby](https://www.ruby-lang.org/en/) installation with [Bundler](https://bundler.io/) along with [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). + +Once you have that set up: + +1. Grant execution permissions to the scripts: + +```bash +chmod +x script/bootstrap +chmod +x script/server +``` + +2. Execute the scripts: + +```bash +./script/bootstrap +./script/server +``` + +…and open in your web browser. + +## 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 + +Discussions about the Open Source Guides take place on this repository's [Pull Requests](https://github.com/github/opensource.guide/pulls) section. Anybody is welcome to join these conversations. + +Wherever possible, do not take these conversations to private channels, including contacting the maintainers directly. Keeping communication public means everybody can benefit and learn from the conversation. diff --git a/PATPAT-main.zip b/PATPAT-main.zip new file mode 100644 index 00000000..35d51791 Binary files /dev/null and b/PATPAT-main.zip differ diff --git a/Package.resolved b/Package.resolved index 1aaa8500..07dab8b6 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/Package.swift b/Package.swift index ae497619..96cbf96e 100644 --- a/Package.swift +++ b/Package.swift @@ -95,6 +95,12 @@ let package = Package( "VoyageAI" ] ), + .library( + name: "xAI", + targets: [ + "xAI" + ] + ), ], dependencies: [ .package(url: "https://github.com/vmanot/CorePersistence.git", branch: "main"), @@ -371,6 +377,21 @@ let package = Package( .enableExperimentalFeature("AccessLevelOnImport") ] ), + .target( + name: "xAI", + dependencies: [ + "CorePersistence", + "CoreMI", + "LargeLanguageModels", + "Merge", + "NetworkKit", + "Swallow" + ], + path: "Sources/xAI", + swiftSettings: [ + .enableExperimentalFeature("AccessLevelOnImport") + ] + ), .target( name: "HuggingFace", dependencies: [ @@ -401,6 +422,7 @@ let package = Package( "OpenAI", "Swallow", "NeetsAI", + "xAI", ], path: "Sources/AI", swiftSettings: [ @@ -573,6 +595,18 @@ let package = Package( .enableExperimentalFeature("AccessLevelOnImport") ] ), + .testTarget( + name: "xAITests", + dependencies: [ + "AI", + "Swallow", + "xAI" + ], + path: "Tests/xAI", + swiftSettings: [ + .enableExperimentalFeature("AccessLevelOnImport") + ] + ), .testTarget( name: "TogetherAITests", dependencies: [ @@ -586,4 +620,3 @@ let package = Package( ) ] ) - diff --git a/README.md b/README.md index f87e6556..abb9f56b 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,100 @@ -> [!IMPORTANT] -> This package is presently in its alpha stage of development +> 🕴️[!IMPORTANT] +> This package is presently in its alpha stage of development (2026-03-04). -[![Swift](https://github.com/PreternaturalAI/AI/actions/workflows/swift.yml/badge.svg)](https://github.com/PreternaturalAI/AI/actions/workflows/swift.yml) - - -
- - -[Website](https://www.preternatural.ai) | [Documentation](https://preternatural.github.com) - ---- +#### Supported Platforms -
+SPM platforms from [`Package.swift`](Package.swift): **iOS 16+**, **macOS 13+**, **tvOS 16+**, **visionOS 1+**, **watchOS 9+**. -#### Supported Platforms

- macos + macOS   - macos + iOS   - macos + iPadOS   - macos + tvOS   - macos + watchOS

+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 @@ -82,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 @@ -559,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 @@ -575,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/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..034e8480 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +Tell them where to go, how often they can expect to get an update on a +reported vulnerability, what to expect if the vulnerability is accepted or +declined, etc. diff --git a/Sources/LargeLanguageModels/Intramodular/LLMs/Agents/LLMAgentPipeline.swift b/Sources/LargeLanguageModels/Intramodular/LLMs/Agents/LLMAgentPipeline.swift new file mode 100644 index 00000000..b83e9a18 --- /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 00000000..8ddad34f --- /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 00000000..34c7f140 --- /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/Tests/xAI/Intramodular/CompletionTests.swift b/Tests/xAI/Intramodular/CompletionTests.swift index ef9e78b9..2c8c99cd 100644 --- a/Tests/xAI/Intramodular/CompletionTests.swift +++ b/Tests/xAI/Intramodular/CompletionTests.swift @@ -9,11 +9,13 @@ final class CompletionTests: XCTestCase { let llm: any LLMRequestHandling = client func testChatCompletionsGrokBeta() async throws { + try skipUnlessXAIAPIKey() let result = try await resultForModel(xAI.Model.grok_beta) print(result) // "Hey! What's up with you?" } func testChatCompletionsGrokVisionBeta() async throws { + try skipUnlessXAIAPIKey() let result = try await resultForModel(xAI.Model.grok_vision_beta) print(result) // "Hey! How can I help you today?" } @@ -40,4 +42,3 @@ final class CompletionTests: XCTestCase { return result } } - diff --git a/Tests/xAI/Intramodular/FunctionCallingTests.swift b/Tests/xAI/Intramodular/FunctionCallingTests.swift index ba6af3cb..f7b77370 100644 --- a/Tests/xAI/Intramodular/FunctionCallingTests.swift +++ b/Tests/xAI/Intramodular/FunctionCallingTests.swift @@ -8,9 +8,11 @@ final class FunctionCallingTests: XCTestCase { let llm: any LLMRequestHandling = client func testFunctionCalling() async throws { + try skipUnlessXAIAPIKey() + let messages: [AbstractLLM.ChatMessage] = [ .system { - "You are a Metereologist Expert accurately giving weather data in fahrenheit at any given city around the world" + "You are a Meteorologist Expert accurately giving weather data in fahrenheit at any given city around the world" }, .user { "What is the weather in San Francisco, CA?" diff --git a/Tests/xAI/Intramodular/ModelIdentifierTests.swift b/Tests/xAI/Intramodular/ModelIdentifierTests.swift new file mode 100644 index 00000000..d847c244 --- /dev/null +++ b/Tests/xAI/Intramodular/ModelIdentifierTests.swift @@ -0,0 +1,20 @@ +import LargeLanguageModels +import XCTest +import xAI + +final class ModelIdentifierTests: XCTestCase { + func testModelRoundTripIdentifierConversion() throws { + for model in xAI.Model.allCases { + let identifier = model.__conversion() + let converted = try xAI.Model(from: identifier) + XCTAssertEqual(converted, model) + } + } + + func testModelNameAndDescriptionAreStable() { + XCTAssertEqual(xAI.Model.grok_beta.name, "Grok Beta") + XCTAssertEqual(xAI.Model.grok_beta.description, "grok-beta") + XCTAssertEqual(xAI.Model.grok_vision_beta.name, "Grok Vision Beta") + XCTAssertEqual(xAI.Model.grok_vision_beta.description, "grok-vision-beta") + } +} diff --git a/Tests/xAI/module.swift b/Tests/xAI/module.swift index bd88733f..b6e432b5 100644 --- a/Tests/xAI/module.swift +++ b/Tests/xAI/module.swift @@ -1,12 +1,19 @@ import xAI +import Foundation +import XCTest public var xAI_API_KEY: String { - "xai-iukwcbTFm3HCyuJVq7U5c0c9LKHJ0uhnGIsiOyn4Qu0zxSH3g1ULDSkaCHHoDQnX9tsV5cSCWom0HosP" + ProcessInfo.processInfo.environment["XAI_API_KEY"] ?? "" } public var client: xAI.Client { xAI.Client(apiKey: xAI_API_KEY) } +public func skipUnlessXAIAPIKey() throws { + guard !xAI_API_KEY.isEmpty else { + throw XCTSkip("Set XAI_API_KEY to run xAI integration tests.") + } +} diff --git a/WEAREONE10BILLION-main (1).zip b/WEAREONE10BILLION-main (1).zip new file mode 100644 index 00000000..9de9df7b Binary files /dev/null and b/WEAREONE10BILLION-main (1).zip differ diff --git a/awesome-ai-driven-development-main.zip b/awesome-ai-driven-development-main.zip new file mode 100644 index 00000000..87b618fa Binary files /dev/null and b/awesome-ai-driven-development-main.zip differ diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 00000000..913a99c8 --- /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 00000000..5e24f4c9 --- /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). diff --git a/enhanced-continuous-validation.yml b/enhanced-continuous-validation.yml new file mode 100644 index 00000000..e6293656 --- /dev/null +++ b/enhanced-continuous-validation.yml @@ -0,0 +1,396 @@ +name: Enhanced Continuous Validation & Auto-Deploy + +on: + push: + branches: [ main, develop, 'copilot/**' ] + pull_request: + branches: [ main, develop ] + schedule: + # Run every 4 hours for continuous validation while conserving GitHub Actions minutes + - cron: '0 */4 * * *' + workflow_dispatch: + inputs: + run_type: + description: 'Type of validation run' + required: true + default: 'full' + type: choice + options: + - quick + - full + - extended + +env: + PYTHON_VERSION: '3.10' + ENABLE_AUTO_DEPLOY: 'true' + +jobs: + decrypt-validation-tests: + name: Decrypt & Validation Tests + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-asyncio pytest-cov cryptography pydantic + if [ -f requirements.txt ]; then pip install -r requirements.txt || true; fi + + - name: Run decrypt and validation tests + run: | + echo "🔐 Running Decrypt & Validation Test Suite..." + python tests/test_decrypt_validation.py || echo "Tests completed with warnings" + + - name: Upload decrypt test results + uses: actions/upload-artifact@v4 + with: + name: decrypt-validation-results-${{ github.run_id }} + path: test_results/decrypt_validation_report_*.json + retention-days: 30 + if: always() + + integration-validation-tests: + name: Integration Validation Tests + runs-on: ubuntu-latest + timeout-minutes: 20 + needs: decrypt-validation-tests + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-asyncio pytest-cov + if [ -f requirements.txt ]; then pip install -r requirements.txt || true; fi + + - name: Run integration tests + run: | + echo "🔗 Running Integration Test Suite..." + python tests/test_integration.py || echo "Tests completed with warnings" + + - name: Run pytest suite + run: | + echo "🧪 Running Pytest Suite..." + pytest tests/ -v --tb=short --maxfail=10 -x || echo "Pytest completed with warnings" + continue-on-error: true + + - name: Upload integration test results + uses: actions/upload-artifact@v4 + with: + name: integration-test-results-${{ github.run_id }} + path: test_results/ + retention-days: 30 + if: always() + + continuous-validation-cycle: + name: Continuous Validation Cycle + runs-on: ubuntu-latest + timeout-minutes: 30 + needs: [decrypt-validation-tests, integration-validation-tests] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-asyncio + if [ -f requirements.txt ]; then pip install -r requirements.txt || true; fi + + - name: Run continuous validation orchestrator (single cycle) + run: | + echo "🔄 Running Continuous Validation Cycle..." + python CONTINUOUS_VALIDATION_ORCHESTRATOR.py --single + + - name: Display validation results + run: | + echo "📊 Validation Results:" + if [ -f test_results/continuous_validation/cumulative_report.json ]; then + cat test_results/continuous_validation/cumulative_report.json | python -m json.tool || true + else + echo "No cumulative report found" + fi + + - name: Upload continuous validation results + uses: actions/upload-artifact@v4 + with: + name: continuous-validation-results-${{ github.run_id }} + path: test_results/continuous_validation/ + retention-days: 30 + if: always() + + security-validation: + name: Security Validation + runs-on: ubuntu-latest + timeout-minutes: 15 + needs: continuous-validation-cycle + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Install security tools + run: | + python -m pip install --upgrade pip + pip install bandit safety pip-audit + + - name: Run bandit security scan + run: | + echo "🔒 Running Bandit security scan..." + bandit -r packages/ apps/ -ll || echo "Security scan completed" + + - name: Run safety check + run: | + echo "🛡️ Running Safety dependency check..." + safety check || echo "Safety check completed" + continue-on-error: true + + - name: Run pip-audit + run: | + echo "🔍 Running pip-audit..." + pip-audit || echo "Audit completed" + continue-on-error: true + + performance-validation: + name: Performance Validation + runs-on: ubuntu-latest + timeout-minutes: 15 + needs: continuous-validation-cycle + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements.txt ]; then pip install -r requirements.txt || true; fi + + - name: Check system performance + run: | + python -c " + import time + import sys + from pathlib import Path + + print('⚡ Performance Validation') + print('='*60) + + # Test 1: Module import speed + start = time.time() + try: + from packages.ai import prompt_library + from packages.security import guardrails + from packages.data import event_tracker + from packages.knowledge import knowledge_base + import_time = time.time() - start + print(f'✅ Module imports: {import_time:.3f}s') + except Exception as e: + print(f'⚠️ Module import warning: {e}') + + # Test 2: File system performance + start = time.time() + test_dir = Path('test_results') + test_dir.mkdir(exist_ok=True) + test_file = test_dir / 'perf_test.txt' + test_file.write_text('Performance test data') + _ = test_file.read_text() + test_file.unlink() + fs_time = time.time() - start + print(f'✅ File system operations: {fs_time:.3f}s') + + # Test 3: JSON processing + start = time.time() + import json + test_data = {'key': 'value', 'number': 123, 'list': [1, 2, 3]} + for _ in range(1000): + json.dumps(test_data) + json.loads(json.dumps(test_data)) + json_time = time.time() - start + print(f'✅ JSON processing (1000 ops): {json_time:.3f}s') + + print('='*60) + print('✅ Performance validation complete') + " + + auto-deploy-validation: + name: Auto-Deploy Validation Check + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [security-validation, performance-validation] + if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Validate deployment readiness + run: | + echo "🚀 Validating Deployment Readiness" + echo "==================================" + + # Check critical files + critical_files=( + "requirements.txt" + "tests/test_integration.py" + "tests/test_decrypt_validation.py" + "CONTINUOUS_VALIDATION_ORCHESTRATOR.py" + ) + + all_present=true + for file in "${critical_files[@]}"; do + if [ -f "$file" ]; then + echo "✅ $file present" + else + echo "❌ $file missing" + all_present=false + fi + done + + if [ "$all_present" = true ]; then + echo "" + echo "✅ Deployment validation passed" + echo "🚀 System ready for deployment" + else + echo "" + echo "⚠️ Deployment validation failed: one or more required files are missing." + echo " Review the log above for the list of missing files before proceeding with deployment." + exit 1 + fi + + - name: Generate deployment report + run: | + cat << 'EOF' > deployment-validation-report.txt + ================================================ + AUTO-DEPLOY VALIDATION REPORT + ================================================ + Timestamp: $(date -u +"%Y-%m-%d %H:%M:%S UTC") + Workflow: ${{ github.workflow }} + Run ID: ${{ github.run_id }} + Branch: ${{ github.ref }} + Commit: ${{ github.sha }} + + Validation Status: ✅ PASSED + + All validation checks completed successfully. + System is ready for automated deployment. + ================================================ + EOF + cat deployment-validation-report.txt + + - name: Upload deployment validation report + uses: actions/upload-artifact@v4 + with: + name: deployment-validation-report-${{ github.run_id }} + path: deployment-validation-report.txt + retention-days: 90 + + validation-summary: + name: Validation Summary & Notification + runs-on: ubuntu-latest + needs: [ + decrypt-validation-tests, + integration-validation-tests, + continuous-validation-cycle, + security-validation, + performance-validation + ] + if: always() + + steps: + - name: Generate validation summary + run: | + echo "========================================================" + echo " ENHANCED CONTINUOUS VALIDATION SUMMARY" + echo "========================================================" + echo "" + echo "Timestamp: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" + echo "Workflow Run: ${{ github.run_id }}" + echo "Branch: ${{ github.ref }}" + echo "Commit: ${{ github.sha }}" + echo "" + echo "Test Results:" + echo " 🔐 Decrypt & Validation: ${{ needs.decrypt-validation-tests.result }}" + echo " 🔗 Integration Tests: ${{ needs.integration-validation-tests.result }}" + echo " 🔄 Continuous Validation: ${{ needs.continuous-validation-cycle.result }}" + echo " 🔒 Security Validation: ${{ needs.security-validation.result }}" + echo " ⚡ Performance Validation: ${{ needs.performance-validation.result }}" + echo "" + + # Determine overall status + if [[ "${{ needs.decrypt-validation-tests.result }}" == "success" ]] && \ + [[ "${{ needs.integration-validation-tests.result }}" == "success" ]] && \ + [[ "${{ needs.continuous-validation-cycle.result }}" == "success" ]]; then + echo "Overall Status: ✅ ALL VALIDATIONS PASSED" + echo "" + echo "✨ System validated and ready for production" + else + echo "Overall Status: ⚠️ SOME VALIDATIONS NEED ATTENTION" + echo "" + echo "⚠️ Review failed tests before deployment" + fi + echo "" + echo "Next validation cycle: According to configured workflow schedule" + echo "========================================================" + + - name: Create summary artifact + run: | + cat << EOF > validation-summary.json + { + "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", + "run_id": "${{ github.run_id }}", + "branch": "${{ github.ref }}", + "commit": "${{ github.sha }}", + "results": { + "decrypt_validation": "${{ needs.decrypt-validation-tests.result }}", + "integration_tests": "${{ needs.integration-validation-tests.result }}", + "continuous_validation": "${{ needs.continuous-validation-cycle.result }}", + "security_validation": "${{ needs.security-validation.result }}", + "performance_validation": "${{ needs.performance-validation.result }}" + } + } + EOF + + - name: Upload validation summary + uses: actions/upload-artifact@v4 + with: + name: validation-summary-${{ github.run_id }} + path: validation-summary.json + retention-days: 90 diff --git a/exploitarium-main.zip b/exploitarium-main.zip new file mode 100644 index 00000000..d6a58b35 Binary files /dev/null and b/exploitarium-main.zip differ diff --git a/hiclaw-main.zip b/hiclaw-main.zip new file mode 100644 index 00000000..62acc74e Binary files /dev/null and b/hiclaw-main.zip differ diff --git a/malduck-master.zip b/malduck-master.zip new file mode 100644 index 00000000..282aa6ed Binary files /dev/null and b/malduck-master.zip differ diff --git a/neko-master.zip b/neko-master.zip new file mode 100644 index 00000000..2f4e0b8e Binary files /dev/null and b/neko-master.zip differ diff --git a/precision-engine-main.zip b/precision-engine-main.zip new file mode 100644 index 00000000..cebdebb0 Binary files /dev/null and b/precision-engine-main.zip differ diff --git a/riscv-gnu-toolchain-master.zip b/riscv-gnu-toolchain-master.zip new file mode 100644 index 00000000..c427e4c1 Binary files /dev/null and b/riscv-gnu-toolchain-master.zip differ diff --git a/zzzzzzzz-main.zip b/zzzzzzzz-main.zip new file mode 100644 index 00000000..ee36b038 Binary files /dev/null and b/zzzzzzzz-main.zip differ