@geminixiang/mikan 1.0.0-beta.40 → 1.0.0-beta.41
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/CHANGELOG.md +26 -0
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +7 -6
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/components.d.ts +33 -0
- package/dist/adapters/discord/components.d.ts.map +1 -0
- package/dist/adapters/discord/components.js +32 -0
- package/dist/adapters/discord/components.js.map +1 -0
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +16 -6
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/discord/format.d.ts +3 -0
- package/dist/adapters/discord/format.d.ts.map +1 -0
- package/dist/adapters/discord/format.js +86 -0
- package/dist/adapters/discord/format.js.map +1 -0
- package/dist/adapters/markdown-tables.d.ts +37 -0
- package/dist/adapters/markdown-tables.d.ts.map +1 -0
- package/dist/adapters/markdown-tables.js +164 -0
- package/dist/adapters/markdown-tables.js.map +1 -0
- package/dist/adapters/progressive-renderer.d.ts.map +1 -1
- package/dist/adapters/progressive-renderer.js +69 -12
- package/dist/adapters/progressive-renderer.js.map +1 -1
- package/dist/adapters/slack/assistant.d.ts +101 -0
- package/dist/adapters/slack/assistant.d.ts.map +1 -0
- package/dist/adapters/slack/assistant.js +204 -0
- package/dist/adapters/slack/assistant.js.map +1 -0
- package/dist/adapters/slack/blocks.d.ts.map +1 -1
- package/dist/adapters/slack/blocks.js +4 -82
- package/dist/adapters/slack/blocks.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +52 -0
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +161 -5
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
- package/dist/adapters/slack/response-lifecycle.js +86 -15
- package/dist/adapters/slack/response-lifecycle.js.map +1 -1
- package/dist/adapters/slack/stream-limits.d.ts +35 -0
- package/dist/adapters/slack/stream-limits.d.ts.map +1 -0
- package/dist/adapters/slack/stream-limits.js +56 -0
- package/dist/adapters/slack/stream-limits.js.map +1 -0
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +26 -47
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +7 -19
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/types.d.ts +24 -1
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +2 -1
- package/dist/agent.js.map +1 -1
- package/dist/commands/extensions.d.ts +18 -6
- package/dist/commands/extensions.d.ts.map +1 -1
- package/dist/commands/extensions.js +55 -8
- package/dist/commands/extensions.js.map +1 -1
- package/dist/env-manifest.d.ts.map +1 -1
- package/dist/env-manifest.js +4 -0
- package/dist/env-manifest.js.map +1 -1
- package/dist/harness/subagent-runner.d.ts +6 -0
- package/dist/harness/subagent-runner.d.ts.map +1 -1
- package/dist/harness/subagent-runner.js +63 -0
- package/dist/harness/subagent-runner.js.map +1 -1
- package/dist/subagent-progress.d.ts +3 -7
- package/dist/subagent-progress.d.ts.map +1 -1
- package/dist/subagent-progress.js +15 -10
- package/dist/subagent-progress.js.map +1 -1
- package/dist/tools/subagent.d.ts +8 -1
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +24 -1
- package/dist/tools/subagent.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/web/admin/portal.js +5 -1
- package/dist/web/admin/portal.js.map +1 -1
- package/package.json +2 -1
- package/dist/adapters/telegram/html.d.ts +0 -3
- package/dist/adapters/telegram/html.d.ts.map +0 -1
- package/dist/adapters/telegram/html.js +0 -101
- package/dist/adapters/telegram/html.js.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type Token from "markdown-it/lib/token.mjs";
|
|
2
|
+
export interface MarkdownTable {
|
|
3
|
+
headers: string[];
|
|
4
|
+
rows: string[][];
|
|
5
|
+
/** Source line span, so a caller can slice the prose around it. */
|
|
6
|
+
startLine: number;
|
|
7
|
+
endLine: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Models sometimes draw the separator row in ASCII-art style (`+---+---+`),
|
|
11
|
+
* which GFM does not recognise. Rewriting those pluses is enough to make the
|
|
12
|
+
* table parse; every other line is left exactly as written.
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizeMarkdownTables(source: string): string;
|
|
15
|
+
export declare function inlinePlainText(tokens: Token[] | null | undefined): string;
|
|
16
|
+
/** Every table in `source`, in document order, with its line span. */
|
|
17
|
+
export declare function extractMarkdownTables(source: string): MarkdownTable[];
|
|
18
|
+
/**
|
|
19
|
+
* Display width in monospace cells, by the East Asian Width convention.
|
|
20
|
+
*
|
|
21
|
+
* Padding by code-point count misaligns a Chinese table so badly that the
|
|
22
|
+
* result reads worse than the raw pipes it replaced, so this is a large
|
|
23
|
+
* improvement — but it is an approximation, not a guarantee. Verified against
|
|
24
|
+
* Discord's rendering: its code-block CJK fallback font is *not* exactly twice
|
|
25
|
+
* the Latin advance, so a column mixing `USB-C Hub` with `無線藍牙耳機` still
|
|
26
|
+
* ends up a little ragged. No amount of space padding fixes that, because the
|
|
27
|
+
* ratio is not an integer; the only exact answers are giving up columns for
|
|
28
|
+
* CJK tables entirely, and that trade was considered and declined — close
|
|
29
|
+
* alignment reads better than no table.
|
|
30
|
+
*/
|
|
31
|
+
export declare function displayWidth(text: string): number;
|
|
32
|
+
/**
|
|
33
|
+
* Render a table as aligned monospace rows, for a platform with no table
|
|
34
|
+
* support of its own. The caller decides whether to fence it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function renderMonospaceTable(table: MarkdownTable): string;
|
|
37
|
+
//# sourceMappingURL=markdown-tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-tables.d.ts","sourceRoot":"","sources":["../../src/adapters/markdown-tables.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,2BAA2B,CAAC;AAkBnD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IACjB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAU9D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAS1E;AAoCD,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAUrE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA6BjD;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAsBjE"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import MarkdownIt from "markdown-it";
|
|
2
|
+
/**
|
|
3
|
+
* Locating GFM tables in a response, as plain data.
|
|
4
|
+
*
|
|
5
|
+
* Every platform needs the same thing from a markdown table and renders it
|
|
6
|
+
* differently: Slack has a native table block, Discord has no table support at
|
|
7
|
+
* all and needs monospace alignment. Only the *finding* is common, so that is
|
|
8
|
+
* what lives here — callers keep their own rendering, and neither has to carry
|
|
9
|
+
* a second markdown parser to get at the cells.
|
|
10
|
+
*
|
|
11
|
+
* Prose is deliberately not re-serialized from tokens anywhere: callers slice
|
|
12
|
+
* it verbatim from the source using the line span reported here, so the
|
|
13
|
+
* platform's own renderer stays responsible for everything that is not a table.
|
|
14
|
+
*/
|
|
15
|
+
const markdown = new MarkdownIt({ html: false });
|
|
16
|
+
/**
|
|
17
|
+
* Models sometimes draw the separator row in ASCII-art style (`+---+---+`),
|
|
18
|
+
* which GFM does not recognise. Rewriting those pluses is enough to make the
|
|
19
|
+
* table parse; every other line is left exactly as written.
|
|
20
|
+
*/
|
|
21
|
+
export function normalizeMarkdownTables(source) {
|
|
22
|
+
return source
|
|
23
|
+
.split("\n")
|
|
24
|
+
.map((line) => {
|
|
25
|
+
const trimmed = line.trim();
|
|
26
|
+
if (!trimmed.startsWith("|") || !trimmed.endsWith("|"))
|
|
27
|
+
return line;
|
|
28
|
+
if (!/^[|+\-:\s]+$/.test(trimmed) || !trimmed.includes("+"))
|
|
29
|
+
return line;
|
|
30
|
+
return line.replaceAll("+", "|");
|
|
31
|
+
})
|
|
32
|
+
.join("\n");
|
|
33
|
+
}
|
|
34
|
+
export function inlinePlainText(tokens) {
|
|
35
|
+
if (!tokens)
|
|
36
|
+
return "";
|
|
37
|
+
let text = "";
|
|
38
|
+
for (const token of tokens) {
|
|
39
|
+
if (token.type === "text" || token.type === "code_inline")
|
|
40
|
+
text += token.content;
|
|
41
|
+
else if (token.type === "softbreak" || token.type === "hardbreak")
|
|
42
|
+
text += "\n";
|
|
43
|
+
else if (token.children)
|
|
44
|
+
text += inlinePlainText(token.children);
|
|
45
|
+
}
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
48
|
+
function parseOne(tokens, index) {
|
|
49
|
+
const open = tokens[index];
|
|
50
|
+
if (open?.type !== "table_open" || !open.map)
|
|
51
|
+
return null;
|
|
52
|
+
const headers = [];
|
|
53
|
+
const rows = [];
|
|
54
|
+
let currentRow = null;
|
|
55
|
+
let inHead = false;
|
|
56
|
+
let i = index + 1;
|
|
57
|
+
for (; i < tokens.length; i++) {
|
|
58
|
+
const token = tokens[i];
|
|
59
|
+
if (token === undefined || token.type === "table_close")
|
|
60
|
+
break;
|
|
61
|
+
if (token.type === "thead_open")
|
|
62
|
+
inHead = true;
|
|
63
|
+
else if (token.type === "thead_close")
|
|
64
|
+
inHead = false;
|
|
65
|
+
else if (token.type === "tr_open")
|
|
66
|
+
currentRow = [];
|
|
67
|
+
else if (token.type === "tr_close" && currentRow) {
|
|
68
|
+
if (inHead)
|
|
69
|
+
headers.push(...currentRow);
|
|
70
|
+
else
|
|
71
|
+
rows.push(currentRow);
|
|
72
|
+
currentRow = null;
|
|
73
|
+
}
|
|
74
|
+
else if (token.type === "inline" && currentRow) {
|
|
75
|
+
currentRow.push(inlinePlainText(token.children) || token.content);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// A header with no body is not a table anyone wants rendered as one.
|
|
79
|
+
if (!headers.length || !rows.length)
|
|
80
|
+
return null;
|
|
81
|
+
return {
|
|
82
|
+
table: { headers, rows, startLine: open.map[0], endLine: tokens[i]?.map?.[1] ?? open.map[1] },
|
|
83
|
+
next: i,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Every table in `source`, in document order, with its line span. */
|
|
87
|
+
export function extractMarkdownTables(source) {
|
|
88
|
+
const tokens = markdown.parse(normalizeMarkdownTables(source), {});
|
|
89
|
+
const tables = [];
|
|
90
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
91
|
+
const found = parseOne(tokens, index);
|
|
92
|
+
if (!found)
|
|
93
|
+
continue;
|
|
94
|
+
tables.push(found.table);
|
|
95
|
+
index = found.next;
|
|
96
|
+
}
|
|
97
|
+
return tables;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Display width in monospace cells, by the East Asian Width convention.
|
|
101
|
+
*
|
|
102
|
+
* Padding by code-point count misaligns a Chinese table so badly that the
|
|
103
|
+
* result reads worse than the raw pipes it replaced, so this is a large
|
|
104
|
+
* improvement — but it is an approximation, not a guarantee. Verified against
|
|
105
|
+
* Discord's rendering: its code-block CJK fallback font is *not* exactly twice
|
|
106
|
+
* the Latin advance, so a column mixing `USB-C Hub` with `無線藍牙耳機` still
|
|
107
|
+
* ends up a little ragged. No amount of space padding fixes that, because the
|
|
108
|
+
* ratio is not an integer; the only exact answers are giving up columns for
|
|
109
|
+
* CJK tables entirely, and that trade was considered and declined — close
|
|
110
|
+
* alignment reads better than no table.
|
|
111
|
+
*/
|
|
112
|
+
export function displayWidth(text) {
|
|
113
|
+
let width = 0;
|
|
114
|
+
for (const char of text) {
|
|
115
|
+
const code = char.codePointAt(0) ?? 0;
|
|
116
|
+
const wide = (code >= 0x1100 && code <= 0x115f) || // Hangul Jamo
|
|
117
|
+
(code >= 0x2e80 && code <= 0xa4cf) || // CJK radicals … Yi
|
|
118
|
+
(code >= 0xac00 && code <= 0xd7a3) || // Hangul syllables
|
|
119
|
+
(code >= 0xf900 && code <= 0xfaff) || // CJK compatibility ideographs
|
|
120
|
+
(code >= 0xfe30 && code <= 0xfe6f) || // CJK compatibility forms
|
|
121
|
+
(code >= 0xff00 && code <= 0xff60) || // full-width forms
|
|
122
|
+
(code >= 0xffe0 && code <= 0xffe6) ||
|
|
123
|
+
(code >= 0x1f300 && code <= 0x1faff) || // emoji
|
|
124
|
+
// Wide symbols scattered through Miscellaneous Symbols and Dingbats.
|
|
125
|
+
// ✅ and ❌ carry most verdict columns a model writes, so getting these
|
|
126
|
+
// wrong drifts the alignment of exactly the tables this exists for.
|
|
127
|
+
code === 0x2705 ||
|
|
128
|
+
(code >= 0x270a && code <= 0x270b) ||
|
|
129
|
+
code === 0x2728 ||
|
|
130
|
+
code === 0x274c ||
|
|
131
|
+
code === 0x274e ||
|
|
132
|
+
(code >= 0x2753 && code <= 0x2755) ||
|
|
133
|
+
code === 0x2757 ||
|
|
134
|
+
(code >= 0x2795 && code <= 0x2797) ||
|
|
135
|
+
code === 0x27b0 ||
|
|
136
|
+
code === 0x27bf;
|
|
137
|
+
width += wide ? 2 : 1;
|
|
138
|
+
}
|
|
139
|
+
return width;
|
|
140
|
+
}
|
|
141
|
+
function pad(text, width) {
|
|
142
|
+
return text + " ".repeat(Math.max(0, width - displayWidth(text)));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Render a table as aligned monospace rows, for a platform with no table
|
|
146
|
+
* support of its own. The caller decides whether to fence it.
|
|
147
|
+
*/
|
|
148
|
+
export function renderMonospaceTable(table) {
|
|
149
|
+
const columns = table.headers.length;
|
|
150
|
+
const rows = table.rows.map((row) =>
|
|
151
|
+
// Ragged rows are common in generated markdown; pad rather than drop them.
|
|
152
|
+
Array.from({ length: columns }, (_, index) => row[index] ?? ""));
|
|
153
|
+
const widths = Array.from({ length: columns }, (_, index) => Math.max(displayWidth(table.headers[index] ?? ""), ...rows.map((row) => displayWidth(row[index] ?? ""))));
|
|
154
|
+
const line = (cells) => cells
|
|
155
|
+
.map((cell, index) => pad(cell, widths[index] ?? 0))
|
|
156
|
+
.join(" ")
|
|
157
|
+
.trimEnd();
|
|
158
|
+
return [
|
|
159
|
+
line(table.headers),
|
|
160
|
+
widths.map((width) => "─".repeat(width)).join(" "),
|
|
161
|
+
...rows.map(line),
|
|
162
|
+
].join("\n");
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=markdown-tables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-tables.js","sourceRoot":"","sources":["../../src/adapters/markdown-tables.ts"],"names":[],"mappings":"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","sourcesContent":["import MarkdownIt from \"markdown-it\";\nimport type Token from \"markdown-it/lib/token.mjs\";\n\n/**\n * Locating GFM tables in a response, as plain data.\n *\n * Every platform needs the same thing from a markdown table and renders it\n * differently: Slack has a native table block, Discord has no table support at\n * all and needs monospace alignment. Only the *finding* is common, so that is\n * what lives here — callers keep their own rendering, and neither has to carry\n * a second markdown parser to get at the cells.\n *\n * Prose is deliberately not re-serialized from tokens anywhere: callers slice\n * it verbatim from the source using the line span reported here, so the\n * platform's own renderer stays responsible for everything that is not a table.\n */\n\nconst markdown = new MarkdownIt({ html: false });\n\nexport interface MarkdownTable {\n headers: string[];\n rows: string[][];\n /** Source line span, so a caller can slice the prose around it. */\n startLine: number;\n endLine: number;\n}\n\n/**\n * Models sometimes draw the separator row in ASCII-art style (`+---+---+`),\n * which GFM does not recognise. Rewriting those pluses is enough to make the\n * table parse; every other line is left exactly as written.\n */\nexport function normalizeMarkdownTables(source: string): string {\n return source\n .split(\"\\n\")\n .map((line) => {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"|\") || !trimmed.endsWith(\"|\")) return line;\n if (!/^[|+\\-:\\s]+$/.test(trimmed) || !trimmed.includes(\"+\")) return line;\n return line.replaceAll(\"+\", \"|\");\n })\n .join(\"\\n\");\n}\n\nexport function inlinePlainText(tokens: Token[] | null | undefined): string {\n if (!tokens) return \"\";\n let text = \"\";\n for (const token of tokens) {\n if (token.type === \"text\" || token.type === \"code_inline\") text += token.content;\n else if (token.type === \"softbreak\" || token.type === \"hardbreak\") text += \"\\n\";\n else if (token.children) text += inlinePlainText(token.children);\n }\n return text;\n}\n\nfunction parseOne(tokens: Token[], index: number): { table: MarkdownTable; next: number } | null {\n const open = tokens[index];\n if (open?.type !== \"table_open\" || !open.map) return null;\n\n const headers: string[] = [];\n const rows: string[][] = [];\n let currentRow: string[] | null = null;\n let inHead = false;\n let i = index + 1;\n\n for (; i < tokens.length; i++) {\n const token = tokens[i];\n if (token === undefined || token.type === \"table_close\") break;\n if (token.type === \"thead_open\") inHead = true;\n else if (token.type === \"thead_close\") inHead = false;\n else if (token.type === \"tr_open\") currentRow = [];\n else if (token.type === \"tr_close\" && currentRow) {\n if (inHead) headers.push(...currentRow);\n else rows.push(currentRow);\n currentRow = null;\n } else if (token.type === \"inline\" && currentRow) {\n currentRow.push(inlinePlainText(token.children) || token.content);\n }\n }\n\n // A header with no body is not a table anyone wants rendered as one.\n if (!headers.length || !rows.length) return null;\n\n return {\n table: { headers, rows, startLine: open.map[0], endLine: tokens[i]?.map?.[1] ?? open.map[1] },\n next: i,\n };\n}\n\n/** Every table in `source`, in document order, with its line span. */\nexport function extractMarkdownTables(source: string): MarkdownTable[] {\n const tokens = markdown.parse(normalizeMarkdownTables(source), {});\n const tables: MarkdownTable[] = [];\n for (let index = 0; index < tokens.length; index++) {\n const found = parseOne(tokens, index);\n if (!found) continue;\n tables.push(found.table);\n index = found.next;\n }\n return tables;\n}\n\n/**\n * Display width in monospace cells, by the East Asian Width convention.\n *\n * Padding by code-point count misaligns a Chinese table so badly that the\n * result reads worse than the raw pipes it replaced, so this is a large\n * improvement — but it is an approximation, not a guarantee. Verified against\n * Discord's rendering: its code-block CJK fallback font is *not* exactly twice\n * the Latin advance, so a column mixing `USB-C Hub` with `無線藍牙耳機` still\n * ends up a little ragged. No amount of space padding fixes that, because the\n * ratio is not an integer; the only exact answers are giving up columns for\n * CJK tables entirely, and that trade was considered and declined — close\n * alignment reads better than no table.\n */\nexport function displayWidth(text: string): number {\n let width = 0;\n for (const char of text) {\n const code = char.codePointAt(0) ?? 0;\n const wide =\n (code >= 0x1100 && code <= 0x115f) || // Hangul Jamo\n (code >= 0x2e80 && code <= 0xa4cf) || // CJK radicals … Yi\n (code >= 0xac00 && code <= 0xd7a3) || // Hangul syllables\n (code >= 0xf900 && code <= 0xfaff) || // CJK compatibility ideographs\n (code >= 0xfe30 && code <= 0xfe6f) || // CJK compatibility forms\n (code >= 0xff00 && code <= 0xff60) || // full-width forms\n (code >= 0xffe0 && code <= 0xffe6) ||\n (code >= 0x1f300 && code <= 0x1faff) || // emoji\n // Wide symbols scattered through Miscellaneous Symbols and Dingbats.\n // ✅ and ❌ carry most verdict columns a model writes, so getting these\n // wrong drifts the alignment of exactly the tables this exists for.\n code === 0x2705 ||\n (code >= 0x270a && code <= 0x270b) ||\n code === 0x2728 ||\n code === 0x274c ||\n code === 0x274e ||\n (code >= 0x2753 && code <= 0x2755) ||\n code === 0x2757 ||\n (code >= 0x2795 && code <= 0x2797) ||\n code === 0x27b0 ||\n code === 0x27bf;\n width += wide ? 2 : 1;\n }\n return width;\n}\n\nfunction pad(text: string, width: number): string {\n return text + \" \".repeat(Math.max(0, width - displayWidth(text)));\n}\n\n/**\n * Render a table as aligned monospace rows, for a platform with no table\n * support of its own. The caller decides whether to fence it.\n */\nexport function renderMonospaceTable(table: MarkdownTable): string {\n const columns = table.headers.length;\n const rows = table.rows.map((row) =>\n // Ragged rows are common in generated markdown; pad rather than drop them.\n Array.from({ length: columns }, (_, index) => row[index] ?? \"\"),\n );\n const widths = Array.from({ length: columns }, (_, index) =>\n Math.max(\n displayWidth(table.headers[index] ?? \"\"),\n ...rows.map((row) => displayWidth(row[index] ?? \"\")),\n ),\n );\n const line = (cells: string[]): string =>\n cells\n .map((cell, index) => pad(cell, widths[index] ?? 0))\n .join(\" \")\n .trimEnd();\n return [\n line(table.headers),\n widths.map((width) => \"─\".repeat(width)).join(\" \"),\n ...rows.map(line),\n ].join(\"\\n\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progressive-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/progressive-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EAEtB,MAAM,eAAe,CAAC;AAQvB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAE9D,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CASvE;
|
|
1
|
+
{"version":3,"file":"progressive-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/progressive-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EAEtB,MAAM,eAAe,CAAC;AAQvB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAE9D,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CASvE;AAoCD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,2BAA2B,GAAG;IAChF,SAAS,EAAE,qBAAqB,CAAC;CAClC,CA+eA"}
|
|
@@ -12,8 +12,19 @@ export function formatMarkdownToolResult(result) {
|
|
|
12
12
|
text += `**Result:**\n\`\`\`\n${result.result}\n\`\`\``;
|
|
13
13
|
return text;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Floor on how often a streaming response redraws.
|
|
17
|
+
*
|
|
18
|
+
* Every platform meters edits per channel — Slack's is the tightest at roughly
|
|
19
|
+
* fifty a minute — and a redraw sends the whole message, so the cost is the
|
|
20
|
+
* number of calls, not their size. One second keeps a long answer inside that
|
|
21
|
+
* budget while still reading as live.
|
|
22
|
+
*
|
|
23
|
+
* This is a floor, not a target: the interval is measured from when the last
|
|
24
|
+
* redraw *finished*, so a platform that slows down under load slows the redraw
|
|
25
|
+
* rate with it instead of queueing work it cannot deliver.
|
|
26
|
+
*/
|
|
27
|
+
const DEFAULT_FLUSH_INTERVAL_MS = 1000;
|
|
17
28
|
export function createProgressiveRenderer(platform) {
|
|
18
29
|
const state = {
|
|
19
30
|
responseId: platform.initialResponseId ?? null,
|
|
@@ -28,12 +39,14 @@ export function createProgressiveRenderer(platform) {
|
|
|
28
39
|
typingInterval: null,
|
|
29
40
|
typingFailureWarned: false,
|
|
30
41
|
extraIds: [],
|
|
42
|
+
continuationIds: [],
|
|
31
43
|
};
|
|
32
44
|
const sanitize = platform.sanitize ?? ((text) => text);
|
|
33
45
|
const reportResponseError = platform.responseErrorContext
|
|
34
46
|
? createChatResponseErrorReporter(() => platform.responseErrorContext(state.responseId))
|
|
35
47
|
: (err, operation, extra) => platform.reportError?.(err, operation, extra ?? {}, state.responseId);
|
|
36
48
|
const now = Date.now;
|
|
49
|
+
const flushIntervalMs = platform.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
37
50
|
function stopTyping() {
|
|
38
51
|
if (state.typingInterval !== null) {
|
|
39
52
|
clearInterval(state.typingInterval);
|
|
@@ -57,13 +70,35 @@ export function createProgressiveRenderer(platform) {
|
|
|
57
70
|
stopTyping();
|
|
58
71
|
state.responseId = await platform.post(text);
|
|
59
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Render `text` as a head message plus however many overflow messages it
|
|
75
|
+
* needs.
|
|
76
|
+
*
|
|
77
|
+
* The overflow is *edited* on later redraws, not re-posted. A streaming
|
|
78
|
+
* response redraws roughly once a second, and re-posting meant every redraw
|
|
79
|
+
* past the length limit dropped another copy of the tail into the channel —
|
|
80
|
+
* a single long answer arrived as one correct message followed by six
|
|
81
|
+
* partial duplicates of itself.
|
|
82
|
+
*
|
|
83
|
+
* Reuse is positional: overflow N always lives in the same message, so the
|
|
84
|
+
* text a reader has already scrolled past does not move. A platform whose
|
|
85
|
+
* `postExtra` reports no id cannot be edited, and falls back to the old
|
|
86
|
+
* behaviour rather than losing the content.
|
|
87
|
+
*/
|
|
60
88
|
async function postSplit(text) {
|
|
61
89
|
const [head = text, ...tail] = split(text);
|
|
62
90
|
await postOrUpdate(head);
|
|
63
|
-
for (const part of tail) {
|
|
91
|
+
for (const [index, part] of tail.entries()) {
|
|
92
|
+
const existing = state.continuationIds[index];
|
|
93
|
+
if (existing !== undefined) {
|
|
94
|
+
await platform.update(String(existing), part);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
64
97
|
if (platform.typing?.stopOnSend)
|
|
65
98
|
stopTyping();
|
|
66
|
-
await platform.postExtra(part, state.responseId);
|
|
99
|
+
const id = await platform.postExtra(part, state.responseId);
|
|
100
|
+
if (id !== undefined && id !== null)
|
|
101
|
+
state.continuationIds[index] = id;
|
|
67
102
|
}
|
|
68
103
|
}
|
|
69
104
|
async function postExtra(text) {
|
|
@@ -97,6 +132,12 @@ export function createProgressiveRenderer(platform) {
|
|
|
97
132
|
catch (err) {
|
|
98
133
|
if (!platform.handleTooLong)
|
|
99
134
|
throw err;
|
|
135
|
+
// Only a length rejection may take the truncating path. Treating every
|
|
136
|
+
// failure as "too long" turned a transient rate limit into a response
|
|
137
|
+
// cut to a few thousand characters under a notice blaming its length,
|
|
138
|
+
// and the retry it triggered kept the limit alive.
|
|
139
|
+
if (platform.isTooLongError && !platform.isTooLongError(err))
|
|
140
|
+
throw err;
|
|
100
141
|
const fallback = await platform.handleTooLong(canonicalText, operation, options, state.responseId, postSplit, () => state.responseId);
|
|
101
142
|
return fallback.text;
|
|
102
143
|
}
|
|
@@ -125,7 +166,10 @@ export function createProgressiveRenderer(platform) {
|
|
|
125
166
|
try {
|
|
126
167
|
if (state.responseId !== null) {
|
|
127
168
|
const delta = prepared.slice(state.streamedSource.length);
|
|
128
|
-
|
|
169
|
+
// Below the threshold the delta stays pending: `state.streamedSource`
|
|
170
|
+
// does not advance, so the next tick recomputes it from the same base
|
|
171
|
+
// and `renderFinal` flushes the remainder before stopping.
|
|
172
|
+
if (delta && delta.length >= (stream.minDeltaChars ?? 0)) {
|
|
129
173
|
await stream.append(state.responseId, delta);
|
|
130
174
|
state.streamedSource = prepared;
|
|
131
175
|
}
|
|
@@ -206,12 +250,15 @@ export function createProgressiveRenderer(platform) {
|
|
|
206
250
|
state.source += sanitized;
|
|
207
251
|
state.pendingChars += sanitized.length;
|
|
208
252
|
const elapsed = now() - state.lastFlushAt;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
253
|
+
// A character threshold must not bypass the interval. When it did, a
|
|
254
|
+
// fast stream redrew every eighty characters — well over a hundred
|
|
255
|
+
// edits for a long answer — and the platform started refusing them.
|
|
256
|
+
if (state.lastFlushAt === 0 || (elapsed >= flushIntervalMs && state.pendingChars > 0)) {
|
|
212
257
|
state.pendingChars = 0;
|
|
213
|
-
state.lastFlushAt = now();
|
|
214
258
|
state.source = await renderDelta(state.source);
|
|
259
|
+
// Stamp on completion: a slow or retrying send pushes the next
|
|
260
|
+
// redraw out by however long it took, so pressure never compounds.
|
|
261
|
+
state.lastFlushAt = now();
|
|
215
262
|
}
|
|
216
263
|
}, () => ({ textLength: delta.length, accumulatedLength: state.source.length }));
|
|
217
264
|
}
|
|
@@ -244,7 +291,7 @@ export function createProgressiveRenderer(platform) {
|
|
|
244
291
|
state.source = await renderFinal(state.source);
|
|
245
292
|
if (state.responseId !== null)
|
|
246
293
|
platform.logBotResponse?.(state.source, state.responseId);
|
|
247
|
-
platform.onFinish?.(state.source, state.responseId);
|
|
294
|
+
await platform.onFinish?.(state.source, state.responseId);
|
|
248
295
|
}, () => ({ finalTextLength: finalText?.length }));
|
|
249
296
|
}
|
|
250
297
|
: undefined,
|
|
@@ -257,7 +304,16 @@ export function createProgressiveRenderer(platform) {
|
|
|
257
304
|
await stopNativeStream();
|
|
258
305
|
if (state.working && !state.source.trim())
|
|
259
306
|
return;
|
|
260
|
-
|
|
307
|
+
// Prepare here too, not only on the delta path. This render is the
|
|
308
|
+
// last word on the response, so skipping it let the canonical
|
|
309
|
+
// replace overwrite prepared text with the raw source — a Discord
|
|
310
|
+
// table converted during streaming reverted to literal pipes the
|
|
311
|
+
// moment the run finished.
|
|
312
|
+
const prepared = platform.prepareSource?.(state.source, state.working) ?? state.source;
|
|
313
|
+
state.source = await renderRaw(provisional(prepared, state.working), "replace", options,
|
|
314
|
+
// The prepared text is what was sent, so it is also what the
|
|
315
|
+
// renderer must remember it sent.
|
|
316
|
+
prepared);
|
|
261
317
|
}, () => ({
|
|
262
318
|
textLength: text.length,
|
|
263
319
|
hadExistingResponse: Boolean(state.responseId),
|
|
@@ -341,7 +397,7 @@ export function createProgressiveRenderer(platform) {
|
|
|
341
397
|
stopTyping();
|
|
342
398
|
if (state.streamActive)
|
|
343
399
|
await stopNativeStream().catch(() => undefined);
|
|
344
|
-
for (const id of state.extraIds) {
|
|
400
|
+
for (const id of [...state.extraIds, ...state.continuationIds]) {
|
|
345
401
|
try {
|
|
346
402
|
await platform.deleteExtra?.(id);
|
|
347
403
|
}
|
|
@@ -350,6 +406,7 @@ export function createProgressiveRenderer(platform) {
|
|
|
350
406
|
}
|
|
351
407
|
}
|
|
352
408
|
state.extraIds = [];
|
|
409
|
+
state.continuationIds = [];
|
|
353
410
|
if (state.responseId !== null) {
|
|
354
411
|
try {
|
|
355
412
|
await platform.delete?.(state.responseId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progressive-renderer.js","sourceRoot":"","sources":["../../src/adapters/progressive-renderer.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ChatToolResult,\n ConversationResponder,\n SubagentProgressSnapshot,\n} from \"../adapter.js\";\nimport * as log from \"../log.js\";\nimport {\n createChatResponseErrorReporter,\n formatToolArgs,\n splitText,\n type ChatResponseErrorOperation,\n} from \"./shared.js\";\nimport type { ProgressiveRendererPlatform } from \"./types.js\";\n\nexport function formatMarkdownToolResult(result: ChatToolResult): string {\n const argsFormatted = formatToolArgs(result.args);\n const duration = (result.durationMs / 1000).toFixed(1);\n let text = `**${result.isError ? \"Error\" : \"Done\"} ${result.toolName}**`;\n if (result.label) text += `: ${result.label}`;\n text += ` (${duration}s)\\n`;\n if (argsFormatted) text += `\\`\\`\\`\\n${argsFormatted}\\n\\`\\`\\`\\n`;\n text += `**Result:**\\n\\`\\`\\`\\n${result.result}\\n\\`\\`\\``;\n return text;\n}\n\ninterface RendererState {\n responseId: string | null;\n source: string;\n working: boolean;\n streamActive: boolean;\n streamUnavailable: boolean;\n streamedSource: string;\n pendingChars: number;\n lastFlushAt: number;\n resetDelta: boolean;\n typingInterval: ReturnType<typeof setInterval> | null;\n typingFailureWarned: boolean;\n extraIds: Array<string | number>;\n}\n\nconst DEFAULT_FLUSH_INTERVAL_MS = 750;\nconst DEFAULT_FLUSH_CHARS = 80;\n\nexport function createProgressiveRenderer(platform: ProgressiveRendererPlatform): {\n responder: ConversationResponder;\n} {\n const state: RendererState = {\n responseId: platform.initialResponseId ?? null,\n source: \"\",\n working: true,\n streamActive: false,\n streamUnavailable: false,\n streamedSource: \"\",\n pendingChars: 0,\n lastFlushAt: 0,\n resetDelta: false,\n typingInterval: null,\n typingFailureWarned: false,\n extraIds: [],\n };\n const sanitize = platform.sanitize ?? ((text: string) => text);\n const reportResponseError = platform.responseErrorContext\n ? createChatResponseErrorReporter(() => platform.responseErrorContext!(state.responseId))\n : (err: unknown, operation: ChatResponseErrorOperation, extra?: Record<string, unknown>) =>\n platform.reportError?.(err, operation, extra ?? {}, state.responseId);\n const now = Date.now;\n\n function stopTyping(): void {\n if (state.typingInterval !== null) {\n clearInterval(state.typingInterval);\n state.typingInterval = null;\n }\n }\n\n function provisional(text: string, working: boolean): string {\n if (platform.formatProvisional) return platform.formatProvisional(text, working);\n return working && platform.workingIndicator ? text + platform.workingIndicator : text;\n }\n\n function split(text: string): string[] {\n return splitText(text, platform.maxLength, platform.formatContinuation);\n }\n\n async function postOrUpdate(text: string): Promise<void> {\n if (state.responseId !== null) {\n await platform.update(state.responseId, text);\n return;\n }\n if (platform.typing?.stopOnSend) stopTyping();\n state.responseId = await platform.post(text);\n }\n\n async function postSplit(text: string): Promise<void> {\n const [head = text, ...tail] = split(text);\n await postOrUpdate(head);\n for (const part of tail) {\n if (platform.typing?.stopOnSend) stopTyping();\n await platform.postExtra(part, state.responseId);\n }\n }\n\n async function postExtra(text: string): Promise<void> {\n if (platform.typing?.stopOnSend) stopTyping();\n await platform.postExtra(text, state.responseId);\n }\n\n async function stopNativeStream(): Promise<void> {\n if (!state.streamActive || state.responseId === null || !platform.stream) return;\n const streamId = state.responseId;\n state.streamActive = false;\n state.streamedSource = \"\";\n await platform.stream.stop(streamId);\n }\n\n async function abandonNativeStream(): Promise<void> {\n if (!platform.stream || state.responseId === null) return;\n const streamId = state.responseId;\n state.streamActive = false;\n state.streamedSource = \"\";\n await platform.stream.stop(streamId).catch(() => undefined);\n if (state.responseId === streamId) state.responseId = null;\n }\n\n async function renderRaw(\n text: string,\n operation: \"render\" | \"replace\",\n options?: { createOverflowLink?: () => string },\n canonicalText = text,\n ): Promise<string> {\n try {\n await postSplit(text);\n return canonicalText;\n } catch (err) {\n if (!platform.handleTooLong) throw err;\n const fallback = await platform.handleTooLong(\n canonicalText,\n operation,\n options,\n state.responseId,\n postSplit,\n () => state.responseId,\n );\n return fallback.text;\n }\n }\n\n async function renderDelta(text: string): Promise<string> {\n if (state.working && !text.trim()) return text;\n const prepared = platform.prepareSource?.(text, state.working) ?? text;\n const stream = platform.stream;\n const display = provisional(prepared, state.working);\n if (!stream || state.streamUnavailable) {\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n if (state.responseId !== null && !state.streamActive) {\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n if (\n state.responseId !== null &&\n state.streamActive &&\n !prepared.startsWith(state.streamedSource)\n ) {\n await abandonNativeStream();\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n\n try {\n if (state.responseId !== null) {\n const delta = prepared.slice(state.streamedSource.length);\n if (delta) {\n await stream.append(state.responseId, delta);\n state.streamedSource = prepared;\n }\n return prepared;\n }\n state.responseId = await stream.start(prepared);\n state.streamActive = true;\n state.streamedSource = prepared;\n return prepared;\n } catch (err) {\n state.streamUnavailable = true;\n log.logWarning(\n \"Native response streaming unavailable; falling back to message updates\",\n err instanceof Error ? err.message : String(err),\n );\n await abandonNativeStream();\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n }\n\n async function renderFinal(text: string): Promise<string> {\n const stream = platform.stream;\n if (stream && state.streamActive && state.responseId !== null) {\n let streamed = false;\n try {\n if (text.startsWith(state.streamedSource)) {\n const delta = text.slice(state.streamedSource.length);\n if (delta) await stream.append(state.responseId, delta);\n await stream.stop(state.responseId);\n streamed = true;\n }\n } catch (err) {\n state.streamUnavailable = true;\n log.logWarning(\n \"Native response streaming unavailable; falling back to message updates\",\n err instanceof Error ? err.message : String(err),\n );\n }\n state.streamActive = false;\n state.streamedSource = \"\";\n if (streamed) {\n if (platform.needsCanonicalRender?.(text)) await renderRaw(text, \"render\");\n return text;\n }\n await abandonNativeStream();\n }\n if (state.responseId !== null || text) return renderRaw(text, \"render\");\n return text;\n }\n\n async function run(\n label: string,\n operation: ChatResponseErrorOperation,\n work: () => Promise<void>,\n extra: () => Record<string, unknown>,\n ): Promise<void> {\n const operationPromise = queueTail.then(work);\n const handled = operationPromise.catch(async (err) => {\n const message = err instanceof Error ? err.message : String(err);\n log.logWarning(`${platform.label} ${label} error`, message);\n reportResponseError(err, operation, extra());\n if (platform.notifySendFailure) {\n try {\n await platform.notifySendFailure(message);\n } catch {\n // A secondary notification must not poison the response queue.\n }\n }\n });\n queueTail = handled.catch(() => undefined);\n return handled;\n }\n\n let queueTail = Promise.resolve();\n\n async function appendDelta(delta: string): Promise<void> {\n await run(\n \"appendResponseDelta\",\n \"respond\",\n async () => {\n if (!delta) return;\n if (state.resetDelta) {\n state.source = \"\";\n state.pendingChars = 0;\n state.resetDelta = false;\n }\n const sanitized = sanitize(delta);\n state.source += sanitized;\n state.pendingChars += sanitized.length;\n const elapsed = now() - state.lastFlushAt;\n if (\n state.lastFlushAt === 0 ||\n state.pendingChars >= DEFAULT_FLUSH_CHARS ||\n elapsed >= DEFAULT_FLUSH_INTERVAL_MS\n ) {\n state.pendingChars = 0;\n state.lastFlushAt = now();\n state.source = await renderDelta(state.source);\n }\n },\n () => ({ textLength: delta.length, accumulatedLength: state.source.length }),\n );\n }\n\n const responder: ConversationResponder = {\n respond: async (text: string) => {\n await run(\n \"respond\",\n \"respond\",\n async () => {\n const sanitized = sanitize(text);\n state.source = state.source ? `${state.source}\\n${sanitized}` : sanitized;\n state.pendingChars = 0;\n state.source = await renderDelta(state.source);\n if (state.responseId !== null && platform.logIntermediateResponses) {\n platform.logBotResponse?.(text, state.responseId);\n }\n },\n () => ({\n phase: state.responseId ? \"update\" : \"initial_post\",\n textLength: text.length,\n accumulatedLength: state.source.length,\n }),\n );\n },\n\n appendResponseDelta: platform.supportsDeltas || platform.stream ? appendDelta : undefined,\n\n finishResponse:\n platform.supportsDeltas || platform.stream\n ? async (finalText?: string) => {\n await run(\n \"finishResponse\",\n \"set_working\",\n async () => {\n if (finalText !== undefined) state.source = sanitize(finalText);\n state.resetDelta = false;\n state.pendingChars = 0;\n stopTyping();\n state.working = false;\n state.source = await renderFinal(state.source);\n if (state.responseId !== null)\n platform.logBotResponse?.(state.source, state.responseId);\n platform.onFinish?.(state.source, state.responseId);\n },\n () => ({ finalTextLength: finalText?.length }),\n );\n }\n : undefined,\n\n replaceResponse: async (text: string, options?: { createOverflowLink?: () => string }) => {\n await run(\n \"replaceResponse\",\n \"replace_response\",\n async () => {\n state.source = sanitize(text);\n state.pendingChars = 0;\n state.resetDelta = true;\n if (state.streamActive) await stopNativeStream();\n if (state.working && !state.source.trim()) return;\n state.source = await renderRaw(\n provisional(state.source, state.working),\n \"replace\",\n options,\n state.source,\n );\n },\n () => ({\n textLength: text.length,\n hadExistingResponse: Boolean(state.responseId),\n }),\n );\n },\n\n replaceSubagentProgress: platform.formatSubagentProgress\n ? async (progress: SubagentProgressSnapshot, finalText?: string) => {\n const dashboard = platform.formatSubagentProgress!(progress);\n await responder.replaceResponse(finalText ? `${dashboard}\\n\\n${finalText}` : dashboard);\n }\n : undefined,\n\n respondDiagnostic: async (text, options = {}) => {\n await run(\n \"respondDiagnostic\",\n \"respond_diagnostic\",\n async () => {\n const ids = platform.postDiagnostic\n ? await platform.postDiagnostic(text, options, state.responseId)\n : await postDefaultDiagnostic(text, options);\n state.extraIds.push(...ids);\n },\n () => ({ textLength: text.length, style: options.style }),\n );\n },\n\n respondToolResult: async (result: ChatToolResult) => {\n await responder.respondDiagnostic(platform.formatToolResult(result));\n },\n\n setTyping: async (isTyping: boolean) => {\n await run(\n \"setTyping\",\n \"set_working\",\n async () => {\n if (platform.setTyping) {\n await platform.setTyping(isTyping, state.responseId);\n return;\n }\n const typing = platform.typing;\n if (!typing) return;\n const onTypingError = (err: unknown): void => {\n if (state.typingFailureWarned) return;\n state.typingFailureWarned = true;\n log.logWarning(\n `${platform.label} sendTyping failed (further occurrences suppressed for this session)`,\n err instanceof Error ? err.message : String(err),\n );\n };\n if (isTyping && state.typingInterval === null) {\n typing.send().catch(onTypingError);\n state.typingInterval = setInterval(() => {\n typing.send().catch(onTypingError);\n }, typing.intervalMs);\n } else if (!isTyping) {\n stopTyping();\n }\n },\n () => ({ working: isTyping }),\n );\n },\n\n setWorking: async (working: boolean) => {\n await run(\n \"setWorking\",\n \"set_working\",\n async () => {\n state.working = working;\n if (!working) stopTyping();\n await platform.onWorkingChanged?.(working, state.responseId);\n if (state.responseId === null || (!platform.workingIndicator && !platform.stream)) return;\n if (working && !state.source.trim()) return;\n\n if (state.streamActive && !working) {\n await stopNativeStream();\n return;\n }\n if (state.responseId !== null) {\n state.source = await renderRaw(\n provisional(state.source, working),\n \"render\",\n undefined,\n state.source,\n );\n }\n },\n () => ({ working }),\n );\n },\n\n uploadFile: async (filePath: string, title?: string) => {\n if (platform.uploadFile) {\n await platform.uploadFile(filePath, title);\n return;\n }\n const note = platform.uploadFallbackNote?.(title ?? filePath);\n if (note === undefined) return;\n await run(\n \"uploadFile\",\n \"respond_diagnostic\",\n () => postExtra(note),\n () => ({ filePath }),\n );\n },\n\n ...(platform.react ? { react: platform.react } : {}),\n\n deleteResponse: async () => {\n await run(\n \"deleteResponse\",\n \"respond\",\n async () => {\n stopTyping();\n if (state.streamActive) await stopNativeStream().catch(() => undefined);\n for (const id of state.extraIds) {\n try {\n await platform.deleteExtra?.(id);\n } catch {\n // Deleting diagnostics is best effort.\n }\n }\n state.extraIds = [];\n if (state.responseId !== null) {\n try {\n await platform.delete?.(state.responseId);\n } catch {\n // Deleting the main response is best effort.\n }\n }\n state.responseId = null;\n state.source = \"\";\n state.streamUnavailable = false;\n state.streamedSource = \"\";\n state.streamActive = false;\n state.resetDelta = false;\n state.working = true;\n },\n () => ({}),\n );\n },\n };\n\n async function postDefaultDiagnostic(\n text: string,\n options: { style?: \"muted\" | \"error\" },\n ): Promise<Array<string | number>> {\n const prefix = options.style === \"error\" ? platform.errorPrefix : \"\";\n const ids: Array<string | number> = [];\n for (const part of split(sanitize(`${prefix}${text}`))) {\n const id = await platform.postExtra(part, state.responseId);\n if (typeof id === \"string\" || typeof id === \"number\") ids.push(id);\n }\n return ids;\n }\n\n return { responder };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"progressive-renderer.js","sourceRoot":"","sources":["../../src/adapters/progressive-renderer.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ChatToolResult,\n ConversationResponder,\n SubagentProgressSnapshot,\n} from \"../adapter.js\";\nimport * as log from \"../log.js\";\nimport {\n createChatResponseErrorReporter,\n formatToolArgs,\n splitText,\n type ChatResponseErrorOperation,\n} from \"./shared.js\";\nimport type { ProgressiveRendererPlatform } from \"./types.js\";\n\nexport function formatMarkdownToolResult(result: ChatToolResult): string {\n const argsFormatted = formatToolArgs(result.args);\n const duration = (result.durationMs / 1000).toFixed(1);\n let text = `**${result.isError ? \"Error\" : \"Done\"} ${result.toolName}**`;\n if (result.label) text += `: ${result.label}`;\n text += ` (${duration}s)\\n`;\n if (argsFormatted) text += `\\`\\`\\`\\n${argsFormatted}\\n\\`\\`\\`\\n`;\n text += `**Result:**\\n\\`\\`\\`\\n${result.result}\\n\\`\\`\\``;\n return text;\n}\n\ninterface RendererState {\n responseId: string | null;\n source: string;\n working: boolean;\n streamActive: boolean;\n streamUnavailable: boolean;\n streamedSource: string;\n pendingChars: number;\n lastFlushAt: number;\n resetDelta: boolean;\n typingInterval: ReturnType<typeof setInterval> | null;\n typingFailureWarned: boolean;\n extraIds: Array<string | number>;\n /**\n * Messages holding the overflow of a response too long for one message,\n * in order. Reused across redraws — see `postSplit`.\n */\n continuationIds: Array<string | number>;\n}\n\n/**\n * Floor on how often a streaming response redraws.\n *\n * Every platform meters edits per channel — Slack's is the tightest at roughly\n * fifty a minute — and a redraw sends the whole message, so the cost is the\n * number of calls, not their size. One second keeps a long answer inside that\n * budget while still reading as live.\n *\n * This is a floor, not a target: the interval is measured from when the last\n * redraw *finished*, so a platform that slows down under load slows the redraw\n * rate with it instead of queueing work it cannot deliver.\n */\nconst DEFAULT_FLUSH_INTERVAL_MS = 1000;\n\nexport function createProgressiveRenderer(platform: ProgressiveRendererPlatform): {\n responder: ConversationResponder;\n} {\n const state: RendererState = {\n responseId: platform.initialResponseId ?? null,\n source: \"\",\n working: true,\n streamActive: false,\n streamUnavailable: false,\n streamedSource: \"\",\n pendingChars: 0,\n lastFlushAt: 0,\n resetDelta: false,\n typingInterval: null,\n typingFailureWarned: false,\n extraIds: [],\n continuationIds: [],\n };\n const sanitize = platform.sanitize ?? ((text: string) => text);\n const reportResponseError = platform.responseErrorContext\n ? createChatResponseErrorReporter(() => platform.responseErrorContext!(state.responseId))\n : (err: unknown, operation: ChatResponseErrorOperation, extra?: Record<string, unknown>) =>\n platform.reportError?.(err, operation, extra ?? {}, state.responseId);\n const now = Date.now;\n const flushIntervalMs = platform.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n\n function stopTyping(): void {\n if (state.typingInterval !== null) {\n clearInterval(state.typingInterval);\n state.typingInterval = null;\n }\n }\n\n function provisional(text: string, working: boolean): string {\n if (platform.formatProvisional) return platform.formatProvisional(text, working);\n return working && platform.workingIndicator ? text + platform.workingIndicator : text;\n }\n\n function split(text: string): string[] {\n return splitText(text, platform.maxLength, platform.formatContinuation);\n }\n\n async function postOrUpdate(text: string): Promise<void> {\n if (state.responseId !== null) {\n await platform.update(state.responseId, text);\n return;\n }\n if (platform.typing?.stopOnSend) stopTyping();\n state.responseId = await platform.post(text);\n }\n\n /**\n * Render `text` as a head message plus however many overflow messages it\n * needs.\n *\n * The overflow is *edited* on later redraws, not re-posted. A streaming\n * response redraws roughly once a second, and re-posting meant every redraw\n * past the length limit dropped another copy of the tail into the channel —\n * a single long answer arrived as one correct message followed by six\n * partial duplicates of itself.\n *\n * Reuse is positional: overflow N always lives in the same message, so the\n * text a reader has already scrolled past does not move. A platform whose\n * `postExtra` reports no id cannot be edited, and falls back to the old\n * behaviour rather than losing the content.\n */\n async function postSplit(text: string): Promise<void> {\n const [head = text, ...tail] = split(text);\n await postOrUpdate(head);\n for (const [index, part] of tail.entries()) {\n const existing = state.continuationIds[index];\n if (existing !== undefined) {\n await platform.update(String(existing), part);\n continue;\n }\n if (platform.typing?.stopOnSend) stopTyping();\n const id = await platform.postExtra(part, state.responseId);\n if (id !== undefined && id !== null) state.continuationIds[index] = id;\n }\n }\n\n async function postExtra(text: string): Promise<void> {\n if (platform.typing?.stopOnSend) stopTyping();\n await platform.postExtra(text, state.responseId);\n }\n\n async function stopNativeStream(): Promise<void> {\n if (!state.streamActive || state.responseId === null || !platform.stream) return;\n const streamId = state.responseId;\n state.streamActive = false;\n state.streamedSource = \"\";\n await platform.stream.stop(streamId);\n }\n\n async function abandonNativeStream(): Promise<void> {\n if (!platform.stream || state.responseId === null) return;\n const streamId = state.responseId;\n state.streamActive = false;\n state.streamedSource = \"\";\n await platform.stream.stop(streamId).catch(() => undefined);\n if (state.responseId === streamId) state.responseId = null;\n }\n\n async function renderRaw(\n text: string,\n operation: \"render\" | \"replace\",\n options?: { createOverflowLink?: () => string },\n canonicalText = text,\n ): Promise<string> {\n try {\n await postSplit(text);\n return canonicalText;\n } catch (err) {\n if (!platform.handleTooLong) throw err;\n // Only a length rejection may take the truncating path. Treating every\n // failure as \"too long\" turned a transient rate limit into a response\n // cut to a few thousand characters under a notice blaming its length,\n // and the retry it triggered kept the limit alive.\n if (platform.isTooLongError && !platform.isTooLongError(err)) throw err;\n const fallback = await platform.handleTooLong(\n canonicalText,\n operation,\n options,\n state.responseId,\n postSplit,\n () => state.responseId,\n );\n return fallback.text;\n }\n }\n\n async function renderDelta(text: string): Promise<string> {\n if (state.working && !text.trim()) return text;\n const prepared = platform.prepareSource?.(text, state.working) ?? text;\n const stream = platform.stream;\n const display = provisional(prepared, state.working);\n if (!stream || state.streamUnavailable) {\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n if (state.responseId !== null && !state.streamActive) {\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n if (\n state.responseId !== null &&\n state.streamActive &&\n !prepared.startsWith(state.streamedSource)\n ) {\n await abandonNativeStream();\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n\n try {\n if (state.responseId !== null) {\n const delta = prepared.slice(state.streamedSource.length);\n // Below the threshold the delta stays pending: `state.streamedSource`\n // does not advance, so the next tick recomputes it from the same base\n // and `renderFinal` flushes the remainder before stopping.\n if (delta && delta.length >= (stream.minDeltaChars ?? 0)) {\n await stream.append(state.responseId, delta);\n state.streamedSource = prepared;\n }\n return prepared;\n }\n state.responseId = await stream.start(prepared);\n state.streamActive = true;\n state.streamedSource = prepared;\n return prepared;\n } catch (err) {\n state.streamUnavailable = true;\n log.logWarning(\n \"Native response streaming unavailable; falling back to message updates\",\n err instanceof Error ? err.message : String(err),\n );\n await abandonNativeStream();\n await renderRaw(display, \"render\", undefined, prepared);\n return prepared;\n }\n }\n\n async function renderFinal(text: string): Promise<string> {\n const stream = platform.stream;\n if (stream && state.streamActive && state.responseId !== null) {\n let streamed = false;\n try {\n if (text.startsWith(state.streamedSource)) {\n const delta = text.slice(state.streamedSource.length);\n if (delta) await stream.append(state.responseId, delta);\n await stream.stop(state.responseId);\n streamed = true;\n }\n } catch (err) {\n state.streamUnavailable = true;\n log.logWarning(\n \"Native response streaming unavailable; falling back to message updates\",\n err instanceof Error ? err.message : String(err),\n );\n }\n state.streamActive = false;\n state.streamedSource = \"\";\n if (streamed) {\n if (platform.needsCanonicalRender?.(text)) await renderRaw(text, \"render\");\n return text;\n }\n await abandonNativeStream();\n }\n if (state.responseId !== null || text) return renderRaw(text, \"render\");\n return text;\n }\n\n async function run(\n label: string,\n operation: ChatResponseErrorOperation,\n work: () => Promise<void>,\n extra: () => Record<string, unknown>,\n ): Promise<void> {\n const operationPromise = queueTail.then(work);\n const handled = operationPromise.catch(async (err) => {\n const message = err instanceof Error ? err.message : String(err);\n log.logWarning(`${platform.label} ${label} error`, message);\n reportResponseError(err, operation, extra());\n if (platform.notifySendFailure) {\n try {\n await platform.notifySendFailure(message);\n } catch {\n // A secondary notification must not poison the response queue.\n }\n }\n });\n queueTail = handled.catch(() => undefined);\n return handled;\n }\n\n let queueTail = Promise.resolve();\n\n async function appendDelta(delta: string): Promise<void> {\n await run(\n \"appendResponseDelta\",\n \"respond\",\n async () => {\n if (!delta) return;\n if (state.resetDelta) {\n state.source = \"\";\n state.pendingChars = 0;\n state.resetDelta = false;\n }\n const sanitized = sanitize(delta);\n state.source += sanitized;\n state.pendingChars += sanitized.length;\n const elapsed = now() - state.lastFlushAt;\n // A character threshold must not bypass the interval. When it did, a\n // fast stream redrew every eighty characters — well over a hundred\n // edits for a long answer — and the platform started refusing them.\n if (state.lastFlushAt === 0 || (elapsed >= flushIntervalMs && state.pendingChars > 0)) {\n state.pendingChars = 0;\n state.source = await renderDelta(state.source);\n // Stamp on completion: a slow or retrying send pushes the next\n // redraw out by however long it took, so pressure never compounds.\n state.lastFlushAt = now();\n }\n },\n () => ({ textLength: delta.length, accumulatedLength: state.source.length }),\n );\n }\n\n const responder: ConversationResponder = {\n respond: async (text: string) => {\n await run(\n \"respond\",\n \"respond\",\n async () => {\n const sanitized = sanitize(text);\n state.source = state.source ? `${state.source}\\n${sanitized}` : sanitized;\n state.pendingChars = 0;\n state.source = await renderDelta(state.source);\n if (state.responseId !== null && platform.logIntermediateResponses) {\n platform.logBotResponse?.(text, state.responseId);\n }\n },\n () => ({\n phase: state.responseId ? \"update\" : \"initial_post\",\n textLength: text.length,\n accumulatedLength: state.source.length,\n }),\n );\n },\n\n appendResponseDelta: platform.supportsDeltas || platform.stream ? appendDelta : undefined,\n\n finishResponse:\n platform.supportsDeltas || platform.stream\n ? async (finalText?: string) => {\n await run(\n \"finishResponse\",\n \"set_working\",\n async () => {\n if (finalText !== undefined) state.source = sanitize(finalText);\n state.resetDelta = false;\n state.pendingChars = 0;\n stopTyping();\n state.working = false;\n state.source = await renderFinal(state.source);\n if (state.responseId !== null)\n platform.logBotResponse?.(state.source, state.responseId);\n await platform.onFinish?.(state.source, state.responseId);\n },\n () => ({ finalTextLength: finalText?.length }),\n );\n }\n : undefined,\n\n replaceResponse: async (text: string, options?: { createOverflowLink?: () => string }) => {\n await run(\n \"replaceResponse\",\n \"replace_response\",\n async () => {\n state.source = sanitize(text);\n state.pendingChars = 0;\n state.resetDelta = true;\n if (state.streamActive) await stopNativeStream();\n if (state.working && !state.source.trim()) return;\n // Prepare here too, not only on the delta path. This render is the\n // last word on the response, so skipping it let the canonical\n // replace overwrite prepared text with the raw source — a Discord\n // table converted during streaming reverted to literal pipes the\n // moment the run finished.\n const prepared = platform.prepareSource?.(state.source, state.working) ?? state.source;\n state.source = await renderRaw(\n provisional(prepared, state.working),\n \"replace\",\n options,\n // The prepared text is what was sent, so it is also what the\n // renderer must remember it sent.\n prepared,\n );\n },\n () => ({\n textLength: text.length,\n hadExistingResponse: Boolean(state.responseId),\n }),\n );\n },\n\n replaceSubagentProgress: platform.formatSubagentProgress\n ? async (progress: SubagentProgressSnapshot, finalText?: string) => {\n const dashboard = platform.formatSubagentProgress!(progress);\n await responder.replaceResponse(finalText ? `${dashboard}\\n\\n${finalText}` : dashboard);\n }\n : undefined,\n\n respondDiagnostic: async (text, options = {}) => {\n await run(\n \"respondDiagnostic\",\n \"respond_diagnostic\",\n async () => {\n const ids = platform.postDiagnostic\n ? await platform.postDiagnostic(text, options, state.responseId)\n : await postDefaultDiagnostic(text, options);\n state.extraIds.push(...ids);\n },\n () => ({ textLength: text.length, style: options.style }),\n );\n },\n\n respondToolResult: async (result: ChatToolResult) => {\n await responder.respondDiagnostic(platform.formatToolResult(result));\n },\n\n setTyping: async (isTyping: boolean) => {\n await run(\n \"setTyping\",\n \"set_working\",\n async () => {\n if (platform.setTyping) {\n await platform.setTyping(isTyping, state.responseId);\n return;\n }\n const typing = platform.typing;\n if (!typing) return;\n const onTypingError = (err: unknown): void => {\n if (state.typingFailureWarned) return;\n state.typingFailureWarned = true;\n log.logWarning(\n `${platform.label} sendTyping failed (further occurrences suppressed for this session)`,\n err instanceof Error ? err.message : String(err),\n );\n };\n if (isTyping && state.typingInterval === null) {\n typing.send().catch(onTypingError);\n state.typingInterval = setInterval(() => {\n typing.send().catch(onTypingError);\n }, typing.intervalMs);\n } else if (!isTyping) {\n stopTyping();\n }\n },\n () => ({ working: isTyping }),\n );\n },\n\n setWorking: async (working: boolean) => {\n await run(\n \"setWorking\",\n \"set_working\",\n async () => {\n state.working = working;\n if (!working) stopTyping();\n await platform.onWorkingChanged?.(working, state.responseId);\n if (state.responseId === null || (!platform.workingIndicator && !platform.stream)) return;\n if (working && !state.source.trim()) return;\n\n if (state.streamActive && !working) {\n await stopNativeStream();\n return;\n }\n if (state.responseId !== null) {\n state.source = await renderRaw(\n provisional(state.source, working),\n \"render\",\n undefined,\n state.source,\n );\n }\n },\n () => ({ working }),\n );\n },\n\n uploadFile: async (filePath: string, title?: string) => {\n if (platform.uploadFile) {\n await platform.uploadFile(filePath, title);\n return;\n }\n const note = platform.uploadFallbackNote?.(title ?? filePath);\n if (note === undefined) return;\n await run(\n \"uploadFile\",\n \"respond_diagnostic\",\n () => postExtra(note),\n () => ({ filePath }),\n );\n },\n\n ...(platform.react ? { react: platform.react } : {}),\n\n deleteResponse: async () => {\n await run(\n \"deleteResponse\",\n \"respond\",\n async () => {\n stopTyping();\n if (state.streamActive) await stopNativeStream().catch(() => undefined);\n for (const id of [...state.extraIds, ...state.continuationIds]) {\n try {\n await platform.deleteExtra?.(id);\n } catch {\n // Deleting diagnostics is best effort.\n }\n }\n state.extraIds = [];\n state.continuationIds = [];\n if (state.responseId !== null) {\n try {\n await platform.delete?.(state.responseId);\n } catch {\n // Deleting the main response is best effort.\n }\n }\n state.responseId = null;\n state.source = \"\";\n state.streamUnavailable = false;\n state.streamedSource = \"\";\n state.streamActive = false;\n state.resetDelta = false;\n state.working = true;\n },\n () => ({}),\n );\n },\n };\n\n async function postDefaultDiagnostic(\n text: string,\n options: { style?: \"muted\" | \"error\" },\n ): Promise<Array<string | number>> {\n const prefix = options.style === \"error\" ? platform.errorPrefix : \"\";\n const ids: Array<string | number> = [];\n for (const part of split(sanitize(`${prefix}${text}`))) {\n const id = await platform.postExtra(part, state.responseId);\n if (typeof id === \"string\" || typeof id === \"number\") ids.push(id);\n }\n return ids;\n }\n\n return { responder };\n}\n"]}
|