Skip to content

Commit ac7000f

Browse files
Allow response definition when using assistant
1 parent f97994a commit ac7000f

File tree

9 files changed

+90
-14
lines changed

9 files changed

+90
-14
lines changed

docs/src/main/asciidoc/assistant.adoc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,24 @@ You can add an assistant function to a workspace item using the same approach as
145145
.systemMessage(JOKE_SYSTEM_MESSAGE) // <2>
146146
.userMessage(JOKE_USER_MESSAGE) // <3>
147147
.variables(params)
148+
.responseType(ExpectedResponse.class) // <4>
148149
.assist();
149150
150151
})
151152
.display(Display.split)
152153
.displayType(DisplayType.markdown)
153154
.filter(Patterns.JAVA_SRC));
155+
156+
157+
//...
158+
159+
final record ExpectedResponse(String result, String markdown) {
160+
}
154161
----
155162
<1> Use `assistantFunction` to receive the `Assistant` instance and xref:dev-ui.adoc#input[input] parameters.
156163
<2> Provide an optional *system message* to guide the assistant's behavior.
157164
<3> Provide a *user message* as the primary prompt.
165+
<4> Provide a class defining your expected response structure.
158166

159167
=== Assistant pages
160168

@@ -203,11 +211,16 @@ You can now use this assistant in any JsonRPC method, example:
203211
if (assistant.isPresent()) {
204212
return assistant.get().assistBuilder()
205213
.userMessage("Tell me a funny joke")
214+
.responseType(JokeResponse.class) // <1>
206215
.assist();
207216
}
208217
return CompletableFuture.failedStage(new RuntimeException("Assistant is not available"));
209218
}
219+
220+
//...
221+
final record JokeResponse(String joke) {}
210222
----
223+
<1> Provide a class defining your expected response structure.
211224

212225
==== JsonRPC against the Deployment classpath
213226

