From 501a427da153ecc1fe48199a82d4f00ceb010269 Mon Sep 17 00:00:00 2001 From: Luka Forder Date: Wed, 17 Jun 2026 15:28:25 +0100 Subject: [PATCH 1/7] fix: scary fix to prevent enter ever submitting the form for session creation --- src/routes/(app)/workbench/+page.svelte | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/routes/(app)/workbench/+page.svelte b/src/routes/(app)/workbench/+page.svelte index ee3dbf8..a52dadc 100644 --- a/src/routes/(app)/workbench/+page.svelte +++ b/src/routes/(app)/workbench/+page.svelte @@ -644,12 +644,25 @@ +
{ + if (e.isComposing) return; + if (e.key !== 'Enter') return; + + const el = document.activeElement; + + if (el instanceof HTMLInputElement) { + e.preventDefault(); + el.blur(); + } + }} + onsubmit={(e) => e.preventDefault()} > {#if view === 'workbench'} Date: Wed, 17 Jun 2026 15:28:37 +0100 Subject: [PATCH 2/7] feat: currency input field comp and usage in budget pane --- .../workbench/options/CurrencyInput.svelte | 73 ++++++++ .../(app)/workbench/panes/BudgetPane.svelte | 164 +++--------------- 2 files changed, 97 insertions(+), 140 deletions(-) create mode 100644 src/routes/(app)/workbench/options/CurrencyInput.svelte diff --git a/src/routes/(app)/workbench/options/CurrencyInput.svelte b/src/routes/(app)/workbench/options/CurrencyInput.svelte new file mode 100644 index 0000000..8d96475 --- /dev/null +++ b/src/routes/(app)/workbench/options/CurrencyInput.svelte @@ -0,0 +1,73 @@ + + + + + $ + + + + + diff --git a/src/routes/(app)/workbench/panes/BudgetPane.svelte b/src/routes/(app)/workbench/panes/BudgetPane.svelte index d3efd87..6234390 100644 --- a/src/routes/(app)/workbench/panes/BudgetPane.svelte +++ b/src/routes/(app)/workbench/panes/BudgetPane.svelte @@ -22,6 +22,8 @@ import * as Label from '@coral-os/component-library/ui/label/index.js'; + import CurrencyInput from '../options/CurrencyInput.svelte'; + import { Context } from 'runed'; import { TooltipLabel, TwostepButton } from '@coral-os/component-library'; @@ -99,6 +101,13 @@ 'Once the session budget is exhausted and claimed from, a warning will be produced. This behavior has a high risk of overclaiming.' } ] as const; + + const MICRODOLLARS_PER_DOLLAR = 100_000_000; + + const toDollars = (micro: number) => micro / MICRODOLLARS_PER_DOLLAR; + const toMicro = (dollars: number) => Math.round(dollars * MICRODOLLARS_PER_DOLLAR); + + const isWarnOnly = $derived($formData.sessionBudgetSettings.exhaustionBehavior.type === 'warn'); {#if ctx && $formData} @@ -123,27 +132,12 @@ > Session budget - - - $ - - - { - const dollars = e.currentTarget.valueAsNumber; - - $formData.sessionBudgetSettings.budget = Number.isNaN(dollars) - ? 0 - : Math.round(dollars * 100000000); - }} - type="number" - step="0.01" - placeholder="0.00" - /> - - + { + $formData.sessionBudgetSettings.budget = micro; + }} + /> {/snippet} @@ -281,32 +275,15 @@ > Minimum - - - $ - - - { - if ($formData.sessionBudgetSettings.exhaustionBehavior.type !== 'warn') { - const dollars = e.currentTarget.valueAsNumber; - - $formData.sessionBudgetSettings.exhaustionBehavior.minimum = Number.isNaN( - dollars - ) - ? 0 - : Math.round(dollars * 100000000); - } - }} - type="number" - step="0.01" - placeholder="0.00" - /> - - + { + if ($formData.sessionBudgetSettings.exhaustionBehavior.type !== 'warn') { + $formData.sessionBudgetSettings.exhaustionBehavior.minimum = micro; + } + }} + /> {/if} {/snippet} @@ -359,98 +336,5 @@

- - {/if} From 916b839c05e56e858169f34751b26b2eb4d325b8 Mon Sep 17 00:00:00 2001 From: Luka Forder Date: Wed, 17 Jun 2026 18:07:25 +0100 Subject: [PATCH 3/7] fix: changed min and fixed json import for agent budgets --- src/lib/sessionSchema/index.ts | 1 + src/lib/sessionSchema/types.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/sessionSchema/index.ts b/src/lib/sessionSchema/index.ts index 8df01a4..ceb5657 100644 --- a/src/lib/sessionSchema/index.ts +++ b/src/lib/sessionSchema/index.ts @@ -183,6 +183,7 @@ export const importFromPayload = (json: string): z.output => { blocking: agent.blocking ?? true, systemPrompt: agent.systemPrompt, plugins: agent.plugins ?? [], + budgetSettings: agent.budgetSettings ?? {}, options: agent.options ? (structuredClone(agent.options) as any) : {}, customToolAccess: new Set( (agent.customToolAccess ?? []).map((t) => toolMap[t]).filter(Boolean) as string[] // typescript is stupid this is safe because .filter(Boolean) diff --git a/src/lib/sessionSchema/types.ts b/src/lib/sessionSchema/types.ts index 077eb90..7c88bac 100644 --- a/src/lib/sessionSchema/types.ts +++ b/src/lib/sessionSchema/types.ts @@ -243,7 +243,7 @@ const formSchema = z.object({ ]) .default({ type: 'kill_session', - minimum: 100000 + minimum: 1000000 }) }), tools: z.record(z.string().nonempty(), CustomToolSchema), From 7be86af2ec4193d9d021d587fd964da465b7b7d3 Mon Sep 17 00:00:00 2001 From: Luka Forder Date: Wed, 17 Jun 2026 18:07:35 +0100 Subject: [PATCH 4/7] feat: selects all on focus --- src/routes/(app)/workbench/options/CurrencyInput.svelte | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/routes/(app)/workbench/options/CurrencyInput.svelte b/src/routes/(app)/workbench/options/CurrencyInput.svelte index 8d96475..f8caba4 100644 --- a/src/routes/(app)/workbench/options/CurrencyInput.svelte +++ b/src/routes/(app)/workbench/options/CurrencyInput.svelte @@ -2,6 +2,7 @@ import * as ButtonGroup from '@coral-os/component-library/ui/button-group/index.js'; import * as InputGroup from '@coral-os/component-library/ui/input-group/index.js'; import * as Label from '@coral-os/component-library/ui/label/index.js'; + import { tick } from 'svelte'; const MICRODOLLARS_PER_DOLLAR = 100_000_000; @@ -42,9 +43,14 @@ const dollars = $derived(toDollars(value ?? 0)); - function onFocus(e: FocusEvent & { currentTarget: HTMLInputElement }) { + async function onFocus(e: FocusEvent & { currentTarget: HTMLInputElement }) { isEditing = true; editingValue = isNaN(dollars) ? '' : dollars.toFixed(10).replace(/\.?0+$/, ''); + + await tick(); + e.currentTarget.select(); + + // TODO: without the await tick it doesnt select! :) } function onBlur(e: FocusEvent & { currentTarget: HTMLInputElement }) { From 249775973cfa25660134e789ec9de199f557c7a1 Mon Sep 17 00:00:00 2001 From: Luka Forder Date: Wed, 17 Jun 2026 18:07:48 +0100 Subject: [PATCH 5/7] feat: fixed and updated the agent budget settings --- src/routes/(app)/workbench/+page.svelte | 1 - .../(app)/workbench/panes/AgentPane.svelte | 196 ++++++++---------- 2 files changed, 92 insertions(+), 105 deletions(-) diff --git a/src/routes/(app)/workbench/+page.svelte b/src/routes/(app)/workbench/+page.svelte index a52dadc..bca1844 100644 --- a/src/routes/(app)/workbench/+page.svelte +++ b/src/routes/(app)/workbench/+page.svelte @@ -514,7 +514,6 @@ onMount(async () => { if (sessionDraft.current && sessionDraft.current.agentGraphRequest.agents.length >= 0) { - // ensure required 'from' property is present for importSession sessCtx.importSession({ from: JSON.stringify(sessionDraft.current), success: 'Loaded previous workbench draft' diff --git a/src/routes/(app)/workbench/panes/AgentPane.svelte b/src/routes/(app)/workbench/panes/AgentPane.svelte index 442e42e..678e74b 100644 --- a/src/routes/(app)/workbench/panes/AgentPane.svelte +++ b/src/routes/(app)/workbench/panes/AgentPane.svelte @@ -37,6 +37,7 @@ import { getSessionDataFromTemplateName } from '../templates/TemplateLib'; import { getSessionContext } from '$lib/sessionCreatorContext'; import { cn } from '$lib/utils'; + import CurrencyInput from '../options/CurrencyInput.svelte'; let appCtx = appContext.get(); @@ -95,11 +96,9 @@ return $formData.agents[agentIdx]?.budgetSettings?.exhaustionBehavior; } - function isKillBehavior( - behavior: ReturnType - ): behavior is { type: 'kill'; force: boolean; minimum: number } { - return behavior?.type === 'kill'; - } + const agentBehavior = $derived( + $formData.agents[ctx.selectedAgent!]?.budgetSettings?.exhaustionBehavior + ); {#if ctx.selectedAgent !== null && curAgent && curCatalog} @@ -254,14 +253,15 @@
  1. - + Agent budget + {@const agentIdx = ctx.selectedAgent!} @@ -273,42 +273,35 @@ required: true, type: 'integer' }} - class="max-w-1/4 min-w-1/4 " + class="max-w-1/4 min-w-1/4" > Agent budget - - - $ - - - { - const dollars = e.currentTarget.valueAsNumber; - $formData.agents[ctx.selectedAgent!]!.budgetSettings!.budget = - Number.isNaN(dollars) ? 0 : Math.round(dollars * 100000000); - }} - type="number" - step="0.01" - placeholder="0.00" - /> - - + + { + const agent = $formData.agents[agentIdx]; + if (!agent) return; + + agent.budgetSettings ??= {}; + + agent.budgetSettings.budget = micro; + + $formData.agents = $formData.agents; + }} + /> {/snippet} {#snippet children()} - {@const agentIdx = ctx.selectedAgent!} {@const exhaustionBehavior = getAgentExhaustionBehavior(agentIdx)} - {#if isKillBehavior(getAgentExhaustionBehavior(ctx.selectedAgent!))} - {@const agentIdx = ctx.selectedAgent!} - {@const killBehavior = getAgentExhaustionBehavior(agentIdx) as { - type: 'kill'; - force: boolean; - minimum: number; - }} + {#if agentBehavior?.type !== 'consume_session' && agentBehavior} + {@const killBehavior = getAgentExhaustionBehavior(agentIdx)} + {@const force = killBehavior?.type === 'kill' ? killBehavior.force : false} Force kill agent + True + + False + {/snippet} - - - {#snippet children({ props })} - - Minimum - - - - $ - - - { - const dollars = e.currentTarget.valueAsNumber; - const behavior = - $formData.agents[agentIdx]?.budgetSettings?.exhaustionBehavior; - if (behavior?.type === 'kill') { - behavior.minimum = Number.isNaN(dollars) - ? 0 - : Math.round(dollars * 100000000); - $formData.agents = $formData.agents; - } - }} - type="number" - step="0.01" - placeholder="0.00" - /> - - - {/snippet} - - + {#if killBehavior?.type === 'kill'} + + + {#snippet children({ props })} + + Minimum + + { + killBehavior.minimum = micro; + $formData.agents = $formData.agents; + }} + /> + {/snippet} + + + {/if} {/if} From e6bacc3b64bd47dd2fc9670e2dccfdd2b4544d12 Mon Sep 17 00:00:00 2001 From: Luka Forder Date: Wed, 17 Jun 2026 18:15:27 +0100 Subject: [PATCH 6/7] fix: switched to toggle groups for true/false from the previous button groups --- .../(app)/workbench/panes/AgentPane.svelte | 64 ++++++++----------- .../(app)/workbench/panes/BudgetPane.svelte | 44 +++++-------- 2 files changed, 42 insertions(+), 66 deletions(-) diff --git a/src/routes/(app)/workbench/panes/AgentPane.svelte b/src/routes/(app)/workbench/panes/AgentPane.svelte index 678e74b..8c43eab 100644 --- a/src/routes/(app)/workbench/panes/AgentPane.svelte +++ b/src/routes/(app)/workbench/panes/AgentPane.svelte @@ -405,49 +405,35 @@ > Force kill agent - - - - + agent.budgetSettings.exhaustionBehavior = { + type: 'kill', + force: v === 'true', + minimum: existing?.type === 'kill' ? existing.minimum : 0 + }; + + $formData.agents = $formData.agents; + }} + > + True + + False + {/snippet} diff --git a/src/routes/(app)/workbench/panes/BudgetPane.svelte b/src/routes/(app)/workbench/panes/BudgetPane.svelte index 6234390..c518dc4 100644 --- a/src/routes/(app)/workbench/panes/BudgetPane.svelte +++ b/src/routes/(app)/workbench/panes/BudgetPane.svelte @@ -224,33 +224,23 @@ > Force kill agent - - - - + { + if (v && $formData.sessionBudgetSettings.exhaustionBehavior.type === 'kill_agent') { + $formData.sessionBudgetSettings.exhaustionBehavior.force = v === 'true'; + } + }} + > + True + + False + {/snippet} From 9e59af93b4b558b097746c8b9ec6a95a780e6895 Mon Sep 17 00:00:00 2001 From: Luka Forder Date: Thu, 18 Jun 2026 15:14:10 +0100 Subject: [PATCH 7/7] fix: alan changes Co-authored-by: Alan Panayotov --- src/routes/(app)/workbench/options/CurrencyInput.svelte | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/routes/(app)/workbench/options/CurrencyInput.svelte b/src/routes/(app)/workbench/options/CurrencyInput.svelte index f8caba4..7b41c1e 100644 --- a/src/routes/(app)/workbench/options/CurrencyInput.svelte +++ b/src/routes/(app)/workbench/options/CurrencyInput.svelte @@ -10,11 +10,10 @@ const toMicro = (dollars: number) => Math.round(dollars * MICRODOLLARS_PER_DOLLAR); const formatUSD = (value: number) => { - if (value === 0) return '$0.00'; - if (value < 0.01) return '$' + value.toFixed(10).replace(/\.?0+$/, ''); - return new Intl.NumberFormat('en-US', { + return new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', + currencyDisplay: 'narrowSymbol', minimumFractionDigits: 2, maximumFractionDigits: 8 }).format(value);