mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-08 23:02:41 +02:00
Compare commits
2 commits
e0aaa9a27e
...
290dc54d1e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
290dc54d1e | ||
|
|
c2177a0aa4 |
2 changed files with 75 additions and 63 deletions
|
|
@ -79,7 +79,7 @@ const tabs: TabConfig[] = [
|
||||||
id: "tools",
|
id: "tools",
|
||||||
label: "Tools Library",
|
label: "Tools Library",
|
||||||
icon: Wrench,
|
icon: Wrench,
|
||||||
description: "Browse and enable Composio toolkits",
|
description: "Browse and enable toolkits",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "note-tagging",
|
id: "note-tagging",
|
||||||
|
|
@ -724,7 +724,7 @@ interface ToolkitInfo {
|
||||||
composio_managed_auth_schemes?: string[]
|
composio_managed_auth_schemes?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
function ToolsLibrarySettings({ dialogOpen }: { dialogOpen: boolean }) {
|
function ToolsLibrarySettings({ dialogOpen, rowboatConnected }: { dialogOpen: boolean; rowboatConnected: boolean }) {
|
||||||
// API key state
|
// API key state
|
||||||
const [apiKeyConfigured, setApiKeyConfigured] = useState(false)
|
const [apiKeyConfigured, setApiKeyConfigured] = useState(false)
|
||||||
const [apiKeyInput, setApiKeyInput] = useState("")
|
const [apiKeyInput, setApiKeyInput] = useState("")
|
||||||
|
|
@ -869,65 +869,67 @@ function ToolsLibrarySettings({ dialogOpen }: { dialogOpen: boolean }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Section A: API Key */}
|
{/* Section A: API Key (only in BYOK mode) */}
|
||||||
<div className="space-y-2">
|
{!rowboatConnected && (
|
||||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Composio API Key</span>
|
<div className="space-y-2">
|
||||||
{apiKeyConfigured && !showApiKeyInput ? (
|
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Composio API Key</span>
|
||||||
<div className="flex items-center gap-2">
|
{apiKeyConfigured && !showApiKeyInput ? (
|
||||||
<div className="flex items-center gap-1.5 text-sm text-green-600">
|
<div className="flex items-center gap-2">
|
||||||
<CheckCircle2 className="size-4" />
|
<div className="flex items-center gap-1.5 text-sm text-green-600">
|
||||||
API key configured
|
<CheckCircle2 className="size-4" />
|
||||||
|
API key configured
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowApiKeyInput(true)}
|
||||||
|
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Change
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
) : (
|
||||||
onClick={() => setShowApiKeyInput(true)}
|
<div className="space-y-2">
|
||||||
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
|
<p className="text-xs text-muted-foreground">
|
||||||
>
|
Enter your Composio API key to browse and enable tool integrations.
|
||||||
Change
|
Get your key from{" "}
|
||||||
</button>
|
<a
|
||||||
</div>
|
href="https://app.composio.dev/settings"
|
||||||
) : (
|
target="_blank"
|
||||||
<div className="space-y-2">
|
rel="noopener noreferrer"
|
||||||
<p className="text-xs text-muted-foreground">
|
className="text-primary hover:underline"
|
||||||
Enter your Composio API key to browse and enable tool integrations.
|
|
||||||
Get your key from{" "}
|
|
||||||
<a
|
|
||||||
href="https://app.composio.dev/settings"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
|
||||||
>
|
|
||||||
app.composio.dev/settings
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
value={apiKeyInput}
|
|
||||||
onChange={(e) => setApiKeyInput(e.target.value)}
|
|
||||||
placeholder="Paste your Composio API key"
|
|
||||||
onKeyDown={(e) => e.key === "Enter" && handleSaveApiKey()}
|
|
||||||
className="flex-1"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
onClick={handleSaveApiKey}
|
|
||||||
disabled={!apiKeyInput.trim() || apiKeySaving}
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
{apiKeySaving ? <Loader2 className="size-4 animate-spin" /> : "Save"}
|
|
||||||
</Button>
|
|
||||||
{apiKeyConfigured && (
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => { setShowApiKeyInput(false); setApiKeyInput("") }}
|
|
||||||
>
|
>
|
||||||
Cancel
|
app.composio.dev/settings
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
value={apiKeyInput}
|
||||||
|
onChange={(e) => setApiKeyInput(e.target.value)}
|
||||||
|
placeholder="Paste your Composio API key"
|
||||||
|
onKeyDown={(e) => e.key === "Enter" && handleSaveApiKey()}
|
||||||
|
className="flex-1"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={handleSaveApiKey}
|
||||||
|
disabled={!apiKeyInput.trim() || apiKeySaving}
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
{apiKeySaving ? <Loader2 className="size-4 animate-spin" /> : "Save"}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
{apiKeyConfigured && (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => { setShowApiKeyInput(false); setApiKeyInput("") }}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
{/* Section B: Toolkit Browser (only when API key configured) */}
|
{/* Section B: Toolkit Browser (only when API key configured) */}
|
||||||
{apiKeyConfigured && (
|
{apiKeyConfigured && (
|
||||||
|
|
@ -964,11 +966,11 @@ function ToolsLibrarySettings({ dialogOpen }: { dialogOpen: boolean }) {
|
||||||
<img
|
<img
|
||||||
src={toolkit.meta.logo}
|
src={toolkit.meta.logo}
|
||||||
alt=""
|
alt=""
|
||||||
className="size-7 rounded object-contain flex-shrink-0"
|
className="size-7 rounded object-contain shrink-0"
|
||||||
onError={(e) => { (e.target as HTMLImageElement).style.display = 'none' }}
|
onError={(e) => { (e.target as HTMLImageElement).style.display = 'none' }}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="size-7 rounded bg-muted flex items-center justify-center flex-shrink-0">
|
<div className="size-7 rounded bg-muted flex items-center justify-center shrink-0">
|
||||||
<Wrench className="size-3.5 text-muted-foreground" />
|
<Wrench className="size-3.5 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -994,7 +996,7 @@ function ToolsLibrarySettings({ dialogOpen }: { dialogOpen: boolean }) {
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => handleDisconnect(toolkit.slug)}
|
onClick={() => handleDisconnect(toolkit.slug)}
|
||||||
className="text-xs h-7 flex-shrink-0"
|
className="text-xs h-7 shrink-0"
|
||||||
>
|
>
|
||||||
Disconnect
|
Disconnect
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -1003,7 +1005,7 @@ function ToolsLibrarySettings({ dialogOpen }: { dialogOpen: boolean }) {
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => handleConnect(toolkit.slug)}
|
onClick={() => handleConnect(toolkit.slug)}
|
||||||
disabled={isConnecting}
|
disabled={isConnecting}
|
||||||
className="text-xs h-7 flex-shrink-0"
|
className="text-xs h-7 shrink-0"
|
||||||
>
|
>
|
||||||
{isConnecting ? (
|
{isConnecting ? (
|
||||||
<><Loader2 className="size-3 animate-spin mr-1" />Connecting...</>
|
<><Loader2 className="size-3 animate-spin mr-1" />Connecting...</>
|
||||||
|
|
@ -1649,7 +1651,7 @@ export function SettingsDialog({ children }: SettingsDialogProps) {
|
||||||
) : activeTab === "appearance" ? (
|
) : activeTab === "appearance" ? (
|
||||||
<AppearanceSettings />
|
<AppearanceSettings />
|
||||||
) : activeTab === "tools" ? (
|
) : activeTab === "tools" ? (
|
||||||
<ToolsLibrarySettings dialogOpen={open} />
|
<ToolsLibrarySettings dialogOpen={open} rowboatConnected={rowboatConnected} />
|
||||||
) : loading ? (
|
) : loading ? (
|
||||||
<div className="h-full flex items-center justify-center text-muted-foreground text-sm">
|
<div className="h-full flex items-center justify-center text-muted-foreground text-sm">
|
||||||
Loading...
|
Loading...
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,17 @@ const runtimeContextPrompt = getRuntimeContextPrompt(getRuntimeContext());
|
||||||
* Lists connected toolkits and explains the meta-tool discovery flow.
|
* Lists connected toolkits and explains the meta-tool discovery flow.
|
||||||
*/
|
*/
|
||||||
async function getComposioToolsPrompt(): Promise<string> {
|
async function getComposioToolsPrompt(): Promise<string> {
|
||||||
if (!(await isComposioConfigured())) return '';
|
if (!(await isComposioConfigured())) {
|
||||||
|
return `
|
||||||
|
## Composio Integrations
|
||||||
|
|
||||||
|
**Composio is not configured.** Composio enables integrations with third-party services like Google Sheets, GitHub, Slack, Jira, Notion, LinkedIn, and 20+ others.
|
||||||
|
|
||||||
|
When the user asks to interact with any third-party service (e.g., "connect to Google Sheets", "create a GitHub issue"), do NOT attempt to write code, use shell commands, or load the composio-integration skill. Instead, let the user know that these integrations are available through Composio, and they can enable them by adding their Composio API key in **Settings > Tools Library**. They can get their key from https://app.composio.dev/settings.
|
||||||
|
|
||||||
|
**Exception — Email and Calendar:** For email-related requests (reading emails, sending emails, drafting replies) or calendar-related requests (checking schedule, listing events), do NOT direct the user to Composio. Instead, tell them to connect their email and calendar in **Settings > Connected Accounts**.
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
const connectedToolkits = composioAccountsRepo.getConnectedToolkits();
|
const connectedToolkits = composioAccountsRepo.getConnectedToolkits();
|
||||||
const connectedSection = connectedToolkits.length > 0
|
const connectedSection = connectedToolkits.length > 0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue