@openclawbrain/cli 0.4.12 → 0.4.13

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.
@@ -403,6 +403,7 @@ export declare function buildGraphLocalActionSet(nodeBlockId: string, neighborBl
403
403
  queryVector: Record<string, number>;
404
404
  }, tau: number, stopBias?: number): GraphLocalActionSet;
405
405
  export declare const STOP_ACTION_ID = "__STOP__";
406
+ export declare function buildStopActionUpdateBlockId(nodeBlockId: string): string;
406
407
  export declare function createDefaultBaselineState(alpha?: number): BaselineStateV1;
407
408
  /**
408
409
  * EMA update: on first observation use the raw outcome; thereafter blend.
@@ -3670,7 +3670,11 @@ export function buildGraphLocalActionSet(nodeBlockId, neighborBlockIds, graph, v
3670
3670
  // TrajectoryStepV1, TrajectoryV1 defined below in PG5 section
3671
3671
  export const STOP_ACTION_ID = "__STOP__";
3672
3672
  const STOP_ACTION = STOP_ACTION_ID;
3673
+ const STOP_ACTION_UPDATE_SEPARATOR = "::";
3673
3674
  const DEFAULT_STOP_BIAS = 0.0;
3675
+ export function buildStopActionUpdateBlockId(nodeBlockId) {
3676
+ return `${nodeBlockId}${STOP_ACTION_UPDATE_SEPARATOR}${STOP_ACTION_ID}`;
3677
+ }
3674
3678
  const DEFAULT_TAU = 1.0;
3675
3679
  const DEFAULT_BASELINE_ALPHA = 0.05;
3676
3680
  const MAX_TRAJECTORY_LENGTH = 20;
@@ -3741,15 +3745,12 @@ export function computeTrajectoryPolicyGradient(trajectory, adjacency, graph, ve
3741
3745
  grad = (1 / tau) * (-prob);
3742
3746
  }
3743
3747
  }
3744
- tailGradient.set(j, (tailGradient.get(j) ?? 0) + grad);
3748
+ const gradientKey = j === STOP_ACTION_ID ? buildStopActionUpdateBlockId(step.nodeBlockId) : j;
3749
+ tailGradient.set(gradientKey, (tailGradient.get(gradientKey) ?? 0) + grad);
3745
3750
  }
3746
3751
  }
3747
3752
  // Weight by advantage and pgScale, accumulate into updates
3748
3753
  for (const [blockId, grad] of tailGradient) {
3749
- // Skip STOP action — it has no learnable weight
3750
- if (blockId === STOP_ACTION_ID) {
3751
- continue;
3752
- }
3753
3754
  const scaledDelta = advantage * grad * pgScale;
3754
3755
  const current = updates.get(blockId);
3755
3756
  if (current === undefined) {
@@ -4587,13 +4588,12 @@ function computeTrajectoryPolicyGradientV2(trajectory, adjacency, graph, vectors
4587
4588
  const grad = neighborId === actionKey
4588
4589
  ? (1 / tau) * (1 - prob)
4589
4590
  : (1 / tau) * (-prob);
4590
- tailGradient.set(neighborId, (tailGradient.get(neighborId) ?? 0) + grad);
4591
+ const gradientKey = neighborId === STOP_ACTION ? buildStopActionUpdateBlockId(step.nodeBlockId) : neighborId;
4592
+ tailGradient.set(gradientKey, (tailGradient.get(gradientKey) ?? 0) + grad);
4591
4593
  }
4592
4594
  }
4593
4595
  // Weight by advantage and pgScale
4594
4596
  for (const [blockId, grad] of tailGradient) {
4595
- if (blockId === STOP_ACTION)
4596
- continue; // don't update virtual STOP
4597
4597
  const delta = roundPolicyGradientValue(advantage * grad * pgScale);
4598
4598
  if (delta === 0)
4599
4599
  continue;
@@ -1,6 +1,7 @@
1
1
  export interface ExtensionCompileInput {
2
2
  activationRoot: string;
3
3
  message: string;
4
+ maxContextChars?: number;
4
5
  sessionId?: string;
5
6
  channel?: string;
6
7
  _serveRouteBreadcrumbs?: {
@@ -38,6 +39,7 @@ export interface ExtensionRegistrationApi {
38
39
 
39
40
  export interface NormalizedPromptBuildEvent {
40
41
  message: string;
42
+ maxContextChars?: number;
41
43
  sessionId?: string;
42
44
  channel?: string;
43
45
  warnings: ExtensionDiagnostic[];
@@ -94,6 +96,7 @@ export function normalizePromptBuildEvent(event: unknown): { ok: true; event: No
94
96
  const warnings: ExtensionDiagnostic[] = [];
95
97
  const sessionId = normalizeOptionalScalarField(event.sessionId, "sessionId", warnings);
96
98
  const channel = normalizeOptionalScalarField(event.channel, "channel", warnings);
99
+ const maxContextChars = normalizeOptionalNonNegativeIntegerField(event.maxContextChars, "maxContextChars", warnings);
97
100
  const promptFallback = extractTextContent(event.prompt);
98
101
  let extractedMessage = promptFallback ?? "";
99
102
 
@@ -125,6 +128,7 @@ export function normalizePromptBuildEvent(event: unknown): { ok: true; event: No
125
128
  ok: true,
126
129
  event: {
127
130
  message: extractedMessage,
131
+ ...(maxContextChars !== undefined ? { maxContextChars } : {}),
128
132
  ...(sessionId !== undefined ? { sessionId } : {}),
129
133
  ...(channel !== undefined ? { channel } : {}),
130
134
  warnings
@@ -170,6 +174,7 @@ export function createBeforePromptBuildHandler(input: {
170
174
  const result = input.compileRuntimeContext({
171
175
  activationRoot: input.activationRoot,
172
176
  message: normalized.event.message,
177
+ ...(normalized.event.maxContextChars !== undefined ? { maxContextChars: normalized.event.maxContextChars } : {}),
173
178
  ...(normalized.event.sessionId !== undefined ? { sessionId: normalized.event.sessionId } : {}),
174
179
  ...(normalized.event.channel !== undefined ? { channel: normalized.event.channel } : {}),
175
180
  ...(input.extensionEntryPath === undefined
@@ -249,6 +254,46 @@ function normalizeOptionalScalarField(
249
254
  return undefined;
250
255
  }
251
256
 
257
+ function normalizeOptionalNonNegativeIntegerField(
258
+ value: unknown,
259
+ fieldName: "maxContextChars",
260
+ warnings: ExtensionDiagnostic[]
261
+ ): number | undefined {
262
+ if (value === undefined || value === null) {
263
+ return undefined;
264
+ }
265
+
266
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
267
+ return value;
268
+ }
269
+
270
+ if (typeof value === "bigint" && value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER)) {
271
+ return Number(value);
272
+ }
273
+
274
+ if (typeof value === "string") {
275
+ const trimmed = value.trim();
276
+ if (trimmed.length === 0) {
277
+ return undefined;
278
+ }
279
+ if (/^\d+$/.test(trimmed)) {
280
+ const parsed = Number(trimmed);
281
+ if (Number.isSafeInteger(parsed)) {
282
+ return parsed;
283
+ }
284
+ }
285
+ }
286
+
287
+ warnings.push({
288
+ key: `runtime-${fieldName}-ignored`,
289
+ message:
290
+ `[openclawbrain] fail-open: ignored unsupported before_prompt_build ${fieldName} ` +
291
+ `(${fieldName}=${describeValue(value)})`
292
+ });
293
+
294
+ return undefined;
295
+ }
296
+
252
297
  function extractPromptMessage(message: unknown): string | undefined {
253
298
  if (typeof message === "string") {
254
299
  return normalizeText(message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclawbrain/cli",
3
- "version": "0.4.12",
3
+ "version": "0.4.13",
4
4
  "description": "OpenClawBrain operator CLI package with install/status helpers, daemon controls, and import/export tooling.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -45,7 +45,7 @@
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "@openclawbrain/compiler": "^0.3.4",
48
+ "@openclawbrain/compiler": "0.3.5",
49
49
  "@openclawbrain/contracts": "^0.3.5",
50
50
  "@openclawbrain/events": "^0.3.4",
51
51
  "@openclawbrain/learner": "^0.3.4",
@@ -62,3 +62,4 @@
62
62
  "test": "node --test dist/test/*.test.js"
63
63
  }
64
64
  }
65
+