v0.8.3: WebUI models, providers and keys; garbled thinking fixed
Streaming: Chinese reasoning showed up garbled in the WebUI. The agent loop now feeds visible/thinking text in runs instead of byte by byte, and the WebUI holds an incomplete UTF-8 tail until the next chunk (cst_utf8_hold_feed), so every think_delta/assistant_delta is whole. src/provider_switch.c: model list fetch/cache, key verify-and-save and provider switching moved out of tui.c and shared by TUI and WebUI. WebUI API: - GET /api/providers, GET /api/models[?refresh=1] (401 on a rejected key, still listing built-ins), POST /api/provider, POST /api/key (key checked against /v1/models, saved to credentials 0600, never echoed in replies, events or logs) - /api/config validates everything before applying, persists model, effort and approval (not yolo), warns when effort does not apply; plan_mode no longer forces read-only - state: turn_usage, api_base, key_set/key_from, model_info, effort_applies, sees_images, max_steps, tool_profile, perm_timeout; permission events carry their timeout Frontend: searchable model picker with refresh and manual entry, provider picker and key dialog, effort/vision hints, toasts instead of silent failures, Chinese error text, real protocol in the settings and usage panels, approval countdown from the server's timeout. Tests: utf8 hold unit test, scripts/e2e_webui_settings.py (fake /v1/models, wrong key, switching, persistence, Chinese thinking) run from e2e_webui.sh, scripts/tui_keys/provider.py.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
#ifndef CST_PROVIDER_SWITCH_H
|
||||
#define CST_PROVIDER_SWITCH_H
|
||||
|
||||
/* Model lists, API keys and provider switches, shared by the TUI and the
|
||||
* WebUI so both front ends validate and persist the same way.
|
||||
*
|
||||
* A key is checked with GET /models: a 401/403 (CST_MODELS_AUTH) rejects
|
||||
* it, any other failure (offline, no /models route) lets it through
|
||||
* unverified. A key that passes is saved to <config>/credentials. Keys are
|
||||
* never copied into err. */
|
||||
|
||||
#include "cst_agent.h"
|
||||
#include "cst_models.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CST_PS_MAX_MODELS 512
|
||||
#define CST_PS_UNKNOWN (-1) /* no such provider */
|
||||
#define CST_PS_NEED_KEY (-10) /* no key given, none saved or in the env */
|
||||
/* Non-negative results are flags: */
|
||||
#define CST_PS_UNVERIFIED 1 /* /models failed for another reason; err says */
|
||||
#define CST_PS_UNSAVED 2 /* the credentials file could not be written */
|
||||
|
||||
typedef struct {
|
||||
char id[128];
|
||||
int api; /* listed by the provider's /models (else built-in only) */
|
||||
cst_model_info_t info;
|
||||
} cst_ps_model_t;
|
||||
|
||||
/* GET /models; a good answer refreshes models-cache/<provider>.json. The
|
||||
* count, CST_MODELS_AUTH, or another negative value with err set. */
|
||||
int cst_ps_fetch(const char *provider, const char *api_base, const char *key,
|
||||
char ids[][128], int max, char *err, size_t err_sz);
|
||||
/* The cached list: count, or -1; *fresh when younger than the TTL. */
|
||||
int cst_ps_cached(const char *provider, char ids[][128], int max, int *fresh);
|
||||
|
||||
/* Base URL for provider: cfg's own when it is the current provider (it may
|
||||
* be overridden), else the preset's; "" when unknown. */
|
||||
const char *cst_ps_base(const cst_agent_config_t *cfg, const char *provider);
|
||||
|
||||
/* The model picker list for cfg's provider: the API's ids (the cache while
|
||||
* it is fresh, else a fetch; refresh always fetches) followed by the
|
||||
* built-in names it did not list. *api_rc gets the fetch result (count,
|
||||
* CST_MODELS_AUTH, -1 with err) or the cached count. Returns the count. */
|
||||
int cst_ps_models(const cst_agent_config_t *cfg, int refresh,
|
||||
cst_ps_model_t *out, int max, int *api_rc, char *err,
|
||||
size_t err_sz);
|
||||
|
||||
/* Checks key against /models and saves it: CST_MODELS_AUTH (err set), or
|
||||
* the CST_PS_* flags. When ids is given it gets the fetched list and *nids
|
||||
* the raw fetch result. */
|
||||
int cst_ps_verify_save(const char *provider, const char *api_base,
|
||||
const char *key, char ids[][128], int max, int *nids,
|
||||
char *err, size_t err_sz);
|
||||
|
||||
/* Point cfg at provider p with key: base URL, the remembered model (else
|
||||
* the preset's), settings saved. */
|
||||
void cst_ps_apply_provider(cst_agent_config_t *cfg, const cst_provider_t *p,
|
||||
const char *key);
|
||||
|
||||
/* The whole switch without a prompt: key NULL/"" uses the saved or env
|
||||
* key (else CST_PS_NEED_KEY); a given key is verified and saved first. A
|
||||
* preset with no model takes the first one the API lists. The CST_PS_*
|
||||
* flags, or CST_PS_UNKNOWN / CST_PS_NEED_KEY / CST_MODELS_AUTH. */
|
||||
int cst_ps_switch_provider(cst_agent_config_t *cfg, const char *name,
|
||||
const char *key, char *err, size_t err_sz);
|
||||
|
||||
/* Replace the current provider's key: verified, saved, put in cfg. Same
|
||||
* results as cst_ps_verify_save. */
|
||||
int cst_ps_set_key(cst_agent_config_t *cfg, const char *key, char *err,
|
||||
size_t err_sz);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user