载入中...
搜索中...
未找到
Codec.cpp
浏览该文件的文档.
1#include "agent/Codec.h"
2
3#include <charconv>
4#include <cmath>
5#include <limits>
6#include <stdexcept>
7
8namespace eve::agent {
9namespace {
10struct ParseFailure : std::runtime_error {
11 using std::runtime_error::runtime_error;
12};
13
14const Value::Object& object(const Value& v, std::initializer_list<std::string_view> fields) {
15 const auto* result = v.getIf<Value::Object>();
16 if (!result) throw ParseFailure("Expected object");
17 for (const auto& [key, value] : *result) {
18 bool known = false;
19 for (auto field : fields)
20 if (key == field) known = true;
21 if (!known) throw ParseFailure("Unknown field: " + key);
22 }
23 return *result;
24}
25const Value& required(const Value::Object& o, const char* key) {
26 const auto it = o.find(key);
27 if (it == o.end()) throw ParseFailure(std::string("Missing field: ") + key);
28 return it->second;
29}
30std::string string(const Value& v) {
31 const auto* value = v.getIf<std::string>();
32 if (!value) throw ParseFailure("Expected string");
33 return *value;
34}
35double number(const Value& v) {
36 double result;
37 if (const auto* n = v.getIf<double>())
38 result = *n;
39 else if (const auto* n = v.getIf<std::int64_t>())
40 result = double(*n);
41 else
42 throw ParseFailure("Expected number");
43 if (!std::isfinite(result)) throw ParseFailure("Nonfinite number");
44 return result;
45}
46std::uint64_t unsignedInteger(const Value& v) {
47 if (const auto* n = v.getIf<std::int64_t>()) {
48 if (*n < 0) throw ParseFailure("Expected unsigned integer");
49 return std::uint64_t(*n);
50 }
51 const auto text = string(v);
52 std::uint64_t result = 0;
53 const auto parsed = std::from_chars(text.data(), text.data() + text.size(), result);
54 if (parsed.ec != std::errc{} || parsed.ptr != text.data() + text.size()) throw ParseFailure("Invalid integer");
55 return result;
56}
57std::uint32_t u32(const Value& v) {
58 const auto n = unsignedInteger(v);
59 if (n > std::numeric_limits<std::uint32_t>::max()) throw ParseFailure("Integer overflow");
60 return std::uint32_t(n);
61}
62const Value::Array& array(const Value& v, std::size_t limit) {
63 const auto* a = v.getIf<Value::Array>();
64 if (!a || a->size() > limit) throw ParseFailure("Invalid or oversized array");
65 return *a;
66}
67Observation observation(const Value& v) {
68 const auto& o = object(v, {"features", "legalActions", "coverage", "reward", "outcome", "finding"});
69 Observation result;
70 for (const auto& n : array(required(o, "features"), 1024)) {
71 const auto value = number(n);
72 if (std::abs(value) > 1e6) throw ParseFailure("Feature outside supported range");
73 result.features.push_back(float(value));
74 }
75 for (const auto& n : array(required(o, "legalActions"), 1024)) result.legalActions.push_back(u32(n));
76 if (auto it = o.find("coverage"); it != o.end())
77 for (const auto& key : array(it->second, 64)) result.coverage.push_back(string(key));
78 if (auto it = o.find("reward"); it != o.end()) result.reward = number(it->second);
79 if (auto it = o.find("finding"); it != o.end()) result.finding = string(it->second);
80 if (auto it = o.find("outcome"); it != o.end()) {
81 const auto name = string(it->second);
82 if (name == "running")
83 result.outcome = Outcome::Running;
84 else if (name == "success")
85 result.outcome = Outcome::Success;
86 else if (name == "failure")
87 result.outcome = Outcome::Failure;
88 else
89 throw ParseFailure("Unknown outcome");
90 }
91 return result;
92}
93Value observationValue(const Observation& o) {
94 Value::Array features, actions, coverage;
95 for (auto n : o.features) features.emplace_back(n);
96 for (auto n : o.legalActions) actions.emplace_back(std::int64_t(n));
97 for (const auto& key : o.coverage) coverage.emplace_back(key);
98 return Value::object({{"features", std::move(features)},
99 {"legalActions", std::move(actions)},
100 {"coverage", std::move(coverage)},
101 {"reward", o.reward},
102 {"finding", o.finding},
103 {"outcome", o.outcome == Outcome::Running ? "running"
104 : o.outcome == Outcome::Success ? "success"
105 : "failure"}});
106}
107template <class T, class F>
108Result<T> parse(F&& fn) {
109 try {
110 return Result<T>::success(fn());
111 } catch (const ParseFailure& e) {
112 return Result<T>::failure(Diagnostic::error(DiagnosticCode::ParseError, e.what(), {}, {}, "agent.codec"));
113 }
114}
115} // namespace
116
118 return parse<Config>([&] {
119 const auto& o = object(value, {"featureCount",
120 "actionCount",
121 "population",
122 "generations",
123 "horizon",
124 "elites",
125 "hiddenWidth",
126 "trainingEpochs",
127 "maxFindings",
128 "environmentSeed",
129 "searchSeed",
130 "learningSeed",
131 "dt",
132 "mutationProbability",
133 "randomProbability",
134 "coverageWeight",
135 "failureWeight",
136 "learningRate",
137 "strategy",
138 "backend"});
139 Config c;
140 auto integer = [&](const char* key, std::uint32_t& target) {
141 if (auto it = o.find(key); it != o.end()) target = u32(it->second);
142 };
143 auto seed = [&](const char* key, std::uint64_t& target) {
144 if (auto it = o.find(key); it != o.end()) target = unsignedInteger(it->second);
145 };
146 auto scalar = [&](const char* key, double& target) {
147 if (auto it = o.find(key); it != o.end()) target = number(it->second);
148 };
149 integer("featureCount", c.featureCount);
150 integer("actionCount", c.actionCount);
151 integer("population", c.population);
152 integer("generations", c.generations);
153 integer("horizon", c.horizon);
154 integer("elites", c.elites);
155 integer("hiddenWidth", c.hiddenWidth);
156 integer("trainingEpochs", c.trainingEpochs);
157 integer("maxFindings", c.maxFindings);
158 seed("environmentSeed", c.environmentSeed);
159 seed("searchSeed", c.searchSeed);
160 seed("learningSeed", c.learningSeed);
161 scalar("dt", c.dt);
162 scalar("mutationProbability", c.mutationProbability);
163 scalar("randomProbability", c.randomProbability);
164 scalar("coverageWeight", c.coverageWeight);
165 scalar("failureWeight", c.failureWeight);
166 scalar("learningRate", c.learningRate);
167 if (auto it = o.find("strategy"); it != o.end()) {
168 const auto name = string(it->second);
169 if (name == "random")
170 c.strategy = Strategy::Random;
171 else if (name != "evolution")
172 throw ParseFailure("Unknown strategy");
173 }
174 if (auto it = o.find("backend"); it != o.end()) {
175 const auto name = string(it->second);
176 if (name == "tensor")
177 c.backend = Backend::Tensor;
178 else if (name == "gpu")
179 c.backend = Backend::Gpu;
180 else if (name != "cpu")
181 throw ParseFailure("Unknown backend");
182 }
183 return c;
184 });
185}
187 return parse<Observation>([&] { return observation(value); });
188}
190 auto result = parse<Policy>([&] {
191 const auto& o =
192 object(value, {"schemaId", "schemaVersion", "featureCount", "actionCount", "hiddenWidth", "weights"});
193 Policy p;
194 p.schemaId = string(required(o, "schemaId"));
195 p.schemaVersion = u32(required(o, "schemaVersion"));
196 p.featureCount = u32(required(o, "featureCount"));
197 p.actionCount = u32(required(o, "actionCount"));
198 p.hiddenWidth = u32(required(o, "hiddenWidth"));
199 for (const auto& n : array(required(o, "weights"), 140000)) p.weights.push_back(number(n));
200 return p;
201 });
202 if (!result) return result;
203 auto valid = validatePolicy(result.value());
204 if (!valid) return Result<Policy>::failure(valid.status());
205 return result;
206}
208 return parse<Trace>([&] {
209 const auto& o = object(value, {"schemaId", "schemaVersion", "environmentSeed", "dt", "initial", "steps"});
210 Trace t;
211 t.schemaId = string(required(o, "schemaId"));
212 t.schemaVersion = u32(required(o, "schemaVersion"));
213 if (t.schemaId != "evengine.agent.trace" || t.schemaVersion != 1)
214 throw ParseFailure("Unknown trace schema/version");
215 t.environmentSeed = unsignedInteger(required(o, "environmentSeed"));
216 t.dt = number(required(o, "dt"));
217 t.initial = observation(required(o, "initial"));
218 for (const auto& entry : array(required(o, "steps"), 1024)) {
219 const auto& step = object(entry, {"action", "observation"});
220 t.steps.push_back({u32(required(step, "action")), observation(required(step, "observation"))});
221 }
222 return t;
223 });
224}
227 for (auto w : p.weights) weights.emplace_back(w);
228 return Value::object({{"schemaId", p.schemaId},
229 {"schemaVersion", std::int64_t(p.schemaVersion)},
230 {"featureCount", std::int64_t(p.featureCount)},
231 {"actionCount", std::int64_t(p.actionCount)},
232 {"hiddenWidth", std::int64_t(p.hiddenWidth)},
233 {"weights", std::move(weights)}});
234}
237 for (const auto& s : t.steps)
238 steps.push_back(
239 Value::object({{"action", std::int64_t(s.action)}, {"observation", observationValue(s.observation)}}));
240 return Value::object({{"schemaId", t.schemaId},
241 {"schemaVersion", std::int64_t(t.schemaVersion)},
242 {"environmentSeed", std::to_string(t.environmentSeed)},
243 {"dt", t.dt},
244 {"initial", observationValue(t.initial)},
245 {"steps", std::move(steps)}});
246}
248 Value::Array findings, coverage;
249 for (const auto& t : r.findings) findings.push_back(encodeTrace(t));
250 for (const auto& key : r.coverage) coverage.emplace_back(key);
251 return Value::object({{"schemaId", "evengine.agent.report"},
252 {"schemaVersion", 1},
253 {"policy", encodePolicy(r.policy)},
254 {"best", encodeTrace(r.best)},
255 {"findings", std::move(findings)},
256 {"coverage", std::move(coverage)},
257 {"episodes", std::int64_t(r.episodes)},
258 {"steps", std::int64_t(r.steps)},
259 {"failures", std::int64_t(r.failures)},
260 {"trainingSamples", std::int64_t(r.trainingSamples)},
261 {"bestScore", r.bestScore},
262 {"backend", r.backend},
263 {"trainingBackend", r.trainingBackend}});
264}
265} // namespace eve::agent
LogicalId target
double value
float w
Definition AnimClip.cpp:738
const std::string & s
glm::vec4 p[6]
std::uint32_t key
glm::vec3 n
Definition Grass.cpp:63
double r
float v
std::int32_t second
std::int32_t c
std::string text
bool required
std::string name
bool valid
MeleePoint3 a
Definition MeleeHit.cpp:40
std::vector< std::string > fields
Definition PlayHost.cpp:111
std::vector< ActionSpec > actions
Definition PlayHost.cpp:126
std::uint32_t seed
Definition PointSet.cpp:807
int steps
float t
double number
std::string string
float weights[3]
Json object
int limit
Definition TreeMesh.cpp:164
float step
Definition TreeMesh.cpp:314
std::vector< ImportFinding > findings
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
static Value object(Object value)
Compatibility factory for an object value.
Definition Value.h:114
Value encodePolicy(const Policy &p)
Encode a runner-produced policy into owning versioned data; no references retained.
Definition Codec.cpp:225
Result< Trace > decodeTrace(const Value &value)
Decode version-1 owning replay data; run-time consistency is checked before replay reset.
Definition Codec.cpp:207
Result< Policy > decodePolicy(const Value &value)
Decode and validate version-1 owning policy; unknown keys/versions rejected atomically.
Definition Codec.cpp:189
Result< void > validatePolicy(const Policy &policy)
Validate the complete owning policy before inference/import, with no mutation or callbacks.
Definition Agent.cpp:79
Result< Observation > decodeObservation(const Value &value)
Decode owning observation data, rejecting malformed values; dimensions are checked by run/infer.
Definition Codec.cpp:186
Value encodeReport(const Report &r)
Encode runner-produced report, including policy and replayable evidence, as owning data.
Definition Codec.cpp:247
Value encodeTrace(const Trace &t)
Encode a runner-produced trace into owning versioned data; seeds use lossless decimal strings.
Definition Codec.cpp:235
Result< Config > decodeConfig(const Value &value)
Decode strict script/JSON configuration; unknown keys rejected, no mutations or callbacks.
Definition Codec.cpp:117
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
const EditorValue * field(const EditorValue &value, const char *name)
ModelData parse(std::span< const uint8_t > bytes)
Parse.
SettlementPipeline::Stage fn
Bounded search configuration; seed streams for environment, search and learning are separate.
Definition Agent.h:53
Owning version-1 portable network weights; import validates the entire value before use.
Definition Agent.h:99
std::string schemaId
Definition Agent.h:100
Owning search result; reward, coverage and failures remain separate evidence.
Definition Agent.h:148
In-memory versioned replay evidence, independent of learned model state.
Definition Agent.h:89
std::string schemaId
Definition Agent.h:90