entroly-openclaw 1.0.60 → 1.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -6
- package/engine.js +130 -2
- package/openclaw.plugin.json +9 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,10 +68,22 @@ local JSONL bridge before inviting users onto the Gateway. The plugin requires
|
|
|
68
68
|
the Entroly 1.0.57 bridge v2 protocol; doctor reports an actionable upgrade
|
|
69
69
|
instead of accepting an older, incompatible Python installation.
|
|
70
70
|
|
|
71
|
-
OpenClaw's resolved prompt token budget is authoritative.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
OpenClaw's resolved prompt token budget is authoritative. When an older or
|
|
72
|
+
degraded host cannot provide one, Entroly automatically resolves a conservative
|
|
73
|
+
input ceiling from its model registry. Only `verified`, operator-supplied
|
|
74
|
+
`user`, or explicitly `discovered` metadata is accepted; announced and unknown
|
|
75
|
+
records are rejected. The receipt records the model id, trust state, registry
|
|
76
|
+
digest, native window, output reserve, safety reserve, and source.
|
|
77
|
+
|
|
78
|
+
Context-budget discovery is local and enabled by default. It does not enable
|
|
79
|
+
remote provider discovery or send credentials anywhere. Local Ollama/LM Studio
|
|
80
|
+
and remote OpenRouter discovery remain separate operator opt-ins through
|
|
81
|
+
Entroly's model-registry environment controls. Disable this fallback with
|
|
82
|
+
`autoDiscoverContextBudget: false`.
|
|
83
|
+
|
|
84
|
+
For a custom model that neither OpenClaw nor trusted registry metadata can
|
|
85
|
+
resolve, configure the model in OpenClaw, provide an `ENTROLY_MODEL_REGISTRY`
|
|
86
|
+
override, or set an explicit last-resort fallback:
|
|
75
87
|
|
|
76
88
|
```json5
|
|
77
89
|
{
|
|
@@ -83,8 +95,10 @@ set an explicit operator-approved fallback:
|
|
|
83
95
|
}
|
|
84
96
|
```
|
|
85
97
|
|
|
86
|
-
Without
|
|
87
|
-
actionable warning instead of risking a provider overflow.
|
|
98
|
+
Without any trusted budget, Entroly returns the exact original context with an
|
|
99
|
+
actionable warning instead of risking a provider overflow. Explicit OpenClaw
|
|
100
|
+
budgets always win, followed by the operator's `fallbackTokenBudget`; automatic
|
|
101
|
+
registry discovery is used only when neither is available.
|
|
88
102
|
|
|
89
103
|
## Reproduce the evidence-pinning control
|
|
90
104
|
|
package/engine.js
CHANGED
|
@@ -42,6 +42,9 @@ function statusSnapshot(status) {
|
|
|
42
42
|
"tokens_saved",
|
|
43
43
|
"evidence_pinned",
|
|
44
44
|
"evidence_pin_blocked",
|
|
45
|
+
"context_window",
|
|
46
|
+
"context_output_reserve",
|
|
47
|
+
"context_safety_tokens",
|
|
45
48
|
];
|
|
46
49
|
const booleanFields = ["changed", "provider_independent"];
|
|
47
50
|
const stringFields = [
|
|
@@ -49,6 +52,9 @@ function statusSnapshot(status) {
|
|
|
49
52
|
"receipt_id",
|
|
50
53
|
"provider_mode",
|
|
51
54
|
"budget_source",
|
|
55
|
+
"context_discovery_status",
|
|
56
|
+
"context_discovery_trust",
|
|
57
|
+
"context_discovery_model",
|
|
52
58
|
"model",
|
|
53
59
|
"provider_hint",
|
|
54
60
|
"assembly_strategy",
|
|
@@ -127,6 +133,7 @@ function resolveAssemblyRuntime({ tokenBudget, model, runtimeSettings, fallbackT
|
|
|
127
133
|
prompt_token_budget: runtimeBudget ?? null,
|
|
128
134
|
max_output_tokens: positiveInteger(runtimeSettings?.limits?.maxOutputTokens) ?? null,
|
|
129
135
|
},
|
|
136
|
+
context_discovery: null,
|
|
130
137
|
};
|
|
131
138
|
|
|
132
139
|
if (explicitBudget !== undefined) {
|
|
@@ -161,6 +168,80 @@ function resolveAssemblyRuntime({ tokenBudget, model, runtimeSettings, fallbackT
|
|
|
161
168
|
};
|
|
162
169
|
}
|
|
163
170
|
|
|
171
|
+
function validateContextBudgetDiscovery(result) {
|
|
172
|
+
if (!result || result.ok !== true || result.schema_version !== ENTROLY_BRIDGE_SCHEMA) {
|
|
173
|
+
throw new Error("Entroly bridge returned an invalid context-discovery response");
|
|
174
|
+
}
|
|
175
|
+
if (result.status === "unavailable") {
|
|
176
|
+
return {
|
|
177
|
+
available: false,
|
|
178
|
+
metadata: {
|
|
179
|
+
status: "unavailable",
|
|
180
|
+
trust: boundedString(result.trust, 32),
|
|
181
|
+
model_id: boundedString(result.model, 256),
|
|
182
|
+
exact: null,
|
|
183
|
+
context_window: null,
|
|
184
|
+
output_reserve_tokens: null,
|
|
185
|
+
safety_tokens: null,
|
|
186
|
+
registry_digest: boundedString(result.registry_digest, 64),
|
|
187
|
+
source: null,
|
|
188
|
+
},
|
|
189
|
+
warning: safeDiagnostic(result.warning ?? "trusted model metadata was unavailable"),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (result.status !== "resolved" || result.budget_source !== "entroly_model_registry") {
|
|
193
|
+
throw new Error("Entroly bridge returned an unknown context-discovery state");
|
|
194
|
+
}
|
|
195
|
+
const tokenBudget = positiveInteger(result.token_budget);
|
|
196
|
+
const contextWindow = positiveInteger(result.context_window);
|
|
197
|
+
const outputReserve = positiveInteger(result.output_reserve_tokens);
|
|
198
|
+
const safetyTokens = positiveInteger(result.safety_tokens);
|
|
199
|
+
const trust = boundedString(result.trust, 32);
|
|
200
|
+
const modelId = boundedString(result.model_id, 256);
|
|
201
|
+
const registryDigest = boundedString(result.registry_digest, 64);
|
|
202
|
+
if (
|
|
203
|
+
tokenBudget === undefined ||
|
|
204
|
+
tokenBudget < 1024 ||
|
|
205
|
+
contextWindow === undefined ||
|
|
206
|
+
outputReserve === undefined ||
|
|
207
|
+
safetyTokens === undefined ||
|
|
208
|
+
!["verified", "user", "discovered"].includes(trust) ||
|
|
209
|
+
modelId === null ||
|
|
210
|
+
registryDigest === null ||
|
|
211
|
+
!/^[0-9a-f]{64}$/.test(registryDigest) ||
|
|
212
|
+
tokenBudget + outputReserve + safetyTokens > contextWindow
|
|
213
|
+
) {
|
|
214
|
+
throw new Error("Entroly bridge returned unsafe context-discovery limits");
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
available: true,
|
|
218
|
+
tokenBudget,
|
|
219
|
+
metadata: {
|
|
220
|
+
status: "resolved",
|
|
221
|
+
trust,
|
|
222
|
+
model_id: modelId,
|
|
223
|
+
exact: result.exact === true,
|
|
224
|
+
context_window: contextWindow,
|
|
225
|
+
output_reserve_tokens: outputReserve,
|
|
226
|
+
safety_tokens: safetyTokens,
|
|
227
|
+
registry_digest: registryDigest,
|
|
228
|
+
source: boundedString(result.source, 512),
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function applyDiscoveredBudget(runtime, discovery) {
|
|
234
|
+
return {
|
|
235
|
+
...runtime,
|
|
236
|
+
tokenBudget: discovery.tokenBudget,
|
|
237
|
+
budgetSource: "entroly_model_registry",
|
|
238
|
+
runtimeMetadata: {
|
|
239
|
+
...runtime.runtimeMetadata,
|
|
240
|
+
context_discovery: discovery.metadata,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
164
245
|
function canonicalJson(value) {
|
|
165
246
|
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
166
247
|
if (value && typeof value === "object") {
|
|
@@ -295,6 +376,14 @@ export function formatEntrolyStatus(status) {
|
|
|
295
376
|
`Estimated reduction: ${reduction}% (${saved.toLocaleString()} tokens)`,
|
|
296
377
|
`Changed: ${status.changed ? "yes" : "no"}`,
|
|
297
378
|
];
|
|
379
|
+
if (status.context_discovery_status === "resolved") {
|
|
380
|
+
lines.splice(
|
|
381
|
+
3,
|
|
382
|
+
0,
|
|
383
|
+
`Context discovery: ${status.context_discovery_trust ?? "trusted"} metadata for ${status.context_discovery_model ?? "active model"}`,
|
|
384
|
+
`Discovered window: ${(status.context_window ?? 0).toLocaleString()} tokens (${(status.context_output_reserve ?? 0).toLocaleString()} output reserve + ${(status.context_safety_tokens ?? 0).toLocaleString()} safety reserve)`,
|
|
385
|
+
);
|
|
386
|
+
}
|
|
298
387
|
if (status.receipt_id) lines.push(`Receipt: ${boundedString(status.receipt_id, 160)}`);
|
|
299
388
|
if (status.warnings?.length) {
|
|
300
389
|
lines.push(`Warnings: ${status.warnings.map((warning) => safeDiagnostic(warning)).join(" | ")}`);
|
|
@@ -390,12 +479,39 @@ export function createEntrolyContextEngine({
|
|
|
390
479
|
throw error;
|
|
391
480
|
}
|
|
392
481
|
const sourceMessages = messages;
|
|
393
|
-
|
|
482
|
+
let assemblyRuntime = resolveAssemblyRuntime({
|
|
394
483
|
tokenBudget,
|
|
395
484
|
model,
|
|
396
485
|
runtimeSettings,
|
|
397
486
|
fallbackTokenBudget: config.fallbackTokenBudget,
|
|
398
487
|
});
|
|
488
|
+
if (
|
|
489
|
+
assemblyRuntime.tokenBudget === undefined &&
|
|
490
|
+
config.autoDiscoverContextBudget !== false &&
|
|
491
|
+
assemblyRuntime.model
|
|
492
|
+
) {
|
|
493
|
+
try {
|
|
494
|
+
const discovery = validateContextBudgetDiscovery(
|
|
495
|
+
await bridge.request({
|
|
496
|
+
operation: "resolve_context_budget",
|
|
497
|
+
model: assemblyRuntime.model,
|
|
498
|
+
provider_hint: assemblyRuntime.runtimeMetadata.model.provider,
|
|
499
|
+
requested_output_tokens:
|
|
500
|
+
assemblyRuntime.runtimeMetadata.limits.max_output_tokens,
|
|
501
|
+
}),
|
|
502
|
+
);
|
|
503
|
+
if (discovery.available) {
|
|
504
|
+
assemblyRuntime = applyDiscoveredBudget(assemblyRuntime, discovery);
|
|
505
|
+
} else {
|
|
506
|
+
assemblyRuntime.runtimeMetadata.context_discovery = discovery.metadata;
|
|
507
|
+
logger.warn?.(`entroly: context auto-discovery unavailable: ${discovery.warning}`);
|
|
508
|
+
}
|
|
509
|
+
} catch (error) {
|
|
510
|
+
logger.warn?.(
|
|
511
|
+
`entroly: context auto-discovery failed safely: ${safeDiagnostic(error)}`,
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
399
515
|
const preserveLastN = positiveInteger(config.preserveLastN) ?? 4;
|
|
400
516
|
let systemPromptAddition;
|
|
401
517
|
try {
|
|
@@ -419,6 +535,18 @@ export function createEntrolyContextEngine({
|
|
|
419
535
|
provider_mode: PROVIDER_MODE,
|
|
420
536
|
provider_independent: true,
|
|
421
537
|
budget_source: assemblyRuntime.budgetSource,
|
|
538
|
+
context_discovery_status:
|
|
539
|
+
assemblyRuntime.runtimeMetadata.context_discovery?.status,
|
|
540
|
+
context_discovery_trust:
|
|
541
|
+
assemblyRuntime.runtimeMetadata.context_discovery?.trust,
|
|
542
|
+
context_discovery_model:
|
|
543
|
+
assemblyRuntime.runtimeMetadata.context_discovery?.model_id,
|
|
544
|
+
context_window:
|
|
545
|
+
assemblyRuntime.runtimeMetadata.context_discovery?.context_window,
|
|
546
|
+
context_output_reserve:
|
|
547
|
+
assemblyRuntime.runtimeMetadata.context_discovery?.output_reserve_tokens,
|
|
548
|
+
context_safety_tokens:
|
|
549
|
+
assemblyRuntime.runtimeMetadata.context_discovery?.safety_tokens,
|
|
422
550
|
});
|
|
423
551
|
return {
|
|
424
552
|
messages: sourceMessages,
|
|
@@ -430,7 +558,7 @@ export function createEntrolyContextEngine({
|
|
|
430
558
|
if (assemblyRuntime.tokenBudget === undefined) {
|
|
431
559
|
return failOpen(
|
|
432
560
|
new Error(
|
|
433
|
-
"OpenClaw did not provide a positive prompt token budget; configure the model context window or plugins.entries.entroly.config.fallbackTokenBudget",
|
|
561
|
+
"OpenClaw did not provide a positive prompt token budget and Entroly could not resolve trusted model metadata; configure the model context window or plugins.entries.entroly.config.fallbackTokenBudget",
|
|
434
562
|
),
|
|
435
563
|
);
|
|
436
564
|
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"minimum": 1024,
|
|
33
33
|
"maximum": 4000000
|
|
34
34
|
},
|
|
35
|
+
"autoDiscoverContextBudget": {
|
|
36
|
+
"type": "boolean",
|
|
37
|
+
"default": true
|
|
38
|
+
},
|
|
35
39
|
"receiptDir": {
|
|
36
40
|
"type": "string",
|
|
37
41
|
"minLength": 1
|
|
@@ -77,7 +81,11 @@
|
|
|
77
81
|
},
|
|
78
82
|
"fallbackTokenBudget": {
|
|
79
83
|
"label": "Fallback Prompt Token Budget",
|
|
80
|
-
"help": "
|
|
84
|
+
"help": "Operator-approved budget used when OpenClaw cannot provide one. It takes precedence over automatic registry discovery."
|
|
85
|
+
},
|
|
86
|
+
"autoDiscoverContextBudget": {
|
|
87
|
+
"label": "Auto-discover Context Budget",
|
|
88
|
+
"help": "When OpenClaw omits a budget, resolve a conservative input ceiling from verified, user-supplied, or explicitly discovered model metadata. No remote discovery is enabled automatically."
|
|
81
89
|
},
|
|
82
90
|
"receiptDir": {
|
|
83
91
|
"label": "Receipt Directory",
|