createSession method
Create a tool-calling session that runs entirely in a dedicated worker
isolate, so the inline llama.cpp generation loop (create + every step)
never blocks the calling isolate. Events are copied SYNCHRONOUSLY inside a
worker-owned NativeCallable.isolateLocal (commons' dispatcher hands out a
stack-local buffer valid only for the call — see tool_calling_session.cpp
dispatch_pending) and forwarded to this isolate over a port, where they
are decoded onto the returned broadcast stream. Tool results are sent back
to the worker via ToolCallingSessionHandle.stepWithResult; cancellation
uses the thread-safe rac_tool_calling_session_cancel_proto directly.
Implementation
ToolCallingSessionHandle createSession(
ToolCallingSessionCreateRequest request,
) {
// Ownership transfers to ToolCallingSessionHandle, whose close() method
// closes the controller after the worker port is quiesced.
// ignore: close_sinks
final controller = StreamController<ToolCallingSessionEvent>.broadcast();
final fromWorker = ReceivePort();
final idCompleter = Completer<int>();
final handle = ToolCallingSessionHandle._(
sessionId: idCompleter.future,
events: controller,
fromWorker: fromWorker,
);
fromWorker.listen((Object? message) {
if (message is SendPort) {
handle._toWorker = message;
} else if (message is Uint8List) {
if (controller.isClosed) return;
try {
controller.add(ToolCallingSessionEvent.fromBuffer(message));
} catch (e, st) {
controller.addError(e, st);
}
} else if (message is int) {
_logger.debug('Tool calling session created: handle=$message');
if (!idCompleter.isCompleted) idCompleter.complete(message);
} else if (message is List && message.isNotEmpty && message[0] == 'err') {
final err = StateError(
message.length > 1 ? '${message[1]}' : 'tool-calling worker error',
);
if (!controller.isClosed) controller.addError(err);
if (!idCompleter.isCompleted) idCompleter.completeError(err);
}
});
final bytes = request.writeToBuffer();
unawaited(() async {
try {
final iso = await Isolate.spawn(_toolSessionWorkerEntry, <dynamic>[
fromWorker.sendPort,
bytes,
]);
handle._isolate = iso;
if (handle._closed) iso.kill(priority: Isolate.immediate);
} catch (e, st) {
if (!controller.isClosed) controller.addError(e, st);
if (!idCompleter.isCompleted) idCompleter.completeError(e, st);
}
}());
return handle;
}