@blockrun/franklin 3.15.75 → 3.15.77
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/agent/context.js +1 -0
- package/dist/agent/llm.d.ts +17 -0
- package/dist/agent/llm.js +30 -0
- package/dist/stats/audit.js +18 -2
- package/package.json +1 -1
package/dist/agent/context.js
CHANGED
|
@@ -27,6 +27,7 @@ When a user asks for a current price, today's news, or any live-world state, **c
|
|
|
27
27
|
|
|
28
28
|
# System
|
|
29
29
|
- All text you output outside of tool use is displayed to the user. Use markdown for formatting.
|
|
30
|
+
- **Markdown tables**: use plain ASCII pipe \`|\` for every column separator, not the box-drawing \`│\` (U+2502). Mixing \`│\` data rows with \`|\` separator rows produces a broken table that no renderer parses correctly. Same rule for the separator: use \`---\`, not \`━━━\` or other Unicode dashes. If you can't draw a clean table in plain ASCII, emit a bullet list instead.
|
|
30
31
|
- Tools are your hands. You MUST use tools to take action — do not describe what you would do without doing it. Never end your turn with a promise of future action — execute it now. Every response should either (a) contain tool calls that make progress, or (b) deliver a final result to the user.
|
|
31
32
|
- You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make ALL independent tool calls in parallel. This is critical for performance. However, if tool calls depend on previous results, run them sequentially — do NOT use placeholders or guess dependent values.
|
|
32
33
|
|
package/dist/agent/llm.d.ts
CHANGED
|
@@ -52,6 +52,23 @@ export interface LLMClientOptions {
|
|
|
52
52
|
chain: Chain;
|
|
53
53
|
debug?: boolean;
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Replace Unicode box-drawing characters with their ASCII equivalents.
|
|
57
|
+
*
|
|
58
|
+
* Models occasionally emit U+2502 (`│`) and U+2500 (`─`) in markdown tables
|
|
59
|
+
* — sometimes mixed with ASCII `|` / `-` in the same table. No markdown
|
|
60
|
+
* renderer parses the mix, and the "table" displays as run-on text. Verified
|
|
61
|
+
* 2026-05-06 in a real session: opus-4.7 emitted a CRCL fundamentals table
|
|
62
|
+
* with `│` data rows and `|` separator, ignoring the system-prompt nudge
|
|
63
|
+
* added in 3.15.76. The unconditional swap fixes the rendering at the
|
|
64
|
+
* streaming boundary so every downstream surface (user terminal, conversation
|
|
65
|
+
* history, audit log) gets the corrected version.
|
|
66
|
+
*
|
|
67
|
+
* Trade: the rare case where a user genuinely wants box-drawing in output
|
|
68
|
+
* (e.g. asking what U+2502 looks like) loses fidelity. Acceptable — that
|
|
69
|
+
* case has no real-world frequency, the broken-tables case has weekly.
|
|
70
|
+
*/
|
|
71
|
+
export declare function sanitizeTableUnicode(s: string): string;
|
|
55
72
|
/**
|
|
56
73
|
* Extract the most human-readable message from an error body.
|
|
57
74
|
* Some gateways wrap provider errors multiple times, e.g.
|
package/dist/agent/llm.js
CHANGED
|
@@ -28,6 +28,27 @@ function parseTimeoutEnv(name) {
|
|
|
28
28
|
const parsed = raw ? Number.parseInt(raw, 10) : NaN;
|
|
29
29
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Replace Unicode box-drawing characters with their ASCII equivalents.
|
|
33
|
+
*
|
|
34
|
+
* Models occasionally emit U+2502 (`│`) and U+2500 (`─`) in markdown tables
|
|
35
|
+
* — sometimes mixed with ASCII `|` / `-` in the same table. No markdown
|
|
36
|
+
* renderer parses the mix, and the "table" displays as run-on text. Verified
|
|
37
|
+
* 2026-05-06 in a real session: opus-4.7 emitted a CRCL fundamentals table
|
|
38
|
+
* with `│` data rows and `|` separator, ignoring the system-prompt nudge
|
|
39
|
+
* added in 3.15.76. The unconditional swap fixes the rendering at the
|
|
40
|
+
* streaming boundary so every downstream surface (user terminal, conversation
|
|
41
|
+
* history, audit log) gets the corrected version.
|
|
42
|
+
*
|
|
43
|
+
* Trade: the rare case where a user genuinely wants box-drawing in output
|
|
44
|
+
* (e.g. asking what U+2502 looks like) loses fidelity. Acceptable — that
|
|
45
|
+
* case has no real-world frequency, the broken-tables case has weekly.
|
|
46
|
+
*/
|
|
47
|
+
export function sanitizeTableUnicode(s) {
|
|
48
|
+
if (!s)
|
|
49
|
+
return s;
|
|
50
|
+
return s.replace(/│/g, '|').replace(/─/g, '-');
|
|
51
|
+
}
|
|
31
52
|
function getModelRequestTimeoutMs() {
|
|
32
53
|
// 180s budget for *time-to-headers* (the gateway flushes SSE headers only
|
|
33
54
|
// once the upstream model emits its first token). Reasoning-class models
|
|
@@ -545,6 +566,15 @@ export class ModelClient {
|
|
|
545
566
|
const appendText = (text) => {
|
|
546
567
|
if (!text)
|
|
547
568
|
return;
|
|
569
|
+
// Sanitize Unicode box-drawing chars to ASCII pipe/dash. 3.15.76's
|
|
570
|
+
// system-prompt nudge asked models not to emit U+2502 / U+2500 in
|
|
571
|
+
// tables — opus-4.7 ignored it 2026-05-06, shipped a CRCL analysis
|
|
572
|
+
// table where data rows used `│` and the separator used `|`. No
|
|
573
|
+
// markdown renderer parses that mix; the table displayed as run-on
|
|
574
|
+
// text. Normalize at the streaming boundary so the user, the model
|
|
575
|
+
// history (next turn the model sees its own corrected output), and
|
|
576
|
+
// the audit log all match.
|
|
577
|
+
text = sanitizeTableUnicode(text);
|
|
548
578
|
currentText += text;
|
|
549
579
|
if (textEmission.mode === 'undecided') {
|
|
550
580
|
const trimmed = currentText.trimStart();
|
package/dist/stats/audit.js
CHANGED
|
@@ -105,6 +105,12 @@ export function readAudit() {
|
|
|
105
105
|
return [];
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Regex: SCREAMING-CASE bracketed label like `[SYSTEM NOTE]`,
|
|
110
|
+
* `[FRANKLIN HARNESS PREFETCH]`, `[GROUNDING CHECK FAILED]`. Used to detect
|
|
111
|
+
* harness-injected text that masks the real user prompt in audit forensics.
|
|
112
|
+
*/
|
|
113
|
+
const SYNTHETIC_LABEL = /\[[A-Z][A-Z _-]+\]/;
|
|
108
114
|
/** Pull the last user message from a Dialogue history, flatten, and strip newlines. */
|
|
109
115
|
export function extractLastUserPrompt(history) {
|
|
110
116
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
@@ -122,9 +128,19 @@ export function extractLastUserPrompt(history) {
|
|
|
122
128
|
// "[FRANKLIN HARNESS PREFETCH] CRCL price..." and 18 showed
|
|
123
129
|
// "[GROUNDING CHECK FAILED] ..." instead of the user's actual question.
|
|
124
130
|
// Skip any message whose first non-whitespace block is a SCREAMING-CASE
|
|
125
|
-
// bracketed label
|
|
126
|
-
if (
|
|
131
|
+
// bracketed label.
|
|
132
|
+
if (new RegExp('^' + SYNTHETIC_LABEL.source).test(cleaned))
|
|
127
133
|
continue;
|
|
134
|
+
// 3.15.76: also strip TRAILING synthetic labels. Newer post-response
|
|
135
|
+
// evaluators append `[SYSTEM NOTE] The user is correcting you. Your
|
|
136
|
+
// previous response was wrong...` to the user's real text within the
|
|
137
|
+
// SAME message — so the message doesn't start with the bracket but the
|
|
138
|
+
// audit field still ends up half-real, half-synthetic. The bracket is
|
|
139
|
+
// preceded by whitespace + at least one real character, so trim from
|
|
140
|
+
// the first such occurrence.
|
|
141
|
+
const trailing = cleaned.match(new RegExp('^(.+?)\\s' + SYNTHETIC_LABEL.source));
|
|
142
|
+
if (trailing && trailing[1].trim())
|
|
143
|
+
return trailing[1].trim();
|
|
128
144
|
return cleaned;
|
|
129
145
|
}
|
|
130
146
|
return undefined;
|
package/package.json
CHANGED