feat: Add intelligent auto-router and enhanced integrations

- Add intelligent-router.sh hook for automatic agent routing
- Add AUTO-TRIGGER-SUMMARY.md documentation
- Add FINAL-INTEGRATION-SUMMARY.md documentation
- Complete Prometheus integration (6 commands + 4 tools)
- Complete Dexto integration (12 commands + 5 tools)
- Enhanced Ralph with access to all agents
- Fix /clawd command (removed disable-model-invocation)
- Update hooks.json to v5 with intelligent routing
- 291 total skills now available
- All 21 commands with automatic routing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
admin
2026-01-28 00:27:56 +04:00
Unverified
parent 3b128ba3bd
commit b52318eeae
1724 changed files with 351216 additions and 0 deletions

View File

@@ -0,0 +1,372 @@
import React, { useState } from 'react';
import { useCreateAgent, type CreateAgentPayload } from '../hooks/useAgents';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from '../ui/dialog';
import { Button } from '../ui/button';
import { Input } from '../ui/input';
import { Textarea } from '../ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
import { AlertCircle, Loader2, Eye, EyeOff, Info } from 'lucide-react';
import { LLM_PROVIDERS } from '@dexto/core';
interface CreateAgentModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onAgentCreated?: (agentName: string) => void;
}
interface FormData {
id: string;
idManuallyEdited: boolean;
name: string;
description: string;
provider: string;
model: string;
apiKey: string;
systemPrompt: string;
}
const initialFormData: FormData = {
id: '',
idManuallyEdited: false,
name: '',
description: '',
provider: 'anthropic',
model: 'claude-sonnet-4-5-20250929',
apiKey: '',
systemPrompt: '',
};
// Convert name to a valid ID (lowercase, hyphens, no special chars)
function nameToId(name: string): string {
return name
.toLowerCase()
.trim()
.replace(/[^a-z0-9\s-]/g, '') // Remove special chars
.replace(/\s+/g, '-') // Spaces to hyphens
.replace(/-+/g, '-') // Multiple hyphens to single
.replace(/^-|-$/g, ''); // Trim leading/trailing hyphens
}
export default function CreateAgentModal({
open,
onOpenChange,
onAgentCreated,
}: CreateAgentModalProps) {
const [form, setForm] = useState<FormData>(initialFormData);
const [errors, setErrors] = useState<Record<string, string>>({});
const [createError, setCreateError] = useState<string | null>(null);
const [showApiKey, setShowApiKey] = useState(false);
const createAgentMutation = useCreateAgent();
const isCreating = createAgentMutation.isPending;
const updateField = (field: keyof FormData, value: string) => {
setForm((prev) => {
const next = { ...prev, [field]: value };
// Auto-generate ID from name if ID hasn't been manually edited
if (field === 'name' && !prev.idManuallyEdited) {
next.id = nameToId(value);
}
// Mark ID as manually edited if user types in it
if (field === 'id') {
next.idManuallyEdited = true;
}
return next;
});
if (errors[field]) {
setErrors((prev) => {
const next = { ...prev };
delete next[field];
return next;
});
}
};
const validateForm = (): boolean => {
const newErrors: Record<string, string> = {};
if (!form.id.trim()) {
newErrors.id = 'Required';
} else if (!/^[a-z0-9-]+$/.test(form.id)) {
newErrors.id = 'Lowercase letters, numbers, and hyphens only';
}
if (!form.name.trim()) {
newErrors.name = 'Required';
}
if (!form.description.trim()) {
newErrors.description = 'Required';
}
if (!form.provider) {
newErrors.provider = 'Required';
}
if (!form.model.trim()) {
newErrors.model = 'Required';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleCreate = async () => {
if (!validateForm()) return;
setCreateError(null);
const payload: CreateAgentPayload = {
id: form.id.trim(),
name: form.name.trim(),
description: form.description.trim(),
config: {
llm: {
provider: form.provider as CreateAgentPayload['config']['llm']['provider'],
model: form.model.trim(),
apiKey: form.apiKey.trim() || undefined,
},
...(form.systemPrompt.trim() && {
systemPrompt: {
contributors: [
{
id: 'primary',
type: 'static' as const,
priority: 0,
enabled: true,
content: form.systemPrompt.trim(),
},
],
},
}),
},
};
createAgentMutation.mutate(payload, {
onSuccess: (data) => {
setForm(initialFormData);
setErrors({});
onOpenChange(false);
if (onAgentCreated && data.id) {
onAgentCreated(data.id);
}
},
onError: (error: Error) => {
setCreateError(error.message);
},
});
};
const handleCancel = () => {
setForm(initialFormData);
setErrors({});
setCreateError(null);
onOpenChange(false);
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-md max-h-[85vh] flex flex-col gap-0 p-0 overflow-hidden">
<DialogHeader className="px-5 pt-5 pb-4 border-b border-border/40">
<DialogTitle className="text-base">Create Agent</DialogTitle>
<DialogDescription className="text-sm">
Configure your new agent. Advanced options can be set after creation.
</DialogDescription>
</DialogHeader>
{/* Error */}
{createError && (
<div className="mx-5 mt-4 p-3 rounded-lg bg-destructive/10 border border-destructive/20 flex items-start gap-2">
<AlertCircle className="h-4 w-4 text-destructive shrink-0 mt-0.5" />
<p className="text-sm text-destructive">{createError}</p>
</div>
)}
{/* Form */}
<div className="flex-1 overflow-y-auto px-5 py-4 space-y-5">
{/* Identity */}
<Section title="Identity">
<Field label="Name" required error={errors.name}>
<Input
value={form.name}
onChange={(e) => updateField('name', e.target.value)}
placeholder="My Agent"
aria-invalid={!!errors.name}
/>
</Field>
<Field
label="ID"
required
error={errors.id}
hint={!form.idManuallyEdited ? 'Auto-generated from name' : undefined}
>
<Input
value={form.id}
onChange={(e) => updateField('id', e.target.value)}
placeholder="my-agent"
aria-invalid={!!errors.id}
className="font-mono text-sm"
/>
</Field>
<Field label="Description" required error={errors.description}>
<Input
value={form.description}
onChange={(e) => updateField('description', e.target.value)}
placeholder="A helpful assistant for..."
aria-invalid={!!errors.description}
/>
</Field>
</Section>
{/* Model */}
<Section title="Language Model">
<div className="grid grid-cols-2 gap-3">
<Field label="Provider" required error={errors.provider}>
<Select
value={form.provider}
onValueChange={(value) => updateField('provider', value)}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select provider..." />
</SelectTrigger>
<SelectContent>
{LLM_PROVIDERS.map((p) => (
<SelectItem key={p} value={p}>
{p.charAt(0).toUpperCase() +
p.slice(1).replace(/-/g, ' ')}
</SelectItem>
))}
</SelectContent>
</Select>
</Field>
<Field label="Model" required error={errors.model}>
<Input
value={form.model}
onChange={(e) => updateField('model', e.target.value)}
placeholder="claude-sonnet-4-5-20250929"
aria-invalid={!!errors.model}
/>
</Field>
</div>
<Field label="API Key" hint="Leave empty to use environment variable">
<div className="relative">
<Input
type={showApiKey ? 'text' : 'password'}
value={form.apiKey}
onChange={(e) => updateField('apiKey', e.target.value)}
placeholder="$ANTHROPIC_API_KEY"
className="pr-9"
/>
<button
type="button"
onClick={() => setShowApiKey(!showApiKey)}
className="absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded hover:bg-muted/50 transition-colors"
aria-label={showApiKey ? 'Hide API key' : 'Show API key'}
>
{showApiKey ? (
<EyeOff className="h-4 w-4 text-muted-foreground" />
) : (
<Eye className="h-4 w-4 text-muted-foreground" />
)}
</button>
</div>
</Field>
</Section>
{/* System Prompt */}
<Section title="System Prompt" optional>
<Field>
<Textarea
value={form.systemPrompt}
onChange={(e) => updateField('systemPrompt', e.target.value)}
placeholder="You are a helpful assistant..."
rows={4}
className="font-mono text-sm resize-y"
/>
</Field>
<p className="text-[11px] text-muted-foreground/70 flex items-center gap-1">
<Info className="h-3 w-3" />
You can add MCP servers and other options after creation
</p>
</Section>
</div>
{/* Footer */}
<DialogFooter className="px-5 py-4 border-t border-border/40 bg-muted/20">
<Button variant="outline" onClick={handleCancel} disabled={isCreating}>
Cancel
</Button>
<Button onClick={handleCreate} disabled={isCreating}>
{isCreating && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Create
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
// ============================================================================
// SHARED COMPONENTS
// ============================================================================
function Section({
title,
optional,
children,
}: {
title: string;
optional?: boolean;
children: React.ReactNode;
}) {
return (
<div>
<div className="mb-2.5 flex items-baseline gap-2">
<h3 className="text-sm font-medium text-foreground">{title}</h3>
{optional && (
<span className="text-[10px] text-muted-foreground/60 uppercase tracking-wide">
Optional
</span>
)}
</div>
<div className="space-y-3">{children}</div>
</div>
);
}
function Field({
label,
required,
hint,
error,
children,
}: {
label?: string;
required?: boolean;
hint?: string;
error?: string;
children: React.ReactNode;
}) {
return (
<div>
{label && (
<label className="block text-xs font-medium text-muted-foreground mb-1.5">
{label}
{required && <span className="text-destructive ml-0.5">*</span>}
</label>
)}
{children}
{hint && !error && <p className="text-[11px] text-muted-foreground/70 mt-1">{hint}</p>}
{error && <p className="text-[11px] text-destructive mt-1">{error}</p>}
</div>
);
}