execute method

  1. @override
Future<Content> execute(
  1. ToolContext context,
  2. Map<String, dynamic> arguments
)
override

Implementation

@override
Future<Content> execute(ToolContext context, Map<String, dynamic> arguments) async {
  if (!navigator.mounted) {
    return ErrorContent(text: "Client toolkit request could not be shown because the chat view is no longer mounted.");
  }

  final responseController = CodeLineEditingController.fromText(
    const JsonEncoder.withIndent('  ').convert(<String, Object?>{"answer": ""}),
  );
  Object? responseError;
  final resolvedTitle = title?.trim().isNotEmpty == true ? title!.trim() : name;
  final resolvedDescription = description?.trim().isNotEmpty == true
      ? description!.trim()
      : "The agent requested a response from this client-side tool.";

  try {
    final response = await showShadDialog<Content>(
      context: navigator.context,
      builder: (context) => StatefulBuilder(
        builder: (context, setDialogState) => ShadDialog(
          title: Text(resolvedTitle),
          description: Text(resolvedDescription),
          actions: [
            ShadButton.secondary(
              onPressed: () => Navigator.of(context).pop(ErrorContent(text: "Client toolkit request was cancelled.")),
              child: const Text("Cancel"),
            ),
            ShadButton(
              onPressed: () {
                try {
                  final parsed = jsonDecode(responseController.text);
                  if (parsed is! Map) {
                    throw const FormatException("Response must be a JSON object.");
                  }
                  Navigator.of(context).pop(JsonContent(json: parsed.map((key, value) => MapEntry(key.toString(), value))));
                } catch (error) {
                  setDialogState(() => responseError = error);
                }
              },
              child: const Text("Send"),
            ),
          ],
          child: SizedBox(
            width: 680,
            height: 420,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (arguments.isNotEmpty) ...[
                  Text("Arguments", style: ShadTheme.of(context).textTheme.small),
                  const SizedBox(height: 6),
                  Container(
                    width: double.infinity,
                    padding: const EdgeInsets.all(12),
                    decoration: BoxDecoration(color: ShadTheme.of(context).colorScheme.muted, borderRadius: BorderRadius.circular(8)),
                    child: Text(const JsonEncoder.withIndent('  ').convert(arguments)),
                  ),
                  const SizedBox(height: 12),
                ],
                Text("Response", style: ShadTheme.of(context).textTheme.small),
                const SizedBox(height: 6),
                Expanded(
                  child: CodeEditor(
                    style: CodeEditorStyle(
                      fontSize: 14,
                      fontFamily: ThreadTypographyOverride.maybeCodeFontFamilyOf(context) ?? defaultThreadCodeFontFamily,
                      codeTheme: CodeHighlightTheme(
                        languages: {'default': CodeHighlightThemeMode(mode: langJson)},
                        theme: monokaiSublimeTheme,
                      ),
                    ),
                    controller: responseController,
                    onChanged: (_) {
                      if (responseError != null) {
                        setDialogState(() => responseError = null);
                      }
                    },
                  ),
                ),
                if (responseError != null) ...[
                  const SizedBox(height: 8),
                  ShadAlert.destructive(description: Text("$responseError", maxLines: 3)),
                ],
              ],
            ),
          ),
        ),
      ),
    );
    return response ?? ErrorContent(text: "Client toolkit request was cancelled.");
  } finally {
    responseController.dispose();
  }
}