mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-29 14:37:44 +02:00
- Add CoreProvider to @multica/core/platform — single component for API/stores/WS/QueryClient init - Delete 13 platform files across web (6) and desktop (7), each app keeps only navigation.tsx - Extract AppSidebar + DashboardLayout to @multica/views/layout - Extract LoginPage to @multica/views/auth - Extract AgentsPage (1,279 lines) to @multica/views/agents (11 files) - Extract InboxPage (468 lines) to @multica/views/inbox (5 files) - Extract SettingsPage + 6 tabs (1,277 lines) to @multica/views/settings (9 files) - Fix AppLink to use forwardRef for Base UI render prop compatibility - Fix Tailwind @source to scan .ts files (status config with bg-info/bg-warning) - Suppress next-themes React 19 script tag warning - Add WebProviders wrapper for Server→Client function passing - Wire all desktop routes to shared views, remove PlaceholderPage - Net: +106 / -4,094 lines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import { Loader2, Save } from "lucide-react";
|
|
import type { Agent } from "@multica/core/types";
|
|
import { Button } from "@multica/ui/components/ui/button";
|
|
|
|
export function InstructionsTab({
|
|
agent,
|
|
onSave,
|
|
}: {
|
|
agent: Agent;
|
|
onSave: (instructions: string) => Promise<void>;
|
|
}) {
|
|
const [value, setValue] = useState(agent.instructions ?? "");
|
|
const [saving, setSaving] = useState(false);
|
|
const isDirty = value !== (agent.instructions ?? "");
|
|
|
|
// Sync when switching between agents.
|
|
useEffect(() => {
|
|
setValue(agent.instructions ?? "");
|
|
}, [agent.id, agent.instructions]);
|
|
|
|
const handleSave = async () => {
|
|
setSaving(true);
|
|
try {
|
|
await onSave(value);
|
|
} catch {
|
|
// toast handled by parent
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div>
|
|
<h3 className="text-sm font-semibold">Agent Instructions</h3>
|
|
<p className="text-xs text-muted-foreground mt-0.5">
|
|
Define this agent's identity and working style. These instructions are
|
|
injected into the agent's context for every task.
|
|
</p>
|
|
</div>
|
|
|
|
<textarea
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
placeholder={`Define this agent's role, expertise, and working style.\n\nExample:\nYou are a frontend engineer specializing in React and TypeScript.\n\n## Working Style\n- Write small, focused PRs — one commit per logical change\n- Prefer composition over inheritance\n- Always add unit tests for new components\n\n## Constraints\n- Do not modify shared/ types without explicit approval\n- Follow the existing component patterns in features/`}
|
|
className="w-full min-h-[300px] rounded-md border bg-transparent px-3 py-2 text-sm font-mono placeholder:text-muted-foreground/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring resize-y"
|
|
/>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-xs text-muted-foreground">
|
|
{value.length > 0 ? `${value.length} characters` : "No instructions set"}
|
|
</span>
|
|
<Button
|
|
size="xs"
|
|
onClick={handleSave}
|
|
disabled={!isDirty || saving}
|
|
>
|
|
{saving ? (
|
|
<Loader2 className="h-3 w-3 animate-spin" />
|
|
) : (
|
|
<Save className="h-3 w-3" />
|
|
)}
|
|
Save
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|