Skip to content

Commit 183c1f7

Browse files
committed
Allow adding input fields for tools
1 parent a32611d commit 183c1f7

File tree

4 files changed

+59
-17
lines changed

4 files changed

+59
-17
lines changed

llmstack/client/src/components/apps/AppInputSchemaEditor.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ export default function AppInputSchemaEditor({
129129
return (
130130
<Container>
131131
<Typography mb={3} style={{ margin: 10 }}>
132-
Define the input fields you want this app to accept. These will be
133-
rendered as a form for users to fill out. If using the app via the API,
134-
the input fields will form the JSON schema for the input data.
132+
{props?.message
133+
? props.message
134+
: "Define the input fields you want this app to accept. These will be rendered as a form for users to fill out. If using the app via the API, the input fields will form the JSON schema for the input data."}
135135
</Typography>
136136
<Table
137137
sx={{

llmstack/client/src/components/apps/ProcessorEditor.jsx

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
Typography,
99
} from "@mui/material";
1010
import validator from "@rjsf/validator-ajv8";
11-
import { lazy, useEffect, useState } from "react";
11+
import { lazy, useEffect, useRef, useState } from "react";
1212
import { useRecoilValue } from "recoil";
1313
import { useValidationErrorsForAppComponents } from "../../data/appValidation";
1414
import { appsState } from "../../data/atoms";
@@ -18,6 +18,7 @@ const ThemedJsonForm = lazy(() => import("../ThemedJsonForm"));
1818
const AppSelector = lazy(() => import("./AppSelector"));
1919
const AppStepCard = lazy(() => import("./AppStepCard"));
2020
const TextFieldWithVars = lazy(() => import("./TextFieldWithVars"));
21+
const AppInputSchemaEditor = lazy(() => import("./AppInputSchemaEditor"));
2122

2223
function PromptlyAppStepCard({
2324
appId,
@@ -195,6 +196,7 @@ export function ProcessorEditor({
195196
const processor = processors[index];
196197
const apiBackend = processor?.api_backend;
197198
const [errors, setErrors] = useState([]);
199+
const inputFields = useRef(processor?.input_fields || []);
198200

199201
useEffect(() => {
200202
let newErrors = [];
@@ -309,6 +311,33 @@ export function ProcessorEditor({
309311
}
310312
>
311313
<CardContent style={{ maxHeight: 400, overflow: "auto" }}>
314+
{isTool && (
315+
<Accordion defaultExpanded={inputFields.length > 0}>
316+
<AccordionSummary
317+
expandIcon={<ExpandMoreIcon />}
318+
aria-controls="input-fields-content"
319+
id="input-fields-header"
320+
style={{ backgroundColor: "#dce8fb" }}
321+
className="app-editor-section-header"
322+
>
323+
Input Fields
324+
</AccordionSummary>
325+
<AccordionDetails>
326+
<AppInputSchemaEditor
327+
fields={inputFields.current}
328+
setFields={(fields) => {
329+
inputFields.current = fields;
330+
processors[index].input_fields = fields;
331+
setProcessors([...processors]);
332+
}}
333+
setErrors={setErrors}
334+
message={
335+
"Define the input fields you want to expose to the model. You must use these fields as input to the processor with template variables."
336+
}
337+
/>
338+
</AccordionDetails>
339+
</Accordion>
340+
)}
312341
<Accordion defaultExpanded={true}>
313342
<AccordionSummary
314343
expandIcon={<ExpandMoreIcon />}
@@ -388,8 +417,8 @@ export function ProcessorEditor({
388417
<Accordion defaultExpanded={true}>
389418
<AccordionSummary
390419
expandIcon={<ExpandMoreIcon />}
391-
aria-controls="config-content"
392-
id="config-header"
420+
aria-controls="output-template-content"
421+
id="output-template-header"
393422
style={{ backgroundColor: "#dce8fb" }}
394423
className="app-editor-section-header"
395424
>

llmstack/client/src/pages/AppConsole.jsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
Tooltip,
2121
} from "@mui/material";
2222
import { enqueueSnackbar } from "notistack";
23-
import { useEffect, useState } from "react";
23+
import { useCallback, useEffect, useState } from "react";
2424
import { useNavigate, useParams } from "react-router-dom";
2525
import { useRecoilValue } from "recoil";
2626
import { ReactComponent as CodeIcon } from "../assets/images/icons/code.svg";
@@ -348,6 +348,7 @@ export default function AppConsolePage(props) {
348348
processor.api_backend?.slug || processor.processor_slug,
349349
config: processor.config,
350350
input: processor.input,
351+
input_fields: processor.input_fields || [],
351352
output_template: processor.output_template || {},
352353
})),
353354
};
@@ -371,6 +372,18 @@ export default function AppConsolePage(props) {
371372
});
372373
};
373374

375+
const setProcessorsCallback = useCallback(
376+
(newProcessors) => {
377+
setApp((app) => ({
378+
...app,
379+
processors: newProcessors,
380+
data: { ...app.data, processors: newProcessors },
381+
}));
382+
setProcessors(newProcessors);
383+
},
384+
[setApp, setProcessors],
385+
);
386+
374387
return isLoading ? (
375388
<CircularProgress />
376389
) : (
@@ -663,14 +676,7 @@ export default function AppConsolePage(props) {
663676
{selectedMenuItem === "editor" && (
664677
<AppEditor
665678
processors={processors}
666-
setProcessors={(newProcessors) => {
667-
setApp((app) => ({
668-
...app,
669-
processors: newProcessors,
670-
data: { ...app.data, processors: newProcessors },
671-
}));
672-
setProcessors(newProcessors);
673-
}}
679+
setProcessors={setProcessorsCallback}
674680
appConfig={{
675681
layout:
676682
app?.data?.type_slug === "web"

llmstack/processors/providers/api_processor_interface.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
)
1717
from llmstack.common.blocks.base.schema import BaseSchema as _Schema
1818
from llmstack.common.utils.liquid import render_template
19+
from llmstack.common.utils.utils import get_tool_json_schema_from_input_fields
1920
from llmstack.play.actor import Actor, BookKeepingData
2021
from llmstack.play.actors.agent import ToolInvokeInput
2122
from llmstack.play.utils import extract_jinja2_variables
@@ -239,6 +240,9 @@ def get_output_ui_schema(cls) -> dict:
239240

240241
@classmethod
241242
def get_tool_input_schema(cls, processor_data) -> dict:
243+
if processor_data and "input_fields" in processor_data:
244+
return get_tool_json_schema_from_input_fields(name="", input_fields=processor_data["input_fields"])
245+
242246
return json.loads(cls.get_input_schema())
243247

244248
@classmethod
@@ -392,19 +396,20 @@ def tool_invoke_input(self, tool_args: dict) -> ToolInvokeInput:
392396
)
393397

394398
def invoke(self, message: ToolInvokeInput) -> Any:
399+
self._base_input = self._input
395400
try:
396401
self._input = (
397402
hydrate_input(
398403
self._input,
399-
message.input,
404+
{**message.input, **message.tool_args},
400405
)
401406
if message
402407
else self._input
403408
)
404409
self._config = (
405410
hydrate_input(
406411
self._config,
407-
message.input,
412+
{**message.input, **message.tool_args},
408413
)
409414
if self._config
410415
else self._config
@@ -446,6 +451,8 @@ def invoke(self, message: ToolInvokeInput) -> Any:
446451

447452
self._output_stream.bookkeep(bookkeeping_data)
448453

454+
self._input = self._base_input
455+
449456
def input_stream(self, message: Any) -> Any:
450457
# We do not support input stream for this processor
451458
pass

0 commit comments

Comments
 (0)