Skip to content

Commit 835a12f

Browse files
committed
docs: update for 6-provider architecture and reasoning primitives
Bring all top-level docs in line with the data-driven provider registry that now supports 6 providers (openai, anthropic, gemini, ollama, openrouter, together). - README.md: lead description and Quick Links cover all 6 providers - SETUP.md: add OpenRouter and Together AI setup sections, update parameter table and provider-specific defaults; note DeepSeek-R1 thinking-tag behavior + max_tokens guidance - USAGE.md: provider list in `set-provider` reference; add a reasoning/thinking example block (`set-thinking`, `set-reasoning-effort`, `set-thinking-budget`, `chat-with-thinking`); expand discovery examples - API-REFERENCE.md: add quick-table rows for the 4 reasoning primitives, add a full Reasoning / Thinking Primitives section, extend Valid Providers list, readiness-check table, and provider-status example to include OpenRouter and Together - EXAMPLES.md: include OpenRouter and Together in the compare-providers list; add Reasoning Models and OpenRouter one-key-many-models examples - TESTING.md: document `demos/tests/config.txt.example` workflow, enumerate the 13 test procedures (including the two skip-aware provider-specific ones), list OPENROUTER_API_KEY / TOGETHER_API_KEY for future smoke-test secrets
1 parent c8ef2af commit 835a12f

6 files changed

Lines changed: 237 additions & 20 deletions

File tree

docs/API-REFERENCE.md

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ The NetLogo Multi-LLM Extension provides a unified interface for multiple Large
1111
| `llm:chat text` | Chat | Send synchronous chat message, returns response |
1212
| `llm:chat-async text` | Chat | Send asynchronous chat message, returns awaitable reporter |
1313
| `llm:chat-with-template file vars` | Chat | Send templated prompt with variable substitution |
14+
| `llm:chat-with-thinking text` | Chat | Returns `[answer thinking]` for reasoning-capable models |
1415
| `llm:choose prompt choices` | Chat | Force selection from provided options |
16+
| `llm:set-thinking bool` | Reasoning | Enable/disable reasoning mode for current provider |
17+
| `llm:set-reasoning-effort level` | Reasoning | Set effort: `"low"`, `"medium"`, `"high"` |
18+
| `llm:set-thinking-budget n` | Reasoning | Token budget for thinking (min 1024; Anthropic + Gemini) |
1519
| `llm:history` | History | Get current agent's conversation history |
1620
| `llm:set-history list` | History | Set conversation history for current agent |
1721
| `llm:clear-history` | History | Clear conversation history for current agent |
1822
| `llm:load-config filename` | Configuration | Load settings from file |
19-
| `llm:set-provider name` | Configuration | Set active provider (openai, anthropic, gemini, ollama) |
23+
| `llm:set-provider name` | Configuration | Set active provider (openai, anthropic, gemini, ollama, openrouter, together) |
2024
| `llm:set-api-key key` | Configuration | Set API key for current provider |
2125
| `llm:set-model name` | Configuration | Set model to use for current provider |
2226
| `llm:providers` | Discovery | List ready providers with configured keys/servers |
@@ -70,6 +74,8 @@ llm:load-config "models/gpt4-config.txt"
7074
- `"anthropic"` - Anthropic Claude models
7175
- `"gemini"` - Google Gemini models
7276
- `"ollama"` - Local Ollama models
77+
- `"openrouter"` - OpenRouter (200+ models from many vendors via one API key)
78+
- `"together"` - Together AI (fast open-source model inference)
7379

7480
**Example**:
7581

@@ -229,6 +235,65 @@ set color read-from-string color-choice
229235
- Useful for agent decision-making in models
230236
- Maintains conversation context
231237

