Files
CST-agent/include/cst_util.h
T
WHC 2d1052fd5f 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.
2026-10-09 15:54:53 +08:00

69 lines
2.4 KiB
C

#ifndef CST_UTIL_H
#define CST_UTIL_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
char *buf;
size_t len;
size_t cap;
} cst_buf_t;
int cst_buf_append(cst_buf_t *b, const char *s, size_t n);
int cst_buf_puts(cst_buf_t *b, const char *s);
int cst_buf_printf(cst_buf_t *b, const char *fmt, ...);
void cst_buf_free(cst_buf_t *b);
/* Take ownership of the NUL-terminated buffer (never NULL on success). */
char *cst_buf_steal(cst_buf_t *b);
/* Largest n' <= n that does not split a UTF-8 sequence of s. */
size_t cst_utf8_floor(const char *s, size_t n);
/* Copy s[0..n) replacing invalid UTF-8 with '?'. malloc'd, NUL-terminated. */
char *cst_utf8_sanitize(const char *s, size_t n, size_t *out_len);
int cst_utf8_valid(const char *s, size_t n);
/* Re-chunks a byte stream so no piece ends inside a UTF-8 sequence: the
* incomplete tail (at most 3 bytes) waits in the hold for the next feed. */
typedef struct {
char b[4];
size_t n;
} cst_utf8_hold_t;
/* Returns the complete prefix of hold+s[0..n) (malloc'd, NUL-terminated,
* *out_len may be 0), or NULL on OOM. */
char *cst_utf8_hold_feed(cst_utf8_hold_t *h, const char *s, size_t n,
size_t *out_len);
/* Text files may start with a UTF-8 BOM (Windows editors): its length (0/3),
* and an in-place strip of the NUL-terminated s (*len updated when given). */
size_t cst_bom_len(const char *s, size_t n);
void cst_strip_bom(char *s, size_t *len);
/* Line endings: "\r\n" -> "\n" in place (returns the new length); whether
* every line of s ends in "\r\n" (and at least one does); and a malloc'd
* copy of s with bare "\n" turned into "\r\n" when crlf, its BOM dropped and
* a BOM added when bom. Edits keep a Windows file's style with these. */
size_t cst_crlf_to_lf(char *s, size_t n);
int cst_text_is_crlf(const char *s, size_t n);
char *cst_text_restyle(const char *s, size_t n, int crlf, int bom,
size_t *out_len);
/* fnmatch(3) without FNM_PATHNAME ('*' also crosses '/'): * ? [..] [!..]
* [[:class:]] and backslash escapes over UTF-8 code points. Returns 0 on a
* match. Always case-insensitive on Windows. */
#define CST_FNM_PERIOD 1 /* a leading '.' must be matched literally */
#define CST_FNM_CASEFOLD 2
int cst_fnmatch(const char *pat, const char *str, int flags);
uint64_t cst_fnv1a64(uint64_t h, const void *data, size_t n);
#define CST_FNV_INIT 1469598103934665603ULL
#ifdef __cplusplus
}
#endif
#endif