@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.
Files changed (81) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/adapters/discord/bot.d.ts.map +1 -1
  3. package/dist/adapters/discord/bot.js +7 -6
  4. package/dist/adapters/discord/bot.js.map +1 -1
  5. package/dist/adapters/discord/components.d.ts +33 -0
  6. package/dist/adapters/discord/components.d.ts.map +1 -0
  7. package/dist/adapters/discord/components.js +32 -0
  8. package/dist/adapters/discord/components.js.map +1 -0
  9. package/dist/adapters/discord/context.d.ts.map +1 -1
  10. package/dist/adapters/discord/context.js +16 -6
  11. package/dist/adapters/discord/context.js.map +1 -1
  12. package/dist/adapters/discord/format.d.ts +3 -0
  13. package/dist/adapters/discord/format.d.ts.map +1 -0
  14. package/dist/adapters/discord/format.js +86 -0
  15. package/dist/adapters/discord/format.js.map +1 -0
  16. package/dist/adapters/markdown-tables.d.ts +37 -0
  17. package/dist/adapters/markdown-tables.d.ts.map +1 -0
  18. package/dist/adapters/markdown-tables.js +164 -0
  19. package/dist/adapters/markdown-tables.js.map +1 -0
  20. package/dist/adapters/progressive-renderer.d.ts.map +1 -1
  21. package/dist/adapters/progressive-renderer.js +69 -12
  22. package/dist/adapters/progressive-renderer.js.map +1 -1
  23. package/dist/adapters/slack/assistant.d.ts +101 -0
  24. package/dist/adapters/slack/assistant.d.ts.map +1 -0
  25. package/dist/adapters/slack/assistant.js +204 -0
  26. package/dist/adapters/slack/assistant.js.map +1 -0
  27. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  28. package/dist/adapters/slack/blocks.js +4 -82
  29. package/dist/adapters/slack/blocks.js.map +1 -1
  30. package/dist/adapters/slack/bot.d.ts +52 -0
  31. package/dist/adapters/slack/bot.d.ts.map +1 -1
  32. package/dist/adapters/slack/bot.js +161 -5
  33. package/dist/adapters/slack/bot.js.map +1 -1
  34. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  35. package/dist/adapters/slack/response-lifecycle.js +86 -15
  36. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  37. package/dist/adapters/slack/stream-limits.d.ts +35 -0
  38. package/dist/adapters/slack/stream-limits.d.ts.map +1 -0
  39. package/dist/adapters/slack/stream-limits.js +56 -0
  40. package/dist/adapters/slack/stream-limits.js.map +1 -0
  41. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  42. package/dist/adapters/telegram/bot.js +26 -47
  43. package/dist/adapters/telegram/bot.js.map +1 -1
  44. package/dist/adapters/telegram/context.d.ts.map +1 -1
  45. package/dist/adapters/telegram/context.js +7 -19
  46. package/dist/adapters/telegram/context.js.map +1 -1
  47. package/dist/adapters/types.d.ts +24 -1
  48. package/dist/adapters/types.d.ts.map +1 -1
  49. package/dist/adapters/types.js.map +1 -1
  50. package/dist/agent.d.ts.map +1 -1
  51. package/dist/agent.js +2 -1
  52. package/dist/agent.js.map +1 -1
  53. package/dist/commands/extensions.d.ts +18 -6
  54. package/dist/commands/extensions.d.ts.map +1 -1
  55. package/dist/commands/extensions.js +55 -8
  56. package/dist/commands/extensions.js.map +1 -1
  57. package/dist/env-manifest.d.ts.map +1 -1
  58. package/dist/env-manifest.js +4 -0
  59. package/dist/env-manifest.js.map +1 -1
  60. package/dist/harness/subagent-runner.d.ts +6 -0
  61. package/dist/harness/subagent-runner.d.ts.map +1 -1
  62. package/dist/harness/subagent-runner.js +63 -0
  63. package/dist/harness/subagent-runner.js.map +1 -1
  64. package/dist/subagent-progress.d.ts +3 -7
  65. package/dist/subagent-progress.d.ts.map +1 -1
  66. package/dist/subagent-progress.js +15 -10
  67. package/dist/subagent-progress.js.map +1 -1
  68. package/dist/tools/subagent.d.ts +8 -1
  69. package/dist/tools/subagent.d.ts.map +1 -1
  70. package/dist/tools/subagent.js +24 -1
  71. package/dist/tools/subagent.js.map +1 -1
  72. package/dist/types.d.ts +8 -0
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/types.js.map +1 -1
  75. package/dist/web/admin/portal.js +5 -1
  76. package/dist/web/admin/portal.js.map +1 -1
  77. package/package.json +2 -1
  78. package/dist/adapters/telegram/html.d.ts +0 -3
  79. package/dist/adapters/telegram/html.d.ts.map +0 -1
  80. package/dist/adapters/telegram/html.js +0 -101
  81. 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;AAoBD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,2BAA2B,GAAG;IAChF,SAAS,EAAE,qBAAqB,CAAC;CAClC,CAscA"}
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
- const DEFAULT_FLUSH_INTERVAL_MS = 750;
16
- const DEFAULT_FLUSH_CHARS = 80;
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
- if (delta) {
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
- if (state.lastFlushAt === 0 ||
210
- state.pendingChars >= DEFAULT_FLUSH_CHARS ||
211
- elapsed >= DEFAULT_FLUSH_INTERVAL_MS) {
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
- state.source = await renderRaw(provisional(state.source, state.working), "replace", options, state.source);
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"]}