| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- <script lang="ts">
- import { Card } from '$lib/components/common/card';
- import { Icon } from '$lib/components/common/icon';
- import { Button } from '$lib/components/controls/button';
- import * as Field from '$lib/components/controls/field';
- import { Input } from '$lib/components/controls/input';
- import { Spinner } from '$lib/components/controls/spinner';
- import { Textarea } from '$lib/components/controls/textarea';
- import { ArrayInput } from '$lib/components/forms/array-input';
- import { DeploymentForm } from '$lib/components/forms/deployment';
- import { IconPicker } from '$lib/components/forms/icon-picker';
- import { Optional } from '$lib/components/forms/optional';
- import { KBSelectDialog } from '$lib/components/kbs/select';
- import { ModelSelectDialog } from '$lib/components/models/select';
- import { ToolSelectDialog } from '$lib/components/tools/select';
- import type { KnowledgeBase, Model, Tool } from '$lib/types/entities';
- import { type AgentFormValue, DEFAULT_AGENT_FORM_VALUE } from './types';
- let {
- workspaceId,
- disabled = false,
- submitting = false,
- value,
- cancelHref,
- onsubmit,
- }: {
- workspaceId: string;
- disabled?: boolean;
- submitting?: boolean;
- value?: AgentFormValue;
- cancelHref: string;
- onsubmit: (value: AgentFormValue) => void;
- } = $props();
- const isEdit = $derived(value !== undefined);
- let form = $state<AgentFormValue>({ ...DEFAULT_AGENT_FORM_VALUE });
- let errors = $state<{
- name?: string;
- }>({});
- let modelSelectionShown = $state(false);
- let kbSelectionShown = $state(false);
- let toolSelectionShown = $state(false);
- const initForm = (value?: AgentFormValue) => {
- if (!value) {
- form = { ...DEFAULT_AGENT_FORM_VALUE };
- } else {
- form = {
- ...$state.snapshot(value),
- };
- }
- };
- $effect(() => initForm(value));
- const onModelSelect = (model: Model) => {
- form.model = { id: model.id, type: model.mode, icon: model.icon, name: model.name };
- modelSelectionShown = false;
- };
- const onKbSelect = (kbs: KnowledgeBase[]): KnowledgeBase[] => {
- form.kbs = kbs.map((kb) => ({ id: kb.id, type: kb.mode, icon: kb.icon, name: kb.name }));
- return kbs;
- };
- const onToolSelect = (tools: Tool[]): Tool[] => {
- form.tools = tools.map((tool) => ({
- id: tool.id,
- type: tool.mode,
- icon: tool.icon,
- name: tool.name,
- }));
- return tools;
- };
- const handleSubmit = async () => {
- onsubmit(form);
- };
- </script>
- {#snippet panel()}
- <div class="flex items-center gap-2">
- <Button href={cancelHref} size="sm" variant="outline">Cancel</Button>
- <Button disabled={submitting} size="sm" onclick={handleSubmit}>
- {#if submitting}
- <Spinner />
- {/if}
- {isEdit ? 'Save Changes' : 'Create'}
- </Button>
- </div>
- {/snippet}
- <div class="mx-auto max-w-2xl p-6">
- <!-- Page header -->
- <div class="mb-4 flex items-center justify-between gap-4">
- <div>
- <h1 class="text-xl font-semibold text-white/90">
- {isEdit ? 'Edit Agent' : 'New Agent'}
- </h1>
- </div>
- {@render panel()}
- </div>
- <!-- Basic Information panel (shared) -->
- <Card class="mb-4" title="Basic Information">
- <div class="mb-4 flex gap-8">
- <!-- Icon -->
- <div class="shrink-0">
- <IconPicker bind:value={form.icon} />
- </div>
- <!-- Name -->
- <div class="min-w-0 flex-1 space-y-4">
- <Field.Set>
- <Field.Field>
- <Field.Label for="name">Name</Field.Label>
- <Input id="name" maxlength={64} bind:value={form.name} />
- <Field.Error>{errors.name}</Field.Error>
- </Field.Field>
- <Field.Field>
- <Field.Label for="description">Description</Field.Label>
- <Textarea
- id="description"
- placeholder="What does this tool do?"
- rows={3}
- bind:value={form.description}
- />
- <Field.Description>
- Provide a brief description that can also help AI assistant to understand the agent's
- functionality.
- </Field.Description>
- </Field.Field>
- </Field.Set>
- </div>
- </div>
- <Optional title="Tags">
- <Field.Field>
- <ArrayInput {disabled} bind:value={form.tags} />
- <Field.Description>
- Tags can be used for filtering and searching in the list view.
- </Field.Description>
- </Field.Field>
- </Optional>
- </Card>
- <Card class="mb-4" title="Configuration">
- <Field.Set>
- <Field.Field>
- <Field.Label for="systemPrompt">System Prompt</Field.Label>
- <Textarea
- id="systemPrompt"
- placeholder="You are a helpful assistant..."
- rows={5}
- bind:value={form.systemPrompt}
- />
- </Field.Field>
- <Field.Field>
- <Field.Label>Language Model</Field.Label>
- <Field.Content>
- <div class="flex flex-wrap items-center gap-2">
- <Button size="sm" variant="outline" onclick={() => (modelSelectionShown = true)}>
- {#if form.model}
- <Icon icon={form.model.icon} size={14} />
- <div>{form.model.name}</div>
- {:else}
- Select model...
- {/if}
- </Button>
- </div>
- </Field.Content>
- </Field.Field>
- <Field.Field>
- <Field.Label>Tools</Field.Label>
- <Field.Content>
- <div class="flex flex-wrap items-center gap-2">
- {#each form.tools as tool (tool.id)}
- <Button size="sm" variant="outline" onclick={() => (toolSelectionShown = true)}>
- <Icon icon={tool.icon} size={14} />
- <div>{tool.name}</div>
- </Button>
- {:else}
- <Button size="sm" variant="outline" onclick={() => (toolSelectionShown = true)}>
- Select tools...
- </Button>
- {/each}
- </div>
- </Field.Content>
- </Field.Field>
- <Field.Field>
- <Field.Label>Knowledge Bases</Field.Label>
- <Field.Content>
- <div class="flex flex-wrap items-center gap-2">
- {#each form.kbs as kb (kb.id)}
- <Button size="sm" variant="outline" onclick={() => (kbSelectionShown = true)}>
- <Icon icon={kb.icon} size={14} />
- <div>{kb.name}</div>
- </Button>
- {:else}
- <Button size="sm" variant="outline" onclick={() => (kbSelectionShown = true)}>
- Select knowledge bases...
- </Button>
- {/each}
- </div>
- </Field.Content>
- </Field.Field>
- </Field.Set>
- </Card>
- <Card class="mb-4" title="Deployment">
- <Optional title="Runtime Settings">
- <DeploymentForm {disabled} bind:form />
- </Optional>
- </Card>
- <!-- Footer actions -->
- <div class="flex justify-end">
- {@render panel()}
- </div>
- </div>
- <ModelSelectDialog
- category="language"
- {workspaceId}
- bind:open={modelSelectionShown}
- onselect={(model) => onModelSelect(model)}
- />
- <KBSelectDialog {workspaceId} bind:open={kbSelectionShown} onselect={(kbs) => onKbSelect(kbs)} />
- <ToolSelectDialog
- {workspaceId}
- bind:open={toolSelectionShown}
- onselect={(tools) => onToolSelect(tools)}
- />
|