Skip to content

feat(ai): Add the Agents view#91

Merged
nfebe merged 1 commit into
mainfrom
feat/agent-runtimes
Jul 23, 2026
Merged

feat(ai): Add the Agents view#91
nfebe merged 1 commit into
mainfrom
feat/agent-runtimes

Conversation

@nfebe

@nfebe nfebe commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Panel surface for agents (flatrun/agent#189: markdown files run as AI sessions by the runtime). Agents get their own section in the navigation. The list shows each agent with its scope; Run opens the assistant on the resulting session, so the transcript and any pending tool approvals are handled by the existing chat rather than a new surface. The empty state shows where the files live and an example within what the tools can actually do.

@sourceant

sourceant Bot commented Jul 23, 2026

Copy link
Copy Markdown

Code Review Summary

This PR adds the 'Agents' feature, allowing users to define and run markdown-based AI agents. It includes API service updates, navigation, and a comprehensive management view.

🚀 Key Improvements

  • New AgentsView for CRUD and execution of agents.
  • Integration of agent sessions into the main assistant UI.
  • Addition of agent metadata to AI session interfaces for better tracking.

💡 Minor Suggestions

  • Switch to Markdown syntax highlighting in the editor.
  • Add client-side regex validation for agent names.
  • Improve UX by opening the editor modal before fetching content.

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Comment thread src/views/RuntimesView.vue Outdated
<div class="runtime-title">
<Icon name="bot" :size="16" />
<h3>{{ rt.name }}</h3>
<span class="scope-badge" :class="rt.scope">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If rt.scope is 'deployment' but the deployment property is null or undefined, the badge will appear empty. Providing a fallback string ensures the UI remains descriptive.

Suggested change
<span class="scope-badge" :class="rt.scope">
<span class="scope-badge" :class="rt.scope">
{{ rt.scope === "deployment" ? (rt.deployment || "deployment") : "system" }}
</span>

@nfebe
nfebe force-pushed the feat/agent-runtimes branch from 6853127 to f405966 Compare July 23, 2026 12:36
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 23, 2026

Copy link
Copy Markdown

Deploying flatrun-ui with  Cloudflare Pages  Cloudflare Pages

Latest commit: 798fceb
Status: ✅  Deploy successful!
Preview URL: https://1d0f37cc.flatrun-ui.pages.dev
Branch Preview URL: https://feat-agent-runtimes.flatrun-ui.pages.dev

View logs

@nfebe nfebe changed the title feat(ai): Add the Agent Runtimes view feat(ai): Add the Agents view Jul 23, 2026

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Comment thread src/views/AgentsView.vue
<div class="agent-title">
<Icon name="bot" :size="16" />
<h3>{{ agent.name }}</h3>
<span class="scope-badge" :class="agent.scope">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If an agent's scope is 'deployment' but the deployment property is missing or null, the badge will appear empty. Providing a fallback string (similar to other views in the system) ensures the UI remains descriptive.

Suggested change
<span class="scope-badge" :class="agent.scope">
<span class="scope-badge" :class="agent.scope">
{{ agent.scope === "deployment" ? (agent.deployment || "deployment") : "system" }}
</span>

Comment thread src/views/AgentsView.vue
</div>
<div class="header-actions">
<button class="btn btn-icon" :disabled="loading" @click="fetchAgents">
<i class="pi pi-refresh" :class="{ 'pi-spin': loading }" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

For visual consistency across the application, consider using the project's custom Icon component instead of raw <i> tags with PrimeIcons classes where possible.

Suggested change
<i class="pi pi-refresh" :class="{ 'pi-spin': loading }" />
<Icon name="refresh" :class="{ 'pi-spin': loading }" :size="16" />

@nfebe
nfebe force-pushed the feat/agent-runtimes branch from f405966 to 3b2df84 Compare July 23, 2026 12:42

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Comment thread src/views/AgentsView.vue
</div>

<div v-if="loading && agents.length === 0" class="loading-state">
<i class="pi pi-spin pi-spinner" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

For consistency with other components in the application, use the custom Icon component for the loading spinner.

Suggested change
<i class="pi pi-spin pi-spinner" />
+ <Icon name="spinner" class="pi-spin" :size="20" />

Comment thread src/views/AgentsView.vue
const { data } = await agentsApi.run(agent.name);
// The run is a session; open the assistant on it so pending tool
// approvals and the transcript are handled by the existing chat.
assist.embedded = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It is generally better to perform the asynchronous data loading before making the assistant panel visible. This ensures that the UI doesn't display a stale or empty state if loadSession fails or takes time to complete.

Suggested change
assist.embedded = false;
+ await assist.loadSession(data.id);
+ assist.subject = agent.name;
+ assist.embedded = false;
+ assist.visible = true;

Agents get their own section in the navigation, aligned with the other
main menu items. The view lists each agent with its scope; Run opens the
assistant on the resulting session, so the transcript and any pending
tool approvals are handled in the existing chat.

Agents can now also be written in the panel: a New Agent editor with a
starter template, edit and delete on each card, and validation errors
surfaced on save so an invalid definition is never stored. Together with
the assistant's ability to write agent files on request, an agent can be
created by describing it in chat, by editing it in the panel, or by
dropping a file in the agents directory.
@nfebe
nfebe force-pushed the feat/agent-runtimes branch from 3b2df84 to 798fceb Compare July 23, 2026 13:06

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Comment thread src/views/AgentsView.vue
const authStore = useAuthStore();
const canWrite = computed(() => authStore.hasPermission("settings:write"));

const editorExtensions = [yaml(), oneDark];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Since agents are markdown files with instructions, using the markdown extension for Codemirror would provide better syntax highlighting for the body than the yaml extension, which is only strictly correct for the frontmatter section.

Suggested change
const editorExtensions = [yaml(), oneDark];
const editorExtensions = [markdown(), oneDark];

Comment thread src/views/AgentsView.vue
};

const saveAgent = async () => {
const name = editingName.value || nameInput.value.trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Validating the agent name on the client side provides immediate feedback and prevents unnecessary API calls that would fail with a 400 error. It ensures the name matches the constraints mentioned in the input placeholder.

Suggested change
const name = editingName.value || nameInput.value.trim();
const name = editingName.value || nameInput.value.trim();
const nameRegex = /^[a-zA-Z0-9._-]+$/;
if (!name || !nameRegex.test(name)) {
notifications.warning("Invalid name", "Name must only contain letters, digits, dots, dashes, and underscores");
return;
}

Comment thread src/views/AgentsView.vue
assistant's tools; anything that changes state waits for approval.
`;

const openEditor = async (agent: AgentDefinition | null) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The modal only opens after the content is successfully fetched. On slower connections, the UI feels unresponsive between clicking 'Edit' and the modal appearing. It's better to open the modal immediately and show a loading state inside the editor.

Suggested change
const openEditor = async (agent: AgentDefinition | null) => {
const openEditor = async (agent: AgentDefinition | null) => {
editingName.value = agent?.name ?? null;
nameInput.value = "";
editorContent.value = editorTemplate;
editorOpen.value = true;
if (agent) {
try {
const { data } = await agentsApi.get(agent.name);
editorContent.value = data.content;
} catch (err: any) {
notifications.error("Error", err.response?.data?.error || "Failed to load agent");
editorOpen.value = false;
}
}
};

@nfebe
nfebe merged commit f588d3d into main Jul 23, 2026
5 checks passed
@nfebe
nfebe deleted the feat/agent-runtimes branch July 23, 2026 13:22
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.

1 participant