@@ -235,11 +248,16 @@ Then use the `BuildTimeActionBuildItem` and register assistant actions via `.add
235248
return assistant.assistBuilder()
236249
.userMessage(USER_MESSAGE)
237250
.variables(p)
251+
.responseType(JokeResponse.class) // <2>
238252
.assist();
239253
}).build());
240254
buildTimeActionProducer.produce(bta);
255+
256+
//...
257+
final record JokeResponse(String joke) {}
241258
----
242259
<1> Use `assistantFunction` instead of `function` to access the assistant context.
260+
<2> Provide a class defining your expected response structure.
243261

244262
=== Assistant State in the UI
245263

@@ -312,13 +330,18 @@ AssistantConsoleBuildItem createCliAssistantEntry() {
312330
.function((a) -> {
313331
return a.assistBuilder()
314332
.userMessage("Tell a funny joke")
333+
.responseType(JokeResponse.class) // <3>
315334
.assist();
316335
})
317336
.build();
318337
}
338+
//...
339+
final record JokeResponse(String joke) {}
340+
319341
----
320342
<1> This is the description that appears in the Assistant section of the log menu.
321343
<2> This is the keyboard shortcut that triggers the assistant function.
344+
<3> Provide a class defining your expected response structure.
322345

323346
When added, this will result in a new entry under the `Assistant` heading in the log shortcut menu:
324347

extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void createBuildTimeActions(BuildProducer<BuildTimeActionBuildItem> buildTimeAct
4747
return assistant.assistBuilder()
4848
.userMessage(ADD_DATA_MESSAGE)
4949
.variables(p)
50+
.responseType(MoreDataResponse.class)
5051
.assist();
5152
}).build();
5253

@@ -63,7 +64,10 @@ JsonRPCProvidersBuildItem createJsonRPCService() {
6364
Given the provided sql script:
6465
{{currentInsertScript}}
6566
Can you add 10 more inserts into the script and return the result
66-
(including the provided entries, so update the script)
67-
Return the result in a field called `script`.
67+
(including the provided entries, so update the script) in the script field.
6868
""";
69+
70+
final record MoreDataResponse(String script) {
71+
}
72+
6973
}

extensions/agroal/runtime-dev/src/main/java/io/quarkus/agroal/runtime/dev/ui/DatabaseInspector.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ public CompletionStage<Map<String, String>> generateTableData(String datasource,
365365
if (matchingTable.isPresent()) {
366366
return assistant.get().assistBuilder()
367367
.userMessage(generateInsertPrompt(matchingTable.get(), rowCount))
368+
.responseType(InsertStatementResponse.class)
368369
.assist();
369370
}
370371
}
@@ -377,6 +378,7 @@ public CompletionStage<Map<String, String>> englishToSQL(String datasource, Stri
377378

378379
return assistant.get().assistBuilder()
379380
.userMessage(englishToSqlPrompt(tables, schema, name, english))
381+
.responseType(EnglishToSQLResponse.class)
380382
.assist();
381383

382384
}
@@ -509,7 +511,7 @@ private boolean isBinary(int dataType) {
509511

510512
private String englishToSqlPrompt(List<Table> tables, String schema, String name, String english) {
511513
StringBuilder sb = new StringBuilder();
512-
sb.append("Generate valid SQL given the following english statement: ")
514+
sb.append("Generate valid SQL given the following english statement: \n")
513515
.append(english)
514516
.append("\n\nAnd this is the known tables in the database:\n");
515517

@@ -606,4 +608,10 @@ private static record Datasource(String name, String jdbcUrl, boolean isDefault)
606608
private static record DataSet(List<String> cols, List<Map<String, String>> data, String error, String message,
607609
int totalNumberOfElements) {
608610
}
611+
612+
final record EnglishToSQLResponse(String sql, String error) {
613+
}
614+
615+
final record InsertStatementResponse(String script) {
616+
}
609617
}

extensions/assistant/runtime-dev/src/main/java/io/quarkus/assistant/runtime/dev/Assistant.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ <T> CompletionStage<T> exception(Optional<String> systemMessage, String userMess
4545
*/
4646
<T> CompletionStage<T> assist(Optional<String> systemMessageTemplate,
4747
String userMessageTemplate,
48-
Map<String, String> variables, List<Path> paths);
48+
Map<String, String> variables, List<Path> paths, Class<?> responseType);
4949

5050
default ExceptionBuilder exceptionBuilder() {
5151
return new ExceptionBuilder(this);
@@ -62,6 +62,7 @@ class AssistBuilder {
6262
private String userMessage;
6363
private final Map<String, String> variables = new LinkedHashMap<>();
6464
private final List<Path> paths = new ArrayList<>();
65+
private Class<?> responseType = null;
6566

6667
AssistBuilder(Assistant assistant) {
6768
this.assistant = assistant;
@@ -105,12 +106,19 @@ public AssistBuilder addPath(Path path) {
105106
return this;
106107
}
107108

109+
public AssistBuilder responseType(Class<?> responseType) {
110+
if (responseType != null) {
111+
this.responseType = responseType;
112+
}
113+
return this;
114+
}
115+
108116
@SuppressWarnings("unchecked")
109117
public <T> CompletionStage<T> assist() {
110-
if (userMessage == null || userMessage.isBlank()) {
118+
if (null == userMessage || userMessage.isBlank()) {
111119
throw new IllegalStateException("User message is required");
112120
}
113-
return (CompletionStage<T>) assistant.assist(systemMessage, userMessage, variables, paths);
121+
return (CompletionStage<T>) assistant.assist(systemMessage, userMessage, variables, paths, responseType);
114122
}
115123
}
116124

extensions/devui/resources/src/main/resources/dev-ui/qwc/qwc-workspace.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,15 @@ export class QwcWorkspace extends observeState(QwcHotReloadElement) {
512512
}
513513
this._showActionProgress = false;
514514
document.body.style.cursor = 'default';
515+
}).catch((err) => {
516+
console.error(err);
517+
this._showActionProgress = false;
518+
document.body.style.cursor = 'default';
519+
if(err.error.message){
520+
notifier.showErrorMessage(err.message + ". Please check your logs.");
521+
}else {
522+
notifier.showErrorMessage("An error occured. Please check your logs.");
523+
}
515524
});
516525
}
517526

extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/devui/SchedulerDevUIProcessor.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ void createBuildTimeActions(BuildProducer<BuildTimeActionBuildItem> buildTimeAct
5454
return assistant.assistBuilder()
5555
.userMessage(INTERPRET_CRON)
5656
.variables(p)
57+
.responseType(InterpretResponse.class)
5758
.assist();
5859
}).build();
5960

@@ -65,6 +66,7 @@ void createBuildTimeActions(BuildProducer<BuildTimeActionBuildItem> buildTimeAct
6566
return assistant.assistBuilder()
6667
.userMessage(CREATE_CRON)
6768
.variables(p)
69+
.responseType(CronResponse.class)
6870
.assist();
6971
}).build();
7072

@@ -77,15 +79,20 @@ JsonRPCProvidersBuildItem rpcProvider() {
7779
}
7880

7981
private static final String INTERPRET_CRON = """
80-
Can you please interpret this cron and describe it in plain English. Reply in markdown format in a field called markdown.
82+
Can you please interpret this cron and describe it in plain English. Reply in markdown format in the markdown field.
8183
8284
Here is the cron: {{cron}}
8385
""";
8486

8587
private static final String CREATE_CRON = """
8688
Can you create a valid cron expression for the following description: {{description}}
8789
88-
Reply with the valid cron in a field called cron. Add an example on how to use this with the quarkus-scheduler extenion in a field called example. For the example please use markdown.
90+
Reply with the valid cron in the cron field. Add an example in markdown format on how to use this with the quarkus-scheduler extension in the markdown field.
8991
""";
9092

93+
final record InterpretResponse(String markdown) {
94+
}
95+
96+
final record CronResponse(String cron, String markdown) {
97+
}
9198
}

extensions/scheduler/deployment/src/main/resources/dev-ui/qwc-scheduler-cron-builder.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,8 @@ export class QwcSchedulerCronBuilder extends LitElement {
119119
this._createCronLoading = false;
120120
document.body.style.cursor = 'default';
121121
this._cron = jsonResponse.result.cron;
122-
this._example = jsonResponse.result.example;
122+
this._example = jsonResponse.result.markdown;
123123
});
124124
}
125-
126-
127-
128125
}
129126
customElements.define('qwc-scheduler-cron-builder', QwcSchedulerCronBuilder);

extensions/smallrye-graphql/runtime-dev/src/main/java/io/quarkus/smallrye/graphql/runtime/dev/GraphQLJsonRpcService.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,35 @@ public CompletionStage<Map<String, String>> generateClient(String language, Stri
4141
.addVariable("schemaDocument", schemaDocument)
4242
.addVariable("language", language)
4343
.addVariable("extraContext", extraContext)
44+
.responseType(GraphQLClientResponse.class)
4445
.assist();
4546
}
4647
return CompletableFuture.failedStage(new RuntimeException("Assistant is not available"));
4748
}
4849

4950
private static final String USER_MESSAGE = """
5051
Given the GraphQL Schema document :
52+
53+
```json
5154
{{schemaDocument}}
55+
```
56+
5257
Please generate a {{language}} Object that act as a client to all the operations in the schema.
5358
This {{language}} code must be able to be called like this (pseudo code):
59+
5460
```
5561
var stub = new ResourceNameHereClient();
5662
var response = stub.doOperation(someparam);
5763
```
64+
5865
Your reponse should only contain one field called `code` that contains a value with only the {{language}} code, nothing else, no explanation, and do not put the code in backticks.
5966
The {{language}} code must run and be valid.
60-
Example response: {code: 'package foo.bar; // more code here'}
67+
68+
Example response: `{code: 'package foo.bar; // more code here'}`
6169
6270
{{extraContext}}
6371
""";
6472

73+
final record GraphQLClientResponse(String code) {
74+
}
6575
}

extensions/smallrye-openapi/runtime-dev/src/main/java/io/quarkus/smallrye/openapi/runtime/dev/OpenApiJsonRpcService.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,22 @@ public CompletionStage<Map<String, String>> generateClient(String language, Stri
3636
.addVariable("schemaDocument", schemaDocument)
3737
.addVariable("language", language)
3838
.addVariable("extraContext", extraContext)
39+
.responseType(OpenApiClientResponse.class)
3940
.assist();
4041
}
4142
return CompletableFuture.failedStage(new RuntimeException("Assistant is not available"));
4243
}
4344

4445
private static final String USER_MESSAGE = """
4546
Given the OpenAPI Schema document :
47+
48+
```json
4649
{{schemaDocument}}
50+
```
51+
4752
Please generate a {{language}} Object that act as a client to all the operations in the schema.
4853
This {{language}} code must be able to be called like this (pseudo code):
54+
4955
```
5056
var stub = new ResourceNameHereClient();
5157
var response = stub.doOperation(someparam);
@@ -54,8 +60,12 @@ public CompletionStage<Map<String, String>> generateClient(String language, Stri
5460
Don't use ResourceNameHereClient as the name for the generated code (it's just an example). Derive a sensible name from the schema provided.
5561
Your reponse should only contain one field called `code` that contains a value with only the {{language}} code, nothing else, no explanation, and do not put the code in backticks.
5662
The {{language}} code must run and be valid.
57-
Example response: {code: 'package foo.bar; // more code here'}
63+
64+
Example response: `{code: 'package foo.bar; // more code here'}`
5865
5966
{{extraContext}}
6067
""";
68+
69+
final record OpenApiClientResponse(String code) {
70+
}
6171
}

0 commit comments

Comments
 (0)