238+
## Reasoning / Thinking Primitives
239+
240+
For models that expose intermediate reasoning (Anthropic Claude, Google Gemini, Ollama qwen3/deepseek-r1, OpenRouter, Together AI). OpenAI o-series uses internal reasoning that the API does not return.
241+
242+
### llm:chat-with-thinking
243+
244+
**Syntax**: `llm:chat-with-thinking text`
245+
246+
**Description**: Same as `llm:chat`, but returns both the final answer and the model's reasoning text as a 2-element list.
247+
248+
**Returns**: `[answer thinking]` — both strings. `thinking` will be `""` if the provider/model does not expose reasoning tokens.
249+
250+
**Example**:
251+
252+
```netlogo
253+
llm:set-thinking true
254+
let result llm:chat-with-thinking "What is 17 * 23?"
255+
let answer item 0 result
256+
let thinking item 1 result
257+
print (word "Answer: " answer)
258+
print (word "Reasoning: " thinking)
259+
```
260+
261+
**Notes**:
262+
263+
- Only the final answer is added to conversation history (not the thinking text).
264+
- For DeepSeek-R1 on Together AI, thinking is parsed from `<think>...</think>` tags in the content.
265+
- For Anthropic, OpenRouter, and Gemini, thinking comes from a dedicated reasoning field in the API response.
266+
267+
### llm:set-thinking
268+
269+
**Syntax**: `llm:set-thinking enabled?`
270+
271+
**Description**: Enable or disable reasoning mode for the current provider. When enabled, the request includes provider-specific reasoning fields.
272+
273+
**Parameters**:
274+
275+
- `enabled?` (boolean): `true` to enable, `false` to disable
276+
277+
### llm:set-reasoning-effort
278+
279+
**Syntax**: `llm:set-reasoning-effort level`
280+
281+
**Description**: Set the reasoning effort hint for models that support it (OpenAI o-series, OpenRouter, Together AI hybrid models).
282+
283+
**Parameters**:
284+
285+
- `level` (string): `"low"`, `"medium"`, or `"high"`
286+
287+
### llm:set-thinking-budget
288+
289+
**Syntax**: `llm:set-thinking-budget tokens`
290+
291+
**Description**: Maximum tokens the model may spend on reasoning before producing the final answer. Used by Anthropic and Gemini.
292+
293+
**Parameters**:
294+
295+
- `tokens` (number): Minimum 1024. For Anthropic, the value is clamped to `[1024, max_tokens-1]`.
296+
232297
## History Management
233298

