Files
tai/taicpp/src/cap/cap_model_catalog.h
T

87 lines
3.4 KiB
C++

#pragma once
// CapModelCatalog: which CAP agents exist on this machine and which models each
// of them offers, so `@agent` and `@agent:model` mentions resolve in one place.
//
// Model discovery protocol (docs/cap.md "Model catalog"):
// 1. `[models] list = [...]` and `default = "..."` in the agent manifest.
// 2. `[models] probe = ["bin", "--cap-models"]` (or `capabilities.models = true`
// for `<binary> --cap-models`): the agent prints a JSON array of ids or
// objects {id|name|model}, or {"models": [...], "default": "..."}, or one id
// per line. Probes are bounded by CAP_MODEL_PROBE_TIMEOUT seconds.
// Every failure lands in the agent's entry (status, error); nothing throws out.
#include <functional>
#include <map>
#include <mutex>
#include <string>
#include <vector>
#include "cap_registry.h"
namespace detz::cap {
inline constexpr double CAP_MODEL_PROBE_TIMEOUT = 5.0; // seconds per probe
inline constexpr size_t CAP_MODEL_PROBE_MAX_BYTES = 1u << 20;
inline constexpr size_t CAP_MODEL_MAX = 500; // models kept per agent
inline constexpr size_t CAP_AGENT_MAX = 64; // agents kept in the catalog
inline constexpr double CAP_CATALOG_TTL = 60.0; // seconds an entry stays cached
struct CapAgentEntry {
std::string name;
std::string status; // ready | no_binary | bad_manifest | no_manifest
std::string error; // why status is not ready
std::string binary;
std::string manifestSource;
std::string binding;
std::vector<std::string> models;
std::string defaultModel;
std::string modelSource; // manifest | probe | manifest+probe | none
std::string modelError; // probe failure, empty when fine
double loadedAt{0};
bool ready() const { return status == "ready"; }
};
struct CapSelection {
bool ok{false};
std::string agent;
std::string model; // empty: the agent's own default
std::string note; // set when the model could not be verified
std::string error; // detailed report when !ok
};
class CapModelCatalog {
public:
// Runs argv, returns stdout; throws std::exception on failure or timeout.
using Prober = std::function<std::string(const std::vector<std::string>& argv, double timeout)>;
explicit CapModelCatalog(CapRegistry registry = CapRegistry(), Prober prober = nullptr);
std::vector<std::string> agentNames() const;
CapAgentEntry entry(const std::string& name);
std::vector<CapAgentEntry> entries();
CapManifest manifest(const std::string& name) const;
// True when the first word of `spec` (before ':') names a catalog agent.
bool isAgent(const std::string& spec) const;
// `agent`, `agent:model`, or a bare model id found on exactly one agent.
CapSelection resolve(const std::string& spec);
// Detailed per-agent listing used by every failure message.
std::string report();
static std::string formatReport(const std::vector<CapAgentEntry>& all);
void invalidate();
private:
static std::string defaultProbe(const std::vector<std::string>& argv, double timeout);
CapAgentEntry load(const std::string& name) const;
void probeInto(CapAgentEntry& e, const CapManifest& m) const;
static std::string match(const CapAgentEntry& e, const std::string& want, std::string& problem);
std::string findName(const std::string& word) const;
CapRegistry registry_;
Prober prober_;
std::mutex mu_;
std::map<std::string, CapAgentEntry> cache_;
};
} // namespace detz::cap