feat(server): edit tool intent collect (#12998)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Footnotes are now included in streamed AI responses, formatted as
markdown and appended at the end of the output when available.

* **Improvements**
* Enhanced handling of footnotes across multiple AI providers, ensuring
consistent display of additional information after the main response.

* **Refactor**
  * Removed citation parsing from one provider to streamline output.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2025-07-04 07:32:30 +08:00
committed by GitHub
parent cfc108613c
commit 53968f6f8c
5 changed files with 40 additions and 9 deletions
@@ -412,6 +412,10 @@ export function toError(error: unknown): Error {
}
}
type DocEditFootnote = {
intent: string;
result: string;
};
export class TextStreamParser {
private readonly logger = new Logger(TextStreamParser.name);
private readonly CALLOUT_PREFIX = '\n[!]\n';
@@ -420,6 +424,8 @@ export class TextStreamParser {
private prefix: string | null = this.CALLOUT_PREFIX;
private readonly docEditFootnotes: DocEditFootnote[] = [];
public parse(chunk: TextStreamPart<CustomAITools>) {
let result = '';
switch (chunk.type) {
@@ -463,6 +469,13 @@ export class TextStreamParser {
result += `\nWriting document "${chunk.args.title}"\n`;
break;
}
case 'doc_edit': {
this.docEditFootnotes.push({
intent: chunk.args.instructions,
result: '',
});
break;
}
}
result = this.markAsCallout(result);
break;
@@ -476,6 +489,10 @@ export class TextStreamParser {
case 'doc_edit': {
if (chunk.result && typeof chunk.result === 'object') {
result += `\n${chunk.result.result}\n`;
this.docEditFootnotes[this.docEditFootnotes.length - 1].result =
chunk.result.result;
} else {
this.docEditFootnotes.pop();
}
break;
}
@@ -520,6 +537,13 @@ export class TextStreamParser {
return result;
}
public end() {
const footnotes = this.docEditFootnotes.map((footnote, index) => {
return `[^edit${index + 1}]: ${JSON.stringify({ type: 'doc-edit', ...footnote })}`;
});
return footnotes.join('\n');
}
private addPrefix(text: string) {
if (this.prefix) {
const result = this.prefix + text;