234299
### llm:history
@@ -320,12 +385,14 @@ if member? "ollama" llm:providers [
320385

321386
**Readiness Checks**:
322387

323-
| Provider | Check Performed |
324-
| --------- | --------------------------------------------------- |
325-
| OpenAI | Has `openai_api_key` or `api_key` configured |
326-
| Anthropic | Has `anthropic_api_key` or `api_key` configured |
327-
| Gemini | Has `gemini_api_key` or `api_key` configured |
328-
| Ollama | Server reachable at `ollama_base_url` (1s timeout) |
388+
| Provider | Check Performed |
389+
| ----------- | ----------------------------------------------------- |
390+
| OpenAI | Has `openai_api_key` or `api_key` configured |
391+
| Anthropic | Has `anthropic_api_key` or `api_key` configured |
392+
| Gemini | Has `gemini_api_key` or `api_key` configured |
393+
| Ollama | Server reachable at `ollama_base_url` (1s timeout) |
394+
| OpenRouter | Has `openrouter_api_key` configured |
395+
| Together AI | Has `together_api_key` configured |
329396

330397
### llm:providers-all
331398

@@ -339,7 +406,7 @@ if member? "ollama" llm:providers [
339406

340407
```netlogo
341408
let all-providers llm:providers-all
342-
print all-providers ; ["openai" "anthropic" "gemini" "ollama"]
409+
print all-providers ; ["openai" "anthropic" "gemini" "ollama" "openrouter" "together"]
343410
```
344411

345412
### llm:provider-status
@@ -359,7 +426,9 @@ print status
359426
; [["openai" ["ready" true] ["has-key" true]]
360427
; ["anthropic" ["ready" false] ["has-key" false]]
361428
; ["gemini" ["ready" false] ["has-key" false]]
362-
; ["ollama" ["ready" true] ["reachable" true] ["base-url" "http://localhost:11434"]]]
429+
; ["ollama" ["ready" true] ["reachable" true] ["base-url" "http://localhost:11434"]]
430+
; ["openrouter" ["ready" false] ["has-key" false]]
431+
; ["together" ["ready" false] ["has-key" false]]]
363432
364433
; Check specific provider status
365434
foreach llm:provider-status [ provider-info ->
@@ -394,7 +463,7 @@ foreach llm:provider-status [ provider-info ->
394463

395464
**Parameters**:
396465

397-
- `provider-name` (string): Provider to get help for (`openai`, `anthropic`, `gemini`, `ollama`)
466+
- `provider-name` (string): Provider to get help for (`openai`, `anthropic`, `gemini`, `ollama`, `openrouter`, `together`)
398467

399468
**Returns**: String - Multi-line setup instructions
400469

docs/EXAMPLES.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ extensions [llm]
306306
globals [providers-list current-question]
307307
308308
to setup
309-
set providers-list ["openai" "anthropic" "gemini"]
309+
set providers-list ["openai" "anthropic" "gemini" "openrouter" "together"]
310310
set current-question ""
311311
end
312312
@@ -479,6 +479,56 @@ end
479479

480480
## Advanced Usage Examples
481481

482+
### Reasoning Models — Show the Model's Work
483+
484+
Use `llm:chat-with-thinking` to get both the final answer and the model's intermediate reasoning. Works with Anthropic Claude, Gemini 2.x, Ollama qwen3 / deepseek-r1, OpenRouter reasoning models, and Together AI's DeepSeek-R1.
485+
486+
```netlogo
487+
extensions [llm]
488+
489+
to setup-reasoning
490+
llm:load-config "config.txt" ;; e.g. provider=together, model=deepseek-ai/DeepSeek-R1
491+
llm:set-thinking true
492+
llm:set-reasoning-effort "high" ;; OpenAI o-series + OpenRouter + Together hybrid
493+
llm:set-thinking-budget 4096 ;; Anthropic + Gemini
494+
end
495+
496+
to ask-with-reasoning [ question ]
497+
let result llm:chat-with-thinking question
498+
let answer item 0 result
499+
let thinking item 1 result
500+
print (word "Q: " question)
501+
print (word "Reasoning: " thinking)
502+
print (word "Answer: " answer)
503+
end
504+
505+
;; ask-with-reasoning "If a train leaves Chicago at 3pm going 60 mph, ..."
506+
```
507+
508+
Note: bump `max_tokens` to 2000+ in your config for reasoning models; they often spend most of their token budget on the thinking phase before producing the final answer.
509+
510+
### OpenRouter — One Key, Many Models
511+
512+
Switch between vendors without juggling separate API keys:
513+
514+
```netlogo
515+
extensions [llm]
516+
517+
to setup
518+
llm:set-provider "openrouter"
519+
llm:set-api-key "sk-or-your-key"
520+
end
521+
522+
to compare-vendors-via-openrouter
523+
let prompt "Summarize agent-based modeling in one sentence."
524+
foreach ["openai/gpt-4o-mini" "anthropic/claude-3.5-haiku" "meta-llama/llama-3.3-70b-instruct"] [ m ->
525+
llm:set-model m
526+
print (word m ": " llm:chat prompt)
527+
llm:clear-history
528+
]
529+
end
530+
```
531+
482532
### Async Processing with Multiple Requests
483533

484534
Handle multiple LLM requests simultaneously:

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# NetLogo Multi-LLM Extension
22

3-
Unified LLM capabilities for NetLogo with multi-provider support (OpenAI, Anthropic/Claude, Google/Gemini, and local Ollama), per‑agent memory, async requests, and simple configuration.
3+
Unified LLM capabilities for NetLogo with multi-provider support OpenAI, Anthropic/Claude, Google/Gemini, local Ollama, OpenRouter (200+ models via one key), and Together AI (fast open-source inference) — plus per‑agent memory, async requests, reasoning/thinking models, and simple configuration.
44

55
## Quick Links
66
- Usage Guide: `docs/USAGE.md`
@@ -20,7 +20,7 @@ extensions [ llm ]
2020
```
2121
llm:load-config "config.txt"
2222
```
23-
See `docs/CONFIGURATION.md` for ready-to-copy examples (OpenAI, Anthropic, Gemini, Ollama). For inline setup:
23+
See `docs/CONFIGURATION.md` for ready-to-copy examples (OpenAI, Anthropic, Gemini, Ollama, OpenRouter, Together AI). For inline setup:
2424
```
2525
llm:set-provider "openai"
2626
llm:set-api-key "sk-REPLACE_ME"

docs/SETUP.md

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,63 @@ timeout_seconds=60
101101

102102
**Pull command**: `ollama pull [model-name]`
103103

104+
### OpenRouter (200+ models via one key)
105+
106+
OpenRouter routes requests to many model vendors (OpenAI, Anthropic, Google, Meta, DeepSeek, etc.) through a single API.
107+
108+
1. **Get API Key**: Visit [openrouter.ai/keys](https://openrouter.ai/keys)
109+
2. **Create config.txt**:
110+
```
111+
provider=openrouter
112+
model=openai/gpt-4o-mini
113+
openrouter_api_key=sk-or-your-key-here
114+
temperature=0.7
115+
max_tokens=1000
116+
```
117+
118+
**Available Models** (vendor-prefixed):
119+
- `openai/gpt-4o-mini` - Fast, cost-effective (recommended)
120+
- `openai/gpt-4o` - GPT-4o through OpenRouter
121+
- `anthropic/claude-3.5-sonnet` - Claude 3.5 Sonnet
122+
- `anthropic/claude-3.5-haiku` - Fast Claude
123+
- `google/gemini-2.0-flash-exp` - Latest Gemini
124+
- `meta-llama/llama-3.3-70b-instruct` - Llama 3.3 70B
125+
- `deepseek/deepseek-r1` - Reasoning model
126+
127+
Browse the full catalog: [openrouter.ai/models](https://openrouter.ai/models)
128+
129+
### Together AI (open-source models)
130+
131+
Together AI provides fast inference for open-source models (Llama, DeepSeek, Qwen, Mistral, Gemma) via an OpenAI-compatible API.
132+
133+
1. **Get API Key**: Visit [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys)
134+
2. **Create config.txt**:
135+
```
136+
provider=together
137+
model=meta-llama/Llama-3.3-70B-Instruct-Turbo
138+
together_api_key=your-together-key-here
139+
temperature=0.7
140+
max_tokens=1000
141+
```
142+
143+
**Available Models** (vendor-prefixed):
144+
- `meta-llama/Llama-3.3-70B-Instruct-Turbo` - Fast Llama 3.3 (recommended)
145+
- `meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo` - Llama 3.1 70B
146+
- `deepseek-ai/DeepSeek-R1` - Reasoning model with `<think>` tag output
147+
- `Qwen/Qwen2.5-72B-Instruct-Turbo` - Qwen 2.5 72B
148+
- `mistralai/Mixtral-8x22B-Instruct-v0.1` - Mistral mixture-of-experts
149+
150+
Browse the full catalog: [api.together.ai/models](https://api.together.ai/models)
151+
152+
**Reasoning model note:** DeepSeek-R1 emits its thinking inside `<think>...</think>` tags (sometimes filling the entire response). Use `llm:chat-with-thinking` to get the answer and reasoning split out, and bump `max_tokens` to 2000+ so the model has room to finish its answer after thinking.
153+
104154
## Configuration Parameters
105155

106156
### Core Settings
107157

108158
| Parameter | Description | Required | Default |
109159
|-----------|-------------|----------|---------|
110-
| `provider` | LLM provider (`openai`, `anthropic`, `gemini`, `ollama`) | Yes | - |
160+
| `provider` | LLM provider (`openai`, `anthropic`, `gemini`, `ollama`, `openrouter`, `together`) | Yes | - |
111161
| `model` | Model identifier | Yes | Provider-specific |
112162
| `api_key` | API authentication key | Yes* | - |
113163
| `temperature` | Response randomness (0.0-1.0) | No | 0.7 |
@@ -141,6 +191,16 @@ timeout_seconds=60
141191
- `max_tokens`: 2048
142192
- `timeout_seconds`: 60
143193

194+
**OpenRouter**:
195+
- `base_url`: `https://openrouter.ai/api/v1`
196+
- `max_tokens`: 1000
197+
- API key config field: `openrouter_api_key`
198+
199+
**Together AI**:
200+
- `base_url`: `https://api.together.xyz/v1`
201+
- `max_tokens`: 1000
202+
- API key config field: `together_api_key`
203+
144204
## Testing Your Setup
145205

146206
1. **Create Test Model**:
@@ -173,7 +233,7 @@ end
173233

174234
**"Provider not found"**
175235
- Check `provider=` line in config.txt
176-
- Verify spelling: `openai`, `anthropic`, `gemini`, `ollama`
236+
- Verify spelling: `openai`, `anthropic`, `gemini`, `ollama`, `openrouter`, `together`
177237

178238
**"API key invalid"**
179239
- Verify API key is correct and active

docs/TESTING.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,31 @@ These tests are **excluded from default `sbt test`** and from CI.
8282
Use `demos/tests/tests.nlogox` when you want to verify real providers end-to-end.
8383

8484
These tests do require:
85-
- valid provider credentials for cloud providers, or
85+
- valid provider credentials for cloud providers (OpenAI, Anthropic, Gemini, OpenRouter, Together AI), or
8686
- a running Ollama server for local provider tests
8787

88+
### Test setup
89+
90+
1. Copy the template: `cp demos/tests/config.txt.example demos/tests/config.txt`
91+
2. Edit `config.txt`: set `provider=` to your chosen provider and replace the matching `*_api_key=REPLACE_ME` line with a real key. `config.txt` is gitignored, so the key stays local.
92+
3. Open `demos/tests/tests.nlogox` in NetLogo.
93+
4. In the Command Center: `run-all-tests`
94+
95+
### What the suite covers
96+
97+
The suite runs the same 13 test procedures regardless of provider, plus two provider-specific procedures that auto-skip if not applicable:
98+
99+
- `test-providers` — registry has all 6 providers and `provider-help` returns text for each
100+
- `test-invalid-provider` — bogus provider name is rejected
101+
- `test-load-config` / `test-config-rollback` — config file loads cleanly and rolls back on failure
102+
- `test-sync-chat`, `test-async-chat`, `test-choose`, `test-history` — core chat flow
103+
- `test-thinking-config`, `test-chat-with-thinking` — reasoning primitives and `[answer thinking]` return shape
104+
- `test-openrouter-vendor-prefix` — vendor-prefixed model names (skips unless `provider=openrouter`)
105+
- `test-together-thinking` — DeepSeek-R1 `<think>` tag extraction (skips unless `provider=together` AND model contains "DeepSeek")
106+
- `test-reasoning-marker``[reasoning]` marker visible in `llm:list-models`
107+
108+
To exercise everything, run the suite twice — once with `provider=openrouter`, once with `provider=together` (use `model=deepseek-ai/DeepSeek-R1` and `max_tokens=2000+` for the Together reasoning test).
109+
88110
Suggested usage:
89111
- run automated tests first (`sbt test`)
90112
- run manual integration checks before releases or when changing provider adapters
@@ -125,5 +147,5 @@ For cloud-provider smoke tests you will need real API keys in CI secrets.
125147

126148
Typical setup later:
127149
- separate workflow (manual trigger and/or nightly schedule)
128-
- secrets like `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`
150+
- secrets like `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `TOGETHER_API_KEY`
129151
- not required for normal PR merges (to avoid flaky/costly gating)

0 commit comments

Comments
 (0)