createTaskUpdateTool function
Builds the tool that updates a session task.
Implementation
Tool<JsonMap, String> createTaskUpdateTool(
Genkit ai, {
required ToolRuntime runtime,
}) {
final idList = <String, Object?>{
'type': 'array',
'items': <String, Object?>{'type': 'string'},
};
return defineTextTool(
ai,
runtime: runtime,
name: 'task_update',
description: _description,
properties: <String, Object?>{
'taskId': stringProperty('The id of the task to update.'),
'status': stringProperty('New status.', enumValues: <String>['pending', 'in_progress', 'completed']),
'subject': stringProperty('New title.'),
'description': stringProperty('New description.'),
'activeForm': stringProperty('New present-continuous form.'),
'owner': stringProperty('Who owns the task.'),
'addBlocks': <String, Object?>{...idList, 'description': 'Ids of tasks this task blocks.'},
'addBlockedBy': <String, Object?>{...idList, 'description': 'Ids of tasks that block this task.'},
'metadata': <String, Object?>{'type': 'object', 'description': 'Metadata keys to merge; null removes a key.'},
},
required: <String>['taskId'],
run: (input) async {
final taskId = requireString(input, 'taskId').trim();
final task = runtime.taskById(taskId);
if (task == null) {
throw ToolFailure('Task #$taskId was not found. Use task_list to see existing tasks.');
}
final statusInput = readString(input, 'status');
final newStatus = parseSessionTaskStatus(statusInput);
if (statusInput != null && newStatus == null) {
throw const ToolFailure('`status` must be pending, in_progress, or completed.');
}
final transitionError = runtime.validateTaskTransition(taskId: taskId, newStatus: newStatus);
if (transitionError != null) {
throw ToolFailure(transitionError);
}
String? nonBlank(String key) {
final value = readString(input, key)?.trim();
return value == null || value.isEmpty ? null : value;
}
task
..subject = nonBlank('subject') ?? task.subject
..description = nonBlank('description') ?? task.description
..activeForm = nonBlank('activeForm') ?? task.activeForm
..owner = nonBlank('owner') ?? task.owner
..status = newStatus ?? task.status;
_addIds(task.blocks, readList(input, 'addBlocks'));
_addIds(task.blockedBy, readList(input, 'addBlockedBy'));
for (final entry in (readJsonMap(input, 'metadata') ?? const <String, dynamic>{}).entries) {
if (entry.value == null) {
task.metadata.remove(entry.key);
} else {
task.metadata[entry.key] = entry.value;
}
}
runtime.startTool('task_update', '#${task.id} ${sessionTaskStatusLabel(task.status)}: ${task.subject}');
return jsonEncode(<String, Object?>{'task': task.toJson()});
},
);
}