# 🧠 BRAIIN - Behavioral Reasoning AI for Intelligent Navigation

**BRAIIN** is an AI-powered tool orchestrator that intelligently selects and combines **API calls, database queries, and external tools** to achieve complex tasks.
Inspired by systems like **J.A.R.V.I.S.**, **BRAIIN** enables **autonomous reasoning** to determine the best execution path for a given request.

## 🚀 Features
- 🏗 **Tool Orchestration** – Dynamically chooses the best tools (APIs, databases, system commands) for a task.
- 🔄 **Multi-Step Reasoning** – Can combine multiple tools to solve complex problems.
- 🧠 **LLM-Powered Decision Making** – Uses **large language models** (LLMs) to analyze and optimize tool usage.
- 🔌 **Flexible & Extendable** – Easily add **custom tools** for specific use cases.
- ⚡ **Real-Time Execution** – Executes tasks efficiently with minimal latency.
- 📡 **Answer Streaming** – Stream the final answer token by token to your UI via `onToken`, with no extra LLM call.
- 🧩 **Structured Tool Input** – Tools accept simple strings or structured objects for complex parameters.
- 🔁 **Context Persistence** – Tool results are tracked across tasks to avoid redundant calls.

## 📦 Installation
```sh
npm install braiin openai
```

## Concept
BRAIIN is based on the concept of an Orchestrator and one or multiple Agents that have each one or multiple Tools.

- A **tool** is an object that has a tag, a description, an input and an output fields. Its purpose is to achieve a given specific goal like writing a file. The input can be a simple string description or an array of structured parameters.
- An **agent** is an object that has a name, a description and a list of tools. Each agent is specialised in a specific topic (math, management, handling files, ...) and has a set of tools (write file, read file, ...) that can be used to achieve a specific goal.
- An **orchestrator** is an object that has a set of agents that are each specialised in a specific topic.
The orchestrator is the one that orchestrates the execution of the tools based on the user's request. It is the one that chooses which agent to use and which tool to use, it is capable of combining the tools to achieve the best result.

![concept](https://cdn.jsdelivr.net/npm/braiin/assets/braiin.jpg)

## Example
```typescript
// user.retriever.tool.ts
import { Tool } from 'braiin'

const users = [
  { name: 'User 1', age: 25, email: 'user1@example.com' },
  { name: 'User 2', age: 30, email: 'user2@example.com' },
  { name: 'User 3', age: 35, email: 'user3@example.com' }
]

export const userRetrieverTool: Tool = {
  tag: 'user-retriever',
  description: 'Retrieve a user informations from its name',
  input: 'The user\'s name',
  output: 'A json object containing the user\'s informations if the user was found, an empty string otherwise',
  call: async (userName) => {
    const user = users.find(u => u.name === userName)
    return user ? JSON.stringify(user) : ''
  }
}
```

```typescript
// user.birth.tool.ts
import { Tool } from 'braiin'

export const userBirthYearTool: Tool = {
  tag: 'user-birth-year',
  description: 'Compute the birth year of a user from its age',
  input: 'The user\'s age',
  output: 'A number representing the user\'s birth year',
  call: async (age) => {
    const year = new Date().getFullYear()
    const ageAsNumber = age ? parseInt(age as string) : year
    return `${year - ageAsNumber}`
  }
}
```

```typescript
// index.ts
import { userRetrieverTool } from './user.retriever.tool'
import { userBirthYearTool } from './user.birth.tool'
import { createAgent, createOrchestrator } from 'braiin'

const userAgent = createAgent(
  'user-agent',
  'You are a useful assistant that answers questions about users.',
  [userRetrieverTool, userBirthYearTool]
)

const orchestrator = createOrchestrator(
  [userAgent],
  {
    apiKey: 'your api key',
    model: 'gpt-4o',
    serverUrl: 'https://api.openai.com/v1',
    temperature: 0
  }
)

const result = await orchestrator.executeTask(
  'When was User 1 born?'
)

console.log(result.answer) // User 1 was born in 2001
console.log(result.status) // 'success'
console.log(result.toolTraces) // [{ tool: 'user-retriever', input: 'User 1', result: '...' }, ...]
```

## Streaming the final answer

Pass an `onToken` callback as the **5th argument** of `executeTask` to stream the final answer token by token, exactly as the model writes it — with **no extra LLM call**:

```typescript
const result = await orchestrator.executeTask(
  'When was User 1 born?',
  [],          // history (optional)
  [],          // toolTraces (optional)
  undefined,   // logCallback (optional — raw protocol of every step, for debugging)
  (token) => process.stdout.write(token) // onToken — streamed final answer
)

console.log(result.answer) // still holds the full answer once the chain completes
```

Only the **final answer** is streamed — the intermediate agent/tool steps are not. `onToken` is purely additive: the same answer is also returned in `result.answer`. On the OpenAI-compatible backend the answer streams token by token; on a non-streaming backend it is delivered in a single chunk at the end.

## Context Persistence

Tool results are tracked as `toolTraces` and can be passed between calls to avoid redundant tool executions:

```typescript
const first = await orchestrator.executeTask('Tell me about User 1\'s wife')
// first.toolTraces holds only the traces produced by THIS call

const second = await orchestrator.executeTask(
  'Has User 1 been married before?',
  [],
  first.toolTraces          // injected as context, so tools aren't re-run
)
// second.toolTraces holds only the second call's traces.
// Accumulate across turns yourself if you need the full history:
const allTraces = [...first.toolTraces, ...second.toolTraces]
```

`TaskResult.toolTraces` contains **only the traces produced during that call**. Passing prior traces injects them as context (the model reuses their results) but does **not** echo them back into the next result — you accumulate them yourself if you need a running history.

## Structured Tool Input

Tools can define structured parameters instead of a simple string description:

```typescript
import { Tool } from 'braiin'

const writeFileTool: Tool = {
  tag: 'write-file',
  description: 'Write content to a file',
  input: [
    { name: 'path', description: 'The file path', required: true },
    { name: 'content', description: 'The file content', required: true }
  ],
  output: 'Confirmation that the file was written',
  call: async (input) => {
    const { path, content } = input as Record<string, string>
    // write file logic here
    return `File written to ${path}`
  }
}
```

## Configuration

| Option | Default | Description |
| --- | --- | --- |
| `apiKey` | *required* | Your LLM API key |
| `model` | `'gpt-4o'` | The model to use |
| `serverUrl` | `'https://api.openai.com/v1'` | Base URL for any OpenAI-compatible API |
| `temperature` | `0` | LLM temperature |
| `maxSteps` | `50` | Maximum chain iterations (prevents infinite loops) |
| `stepsInterval` | `undefined` | Delay in ms between chain steps (rate limiting) |
| `optionalPrompt` | `undefined` | Additional instructions appended to the system prompt |

## Claude Code skill

`braiin` ships with a [Claude Code](https://claude.com/claude-code) skill that teaches the agent how to use the library — the primitives, the LLM protocol, every config option, streaming, and best practices. Install it once after adding the dependency:

```sh
npx braiin init-skill           # installs into ./.claude/skills/braiin (this project)
npx braiin init-skill --global  # installs into ~/.claude/skills/braiin (all projects)
```

Claude Code does not auto-discover skills inside `node_modules`, so this one-time command copies the bundled skill to where Claude Code looks for it. The skill is versioned with the library — re-run the command after upgrading `braiin` to refresh the guidance. The project-level `.claude/skills/braiin` can be committed so your whole team gets it automatically.
