Skip to content

feat(ui): allow to edit agent before importing#444

Merged
mudler merged 1 commit intomainfrom
feat/import-edit
Mar 4, 2026
Merged

feat(ui): allow to edit agent before importing#444
mudler merged 1 commit intomainfrom
feat/import-edit

Conversation

@mudler
Copy link
Owner

@mudler mudler commented Mar 4, 2026

No description provided.

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Copilot AI review requested due to automatic review settings March 4, 2026 17:36
@mudler mudler merged commit d9bf193 into main Mar 4, 2026
2 of 3 checks passed
@mudler mudler deleted the feat/import-edit branch March 4, 2026 17:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an “edit before import” flow for agents in the React UI and introduces guards/normalization to avoid sending assistant-final conversations that some backends (e.g., enable_thinking) reject.

Changes:

  • Web UI: Parse imported agent JSON client-side, show an editable AgentForm, then create the agent from edited data.
  • API: Reject “continue thread” requests (previous_response_id) that contain no new user/tool message.
  • Core agent: Normalize conversations that end with an assistant message by appending a whitespace user message.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
webui/react-ui/src/pages/ImportAgent.jsx Switches import workflow from uploading a file to parsing JSON, editing in AgentForm, and creating the agent.
webui/app.go Adds validation to prevent continuing a conversation without new input.
core/agent/agent.go Adds normalization to avoid requests ending with an assistant message for enable_thinking backends.
Comments suppressed due to low confidence (6)

webui/react-ui/src/pages/ImportAgent.jsx:81

  • Building the route with the raw agent name can break navigation when formData.name contains spaces or reserved URL characters (e.g., /, ?, #). Use encodeURIComponent(formData.name) when interpolating into the URL, or prefer navigating with an identifier returned by createAgent if available.
      await agentApi.createAgent(formData);
      showToast(`Agent "${formData.name}" imported successfully`, 'success');
      navigate(`/settings/${formData.name}`);

webui/react-ui/src/pages/ImportAgent.jsx:67

  • After going back to file selection, choosing the same file again may not fire onChange because the hidden file input’s value hasn’t changed. Consider clearing the input value after processing a file and/or in handleBack (typically via a ref), or force-remounting the input (e.g., with a key) so re-selecting the same file triggers parsing.
  const handleBack = () => {
    setShowForm(false);
    setFormData({});
  };

webui/react-ui/src/pages/ImportAgent.jsx:148

  • After going back to file selection, choosing the same file again may not fire onChange because the hidden file input’s value hasn’t changed. Consider clearing the input value after processing a file and/or in handleBack (typically via a ref), or force-remounting the input (e.g., with a key) so re-selecting the same file triggers parsing.
              <input
                type="file"
                id="fileInput"
                accept=".json"
                onChange={handleFileChange}
                style={{ display: 'none' }}
              />

webui/react-ui/src/pages/ImportAgent.jsx:117

  • The UI renders AgentForm even when metadata is still null (metadata is fetched asynchronously). If AgentForm relies on metadata being present, this can cause inconsistent rendering or runtime errors. Consider gating the form render until metadata is loaded (or providing a safe default shape + a loading state).
            <AgentForm
              formData={formData}
              setFormData={setFormData}
              onSubmit={handleSubmit}
              loading={loading}
              submitButtonText="Import Agent"
              isEdit={false}
              metadata={metadata}
            />

webui/app.go:602

  • The validation is conditioned on len(conv) > 0, so previous_response_id with no new messages will be allowed when conv is empty (e.g., missing/invalid conversation lookup), potentially resulting in an empty message list being sent downstream. Consider rejecting any request with previous_response_id != \"\" and len(newMessages) == 0 regardless of conv length (or explicitly validating that messages is non-empty).
		newMessages := request.ToChatCompletionMessages()
		messages := append(conv, newMessages...)

		// Continuing a thread (previous_response_id) without any new user/tool message causes
		// the job to end with an assistant message, which backends with enable_thinking reject.
		// Require at least one new message when continuing so we never send assistant-final conv.
		if previousResponseID != "" && len(conv) > 0 && len(newMessages) == 0 {
			return c.Status(http.StatusBadRequest).JSON(types.ResponseBody{
				Error: "previous_response_id was set but no new input was sent; send at least one user or tool message when continuing a conversation",
			})
		}

core/agent/agent.go:931

  • Appending a whitespace user message changes the conversation semantics (the model will respond to a blank user prompt) and can affect logs/analytics or downstream behavior. If the intent is strictly to avoid enable_thinking rejection, prefer a more explicit strategy (e.g., erroring when continuing without new input where possible, or using a clearly-defined sentinel message constant and documenting how it’s handled), rather than silently injecting a user message.
	if len(conv) > 0 && conv[len(conv)-1].Role == AssistantRole {
		conv = append(conv, openai.ChatCompletionMessage{
			Role:    UserRole,
			Content: " ",
		})
	}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants