Skip to content

R.3: remove implicit <PROVIDER>_API_KEY reading; native default key read at request time - #21

Open
cunninghamcard-bit wants to merge 16 commits into
exp/restartfrom
exp/u1R.3-no-implicit-provider-key
Open

cunninghamcard-bit wants to merge 16 commits into
exp/restartfrom
exp/u1R.3-no-implicit-provider-key

Conversation

@cunninghamcard-bit

@cunninghamcard-bit cunninghamcard-bit commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

R.3 (阶段 1R, A6, D23): 删除 arcships#226 加的通用隐式 <PROVIDER>_API_KEY 读取。

Stacked on #20 (-> #19):三者都改 provider_handle.rs。#19/#20 合并前 diff 会包含它们;R.3 本身是 ff8fae77。

  • 删掉 format!("{}_API_KEY") 通用查找;non_empty_env 只剩 *_BASE_URL。
  • OpenAI 原生默认 OPENAI_API_KEY 保留,改为请求时读取;缺失时请求报 LoadApiKey。Some("") 不回落。
  • 换了 base URL 且没 key:不读 env,也不发 Authorization(请审查确认是否符合 D23)。
  • 测试 env 由 crate 内部 EnvSource::Vars(纯 HashMap)注入,不用闭包,不用 set_var。
  • 新测试 provider_handle::env_tests 7 个:通用 key 不读;构造后再设 env、请求时读到(mock 断言 Bearer);默认 env 缺失时请求失败;Some("") 不回落;换 base URL 不读;auth=none 不读;离线回放不读。
R.0 8455db9 R.3 ff8fae7
cargo test 2871/0/7 2882/0/7
fmt / clippy – pass
boundary script 0 0
gen_ts_types --check – up to date
Python 93 pass / 5 fail 95 pass / same 5 fail
Node 87 pass / 1 fail 93 pass / same 1 fail

未验证:Go/Java/Kotlin/Swift/Flutter 只看 CI。

Review follow-up

  • Review fix (82dc7dc): Handles (env/fetch injection) is #[cfg(test)] only; prod has no dead fields. #[serial] removed from env_tests; the replay test filters its own recording by a unique state since the recorder is process-global. serial_test dev-dep kept (used by integration tests).

Drop ProviderOptions.body_overrides and both arcships#226 rejections in
provider_handle.rs; ProviderOptions now denies unknown fields. Node
ProviderConfig loses bodyOverrides and reports any unknown key as
InvalidArgumentError 'unknown field `x`'. Python docs updated; Python
already rejects unknown keys via serde. Tests in Rust/Python/Node.
Adds docs/amendments/A6-remove-226-per-rfc.md verbatim.
…keys)

Replace the hand-written key allowlist: the JS object is read as a raw
JSON map (undefined values skipped), maxRetries is rejected first with
the call-level message, then the map deserializes into ProviderConfig
with #[serde(deny_unknown_fields, rename_all = "camelCase")]. The
max_retries struct field is gone (index.d.ts loses maxRetries?). Tests:
maxRetries gets the call-level message, undefined keys are absent.
…ies only (A6 item 2)

Drop RetryConfig and prepare_retries_with_config from aimux-core,
DecisionModel::retry_config, the retry fields/overrides in jev,
openai/decision (with_retry_config), runtime_decision and
decision_support (snapshot no longer records max_retries), and the
handle-level ProviderOptions.max_retries default in provider_handle.
decide() uses retry::prepare_retries(options.max_retries, ...).
New mock test: max_retries = 0/1/3/None makes exactly 1/2/4/3 requests.
…n jev_test

Retry counting moves into aimux-core decision_model::retry_tests, using a
crate-internal #[cfg(test)] PreparedRetries::with_initial_delay(ZERO);
asserts attempts = max_retries + 1 and RetryErrorReason::MaxRetriesExceeded
with the last 503/429/529 error. jev_test keeps status classification at
max_retries = 0 plus one max_retries = 1 run on 503 asserting 2 requests
and retry exhaustion. No public API, feature or binding change.
…st time (A6 item 4, D23)

provider_handle no longer reads the generic format!("{}_API_KEY") for local
runtimes (arcships#226). openai with api_key None keeps the package default
OPENAI_API_KEY, now read at request time (arcships#200:538); Some("") is used as
given (RFC-0040:67); a changed base URL without a key sends no credential and
reads no env. Tests inject env as a plain-data map (crate-internal
EnvSource::Vars), never std::env::set_var: generic key not read, env set after
construction is used, Some("") no fallback, replay/auth=none/changed base URL
read nothing. api_key_source field stays for R.4; placeholder key for R.5.
… the struct

Drop #[napi(skip)] invalid: Option<String>; from_napi_value now returns the
InvalidArgumentError directly. The constructors' 3rd arg becomes ConfigArg
(dispatch on JS type) because napi's Either swallowed the member error.
… from env_tests

Prod compiles no Handles / fetch / env plumbing. The env is injected, so the
tests need no serialization; the replay test keeps only its own recording
(unique state) since the recorder is process-global.
Constructors accept the config argument as serde_json::Value (d.ts unchanged),
so conversion never throws synchronously; maxRetries, unknown keys and wrong
types are refused inside the async body as InvalidArgumentError. ConfigArg and
the custom ProviderConfig FromNapiValue are gone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant