promptToolStreamFunction function

StreamFunction promptToolStreamFunction(
  1. StreamFunction inner, {
  2. PromptToolOptions? options,
})

Wraps inner with prompt-based tool calling.

When context.tools is non-empty (or PromptToolOptions.injectWhenNoTools is set), the returned StreamFunction appends the tool instructions to the system prompt, re-serializes tool calls/results in the message history as fenced text, and parses tool_call fenced blocks out of the inner stream's text into the harness tool-call event contract. Otherwise the inner stream is returned untouched (byte-identical passthrough).

The wrapper preserves the provider contract: it never throws and terminates with exactly one DoneEvent or ErrorEvent.

Implementation

StreamFunction promptToolStreamFunction(
  StreamFunction inner, {
  PromptToolOptions? options,
}) {
  final opts = options ?? const PromptToolOptions();
  return (Model model, Context context, {CancelToken? cancelToken}) {
    final tools = context.tools ?? const <Tool>[];
    if (tools.isEmpty && !opts.injectWhenNoTools) {
      return inner(model, context, cancelToken: cancelToken);
    }

    final out = AssistantMessageEventStream();
    final parser = _PromptToolStreamParser(out, opts, model);

    final AssistantMessageEventStream innerStream;
    try {
      innerStream = inner(
        model,
        _transformContext(context, tools, opts.slim),
        cancelToken: cancelToken,
      );
    } catch (error) {
      // Defensive: the StreamFunction contract is never-throw.
      parser.fail(error);
      out.end();
      return out;
    }

    unawaited(() async {
      try {
        await for (final event in innerStream) {
          parser.handle(event);
        }
        parser.streamClosed();
      } catch (error) {
        // Defensive: inner streams report failures as ErrorEvents.
        parser.fail(error);
      } finally {
        out.end();
      }
    }());
    return out;
  };
}