rig 0.36.0

An opinionated library for building LLM powered applications.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# AGENTS.md

Guidelines for AI coding agents contributing to Rig.

## Rig Skill Modules

This file is the canonical source for Rig AI-agent guidance.

Module IDs:
- `rig-core-patterns`
- `rig-provider-implementation`
- `rig-vector-store-implementation`
- `rig-wasm-compat`
- `rig-prompt-hooks`
- `rig-quality-gates`

## Accountability

**You, the user, are entirely accountable for any code generated by an AI agent.**

The pull request you submit represents your work, regardless of how much was AI-assisted. Reviewers will hold you to the same quality standards as any other contributor. "The AI wrote it" is not an acceptable excuse for poor code quality, missing error handling, or incomplete implementations.

Before submitting any PR:
1. Review every line of generated code
2. Ensure you understand what it does and why
3. Verify it meets all contribution guidelines
4. Test it thoroughly
5. Ensure the user understands how what you've implemented actually works

---

<a id="rig-core-patterns"></a>
## Rig's Design Philosophy

<!-- RIG_SKILL_MODULE: rig-core-patterns START -->
Rig is built on several core principles that all contributions must respect:

### Trait-Based Abstractions

Rig uses traits to define provider-agnostic interfaces:

- `CompletionModel` - For text completion/chat models
- `EmbeddingModel` - For embedding generation
- `VectorStoreIndex` - For vector similarity search
- `Tool` - For defining callable tools

New implementations should implement these traits rather than creating parallel abstractions.

### Builder Pattern

Nearly every configurable type uses the builder pattern:

```rust
let agent = client
    .agent(openai::GPT_5_2)
    .preamble("System prompt")
    .tool(my_tool)
    .temperature(0.8)
    .build();
```

Follow this pattern for any new configurable types.

### Generic Client Architecture

The client system uses a generic architecture with provider extensions:

```rust
pub struct Client<Ext = Nothing, H = reqwest::Client> {
    // ...
}
```

Where `Ext` is a provider extension defining capabilities and `H` is the HTTP backend.

### Capability-Based Providers

Providers declare their capabilities explicitly:

```rust
impl<H> Capabilities<H> for MyProviderExt {
    type Completion = Capable<CompletionModel<H>>;  // Supported
    type Embeddings = Nothing;                       // Not supported
    // ...
}
```

Use `Capable<T>` for supported features and `Nothing` for unsupported ones.
<!-- RIG_SKILL_MODULE: rig-core-patterns END -->

---

<a id="rig-provider-implementation"></a>
## Implementing New Providers

<!-- RIG_SKILL_MODULE: rig-provider-implementation START -->
Reference implementation: `crates/rig-core/src/providers/openai/` (Chat Completions API)

When implementing a new provider, study the OpenAI Chat Completions implementation thoroughly. It demonstrates the complete pattern including both completion and embedding models.

### Required Components

1. **Provider Extension and Builder Structs**
   ```rust
   #[derive(Debug, Default, Clone, Copy)]
   pub struct MyProviderExt;

   #[derive(Debug, Default, Clone, Copy)]
   pub struct MyProviderBuilder;
   ```

2. **Provider Trait Implementation**
   ```rust
   impl Provider for MyProviderExt {
       type Builder = MyProviderBuilder;
       const VERIFY_PATH: &'static str = "/models";  // Health check endpoint

       fn build<H>(...) -> http_client::Result<Self> {
           Ok(Self)
       }
   }
   ```

3. **Capabilities Declaration**
   Explicitly declare what your provider supports:
   ```rust
   impl<H> Capabilities<H> for MyProviderExt {
       type Completion = Capable<completion::CompletionModel<H>>;  // Supported
       type Embeddings = Nothing;                                   // Not supported
   }
   ```
   Use `Capable<T>` for supported features and `Nothing` for unsupported ones.

4. **ProviderBuilder Implementation**
   ```rust
   impl ProviderBuilder for MyProviderBuilder {
       type Output = MyProviderExt;
       type ApiKey = BearerAuth;  // Or custom auth type
       const BASE_URL: &'static str = "https://api.provider.com/v1";
   }
   ```

5. **Client Type Aliases**
   ```rust
   pub type Client<H = reqwest::Client> = client::Client<MyProviderExt, H>;
   ```

6. **Model Constants**
   ```rust
   pub const MODEL_NAME: &str = "model-name";
   ```

