1mod session;
2
3use project::Project;
4use session::*;
5
6use assistant_tool::{Tool, ToolRegistry};
7use gpui::{App, AppContext as _, Entity, Task};
8use schemars::JsonSchema;
9use serde::Deserialize;
10use std::sync::Arc;
11
12pub fn init(cx: &App) {
13 let registry = ToolRegistry::global(cx);
14 registry.register_tool(ScriptingTool);
15}
16
17#[derive(Debug, Deserialize, JsonSchema)]
18struct ScriptingToolInput {
19 lua_script: String,
20}
21
22struct ScriptingTool;
23
24impl Tool for ScriptingTool {
25 fn name(&self) -> String {
26 "lua-interpreter".into()
27 }
28
29 fn description(&self) -> String {
30 include_str!("scripting_tool_description.txt").into()
31 }
32
33 fn input_schema(&self) -> serde_json::Value {
34 let schema = schemars::schema_for!(ScriptingToolInput);
35 serde_json::to_value(&schema).unwrap()
36 }
37
38 fn run(
39 self: Arc<Self>,
40 input: serde_json::Value,
41 project: Entity<Project>,
42 cx: &mut App,
43 ) -> Task<anyhow::Result<String>> {
44 let input = match serde_json::from_value::<ScriptingToolInput>(input) {
45 Err(err) => return Task::ready(Err(err.into())),
46 Ok(input) => input,
47 };
48
49 // TODO: Store a session per thread
50 let session = cx.new(|cx| ScriptSession::new(project, cx));
51 let lua_script = input.lua_script;
52
53 let (script_id, script_task) =
54 session.update(cx, |session, cx| session.run_script(lua_script, cx));
55
56 cx.spawn(|cx| async move {
57 script_task.await;
58
59 let message = session.read_with(&cx, |session, _cx| {
60 // Using a id to get the script output seems impractical.
61 // Why not just include it in the Task result?
62 // This is because we'll later report the script state as it runs,
63 // currently not supported by the `Tool` interface.
64 session
65 .get(script_id)
66 .output_message_for_llm()
67 .expect("Script shouldn't still be running")
68 })?;
69
70 drop(session);
71 Ok(message)
72 })
73 }
74}