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