7. **CompletionModel Implementation**
   Implement the `completion::CompletionModel` trait with proper:
   - Request conversion (`TryFrom<CompletionRequest>`)
   - Response conversion (into Rig's standard response types)
   - Streaming support
   - Telemetry/tracing spans

8. **Message Type Conversions**
   Implement `TryFrom`/`From` conversions between Rig's `message::Message` types and your provider's message format.

9. **EmbeddingModel Implementation** (if supported)
   Implement the `EmbeddingModel` trait:
   - Set `MAX_DOCUMENTS` for batch embedding limits
   - Implement `embed_texts` for batch document embedding
   - Map errors to `EmbeddingError`
   - Provide `ndims()` returning the embedding vector dimensionality

### Critical Requirements

- **Do not diverge from the provider's actual API.** If OpenAI's API has a field, implement it as OpenAI defines it. Do not add fields that don't exist in the real API.
- **Implement proper error handling** using `CompletionError`, `EmbeddingError`, etc.
- **Add telemetry spans** following GenAI semantic conventions (see existing providers).
- **Support both streaming and non-streaming** where the provider supports it.
<!-- RIG_SKILL_MODULE: rig-provider-implementation END -->

---

<a id="rig-vector-store-implementation"></a>
## Implementing Vector Stores

<!-- RIG_SKILL_MODULE: rig-vector-store-implementation START -->
Vector stores live in separate companion crates (e.g., `rig-mongodb`, `rig-lancedb`).

### Core Trait

```rust
pub trait VectorStoreIndex: WasmCompatSend + WasmCompatSync {
    type Filter: SearchFilter + WasmCompatSend + WasmCompatSync;

    fn top_n<T: for<'a> Deserialize<'a> + WasmCompatSend>(
        &self,
        req: VectorSearchRequest<Self::Filter>,
    ) -> impl Future<Output = Result<Vec<(f64, String, T)>, VectorStoreError>> + WasmCompatSend;

    fn top_n_ids(
        &self,
        req: VectorSearchRequest<Self::Filter>,
    ) -> impl Future<Output = Result<Vec<(f64, String)>, VectorStoreError>> + WasmCompatSend;
}
```

### Requirements

- Implement both `top_n` and `top_n_ids`
- Define an appropriate `Filter` type for your backend
- Use `WasmCompatSend`/`WasmCompatSync` bounds (see below)
- Return proper `VectorStoreError` variants
<!-- RIG_SKILL_MODULE: rig-vector-store-implementation END -->

---

<a id="rig-wasm-compat"></a>
## WasmCompatSend / WasmCompatSync

<!-- RIG_SKILL_MODULE: rig-wasm-compat START -->
Rig supports WebAssembly targets. Since WASM is single-threaded, `Send`/`Sync` bounds are unnecessary and can prevent compilation.

### The Pattern

```rust
#[cfg(not(target_family = "wasm"))]
pub trait WasmCompatSend: Send {}  // native

#[cfg(target_family = "wasm")]
pub trait WasmCompatSend {}        // wasm

#[cfg(not(target_family = "wasm"))]
pub trait WasmCompatSync: Sync {}  // native

#[cfg(target_family = "wasm")]
pub trait WasmCompatSync {}        // wasm
```

### Usage Rules

**Always use `WasmCompatSend` and `WasmCompatSync` instead of raw `Send` and `Sync`** in trait bounds.

```rust
// Correct
pub trait MyTrait: WasmCompatSend + WasmCompatSync {
    fn do_thing(&self) -> impl Future<Output = ()> + WasmCompatSend;
}

// Incorrect - will break WASM builds
pub trait MyTrait: Send + Sync {
    fn do_thing(&self) -> impl Future<Output = ()> + Send;
}
```

### Boxed Futures

Use `WasmBoxedFuture` for boxed futures:

```rust
pub type WasmBoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;  // native
pub type WasmBoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;         // wasm
```

### Conditional Error Types

Some error types need platform-specific bounds:

```rust
#[derive(Debug, thiserror::Error)]
pub enum MyError {
    #[cfg(not(target_family = "wasm"))]
    #[error("Error: {0}")]
    Inner(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),

    #[cfg(target_family = "wasm")]
    #[error("Error: {0}")]
    Inner(#[from] Box<dyn std::error::Error + 'static>),
}
```
<!-- RIG_SKILL_MODULE: rig-wasm-compat END -->

---

<a id="rig-prompt-hooks"></a>
## Prompt Hooks

<!-- RIG_SKILL_MODULE: rig-prompt-hooks START -->
Prompt hooks allow observing and controlling the agent's execution lifecycle.

### The PromptHook Trait

`PromptHook<M>` provides callbacks for both streaming and non-streaming requests. All methods have default implementations — implement only what you need.

### Hook Callbacks

- `on_completion_call` - Before sending prompt to model (returns `HookAction`)
- `on_completion_response` - After receiving response (returns `HookAction`)
- `on_tool_call` - Before invoking a tool (returns `ToolCallHookAction`)
- `on_tool_result` - After tool returns result (returns `HookAction`)
- `on_text_delta` - During streaming, on each text chunk (returns `HookAction`)
- `on_tool_call_delta` - During streaming, on each tool call chunk (returns `HookAction`)

### Control Flow

- `ToolCallHookAction::Continue` (or `.cont()`) - Allow tool execution
- `ToolCallHookAction::Skip { reason }` (or `.skip("reason")`) - Reject tool; reason becomes tool result
- `ToolCallHookAction::Terminate { reason }` (or `.terminate("reason")`) - Terminate the agentic loop early
- `HookAction::Continue` (or `.cont()`) - Continue normal execution
- `HookAction::Terminate { reason }` (or `.terminate("reason")`) - Terminate the agentic loop early

### Design Rationale

1. **Default implementations** - All methods have defaults; implement only what you need
2. **Per-request hooks** - Attached via `.with_hook()`, not globally
3. **WASM compatible** - Uses `WasmCompatSend`/`WasmCompatSync` bounds
<!-- RIG_SKILL_MODULE: rig-prompt-hooks END -->

---

<a id="rig-quality-gates"></a>
## Coding Style & Quality Gates

<!-- RIG_SKILL_MODULE: rig-quality-gates START -->

### Trait Bounds

Use full `where` clause syntax for readability:

```rust
// Correct
impl<T> CompletionModel for MyModel<T>
where
    T: HttpClientExt + Clone + WasmCompatSend + Debug + Default + 'static,
{
    // ...
}

// Avoid inline bounds for complex signatures
impl<T: HttpClientExt + Clone + WasmCompatSend + Debug + Default + 'static> CompletionModel for MyModel<T> {
    // ...
}
```

### Error Handling

**DO NOT use `String` as an error type.** Define proper error enums:

```rust
// Correct
#[derive(Debug, thiserror::Error)]
pub enum MyError {
    #[error("Failed to parse response: {0}")]
    ParseError(#[from] serde_json::Error),

    #[error("Provider returned error: {0}")]
    ProviderError(String),
}

// Absolutely forbidden
fn do_thing() -> Result<(), String>  // NO
```

**DO NOT stub out error handling:**

```rust
// Forbidden
let result = fallible_operation().unwrap();  // NO
let result = fallible_operation().expect("this should work");  // NO unless truly impossible

// Correct
let result = fallible_operation()?;
let result = fallible_operation().map_err(MyError::from)?;
```

### Comments

**Comments explain WHY, not WHAT.**

If you need to explain what code is doing, the code itself is unclear. Rename variables, extract functions, or restructure.

```rust
// Bad - explains what
// Increment counter by one
counter += 1;

// Bad - explains what
// Check if user is admin
if user.role == Role::Admin {

// Good - explains why
// Rate limiting resets at midnight UTC, so we need the day boundary
let boundary = timestamp.truncate_to_day();

// Good - explains non-obvious business logic
// Providers may return tool calls split across multiple chunks,
// so we accumulate them by index until the stream ends
```

### Documentation

- Add doc comments (`///`) to all public items
- Add module-level documentation (`//!`) to modules
- Include usage examples in doc comments where helpful

### TODO Items

**TODO items are not allowed in submitted code.**

If you need a TODO, the implementation is incomplete. Either:
1. Complete the implementation
2. Don't submit it yet
3. Create a separate issue tracking the future work

```rust
// Forbidden
fn process() {
    // TODO: handle edge case
}

// Forbidden
fn process() {
    unimplemented!("will add later")
}
```

---

## Before Submitting

### Required Checks

Run these commands and fix all issues before submitting:

```bash
cargo fmt
cargo clippy --all-targets --all-features
cargo test
```

If you cannot run these commands (e.g., environment limitations), explicitly ask the user to run them before the PR is submitted.

### Architectural Changes

If your change involves:
- New traits or significant trait modifications
- Changes to the client/provider architecture
- New abstractions or patterns
- Breaking changes to public APIs

**Discuss with the user first.** Do not implement major architectural changes without explicit approval. Open an issue for discussion if needed.

### Self-Review Checklist

Before considering code complete:

- [ ] All error cases handled properly (no `.unwrap()` or `.expect()` on fallible operations unless truly impossible)
- [ ] No `String` error types
- [ ] No TODO comments
- [ ] No stubbed implementations
- [ ] Comments explain "why", not "what"
- [ ] Uses `WasmCompatSend`/`WasmCompatSync` instead of `Send`/`Sync`
- [ ] Follows existing code patterns in the codebase
- [ ] Includes tests or examples that compile
- [ ] `cargo fmt` passes
- [ ] `cargo clippy --all-targets --all-features` passes
- [ ] `cargo test` passes

---

## Commits

DO NOT MAKE COMMITS UNLESS THE USER HAS ASKED YOU TO DO SO. Users should be able to manually verify that what you have done has worked before proceeding with a commit, and may also want to write their own commit messages.

If the PR contains breaking changes, the PR message must list the public API items that have broken and the migration path for each.

## What Will Be Rejected

PRs will be rejected if they contain:

- **Lazy workarounds** - `String` error types, `.unwrap()` everywhere, incomplete handling
- **TODO items** - Submit complete work or don't submit
- **Stubbed error handling** - Every error path must be properly handled
- **Provider API divergence** - Don't add fields/features that don't exist in real provider APIs
- **Missing WASM compatibility** - Using `Send`/`Sync` instead of `WasmCompat*` variants
- **Unclear code requiring explanatory comments** - Refactor instead
- **Architectural changes without discussion** - Major changes need approval first

Remember: The quality bar exists because Rig is used in production by many projects. Every contribution must maintain that standard.
<!-- RIG_SKILL_MODULE: rig-quality-gates END -->