File size: 2,018 Bytes
db9635c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import {
  StreamingToolParser as HTMLStreamingToolParser,
  extractToolCalls as htmlExtractToolCalls,
  filterToolCalls as htmlFilterToolCalls,
} from "./tool-parser-htmlparser2";

export interface ToolCallMatch {
  toolName: string;
  startIndex: number;
  endIndex?: number;
  args?: string;
  complete: boolean;
}

export class StreamingToolCallParser {
  private htmlParser: HTMLStreamingToolParser;
  private buffer = "";

  constructor() {
    this.htmlParser = new HTMLStreamingToolParser();
  }

  reset(): void {
    this.buffer = "";
    this.htmlParser.reset();
  }

  /**
   * Process incoming text and detect tool call boundaries
   * Returns the safe text (without tool calls) and any detected tool calls
   */
  process(text: string): {
    safeText: string;
    toolCalls: ToolCallMatch[];
    pendingToolCall: boolean;
  } {
    this.buffer += text;
    const result = this.htmlParser.write(text);

    return {
      safeText: result.safeText,
      toolCalls: result.toolCalls.map((tc) => ({
        toolName: tc.name,
        startIndex: tc.startIndex || 0,
        endIndex: tc.endIndex,
        args: tc.rawArgs,
        complete: tc.complete,
      })),
      pendingToolCall: result.pendingToolCall,
    };
  }

  /**
   * Get any buffered content that hasn't been processed yet
   */
  getBuffer(): string {
    return this.buffer;
  }

  /**
   * Check if parser is currently inside a tool call
   */
  isInToolCall(): boolean {
    const result = this.htmlParser.write("");
    return result.pendingToolCall;
  }
}

/**
 * Static utility to filter tool calls from text (non-streaming)
 */
export function filterToolCalls(text: string): string {
  return htmlFilterToolCalls(text);
}

/**
 * Static utility to extract tool calls from text
 */
export function extractToolCalls(
  text: string,
): Array<{ name: string; args: Record<string, unknown> }> {
  const htmlToolCalls = htmlExtractToolCalls(text);

  return htmlToolCalls.map((tc) => ({
    name: tc.name,
    args: tc.args,
  }));
}