sendUser method

Dispatch a user message: append the user turn, call system.agents.ask, append the assistant reply (or assistantError on failure plus optional toolUse turns), and return a structured result.

Implementation

Future<AgentChatDispatchResult> sendUser(String text) async {
  _checkAlive();
  final appended = <ChatTurn>[];
  final userTurn = ChatTurn(
    id: _newId('user'),
    role: ChatRole.user,
    text: text,
    ts: DateTime.now().toUtc(),
    agentId: agentId,
  );
  appended.add(await appendTurn(userTurn));

  AgentReply? reply;
  try {
    reply = await _ask(text);
  } catch (err) {
    final errTurn = ChatTurn(
      id: _newId('err'),
      role: ChatRole.assistantError,
      text: err.toString(),
      ts: DateTime.now().toUtc(),
      agentId: agentId,
      meta: <String, dynamic>{'error': err.runtimeType.toString()},
    );
    appended.add(await appendTurn(errTurn));
    return AgentChatDispatchResult(
      appended: List.unmodifiable(appended),
      error: err,
    );
  }

  final assistantTurn = ChatTurn(
    id: _newId('asst'),
    role: ChatRole.assistant,
    text: reply.content,
    ts: reply.timestamp.toUtc(),
    agentId: agentId,
    meta: _replyMeta(reply),
  );
  appended.add(await appendTurn(assistantTurn));

  final calls = reply.toolCalls ?? const <AgentToolCall>[];
  if (calls.isNotEmpty) {
    final clamped =
        calls.length > _turnLimit ? calls.sublist(0, _turnLimit) : calls;
    for (final c in clamped) {
      final toolTurn = ChatTurn(
        id: _newId('tool'),
        role: ChatRole.toolUse,
        text: c.name,
        ts: DateTime.now().toUtc(),
        agentId: agentId,
        meta: <String, dynamic>{
          'toolCallId': c.id,
          'arguments': c.arguments,
        },
      );
      appended.add(await appendTurn(toolTurn));
    }
    if (calls.length > _turnLimit) {
      final warn = ChatTurn(
        id: _newId('warn'),
        role: ChatRole.system,
        text: 'turn-limit reached ($_turnLimit) — '
            '${calls.length - _turnLimit} additional tool call(s) suppressed',
        ts: DateTime.now().toUtc(),
        agentId: agentId,
      );
      appended.add(await appendTurn(warn));
    }
  }

  return AgentChatDispatchResult(
    appended: List.unmodifiable(appended),
    reply: reply,
  );
}