@stagewhisper/stagewhisper 0.46.0 → 0.47.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/plugin-main.ts +34 -32
- package/src/reasoning.ts +24 -12
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/plugin-main.ts
CHANGED
|
@@ -211,6 +211,27 @@ export default definePluginEntry({
|
|
|
211
211
|
console.log(`\nTesting reasoning with model: ${modelLabel}`);
|
|
212
212
|
console.log("Sending test request to local /v1/responses ...");
|
|
213
213
|
|
|
214
|
+
const testSchema = {
|
|
215
|
+
type: "object",
|
|
216
|
+
properties: {
|
|
217
|
+
signals: {
|
|
218
|
+
type: "array",
|
|
219
|
+
items: {
|
|
220
|
+
type: "object",
|
|
221
|
+
properties: {
|
|
222
|
+
severity: { type: "string", enum: ["green", "orange", "red"] },
|
|
223
|
+
message: { type: "string" },
|
|
224
|
+
},
|
|
225
|
+
required: ["severity", "message"],
|
|
226
|
+
additionalProperties: false,
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
no_signal_reason: { type: "string" },
|
|
230
|
+
},
|
|
231
|
+
required: ["signals", "no_signal_reason"],
|
|
232
|
+
additionalProperties: false,
|
|
233
|
+
};
|
|
234
|
+
|
|
214
235
|
const start = Date.now();
|
|
215
236
|
try {
|
|
216
237
|
const result = await callOpenResponses(api, {
|
|
@@ -219,34 +240,14 @@ export default definePluginEntry({
|
|
|
219
240
|
transcript: "Candidate: I think we should use Redis for caching.",
|
|
220
241
|
playbook_guidance: "Evaluate technical decisions",
|
|
221
242
|
}),
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
type: "array",
|
|
231
|
-
items: {
|
|
232
|
-
type: "object",
|
|
233
|
-
properties: {
|
|
234
|
-
severity: { type: "string", enum: ["green", "orange", "red"] },
|
|
235
|
-
message: { type: "string" },
|
|
236
|
-
},
|
|
237
|
-
required: ["severity", "message"],
|
|
238
|
-
additionalProperties: false,
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
no_signal_reason: { type: "string" },
|
|
242
|
-
},
|
|
243
|
-
required: ["signals", "no_signal_reason"],
|
|
244
|
-
additionalProperties: false,
|
|
245
|
-
},
|
|
246
|
-
strict: true,
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
temperature: 0.2,
|
|
243
|
+
instructions: [
|
|
244
|
+
'You are a structured reasoning engine for the "reasoning_test" task.',
|
|
245
|
+
"You MUST respond with a JSON object conforming to this schema.",
|
|
246
|
+
"Output ONLY valid JSON. No markdown fences, no explanation, no extra text.",
|
|
247
|
+
"",
|
|
248
|
+
"JSON Schema:",
|
|
249
|
+
JSON.stringify(testSchema, null, 2),
|
|
250
|
+
].join("\n"),
|
|
250
251
|
max_output_tokens: 1024,
|
|
251
252
|
});
|
|
252
253
|
|
|
@@ -260,17 +261,18 @@ export default definePluginEntry({
|
|
|
260
261
|
}
|
|
261
262
|
|
|
262
263
|
const output = result.output;
|
|
263
|
-
const
|
|
264
|
+
const msgItem = Array.isArray(output)
|
|
264
265
|
? (output.find((o) => o.type === "message") as Record<string, unknown> | undefined)
|
|
265
266
|
: null;
|
|
266
|
-
const textContent =
|
|
267
|
-
? ((
|
|
267
|
+
const textContent = msgItem
|
|
268
|
+
? ((msgItem.content as Array<Record<string, unknown>>)?.find(
|
|
268
269
|
(c) => c.type === "output_text",
|
|
269
270
|
)?.text as string | undefined)
|
|
270
271
|
: null;
|
|
271
272
|
if (textContent) {
|
|
273
|
+
const cleaned = textContent.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/, "").trim();
|
|
272
274
|
try {
|
|
273
|
-
const parsed = JSON.parse(
|
|
275
|
+
const parsed = JSON.parse(cleaned);
|
|
274
276
|
console.log(" Schema-valid JSON: ✓");
|
|
275
277
|
console.log(` Output: ${JSON.stringify(parsed, null, 2)}`);
|
|
276
278
|
} catch {
|
package/src/reasoning.ts
CHANGED
|
@@ -19,7 +19,6 @@ export async function probeOpenResponses(
|
|
|
19
19
|
model: "openclaw/default",
|
|
20
20
|
input: "Reply with exactly: OK",
|
|
21
21
|
max_output_tokens: 16,
|
|
22
|
-
temperature: 0,
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
const controller = new AbortController();
|
|
@@ -81,6 +80,23 @@ function extractTextOutput(result: OpenResponsesResponseResource): string | null
|
|
|
81
80
|
return null;
|
|
82
81
|
}
|
|
83
82
|
|
|
83
|
+
function buildSchemaInstruction(schema: Record<string, unknown>, purpose: string, systemInstruction?: string): string {
|
|
84
|
+
const parts: string[] = [];
|
|
85
|
+
if (systemInstruction) {
|
|
86
|
+
parts.push(systemInstruction);
|
|
87
|
+
parts.push("");
|
|
88
|
+
}
|
|
89
|
+
parts.push(
|
|
90
|
+
`You are a structured reasoning engine for the "${purpose}" task.`,
|
|
91
|
+
"You MUST respond with a JSON object conforming to this schema.",
|
|
92
|
+
"Output ONLY valid JSON. No markdown fences, no explanation, no extra text.",
|
|
93
|
+
"",
|
|
94
|
+
"JSON Schema:",
|
|
95
|
+
JSON.stringify(schema, null, 2),
|
|
96
|
+
);
|
|
97
|
+
return parts.join("\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
84
100
|
export async function executeReasoningJob(
|
|
85
101
|
api: OpenClawPluginApi,
|
|
86
102
|
job: ReasoningJobEnvelope,
|
|
@@ -109,17 +125,12 @@ export async function executeReasoningJob(
|
|
|
109
125
|
const requestBody: OpenResponsesCreateResponseRequestBody = {
|
|
110
126
|
model,
|
|
111
127
|
input: JSON.stringify(job.payload),
|
|
112
|
-
instructions: (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
schema: job.response_schema,
|
|
118
|
-
strict: true,
|
|
119
|
-
},
|
|
120
|
-
},
|
|
128
|
+
instructions: buildSchemaInstruction(
|
|
129
|
+
job.response_schema,
|
|
130
|
+
job.purpose,
|
|
131
|
+
(job.payload.system_instruction as string) ?? undefined,
|
|
132
|
+
),
|
|
121
133
|
max_output_tokens: 4096,
|
|
122
|
-
temperature: 0.2,
|
|
123
134
|
};
|
|
124
135
|
|
|
125
136
|
const controller = new AbortController();
|
|
@@ -131,8 +142,9 @@ export async function executeReasoningJob(
|
|
|
131
142
|
|
|
132
143
|
let parsed: Record<string, unknown> | null = null;
|
|
133
144
|
if (textOutput) {
|
|
145
|
+
const cleaned = textOutput.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/, "").trim();
|
|
134
146
|
try {
|
|
135
|
-
parsed = JSON.parse(
|
|
147
|
+
parsed = JSON.parse(cleaned) as Record<string, unknown>;
|
|
136
148
|
} catch {
|
|
137
149
|
return {
|
|
138
150
|
job_id: job.job_id,
|