mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 08:02:18 +00:00
* feat(frontend): group the AI agent step form and edit saved agents in a modal Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: edit a saved AI agent through its own resource draft Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: drop the agent fork-for-edit session now that edits live in a draft Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: edit ai_agent resources from the resources page with the agent editor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: send a standalone agent's brain from the module when testing a step Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep the agent draft faithful to the resource it deploys to Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore: add the sqlx cache entry for the eval subject rename Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: share the module insert between the graph and the agent editor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): open evals inside the agent editor, actions in its header Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): add tools from the agent editor and lighten its test pane Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): open an ai_agent deep link in the agent editor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): drop the failed result badge on a step that never ran Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): head the agent editor's levels with a back control Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): drop connect and fill inputs from the agent editor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): lighten the agent editor's run panel Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): stop a nested agent tool's config reading as AI-filled Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): offer only AI or static on an agent tool's inputs Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): give a saved agent's tool editor a static-only surface Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): open an agent tool in a drawer beside the agent Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(frontend): hide unset agent config in the run form Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(frontend): share the input forms' pickers and s3 lookup Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(frontend): drop a dead agent-editor export and fix two stale comments Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): reach an ai_agent's resource-level settings and copilot Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): open an ai_agent's resource view as JSON, not the generic form Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): address review findings on the agent editor's draft and streaming Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): close the agent editor on a version restore, as the resource editor does Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): stop the provider picker auto-writing a kind, and clear review nits Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(frontend): drop the fork-for-edit leftovers from the agent card Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): mount the agent editor in the dev flow editor and guard the deep-link race Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): deploy the agent config that was submitted, and refuse one no run could use Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(frontend): build the agent editor's rows from the design-system button Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): keep a draft-only agent's draft, and let a blank MCP summary deploy Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): guard read-only agents, incomplete MCP tools and duplicate editor mounts Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: read-only agent editor, linked-card refresh, atomic eval rename * fix: eval rename needs the privileged pool, per-workspace write access * fix(frontend): drop the agent editor target when its mount goes away * refactor: drop the agent rename work from this PR, unban the bindable defaults * fix(frontend): refuse a renaming deploy and drop the copilot from static-only fields * fix(frontend): mirror the worker's streaming rule and scope agent writes to their target * fix(frontend): read runtime streaming as off and reset the drawer's json view * fix(frontend): read an unsettled output_type as non-streaming too * fix(frontend): let the showing modal claim an agent opened from inside it * fix(frontend): keep in-flight edits, tool replacements and every linked step in sync * fix(frontend): keep attachments in the run form and bind the agent ref to its tools * fix(frontend): preview the agent as authored and re-evaluate step args on run * fix(frontend): scope agent-editor ownership to the flow's workspace * fix(frontend): drop the tool drill-in where there is no graph to select on * fix(frontend): require a provider kind and keep one resource editor open at a time * fix(frontend): keep legacy nulls, static-only text literal, and the handover anchor * test(worker): pin the agent streaming default * fix(frontend): let an AI-fillable input be switched to static * fix(frontend): report agent editor background failures instead of floating them * fix(frontend): keep the version pane's path alive while the editor closes * fix(frontend): clear the anchor-keep flag at the start of each drawer session * fix(frontend): preview the agent without its synthetic path, refresh the baseline on external writes * refactor(frontend): drop the unverifiable baseline refresh, state the synthetic-path rule * fix(frontend): keep the synthetic path out of agent tool test runs too * refactor(frontend): host the agent editor under the agent's own path * fix(frontend): mark an agent editor's host explicitly instead of inferring it from the path * fix(frontend): discard linked-agent responses from before a deploy * fix(frontend): keep a flow mount from claiming an agent editor's nested target * feat(frontend): keep an agent used as a tool inside the agent being edited * fix(frontend): reserve the agent editor's root module id * docs(frontend): record why the agent editor previews under the agent's path * fix(frontend): refuse to open or deploy a resource that is not an agent * docs(frontend): put the scope-migration comment on the function it describes * fix(frontend): refuse an agent path whose resource type is not proven * fix(frontend): recheck the resource type before deploying, and keep expressions off static-only inputs * fix(frontend): lazy-load the agent editor and slide its levels like the evals pane * refactor: drop unreachable non-list tools check from agent deploy Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): clear text-only agent fields on image output, reserve the root id Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): keep the agent editor usable for a non-list tools value Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): stop the parked eval run list from taking arrow keys Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): report a non-list tools value on deploy instead of throwing Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): keep temperature editable for image output Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): skip non-object tool entries when rendering an agent Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): guard tool entry reads instead of copying the tool array Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(frontend): key tool rows by position so duplicate ids render Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
163 lines
4.8 KiB
Svelte
163 lines
4.8 KiB
Svelte
<script lang="ts">
|
|
import type { Schema } from '$lib/common'
|
|
import { type InputTransform } from '$lib/gen'
|
|
import { workspaceStore } from '$lib/stores'
|
|
import { allTrue, type DynamicInput as DynamicInputTypes } from '$lib/utils'
|
|
import { untrack } from 'svelte'
|
|
import StepInputsGen from './copilot/StepInputsGen.svelte'
|
|
import type { PickableProperties } from './flows/previousResults'
|
|
import InputTransformForm from './InputTransformForm.svelte'
|
|
import InputTransformPickers from './InputTransformPickers.svelte'
|
|
import { useS3StorageConfigured } from './inputTransformEnv.svelte'
|
|
import type ItemPicker from './ItemPicker.svelte'
|
|
import type VariableEditor from './VariableEditor.svelte'
|
|
import ResizeTransitionWrapper from './common/ResizeTransitionWrapper.svelte'
|
|
|
|
interface Props {
|
|
schema: Schema | { properties?: Record<string, any> }
|
|
args?: Record<string, InputTransform | any>
|
|
isValid?: boolean
|
|
extraLib?: string
|
|
previousModuleId?: string | undefined
|
|
filter?: string[] | undefined
|
|
noDynamicToggle?: boolean
|
|
/** Passed to every field. See `InputTransformForm` for what each one drops. */
|
|
noConnect?: boolean
|
|
noJavascript?: boolean
|
|
pickableProperties?: PickableProperties | undefined
|
|
enableAi?: boolean
|
|
class?: string
|
|
helperScript?: DynamicInputTypes.HelperScript
|
|
isAgentTool?: boolean
|
|
allowedAiTransforms?: string[] | undefined
|
|
chatInputEnabled?: boolean
|
|
workspace?: string | undefined
|
|
}
|
|
|
|
let {
|
|
schema = $bindable(),
|
|
args = $bindable({}),
|
|
isValid = $bindable(true),
|
|
extraLib = $bindable('missing extraLib'),
|
|
previousModuleId = undefined,
|
|
filter = undefined,
|
|
noDynamicToggle = false,
|
|
noConnect = false,
|
|
noJavascript = false,
|
|
pickableProperties = undefined,
|
|
enableAi = false,
|
|
class: clazz = '',
|
|
helperScript = undefined,
|
|
isAgentTool = false,
|
|
allowedAiTransforms = isAgentTool ? undefined : [],
|
|
chatInputEnabled = false,
|
|
workspace
|
|
}: Props = $props()
|
|
|
|
let ws = $derived(workspace ?? $workspaceStore)
|
|
|
|
let inputCheck: { [id: string]: boolean } = $state({})
|
|
|
|
$effect(() => {
|
|
isValid = allTrue(inputCheck) ?? false
|
|
})
|
|
|
|
$effect(() => {
|
|
if (args == undefined || typeof args !== 'object') {
|
|
args = {}
|
|
}
|
|
})
|
|
|
|
export function setArgs(nargs: Record<string, InputTransform | any>) {
|
|
args = nargs
|
|
}
|
|
|
|
function removeExtraKey() {
|
|
const nargs = {}
|
|
Object.keys(args ?? {}).forEach((key) => {
|
|
if (keys.includes(key)) {
|
|
nargs[key] = args[key]
|
|
}
|
|
})
|
|
args = nargs
|
|
}
|
|
|
|
let pickForField: string | undefined = $state()
|
|
let itemPicker: ItemPicker | undefined = $state(undefined)
|
|
let variableEditor: VariableEditor | undefined = $state(undefined)
|
|
|
|
const s3Storage = useS3StorageConfigured(() => ws)
|
|
|
|
let keys: string[] = $state([])
|
|
$effect(() => {
|
|
let lkeys = Object.keys(schema?.properties ?? {})
|
|
if (schema?.properties && JSON.stringify(lkeys) != JSON.stringify(keys)) {
|
|
keys = lkeys
|
|
untrack(() => removeExtraKey())
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<div class="w-full mb-6 {clazz}">
|
|
<!-- Not offered on a tool: the fields it fills are exactly the ones left empty for the agent
|
|
to fill at run time, and filling one rewrites it into an expression, which takes it out of
|
|
the schema the model is given. -->
|
|
{#if enableAi && !isAgentTool}
|
|
<div class="pt-2">
|
|
<StepInputsGen
|
|
{pickableProperties}
|
|
argNames={keys
|
|
? keys.filter(
|
|
(argName) =>
|
|
Object.keys(schema.properties ?? {}).includes(argName) &&
|
|
Object.keys(args ?? {}).includes(argName) &&
|
|
((args[argName].type === 'static' && !args[argName].value) ||
|
|
(args[argName].type === 'javascript' && !args[argName].expr))
|
|
)
|
|
: []}
|
|
{schema}
|
|
/>
|
|
</div>
|
|
{/if}
|
|
{#if keys.length > 0}
|
|
{#each keys as argName, index (argName)}
|
|
{#if (!filter || filter.includes(argName)) && Object.keys(schema.properties ?? {}).includes(argName)}
|
|
<ResizeTransitionWrapper class="mt-6" innerClass="w-full" vertical>
|
|
<InputTransformForm
|
|
{previousModuleId}
|
|
bind:arg={args[argName]}
|
|
bind:schema
|
|
bind:argName={keys[index]}
|
|
argExtra={schema.properties?.[argName] ?? {}}
|
|
bind:inputCheck={
|
|
() => inputCheck[argName] ?? false, (value) => (inputCheck[argName] = value)
|
|
}
|
|
bind:extraLib
|
|
{variableEditor}
|
|
{itemPicker}
|
|
bind:pickForField
|
|
{noDynamicToggle}
|
|
{noConnect}
|
|
{noJavascript}
|
|
{pickableProperties}
|
|
{enableAi}
|
|
{helperScript}
|
|
{isAgentTool}
|
|
{allowedAiTransforms}
|
|
s3StorageConfigured={s3Storage.current}
|
|
{chatInputEnabled}
|
|
{workspace}
|
|
otherArgs={Object.fromEntries(
|
|
Object.entries(args ?? {}).filter(([key]) => key !== argName)
|
|
)}
|
|
/>
|
|
</ResizeTransitionWrapper>
|
|
{/if}
|
|
{/each}
|
|
{:else}
|
|
<div class="text-primary text-xs mt-2">No inputs</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<InputTransformPickers {args} {pickForField} {workspace} bind:itemPicker bind:variableEditor />
|