principles-disciple 1.133.0 → 1.134.0
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/dist/core/schema/schema-definitions.js +3 -0
- package/dist/core/trajectory-types.d.ts +5 -0
- package/dist/core/trajectory.d.ts +1 -0
- package/dist/core/trajectory.js +29 -8
- package/dist/hooks/after-tool-call-helpers.d.ts +5 -0
- package/dist/hooks/after-tool-call-helpers.js +64 -0
- package/dist/hooks/llm.d.ts +8 -0
- package/dist/hooks/llm.js +30 -0
- package/dist/hooks/trajectory-evidence.js +6 -2
- package/dist/openclaw-sdk.d.ts +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -49,6 +49,8 @@ export const SCHEMAS = {
|
|
|
49
49
|
empathy_signal_json TEXT NOT NULL,
|
|
50
50
|
blob_ref TEXT,
|
|
51
51
|
raw_excerpt TEXT,
|
|
52
|
+
stop_reason TEXT,
|
|
53
|
+
thinking_blocks_count INTEGER,
|
|
52
54
|
created_at TEXT NOT NULL
|
|
53
55
|
)`,
|
|
54
56
|
indexes: [
|
|
@@ -87,6 +89,7 @@ export const SCHEMAS = {
|
|
|
87
89
|
gfi_before REAL,
|
|
88
90
|
gfi_after REAL,
|
|
89
91
|
params_json TEXT NOT NULL,
|
|
92
|
+
result_preview TEXT,
|
|
90
93
|
created_at TEXT NOT NULL
|
|
91
94
|
)`,
|
|
92
95
|
indexes: [
|
|
@@ -28,6 +28,8 @@ export interface TrajectoryAssistantTurnInput {
|
|
|
28
28
|
sanitizedText: string;
|
|
29
29
|
usageJson: unknown;
|
|
30
30
|
empathySignalJson: unknown;
|
|
31
|
+
stopReason?: string | null;
|
|
32
|
+
thinkingBlocksCount?: number | null;
|
|
31
33
|
createdAt?: string;
|
|
32
34
|
}
|
|
33
35
|
export interface TrajectoryUserTurnInput {
|
|
@@ -50,6 +52,7 @@ export interface TrajectoryToolCallInput {
|
|
|
50
52
|
gfiBefore?: number | null;
|
|
51
53
|
gfiAfter?: number | null;
|
|
52
54
|
paramsJson?: unknown;
|
|
55
|
+
resultPreview?: string | null;
|
|
53
56
|
createdAt?: string;
|
|
54
57
|
}
|
|
55
58
|
export interface TrajectoryPainEventInput {
|
|
@@ -190,6 +193,8 @@ export interface AssistantTurnRecord {
|
|
|
190
193
|
rawText: string;
|
|
191
194
|
sanitizedText: string;
|
|
192
195
|
blobRef: string | null;
|
|
196
|
+
stopReason: string | null;
|
|
197
|
+
thinkingBlocksCount: number | null;
|
|
193
198
|
createdAt: string;
|
|
194
199
|
}
|
|
195
200
|
export interface CorrectionSampleRecord {
|
package/dist/core/trajectory.js
CHANGED
|
@@ -93,9 +93,9 @@ export class TrajectoryDatabase {
|
|
|
93
93
|
const result = this.db.prepare(`
|
|
94
94
|
INSERT INTO assistant_turns (
|
|
95
95
|
session_id, run_id, provider, model, raw_text, sanitized_text, usage_json,
|
|
96
|
-
empathy_signal_json, blob_ref, raw_excerpt, created_at
|
|
97
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
98
|
-
`).run(input.sessionId, input.runId, input.provider, input.model, rawStorage.inlineText, input.sanitizedText, safeJson(input.usageJson), safeJson(input.empathySignalJson), rawStorage.blobRef, rawStorage.excerpt, createdAt);
|
|
96
|
+
empathy_signal_json, blob_ref, raw_excerpt, stop_reason, thinking_blocks_count, created_at
|
|
97
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
98
|
+
`).run(input.sessionId, input.runId, input.provider, input.model, rawStorage.inlineText, input.sanitizedText, safeJson(input.usageJson), safeJson(input.empathySignalJson), rawStorage.blobRef, rawStorage.excerpt, input.stopReason ?? null, input.thinkingBlocksCount ?? null, createdAt);
|
|
99
99
|
return Number(result.lastInsertRowid);
|
|
100
100
|
});
|
|
101
101
|
}
|
|
@@ -120,9 +120,9 @@ export class TrajectoryDatabase {
|
|
|
120
120
|
const result = this.db.prepare(`
|
|
121
121
|
INSERT INTO tool_calls (
|
|
122
122
|
session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message,
|
|
123
|
-
gfi_before, gfi_after, params_json, created_at
|
|
124
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
125
|
-
`).run(input.sessionId, input.toolName, input.outcome, input.durationMs ?? null, input.exitCode ?? null, input.errorType ?? null, input.errorMessage ?? null, input.gfiBefore ?? null, input.gfiAfter ?? null, safeJson(input.paramsJson), createdAt);
|
|
123
|
+
gfi_before, gfi_after, params_json, result_preview, created_at
|
|
124
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
125
|
+
`).run(input.sessionId, input.toolName, input.outcome, input.durationMs ?? null, input.exitCode ?? null, input.errorType ?? null, input.errorMessage ?? null, input.gfiBefore ?? null, input.gfiAfter ?? null, safeJson(input.paramsJson), input.resultPreview ?? null, createdAt);
|
|
126
126
|
return Number(result.lastInsertRowid);
|
|
127
127
|
});
|
|
128
128
|
if (input.outcome === 'success') {
|
|
@@ -548,7 +548,8 @@ export class TrajectoryDatabase {
|
|
|
548
548
|
*/
|
|
549
549
|
listAssistantTurns(sessionId) {
|
|
550
550
|
const rows = this.db.prepare(`
|
|
551
|
-
SELECT id, session_id, run_id, provider, model, raw_text, sanitized_text, blob_ref,
|
|
551
|
+
SELECT id, session_id, run_id, provider, model, raw_text, sanitized_text, blob_ref,
|
|
552
|
+
stop_reason, thinking_blocks_count, created_at
|
|
552
553
|
FROM assistant_turns
|
|
553
554
|
WHERE session_id = ?
|
|
554
555
|
ORDER BY id ASC
|
|
@@ -562,6 +563,8 @@ export class TrajectoryDatabase {
|
|
|
562
563
|
rawText: this.restoreRawText(row.raw_text, row.blob_ref),
|
|
563
564
|
sanitizedText: String(row.sanitized_text ?? ''),
|
|
564
565
|
blobRef: row.blob_ref ? String(row.blob_ref) : null,
|
|
566
|
+
stopReason: row.stop_reason != null ? String(row.stop_reason) : null,
|
|
567
|
+
thinkingBlocksCount: row.thinking_blocks_count != null ? Number(row.thinking_blocks_count) : null,
|
|
565
568
|
createdAt: String(row.created_at),
|
|
566
569
|
}));
|
|
567
570
|
}
|
|
@@ -574,7 +577,7 @@ export class TrajectoryDatabase {
|
|
|
574
577
|
listToolCallsForSession(sessionId) {
|
|
575
578
|
const rows = this.db.prepare(`
|
|
576
579
|
SELECT id, tool_name, outcome, params_json, duration_ms, exit_code, error_type, error_message,
|
|
577
|
-
gfi_before, gfi_after, created_at
|
|
580
|
+
gfi_before, gfi_after, result_preview, created_at
|
|
578
581
|
FROM tool_calls
|
|
579
582
|
WHERE session_id = ?
|
|
580
583
|
ORDER BY id ASC
|
|
@@ -604,6 +607,7 @@ export class TrajectoryDatabase {
|
|
|
604
607
|
errorMessage: row.error_message ? String(row.error_message) : null,
|
|
605
608
|
gfiBefore: row.gfi_before != null ? Number(row.gfi_before) : null,
|
|
606
609
|
gfiAfter: row.gfi_after != null ? Number(row.gfi_after) : null,
|
|
610
|
+
resultPreview: row.result_preview != null ? String(row.result_preview) : null,
|
|
607
611
|
createdAt: String(row.created_at),
|
|
608
612
|
};
|
|
609
613
|
});
|
|
@@ -1085,6 +1089,23 @@ export class TrajectoryDatabase {
|
|
|
1085
1089
|
}
|
|
1086
1090
|
}
|
|
1087
1091
|
}
|
|
1092
|
+
// Trajectory enhancement: add stop_reason, thinking_blocks_count, result_preview
|
|
1093
|
+
const trajectoryEnhancementColumns = [
|
|
1094
|
+
{ table: 'assistant_turns', name: 'stop_reason', type: 'TEXT' },
|
|
1095
|
+
{ table: 'assistant_turns', name: 'thinking_blocks_count', type: 'INTEGER' },
|
|
1096
|
+
{ table: 'tool_calls', name: 'result_preview', type: 'TEXT' },
|
|
1097
|
+
];
|
|
1098
|
+
for (const col of trajectoryEnhancementColumns) {
|
|
1099
|
+
try {
|
|
1100
|
+
this.db.exec(`ALTER TABLE ${col.table} ADD COLUMN ${col.name} ${col.type}`);
|
|
1101
|
+
}
|
|
1102
|
+
catch (err) {
|
|
1103
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1104
|
+
if (!message.includes('duplicate column name') && !message.includes('no column named')) {
|
|
1105
|
+
throw err;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1088
1109
|
// PRI-406: Partial unique index on canonical_pain_id (non-null only) for dedup
|
|
1089
1110
|
this.db.exec(`
|
|
1090
1111
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_pain_events_canonical_pain_id
|
|
@@ -17,6 +17,11 @@ import { type SessionState } from '../core/session-tracker.js';
|
|
|
17
17
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
18
18
|
import type { PluginHookAfterToolCallEvent } from '../openclaw-sdk.js';
|
|
19
19
|
import type { ToolCallOutcome, ToolCallObservation, PainAdmissionDecision } from './after-tool-call-types.js';
|
|
20
|
+
/**
|
|
21
|
+
* Extract a preview string from tool call result for diagnostic evidence.
|
|
22
|
+
* Pure function — no I/O, no side effects. ERR-001 / ERR-014 compliant.
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractToolResultPreview(result: unknown): string | null;
|
|
20
25
|
/**
|
|
21
26
|
* Classify the outcome of a tool call event.
|
|
22
27
|
*
|
|
@@ -25,6 +25,68 @@ import { resolveSourceKind, buildToolFailureObservation } from './raw-observatio
|
|
|
25
25
|
import { evaluateEvidenceTriage } from './triage-adapter.js';
|
|
26
26
|
import { evaluateTriggerController } from '@principles/core/runtime-v2';
|
|
27
27
|
import { buildTrajectoryEvidence } from './trajectory-evidence.js';
|
|
28
|
+
const RESULT_PREVIEW_MAX_LENGTH = 500;
|
|
29
|
+
/**
|
|
30
|
+
* Extract a preview string from tool call result for diagnostic evidence.
|
|
31
|
+
* Pure function — no I/O, no side effects. ERR-001 / ERR-014 compliant.
|
|
32
|
+
*/
|
|
33
|
+
export function extractToolResultPreview(result) {
|
|
34
|
+
if (result === null || result === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
try {
|
|
37
|
+
// String result: truncate directly
|
|
38
|
+
if (typeof result === 'string') {
|
|
39
|
+
return result.length > RESULT_PREVIEW_MAX_LENGTH
|
|
40
|
+
? `${result.slice(0, RESULT_PREVIEW_MAX_LENGTH - 3)}...`
|
|
41
|
+
: result;
|
|
42
|
+
}
|
|
43
|
+
// Object with content array (e.g., Anthropic content blocks)
|
|
44
|
+
if (typeof result === 'object' && !Array.isArray(result)) {
|
|
45
|
+
const obj = result;
|
|
46
|
+
if (Array.isArray(obj.content)) {
|
|
47
|
+
const textParts = [];
|
|
48
|
+
for (const block of obj.content) {
|
|
49
|
+
if (block && typeof block === 'object' && !Array.isArray(block)) {
|
|
50
|
+
const blockObj = block;
|
|
51
|
+
if (blockObj.type === 'text' && typeof blockObj.text === 'string') {
|
|
52
|
+
textParts.push(blockObj.text);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (textParts.length > 0) {
|
|
57
|
+
const joined = textParts.join('\n');
|
|
58
|
+
return joined.length > RESULT_PREVIEW_MAX_LENGTH
|
|
59
|
+
? `${joined.slice(0, RESULT_PREVIEW_MAX_LENGTH - 3)}...`
|
|
60
|
+
: joined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Object without content array: JSON.stringify with depth limiter (ERR-014)
|
|
64
|
+
const serialized = JSON.stringify(obj, (_key, value) => {
|
|
65
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
66
|
+
const keys = Object.keys(value);
|
|
67
|
+
if (keys.length > 10) {
|
|
68
|
+
const truncated = {};
|
|
69
|
+
for (const k of keys.slice(0, 10)) {
|
|
70
|
+
truncated[k] = value[k];
|
|
71
|
+
}
|
|
72
|
+
truncated['__truncated__'] = true;
|
|
73
|
+
return truncated;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}, 2);
|
|
78
|
+
if (serialized && serialized !== '{}') {
|
|
79
|
+
return serialized.length > RESULT_PREVIEW_MAX_LENGTH
|
|
80
|
+
? `${serialized.slice(0, RESULT_PREVIEW_MAX_LENGTH - 3)}...`
|
|
81
|
+
: serialized;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return '[result_preview_extraction_failed]';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
28
90
|
// ── Stage 1: Classify ───────────────────────────────────────────────────────
|
|
29
91
|
/**
|
|
30
92
|
* Classify the outcome of a tool call event.
|
|
@@ -150,6 +212,7 @@ export function handleFrictionTrackingForFailure(sessionId, event, outcome, obse
|
|
|
150
212
|
gfiBefore,
|
|
151
213
|
gfiAfter: updatedState.currentGfi,
|
|
152
214
|
paramsJson: sanitizeToolParamsForEvidence(event.params, workspaceDir),
|
|
215
|
+
resultPreview: extractToolResultPreview(event.result),
|
|
153
216
|
});
|
|
154
217
|
return updatedState;
|
|
155
218
|
}
|
|
@@ -188,6 +251,7 @@ export function handleFrictionTrackingForSuccess(sessionId, event, outcome, obse
|
|
|
188
251
|
gfiBefore,
|
|
189
252
|
gfiAfter: resetState.currentGfi,
|
|
190
253
|
paramsJson: sanitizeToolParamsForEvidence(event.params, workspaceDir),
|
|
254
|
+
resultPreview: extractToolResultPreview(event.result),
|
|
191
255
|
});
|
|
192
256
|
wctx.eventLog.recordToolCall(sessionId, {
|
|
193
257
|
toolName: event.toolName,
|
package/dist/hooks/llm.d.ts
CHANGED
|
@@ -8,6 +8,14 @@ export interface EmpathySignal {
|
|
|
8
8
|
}
|
|
9
9
|
export declare function extractEmpathySignal(text: string): EmpathySignal;
|
|
10
10
|
export declare function isEmpathyAuditPayload(text: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Extract enhanced fields from lastAssistant (complete AssistantMessage) in hook payload.
|
|
13
|
+
* Pure function — no I/O, no side effects. ERR-001 compliant.
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractAssistantEnhancedFields(lastAssistant: unknown): {
|
|
16
|
+
stopReason: string | null;
|
|
17
|
+
thinkingBlocksCount: number | null;
|
|
18
|
+
};
|
|
11
19
|
export declare function handleLlmOutput(event: PluginHookLlmOutputEvent, ctx: PluginHookAgentContext & {
|
|
12
20
|
workspaceDir?: string;
|
|
13
21
|
}): void;
|
package/dist/hooks/llm.js
CHANGED
|
@@ -124,6 +124,33 @@ export function isEmpathyAuditPayload(text) {
|
|
|
124
124
|
return true;
|
|
125
125
|
return false;
|
|
126
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Extract enhanced fields from lastAssistant (complete AssistantMessage) in hook payload.
|
|
129
|
+
* Pure function — no I/O, no side effects. ERR-001 compliant.
|
|
130
|
+
*/
|
|
131
|
+
export function extractAssistantEnhancedFields(lastAssistant) {
|
|
132
|
+
if (!lastAssistant || typeof lastAssistant !== 'object' || Array.isArray(lastAssistant)) {
|
|
133
|
+
return { stopReason: null, thinkingBlocksCount: null };
|
|
134
|
+
}
|
|
135
|
+
const obj = lastAssistant;
|
|
136
|
+
// stopReason: typeof guard
|
|
137
|
+
const stopReason = typeof obj.stopReason === 'string' ? obj.stopReason : null;
|
|
138
|
+
// thinkingBlocksCount: iterate content array, count thinking/redacted_thinking blocks
|
|
139
|
+
let thinkingBlocksCount = null;
|
|
140
|
+
if (Array.isArray(obj.content)) {
|
|
141
|
+
let count = 0;
|
|
142
|
+
for (const block of obj.content) {
|
|
143
|
+
if (block && typeof block === 'object' && !Array.isArray(block)) {
|
|
144
|
+
const blockType = block.type;
|
|
145
|
+
if (blockType === 'thinking' || blockType === 'redacted_thinking') {
|
|
146
|
+
count++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
thinkingBlocksCount = count;
|
|
151
|
+
}
|
|
152
|
+
return { stopReason, thinkingBlocksCount };
|
|
153
|
+
}
|
|
127
154
|
export function handleLlmOutput(event, ctx) {
|
|
128
155
|
if (!ctx.workspaceDir || !ctx.sessionId)
|
|
129
156
|
return;
|
|
@@ -142,6 +169,7 @@ export function handleLlmOutput(event, ctx) {
|
|
|
142
169
|
return;
|
|
143
170
|
const text = event.assistantTexts.join('\n');
|
|
144
171
|
const signal = extractEmpathySignal(text);
|
|
172
|
+
const enhancedFields = extractAssistantEnhancedFields(event.lastAssistant);
|
|
145
173
|
const createdAt = new Date().toISOString();
|
|
146
174
|
let assistantTurnId = null;
|
|
147
175
|
try {
|
|
@@ -154,6 +182,8 @@ export function handleLlmOutput(event, ctx) {
|
|
|
154
182
|
sanitizedText: sanitizeAssistantText(text),
|
|
155
183
|
usageJson: event.usage || {},
|
|
156
184
|
empathySignalJson: signal,
|
|
185
|
+
stopReason: enhancedFields.stopReason,
|
|
186
|
+
thinkingBlocksCount: enhancedFields.thinkingBlocksCount,
|
|
157
187
|
createdAt,
|
|
158
188
|
});
|
|
159
189
|
}
|
|
@@ -41,9 +41,11 @@ export function buildTrajectoryEvidence(wctx, sessionId) {
|
|
|
41
41
|
if (evidence.length >= MAX_EVIDENCE_ENTRIES)
|
|
42
42
|
break;
|
|
43
43
|
const sanitizedNote = sanitizeAssistantText((turn.sanitizedText ?? '').slice(0, MAX_EVIDENCE_NOTE_CHARS));
|
|
44
|
+
// Enhanced: append truncation warning when stop_reason=length
|
|
45
|
+
const truncationWarning = turn.stopReason === 'length' ? ' [TRUNCATED: output cut off by length limit]' : '';
|
|
44
46
|
evidence.push({
|
|
45
47
|
sourceRef: `agent_turn:${turn.createdAt}`,
|
|
46
|
-
note: sanitizedNote,
|
|
48
|
+
note: sanitizedNote + truncationWarning,
|
|
47
49
|
});
|
|
48
50
|
}
|
|
49
51
|
}
|
|
@@ -62,7 +64,9 @@ export function buildTrajectoryEvidence(wctx, sessionId) {
|
|
|
62
64
|
for (const tc of failedToolCalls) {
|
|
63
65
|
if (evidence.length >= MAX_EVIDENCE_ENTRIES)
|
|
64
66
|
break;
|
|
65
|
-
|
|
67
|
+
// Enhanced: append resultPreview when available
|
|
68
|
+
const previewSuffix = tc.resultPreview ? ` | ${tc.resultPreview.slice(0, 200)}` : '';
|
|
69
|
+
const note = `Tool ${tc.toolName} failed: ${tc.errorType ?? 'unknown'} (exitCode: ${tc.exitCode ?? 'N/A'})${previewSuffix}`;
|
|
66
70
|
evidence.push({
|
|
67
71
|
sourceRef: `tool_call_failure:${tc.createdAt}`,
|
|
68
72
|
note: sanitizeAssistantText(note.slice(0, MAX_EVIDENCE_NOTE_CHARS)),
|
package/dist/openclaw-sdk.d.ts
CHANGED
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "principles-disciple",
|
|
3
3
|
"name": "Principles Disciple",
|
|
4
4
|
"description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.134.0",
|
|
6
6
|
"activation": {
|
|
7
7
|
"onCapabilities": [
|
|
8
8
|
"hook"
|