fix: 8531 - elicitation fixes (#8999)
Signed-off-by: Alex Hancock <alexhancock@block.xyz>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { ActionRequired } from '../api';
|
||||
import { defineMessages, useIntl } from '../i18n';
|
||||
import { Button } from './ui/button';
|
||||
import JsonSchemaForm from './ui/JsonSchemaForm';
|
||||
import type { JsonSchema } from './ui/JsonSchemaForm';
|
||||
|
||||
@@ -25,6 +26,10 @@ const i18n = defineMessages({
|
||||
id: 'elicitationRequest.submit',
|
||||
defaultMessage: 'Submit',
|
||||
},
|
||||
accept: {
|
||||
id: 'elicitationRequest.accept',
|
||||
defaultMessage: 'Accept',
|
||||
},
|
||||
waitingForResponse: {
|
||||
id: 'elicitationRequest.waitingForResponse',
|
||||
defaultMessage: 'Waiting for your response ({timeRemaining} remaining)',
|
||||
@@ -79,11 +84,19 @@ export default function ElicitationRequest({
|
||||
|
||||
const { id: elicitationId, message, requested_schema } = actionRequiredContent.data;
|
||||
|
||||
const schema = (requested_schema ?? {}) as JsonSchema;
|
||||
const hasSchemaFields = Boolean(schema.properties && Object.keys(schema.properties).length > 0);
|
||||
|
||||
const handleSubmit = (formData: Record<string, unknown>) => {
|
||||
setSubmitted(true);
|
||||
onSubmit(elicitationId, formData);
|
||||
};
|
||||
|
||||
const handleAccept = () => {
|
||||
setSubmitted(true);
|
||||
onSubmit(elicitationId, {});
|
||||
};
|
||||
|
||||
if (isCancelledMessage) {
|
||||
return (
|
||||
<div className="goose-message-content bg-background-secondary rounded-2xl px-4 py-2 text-text-primary">
|
||||
@@ -147,11 +160,19 @@ export default function ElicitationRequest({
|
||||
</div>
|
||||
</div>
|
||||
<div className="goose-message-content bg-background-primary border border-border-primary dark:border-gray-700 rounded-b-2xl px-4 py-3">
|
||||
<JsonSchemaForm
|
||||
schema={requested_schema as JsonSchema}
|
||||
onSubmit={handleSubmit}
|
||||
submitLabel={intl.formatMessage(i18n.submit)}
|
||||
/>
|
||||
{hasSchemaFields ? (
|
||||
<JsonSchemaForm
|
||||
schema={schema}
|
||||
onSubmit={handleSubmit}
|
||||
submitLabel={intl.formatMessage(i18n.submit)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex gap-2">
|
||||
<Button type="button" onClick={handleAccept}>
|
||||
{intl.formatMessage(i18n.accept)}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={`mt-3 pt-3 border-t border-border-primary flex items-center gap-2 text-sm ${isUrgent ? 'text-red-500' : 'text-text-secondary'}`}
|
||||
>
|
||||
@@ -169,7 +190,11 @@ export default function ElicitationRequest({
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>{intl.formatMessage(i18n.waitingForResponse, { timeRemaining: formatTime(timeRemaining) })}</span>
|
||||
<span>
|
||||
{intl.formatMessage(i18n.waitingForResponse, {
|
||||
timeRemaining: formatTime(timeRemaining),
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,12 @@ export default function GooseMessage({
|
||||
{thinkingContent && (
|
||||
<ThinkingContent
|
||||
content={thinkingContent}
|
||||
isExpanded={isStreaming && !displayText.trim() && imagePaths.length === 0 && toolRequests.length === 0}
|
||||
isExpanded={
|
||||
isStreaming &&
|
||||
!displayText.trim() &&
|
||||
imagePaths.length === 0 &&
|
||||
toolRequests.length === 0
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -283,7 +283,12 @@ export default function ProgressiveMessageList({
|
||||
{/* Loading indicator when progressively rendering */}
|
||||
{isLoading && (
|
||||
<div className="flex flex-col items-center justify-center py-8">
|
||||
<LoadingGoose message={intl.formatMessage(i18n.loadingMessages, { renderedCount, totalCount: messages.length })} />
|
||||
<LoadingGoose
|
||||
message={intl.formatMessage(i18n.loadingMessages, {
|
||||
renderedCount,
|
||||
totalCount: messages.length,
|
||||
})}
|
||||
/>
|
||||
<div className="text-xs text-text-secondary mt-2">
|
||||
{intl.formatMessage(i18n.searchHint)}
|
||||
</div>
|
||||
|
||||
@@ -82,6 +82,7 @@ export default function JsonSchemaForm({
|
||||
const [formData, setFormData] = useState<Record<string, unknown>>(() => {
|
||||
const initial: Record<string, unknown> = {};
|
||||
if (schema.properties) {
|
||||
const isRequired = (key: string) => schema.required?.includes(key) ?? false;
|
||||
for (const [key, prop] of Object.entries(schema.properties)) {
|
||||
if (prop.default !== undefined) {
|
||||
initial[key] = prop.default;
|
||||
@@ -89,6 +90,8 @@ export default function JsonSchemaForm({
|
||||
initial[key] = false;
|
||||
} else if (prop.type === 'number' || prop.type === 'integer') {
|
||||
initial[key] = prop.minimum ?? 0;
|
||||
} else if (prop.enum && prop.enum.length > 0 && isRequired(key)) {
|
||||
initial[key] = prop.enum[0];
|
||||
} else {
|
||||
initial[key] = '';
|
||||
}
|
||||
|
||||
@@ -897,15 +897,26 @@ export function useChatStream({
|
||||
return;
|
||||
}
|
||||
|
||||
// An elicitation response unblocks an in-flight tool call on the original
|
||||
// request's SSE stream — don't start a new stream or flip chat state.
|
||||
const responseMessage = createElicitationResponseMessage(elicitationId, userData);
|
||||
const currentMessages = [...currentState.messages, responseMessage];
|
||||
const nextMessages = [...currentState.messages, responseMessage];
|
||||
dispatch({ type: 'SET_MESSAGES', payload: nextMessages });
|
||||
|
||||
dispatch({ type: 'SET_MESSAGES', payload: currentMessages });
|
||||
dispatch({ type: 'START_STREAMING' });
|
||||
|
||||
await submitToSession(sessionId, responseMessage, currentMessages);
|
||||
try {
|
||||
await sessionReply({
|
||||
path: { id: sessionId },
|
||||
body: {
|
||||
request_id: uuidv7(),
|
||||
user_message: responseMessage,
|
||||
},
|
||||
throwOnError: true,
|
||||
});
|
||||
} catch (error) {
|
||||
onFinish('Submit error: ' + errorMessage(error));
|
||||
}
|
||||
},
|
||||
[sessionId, submitToSession]
|
||||
[sessionId, onFinish]
|
||||
);
|
||||
|
||||
const setRecipeUserParams = useCallback(
|
||||
|
||||
@@ -899,6 +899,9 @@
|
||||
"dirSwitcher.failedToUpdateWorkingDir": {
|
||||
"defaultMessage": "Failed to update working directory"
|
||||
},
|
||||
"elicitationRequest.accept": {
|
||||
"defaultMessage": "Accept"
|
||||
},
|
||||
"elicitationRequest.cancelled": {
|
||||
"defaultMessage": "Information request was cancelled."
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user