v0.7.0: image input, model registry, prefix-cache savings
Images - vision gate: text-only models get a note instead of image parts and no view_image tool; unknown models retry once without images on HTTP 400 - paste: Ctrl+V and /attach paste read the clipboard (wl-paste, xclip, pngpaste/osascript, Win32 PNG or CF_DIB converted to PNG); pasting image file paths attaches them - MCP image content is stored in the session and sent with the tool result - attach: rel path validation, base64 decode, /retry keeps images Model registry - built-in src/models_builtin.json embedded at build time, merged with <config>/models.json and cached GET /models metadata (context, vision, pricing); most specific rule wins per field - /model labels, /status source, --list-models [provider] Cache and cost - stable request prefix (frozen tools, notes as messages), DeepSeek prefix completion, OpenAI/Anthropic cache hints, /cost and hit rate in the status
This commit is contained in:
+42
-4
@@ -56,6 +56,15 @@ static const cst_tool_def_t TOOLS[] = {
|
||||
{"limit", I, 0, "maximum number of lines"},
|
||||
{"line_numbers", B, 0, "`N|` line prefixes (default true)"}},
|
||||
CST_TP_READ, 1, run_read_file, NULL, NO_DYN},
|
||||
{"view_image",
|
||||
"Show a local image to yourself: PNG, JPEG, GIF, WebP or BMP, checked by "
|
||||
"content. The file is copied into the session store and comes back as an "
|
||||
"image you can actually see (not as text). Use it for screenshots, "
|
||||
"diagrams and UI checks; path resolves like read_file's.",
|
||||
NULL,
|
||||
{{"path", S, 1, "image file path relative to the workspace"},
|
||||
{"detail", S, 0, "low or high (provider hint; default auto)"}},
|
||||
CST_TP_READ, 0, cst_tool_view_image, NULL, NO_DYN},
|
||||
{"run_shell",
|
||||
"Run a non-interactive shell command in the workspace root for builds, "
|
||||
"tests, git and other CLIs (stdin is empty; long runs are killed). "
|
||||
@@ -333,8 +342,8 @@ int cst_tool_active(const cst_agent_config_t *cfg, const cst_tool_def_t *t) {
|
||||
return 1;
|
||||
if (cfg->tool_profile == CST_TOOLS_MINIMAL && !t->minimal)
|
||||
return 0;
|
||||
if ((cfg->plan_mode || cfg->read_only) &&
|
||||
(t->perm == CST_TP_WRITE || t->perm == CST_TP_SHELL))
|
||||
/* plan_mode is enforced when a call runs, so tools[] stays the same */
|
||||
if (cfg->read_only && (t->perm == CST_TP_WRITE || t->perm == CST_TP_SHELL))
|
||||
return 0;
|
||||
if (cfg->depth > 0 && strcmp(t->name, "task") == 0)
|
||||
return 0;
|
||||
@@ -413,16 +422,44 @@ static int is_minimal(const cst_agent_config_t *cfg) {
|
||||
return cfg && cfg->tool_profile == CST_TOOLS_MINIMAL;
|
||||
}
|
||||
|
||||
static int is_external(const cst_tool_def_t *t) {
|
||||
return t->owner && strncmp(t->owner, "builtin:", 8) != 0;
|
||||
}
|
||||
|
||||
static int by_name(const void *x, const void *y) {
|
||||
const cst_tool_def_t *a = *(const cst_tool_def_t *const *)x;
|
||||
const cst_tool_def_t *b = *(const cst_tool_def_t *const *)y;
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
void *cst_tools_schema_cfg(const cst_agent_config_t *cfg) {
|
||||
cJSON *arr = cJSON_CreateArray();
|
||||
if (!arr)
|
||||
return NULL;
|
||||
int legacy = is_minimal(cfg);
|
||||
int n = cst_tool_count();
|
||||
/* Built-ins in registry order, then plugin/MCP tools by name: servers
|
||||
* finish starting in any order, and tools[] is part of the cached prefix. */
|
||||
const cst_tool_def_t **order = calloc((size_t)(n ? n : 1), sizeof(*order));
|
||||
if (!order) {
|
||||
cJSON_Delete(arr);
|
||||
return NULL;
|
||||
}
|
||||
int nb = 0, no = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
const cst_tool_def_t *t = cst_tool_at(i);
|
||||
if (!t || !cst_tool_active(cfg, t))
|
||||
continue;
|
||||
if (t && cst_tool_active(cfg, t) && !is_external(t))
|
||||
order[no++] = t;
|
||||
}
|
||||
nb = no;
|
||||
for (int i = 0; i < n; i++) {
|
||||
const cst_tool_def_t *t = cst_tool_at(i);
|
||||
if (t && cst_tool_active(cfg, t) && is_external(t))
|
||||
order[no++] = t;
|
||||
}
|
||||
qsort(order + nb, (size_t)(no - nb), sizeof(*order), by_name);
|
||||
for (int i = 0; i < no; i++) {
|
||||
const cst_tool_def_t *t = order[i];
|
||||
cJSON *tool = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(tool, "type", "function");
|
||||
cJSON *fn = cJSON_AddObjectToObject(tool, "function");
|
||||
@@ -457,6 +494,7 @@ void *cst_tools_schema_cfg(const cst_agent_config_t *cfg) {
|
||||
}
|
||||
cJSON_AddItemToArray(arr, tool);
|
||||
}
|
||||
free(order);
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user