TUI keys: register both CSI and SS3 forms of the cursor/Home/End keys and
the xterm modifier sequences when terminfo lacks them, so an arrow sent in
the "other" form no longer turns into Esc + a typed letter. Up/Down move by
visual (soft-wrapped) row, and the draft survives a trip through history.
scripts/tui_keys drives the TUI in a pty to check all of this.
Images: text inside a multimodal content array is now a {"type":"text"}
part; DeepSeek rejected the bare string with HTTP 422. deepseek-flash
(and its deepseek-chat / deepseek-reasoner aliases) read images, so the
registry marks them vision; deepseek-v4-pro stays text only.
CI: models.c lost _DEFAULT_SOURCE in 0.7.0 and gmtime_r broke the musl
build; tests sleep with poll() instead of usleep for the same reason.
45 lines
1.1 KiB
C
45 lines
1.1 KiB
C
#ifndef _DEFAULT_SOURCE
|
|
#define _DEFAULT_SOURCE
|
|
#endif
|
|
|
|
#include "cst_agent.h"
|
|
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
/* Provider and model data live in model_registry.c (cst_models.h). */
|
|
|
|
int cst_price_is_peak(time_t when) {
|
|
time_t bj = when + 8 * 3600;
|
|
struct tm tmv;
|
|
#ifdef _WIN32
|
|
gmtime_s(&tmv, &bj);
|
|
#else
|
|
gmtime_r(&bj, &tmv);
|
|
#endif
|
|
if (tmv.tm_wday == 0 || tmv.tm_wday == 6)
|
|
return 0;
|
|
return (tmv.tm_hour >= 9 && tmv.tm_hour < 12) ||
|
|
(tmv.tm_hour >= 14 && tmv.tm_hour < 18);
|
|
}
|
|
|
|
double cst_price_cost(const cst_price_t *p, long miss, long hit, long write,
|
|
long out, time_t when) {
|
|
if (!p)
|
|
return 0;
|
|
double c = (miss * p->miss + hit * p->hit + write * p->write +
|
|
out * p->out) / 1e6;
|
|
if (p->offpeak_half && !cst_price_is_peak(when))
|
|
c /= 2;
|
|
return c;
|
|
}
|
|
|
|
int cst_effort_valid(const char *effort) {
|
|
static const char *const ok[] = {"low", "medium", "high", "max"};
|
|
for (size_t i = 0; effort && i < sizeof(ok) / sizeof(ok[0]); i++) {
|
|
if (strcmp(effort, ok[i]) == 0)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|