Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
yilsem committed 2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 files changed
+3442369

No files matched your search

@@ -0,0 +1,161 @@
import { useStore } from '@nanostores/react'
import { useEffect, useState } from 'react'
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog'
import { saveMemoryProviderConfig } from '@/hermes'
import { ExternalLink, Loader2, Save, SlidersHorizontal } from '@/lib/icons'
import { notify, notifyError } from '@/store/notifications'
import { $activeGatewayProfile } from '@/store/profile'
import type { MemoryProviderConfig, MemoryProviderField } from '@/types/hermes'
import { ListRow } from '../primitives'
import { FieldControl, FieldTitle } from './field-control'
// Secrets seed blank: values are write-only and blank keeps the stored one.
function seedAll(config: MemoryProviderConfig): Record<string, string> {
return Object.fromEntries(config.fields.map(field => [field.key, field.kind === 'secret' ? '' : field.value]))
}
// Group fields in declared order, preserving first-seen group sequence.
function groupFields(fields: MemoryProviderField[]): [string, MemoryProviderField[]][] {
const groups: [string, MemoryProviderField[]][] = []
for (const field of fields) {
const name = field.group || 'Other'
const bucket = groups.find(([key]) => key === name)
if (bucket) {
bucket[1].push(field)
} else {
groups.push([name, [field]])
}
}
return groups
}
export function ProviderConfigModal({
config,
profile = null,
provider,
open,
onOpenChange,
onSaved
}: {
config: MemoryProviderConfig
profile?: null | string
provider: string
open: boolean
onOpenChange: (open: boolean) => void
onSaved: () => Promise<void> | void
}) {
const activeProfile = useStore($activeGatewayProfile)
const [values, setValues] = useState<Record<string, string>>({})
const [seeded, setSeeded] = useState<Record<string, string>>({})
const [saving, setSaving] = useState(false)
// Reseed on open so edits never start from a stale prior-session snapshot.
useEffect(() => {
if (open) {
const seed = seedAll(config)
setSeeded(seed)
setValues(seed)
}
}, [open, config])
const save = async () => {
// Untouched keys stay unsubmitted; runtime defaults still own their values.
const edited = Object.fromEntries(Object.entries(values).filter(([key, value]) => value !== seeded[key]))
setSaving(true)
try {
await saveMemoryProviderConfig(provider, edited, profile)
notify({ kind: 'success', title: `${config.label} saved`, message: 'Memory provider configuration updated.' })
await onSaved()
onOpenChange(false)
} catch (err) {
notifyError(err, `Failed to save ${config.label} settings`)
} finally {
setSaving(false)
}
}
return (
<Dialog onOpenChange={onOpenChange} open={open}>
<DialogContent bodyClassName="dt-portal-scrollbar" className="max-w-2xl">
<DialogHeader>
<DialogTitle icon={SlidersHorizontal}>{config.label} — full configuration</DialogTitle>
<DialogDescription>
Every {config.label} option for the <span className="font-medium">{profile ?? activeProfile}</span> profile.
Blank fields fall back to the resolved host or built-in default.
</DialogDescription>
{config.docs_url && (
<a
className="inline-flex w-fit items-center gap-1 text-[length:var(--conversation-caption-font-size)] text-(--ui-accent-secondary) underline-offset-4 transition-colors hover:underline"
href={config.docs_url}
onClick={event => {
event.preventDefault()
void window.hermesDesktop?.openExternal?.(config.docs_url)
}}
rel="noreferrer"
target="_blank"
>
{config.label} configuration reference
<ExternalLink className="size-3" />
</a>
)}
</DialogHeader>
<div className="min-w-0">
{groupFields(config.fields).map(([group, fields]) => (
<section className="mt-6 first:mt-2" key={group}>
<h3 className="border-b border-(--ui-accent-secondary)/30 pb-1.5 font-mono text-[0.68rem] uppercase tracking-wide text-(--ui-accent-secondary)">
{group}
</h3>
<div className="pl-1">
{fields.map(field => (
<div className="border-b border-border/40 last:border-b-0" key={field.key}>
<ListRow
action={
<FieldControl
field={field}
onChange={value => setValues(current => ({ ...current, [field.key]: value }))}
value={values[field.key] ?? ''}
/>
}
description={field.description}
title={<FieldTitle field={field} />}
/>
</div>
))}
</div>
</section>
))}
</div>
<DialogFooter>
<DialogClose asChild>
<Button size="sm" type="button" variant="ghost">
Cancel
</Button>
</DialogClose>
<Button disabled={saving} onClick={() => void save()} size="sm">
{saving ? <Loader2 className="size-3.5 animate-spin" /> : <Save />}
Save changes
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}