clm.tool_register("concurrent_async", { description = "exercise concurrent lua async operations", params_schema = { type = "object", properties = { get_url = { type = "string" }, post_url = { type = "string" }, }, required = { "get_url", "post_url" }, }, no_prompt = true, invoke = function(args, ctx) local started = 0 local tasks = { clm.spawn(function() started = started + 1 local response, err = http.get(args.get_url) if response == nil then error(err) end return response.body end), clm.spawn(function() started = started + 1 local response, err = http.post(args.post_url, "{}") if response == nil then error(err) end return response.body end), clm.spawn(function() started = started + 1 clm.sleep(0) return "slept" end), clm.spawn(function() started = started + 1 return "multi", "value" end), } if started ~= 0 then ctx:fail("spawn ran a task before returning") return end if tasks[1]:result() ~= nil then ctx:fail("pending task unexpectedly had a result") return end local first, wait_err = clm.wait_any(tasks) if first == nil then ctx:fail(wait_err) return end local first_outcome = tasks[first]:result() if first_outcome == nil or not first_outcome.ok then ctx:fail("wait_any returned an unsuccessful task") return end local outcomes = clm.await_all(tasks) for i, outcome in ipairs(outcomes) do if not outcome.ok then ctx:fail("task " .. i .. " failed: " .. outcome.error) return end end ctx:complete(table.concat({ outcomes[1].value, outcomes[2].value, outcomes[3].value, outcomes[4].value[1], outcomes[4].value[2], }, ":")) end,}) clm.tool_register("concurrent_error", { description = "exercise independent task outcomes", params_schema = { type = "object" }, no_prompt = true, invoke = function(_, ctx) local tasks = { clm.spawn(function() clm.sleep(0) return "survived" end), clm.spawn(function() error("child boom") end), } local outcomes = clm.await_all(tasks) if not outcomes[1].ok or outcomes[1].value ~= "survived" then ctx:fail("await_all cancelled an independent sibling") return end if outcomes[2].ok or not outcomes[2].error:find("child boom", 1, true) then ctx:fail("await_all did not preserve the child error") return end ctx:complete(outcomes[1].value .. ":" .. outcomes[2].error) end,}) clm.tool_register("concurrent_try_error", { description = "exercise fail-fast task cancellation", params_schema = { type = "object" }, no_prompt = true, invoke = function(_, ctx) local tasks = { clm.spawn(function() clm.sleep(30000) return "too late" end), clm.spawn(function() error("try boom") end), } local results, err = clm.try_all(tasks) if results ~= nil then ctx:fail("try_all unexpectedly succeeded") return end local cancelled = tasks[1]:result() if cancelled == nil or not cancelled.cancelled then ctx:fail("try_all did not cancel the unfinished sibling") return end ctx:complete(err .. ":cancelled") end,}) clm.tool_register("wait_timeout_cancel", { description = "exercise wait timeout and explicit cancellation", params_schema = { type = "object" }, no_prompt = true, invoke = function(_, ctx) local task = clm.spawn(function() clm.sleep(30000) return "too late" end) local index, err = clm.wait_any({ task }, 0) if index ~= nil or err ~= "timeout" then ctx:fail("wait_any did not time out") return end if not task:cancel("test cancellation") then ctx:fail("task cancellation failed") return end if not task:cancel("ignored replacement") then ctx:fail("task cancellation was not idempotent") return end task:wait() local outcome = task:result() if outcome == nil or not outcome.cancelled or outcome.error ~= "test cancellation" then ctx:fail("cancelled task result is incorrect") return end ctx:complete("timeout:cancelled") end,}) clm.tool_register("complete_with_live_task", { description = "exercise completion with a live task", params_schema = { type = "object" }, no_prompt = true, invoke = function(_, ctx) clm.spawn(function() clm.sleep(30000) end) ctx:complete("must not succeed") end,}) clm.tool_register("complete_with_unobserved_error", { description = "exercise completion with an unobserved task error", params_schema = { type = "object" }, no_prompt = true, invoke = function(_, ctx) local task = clm.spawn(function() error("unobserved boom") end) task:wait() ctx:complete("must not succeed") end,}) clm.tool_register("unawaited_task", { description = "exercise abandoned task cancellation", params_schema = { type = "object" }, no_prompt = true, invoke = function() clm.spawn(function() while true do clm.sleep(30000) end end) end,})
clm.tool_register("concurrent_async", {
description = "exercise concurrent lua async operations",
params_schema = {
type = "object",
properties = {
get_url = { type = "string" },
post_url = { type = "string" },
},
required = { "get_url", "post_url" },
},
no_prompt = true,
invoke = function(args, ctx)
local started = 0
local tasks = {
clm.spawn(function()
started = started + 1
local response, err = http.get(args.get_url)
if response == nil then
error(err)
end
return response.body
end),
clm.spawn(function()
started = started + 1
local response, err = http.post(args.post_url, "{}")
if response == nil then
error(err)
end
return response.body
end),
clm.spawn(function()
started = started + 1
clm.sleep(0)
return "slept"
end),
clm.spawn(function()
started = started + 1
return "multi", "value"
end),
}
if started ~= 0 then
ctx:fail("spawn ran a task before returning")
return
end
if tasks[1]:result() ~= nil then
ctx:fail("pending task unexpectedly had a result")
return
end
local first, wait_err = clm.wait_any(tasks)
if first == nil then
ctx:fail(wait_err)
return
end
local first_outcome = tasks[first]:result()
if first_outcome == nil or not first_outcome.ok then
ctx:fail("wait_any returned an unsuccessful task")
return
end
local outcomes = clm.await_all(tasks)
for i, outcome in ipairs(outcomes) do
if not outcome.ok then
ctx:fail("task " .. i .. " failed: " .. outcome.error)
return
end
end
ctx:complete(table.concat({
outcomes[1].value,
outcomes[2].value,
outcomes[3].value,
outcomes[4].value[1],
outcomes[4].value[2],
}, ":"))
end,
})
clm.tool_register("concurrent_error", {
description = "exercise independent task outcomes",
params_schema = { type = "object" },
no_prompt = true,
invoke = function(_, ctx)
local tasks = {
clm.spawn(function()
clm.sleep(0)
return "survived"
end),
clm.spawn(function()
error("child boom")
end),
}
local outcomes = clm.await_all(tasks)
if not outcomes[1].ok or outcomes[1].value ~= "survived" then
ctx:fail("await_all cancelled an independent sibling")
return
end
if outcomes[2].ok or not outcomes[2].error:find("child boom", 1, true) then
ctx:fail("await_all did not preserve the child error")
return
end
ctx:complete(outcomes[1].value .. ":" .. outcomes[2].error)
end,
})
clm.tool_register("concurrent_try_error", {
description = "exercise fail-fast task cancellation",
params_schema = { type = "object" },
no_prompt = true,
invoke = function(_, ctx)
local tasks = {
clm.spawn(function()
clm.sleep(30000)
return "too late"
end),
clm.spawn(function()
error("try boom")
end),
}
local results, err = clm.try_all(tasks)
if results ~= nil then
ctx:fail("try_all unexpectedly succeeded")
return
end
local cancelled = tasks[1]:result()
if cancelled == nil or not cancelled.cancelled then
ctx:fail("try_all did not cancel the unfinished sibling")
return
end
ctx:complete(err .. ":cancelled")
end,
})
clm.tool_register("wait_timeout_cancel", {
description = "exercise wait timeout and explicit cancellation",
params_schema = { type = "object" },
no_prompt = true,
invoke = function(_, ctx)
local task = clm.spawn(function()
clm.sleep(30000)
return "too late"
end)
local index, err = clm.wait_any({ task }, 0)
if index ~= nil or err ~= "timeout" then
ctx:fail("wait_any did not time out")
return
end
if not task:cancel("test cancellation") then
ctx:fail("task cancellation failed")
return
end
if not task:cancel("ignored replacement") then
ctx:fail("task cancellation was not idempotent")
return
end
task:wait()
local outcome = task:result()
if outcome == nil or not outcome.cancelled or
outcome.error ~= "test cancellation" then
ctx:fail("cancelled task result is incorrect")
return
end
ctx:complete("timeout:cancelled")
end,
})
clm.tool_register("complete_with_live_task", {
description = "exercise completion with a live task",
params_schema = { type = "object" },
no_prompt = true,
invoke = function(_, ctx)
clm.spawn(function()
clm.sleep(30000)
end)
ctx:complete("must not succeed")
end,
})
clm.tool_register("complete_with_unobserved_error", {
description = "exercise completion with an unobserved task error",
params_schema = { type = "object" },
no_prompt = true,
invoke = function(_, ctx)
local task = clm.spawn(function()
error("unobserved boom")
end)
task:wait()
ctx:complete("must not succeed")
end,
})
clm.tool_register("unawaited_task", {
description = "exercise abandoned task cancellation",
params_schema = { type = "object" },
no_prompt = true,
invoke = function()
clm.spawn(function()
while true do
clm.sleep(30000)
end
end)
end,
})