Auto deployments & columns
This commit is contained in:
parent
cc92cf681c
commit
fab5746c42
1 changed files with 65 additions and 46 deletions
111
src/tools.rs
111
src/tools.rs
|
|
@ -86,10 +86,7 @@ impl ToolDefinition {
|
|||
}
|
||||
|
||||
pub fn to_short_doc(&self) -> String {
|
||||
format!(
|
||||
"- {}: {}\n",
|
||||
self.name, self.description
|
||||
)
|
||||
format!("- {}: {}\n", self.name, self.description)
|
||||
}
|
||||
|
||||
/// Strip the project_id parameter from the tool's JSON schema.
|
||||
|
|
@ -141,12 +138,17 @@ impl ToolDefinition {
|
|||
}
|
||||
|
||||
/// Filter tools by execution context
|
||||
pub fn filter_by_context(tools: &[ToolDefinition], context: ExecutionContext) -> Vec<ToolDefinition> {
|
||||
pub fn filter_by_context(
|
||||
tools: &[ToolDefinition],
|
||||
context: ExecutionContext,
|
||||
) -> Vec<ToolDefinition> {
|
||||
match context {
|
||||
ExecutionContext::Both => tools.to_vec(),
|
||||
context => tools
|
||||
.iter()
|
||||
.filter(|t| t.execution_context == context || t.execution_context == ExecutionContext::Both)
|
||||
.filter(|t| {
|
||||
t.execution_context == context || t.execution_context == ExecutionContext::Both
|
||||
})
|
||||
.cloned()
|
||||
.collect(),
|
||||
}
|
||||
|
|
@ -154,11 +156,7 @@ impl ToolDefinition {
|
|||
|
||||
/// Filter tools to only include non-deprecated ones
|
||||
pub fn filter_active(tools: &[ToolDefinition]) -> Vec<ToolDefinition> {
|
||||
tools
|
||||
.iter()
|
||||
.filter(|t| !t.deprecated)
|
||||
.cloned()
|
||||
.collect()
|
||||
tools.iter().filter(|t| !t.deprecated).cloned().collect()
|
||||
}
|
||||
|
||||
/// Check compatibility with another tool definition
|
||||
|
|
@ -1099,15 +1097,16 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
|||
),
|
||||
tool!(
|
||||
"kanban_create_todo",
|
||||
"Create a new todo item in a Kanban column",
|
||||
"kanban",
|
||||
false, false, true,
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_id": { "type": "string", "description": "Project ID" },
|
||||
"board_id": { "type": "string", "description": "Board ID (defaults to project's primary board)" },
|
||||
"column_id": { "type": "string", "description": "Column ID to place the todo" },
|
||||
"Create a new todo item in a Kanban board",
|
||||
"kanban",
|
||||
false, false, true,
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_id": { "type": "string", "description": "Project ID" },
|
||||
"board_id": { "type": "string", "description": "Board ID (defaults to project's primary board)" },
|
||||
"status": { "type": "string", "enum": ["Ready","InProgress","Done","Blocked","Delegated","Failed","PendingApproval"], "description": "Initial status of the todo" },
|
||||
|
||||
"title": { "type": "string", "description": "Title of the todo" },
|
||||
"description": { "type": "string", "description": "Optional description" },
|
||||
"priority": { "type": "number", "description": "Priority (1-1000)" },
|
||||
|
|
@ -1115,7 +1114,7 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
|||
"agent_prompt": { "type": "string", "description": "Optional agent prompt if deploy_agent is true" },
|
||||
"agent_task_details": { "type": "string", "description": "Optional agent task details" }
|
||||
},
|
||||
"required": ["project_id", "column_id", "title"]
|
||||
"required": ["project_id", "title"]
|
||||
})
|
||||
),
|
||||
tool!(
|
||||
|
|
@ -1152,19 +1151,19 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
|||
),
|
||||
tool!(
|
||||
"kanban_move_todo",
|
||||
"Move a todo to a different column or reorder it",
|
||||
"kanban",
|
||||
false, false, true,
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_id": { "type": "string", "description": "Project ID" },
|
||||
"todo_id": { "type": "string", "description": "ID of the todo to move" },
|
||||
"column_id": { "type": "string", "description": "Target column ID" },
|
||||
"task_order": { "type": "number", "description": "New order position" }
|
||||
},
|
||||
"required": ["project_id", "todo_id", "column_id"]
|
||||
})
|
||||
"Move a todo item to a different status",
|
||||
"kanban",
|
||||
false, false, true,
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_id": { "type": "string", "description": "Project ID" },
|
||||
"todo_id": { "type": "string", "description": "ID of the todo to move" },
|
||||
"status": { "type": "string", "enum": ["Ready","InProgress","Done","Blocked","Delegated","Failed","PendingApproval"], "description": "Target status" },
|
||||
"task_order": { "type": "number", "description": "New order position" }
|
||||
},
|
||||
"required": ["project_id", "todo_id"]
|
||||
})
|
||||
),
|
||||
tool!(
|
||||
"kanban_create_task",
|
||||
|
|
@ -2014,10 +2013,7 @@ Done with tools.
|
|||
|
||||
#[test]
|
||||
fn test_execution_context_default() {
|
||||
assert_eq!(
|
||||
ExecutionContext::default(),
|
||||
ExecutionContext::Both
|
||||
);
|
||||
assert_eq!(ExecutionContext::default(), ExecutionContext::Both);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2043,7 +2039,10 @@ Done with tools.
|
|||
"```\nSome trailing text.",
|
||||
];
|
||||
let results = parse_tool_call_stream(chunks.into_iter());
|
||||
assert!(results.is_empty(), "tool-result: at stream start should be rejected");
|
||||
assert!(
|
||||
results.is_empty(),
|
||||
"tool-result: at stream start should be rejected"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2053,7 +2052,10 @@ Done with tools.
|
|||
"```tool-result:write_file\n{\"call_id\": \"c2\"}\n```\n",
|
||||
];
|
||||
let results = parse_tool_call_stream(chunks.into_iter());
|
||||
assert!(results.is_empty(), "multiple tool-result: blocks should all be rejected");
|
||||
assert!(
|
||||
results.is_empty(),
|
||||
"multiple tool-result: blocks should all be rejected"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2064,15 +2066,24 @@ Done with tools.
|
|||
"```tool:search_files\n{\"call_id\": \"c3\"}\n```\n",
|
||||
];
|
||||
let results = parse_tool_call_stream(chunks.into_iter());
|
||||
assert_eq!(results.len(), 2, "should only parse the tool: blocks, not tool-result:");
|
||||
assert_eq!(
|
||||
results.len(),
|
||||
2,
|
||||
"should only parse the tool: blocks, not tool-result:"
|
||||
);
|
||||
assert_eq!(results[0].call_id, "c1");
|
||||
assert_eq!(results[1].call_id, "c3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_streaming_tool_result_only_chunk() {
|
||||
let results = parse_tool_call_stream(vec!["```tool-result:read_file\n{\"call_id\": \"c1\"}\n```\n"].into_iter());
|
||||
assert!(results.is_empty(), "tool-result: as only chunk content should be rejected");
|
||||
let results = parse_tool_call_stream(
|
||||
vec!["```tool-result:read_file\n{\"call_id\": \"c1\"}\n```\n"].into_iter(),
|
||||
);
|
||||
assert!(
|
||||
results.is_empty(),
|
||||
"tool-result: as only chunk content should be rejected"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2083,12 +2094,20 @@ Done with tools.
|
|||
"Some text after.",
|
||||
];
|
||||
let results = parse_tool_call_stream(chunks.into_iter());
|
||||
assert!(results.is_empty(), "tool-result: in middle of text should be rejected");
|
||||
assert!(
|
||||
results.is_empty(),
|
||||
"tool-result: in middle of text should be rejected"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_streaming_finish_rejects_tool_result_no_closing_fence() {
|
||||
let results = parse_tool_call_stream(vec!["```tool-result:read_file\n{\"call_id\": \"c1\"}\n"].into_iter());
|
||||
assert!(results.is_empty(), "tool-result: without closing fence should be rejected by finish()");
|
||||
let results = parse_tool_call_stream(
|
||||
vec!["```tool-result:read_file\n{\"call_id\": \"c1\"}\n"].into_iter(),
|
||||
);
|
||||
assert!(
|
||||
results.is_empty(),
|
||||
"tool-result: without closing fence should be rejected by finish()"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue