Skip to content

Releases: seokhoonj/thinchat

v0.3.2

Choose a tag to compare

@seokhoonj seokhoonj released this 19 Sep 11:57

Loosen the credbox dependency pin to lower-bound-only (drop the speculative <0.5 upper cap on an internally-owned sibling), so a future credbox minor does not force a cascade re-release and co-installed siblings never conflict on the shared dependency. No functional change.

thinchat 0.3.1 — lazy credential store

Choose a tag to compare

@seokhoonj seokhoonj released this 17 Sep 11:51

Builds the credential store lazily, on the first key call, instead of at import. A malformed THINCHAT_STORE_APP / THINCHAT_NAMESPACE override — the host-embedding redirect Credentials.for_app exists to serve — no longer aborts import thinchat; any credbox binding fault is translated to a CredentialStoreError at the call site, so a foreign exception type never escapes.

Pins credbox>=0.4.0,<0.5. credbox 0.4.0 defers store-binding validation to first store access, so passing api_key= (or setting a provider's *_API_KEY env var) resolves without ever validating or touching the store binding.

thinchat 0.3.0

Choose a tag to compare

@seokhoonj seokhoonj released this 12 Sep 04:35

thinchat 0.3.0

Credential storage moves from xdg-kit to credbox, complete() now returns a Completion
result object, and two provider defaults that had broken against current APIs are fixed. This
release is backward-compatible for library callers; the one behavior change is CLI-only (below).

Changed

  • Credential store: xdg-kit → credbox. The store keeps the same path and format
    (~/.config/thinchat/credentials.json, mode 0600), so keys saved with an earlier version are
    read unchanged — a pip install -U picks up credbox and drops xdg-kit automatically. The
    re-exported Secret (masked in logs/tracebacks; .reveal() for the plaintext) is now
    credbox's type.

Added

  • Completion result object — complete() / acomplete() return a Completion, a str
    subclass (so every existing caller is unchanged) that also carries .finish_reason,
    .truncated (True when the reply hit the token cap), .usage, and .model. You can now tell a
    finished reply from one cut off at the token cap.
  • Per-call model= and extra={...} on every verb — override the model for one call, and
    splat provider-specific request fields (OpenAI seed, Anthropic thinking, …) into the
    request. extra keys are provider-specific and reach the request only, not the reply.
  • AuthError (a subclass of LLMError) for a rejected credential (HTTP 401/403), and
    LLMError.status_code so a caller can tell a transient 5xx from a permanent 4xx without
    matching on the message text.
  • Typing :: Typed classifier, a SECURITY.md, and a Changelog link in the project metadata.

Fixed

  • Gemini embeddings work out of the box again — the default embed model was
    text-embedding-004, which Google shut down; it is now gemini-embedding-001.
  • OpenAI completions work on current reasoning models — the reply cap is now sent as
    max_completion_tokens for OpenAI (its newer models reject max_tokens); the Gemini/Ollama
    compat layers still receive max_tokens.
  • Hardened the key-leak protection — the SDK-error → LLMError mapping is now fully total
    (a hostile error object cannot make it raise and re-chain the key-bearing error onto the
    traceback), control characters (incl. C1) are neutralized in error detail, and a Retry-After
    that is non-finite/negative/absurdly large is treated as no hint.
  • Stricter embedding-response validation — mixed/duplicate/out-of-range indices and
    non-numeric vector elements are rejected as LLMError instead of misaligning or crashing.

CLI

  • thinchat get <provider> on a missing key now writes to stderr and exits non-zero (was
    stdout + exit 0), so key=$(thinchat get X) in a script captures an empty value and a testable
    exit code. (The one behavior change in this release.)
  • thinchat list prints a short legend clarifying it reflects the file store only (an env var
    still resolves but is not shown).

Docs

  • README rewritten to lead with what thinchat adds over the raw SDKs (leak-safe keys, one shared
    credential store), a dedicated API keys section (store → env → api_key=, by
    recommendation), and a restyled flow diagram. English/Korean kept in sync.

Compatibility

  • Library callers: backward-compatible. Completion is a str; model=/extra= are new
    optional keyword args; AuthError is an LLMError subclass, so except LLMError still catches
    it. Env-var users are unaffected; file-store users' saved keys are read unchanged.
  • Only breaking change: the CLI thinchat get exit/stream behavior above (affects a shell
    script parsing its output, not the Python API).

v0.2.0

Choose a tag to compare

@seokhoonj seokhoonj released this 07 Sep 06:53

Add an on-disk credential store and a thinchat CLI, backed by xdg-kit. A provider key now resolves through api_key= > <PROVIDER>_API_KEY env > ~/.config/thinchat/credentials.json (0600); thinchat set/get/list/unset manage the store, and set_api_key/get_api_key/stored_providers/unset_api_key expose it programmatically. The pure-library core (make_client(api_key=...)) is unchanged and never reads a file. API keys are now redacted from LLM error messages and their cause chain.

v0.1.3

Choose a tag to compare

@seokhoonj seokhoonj released this 01 Aug 04:29

Add RateLimitError — a typed 429 rate limit.

A rate limit (HTTP 429) that outlives the vendor SDK's own retries now surfaces as RateLimitError instead of a generic LLMError. It is a subclass of LLMError (so existing handlers still catch it) and carries retry_after — the Retry-After wait in seconds when the service sent one, else None. Both provider clients map the SDK's 429 across completion, embedding, and streaming; the actual backoff stays in the SDK (via max_retries), so no retry loop is added.

v0.1.2

Choose a tag to compare

@seokhoonj seokhoonj released this 29 Jul 13:42