-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
468 lines (388 loc) · 22.6 KB
/
Copy path.env.example
File metadata and controls
468 lines (388 loc) · 22.6 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
# Environment variables for git-metadata-extractor.
# Copy this file to `.env` and fill in your actual values. `.env` is gitignored.
# Anything left commented out falls back to the default shown next to it.
# ---------------------------------------------------------------------------
# Dev container
# ---------------------------------------------------------------------------
# Optional: devcontainer SSH password — applied on each container start
# (see .devcontainer/set-vscode-password.sh). Do not commit a real value.
# VSCODE_PASSWORD=
# If PyPI fails inside the devcontainer with DNS errors, set custom resolvers
# in `.devcontainer/.env` (see `.devcontainer/.env.example`). No variable here.
# ---------------------------------------------------------------------------
# Required credentials
# ---------------------------------------------------------------------------
# GitHub API token. Required for v2 preflight (`/v2/health` flips to
# `degraded` without it), for all real GitHub provider calls, and for the
# `src/index/github/` indexer (REST metadata + README fetches).
GME_GITHUB_TOKEN=your-github-token-here
# Bound for retrying transient GitHub provider failures (gimie returning
# empty/malformed JSON during 502s, rate-limit blips, etc.). Default 3.
# Set to 0 to disable. Non-transient errors (NOT_FOUND, UnicodeDecodeError)
# never retry — UnicodeDecodeError falls back to a minimal payload instead.
# V2_GITHUB_REPO_MAX_RETRIES=3
# ---------------------------------------------------------------------------
# LLM provider credentials (only the one(s) referenced by your model config
# need to be set — `src/v2/agents/llm/runtime.py` validates this at startup
# and surfaces a clear error if the configured profile's env var is missing).
# ---------------------------------------------------------------------------
# EPFL RCP inference endpoint token. Comma-separated list of tokens is
# supported (`sk-A,sk-B`) — model_config.py round-robins across them at
# every model instantiation, which doubles the effective per-process
# rate-limit budget when more than one token is provided. Same pattern
# as `GME_GITHUB_TOKEN`.
RCP_TOKEN=your-rcp-token-here
# OpenAI API key (only if a model profile is configured for OpenAI).
OPENAI_API_KEY=your-openai-key-here
# OpenRouter API key (only if a model profile is configured for OpenRouter).
OPENROUTER_API_KEY=your-openrouter-key-here
# ---------------------------------------------------------------------------
# Optional integrations
# ---------------------------------------------------------------------------
# Infoscience bearer token. Leave unset for public endpoints; required only
# when the deployment hits protected Infoscience routes.
# INFOSCIENCE_TOKEN=
# Remote Selenium endpoint used by the link-veracity stage and the LLM
# `fetch_link_content_via_selenium` tool. Leave unset to disable Selenium-based
# fetching (the pipeline degrades gracefully with warnings).
# SELENIUM_REMOTE_URL=http://localhost:4444
# ---------------------------------------------------------------------------
# V2 pipeline runtime
# ---------------------------------------------------------------------------
# Default agent runtime when `/v2/extract` requests omit `agent_runtime`.
# One of `rule_based|llm`. Default: `llm`.
# V2_AGENT_RUNTIME_DEFAULT=llm
# When `true`, `/v2/extract` (GET and POST) wires up mock providers — no
# external GitHub/ORCID/Infoscience/ROR calls. Default: `true`. Set to
# `false` for production deployments that talk to real APIs.
# V2_USE_MOCK_PROVIDERS=true
# LLM critic pruning. When `false` (default), the critic stage is skipped
# entirely so no persons/orgs/repos/articles are dropped. Set to `true` to
# re-enable critic drop suggestions; flagged entities appear in
# `excluded_entities` with reason "critic pruning".
# V2_APPLY_CRITIC_PRUNING=false
# Maximum number of LLM agents that may run concurrently inside any fan-out
# stage (person/org/article/membership/contribution). Higher values speed up
# heavy repos (renku-class, ~80 contributors) but push more parallel load
# onto the model endpoint. Default: 6.
# V2_MAX_CONCURRENT_AGENTS=6
# Per-link veracity stage (Selenium fetch + LLM verdict on every external
# URL the pipeline collects). Off by default — it is the slowest stage and
# rarely changes outputs; enable only when auditing link rot or veracity.
# V2_LINK_VERACITY_ENABLED=false
# Hybrid refiner stage: after the rule-based pipeline runs, the LLM agent
# pool refines/repairs each entity (canonical IDs, missing fields). Default
# `true` for `agent_runtime=llm` and ignored for `rule_based`.
# V2_HYBRID_REFINER_ENABLED=true
# Affiliation-from-Person-signals pipeline. Three independent stages run in
# the same pipeline slot (right after reconciliation, before the LLM critic)
# and stamp `schema:affiliation` on Person entities the rule-based path left
# unanchored. All default `true`; set to `false`/`0`/`no`/`off` to skip a
# stage entirely (e.g. catalog backfills that should preserve the raw
# `_company` strings unchanged).
#
# `resolve_company_to_ror` reads the structured `_company` field, sends it
# through the same ROR RAG with strict acceptance (score >= 0.55, type in
# {company,education,funder,facility,government,nonprofit}, gap >= 0.02 or
# exact-name override). Cheap — one vector search per unique company string.
# V2_RESOLVE_COMPANY_TO_ROR=true
#
# `resolve_bio_to_ror` (deterministic backstop) — when `_company` is empty,
# extracts org candidates from `_bio` / `_orcid_biography` via regex
# (`at <Org>`, `@handle`, `, <Org>` after a role, `from <Org>`) AND from
# `_blog` / `_email` host via a small DOMAIN_HINTS table (EPFL, ETH Zurich,
# MIT, DeepMind, …). Reuses the same acceptance gate as the company stage.
# Email is matched by domain only — the local part is hashed in `_email`.
# V2_RESOLVE_BIO_TO_ROR=true
#
# `resolve_bio_to_ror_llm` (LLM long-tail) — for each Person still missing
# `schema:affiliation` after the two stages above AND with at least one of
# bio / orcid bio / profile readme, run a single-Person `bio_resolver` LLM
# agent with `search_ror_rag` tool access. Confidence floor 0.7 + verbatim
# quote required. Only runs under `agent_runtime=llm` or `hybrid` — a
# no-op under `rule_based` even when the flag is true. Concurrency is
# bounded (default 4) so a 100-contributor repo doesn't fan out 100x.
# V2_RESOLVE_BIO_TO_ROR_LLM=true
# V2_RESOLVE_BIO_TO_ROR_LLM_CONCURRENCY=4
# Owned-repo fan-out for user/organization roots. When `false` (default), a
# user/org extraction keeps its repositories as references in `pulse:owns`
# instead of running the full per-repo pipeline on each — fast, and avoids
# timeouts on big accounts (80+ repos). Set `true` to restore eager
# expansion (capped at 25 repos for orgs, 50 for users).
# V2_EXPAND_OWNED_REPOS=false
# Top-N bookend contributors to materialise in context_gather (first/last
# committers by date). Larger values widen the scout brief but inflate the
# token bill. Default: 50.
# V2_CONTRIBUTOR_BOOKENDS_TOP_N=50
# Override the LLM model used by every v2 agent profile (rewrites the
# `model` field across every `MODEL_CONFIGS[*]` entry at load time).
# Useful when the default model on the shared inference endpoint is
# degraded and you want a temporary fallback without editing
# `src/v1/llm/model_config.py`. Unset / empty = use the defaults
# (currently `openai/gpt-oss-120b`).
# Examples for inference-rcp.epfl.ch when gpt-oss is down:
# V2_LLM_MODEL_OVERRIDE=Qwen/Qwen3-30B-A3B-Instruct-2507
# V2_LLM_MODEL_OVERRIDE=mistralai/Ministral-3-8B-Instruct-2512
# V2_LLM_MODEL_OVERRIDE=
# Scout-mode upgrade for the `context_summary` LLM stage. When `true`,
# the summary agent gets the broad RAG-search toolkit (orcid, ror,
# infoscience, openalex, zenodo, ethz_research_collection, huggingface,
# renkulab, snsf, epfl_graph + selenium_fetch) on top of the legacy
# `grep_repository_corpus` + DuckDuckGo pair, and switches to a
# scout-style system prompt that produces a structured brief with
# explicit People / Organizations / Articles / Affiliations / Caveats
# sections. Per-entity agents (person, org, article, membership,
# contribution) automatically benefit since they already consume the
# `summary_markdown` field. Trade-off: one heavier upfront LLM call,
# but per-entity calls send less context (raw blobs already stripped)
# and duplicate ORCID/ROR lookups across entities collapse into the
# scout's shared brief. Off by default.
# V2_CONTEXT_SUMMARY_SCOUT_MODE=false
# ---------------------------------------------------------------------------
# V2 caches
# ---------------------------------------------------------------------------
# Provider response cache (GitHub users/orgs, ORCID, Infoscience, ROR) AND
# the async-job store backing `POST /v2/extract` + `GET /v2/jobs/{job_id}`.
# Single TTL applied to every cached entry.
# V2_PROVIDER_CACHE_PATH=.cache/v2/providers.db
# V2_PROVIDER_CACHE_TTL_DAYS=30
# V2_PROVIDER_CACHE_ENABLED=true
# Pipeline-level response cache (the outer `/extract` → V2ExtractResponse
# cache). Set to `false` to force every `/extract` call to re-run the full
# pipeline while keeping every sub-cache (provider responses, agent verdicts,
# Selenium fetches, link-veracity verdicts) active. Useful when verifying the
# sub-caches are doing their job. Default: `true`.
# V2_PIPELINE_CACHE_ENABLED=true
# ---------------------------------------------------------------------------
# Logging & observability
# ---------------------------------------------------------------------------
# FastAPI / Python log level. One of DEBUG|INFO|WARNING|ERROR. Default: INFO.
# LOG_LEVEL=INFO
# Per-request log of every external-service query the LLM agents try
# (Infoscience, ORCID, ROR, GitHub, DuckDuckGo, Selenium, etc.). Each
# `/extract` call writes one JSON file `<run_id>.json` here. Default:
# `logs/v2_queries/` (relative to the server's working directory).
# V2_QUERY_LOG_DIR=logs/v2_queries
# Log level for the v2 skill subprocesses (selenium_fetch and the other
# search_* skills under src/v2/skills/). Independent from LOG_LEVEL so the
# noisy skill output can stay quiet while the main FastAPI app runs at INFO.
# Default: WARNING.
# V2_SKILL_LOG_LEVEL=WARNING
# ---------------------------------------------------------------------------
# src/index/* (Infoscience + OpenAlex RAG indexing)
# ---------------------------------------------------------------------------
# Override default data root for `src/index/*` (where harvested raw JSON,
# extracted text, and the LanceDB / DuckDB stores live). Default: `data/index`.
# OpenAlex artifacts live under `<INDEX_DATA_DIR>/openalex/`.
# INDEX_DATA_DIR=data/index
# Pipeline tuning, model pins, and Solr filter terms for Infoscience live in
# `config/index/infoscience.yaml`. RCP and Infoscience auth tokens are
# read from `RCP_TOKEN` / `INFOSCIENCE_TOKEN` above.
# Set to `false` to disable the V2 Infoscience RAG agent tool. Default is
# on; the tool degrades gracefully when the Qdrant collection is missing.
# V2_INFOSCIENCE_RAG_ENABLED=true
# ---------------------------------------------------------------------------
# src/index/openalex — OpenAlex ingestion + RAG over EPFL/Switzerland
# ---------------------------------------------------------------------------
# Static settings (RCP base URL, model pins, scope ROR/country, Qdrant URL,
# chunking sizes, etc.) live in `config/index/openalex.yaml`. Only secrets
# and the most common runtime overrides go here.
# Required: email used by OpenAlex polite pool. Without this, requests fall
# back to the slower public pool with stricter rate limits.
# OPENALEX_MAILTO=you@example.com
# Optional: override the Qdrant API key at runtime (not in YAML).
# INDEX_QDRANT_API_KEY=
# Optional runtime overrides (rarely needed — defaults from YAML are correct
# for the EPFL deployment). When running inside the devcontainer the Qdrant
# service is reachable as `gme-qdrant`; from a host shell or external runner
# use `localhost`.
# INDEX_QDRANT_URL=http://gme-qdrant:6333
# INDEX_QDRANT_PREFER_GRPC=false
# INDEX_OPENALEX_SCOPE_ROR=https://ror.org/02s376052
# INDEX_OPENALEX_SCOPE_COUNTRY=ch
# Set to `false` to disable the V2 OpenAlex RAG agent tool. Default is on;
# the tool degrades gracefully when the Qdrant collection is missing.
# V2_OPENALEX_RAG_ENABLED=true
# ---------------------------------------------------------------------------
# src/index/huggingface — HuggingFace ingestion + RAG over EPFL/Switzerland
# ---------------------------------------------------------------------------
# Static settings (RCP base URL, model pins, EPFL/Swiss org seeds, discovery
# search terms, Qdrant URL, chunking) live in `config/index/huggingface.yaml`.
# Only secrets and the most common runtime overrides go here.
# Recommended: HuggingFace Hub access token. Anonymous IPs share a 500 req /
# 5 min API bucket; authenticated free tier raises that to 1k API + 5k
# resolver requests per window. Required in practice for the Switzerland
# sweep.
# HF_TOKEN=
# Optional: override the active scope at runtime (epfl | switzerland).
# INDEX_HUGGINGFACE_SCOPE=epfl
# Set to `false` to disable the V2 HuggingFace RAG agent tool. Default is on;
# the tool degrades gracefully when the Qdrant collection is missing.
# V2_HUGGINGFACE_RAG_ENABLED=true
# ---------------------------------------------------------------------------
# src/index/zenodo — Zenodo ingestion + RAG over EPFL/Switzerland
# ---------------------------------------------------------------------------
# Static settings (RCP base URL, model pins, EPFL/Swiss community lists,
# Qdrant URL, chunking sizes, page size, rate limit) live in
# `config/index/zenodo.yaml`. Only secrets and the most common runtime
# overrides go here.
# Optional: Zenodo personal access token. Anonymous access works (page size
# capped at 25 server-side); a token raises page size to 100 but is
# recommended for stability.
# ZENODO_TOKEN=
# Optional: override the active scope at runtime (epfl | switzerland).
# INDEX_ZENODO_SCOPE=epfl
# Set to `false` to disable the V2 Zenodo RAG agent tool. Default is on;
# the tool degrades gracefully when the Qdrant collection is missing.
# V2_ZENODO_RAG_ENABLED=true
# ---------------------------------------------------------------------------
# SWISSUbase index module (`src/index/swissubase/`)
# ---------------------------------------------------------------------------
# SWISSUbase (www.swissubase.ch) is the Swiss national platform for
# sharing/preserving social-science research data, run by FORS / UZH /
# U. Neuchâtel / DASCH. There is no public REST API: every catalogue
# detail endpoint requires the session cookie set by the SPA. Ingest
# therefore drives a Selenium browser session and calls the JSON
# endpoints from inside the authenticated browser context, so
# SELENIUM_REMOTE_URL must be set.
#
# Static settings (catalogue base URL, language, polite delay, scope
# patterns, Qdrant URL, chunking sizes) live in
# `config/index/swissubase.yaml`. Only runtime overrides go here.
# Override the active ingest scope:
# epfl_sdsc_ethz (default) — embed only studies whose institution
# string matches EPFL / ETHZ / SDSC.
# switzerland — embed every study (full ~13k catalogue).
# INDEX_SWISSUBASE_SCOPE=epfl_sdsc_ethz
# Set to `false` to disable the V2 SWISSUbase RAG agent tool. Default
# is on, but the agent tool degrades gracefully (returns []) when the
# Qdrant collection isn't built yet.
# V2_SWISSUBASE_RAG_ENABLED=true
# ---------------------------------------------------------------------------
# RenkuLab index module (`src/index/renkulab/`)
# ---------------------------------------------------------------------------
# RenkuLab (renkulab.io) is SDSC's data-science platform. The index covers
# four entity types — projects, groups, users, data_connectors — pulled
# from the public `/api/data` REST surface. Three list endpoints are
# anonymous; users are harvested via `/search/query?q=type:User` (the
# dedicated `/users` endpoint requires auth).
#
# Static settings (Renku base URL, page size, rate limit, Qdrant URL,
# chunking sizes, scope keyword filters) live in
# `config/index/renkulab.yaml`. Only secrets and runtime overrides
# go here.
# Optional: RenkuLab personal access token. Anonymous access works for
# everything the indexer needs today; set this if you want richer user
# records via `/users` in the future.
# RENKULAB_TOKEN=
# Override the active ingest scope (all | epfl | switzerland). Scope
# filters are heuristic substring matches against namespace, path,
# keywords, and repository URLs — Renku has no first-class community.
# INDEX_RENKULAB_SCOPE=all
# Set to `false` to disable the V2 RenkuLab RAG agent tool. Default is
# on; the tool degrades gracefully (returns []) when collections are
# missing.
# V2_RENKULAB_RAG_ENABLED=true
# ---------------------------------------------------------------------------
# Open Access Monitor CH index module (`src/index/oamonitor/`)
# ---------------------------------------------------------------------------
# Local mirror of the OAM-CH Mongo-proxy API (Journals / Publications /
# Publishers / Organisations) with per-entity Qdrant collections. The
# OAM API is public; no token required. Static settings (RCP base URL,
# model pins, Qdrant URL, page size) live in `config/index/oamonitor.yaml`.
# Override the upstream API base URL (default: https://oam.oamonitor.ch/api/data/public).
# OAMONITOR_API_BASE_URL=
# Set to `false` to disable the V2 OAM-CH RAG agent tool. Default is on;
# the tool degrades gracefully (returns []) when collections are missing.
# V2_OAMONITOR_RAG_ENABLED=true
# ---------------------------------------------------------------------------
# GitHub repository index module (`src/index/github/`)
# ---------------------------------------------------------------------------
# A deterministic GitHub-REST-fed index of EPFL/Swiss/gimie-list repos
# (metadata + README chunks, embedded with Qwen3-Embedding-8B). Reuses
# the existing `GME_GITHUB_TOKEN` for REST + README fetches — no new secret.
# `GME_GITHUB_TOKEN` may be a comma-separated list of PATs to multiply the
# 5K req/h auth budget; the client round-robins and parks rate-limited
# tokens until their reset.
#
# Static settings (RCP base URL, model pins, scope seeds, Qdrant URL,
# chunking sizes, README size cap) live in `config/index/github.yaml`.
# Only runtime overrides go here.
# Override the active ingest scope (epfl | switzerland | <any seed name>).
# INDEX_GITHUB_SCOPE=epfl
# Set to `false` to disable the V2 GitHub RAG agent tool. Default is on;
# the tool degrades gracefully (returns []) when the github_repos
# collection isn't built yet. Wired into the repository agent so the
# LLM can find related repos / canonical implementations while
# reasoning about the repo it is processing.
# V2_GITHUB_RAG_ENABLED=true
# Auto-ingest every newly seen PUBLIC repository into the GitHub RAG
# index after a successful /v2/extract call. Off by default so existing
# deployments don't change behaviour. When `true`, an async background
# task fires after each completed repository extraction:
#
# 1. Skip if the repo is already in the GitHub DuckDB (no refresh).
# 2. Fetch its metadata + README via the GitHub REST API.
# 3. Persist the row to DuckDB and embed the README chunks into the
# `github_repos` Qdrant collection.
# 4. Private/unreachable repos surface as `skipped_404` and emit one
# log line — no caller-visible error.
#
# This grows the GitHub RAG index organically as repos are processed,
# so subsequent extractions find them via `search_github_rag` without
# manual cli ingest runs. Module-level lock serialises DuckDB writes
# across uvicorn workers, so it's safe with `WORKERS=4` or higher.
# V2_GITHUB_RAG_AUTO_INGEST=false
EPFL_GRAPH_USERNAME=
EPFL_GRAPH_PASSWORD=
# Disable the EPFL Graph disciplines RAG agent tool / federated adapter.
# When unset (default), the v2 LLM repository agent gets a
# `search_epfl_graph_disciplines` tool backed by the Qdrant collection
# `epfl_graph_disciplines`. Run `just epfl-graph-ingest && just
# epfl-graph-embed` once to populate it.
# V2_EPFL_GRAPH_RAG_ENABLED=true
# Concept tagging (optional pipeline stage). When enabled, stamps
# `_concepts` and `_keywords` onto the root repository entity from the
# README. Both fields are stripped before strict validation and JSON-LD
# output for now (schema-compliant); they exist as internal pipeline
# metadata until the ontology adds the corresponding terms.
# Backends: `epfl_graph` (requires EPFL_GRAPH_USERNAME/PASSWORD), `wikipedia`
# (credential-free, MediaWiki opensearch), `llm` (uses the project's
# existing model_config — RCP_TOKEN / OPENAI_API_KEY / OPENROUTER_API_KEY).
# V2_CONCEPT_TAGGING_ENABLED=false
# V2_CONCEPT_TAGGING_BACKEND=epfl_graph
# Drop EPFL Graph concepts whose mixed_score is below this threshold (0..1).
# Helps prune low-confidence noise (e.g. "Graph theory" matched on the word
# "graph"). Only applies to the `epfl_graph` backend.
# V2_CONCEPT_TAGGING_EPFL_MIN_SCORE=0.5
# Enrich each top-N discipline with related publications/people/units via
# OpenAlex (uses pyalex, polite-pool email read from OPENALEX_MAILTO).
# V2_CONCEPT_TAGGING_OPENALEX_RELATED_ENABLED=false
# ---------------------------------------------------------------------------
# Pure-API RAG tools (no local index — direct upstream API calls per query)
# ---------------------------------------------------------------------------
# These tools wrap public REST APIs as LLM agent tools. They don't ingest
# anything locally; each agent invocation issues a fresh HTTP call. All
# default to on; flip to `false` to remove the tool from the agent's
# toolkit (useful for offline testing or when upstream is flaky).
# ORCID public-API search (people lookup by name / affiliation / ORCID iD).
# Requires ORCID_CLIENT_ID / ORCID_CLIENT_SECRET below for authenticated
# access; without them the tool runs against the public anonymous bucket.
# V2_ORCID_RAG_ENABLED=true
# ROR (Research Organization Registry) search — organization disambiguation
# by name / acronym / country. Credential-free public API.
# V2_ROR_RAG_ENABLED=true
# SNSF (Swiss National Science Foundation) grant + person search via the
# public Data Portal API. Credential-free.
# V2_SNSF_RAG_ENABLED=true
# ETHZ Research Collection (DSpace) tool. Uses ETHZ_RESEARCH_COLLECTION_TOKEN
# when set; otherwise falls back to public endpoints.
# V2_ETHZ_RESEARCH_COLLECTION_RAG_ENABLED=true
# Federated RAG router — single agent-facing tool that fan-outs to every
# enabled RAG provider above (Infoscience + OpenAlex + Zenodo + HuggingFace +
# OAM + ORCID + ROR + SNSF + ETHZ-RC + GitHub + RenkuLab + SwissUbase) and
# merges hits. Off by default for individual-tool clarity; turn on for
# scout-mode brainstorm runs.
# V2_FEDERATED_RAG_ENABLED=true
ORCID_CLIENT_ID=
ORCID_CLIENT_SECRET=