aboutsummaryrefslogtreecommitdiff
path: root/modules/core/core-bundle.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-10-23 21:22:30 +0200
committerAgando <roduccomm@gmail.com>2026-10-23 21:22:30 +0200
commit70d7da9dc07f19661a74b19157473de86819e4eb (patch)
tree05fc109dca7a852b457b2035f4993c25a1e1c00e /modules/core/core-bundle.js
parent20afa4faf03d863fa796e9edfbb555d3355d5fa2 (diff)
fix(newos4): world_model_query default path parses again (v4.6.83-84)
_modelDigest() returned JSON.stringify(...) cut at 4000 chars plus '…(digest truncated)'. The tool then did JSON.parse() on it, so the default detail threw 'Unexpected end of JSON input' every single call; detail:'full' worked only because it returned the object untouched. The digest now returns an OBJECT (_modelSnapshot) and shrinks by reducing list lengths, then by dropping whole sections with an explicit 'omitted' list. The string form is generated at the edge and is always valid JSON. Verified: default call -> no error, 13-key snapshot, facts answered; caps 400/1200/4000 all under cap and parseable; the residual floor at cap 200 is identity fields only.
Diffstat (limited to 'modules/core/core-bundle.js')
-rw-r--r--modules/core/core-bundle.js46
1 files changed, 36 insertions, 10 deletions
diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js
index b565365..0b2795a 100644
--- a/modules/core/core-bundle.js
+++ b/modules/core/core-bundle.js
@@ -11557,7 +11557,10 @@ buildSystemPrompt() {
facts: wm._answerQuery(a.question || ''),
version: wm._model.version,
synthesized: wm._model.synthesized,
- snapshot: (a.detail === 'full') ? wm._model : JSON.parse(wm._modelDigest())
+ // v4.6.83: this was JSON.parse(wm._modelDigest()) and the digest was a
+ // string truncated mid-token, so the default path always threw
+ // "Unexpected end of JSON input". The model now hands back an object.
+ snapshot: (a.detail === 'full') ? wm._model : wm._modelSnapshot()
};
return JSON.stringify(wmOut);
}
@@ -19051,30 +19054,53 @@ class WorldModelModule {
// 2026-10-21: ask() used to be a keyword table only, so any real question got
// "Unknown query". Whitelist the fields we are willing to send to a model
// (never the raw model object: it is persisted alongside other VFS data).
- _modelDigest(maxChars) {
+ // v4.6.83: the digest used to be a JSON string cut at 4000 chars with '…(digest truncated)'
+ // glued on. Every caller that tried to parse it got "Unexpected end of JSON input" — the
+ // world_model_query tool did exactly that on its default path. A digest must shrink, never
+ // break: this returns a valid OBJECT and the string form is only produced at the edge.
+ _modelSnapshot(maxChars) {
const m = this._model;
- if (!m) return '';
+ if (!m) return null;
const cap = maxChars || 4000;
- const pick = {
+ const build = (keep) => ({
version: m.version,
synthesized: m.synthesized,
system: m.system,
modules: m.modules,
files: m.files,
- skills: { count: m.skills && m.skills.count, skills: ((m.skills && m.skills.skills) || []).slice(0, 40) },
+ skills: { count: m.skills && m.skills.count, skills: ((m.skills && m.skills.skills) || []).slice(0, keep) },
memory: m.memory,
agents: m.agents,
telemetry: m.telemetry,
projects: m.projects,
- recent: (m.recent || []).slice(0, 20),
+ recent: (m.recent || []).slice(0, Math.min(keep, 20)),
// 2026-10-21: the model only ever exposed a COUNT ("9 recent errors") with no detail,
// so neither the user nor the LLM could say what failed. Carry the last few.
recentErrorSample: this._errorSample ? this._errorSample() : [],
changesSinceLastSnapshot: this._diffSincePrev ? this._diffSincePrev() : []
- };
- let json = JSON.stringify(pick);
- if (json.length > cap) json = json.slice(0, cap) + '…(digest truncated)';
- return json;
+ });
+ // Shrink the lists until the snapshot fits. Truncating the JSON text is what broke it.
+ for (const keep of [40, 20, 10, 5, 3, 1, 0]) {
+ const pick = build(keep);
+ if (JSON.stringify(pick).length <= cap) return pick;
+ }
+ // Last resort: drop whole sections, in order of least value, until it fits. Still a
+ // valid object — a caller can always JSON.parse it and see what was left out.
+ const lean = build(0);
+ lean.truncated = true;
+ lean.omitted = [];
+ for (const key of ['changesSinceLastSnapshot', 'recentErrorSample', 'recent', 'projects',
+ 'skills', 'agents', 'files', 'modules', 'telemetry', 'memory']) {
+ if (JSON.stringify(lean).length <= cap) break;
+ if (key in lean) { delete lean[key]; lean.omitted.push(key); }
+ }
+ return lean;
+ }
+
+ // String form, for prompts. Always valid JSON now.
+ _modelDigest(maxChars) {
+ const snap = this._modelSnapshot(maxChars);
+ return snap ? JSON.stringify(snap) : '';
}
// Last few tool/agent errors with their tool name, for the digest (bounded).