startTool method
Future<void>
startTool(
- String toolId, {
- required void onData(
- CommandResultDto commandOutput
- required void onError(
- CommandResultDto commandOutput
- void onStreamError(
- Object error,
- StackTrace stackTrace
- int timeoutSeconds = -1,
POST /tools/{toolId}/start
Implementation
Future<void> startTool(
String toolId, {
required void Function(CommandResultDto commandOutput) onData,
required void Function(CommandResultDto commandError) onError,
void Function(Object error, StackTrace stackTrace)? onStreamError,
int timeoutSeconds = -1,
}) async {
var terminalErrorReported = false;
try {
final queryParameters = <String, dynamic>{
if (timeoutSeconds >= 0) 'timeout': '$timeoutSeconds',
};
final sseStream = await toolSse.request(
'/${toolId}/start',
queryParameters: queryParameters,
);
var terminalReceived = false;
await for (final chunk in sseStream) {
DaemonApiException? terminalError;
SseClient.parse(chunk, (event, data) {
final result = CommandResultDto.fromJson(data);
if (event == EventType.DATA) {
onData(result);
} else if (event == EventType.DONE) {
terminalReceived = true;
} else if (event == EventType.ERROR) {
terminalReceived = true;
terminalErrorReported = true;
onError(result);
terminalError = DaemonApiException(
code: 'TOOL_START_FAILED',
message: result.error ?? 'OpenTool start failed',
retryable: false,
details: result.toJson(),
);
}
});
if (terminalError != null) throw terminalError!;
if (terminalReceived) return;
}
if (!terminalReceived) {
throw const SseProtocolException(
'Start stream closed before a terminal done or error event',
);
}
} catch (error, stackTrace) {
final normalized = _normalizeError(error);
if (!terminalErrorReported && onStreamError != null) {
onStreamError(normalized, stackTrace);
}
if (identical(normalized, error)) rethrow;
Error.throwWithStackTrace(normalized, stackTrace);
}
}