-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathagentos.toml.example
More file actions
670 lines (618 loc) · 31.1 KB
/
Copy pathagentos.toml.example
File metadata and controls
670 lines (618 loc) · 31.1 KB
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
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
# AgentOS Configuration
# Copy to agentos.toml and edit as needed:
# cp agentos.toml.example agentos.toml
# Precedence: env vars > agentos.toml > defaults
# Also searched: ~/.agentos/config.toml (global user config)
# Assistant speaker label shown on the ◢ marker, the pre-token waiting
# row, and the queued-turn marker in `agentos chat`. Defaults to "agentos".
# Configured via environment variable (not a TOML key):
# export AGENTOS_ASSISTANT_LABEL="Hani"
# Workspace/state defaults
# Defaults:
# workspace_dir = "~/.agentos/workspace"
# state_dir = "~/.agentos/state"
# memory.source = "workspace"
# workspace_dir = "/path/to/workspace"
# state_dir = "/path/to/state"
# workspace_strict = true # true restricts read-side file tools to workspace
# Realtime feedback timing. Heartbeats are non-persistent UI/CLI liveness
# events while a run is active; stream idle timeout is the real upstream stall
# detector. Keep browser grace above stream idle so server terminal errors win.
# agent_stream_heartbeat_interval_seconds = 15.0
# agent_stream_idle_timeout_seconds = 600.0
# webui_stream_idle_grace_seconds = 630.0
# Keep a positive cap for smaller local models so repeated tool calls cannot
# run forever. Zero means unlimited.
# agent_max_iterations = 8
# WebSocket per-connection outbound writer queue. When enabled (default),
# each WS connection gets a bounded asyncio queue + dedicated writer task.
# Producers enqueue and return immediately; slow clients trigger a fast
# 1011 close instead of back-pressuring the gateway. Disable to fall back
# to the legacy direct-`ws.send_text` path under a per-connection lock.
# Kill switch affects new connections only; existing connections retain
# their startup-time behavior.
# Env override: AGENTOS_WS_WRITER_QUEUE_ENABLED=true|false
# ws_writer_queue_enabled = true
# Env override: AGENTOS_WS_WRITER_QUEUE_MAXSIZE=512
# ws_writer_queue_maxsize = 512
# Gateway debug file logging. Raw prompt/tool call capture is separate from
# debug.log and standard diagnostics; it is opt-in through
# AGENTOS_TURN_CALL_LOG=1 or `agentos diagnostics on --raw`.
# log_file_enabled = true
# log_level = "DEBUG" # CRITICAL/FATAL/ERROR/WARNING/WARN/INFO/DEBUG/TRACE
# log_file_max_bytes = 5000000
# log_file_backup_count = 3
# Developer diagnostics. debug is security-sensitive; keep it false in shared
# deployments. diagnostics_enabled enables standard diagnostics at startup.
# Raw turn-call capture remains a separate explicit runtime/env switch.
# debug = false
# diagnostics_enabled = false
# Update notifications. On gateway-connected commands the CLI checks PyPI at
# most once every 24h and prints a one-line notice on stderr when a newer
# use-agent-os release exists (suppressed on non-TTY / CI runs). Set notify =
# false to silence it. See docs/configuration.md#update-notifications.
# [updates]
# notify = true
# Web search settings
# Use Brave when a key is configured, otherwise keep DuckDuckGo.
# search_provider = "duckduckgo" # "duckduckgo" or "brave"
# search_api_key = "" # Brave Search API key; env BRAVE_SEARCH_API_KEY also works
# search_max_results = 5
# search_proxy = "" # e.g. "http://127.0.0.1:7890"
# search_use_env_proxy = false # true = allow HTTP_PROXY/HTTPS_PROXY if search_proxy is empty
# X (Twitter) search via xAI's server-side x_search tool. A separate tool from
# web_search, not one of its providers: xAI searches X's post index and returns
# a synthesized answer with citations. The tool stays hidden from the model
# until an xAI credential resolves, and it bills xAI directly — that spend does
# not appear in `agentos cost`. See docs/x-search.md.
# [x_search]
# enabled = true
# model = "grok-4.5" # any Grok model with server-side x_search access
# base_url = "https://api.x.ai/v1"
# api_key = "" # env XAI_API_KEY also works
# api_key_env = "XAI_API_KEY"
# reasoning_effort = "" # "", low, medium, high, xhigh
# timeout_seconds = 180.0 # one attempt; 30-300
# total_timeout_seconds = 300.0 # whole call including retries; 30-600
# retries = 2 # 5xx / timeout / connection errors only; 0-5
# Browser automation via the agent-browser CLI engine (Vercel Labs, Apache-2.0).
# Install: npm install -g agent-browser && agent-browser install. The `browser`
# tool stays hidden from the model until the binary resolves. Managed headless is
# the default; set cdp_port to attach to your own Chrome (localhost only — no URL
# accepted — and attach_confirmed must also be true). See docs/features/browser.md.
# [browser]
# enabled = true
# headless = true # false opens a visible window (managed mode)
# binary_path = "" # optional explicit path to agent-browser
# cdp_port = 0 # 0 = managed. >0 = attach to Chrome started with
# # --remote-debugging-port=<port>. Localhost only.
# attach_confirmed = false # must be true to let the agent drive your Chrome
# allowed_domains = [] # [] = open web (SSRF still blocks private IPs)
# persist_profile = false # true = keep cookies/login between sessions (on disk)
# session_ttl_minutes = 15
# max_sessions = 3
# snapshot_max_chars = 24000
# dialog_policy = "must_respond" # must_respond | auto_dismiss | auto_accept
# dialog_timeout_s = 300.0
# restrict_evaluate = false # true = block sensitive JS primitives in eval
# allow_unsafe_evaluate = false # true = override restrict_evaluate for trusted pages
[llm]
provider = "openrouter"
model = "openai/gpt-5.6-luna"
# api_key = "" # OpenRouter API key; env OPENROUTER_API_KEY also works
base_url = "https://openrouter.ai/api/v1"
# proxy = "" # e.g. http://127.0.0.1:7890
# Health-aware failover. Consecutive provider-health failures (overload,
# transport, rate limit) open a circuit breaker so turns skip the dead
# provider for a cooldown window instead of paying its timeout every turn.
# One half-open probe per window re-closes it when the provider recovers.
# [llm.circuit_breaker]
# enabled = true
# failure_threshold = 3 # consecutive failures before the breaker opens
# cooldown_seconds = 60 # skip window; doubles per consecutive trip
# max_cooldown_seconds = 600 # cap on the doubling
# Provider quick reference. Support levels marked compat_mock_verified are
# verified by local mocked-contract tests, not by live vendor calls.
#
# provider env var default base_url
# openrouter OPENROUTER_API_KEY https://openrouter.ai/api/v1
# bankr BANKR_API_KEY https://llm.bankr.bot/v1
# opencap OPENCAP_API_KEY https://gw.capminal.ai/api/inference/v1
# surplus SURPLUS_API_KEY https://api.surplusintelligence.ai/v1
# openai OPENAI_API_KEY https://api.openai.com/v1
# anthropic ANTHROPIC_API_KEY https://api.anthropic.com
# ollama none http://localhost:11434
# deepseek DEEPSEEK_API_KEY https://api.deepseek.com
# gemini GEMINI_API_KEY https://generativelanguage.googleapis.com/v1beta/openai
# dashscope DASHSCOPE_API_KEY https://dashscope.aliyuncs.com/compatible-mode/v1
# moonshot MOONSHOT_API_KEY https://api.moonshot.ai/v1
# mistral MISTRAL_API_KEY https://api.mistral.ai/v1
# groq GROQ_API_KEY https://api.groq.com/openai/v1
# zhipu ZAI_API_KEY https://open.bigmodel.cn/api/paas/v4
# siliconflow SILICONFLOW_API_KEY https://api.siliconflow.cn/v1
# volcengine VOLCENGINE_API_KEY https://ark.cn-beijing.volces.com/api/v3
# byteplus BYTEPLUS_API_KEY https://ark.ap-southeast.bytepluses.com/api/v3
# vllm none explicit base_url required
# lm_studio none http://localhost:1234/v1
# ovms none http://localhost:8000/v3
# qianfan QIANFAN_API_KEY https://qianfan.baidubce.com/v2
# aihubmix AIHUBMIX_API_KEY https://aihubmix.com/v1
# minimax MINIMAX_API_KEY https://api.minimax.io/v1
# azure provider-specific unsupported_for_A
#
# Example direct DeepSeek config:
# provider = "deepseek"
# model = "deepseek-v4-flash"
# api_key = "" # env DEEPSEEK_API_KEY also works
# base_url = "https://api.deepseek.com"
# OpenRouter: pin namespaced model IDs to a preferred upstream provider.
# [llm.provider_routing]
# "deepseek/deepseek-v4-flash" = "deepseek"
# "minimax/minimax-m3" = "minimax"
# "z-ai/glm-5.2" = "z-ai"
# "anthropic/claude-opus-5" = "anthropic"
#
# OpenCAP and Surplus use bare model IDs and send values as a provider/seller
# allow-list. Check
# its live model catalog for current model and upstream provider IDs. Omit this
# table to keep gateway auto-routing.
# [llm.provider_routing]
# "glm-5.3" = "provider-id-from-live-catalog"
# Prompt caching controls. Enables prefix caching for supported providers
# (Anthropic, OpenAI, DeepSeek, OpenRouter, etc.).
# mode: "auto" (default; on where supported), "on" (force on), "off" (disabled).
# Env override: AGENTOS_CACHE_MODE=auto|on|off (legacy AGENTOS_CACHE_ENABLED is deprecated).
# [prompt_cache]
# mode = "auto"
# Prompt-ingress safety controls.
# wrap_untrusted_workspace: wrap untrusted workspace files with safety bounding markers.
# injection_scan_mode: "report" (default; log findings), "enforce" (redact matched workspace-file content; the turn still runs), "off".
# [safety]
# wrap_untrusted_workspace = true
# injection_scan_mode = "report"
[memory]
# "workspace" stores MEMORY.md and memory/*.md under workspace_dir.
# SQLite indexes still live under state_dir.
source = "workspace"
# Long-term memory vector indexing defaults to provider="auto". Auto order:
# a downloaded EmbeddingGemma model first (higher quality), then the bundled
# BGE-small ONNX model (offline fallback), then a memory-specific remote key if
# one is configured, then FTS-only. Chat LLM/OpenRouter credentials are not
# used for memory embeddings unless explicitly configured below.
#
# Upgrade the local model with:
# agentos memory embedding-download
# Use --model <id> to select a different model (default: google/embeddinggemma-300m).
# Auto mode then prefers it automatically. Switching the local model changes the
# embedding fingerprint and triggers a full reindex on next start.
# retrieval_mode = "hybrid" # "hybrid" | "fts_only"
#
# [memory.embedding]
# provider = "auto" # "auto" | "none" | "local" | "openai" | "openai-compatible" | "ollama"
#
# [memory.embedding.local]
# model = "" # optional; empty = auto (downloaded EmbeddingGemma else bundled BGE);
# # pin to "google/embeddinggemma-300m" or "BAAI/bge-small-zh-v1.5"
# onnx_dir = "" # optional; empty uses the resolved model's export; supports absolute, ~, or process-relative paths
#
# [memory.embedding.remote]
# api_key = ""
# base_url = "https://api.openai.com/v1"
# model = "text-embedding-3-small"
# headers = {}
#
# [memory.embedding.ollama]
# base_url = "http://localhost:11434"
# model = "embeddinggemma"
# Older setups may still have "nomic-embed-text" configured here; that
# continues to work, but changing the model (in either direction) triggers
# a full reindex since it changes the embedding fingerprint.
# Turn capture writes memory/archive/** audit transcripts by default.
# These archives are not searchable memory unless explicitly opted in.
# capture_user = true
# capture_assistant = false
# capture_excluded_run_kinds = ["recall", "session_recall"]
# capture_excluded_provenance_kinds = ["recall", "tool_result", "memory_injected"]
#
# Curated memory: MEMORY.md (agent notes) and USER.md (user profile) are
# bounded entry stores injected into every system prompt. When full, the
# agent consolidates via the `memory` tool instead of growing unbounded.
# curated_memory_char_limit = 4000
# curated_user_char_limit = 2000
#
# inject_limit bounds total passive memory injection into the system prompt
# (curated blocks plus any legacy free-form fallback). Keep it comfortably
# above curated_memory_char_limit + curated_user_char_limit + header
# overhead so a full MEMORY.md and a full USER.md both fit without either
# block being dropped whole at the injection boundary.
# inject_limit = 6400
# [memory.provider]
# Optional external memory provider layered on top of built-in memory. When a
# provider is selected it adds a prompt recall block, fenced recall, per-turn
# sync, and a write mirror. name is empty by default (built-in memory only).
# The provider is built once at boot, so changing name requires a gateway
# restart. mem0 needs the extra: pip install "use-agent-os[mem0]".
# name = "mem0" # "" (disabled) | "mem0"
#
# [memory.provider.mem0]
# mem0 defaults target a fully local stack (Ollama LLM + embedder, on-disk
# vector store) so it works offline with no API keys. vector_store_path is
# empty by default and resolves to <agent state dir>/mem0 at boot.
# llm_provider = "ollama"
# llm_model = "qwen3:4b"
# llm_base_url = "http://localhost:11434"
# embedder_provider = "ollama"
# embedder_model = "embeddinggemma"
# embedder_base_url = "http://localhost:11434"
# vector_store_path = "" # empty -> <agent state dir>/mem0
[memory.nudge]
# Periodic memory review. Every `interval` user turns, once the reply is
# already delivered, a short background turn re-reads the conversation and
# saves anything durable it finds. Without it MEMORY.md tends to stay empty:
# saving is never the most urgent thing in any single turn.
#
# Skipped for cron/heartbeat/subagent turns, and for any turn where the agent
# already wrote to memory on its own.
enabled = true
interval = 10 # user turns between reviews; 0 disables
# max_iterations = 6 # ceiling on the review turn's own tool loop
# timeout_seconds = 90.0
[skills]
# Experimental skill relevance filtering. Default is off; deterministic
# skill gating still runs for visibility, platform, and tool availability.
filter_enabled = false
filter_top_k = 5
# Character budget for the injected skills block. Above it the block falls
# back to names only, then starts dropping skills (lowest-precedence layer
# first). The bundled set renders ~16k with descriptions, so the default
# leaves room for installed skills before either fallback kicks in.
max_skills_prompt_chars = 24000
# Ceiling on one skill_view result. Unlike the block above, a tool result is
# not cached, so a large skill costs its tokens again on every re-read. Over
# this, the opening sections come back with an index of the rest, which the
# agent reads one section at a time. 0 restores whole-body reads.
max_skill_view_chars = 10000
# injection_mode = "system" # "system", "user_context", or "user_message"
# The default lexical strategy is dependency-free. "semantic" and "hybrid"
# are legacy experimental modes that need the bundled BGE ONNX backend
# (onnxruntime + transformers tokenizer + the int8 ONNX export shipped under
# src/agentos/memory/models/bge_onnx/). Install via
# `uv sync --extra recommended`. If unavailable, they degrade to lexical-only.
# filter_strategy = "lexical" # "lexical" | "semantic" | "hybrid"
# filter_lexical_top_n = 20
# filter_semantic_top_n = 20
# filter_rrf_k = 60
# filter_embedding_model = "BAAI/bge-small-zh-v1.5" # bundled BGE default;
# set "google/embeddinggemma-300m" to reuse a downloaded EmbeddingGemma export
# Settings individual skills declare via metadata.agentos.config in their
# SKILL.md. Keys belong to the skills, so this section is free-form. Credentials
# do NOT go here — those belong in ~/.agentos/.env (`agentos env set`), where
# they are masked in listings and gated on write.
# [skills.config]
# wiki.path = "/srv/wiki"
[task_runtime]
# Server-side agent turn queue. Same-session tasks are serialized;
# different sessions can run concurrently up to this limit.
max_concurrency = 4
# Waiting tasks per session before new follow-up work is rejected.
max_pending_per_session = 64
[agentos_router]
enabled = true # auto tier router
auto_thinking = true
rollout_phase = "full"
strategy = "pilot-v1" # "pilot-v1" (default; local ONNX+MiniLM router,
# English-optimized, no LLM call). Needs the
# models/pilot_v1/ bundle + the bundled MiniLM embedder;
# a missing bundle degrades to the default tier unless
# require_router_runtime is set. See [agentos_router.pilot].
# strategy = "llm_judge" # the only other selectable strategy: routes via a small
# LLM judge call (see judge_* settings below).
# NOTE: the legacy "v4_phase3" local ML strategy is no longer a supported
# persisted choice — a config that still pins it is automatically migrated to
# "pilot-v1" on the next load (the original is backed up next to this file).
# LLM judge (strategy = "llm_judge"): leave judge_model unset for Auto — the
# judge follows the tier profile's cheapest text tier (c0 first), so profile
# switches auto-update it. judge_provider must match [llm].provider.
# Env overrides: AGENTOS_ROUTER_JUDGE_MODEL / AGENTOS_ROUTER_JUDGE_PROVIDER.
# judge_model = "deepseek/deepseek-v4-flash"
# judge_provider = "openrouter"
judge_input_max_chars = 4000
judge_short_circuit_enabled = true
# Extra exact greeting/ack phrases (case-insensitive) that skip the judge;
# empty uses the built-in default allowlist.
# judge_short_circuit_allowlist = ["ack", "roger"]
# Judge-internal timeout (seconds). Leave unset to derive it from
# routing_timeout_seconds, staying strictly below the outer router budget.
# judge_timeout_seconds = 8.0
# Optional provider tier profile. Leave unset to preserve the built-in
# OpenRouter defaults below. If set, it must match [llm].provider; the router
# does not switch providers at runtime.
#
# INVARIANT: routing is single-provider. Tiers only select the MODEL for a
# turn; every request still goes through the one [llm].provider client. A
# tier whose `provider` differs from [llm].provider cannot reach that other
# provider — on local providers (ollama / lm_studio / ovms / vllm) such a
# tier is degraded to [llm].model at runtime (metadata: routing_degraded).
# To get real multi-model routing, point every tier at a model that
# [llm].provider itself serves (see the local example below).
# tier_profile = "dashscope" # openrouter | dashscope | deepseek | gemini | volcengine
default_tier = "c1"
confidence_threshold = 0.5
kv_cache_anti_downgrade_enabled = true
kv_cache_anti_downgrade_window_seconds = 600
complaint_upgrade_enabled = true
complaint_upgrade_steps = 1
complaint_upgrade_max_chars = 160
# Translation ceiling. The router scores reasoning difficulty, so an ordinary
# "translate this" lands on c1 even in English, and drifts further in other
# languages because they are outside the training corpus. A deterministic
# detector (14 languages) caps a translation turn at translate_ceiling_tier.
# Every detected translation is capped, extras and all. A complaint upgrade
# wins over the cap and the large-context floor still applies after it; the
# only request that keeps the verb without taking the cap is porting code
# ("translate this Python module to Rust"), which is a request to write code.
translate_ceiling_enabled = true
translate_ceiling_tier = "c0"
estimated_output_savings_pct = 0.03
upgrade_to_c3_compaction_enabled = true
# Pilot router settings (only used when strategy = "pilot-v1"). The strategy
# couples safety_net_threshold with confidence_threshold above into t_eff; a
# pilot_artifact_dir override points at a Pilot bundle outside models/pilot_v1/.
[agentos_router.pilot]
safety_net_threshold = 0.5
# pilot_artifact_dir = "/path/to/pilot_v1"
[agentos_router.tiers.c0]
provider = "openrouter"
model = "deepseek/deepseek-v4-flash"
description = "Fast DeepSeek V4 Flash route for trivial chat, short rewrites, extraction, and low-risk simple Q&A"
supports_image = false
thinking_level = "high"
[agentos_router.tiers.c1]
provider = "openrouter"
model = "openai/gpt-5.6-luna"
description = "Default balanced text route for normal agent work, coding assistance, debugging, and moderate analysis"
supports_image = false
thinking_level = "high"
[agentos_router.tiers.c2]
provider = "openrouter"
model = "z-ai/glm-5.2"
description = "Stronger text route for multi-step coding, structured reasoning, larger context synthesis, and harder analysis"
supports_image = false
thinking_level = "high"
[agentos_router.tiers.c3]
provider = "openrouter"
model = "anthropic/claude-opus-5"
description = "Highest-quality text reasoning route for difficult planning, deep review, complex debugging, and high-stakes synthesis"
supports_image = false
thinking_level = "high"
[agentos_router.tiers.image_model]
provider = "openrouter"
model = "minimax/minimax-m3"
description = "Image model: vision-capable route for user-supplied image attachments, screenshots, diagrams, and visual question answering"
supports_image = true
image_only = true
thinking_level = "medium"
# Example: DashScope profile requires:
# [llm]
# provider = "dashscope"
# model = "qwen3.6-plus"
# api_key = "${DASHSCOPE_API_KEY}"
# base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
#
# [agentos_router]
# tier_profile = "dashscope"
# Example: local provider (Ollama) with real multi-model routing. Local
# providers have no tier profile — declare the tiers yourself, and point
# every tier at a model your local server actually serves (`ollama list`).
# Same pattern applies to lm_studio / ovms / vllm. Onboarding writes
# self-consistent single-model tiers for local providers automatically.
# [llm]
# provider = "ollama"
# model = "qwen3.5:2b"
# base_url = "http://localhost:11434"
#
# [agentos_router.tiers.c0]
# provider = "ollama"
# model = "qwen3.5:2b" # small + fast for trivial turns
# [agentos_router.tiers.c1]
# provider = "ollama"
# model = "qwen3.5:9b" # balanced default
# [agentos_router.tiers.c2]
# provider = "ollama"
# model = "qwen3.5:9b"
# [agentos_router.tiers.c3]
# provider = "ollama"
# model = "qwen3.5:latest" # strongest local model for hard turns
# [agentos_router.tiers.image_model]
# provider = "ollama"
# model = "qwen3.5:9b" # must be a vision-capable local model
# supports_image = true
# image_only = true
[tools]
# Plain-text fallback for models that do not reliably support native tool
# calls. When false, AgentOS sends no tool definitions and executes no tools.
enabled = true
# Base allowlist. Tool schemas are the fixed overhead on every provider call in
# every turn — on a stock install roughly 7,300 tokens — so this is usually the
# largest thing you can change. Run `agentos context` to see the current cost
# and what each profile would cost on your install.
#
# full every registered tool (default)
# coding filesystem, runtime, sessions, memory
# messaging message + session inspection
# memory_only memory tools only
# minimal session_status only
#
# The set is fixed for the session, so narrowing it does not disturb the prompt
# cache. `allow` / `also_allow` / `deny` refine it further.
# profile = "coding"
[agent_token_saving]
# Project fresh tool results with the built-in tokenjuice reducer before they
# are fed back into the model. Raw tool responses remain available through the
# tool-result store when configured by the gateway runtime.
tool_result_projection_max_inline_chars = 60000
tool_result_store_max_bytes = 8388608
tool_result_store_disk_budget_bytes = 268435456
tool_result_store_retention_seconds = 604800
[prompt]
# Prompt-layer feature flags.
# platform_hint_enabled = true # channel-specific markdown rendering hints
# env_probe_enabled = true # tell the model which developer tools are on
# # PATH, so it stops reaching for ones this
# # machine does not have. Names only, no paths.
[compaction]
enabled = true
# model = "" # None = use session model
# timeout_seconds = 30.0
[auxiliary]
# The model for work AgentOS does on its own behalf rather than as part of a
# turn: analysing an attached document, describing an image. These calls are
# billed to the session but tracked separately, so `agentos cost` can show what
# the agent spent answering versus what the runtime spent on its own.
#
# Leave empty to reuse the [llm] provider and model. Point it at something
# cheap if these tasks do not need your main model.
# provider = ""
# model = ""
# timeout_seconds = 120.0
# Per-task overrides. Tasks in use: "document" (analysing an attached file) and
# "vision" (describing an image). A task with a capability requirement wants its
# own entry — vision needs a model that can actually see an image.
# [auxiliary.tasks.vision]
# model = "openai/gpt-4o-mini"
[sandbox]
# Per-command ephemeral sandbox + security grading.
#
# sandbox on -> processes run under namespace/profile isolation
# off -> host execution is allowed (logs a WARNING per run)
# security_grading on -> action_kind drives the selected SecurityLevel
# off -> a fixed STANDARD policy is used, no approval flow
#
# Both default to false for the out-of-box bypass posture. Turning sandbox off
# while grading stays on is silently coerced to grading=false with a warning.
sandbox = false
security_grading = false
# default_level = "STANDARD" # DISABLED | STANDARD | STRICT | LOCKED
# backend = "auto" # auto | bubblewrap | seatbelt | noop
# allow_legacy_mode = false # required for default_level = DISABLED
# denial_threshold = 3 # pause autonomous runs after N denials
# extra_ro_mounts = []
# extra_rw_mounts = []
# cpu_seconds = 30
# memory_mb = 1024
# wall_seconds = 60
[permissions]
# Interactive Control default permission mode. The shipped default is "bypass",
# which runs interactive Control tool execution on the host while still blocking sensitive
# paths. Use `agentos sandbox on|bypass|full|reset` to update this together
# with the sandbox section.
default_mode = "bypass" # off | on | bypass | full
# Default elevation posture for unattended cron turns (agent_turn jobs only;
# reminders, script jobs, and system events are never elevated). Separate
# from default_mode above, which only governs interactive Control turns.
# "bypass" lets a scheduled job run shell-based skills with no approval
# prompt; override per-job with `--no-elevated` or `--elevated-mode`.
# See docs/cli.md#letting-a-cron-job-run-shell-based-skills.
cron_default_mode = "bypass" # off | bypass | full
# [auth]
# mode = "none" # none | token | trusted-proxy
# token = ""
# Startup guard: with mode = "none" the gateway refuses to bind a non-loopback
# host (0.0.0.0, a LAN IP, ...). Enable token auth or keep the loopback bind.
# [control_ui]
# On a loopback bind the WebSocket handshake, cross-origin HTTP requests, and
# the HTTP Host header are pinned to loopback origins to block cross-site
# WebSocket hijacking, drive-by API calls, and DNS rebinding from a page in
# the operator's browser. When serving the Control UI through a reverse proxy
# on another host, add that browser origin here (scheme + host [+ port];
# default ports 80/443 are normalized, so "https://agent.example.com" and
# "https://agent.example.com:443" are equivalent):
# allowed_origins = ["https://agent.example.com"]
# Stream model reasoning ("thinking") into the WebUI live and expose it in chat
# history as collapsible blocks. WebUI-only: channel adapters (Slack, Telegram,
# ...) never receive thinking regardless of this flag. Default: true.
# show_thinking = true
# [channels]
# [[channels.channels]]
# name = "my-slack"
# type = "slack"
# token = "xoxb-..."
# connection_mode = "socket" # socket = no public URL; webhook = Events API
# app_token = "xapp-..." # required for Slack Socket Mode
# signing_secret = "" # required for Slack webhook mode
# app_id = "A12345" # optional: enables native-command manifest sync
# manifest_token = "xoxe.xoxp-..." # optional short-lived app configuration token
# command_request_url = "https://agent.example/slack/events"
# slack_channel_id = "C12345"
# reply_in_thread = false
# [[channels.channels]]
# name = "personal"
# type = "telegram"
# token = "123456:bot-token"
# Direct messages always require pairing. Groups are disabled unless every
# group is listed explicitly; group senders must also be paired.
# groups_enabled = false
# group_chat_ids = ["-1001234567890"]
# group_mention_required = true
# [observability]
# Prometheus metrics endpoint exposition, OTLP trace export, and log retention.
# metrics_enabled = true # Expose Prometheus metrics endpoint
# metrics_path = "/metrics" # HTTP route path for Prometheus exposition
# otlp_enabled = false # Export traces to OpenTelemetry collector
# otlp_endpoint = "http://localhost:4318" # OTLP/HTTP traces endpoint URL
# otlp_headers = {} # Optional headers for OTLP exporter
# otlp_service_name = "agentos" # Service name reported in OTLP resource spans
# log_retention_days = 14 # Prune log/trace files older than N days (0 = disabled)
# log_retention_max_total_mb = 500 # Prune oldest logs when total dir size exceeds MB (0 = disabled)
# log_retention_sweep_interval_s = 3600.0 # Cadence for background retention sweeps
# transcribe_voice = false
# max_voice_duration_s = 120
# [[channels.channels]]
# name = "inbox"
# type = "email"
# imap_host = "imap.example.com"
# imap_port = 993
# imap_username = "agent@example.com"
# imap_password = "app-password"
# imap_folder = "INBOX"
# smtp_host = "smtp.example.com"
# smtp_port = 587
# smtp_starttls = true # set smtp_ssl = true with port 465 for implicit TLS
# smtp_username = "agent@example.com"
# smtp_password = "app-password"
# from_address = "agent@example.com"
# from_name = "Agent"
# Required fail-closed From-address allowlist: exact addresses or *@domain
# patterns. Mail from anyone else is dropped before it reaches the agent.
# allowed_senders = ["you@example.com", "*@yourteam.example"]
# poll_interval_s = 30.0
# max_messages_per_poll = 10
# mark_seen = true
# MCP (Model Context Protocol) external servers.
# [[mcp.servers]]
# name = "fetch"
# transport = "stdio"
# command = "uvx"
# args = ["mcp-server-fetch"]
# env = {}
# [budgets]
# Money spend ceilings, in US dollars of estimated (or provider-billed) model
# spend. Nothing is enforced until a ceiling is set. Spend persists in its own
# state file (`spend_ledger.db`) — keyed by UTC day for the daily ceilings and
# by session for the session ceiling — so a restart does not reset them.
# A turn that would run past a hard limit is refused with a clear error; a
# `*_warn` threshold surfaces a one-shot warning instead of stopping the turn.
# Changing any of these requires a gateway restart to take effect.
# enabled = true # suspend every ceiling without deleting the numbers
# session_limit = 5.0 # hard stop per session
# session_warn = 4.0 # warn once per session
# daily_limit = 50.0 # hard stop for gateway-wide spend today
# daily_warn = 40.0 # warn once per day
# [budgets.agent_daily_limit]
# main = 20.0
# [budgets.agent_daily_warn]
# main = 15.0
# [budgets.channel_daily_limit]
# telegram = 10.0
# [budgets.channel_daily_warn]
# telegram = 8.0