Compare commits

..

27 Commits

Author SHA1 Message Date
Vikhyath Mondreti
a02016e247 v0.4.24: sso for chat deployment, usage indicator for file storage, mcp improvements, local kb file storage 2025-10-27 15:32:53 -07:00
Waleed
8620ab255a improvement(docs): added a copy page button to the docs pages (#1743)
* improvement(docs): added a copy page button to the docs pages

* added copy page button & fixed TOC alignment
2025-10-27 15:05:27 -07:00
Waleed
47ddfb639e fix(dropdown): auto-add character to trigger tag dropdown on connection tag drop in agent tools (#1742) 2025-10-27 14:28:29 -07:00
Waleed
5d48c2780c improvement(ui): enhance ring outline for code subblock and mcp tool subblocks in agent (#1741) 2025-10-27 13:59:19 -07:00
Waleed
38614fad79 fix(mcp): resolve variables & block references in mcp subblocks (#1735)
* fix(mcp): resolve variables & block references in mcp subblocks

* cleanup

* ack PR comment

* added variables access to mcp tools when added in agent block

* fix sequential migrations issues
2025-10-27 13:13:11 -07:00
Waleed
6f32aea96b feat(kb): added support for local file storage for knowledgebase (#1738)
* feat(kb): added support for local file storage for knowledgebase

* updated tests

* ack PR comments

* added back env example
2025-10-27 11:28:45 -07:00
Waleed
98e98496e8 Revert "improvement(consts): removed redundant default consts in favor of env…" (#1739)
This reverts commit 659b46fa2f.
2025-10-26 23:06:14 -07:00
Waleed
659b46fa2f improvement(consts): removed redundant default consts in favor of envvar defaults for storage & usage limits (#1737)
* improvement(consts): removed redundant default consts in favor of envvar defaults for storage & usage limits

* remove unnecessary tests
2025-10-26 21:43:00 -07:00
Waleed
fb3d6d4c88 feat(files): added usage indicator for file storage to settings (#1736)
* feat(files): added usage indicator for file storage to settings

* cleanup
2025-10-26 21:36:25 -07:00
Waleed
ec2cc82b72 feat(i18n): update translations (#1734) 2025-10-26 18:35:20 -07:00
Adam Gough
274d5e3afc fix(clay): fixed clay tool (#1725)
* fixed clay tool

* added metadata

* added metadata to types

* fix(clay): remove (optional) from subblock name

* regen docs
2025-10-26 18:30:08 -07:00
Waleed
c552bb9c5f fix(elevenlabs): added internal auth helper for proxy routes (#1732)
* fix(elevenlabs): added internal auth helper for proxy routes

* remove concurrent tests

* build fix
2025-10-25 17:54:27 -07:00
Vikhyath Mondreti
ad7b791242 improvement(deployments): simplify deployments for chat and indicate active version (#1730)
* improvement(deployment-ux): deployment should indicate and make details configurable when activating previous version

* fix activation UI

* remove redundant code

* revert pulsing dot

* fix redeploy bug

* bill workspace owner for deployed chat

* deployed chat

* fix bugs

* fix tests, address greptile

* fix

* ui bug to load api key

* fix qdrant fetch tool
2025-10-25 16:55:34 -07:00
Waleed
ce4893a53c feat(sso-chat-deployment): added sso auth option for chat deployment (#1729)
* feat(sso-chat-deployment): added sso auth option for chat deployment

* ack PR comments
2025-10-25 14:58:25 -07:00
Vikhyath Mondreti
7f1ff7fd86 fix(billing): should allow restoring subscription (#1728)
* fix(already-cancelled-sub): UI should allow restoring subscription

* restore functionality fixed

* fix
2025-10-25 12:59:57 -07:00
Adam Gough
517f1a91b6 fix(google-scopes): added forms and different drive scope (#1532)
* added google forms scope and google drive scope

* added back file scope

---------

Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net>
Co-authored-by: Adam Gough <adamgough@Mac-530.lan>
2025-10-25 12:08:49 -07:00
Waleed
9b2490c4b1 v0.4.23: webflow tools + triggers, copilot api key fix (#1723)
* fix(debug-mode): remove duplicate debug mode flag (#1714)

* feat(i18n): update translations (#1709)

* improvement(condition): added variable and envvar highlighting for condition input (#1718)

* fix(dashboard): add additional context for paginated logs in dashboard, add empty state when selected cell has no data (#1719)

* fix(dashboard): add additional context for paginated logs in dashboard, add empty state when selected cell has no data

* apps/sim

* renaming

* remove relative import

* feat(tools): added webflow OAuth + tools (#1720)

* feat(tools): added webflow OAuth + tools

* remove itemId from delete item

* remove siteId

* added webhook triggers + oauth scopes + site/collection selector

* update sample payload for webflow triggers

* cleanup

* fix discord color

* feat(i18n): update translations (#1721)

* improvement(schedule): fix UI bug with schedule modal (#1722)
2025-10-23 14:48:09 -07:00
Waleed
dba7514350 improvement(schedule): fix UI bug with schedule modal (#1722) 2025-10-23 14:16:59 -07:00
Waleed
e94de1dd26 feat(i18n): update translations (#1721) 2025-10-23 13:15:05 -07:00
Waleed
a4e874b266 feat(tools): added webflow OAuth + tools (#1720)
* feat(tools): added webflow OAuth + tools

* remove itemId from delete item

* remove siteId

* added webhook triggers + oauth scopes + site/collection selector

* update sample payload for webflow triggers

* cleanup

* fix discord color
2025-10-23 13:08:32 -07:00
Waleed
ec034f3fc7 fix(dashboard): add additional context for paginated logs in dashboard, add empty state when selected cell has no data (#1719)
* fix(dashboard): add additional context for paginated logs in dashboard, add empty state when selected cell has no data

* apps/sim

* renaming

* remove relative import
2025-10-22 14:07:52 -07:00
Waleed
e425d064c0 improvement(condition): added variable and envvar highlighting for condition input (#1718) 2025-10-22 13:12:09 -07:00
Waleed
bcd1a2faf6 feat(i18n): update translations (#1709) 2025-10-22 12:55:36 -07:00
Vikhyath Mondreti
989a77261c fix(debug-mode): remove duplicate debug mode flag (#1714) 2025-10-22 00:49:18 -10:00
Vikhyath Mondreti
71ae27b6cd v0.4.22: fix execution context pass for google sheets 2025-10-21 19:48:06 -07:00
Vikhyath Mondreti
5ab482127d fix(remove-exec-context): tools handle workflow id check themselves 2025-10-21 16:34:08 -10:00
Vikhyath Mondreti
b8bc632baa fix(workflow-auth): adding workflowId param to only internal urls (#1710) 2025-10-21 16:30:22 -10:00
195 changed files with 6863 additions and 2198 deletions

View File

@@ -6,6 +6,7 @@ import Link from 'next/link'
import { notFound } from 'next/navigation'
import { StructuredData } from '@/components/structured-data'
import { CodeBlock } from '@/components/ui/code-block'
import { CopyPageButton } from '@/components/ui/copy-page-button'
import { source } from '@/lib/source'
export const dynamic = 'force-dynamic'
@@ -193,8 +194,19 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
component: <CustomFooter />,
}}
>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
<div className='relative'>
<div className='absolute top-1 right-0'>
<CopyPageButton
content={`# ${page.data.title}
${page.data.description || ''}
${page.data.content || ''}`}
/>
</div>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
</div>
<DocsBody>
<MDX
components={{

View File

@@ -36,7 +36,9 @@
/* Shift the sidebar slightly left from the content edge for extra breathing room */
--sidebar-shift: 90px;
--sidebar-offset: max(0px, calc(var(--edge-gutter) - var(--sidebar-shift)));
--toc-offset: var(--edge-gutter);
/* Shift TOC slightly right to match sidebar spacing for symmetry */
--toc-shift: 90px;
--toc-offset: max(0px, calc(var(--edge-gutter) - var(--toc-shift)));
/* Sidebar and TOC have 20px internal padding - navbar accounts for this directly */
/* Extra gap between sidebar/TOC and the main text content */
--content-gap: 1.75rem;
@@ -107,8 +109,21 @@ aside#nd-sidebar {
aside#nd-sidebar {
left: var(--sidebar-offset) !important;
}
[data-toc] {
margin-right: var(--toc-offset) !important;
/* TOC positioning - target all possible selectors */
[data-toc],
aside[data-toc],
div[data-toc],
.fd-toc,
#nd-toc,
nav[data-toc],
aside:has([role="complementary"]) {
right: var(--toc-offset) !important;
}
/* Alternative TOC container targeting */
[data-docs-page] > aside:last-child,
main ~ aside {
right: var(--toc-offset) !important;
}
}

View File

@@ -19,13 +19,13 @@ export function Navbar() {
{/* Desktop: Single row layout */}
<div className='hidden h-16 w-full items-center lg:flex'>
<div
className='grid w-full grid-cols-[auto_1fr_auto] items-center'
className='relative flex w-full items-center justify-between'
style={{
paddingLeft: 'calc(var(--sidebar-offset) + 20px)',
paddingRight: 'calc(var(--toc-offset) + 20px)',
paddingRight: 'calc(var(--toc-offset) + 60px)',
}}
>
{/* Left cluster: translate by sidebar delta to align with sidebar edge */}
{/* Left cluster: logo */}
<div className='flex items-center'>
<Link href='/' className='flex min-w-[100px] items-center'>
<Image
@@ -38,12 +38,12 @@ export function Navbar() {
</Link>
</div>
{/* Center cluster: search */}
<div className='flex flex-1 items-center justify-center pl-32'>
{/* Center cluster: search - absolutely positioned to center */}
<div className='-translate-x-1/2 absolute left-1/2 flex items-center justify-center'>
<SearchTrigger />
</div>
{/* Right cluster aligns with TOC edge using the same right gutter */}
{/* Right cluster aligns with TOC edge */}
<div className='flex items-center gap-4'>
<Link
href='https://sim.ai'

View File

@@ -0,0 +1,42 @@
'use client'
import { useState } from 'react'
import { Check, Copy } from 'lucide-react'
interface CopyPageButtonProps {
content: string
}
export function CopyPageButton({ content }: CopyPageButtonProps) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(content)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
} catch (err) {
console.error('Failed to copy:', err)
}
}
return (
<button
onClick={handleCopy}
className='flex items-center gap-1.5 rounded-lg border border-border/40 bg-background px-2.5 py-1.5 text-muted-foreground/60 text-sm transition-all hover:border-border hover:bg-accent/50 hover:text-muted-foreground'
aria-label={copied ? 'Copied to clipboard' : 'Copy page content'}
>
{copied ? (
<>
<Check className='h-4 w-4' />
<span>Copied</span>
</>
) : (
<>
<Copy className='h-4 w-4' />
<span>Copy page</span>
</>
)}
</button>
)
}

View File

@@ -207,18 +207,18 @@ Populate Clay with data from a JSON file. Enables direct communication and notif
#### Input
| Parameter | Type | Required | Description |
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `webhookURL` | string | Yes | The webhook URL to populate |
| `data` | json | Yes | The data to populate |
| `authToken` | string | Yes | Auth token for Clay webhook authentication |
| `webhookURL` | string | Ja | Die Webhook-URL, die befüllt werden soll |
| `data` | json | Ja | Die Daten, die befüllt werden sollen |
| `authToken` | string | Nein | Optionaler Auth-Token für die Clay-Webhook-Authentifizierung \(die meisten Webhooks benötigen dies nicht\) |
#### Output
| Parameter | Type | Description |
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | json | Clay populate operation results including response data from Clay webhook |
| `data` | json | Antwortdaten vom Clay-Webhook |
| `metadata` | object | Webhook-Antwort-Metadaten |
## Notes

View File

@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="discord"
color="#E0E0E0"
color="#5865F2"
icon={true}
iconSvg={`<svg className="block-icon"
@@ -72,6 +72,7 @@ Eine Nachricht an einen Discord-Kanal senden
| `channelId` | string | Ja | Die Discord-Kanal-ID, an die die Nachricht gesendet werden soll |
| `content` | string | Nein | Der Textinhalt der Nachricht |
| `serverId` | string | Ja | Die Discord-Server-ID \(Guild-ID\) |
| `files` | file[] | Nein | Dateien, die an die Nachricht angehängt werden sollen |
#### Ausgabe

View File

@@ -85,10 +85,11 @@ Eine Datei zu Google Drive hochladen
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `fileName` | string | Ja | Der Name der hochzuladenden Datei |
| `content` | string | Ja | Der Inhalt der hochzuladenden Datei |
| `mimeType` | string | Nein | Der MIME-Typ der hochzuladenden Datei |
| `file` | file | Nein | Binärdatei zum Hochladen (UserFile-Objekt) |
| `content` | string | Nein | Textinhalt zum Hochladen (verwenden Sie entweder diesen ODER file, nicht beides) |
| `mimeType` | string | Nein | Der MIME-Typ der hochzuladenden Datei (wird automatisch aus der Datei erkannt, wenn nicht angegeben) |
| `folderSelector` | string | Nein | Wählen Sie den Ordner aus, in den die Datei hochgeladen werden soll |
| `folderId` | string | Nein | Die ID des Ordners, in den die Datei hochgeladen werden soll \(interne Verwendung\) |
| `folderId` | string | Nein | Die ID des Ordners, in den die Datei hochgeladen werden soll (interne Verwendung) |
#### Ausgabe

View File

@@ -135,6 +135,7 @@ Inhalte in einem Microsoft Teams-Chat schreiben oder aktualisieren
| --------- | ---- | -------- | ----------- |
| `chatId` | string | Ja | Die ID des Chats, in den geschrieben werden soll |
| `content` | string | Ja | Der Inhalt, der in die Nachricht geschrieben werden soll |
| `files` | file[] | Nein | Dateien, die der Nachricht angehängt werden sollen |
#### Ausgabe
@@ -181,9 +182,10 @@ Schreiben oder senden einer Nachricht an einen Microsoft Teams-Kanal
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `teamId` | string | Ja | Die ID des Teams, an das geschrieben werden soll |
| `channelId` | string | Ja | Die ID des Kanals, an den geschrieben werden soll |
| `content` | string | Ja | Der Inhalt, der an den Kanal gesendet werden soll |
| `teamId` | string | Ja | Die ID des Teams, in das geschrieben werden soll |
| `channelId` | string | Ja | Die ID des Kanals, in den geschrieben werden soll |
| `content` | string | Ja | Der Inhalt, der in den Kanal geschrieben werden soll |
| `files` | file[] | Nein | Dateien, die der Nachricht angehängt werden sollen |
#### Ausgabe

View File

@@ -63,9 +63,10 @@ Eine Datei auf OneDrive hochladen
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `fileName` | string | Ja | Der Name der hochzuladenden Datei |
| `content` | string | Ja | Der Inhalt der hochzuladenden Datei |
| `file` | file | Nein | Die hochzuladende Datei (binär) |
| `content` | string | Nein | Der hochzuladende Textinhalt (falls keine Datei bereitgestellt wird) |
| `folderSelector` | string | Nein | Wählen Sie den Ordner aus, in den die Datei hochgeladen werden soll |
| `manualFolderId` | string | Nein | Manuell eingegebene Ordner-ID \(erweiterter Modus\) |
| `manualFolderId` | string | Nein | Manuell eingegebene Ordner-ID (erweiterter Modus) |
#### Ausgabe

View File

@@ -154,10 +154,11 @@ E-Mails über Outlook versenden
| `to` | string | Ja | E-Mail-Adresse des Empfängers |
| `subject` | string | Ja | E-Mail-Betreff |
| `body` | string | Ja | E-Mail-Inhalt |
| `replyToMessageId` | string | Nein | Nachrichten-ID für Antworten \(für Threading\) |
| `replyToMessageId` | string | Nein | Nachrichten-ID, auf die geantwortet wird \(für Threading\) |
| `conversationId` | string | Nein | Konversations-ID für Threading |
| `cc` | string | Nein | CC-Empfänger \(durch Kommas getrennt\) |
| `bcc` | string | Nein | BCC-Empfänger \(durch Kommas getrennt\) |
| `attachments` | file[] | Nein | Dateien, die an die E-Mail angehängt werden sollen |
#### Ausgabe
@@ -177,10 +178,11 @@ E-Mails mit Outlook erstellen
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `to` | string | Ja | E-Mail-Adresse des Empfängers |
| `subject` | string | Ja | Betreff der E-Mail |
| `body` | string | Ja | Inhalt der E-Mail |
| `cc` | string | Nein | CC-Empfänger \(durch Komma getrennt\) |
| `bcc` | string | Nein | BCC-Empfänger \(durch Komma getrennt\) |
| `subject` | string | Ja | E-Mail-Betreff |
| `body` | string | Ja | E-Mail-Inhalt |
| `cc` | string | Nein | CC-Empfänger \(durch Kommas getrennt\) |
| `bcc` | string | Nein | BCC-Empfänger \(durch Kommas getrennt\) |
| `attachments` | file[] | Nein | Dateien, die an den E-Mail-Entwurf angehängt werden sollen |
#### Ausgabe

View File

@@ -139,7 +139,8 @@ Suche nach ähnlichen Vektoren in einer Qdrant-Sammlung
| `collection` | string | Ja | Sammlungsname |
| `vector` | array | Ja | Zu suchender Vektor |
| `limit` | number | Nein | Anzahl der zurückzugebenden Ergebnisse |
| `filter` | object | Nein | Filter für die Suche |
| `filter` | object | Nein | Auf die Suche anzuwendender Filter |
| `search_return_data` | string | Nein | Aus der Suche zurückzugebende Daten |
| `with_payload` | boolean | Nein | Payload in Antwort einschließen |
| `with_vector` | boolean | Nein | Vektor in Antwort einschließen |
@@ -161,7 +162,8 @@ Punkte anhand der ID aus einer Qdrant-Sammlung abrufen
| `url` | string | Ja | Qdrant-Basis-URL |
| `apiKey` | string | Nein | Qdrant-API-Schlüssel \(optional\) |
| `collection` | string | Ja | Sammlungsname |
| `ids` | array | Ja | Array von abzurufenden Punkt-IDs |
| `ids` | array | Ja | Array von Punkt-IDs zum Abrufen |
| `fetch_return_data` | string | Nein | Aus dem Abruf zurückzugebende Daten |
| `with_payload` | boolean | Nein | Payload in Antwort einschließen |
| `with_vector` | boolean | Nein | Vektor in Antwort einschließen |

View File

@@ -199,6 +199,26 @@ Ein neues Element zu einer SharePoint-Liste hinzufügen
| --------- | ---- | ----------- |
| `item` | object | Erstelltes SharePoint-Listenelement |
### `sharepoint_upload_file`
Dateien in eine SharePoint-Dokumentenbibliothek hochladen
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `siteId` | string | Nein | Die ID der SharePoint-Website |
| `driveId` | string | Nein | Die ID der Dokumentenbibliothek (Laufwerk). Wenn nicht angegeben, wird das Standardlaufwerk verwendet. |
| `folderPath` | string | Nein | Optionaler Ordnerpfad innerhalb der Dokumentenbibliothek (z.B. /Documents/Subfolder) |
| `fileName` | string | Nein | Optional: Überschreiben des hochgeladenen Dateinamens |
| `files` | file[] | Nein | Dateien, die nach SharePoint hochgeladen werden sollen |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `uploadedFiles` | array | Array von hochgeladenen Dateiobjekten |
## Hinweise
- Kategorie: `tools`

View File

@@ -78,7 +78,8 @@ Senden Sie Nachrichten an Slack-Kanäle oder Benutzer über die Slack-API. Unter
| `authMethod` | string | Nein | Authentifizierungsmethode: oauth oder bot_token |
| `botToken` | string | Nein | Bot-Token für Custom Bot |
| `channel` | string | Ja | Ziel-Slack-Kanal \(z.B. #general\) |
| `text` | string | Ja | Zu sendender Nachrichtentext \(unterstützt Slack mrkdwn-Formatierung\) |
| `text` | string | Ja | Nachrichtentext zum Senden \(unterstützt Slack mrkdwn-Formatierung\) |
| `files` | file[] | Nein | Dateien, die an die Nachricht angehängt werden sollen |
#### Ausgabe

View File

@@ -202,6 +202,28 @@ Daten in eine Supabase-Tabelle einfügen oder aktualisieren (Upsert-Operation)
| `message` | string | Statusmeldung der Operation |
| `results` | array | Array der eingefügten/aktualisierten Datensätze |
### `supabase_vector_search`
Ähnlichkeitssuche mit pgvector in einer Supabase-Tabelle durchführen
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `projectId` | string | Ja | Ihre Supabase-Projekt-ID \(z.B. jdrkgepadsdopsntdlom\) |
| `functionName` | string | Ja | Der Name der PostgreSQL-Funktion, die die Vektorsuche durchführt \(z.B. match_documents\) |
| `queryEmbedding` | array | Ja | Der Abfragevektor/Embedding, nach dem ähnliche Elemente gesucht werden sollen |
| `matchThreshold` | number | Nein | Minimaler Ähnlichkeitsschwellenwert \(0-1\), typischerweise 0,7-0,9 |
| `matchCount` | number | Nein | Maximale Anzahl der zurückzugebenden Ergebnisse \(Standard: 10\) |
| `apiKey` | string | Ja | Ihr Supabase Service Role Secret Key |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `message` | string | Statusmeldung der Operation |
| `results` | array | Array von Datensätzen mit Ähnlichkeitswerten aus der Vektorsuche. Jeder Datensatz enthält ein Ähnlichkeitsfeld \(0-1\), das angibt, wie ähnlich er dem Abfragevektor ist. |
## Hinweise
- Kategorie: `tools`

View File

@@ -190,6 +190,26 @@ Senden Sie Animationen (GIFs) an Telegram-Kanäle oder Benutzer über die Telegr
| `message` | string | Erfolgs- oder Fehlermeldung |
| `data` | object | Telegram-Nachrichtendaten einschließlich optionaler Medien |
### `telegram_send_document`
Senden Sie Dokumente (PDF, ZIP, DOC, etc.) an Telegram-Kanäle oder -Nutzer über die Telegram Bot API.
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `botToken` | string | Ja | Ihr Telegram Bot API-Token |
| `chatId` | string | Ja | Ziel-Telegram-Chat-ID |
| `files` | file[] | Nein | Zu sendende Dokumentdatei \(PDF, ZIP, DOC, etc.\). Maximale Größe: 50MB |
| `caption` | string | Nein | Dokumentbeschreibung \(optional\) |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `message` | string | Erfolgs- oder Fehlermeldung |
| `data` | object | Telegram-Nachrichtendaten einschließlich Dokument |
## Hinweise
- Kategorie: `tools`

View File

@@ -59,8 +59,9 @@ Verarbeiten und analysieren Sie Bilder mit fortschrittlichen Vision-Modellen. F
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Ja | API-Schlüssel für den ausgewählten Modellanbieter |
| `imageUrl` | string | Ja | Öffentlich zugängliche Bild-URL |
| `model` | string | Nein | Zu verwendendes Vision-Modell \(gpt-4o, claude-3-opus-20240229, etc\) |
| `imageUrl` | string | Nein | Öffentlich zugängliche Bild-URL |
| `imageFile` | file | Nein | Zu analysierende Bilddatei |
| `model` | string | Nein | Zu verwendendes Vision-Modell \(gpt-4o, claude-3-opus-20240229, usw.\) |
| `prompt` | string | Nein | Benutzerdefinierte Eingabeaufforderung für die Bildanalyse |
#### Ausgabe

View File

@@ -0,0 +1,145 @@
---
title: Webflow
description: Webflow CMS-Sammlungen verwalten
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="webflow"
color="#E0E0E0"
icon={true}
iconSvg={`<svg className="block-icon"
viewBox='0 0 1080 674'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M1080 0L735.386 673.684H411.695L555.916 394.481H549.445C430.464 548.934 252.942 650.61 -0.000488281 673.684V398.344C-0.000488281 398.344 161.813 388.787 256.938 288.776H-0.000488281V0.0053214H288.771V237.515L295.252 237.489L413.254 0.0053214H631.644V236.009L638.126 235.999L760.555 0H1080Z'
fill='#146EF5'
/>
</svg>`}
/>
{/* MANUAL-CONTENT-START:intro */}
[Webflow](https://webflow.com/) ist eine leistungsstarke visuelle Webdesign-Plattform, mit der Sie responsive Websites ohne Programmierung erstellen können. Sie kombiniert eine visuelle Design-Oberfläche mit einem robusten CMS (Content Management System), das es Ihnen ermöglicht, dynamische Inhalte für Ihre Websites zu erstellen, zu verwalten und zu veröffentlichen.
Mit Webflow können Sie:
- **Visuell gestalten**: Erstellen Sie benutzerdefinierte Websites mit einem visuellen Editor, der sauberen, semantischen HTML/CSS-Code generiert
- **Inhalte dynamisch verwalten**: Nutzen Sie das CMS, um Sammlungen strukturierter Inhalte wie Blogbeiträge, Produkte, Teammitglieder oder beliebige benutzerdefinierte Daten zu erstellen
- **Sofort veröffentlichen**: Stellen Sie Ihre Websites auf Webflows Hosting bereit oder exportieren Sie den Code für benutzerdefiniertes Hosting
- **Responsive Designs erstellen**: Bauen Sie Websites, die nahtlos auf Desktop, Tablet und Mobilgeräten funktionieren
- **Sammlungen anpassen**: Definieren Sie benutzerdefinierte Felder und Datenstrukturen für Ihre Inhaltstypen
- **Inhaltsaktualisierungen automatisieren**: Verwalten Sie Ihre CMS-Inhalte programmgesteuert über APIs
In Sim ermöglicht die Webflow-Integration Ihren Agenten, nahtlos mit Ihren Webflow-CMS-Sammlungen über API-Authentifizierung zu interagieren. Dies ermöglicht leistungsstarke Automatisierungsszenarien wie das automatische Erstellen von Blogbeiträgen aus KI-generierten Inhalten, das Aktualisieren von Produktinformationen, das Verwalten von Teammitgliederprofilen und das Abrufen von CMS-Elementen für die dynamische Inhaltsgenerierung. Ihre Agenten können vorhandene Elemente auflisten, um Ihre Inhalte zu durchsuchen, bestimmte Elemente nach ID abrufen, neue Einträge erstellen, um frische Inhalte hinzuzufügen, bestehende Elemente aktualisieren, um Informationen aktuell zu halten, und veraltete Inhalte löschen. Diese Integration überbrückt die Lücke zwischen Ihren KI-Workflows und Ihrem Webflow-CMS und ermöglicht automatisierte Inhaltsverwaltung, dynamische Website-Aktualisierungen und optimierte Inhalts-Workflows, die Ihre Websites ohne manuelles Eingreifen frisch und aktuell halten.
{/* MANUAL-CONTENT-END */}
## Gebrauchsanweisung
Integriert Webflow CMS in den Workflow. Kann Elemente in Webflow CMS-Sammlungen erstellen, abrufen, auflisten, aktualisieren oder löschen. Verwalten Sie Ihre Webflow-Inhalte programmatisch. Kann im Trigger-Modus verwendet werden, um Workflows auszulösen, wenn sich Sammlungselemente ändern oder Formulare übermittelt werden.
## Tools
### `webflow_list_items`
Alle Elemente aus einer Webflow CMS-Sammlung auflisten
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Ja | ID der Sammlung |
| `offset` | number | Nein | Offset für Paginierung \(optional\) |
| `limit` | number | Nein | Maximale Anzahl der zurückzugebenden Elemente \(optional, Standard: 100\) |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `items` | json | Array von Sammlungselementen |
| `metadata` | json | Metadaten über die Abfrage |
### `webflow_get_item`
Ein einzelnes Element aus einer Webflow CMS-Sammlung abrufen
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Ja | ID der Sammlung |
| `itemId` | string | Ja | ID des abzurufenden Elements |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `item` | json | Das abgerufene Elementobjekt |
| `metadata` | json | Metadaten über das abgerufene Element |
### `webflow_create_item`
Ein neues Element in einer Webflow CMS-Sammlung erstellen
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Ja | ID der Sammlung |
| `fieldData` | json | Ja | Felddaten für das neue Element als JSON-Objekt. Die Schlüssel sollten mit den Feldnamen der Sammlung übereinstimmen. |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `item` | json | Das erstellte Element-Objekt |
| `metadata` | json | Metadaten über das erstellte Element |
### `webflow_update_item`
Ein vorhandenes Element in einer Webflow CMS-Sammlung aktualisieren
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Ja | ID der Sammlung |
| `itemId` | string | Ja | ID des zu aktualisierenden Elements |
| `fieldData` | json | Ja | Zu aktualisierende Felddaten als JSON-Objekt. Nur Felder einschließen, die geändert werden sollen. |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `item` | json | Das aktualisierte Element-Objekt |
| `metadata` | json | Metadaten über das aktualisierte Element |
### `webflow_delete_item`
Ein Element aus einer Webflow CMS-Sammlung löschen
#### Eingabe
| Parameter | Typ | Erforderlich | Beschreibung |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Ja | ID der Sammlung |
| `itemId` | string | Ja | ID des zu löschenden Elements |
#### Ausgabe
| Parameter | Typ | Beschreibung |
| --------- | ---- | ----------- |
| `success` | boolean | Ob die Löschung erfolgreich war |
| `metadata` | json | Metadaten über die Löschung |
## Hinweise
- Kategorie: `tools`
- Typ: `webflow`

View File

@@ -214,14 +214,14 @@ Populate Clay with data from a JSON file. Enables direct communication and notif
| --------- | ---- | -------- | ----------- |
| `webhookURL` | string | Yes | The webhook URL to populate |
| `data` | json | Yes | The data to populate |
| `authToken` | string | Yes | Auth token for Clay webhook authentication |
| `authToken` | string | No | Optional auth token for Clay webhook authentication \(most webhooks do not require this\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | json | Clay populate operation results including response data from Clay webhook |
| `data` | json | Response data from Clay webhook |
| `metadata` | object | Webhook response metadata |

View File

@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="discord"
color="#E0E0E0"
color="#5865F2"
icon={true}
iconSvg={`<svg className="block-icon"

View File

@@ -66,6 +66,7 @@
"typeform",
"vision",
"wealthbox",
"webflow",
"webhook",
"whatsapp",
"wikipedia",

View File

@@ -143,6 +143,7 @@ Search for similar vectors in a Qdrant collection
| `vector` | array | Yes | Vector to search for |
| `limit` | number | No | Number of results to return |
| `filter` | object | No | Filter to apply to the search |
| `search_return_data` | string | No | Data to return from search |
| `with_payload` | boolean | No | Include payload in response |
| `with_vector` | boolean | No | Include vector in response |
@@ -165,6 +166,7 @@ Fetch points by ID from a Qdrant collection
| `apiKey` | string | No | Qdrant API key \(optional\) |
| `collection` | string | Yes | Collection name |
| `ids` | array | Yes | Array of point IDs to fetch |
| `fetch_return_data` | string | No | Data to return from fetch |
| `with_payload` | boolean | No | Include payload in response |
| `with_vector` | boolean | No | Include vector in response |

View File

@@ -0,0 +1,150 @@
---
title: Webflow
description: Manage Webflow CMS collections
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="webflow"
color="#E0E0E0"
icon={true}
iconSvg={`<svg className="block-icon"
viewBox='0 0 1080 674'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M1080 0L735.386 673.684H411.695L555.916 394.481H549.445C430.464 548.934 252.942 650.61 -0.000488281 673.684V398.344C-0.000488281 398.344 161.813 388.787 256.938 288.776H-0.000488281V0.0053214H288.771V237.515L295.252 237.489L413.254 0.0053214H631.644V236.009L638.126 235.999L760.555 0H1080Z'
fill='#146EF5'
/>
</svg>`}
/>
{/* MANUAL-CONTENT-START:intro */}
[Webflow](https://webflow.com/) is a powerful visual web design platform that enables you to build responsive websites without writing code. It combines a visual design interface with a robust CMS (Content Management System) that allows you to create, manage, and publish dynamic content for your websites.
With Webflow, you can:
- **Design visually**: Create custom websites with a visual editor that generates clean, semantic HTML/CSS code
- **Manage content dynamically**: Use the CMS to create collections of structured content like blog posts, products, team members, or any custom data
- **Publish instantly**: Deploy your sites to Webflow's hosting or export the code for custom hosting
- **Create responsive designs**: Build sites that work seamlessly across desktop, tablet, and mobile devices
- **Customize collections**: Define custom fields and data structures for your content types
- **Automate content updates**: Programmatically manage your CMS content through APIs
In Sim, the Webflow integration enables your agents to seamlessly interact with your Webflow CMS collections through API authentication. This allows for powerful automation scenarios such as automatically creating blog posts from AI-generated content, updating product information, managing team member profiles, and retrieving CMS items for dynamic content generation. Your agents can list existing items to browse your content, retrieve specific items by ID, create new entries to add fresh content, update existing items to keep information current, and delete outdated content. This integration bridges the gap between your AI workflows and your Webflow CMS, enabling automated content management, dynamic website updates, and streamlined content workflows that keep your sites fresh and up-to-date without manual intervention.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrates Webflow CMS into the workflow. Can create, get, list, update, or delete items in Webflow CMS collections. Manage your Webflow content programmatically. Can be used in trigger mode to trigger workflows when collection items change or forms are submitted.
## Tools
### `webflow_list_items`
List all items from a Webflow CMS collection
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Yes | ID of the collection |
| `offset` | number | No | Offset for pagination \(optional\) |
| `limit` | number | No | Maximum number of items to return \(optional, default: 100\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `items` | json | Array of collection items |
| `metadata` | json | Metadata about the query |
### `webflow_get_item`
Get a single item from a Webflow CMS collection
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Yes | ID of the collection |
| `itemId` | string | Yes | ID of the item to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `item` | json | The retrieved item object |
| `metadata` | json | Metadata about the retrieved item |
### `webflow_create_item`
Create a new item in a Webflow CMS collection
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Yes | ID of the collection |
| `fieldData` | json | Yes | Field data for the new item as a JSON object. Keys should match collection field names. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `item` | json | The created item object |
| `metadata` | json | Metadata about the created item |
### `webflow_update_item`
Update an existing item in a Webflow CMS collection
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Yes | ID of the collection |
| `itemId` | string | Yes | ID of the item to update |
| `fieldData` | json | Yes | Field data to update as a JSON object. Only include fields you want to change. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `item` | json | The updated item object |
| `metadata` | json | Metadata about the updated item |
### `webflow_delete_item`
Delete an item from a Webflow CMS collection
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Yes | ID of the collection |
| `itemId` | string | Yes | ID of the item to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the deletion was successful |
| `metadata` | json | Metadata about the deletion |
## Notes
- Category: `tools`
- Type: `webflow`

View File

@@ -207,18 +207,18 @@ Poblar Clay con datos de un archivo JSON. Permite comunicación directa y notifi
#### Entrada
| Parámetro | Tipo | Requerido | Descripción |
| --------- | ---- | -------- | ----------- |
| `webhookURL` | string | Sí | La URL del webhook para poblar |
| `data` | json | Sí | Los datos para poblar |
| `authToken` | string | | Token de autenticación para la autenticación del webhook de Clay |
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | ----------- | ----------- |
| `webhookURL` | string | Sí | La URL del webhook a completar |
| `data` | json | Sí | Los datos para completar |
| `authToken` | string | No | Token de autenticación opcional para la autenticación del webhook de Clay \(la mayoría de los webhooks no requieren esto\) |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `success` | boolean | Estado de éxito de la operación |
| `output` | json | Resultados de la operación de poblado de Clay incluyendo datos de respuesta del webhook de Clay |
| `data` | json | Datos de respuesta del webhook de Clay |
| `metadata` | object | Metadatos de respuesta del webhook |
## Notas

View File

@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="discord"
color="#E0E0E0"
color="#5865F2"
icon={true}
iconSvg={`<svg className="block-icon"
@@ -67,11 +67,12 @@ Enviar un mensaje a un canal de Discord
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | ----------- | ----------- |
| --------- | ---- | -------- | ----------- |
| `botToken` | string | Sí | El token del bot para autenticación |
| `channelId` | string | Sí | El ID del canal de Discord donde enviar el mensaje |
| `channelId` | string | Sí | El ID del canal de Discord al que enviar el mensaje |
| `content` | string | No | El contenido de texto del mensaje |
| `serverId` | string | Sí | El ID del servidor de Discord \(ID del guild\) |
| `files` | file[] | No | Archivos para adjuntar al mensaje |
#### Salida

View File

@@ -85,9 +85,10 @@ Subir un archivo a Google Drive
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | ----------- | ----------- |
| `fileName` | string | Sí | El nombre del archivo a subir |
| `content` | string | | El contenido del archivo a subir |
| `mimeType` | string | No | El tipo MIME del archivo a subir |
| `folderSelector` | string | No | Selecciona la carpeta donde subir el archivo |
| `file` | file | No | Archivo binario para subir \(objeto UserFile\) |
| `content` | string | No | Contenido de texto para subir \(use esto O archivo, no ambos\) |
| `mimeType` | string | No | El tipo MIME del archivo a subir \(auto-detectado del archivo si no se proporciona\) |
| `folderSelector` | string | No | Seleccione la carpeta donde subir el archivo |
| `folderId` | string | No | El ID de la carpeta donde subir el archivo \(uso interno\) |
#### Salida

View File

@@ -133,8 +133,9 @@ Escribir o actualizar contenido en un chat de Microsoft Teams
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `chatId` | string | Sí | El ID del chat donde escribir |
| `content` | string | Sí | El contenido a escribir en el mensaje |
| `chatId` | string | Sí | El ID del chat en el que escribir |
| `content` | string | Sí | El contenido para escribir en el mensaje |
| `files` | file[] | No | Archivos para adjuntar al mensaje |
#### Salida
@@ -181,9 +182,10 @@ Escribir o enviar un mensaje a un canal de Microsoft Teams
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `teamId` | string | Sí | El ID del equipo al que escribir |
| `channelId` | string | Sí | El ID del canal al que escribir |
| `teamId` | string | Sí | El ID del equipo en el que escribir |
| `channelId` | string | Sí | El ID del canal en el que escribir |
| `content` | string | Sí | El contenido para escribir en el canal |
| `files` | file[] | No | Archivos para adjuntar al mensaje |
#### Salida

View File

@@ -61,11 +61,12 @@ Subir un archivo a OneDrive
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| --------- | ---- | ----------- | ----------- |
| `fileName` | string | Sí | El nombre del archivo a subir |
| `content` | string | | El contenido del archivo a subir |
| `file` | file | No | El archivo a subir \(binario\) |
| `content` | string | No | El contenido de texto a subir \(si no se proporciona un archivo\) |
| `folderSelector` | string | No | Seleccionar la carpeta donde subir el archivo |
| `manualFolderId` | string | No | ID de carpeta introducido manualmente \(modo avanzado\) |
| `manualFolderId` | string | No | ID de carpeta ingresado manualmente \(modo avanzado\) |
#### Salida

View File

@@ -150,14 +150,15 @@ Enviar correos electrónicos usando Outlook
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | ----------- | ----------- |
| --------- | ---- | -------- | ----------- |
| `to` | string | Sí | Dirección de correo electrónico del destinatario |
| `subject` | string | Sí | Asunto del correo electrónico |
| `body` | string | Sí | Contenido del cuerpo del correo electrónico |
| `replyToMessageId` | string | No | ID del mensaje al que responder (para hilos) |
| `replyToMessageId` | string | No | ID del mensaje al que responder \(para hilos\) |
| `conversationId` | string | No | ID de conversación para hilos |
| `cc` | string | No | Destinatarios en CC (separados por comas) |
| `bcc` | string | No | Destinatarios en CCO (separados por comas) |
| `cc` | string | No | Destinatarios en CC \(separados por comas\) |
| `bcc` | string | No | Destinatarios en CCO \(separados por comas\) |
| `attachments` | file[] | No | Archivos para adjuntar al correo electrónico |
#### Salida
@@ -181,6 +182,7 @@ Crear borradores de correos electrónicos usando Outlook
| `body` | string | Sí | Contenido del cuerpo del correo electrónico |
| `cc` | string | No | Destinatarios en CC \(separados por comas\) |
| `bcc` | string | No | Destinatarios en CCO \(separados por comas\) |
| `attachments` | file[] | No | Archivos para adjuntar al borrador de correo electrónico |
#### Salida

View File

@@ -133,13 +133,14 @@ Buscar vectores similares en una colección de Qdrant
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| --------- | ---- | ----------- | ----------- |
| `url` | string | Sí | URL base de Qdrant |
| `apiKey` | string | No | Clave API de Qdrant \(opcional\) |
| `collection` | string | Sí | Nombre de la colección |
| `vector` | array | Sí | Vector a buscar |
| `vector` | array | Sí | Vector para buscar |
| `limit` | number | No | Número de resultados a devolver |
| `filter` | object | No | Filtro a aplicar a la búsqueda |
| `filter` | object | No | Filtro para aplicar a la búsqueda |
| `search_return_data` | string | No | Datos a devolver de la búsqueda |
| `with_payload` | boolean | No | Incluir payload en la respuesta |
| `with_vector` | boolean | No | Incluir vector en la respuesta |
@@ -157,11 +158,12 @@ Obtener puntos por ID desde una colección de Qdrant
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| --------- | ---- | ----------- | ----------- |
| `url` | string | Sí | URL base de Qdrant |
| `apiKey` | string | No | Clave API de Qdrant \(opcional\) |
| `collection` | string | Sí | Nombre de la colección |
| `ids` | array | Sí | Array de IDs de puntos a obtener |
| `ids` | array | Sí | Array de IDs de puntos para recuperar |
| `fetch_return_data` | string | No | Datos a devolver de la recuperación |
| `with_payload` | boolean | No | Incluir payload en la respuesta |
| `with_vector` | boolean | No | Incluir vector en la respuesta |

View File

@@ -199,6 +199,26 @@ Añadir un nuevo elemento a una lista de SharePoint
| --------- | ---- | ----------- |
| `item` | object | Elemento de lista de SharePoint creado |
### `sharepoint_upload_file`
Subir archivos a una biblioteca de documentos de SharePoint
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `siteId` | cadena | No | El ID del sitio de SharePoint |
| `driveId` | cadena | No | El ID de la biblioteca de documentos \(unidad\). Si no se proporciona, usa la unidad predeterminada. |
| `folderPath` | cadena | No | Ruta de carpeta opcional dentro de la biblioteca de documentos \(p. ej., /Documents/Subfolder\) |
| `fileName` | cadena | No | Opcional: sobrescribir el nombre del archivo subido |
| `files` | archivo[] | No | Archivos para subir a SharePoint |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `uploadedFiles` | array | Array de objetos de archivos subidos |
## Notas
- Categoría: `tools`

View File

@@ -79,6 +79,7 @@ Envía mensajes a canales o usuarios de Slack a través de la API de Slack. Comp
| `botToken` | string | No | Token del bot para Bot personalizado |
| `channel` | string | Sí | Canal de Slack objetivo (p. ej., #general) |
| `text` | string | Sí | Texto del mensaje a enviar (admite formato mrkdwn de Slack) |
| `files` | file[] | No | Archivos para adjuntar al mensaje |
#### Salida

View File

@@ -202,6 +202,28 @@ Insertar o actualizar datos en una tabla de Supabase (operación upsert)
| `message` | string | Mensaje de estado de la operación |
| `results` | array | Array de registros insertados o actualizados |
### `supabase_vector_search`
Realizar búsqueda de similitud usando pgvector en una tabla de Supabase
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | ----------- | ----------- |
| `projectId` | string | Sí | ID de tu proyecto Supabase \(p. ej., jdrkgepadsdopsntdlom\) |
| `functionName` | string | Sí | Nombre de la función PostgreSQL que realiza la búsqueda vectorial \(p. ej., match_documents\) |
| `queryEmbedding` | array | Sí | El vector/embedding de consulta para buscar elementos similares |
| `matchThreshold` | number | No | Umbral mínimo de similitud \(0-1\), típicamente 0.7-0.9 |
| `matchCount` | number | No | Número máximo de resultados a devolver \(predeterminado: 10\) |
| `apiKey` | string | Sí | Tu clave secreta de rol de servicio de Supabase |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `message` | string | Mensaje de estado de la operación |
| `results` | array | Array de registros con puntuaciones de similitud de la búsqueda vectorial. Cada registro incluye un campo de similitud \(0-1\) que indica cuán similar es al vector de consulta. |
## Notas
- Categoría: `tools`

View File

@@ -190,6 +190,26 @@ Envía animaciones (GIFs) a canales o usuarios de Telegram a través de la API d
| `message` | string | Mensaje de éxito o error |
| `data` | object | Datos del mensaje de Telegram incluyendo medios opcionales |
### `telegram_send_document`
Envía documentos (PDF, ZIP, DOC, etc.) a canales o usuarios de Telegram a través de la API de Bot de Telegram.
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | ----------- | ----------- |
| `botToken` | string | Sí | Tu token de API de Bot de Telegram |
| `chatId` | string | Sí | ID del chat de Telegram objetivo |
| `files` | file[] | No | Archivo de documento para enviar \(PDF, ZIP, DOC, etc.\). Tamaño máximo: 50MB |
| `caption` | string | No | Leyenda del documento \(opcional\) |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `message` | string | Mensaje de éxito o error |
| `data` | object | Datos del mensaje de Telegram incluyendo documento |
## Notas
- Categoría: `tools`

View File

@@ -57,11 +57,12 @@ Procesa y analiza imágenes utilizando modelos avanzados de visión. Capaz de co
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | ----------- | ----------- |
| --------- | ---- | ---------- | ----------- |
| `apiKey` | string | Sí | Clave API para el proveedor de modelo seleccionado |
| `imageUrl` | string | | URL de imagen de acceso público |
| `imageUrl` | string | No | URL de imagen accesible públicamente |
| `imageFile` | file | No | Archivo de imagen para analizar |
| `model` | string | No | Modelo de visión a utilizar \(gpt-4o, claude-3-opus-20240229, etc\) |
| `prompt` | string | No | Indicación personalizada para análisis de imágenes |
| `prompt` | string | No | Prompt personalizado para análisis de imagen |
#### Salida

View File

@@ -0,0 +1,145 @@
---
title: Webflow
description: Gestionar colecciones CMS de Webflow
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="webflow"
color="#E0E0E0"
icon={true}
iconSvg={`<svg className="block-icon"
viewBox='0 0 1080 674'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M1080 0L735.386 673.684H411.695L555.916 394.481H549.445C430.464 548.934 252.942 650.61 -0.000488281 673.684V398.344C-0.000488281 398.344 161.813 388.787 256.938 288.776H-0.000488281V0.0053214H288.771V237.515L295.252 237.489L413.254 0.0053214H631.644V236.009L638.126 235.999L760.555 0H1080Z'
fill='#146EF5'
/>
</svg>`}
/>
{/* MANUAL-CONTENT-START:intro */}
[Webflow](https://webflow.com/) es una potente plataforma visual de diseño web que te permite crear sitios web responsivos sin escribir código. Combina una interfaz de diseño visual con un robusto CMS (Sistema de Gestión de Contenidos) que te permite crear, gestionar y publicar contenido dinámico para tus sitios web.
Con Webflow, puedes:
- **Diseñar visualmente**: Crear sitios web personalizados con un editor visual que genera código HTML/CSS limpio y semántico
- **Gestionar contenido dinámicamente**: Usar el CMS para crear colecciones de contenido estructurado como entradas de blog, productos, miembros del equipo o cualquier dato personalizado
- **Publicar instantáneamente**: Implementar tus sitios en el alojamiento de Webflow o exportar el código para alojamiento personalizado
- **Crear diseños responsivos**: Construir sitios que funcionen perfectamente en dispositivos de escritorio, tabletas y móviles
- **Personalizar colecciones**: Definir campos personalizados y estructuras de datos para tus tipos de contenido
- **Automatizar actualizaciones de contenido**: Gestionar programáticamente el contenido de tu CMS a través de APIs
En Sim, la integración con Webflow permite a tus agentes interactuar sin problemas con tus colecciones CMS de Webflow mediante autenticación API. Esto permite potentes escenarios de automatización como la creación automática de entradas de blog a partir de contenido generado por IA, actualización de información de productos, gestión de perfiles de miembros del equipo y recuperación de elementos CMS para la generación de contenido dinámico. Tus agentes pueden listar elementos existentes para navegar por tu contenido, recuperar elementos específicos por ID, crear nuevas entradas para añadir contenido fresco, actualizar elementos existentes para mantener la información actualizada y eliminar contenido obsoleto. Esta integración cierra la brecha entre tus flujos de trabajo de IA y tu CMS de Webflow, permitiendo la gestión automatizada de contenido, actualizaciones dinámicas del sitio web y flujos de trabajo de contenido optimizados que mantienen tus sitios frescos y actualizados sin intervención manual.
{/* MANUAL-CONTENT-END */}
## Instrucciones de uso
Integra el CMS de Webflow en el flujo de trabajo. Puede crear, obtener, listar, actualizar o eliminar elementos en las colecciones del CMS de Webflow. Gestiona tu contenido de Webflow de forma programática. Se puede usar en modo de activación para iniciar flujos de trabajo cuando cambian los elementos de la colección o se envían formularios.
## Herramientas
### `webflow_list_items`
Listar todos los elementos de una colección del CMS de Webflow
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Sí | ID de la colección |
| `offset` | number | No | Desplazamiento para paginación \(opcional\) |
| `limit` | number | No | Número máximo de elementos a devolver \(opcional, predeterminado: 100\) |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `items` | json | Array de elementos de la colección |
| `metadata` | json | Metadatos sobre la consulta |
### `webflow_get_item`
Obtener un solo elemento de una colección del CMS de Webflow
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Sí | ID de la colección |
| `itemId` | string | Sí | ID del elemento a recuperar |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `item` | json | El objeto del elemento recuperado |
| `metadata` | json | Metadatos sobre el elemento recuperado |
### `webflow_create_item`
Crear un nuevo elemento en una colección del CMS de Webflow
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Sí | ID de la colección |
| `fieldData` | json | Sí | Datos de campo para el nuevo elemento como objeto JSON. Las claves deben coincidir con los nombres de campo de la colección. |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `item` | json | El objeto del elemento creado |
| `metadata` | json | Metadatos sobre el elemento creado |
### `webflow_update_item`
Actualizar un elemento existente en una colección CMS de Webflow
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Sí | ID de la colección |
| `itemId` | string | Sí | ID del elemento a actualizar |
| `fieldData` | json | Sí | Datos de campo para actualizar como objeto JSON. Solo incluye los campos que quieres cambiar. |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `item` | json | El objeto del elemento actualizado |
| `metadata` | json | Metadatos sobre el elemento actualizado |
### `webflow_delete_item`
Eliminar un elemento de una colección CMS de Webflow
#### Entrada
| Parámetro | Tipo | Obligatorio | Descripción |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Sí | ID de la colección |
| `itemId` | string | Sí | ID del elemento a eliminar |
#### Salida
| Parámetro | Tipo | Descripción |
| --------- | ---- | ----------- |
| `success` | boolean | Si la eliminación fue exitosa |
| `metadata` | json | Metadatos sobre la eliminación |
## Notas
- Categoría: `tools`
- Tipo: `webflow`

View File

@@ -211,14 +211,14 @@ Remplir Clay avec des données provenant d'un fichier JSON. Permet une communica
| --------- | ---- | ---------- | ----------- |
| `webhookURL` | string | Oui | L'URL du webhook à remplir |
| `data` | json | Oui | Les données à remplir |
| `authToken` | string | Oui | Jeton d'authentification pour l'authentification du webhook Clay |
| `authToken` | string | Non | Jeton d'authentification optionnel pour l'authentification du webhook Clay \(la plupart des webhooks ne nécessitent pas cela\) |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Statut de réussite de l'opération |
| `output` | json | Résultats de l'opération de remplissage Clay incluant les données de réponse du webhook Clay |
| `data` | json | Données de réponse du webhook Clay |
| `metadata` | object | Métadonnées de réponse du webhook |
## Notes

View File

@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="discord"
color="#E0E0E0"
color="#5865F2"
icon={true}
iconSvg={`<svg className="block-icon"
@@ -72,6 +72,7 @@ Envoyer un message à un canal Discord
| `channelId` | chaîne | Oui | L'ID du canal Discord où envoyer le message |
| `content` | chaîne | Non | Le contenu textuel du message |
| `serverId` | chaîne | Oui | L'ID du serveur Discord \(ID de guilde\) |
| `files` | fichier[] | Non | Fichiers à joindre au message |
#### Sortie

View File

@@ -84,11 +84,12 @@ Téléverser un fichier vers Google Drive
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `fileName` | chaîne | Oui | Le nom du fichier à téléverser |
| `content` | chaîne | Oui | Le contenu du fichier à téléverser |
| `mimeType` | chaîne | Non | Le type MIME du fichier à téléverser |
| `folderSelector` | chaîne | Non | Sélectionnez le dossier téléverser le fichier |
| `folderId` | chaîne | Non | L'ID du dossier où téléverser le fichier \(usage interne\) |
| `fileName` | string | Oui | Le nom du fichier à télécharger |
| `file` | file | Non | Fichier binaire à télécharger \(objet UserFile\) |
| `content` | string | Non | Contenu textuel à télécharger \(utilisez ceci OU fichier, pas les deux\) |
| `mimeType` | string | Non | Le type MIME du fichier à télécharger \(détecté automatiquement à partir du fichier si non fourni\) |
| `folderSelector` | string | Non | Sélectionnez le dossier dans lequel télécharger le fichier |
| `folderId` | string | Non | L'ID du dossier dans lequel télécharger le fichier \(usage interne\) |
#### Sortie

View File

@@ -135,6 +135,7 @@ Lire le contenu d'un chat Microsoft Teams
| --------- | ---- | -------- | ----------- |
| `chatId` | chaîne | Oui | L'ID de la conversation dans laquelle écrire |
| `content` | chaîne | Oui | Le contenu à écrire dans le message |
| `files` | fichier[] | Non | Fichiers à joindre au message |
#### Sortie
@@ -180,10 +181,11 @@ Lire le contenu d'un canal Microsoft Teams
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `teamId` | chaîne | Oui | L'ID de l'équipe à laquelle écrire |
| `channelId` | chaîne | Oui | L'ID du canal auquel écrire |
| --------- | ---- | -------- | ----------- |
| `teamId` | chaîne | Oui | L'ID de l'équipe dans laquelle écrire |
| `channelId` | chaîne | Oui | L'ID du canal dans lequel écrire |
| `content` | chaîne | Oui | Le contenu à écrire dans le canal |
| `files` | fichier[] | Non | Fichiers à joindre au message |
#### Sortie

View File

@@ -61,11 +61,12 @@ Télécharger un fichier vers OneDrive
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | -------- | ----------- |
| `fileName` | chaîne | Oui | Le nom du fichier à télécharger |
| `content` | chaîne | Oui | Le contenu du fichier à télécharger |
| `folderSelector` | chaîne | Non | Sélectionnez le dossier où télécharger le fichier |
| `manualFolderId` | chaîne | Non | ID du dossier saisi manuellement \(mode avancé\) |
| --------- | ---- | ---------- | ----------- |
| `fileName` | string | Oui | Le nom du fichier à télécharger |
| `file` | file | Non | Le fichier à télécharger \(binaire\) |
| `content` | string | Non | Le contenu textuel à télécharger \(si aucun fichier n'est fourni\) |
| `folderSelector` | string | Non | Sélectionner le dossier dans lequel télécharger le fichier |
| `manualFolderId` | string | Non | ID de dossier saisi manuellement \(mode avancé\) |
#### Sortie

View File

@@ -150,14 +150,15 @@ Envoyer des e-mails avec Outlook
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ----------- | ----------- |
| `to` | chaîne | Oui | Adresse e-mail du destinataire |
| `subject` | chaîne | Oui | Objet de l'e-mail |
| `body` | chaîne | Oui | Contenu du corps de l'e-mail |
| `replyToMessageId` | chaîne | Non | ID du message auquel répondre \(pour le fil de discussion\) |
| `conversationId` | chaîne | Non | ID de conversation pour le fil de discussion |
| `cc` | chaîne | Non | Destinataires en CC \(séparés par des virgules\) |
| `bcc` | chaîne | Non | Destinataires en BCC \(séparés par des virgules\) |
| --------- | ---- | ---------- | ----------- |
| `to` | string | Oui | Adresse e-mail du destinataire |
| `subject` | string | Oui | Objet de l'e-mail |
| `body` | string | Oui | Contenu du corps de l'e-mail |
| `replyToMessageId` | string | Non | ID du message auquel répondre \(pour le fil de discussion\) |
| `conversationId` | string | Non | ID de conversation pour le fil de discussion |
| `cc` | string | Non | Destinataires en CC \(séparés par des virgules\) |
| `bcc` | string | Non | Destinataires en BCC \(séparés par des virgules\) |
| `attachments` | file[] | Non | Fichiers à joindre à l'e-mail |
#### Sortie
@@ -175,12 +176,13 @@ Rédiger des e-mails avec Outlook
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | -------- | ----------- |
| --------- | ---- | ---------- | ----------- |
| `to` | string | Oui | Adresse e-mail du destinataire |
| `subject` | string | Oui | Objet de l'e-mail |
| `body` | string | Oui | Contenu du corps de l'e-mail |
| `cc` | string | Non | Destinataires en CC \(séparés par des virgules\) |
| `bcc` | string | Non | Destinataires en BCC \(séparés par des virgules\) |
| `attachments` | file[] | Non | Fichiers à joindre au brouillon d'e-mail |
#### Sortie

View File

@@ -133,13 +133,14 @@ Rechercher des vecteurs similaires dans une collection Qdrant
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `url` | chaîne | Oui | URL de base Qdrant |
| --------- | ---- | ----------- | ----------- |
| `url` | chaîne | Oui | URL de base de Qdrant |
| `apiKey` | chaîne | Non | Clé API Qdrant \(facultative\) |
| `collection` | chaîne | Oui | Nom de la collection |
| `vector` | tableau | Oui | Vecteur à rechercher |
| `limit` | nombre | Non | Nombre de résultats à retourner |
| `filter` | objet | Non | Filtre à appliquer à la recherche |
| `search_return_data` | chaîne | Non | Données à retourner de la recherche |
| `with_payload` | booléen | Non | Inclure la charge utile dans la réponse |
| `with_vector` | booléen | Non | Inclure le vecteur dans la réponse |
@@ -157,11 +158,12 @@ Récupérer des points par ID depuis une collection Qdrant
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `url` | chaîne | Oui | URL de base Qdrant |
| --------- | ---- | ----------- | ----------- |
| `url` | chaîne | Oui | URL de base de Qdrant |
| `apiKey` | chaîne | Non | Clé API Qdrant \(facultative\) |
| `collection` | chaîne | Oui | Nom de la collection |
| `ids` | tableau | Oui | Tableau d'identifiants de points à récupérer |
| `fetch_return_data` | chaîne | Non | Données à retourner de la récupération |
| `with_payload` | booléen | Non | Inclure la charge utile dans la réponse |
| `with_vector` | booléen | Non | Inclure le vecteur dans la réponse |

View File

@@ -199,6 +199,26 @@ Ajouter un nouvel élément à une liste SharePoint
| --------- | ---- | ----------- |
| `item` | object | Élément de liste SharePoint créé |
### `sharepoint_upload_file`
Télécharger des fichiers vers une bibliothèque de documents SharePoint
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `siteId` | chaîne | Non | L'ID du site SharePoint |
| `driveId` | chaîne | Non | L'ID de la bibliothèque de documents \(lecteur\). Si non fourni, utilise le lecteur par défaut. |
| `folderPath` | chaîne | Non | Chemin de dossier optionnel dans la bibliothèque de documents \(par exemple, /Documents/Sousdossier\) |
| `fileName` | chaîne | Non | Optionnel : remplacer le nom du fichier téléchargé |
| `files` | fichier[] | Non | Fichiers à télécharger vers SharePoint |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `uploadedFiles` | tableau | Tableau d'objets de fichiers téléchargés |
## Remarques
- Catégorie : `tools`

View File

@@ -75,11 +75,12 @@ Envoyez des messages aux canaux ou utilisateurs Slack via l'API Slack. Prend en
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ----------- | ----------- |
| --------- | ---- | ---------- | ----------- |
| `authMethod` | chaîne | Non | Méthode d'authentification : oauth ou bot_token |
| `botToken` | chaîne | Non | Jeton du bot pour le Bot personnalisé |
| `channel` | chaîne | Oui | Canal Slack cible (par ex., #general) |
| `text` | chaîne | Oui | Texte du message à envoyer (prend en charge le formatage mrkdwn de Slack) |
| `botToken` | chaîne | Non | Jeton du bot pour Bot personnalisé |
| `channel` | chaîne | Oui | Canal Slack cible \(par ex., #general\) |
| `text` | chaîne | Oui | Texte du message à envoyer \(prend en charge le formatage mrkdwn de Slack\) |
| `files` | fichier[] | Non | Fichiers à joindre au message |
#### Sortie

View File

@@ -202,6 +202,28 @@ Insérer ou mettre à jour des données dans une table Supabase (opération upse
| `message` | string | Message d'état de l'opération |
| `results` | array | Tableau des enregistrements insérés ou mis à jour |
### `supabase_vector_search`
Effectuer une recherche de similarité en utilisant pgvector dans une table Supabase
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ----------- | ----------- |
| `projectId` | chaîne | Oui | L'ID de votre projet Supabase (ex. : jdrkgepadsdopsntdlom) |
| `functionName` | chaîne | Oui | Le nom de la fonction PostgreSQL qui effectue la recherche vectorielle (ex. : match_documents) |
| `queryEmbedding` | tableau | Oui | Le vecteur/embedding de requête pour rechercher des éléments similaires |
| `matchThreshold` | nombre | Non | Seuil minimum de similarité (0-1), généralement 0,7-0,9 |
| `matchCount` | nombre | Non | Nombre maximum de résultats à retourner (par défaut : 10) |
| `apiKey` | chaîne | Oui | Votre clé secrète de rôle de service Supabase |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `message` | chaîne | Message d'état de l'opération |
| `results` | tableau | Tableau d'enregistrements avec scores de similarité issus de la recherche vectorielle. Chaque enregistrement inclut un champ de similarité (0-1) indiquant son degré de similarité avec le vecteur de requête. |
## Notes
- Catégorie : `tools`

View File

@@ -190,6 +190,26 @@ Envoyez des animations (GIF) aux canaux ou utilisateurs Telegram via l'API Bot T
| `message` | chaîne | Message de succès ou d'erreur |
| `data` | objet | Données du message Telegram incluant les médias optionnels |
### `telegram_send_document`
Envoyez des documents (PDF, ZIP, DOC, etc.) aux canaux ou utilisateurs Telegram via l'API Bot Telegram.
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ----------- | ----------- |
| `botToken` | chaîne | Oui | Votre jeton d'API Bot Telegram |
| `chatId` | chaîne | Oui | ID du chat Telegram cible |
| `files` | fichier[] | Non | Fichier document à envoyer \(PDF, ZIP, DOC, etc.\). Taille max : 50 Mo |
| `caption` | chaîne | Non | Légende du document \(facultatif\) |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `message` | chaîne | Message de succès ou d'erreur |
| `data` | objet | Données du message Telegram incluant le document |
## Notes
- Catégorie : `tools`

View File

@@ -58,10 +58,11 @@ Traitez et analysez des images en utilisant des modèles de vision avancés. Cap
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `apiKey` | chaîne | Oui | Clé API pour le fournisseur de modèle sélectionné |
| `imageUrl` | chaîne | Oui | URL d'image accessible publiquement |
| `model` | chaîne | Non | Modèle de vision à utiliser \(gpt-4o, claude-3-opus-20240229, etc\) |
| `prompt` | chaîne | Non | Prompt personnalisé pour l'analyse d'image |
| `apiKey` | string | Oui | Clé API pour le fournisseur de modèle sélectionné |
| `imageUrl` | string | Non | URL d'image accessible publiquement |
| `imageFile` | file | Non | Fichier image à analyser |
| `model` | string | Non | Modèle de vision à utiliser \(gpt-4o, claude-3-opus-20240229, etc\) |
| `prompt` | string | Non | Invite personnalisée pour l'analyse d'image |
#### Sortie

View File

@@ -0,0 +1,145 @@
---
title: Webflow
description: Gérer les collections CMS de Webflow
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="webflow"
color="#E0E0E0"
icon={true}
iconSvg={`<svg className="block-icon"
viewBox='0 0 1080 674'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M1080 0L735.386 673.684H411.695L555.916 394.481H549.445C430.464 548.934 252.942 650.61 -0.000488281 673.684V398.344C-0.000488281 398.344 161.813 388.787 256.938 288.776H-0.000488281V0.0053214H288.771V237.515L295.252 237.489L413.254 0.0053214H631.644V236.009L638.126 235.999L760.555 0H1080Z'
fill='#146EF5'
/>
</svg>`}
/>
{/* MANUAL-CONTENT-START:intro */}
[Webflow](https://webflow.com/) est une plateforme puissante de conception web visuelle qui vous permet de créer des sites web responsifs sans écrire de code. Elle combine une interface de conception visuelle avec un CMS (système de gestion de contenu) robuste qui vous permet de créer, gérer et publier du contenu dynamique pour vos sites web.
Avec Webflow, vous pouvez :
- **Concevoir visuellement** : créer des sites web personnalisés avec un éditeur visuel qui génère du code HTML/CSS propre et sémantique
- **Gérer du contenu dynamiquement** : utiliser le CMS pour créer des collections de contenu structuré comme des articles de blog, des produits, des membres d'équipe ou toute donnée personnalisée
- **Publier instantanément** : déployer vos sites sur l'hébergement de Webflow ou exporter le code pour un hébergement personnalisé
- **Créer des designs responsifs** : construire des sites qui fonctionnent parfaitement sur ordinateur, tablette et appareils mobiles
- **Personnaliser les collections** : définir des champs personnalisés et des structures de données pour vos types de contenu
- **Automatiser les mises à jour de contenu** : gérer programmatiquement votre contenu CMS via des API
Dans Sim, l'intégration Webflow permet à vos agents d'interagir de manière transparente avec vos collections CMS Webflow grâce à l'authentification API. Cela permet des scénarios d'automatisation puissants tels que la création automatique d'articles de blog à partir de contenu généré par IA, la mise à jour d'informations sur les produits, la gestion des profils des membres de l'équipe et la récupération d'éléments CMS pour la génération de contenu dynamique. Vos agents peuvent lister les éléments existants pour parcourir votre contenu, récupérer des éléments spécifiques par ID, créer de nouvelles entrées pour ajouter du contenu frais, mettre à jour des éléments existants pour maintenir les informations à jour et supprimer du contenu obsolète. Cette intégration comble le fossé entre vos flux de travail IA et votre CMS Webflow, permettant une gestion automatisée du contenu, des mises à jour dynamiques de sites web et des flux de travail de contenu rationalisés qui maintiennent vos sites frais et à jour sans intervention manuelle.
{/* MANUAL-CONTENT-END */}
## Instructions d'utilisation
Intègre le CMS Webflow dans le flux de travail. Peut créer, obtenir, lister, mettre à jour ou supprimer des éléments dans les collections CMS Webflow. Gérez votre contenu Webflow par programmation. Peut être utilisé en mode déclencheur pour lancer des flux de travail lorsque les éléments de collection changent ou lorsque des formulaires sont soumis.
## Outils
### `webflow_list_items`
Lister tous les éléments d'une collection CMS Webflow
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Oui | ID de la collection |
| `offset` | number | Non | Décalage pour la pagination \(facultatif\) |
| `limit` | number | Non | Nombre maximum d'éléments à retourner \(facultatif, par défaut : 100\) |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `items` | json | Tableau des éléments de la collection |
| `metadata` | json | Métadonnées sur la requête |
### `webflow_get_item`
Obtenir un seul élément d'une collection CMS Webflow
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | Oui | ID de la collection |
| `itemId` | string | Oui | ID de l'élément à récupérer |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `item` | json | L'objet de l'élément récupéré |
| `metadata` | json | Métadonnées sur l'élément récupéré |
### `webflow_create_item`
Créer un nouvel élément dans une collection CMS Webflow
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `collectionId` | string | Oui | ID de la collection |
| `fieldData` | json | Oui | Données de champ pour le nouvel élément sous forme d'objet JSON. Les clés doivent correspondre aux noms des champs de la collection. |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `item` | json | L'objet de l'élément créé |
| `metadata` | json | Métadonnées concernant l'élément créé |
### `webflow_update_item`
Mettre à jour un élément existant dans une collection CMS Webflow
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `collectionId` | string | Oui | ID de la collection |
| `itemId` | string | Oui | ID de l'élément à mettre à jour |
| `fieldData` | json | Oui | Données de champ à mettre à jour sous forme d'objet JSON. N'incluez que les champs que vous souhaitez modifier. |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `item` | json | L'objet de l'élément mis à jour |
| `metadata` | json | Métadonnées concernant l'élément mis à jour |
### `webflow_delete_item`
Supprimer un élément d'une collection CMS Webflow
#### Entrée
| Paramètre | Type | Obligatoire | Description |
| --------- | ---- | ---------- | ----------- |
| `collectionId` | string | Oui | ID de la collection |
| `itemId` | string | Oui | ID de l'élément à supprimer |
#### Sortie
| Paramètre | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Indique si la suppression a réussi |
| `metadata` | json | Métadonnées concernant la suppression |
## Notes
- Catégorie : `tools`
- Type : `webflow`

View File

@@ -207,18 +207,18 @@ Populate Clay with data from a JSON file. Enables direct communication and notif
#### Input
| Parameter | Type | Required | Description |
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `webhookURL` | string | Yes | The webhook URL to populate |
| `data` | json | Yes | The data to populate |
| `authToken` | string | Yes | Auth token for Clay webhook authentication |
| `webhookURL` | string | はい | 設定するウェブフックURL |
| `data` | json | はい | 設定するデータ |
| `authToken` | string | いいえ | Clayウェブフック認証用のオプション認証トークンほとんどのウェブフックではこれは不要です |
#### Output
| Parameter | Type | Description |
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | json | Clay populate operation results including response data from Clay webhook |
| `data` | json | Clayウェブフックからのレスポンスデータ |
| `metadata` | object | ウェブフックレスポンスのメタデータ |
## Notes

View File

@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="discord"
color="#E0E0E0"
color="#5865F2"
icon={true}
iconSvg={`<svg className="block-icon"
@@ -72,6 +72,7 @@ Discordチャンネルにメッセージを送信する
| `channelId` | string | はい | メッセージを送信するDiscordチャンネルID |
| `content` | string | いいえ | メッセージのテキスト内容 |
| `serverId` | string | はい | DiscordサーバーIDギルドID |
| `files` | file[] | いいえ | メッセージに添付するファイル |
#### 出力

View File

@@ -85,8 +85,9 @@ Google Driveをワークフローに統合します。ファイルの作成、
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `fileName` | string | はい | アップロードするファイルの名前 |
| `content` | string | はい | アップロードするファイルの内容 |
| `mimeType` | string | いいえ | アップロードするファイルのMIMEタイプ |
| `file` | file | いいえ | アップロードするバイナリファイルUserFileオブジェクト |
| `content` | string | いいえ | アップロードするテキストコンテンツfileかこちらのどちらか一方を使用、両方は不可 |
| `mimeType` | string | いいえ | アップロードするファイルのMIMEタイプ指定がない場合はファイルから自動検出 |
| `folderSelector` | string | いいえ | ファイルをアップロードするフォルダを選択 |
| `folderId` | string | いいえ | ファイルをアップロードするフォルダのID内部使用 |

View File

@@ -134,7 +134,8 @@ Microsoft Teams チャットでコンテンツを作成または更新する
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `chatId` | string | はい | 書き込み先のチャットID |
| `content` | string | はい | メッセージに書き込むコンテンツ |
| `content` | string | はい | メッセージに書き込む内容 |
| `files` | file[] | いいえ | メッセージに添付するファイル |
#### 出力
@@ -179,11 +180,12 @@ Microsoft Teamsチャネルにメッセージを書き込むまたは送信す
#### 入力
| パラメータ | 種類 | 必須 | 説明 |
| パラメータ | | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `teamId` | string | はい | 書き込み先のチームID |
| `channelId` | string | はい | 書き込み先のチャネルID |
| `content` | string | はい | チャネルに書き込む内容 |
| `files` | file[] | いいえ | メッセージに添付するファイル |
#### 出力

View File

@@ -63,7 +63,8 @@ OneDriveにファイルをアップロードする
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `fileName` | string | はい | アップロードするファイルの名前 |
| `content` | string | はい | アップロードするファイルの内容 |
| `file` | file | いいえ | アップロードするファイル(バイナリ) |
| `content` | string | いいえ | アップロードするテキストコンテンツ(ファイルが提供されていない場合) |
| `folderSelector` | string | いいえ | ファイルをアップロードするフォルダを選択 |
| `manualFolderId` | string | いいえ | 手動で入力したフォルダID高度なモード |

View File

@@ -158,6 +158,7 @@ Outlookを使用してメールを送信する
| `conversationId` | string | いいえ | スレッド用の会話ID |
| `cc` | string | いいえ | CCの受信者カンマ区切り |
| `bcc` | string | いいえ | BCCの受信者カンマ区切り |
| `attachments` | file[] | いいえ | メールに添付するファイル |
#### 出力
@@ -181,6 +182,7 @@ Outlookを使用してメールを下書きする
| `body` | string | はい | メール本文の内容 |
| `cc` | string | いいえ | CCの受信者カンマ区切り |
| `bcc` | string | いいえ | BCCの受信者カンマ区切り |
| `attachments` | file[] | いいえ | メールの下書きに添付するファイル |
#### 出力

View File

@@ -140,6 +140,7 @@ Qdrantコレクション内で類似ベクトルを検索する
| `vector` | array | はい | 検索対象のベクトル |
| `limit` | number | いいえ | 返す結果の数 |
| `filter` | object | いいえ | 検索に適用するフィルター |
| `search_return_data` | string | いいえ | 検索から返すデータ |
| `with_payload` | boolean | いいえ | レスポンスにペイロードを含める |
| `with_vector` | boolean | いいえ | レスポンスにベクトルを含める |
@@ -162,6 +163,7 @@ QdrantコレクションからIDによってポイントを取得する
| `apiKey` | string | いいえ | Qdrant APIキーオプション |
| `collection` | string | はい | コレクション名 |
| `ids` | array | はい | 取得するポイントIDの配列 |
| `fetch_return_data` | string | いいえ | 取得から返すデータ |
| `with_payload` | boolean | いいえ | レスポンスにペイロードを含める |
| `with_vector` | boolean | いいえ | レスポンスにベクトルを含める |

View File

@@ -199,7 +199,27 @@ SharePointリストに新しいアイテムを追加する
| --------- | ---- | ----------- |
| `item` | object | 作成されたSharePointリストアイテム |
### `sharepoint_upload_file`
SharePointドキュメントライブラリにファイルをアップロードする
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `siteId` | string | いいえ | SharePointサイトのID |
| `driveId` | string | いいえ | ドキュメントライブラリドライブのID。提供されない場合、デフォルトドライブを使用します。 |
| `folderPath` | string | いいえ | ドキュメントライブラリ内のオプションのフォルダパス(例:/Documents/Subfolder |
| `fileName` | string | いいえ | オプション:アップロードされるファイル名を上書きする |
| `files` | file[] | いいえ | SharePointにアップロードするファイル |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `uploadedFiles` | array | アップロードされたファイルオブジェクトの配列 |
## 注意事項
- カテゴリ: `tools`
- カテゴリ: `tools`
- タイプ: `sharepoint`

View File

@@ -78,7 +78,8 @@ Slack APIを通じてSlackチャンネルまたはユーザーにメッセージ
| `authMethod` | string | いいえ | 認証方法oauth または bot_token |
| `botToken` | string | いいえ | カスタムボット用のボットトークン |
| `channel` | string | はい | 対象のSlackチャンネル#general |
| `text` | string | はい | 送信するメッセージテキストSlack mrkdwnフォーマットをサポート) |
| `text` | string | はい | 送信するメッセージテキストSlack mrkdwn形式をサポート) |
| `files` | file[] | いいえ | メッセージに添付するファイル |
#### 出力

View File

@@ -202,7 +202,29 @@ Supabaseテーブルにデータを挿入または更新するアップサー
| `message` | string | 操作ステータスメッセージ |
| `results` | array | アップサートされたレコードの配列 |
### `supabase_vector_search`
Supabaseテーブルでpgvectorを使用して類似性検索を実行する
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `projectId` | string | はい | あなたのSupabaseプロジェクトIDjdrkgepadsdopsntdlom |
| `functionName` | string | はい | ベクトル検索を実行するPostgreSQL関数の名前match_documents |
| `queryEmbedding` | array | はい | 類似アイテムを検索するためのクエリベクトル/埋め込み |
| `matchThreshold` | number | いいえ | 最小類似度しきい値0-1、通常は0.7-0.9 |
| `matchCount` | number | いいえ | 返す結果の最大数デフォルト10 |
| `apiKey` | string | はい | あなたのSupabaseサービスロールシークレットキー |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `message` | string | 操作ステータスメッセージ |
| `results` | array | ベクトル検索からの類似度スコア付きレコードの配列。各レコードには、クエリベクトルとの類似度を示す類似度フィールド0-1が含まれます。 |
## 注意事項
- カテゴリ: `tools`
- カテゴリ: `tools`
- タイプ: `supabase`

View File

@@ -189,6 +189,26 @@ Telegram Bot APIを通じてTelegramチャンネルまたはユーザーにア
| `message` | string | 成功またはエラーメッセージ |
| `data` | object | オプションのメディアを含むTelegramメッセージデータ |
### `telegram_send_document`
Telegram Bot APIを通じて、TelegramチャンネルやユーザーにドキュメントPDF、ZIP、DOCなどを送信します。
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `botToken` | string | はい | あなたのTelegram Bot APIトークン |
| `chatId` | string | はい | 対象のTelegramチャットID |
| `files` | file[] | いいえ | 送信するドキュメントファイルPDF、ZIP、DOCなど。最大サイズ50MB |
| `caption` | string | いいえ | ドキュメントのキャプション(任意) |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `message` | string | 成功またはエラーメッセージ |
| `data` | object | ドキュメントを含むTelegramメッセージデータ |
## 注意事項
- カテゴリー: `tools`

View File

@@ -59,8 +59,9 @@ Visionをワークフローに統合します。ビジョンモデルで画像
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | はい | 選択したモデルプロバイダーのAPIキー |
| `imageUrl` | string | い | 公開アクセス可能な画像URL |
| `model` | string | いいえ | 使用するビジョンモデル \(gpt-4o, claude-3-opus-20240229, など\) |
| `imageUrl` | string | いいえ | 公開アクセス可能な画像URL |
| `imageFile` | file | いいえ | 分析する画像ファイル |
| `model` | string | いいえ | 使用するビジョンモデルgpt-4o、claude-3-opus-20240229など |
| `prompt` | string | いいえ | 画像分析用のカスタムプロンプト |
#### 出力

View File

@@ -0,0 +1,145 @@
---
title: Webflow
description: Webflow CMSコレクションを管理する
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="webflow"
color="#E0E0E0"
icon={true}
iconSvg={`<svg className="block-icon"
viewBox='0 0 1080 674'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M1080 0L735.386 673.684H411.695L555.916 394.481H549.445C430.464 548.934 252.942 650.61 -0.000488281 673.684V398.344C-0.000488281 398.344 161.813 388.787 256.938 288.776H-0.000488281V0.0053214H288.771V237.515L295.252 237.489L413.254 0.0053214H631.644V236.009L638.126 235.999L760.555 0H1080Z'
fill='#146EF5'
/>
</svg>`}
/>
{/* MANUAL-CONTENT-START:intro */}
[Webflow](https://webflow.com/)は、コードを書かずに応答性の高いウェブサイトを構築できる強力なビジュアルウェブデザインプラットフォームです。視覚的なデザインインターフェースと堅牢なCMSコンテンツ管理システムを組み合わせており、ウェブサイト用の動的コンテンツを作成、管理、公開することができます。
Webflowでは以下のことが可能です
- **視覚的にデザインする**クリーンでセマンティックなHTML/CSSコードを生成する視覚エディタで、カスタムウェブサイトを作成
- **動的にコンテンツを管理する**CMSを使用してブログ投稿、製品、チームメンバー、またはカスタムデータなどの構造化されたコンテンツのコレクションを作成
- **即時に公開する**サイトをWebflowのホスティングにデプロイするか、カスタムホスティング用にコードをエクスポート
- **レスポンシブデザインを作成する**:デスクトップ、タブレット、モバイルデバイスでシームレスに動作するサイトを構築
- **コレクションをカスタマイズする**:コンテンツタイプのカスタムフィールドとデータ構造を定義
- **コンテンツ更新を自動化する**APIを通じてCMSコンテンツをプログラムで管理
Simでは、Webflow統合によりエージェントがAPI認証を通じてWebflow CMSコレクションとシームレスに連携できます。これにより、AIが生成したコンテンツからブログ投稿を自動作成したり、製品情報を更新したり、チームメンバープロフィールを管理したり、動的コンテンツ生成のためにCMSアイテムを取得したりするなど、強力な自動化シナリオが可能になります。エージェントは既存のアイテムをリストしてコンテンツを閲覧したり、IDで特定のアイテムを取得したり、新しいエントリを作成して新鮮なコンテンツを追加したり、既存のアイテムを更新して情報を最新の状態に保ったり、古いコンテンツを削除したりできます。この統合により、AIワークフローとWebflow CMSの間のギャップが埋まり、自動化されたコンテンツ管理、動的なウェブサイト更新、合理化されたコンテンツワークフローが可能になり、手動介入なしにサイトを常に新鮮で最新の状態に保つことができます。
{/* MANUAL-CONTENT-END */}
## 使用方法
Webflow CMSをワークフローに統合します。Webflow CMSコレクションのアイテムを作成、取得、一覧表示、更新、または削除できます。Webflowのコンテンツをプログラムで管理します。トリガーモードでは、コレクションアイテムが変更されたり、フォームが送信されたりしたときにワークフローをトリガーするために使用できます。
## ツール
### `webflow_list_items`
Webflow CMSコレクションからすべてのアイテムを一覧表示する
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | はい | コレクションのID |
| `offset` | number | いいえ | ページネーション用のオフセット(オプション) |
| `limit` | number | いいえ | 返すアイテムの最大数オプション、デフォルト100 |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `items` | json | コレクションアイテムの配列 |
| `metadata` | json | クエリに関するメタデータ |
### `webflow_get_item`
Webflow CMSコレクションから単一のアイテムを取得する
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | はい | コレクションのID |
| `itemId` | string | はい | 取得するアイテムのID |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `item` | json | 取得したアイテムオブジェクト |
| `metadata` | json | 取得したアイテムに関するメタデータ |
### `webflow_create_item`
Webflow CMSコレクションに新しいアイテムを作成する
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | はい | コレクションのID |
| `fieldData` | json | はい | 新しいアイテムのフィールドデータJSONオブジェクト形式。キーはコレクションのフィールド名と一致する必要があります。 |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `item` | json | 作成されたアイテムオブジェクト |
| `metadata` | json | 作成されたアイテムに関するメタデータ |
### `webflow_update_item`
Webflow CMSコレクション内の既存アイテムを更新する
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | はい | コレクションのID |
| `itemId` | string | はい | 更新するアイテムのID |
| `fieldData` | json | はい | 更新するフィールドデータJSONオブジェクト形式。変更したいフィールドのみを含めてください。 |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `item` | json | 更新されたアイテムオブジェクト |
| `metadata` | json | 更新されたアイテムに関するメタデータ |
### `webflow_delete_item`
Webflow CMSコレクションからアイテムを削除する
#### 入力
| パラメータ | 型 | 必須 | 説明 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | はい | コレクションのID |
| `itemId` | string | はい | 削除するアイテムのID |
#### 出力
| パラメータ | 型 | 説明 |
| --------- | ---- | ----------- |
| `success` | boolean | 削除が成功したかどうか |
| `metadata` | json | 削除に関するメタデータ |
## 注意事項
- カテゴリー: `tools`
- タイプ: `webflow`

View File

@@ -209,16 +209,16 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `webhookURL` | string | 是 | 用于填充的 webhook URL |
| `webhookURL` | string | 是 | 填充的 webhook URL |
| `data` | json | 是 | 要填充的数据 |
| `authToken` | string | | 用于 Clay webhook 认证的授权令牌 |
| `authToken` | string | | 用于 Clay webhook 认证的可选身份验证令牌(大多数 webhook 不需要此令牌) |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `success` | boolean | 操作成功状态 |
| `output` | json | Clay 填充操作结果,包括来自 Clay webhook 响应数据 |
| `data` | json | 来自 Clay webhook 的响应数据 |
| `metadata` | object | webhook 响应数据 |
## 注意事项

View File

@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="discord"
color="#E0E0E0"
color="#5865F2"
icon={true}
iconSvg={`<svg className="block-icon"
@@ -71,7 +71,8 @@ Sim 中的 Discord 组件使用高效的延迟加载,仅在需要时获取数
| `botToken` | string | 是 | 用于身份验证的机器人令牌 |
| `channelId` | string | 是 | 要发送消息的 Discord 频道 ID |
| `content` | string | 否 | 消息的文本内容 |
| `serverId` | string | 是 | Discord 服务器 IDguild ID |
| `serverId` | string | 是 | Discord 服务器 ID \(公会 ID\) |
| `files` | file[] | 否 | 要附加到消息的文件 |
#### 输出

View File

@@ -84,11 +84,12 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `fileName` | string | 是 | 要上传文件名称 |
| `content` | string | | 要上传的文件内容 |
| `mimeType` | string | 否 | 要上传文件的 MIME 类型 |
| `folderSelector` | string | 否 | 选择上传文件的文件夹 |
| `folderId` | string | 否 | 要上传文件的文件夹 ID内部使用 |
| `fileName` | string | 是 | 要上传文件名称 |
| `file` | file | | 要上传的二进制文件 \(UserFile 对象\) |
| `content` | string | 否 | 要上传的文本内容 \(使用此项或 file不可同时使用\) |
| `mimeType` | string | 否 | 上传文件的 MIME 类型 \(如果未提供,将从文件中自动检测\) |
| `folderSelector` | string | 否 | 选择要上传文件的文件夹 |
| `folderId` | string | 否 | 要上传文件的文件夹 ID \(内部使用\) |
#### 输出

View File

@@ -135,6 +135,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| --------- | ---- | -------- | ----------- |
| `chatId` | string | 是 | 要写入的聊天 ID |
| `content` | string | 是 | 要写入消息的内容 |
| `files` | file[] | 否 | 要附加到消息的文件 |
#### 输出
@@ -184,6 +185,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| `teamId` | string | 是 | 要写入的团队 ID |
| `channelId` | string | 是 | 要写入的频道 ID |
| `content` | string | 是 | 要写入频道的内容 |
| `files` | file[] | 否 | 要附加到消息的文件 |
#### 输出

View File

@@ -62,10 +62,11 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `fileName` | string | 是 | 要上传文件 |
| `content` | string | | 要上传的文件内容 |
| `folderSelector` | string | 否 | 选择要上传文件的文件夹 |
| `manualFolderId` | string | 否 | 手动输入的文件夹 ID高级模式 |
| `fileName` | string | 是 | 要上传文件的名称 |
| `file` | file | | 要上传的文件 \(二进制\) |
| `content` | string | 否 | 要上传的文本内容 \(如果未提供文件\) |
| `folderSelector` | string | 否 | 选择上传文件的文件夹 |
| `manualFolderId` | string | 否 | 手动输入的文件夹 ID \(高级模式\) |
#### 输出

View File

@@ -152,12 +152,13 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `to` | string | 是 | 收件人电子邮件地址 |
| `subject` | string | 是 | 电子邮件主题 |
| `body` | string | 是 | 电子邮件正文内容 |
| `subject` | string | 是 | 邮件主题 |
| `body` | string | 是 | 邮件正文内容 |
| `replyToMessageId` | string | 否 | 要回复的消息 ID用于线程化 |
| `conversationId` | string | 否 | 用于线程化的会话 ID |
| `cc` | string | 否 | 抄送收件人(逗号分隔) |
| `bcc` | string | 否 | 密送收件人(逗号分隔) |
| `cc` | string | 否 | 抄送收件人(逗号分隔) |
| `bcc` | string | 否 | 密送收件人(逗号分隔) |
| `attachments` | file[] | 否 | 要附加到邮件的文件 |
#### 输出
@@ -176,11 +177,12 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `to` | string | 是 | 收件人邮箱地址 |
| `to` | string | 是 | 收件人电子邮件地址 |
| `subject` | string | 是 | 邮件主题 |
| `body` | string | 是 | 邮件正文内容 |
| `cc` | string | 否 | 抄送收件人(逗号分隔) |
| `bcc` | string | 否 | 密送收件人(逗号分隔) |
| `cc` | string | 否 | 抄送收件人(逗号分隔) |
| `bcc` | string | 否 | 密送收件人(逗号分隔) |
| `attachments` | file[] | 否 | 要附加到邮件草稿的文件 |
#### 输出

View File

@@ -138,8 +138,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| `apiKey` | string | 否 | Qdrant API 密钥(可选)|
| `collection` | string | 是 | 集合名称 |
| `vector` | array | 是 | 要搜索的向量 |
| `limit` | number | 否 | 返回结果数量 |
| `filter` | object | 否 | 应用于搜索的过滤器 |
| `limit` | number | 否 | 返回结果数量 |
| `filter` | object | 否 | 应用于搜索的过滤器 |
| `search_return_data` | string | 否 | 搜索中要返回的数据 |
| `with_payload` | boolean | 否 | 在响应中包含有效负载 |
| `with_vector` | boolean | 否 | 在响应中包含向量 |
@@ -162,6 +163,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| `apiKey` | string | 否 | Qdrant API 密钥(可选)|
| `collection` | string | 是 | 集合名称 |
| `ids` | array | 是 | 要获取的点 ID 数组 |
| `fetch_return_data` | string | 否 | 获取中要返回的数据 |
| `with_payload` | boolean | 否 | 在响应中包含有效负载 |
| `with_vector` | boolean | 否 | 在响应中包含向量 |

View File

@@ -199,6 +199,26 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| --------- | ---- | ----------- |
| `item` | object | 创建的 SharePoint 列表项 |
### `sharepoint_upload_file`
将文件上传到 SharePoint 文档库
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `siteId` | string | 否 | SharePoint 站点的 ID |
| `driveId` | string | 否 | 文档库(驱动器)的 ID。如果未提供则使用默认驱动器。 |
| `folderPath` | string | 否 | 文档库中的可选文件夹路径(例如,/Documents/Subfolder |
| `fileName` | string | 否 | 可选:覆盖上传文件的名称 |
| `files` | file[] | 否 | 要上传到 SharePoint 的文件 |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `uploadedFiles` | array | 上传文件对象的数组 |
## 注意事项
- 类别:`tools`

View File

@@ -78,6 +78,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| `botToken` | string | 否 | 自定义 Bot 的令牌 |
| `channel` | string | 是 | 目标 Slack 频道(例如,#general |
| `text` | string | 是 | 要发送的消息文本(支持 Slack mrkdwn 格式) |
| `files` | file[] | 否 | 要附加到消息的文件 |
#### 输出

View File

@@ -202,6 +202,28 @@ Sim 的 Supabase 集成使您能够轻松地将代理工作流连接到您的 Su
| `message` | string | 操作状态消息 |
| `results` | array | 已 upsert 的记录数组 |
### `supabase_vector_search`
在 Supabase 表中使用 pgvector 执行相似性搜索
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `projectId` | string | 是 | 您的 Supabase 项目 ID \(例如jdrkgepadsdopsntdlom\) |
| `functionName` | string | 是 | 执行向量搜索的 PostgreSQL 函数名称 \(例如match_documents\) |
| `queryEmbedding` | array | 是 | 要搜索相似项的查询向量/嵌入 |
| `matchThreshold` | number | 否 | 最小相似度阈值 \(0-1\),通常为 0.7-0.9 |
| `matchCount` | number | 否 | 返回结果的最大数量 \(默认值10\) |
| `apiKey` | string | 是 | 您的 Supabase 服务角色密钥 |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `message` | string | 操作状态消息 |
| `results` | array | 包含向量搜索相似度分数的记录数组。每条记录包括一个相似度字段 \(0-1\),表示与查询向量的相似程度。 |
## 注意事项
- 类别:`tools`

View File

@@ -189,6 +189,26 @@ Telegram 的主要功能包括:
| `message` | 字符串 | 成功或错误消息 |
| `data` | 对象 | 包含可选媒体的 Telegram 消息数据 |
### `telegram_send_document`
通过 Telegram Bot API 将文档PDF、ZIP、DOC 等)发送到 Telegram 频道或用户。
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `botToken` | string | 是 | 您的 Telegram Bot API 令牌 |
| `chatId` | string | 是 | 目标 Telegram 聊天 ID |
| `files` | file[] | 否 | 要发送的文档文件PDF、ZIP、DOC 等。最大大小50MB |
| `caption` | string | 否 | 文档标题(可选) |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `message` | string | 成功或错误消息 |
| `data` | object | 包含文档的 Telegram 消息数据 |
## 注意
- 类别:`tools`

View File

@@ -59,9 +59,10 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | 是 | 所选模型提供商的 API 密钥 |
| `imageUrl` | string | | 可公开访问的图 URL |
| `model` | string | 否 | 要使用的视觉模型gpt-4o、claude-3-opus-20240229 等) |
| `prompt` | string | 否 | 图像分析的自定义提示 |
| `imageUrl` | string | | 可公开访问的图 URL |
| `imageFile` | file | 否 | 要分析的图片文件 |
| `model` | string | 否 | 要使用的视觉模型 \(gpt-4o, claude-3-opus-20240229 等\) |
| `prompt` | string | 否 | 用于图像分析的自定义提示 |
#### 输出

View File

@@ -0,0 +1,144 @@
---
title: Webflow
description: 管理 Webflow CMS 集合
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="webflow"
color="#E0E0E0"
icon={true}
iconSvg={`<svg className="block-icon"
viewBox='0 0 1080 674'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M1080 0L735.386 673.684H411.695L555.916 394.481H549.445C430.464 548.934 252.942 650.61 -0.000488281 673.684V398.344C-0.000488281 398.344 161.813 388.787 256.938 288.776H-0.000488281V0.0053214H288.771V237.515L295.252 237.489L413.254 0.0053214H631.644V236.009L638.126 235.999L760.555 0H1080Z'
fill='#146EF5'
/>
</svg>`}
/>
{/* MANUAL-CONTENT-START:intro */}
[Webflow](https://webflow.com/) 是一个强大的可视化网页设计平台,能够让您无需编写代码即可构建响应式网站。它结合了可视化设计界面和强大的 CMS内容管理系统使您能够为网站创建、管理和发布动态内容。
使用 Webflow您可以
- **可视化设计**:使用可视化编辑器创建自定义网站,该编辑器会生成干净、语义化的 HTML/CSS 代码
- **动态管理内容**:使用 CMS 创建结构化内容集合,例如博客文章、产品、团队成员或任何自定义数据
- **即时发布**:将您的网站部署到 Webflow 的托管服务,或导出代码以进行自定义托管
- **创建响应式设计**:构建在桌面、平板电脑和移动设备上无缝运行的网站
- **自定义集合**:为您的内容类型定义自定义字段和数据结构
- **自动更新内容**:通过 API 编程方式管理您的 CMS 内容
在 Sim 中Webflow 集成使您的代理能够通过 API 身份验证无缝与 Webflow CMS 集合交互。这支持强大的自动化场景,例如从 AI 生成的内容中自动创建博客文章、更新产品信息、管理团队成员资料以及检索 CMS 项目以生成动态内容。您的代理可以列出现有项目以浏览内容,通过 ID 检索特定项目,创建新条目以添加新内容,更新现有项目以保持信息最新,以及删除过时内容。此集成弥合了您的 AI 工作流与 Webflow CMS 之间的差距,实现了自动化内容管理、动态网站更新和简化的内容工作流,使您的网站无需人工干预即可保持新鲜和最新。{/* MANUAL-CONTENT-END */}
## 使用说明
将 Webflow CMS 集成到工作流程中。可以创建、获取、列出、更新或删除 Webflow CMS 集合中的项目。以编程方式管理您的 Webflow 内容。可以在触发模式下使用,当集合项目发生变化或提交表单时触发工作流程。
## 工具
### `webflow_list_items`
列出 Webflow CMS 集合中的所有项目
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | 是 | 集合的 ID |
| `offset` | number | 否 | 分页偏移量(可选) |
| `limit` | number | 否 | 返回的最大项目数可选默认值100 |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `items` | json | 集合项目的数组 |
| `metadata` | json | 查询的元数据 |
### `webflow_get_item`
从 Webflow CMS 集合中获取单个项目
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | 是 | 集合的 ID |
| `itemId` | string | 是 | 要检索的项目 ID |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `item` | json | 检索到的项目对象 |
| `metadata` | json | 检索到的项目的元数据 |
### `webflow_create_item`
在 Webflow CMS 集合中创建一个新项目
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | 是 | 集合的 ID |
| `fieldData` | json | 是 | 新项目的字段数据,格式为 JSON 对象。键名应与集合字段名称匹配。 |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `item` | json | 创建的项目对象 |
| `metadata` | json | 关于创建项目的元数据 |
### `webflow_update_item`
更新 Webflow CMS 集合中的现有项目
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | 是 | 集合的 ID |
| `itemId` | string | 是 | 要更新项目的 ID |
| `fieldData` | json | 是 | 要更新的字段数据,格式为 JSON 对象。仅包含您想更改的字段。 |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `item` | json | 更新的项目对象 |
| `metadata` | json | 关于更新项目的元数据 |
### `webflow_delete_item`
从 Webflow CMS 集合中删除项目
#### 输入
| 参数 | 类型 | 必需 | 描述 |
| --------- | ---- | -------- | ----------- |
| `collectionId` | string | 是 | 集合的 ID |
| `itemId` | string | 是 | 要删除项目的 ID |
#### 输出
| 参数 | 类型 | 描述 |
| --------- | ---- | ----------- |
| `success` | boolean | 是否删除成功 |
| `metadata` | json | 有关删除的元数据 |
## 注意
- 类别:`tools`
- 类型:`webflow`

View File

@@ -439,7 +439,7 @@ checksums:
content/9: 10ec1e8eaecc6f3d30cfa63749e968b7
content/10: f4b856e774ec5e995c437201d22036ee
content/11: 371d0e46b4bd2c23f559b8bc112f6955
content/12: 4e324b7b7dc434eea83f6b5d528ab930
content/12: ae0448bae89d0f81d8a28361acc2d67e
content/13: bcadfc362b69078beee0088e5936c98b
content/14: 0c8b7227f9df8b60ee36d80de899961e
content/15: b3f310d5ef115bea5a8b75bf25d7ea9a
@@ -594,8 +594,14 @@ checksums:
content/47: f18d03fa59e3997a6d951e333d99c822
content/48: bcadfc362b69078beee0088e5936c98b
content/49: 8779f29ccc257e421d64c071949b81fb
content/50: b3f310d5ef115bea5a8b75bf25d7ea9a
content/51: e1fa627fb51f09989752a9bddf0ebb58
content/50: 8782b269ede5cb41fecbd34072214c6c
content/51: 79a5a4e61b55cdb65a6915ef08daeb93
content/52: 371d0e46b4bd2c23f559b8bc112f6955
content/53: 7653b942236c8ad404c6962988fda3d3
content/54: bcadfc362b69078beee0088e5936c98b
content/55: 87cd2cb3a40d59957ca9ad1762c7a816
content/56: b3f310d5ef115bea5a8b75bf25d7ea9a
content/57: e1fa627fb51f09989752a9bddf0ebb58
ac9313ccf1478cdf17fe25081b6b78be:
meta/title: df20085ae7dc009c9b6532113064c6bb
meta/description: 0a0c4af79216512ddc68df973afed52c
@@ -672,8 +678,14 @@ checksums:
content/44: b37f6692238f3a45bfcf106f0d192b21
content/45: bcadfc362b69078beee0088e5936c98b
content/46: 1788748095a805b62a0e21403789dad7
content/47: b3f310d5ef115bea5a8b75bf25d7ea9a
content/48: d2ca5a540458c526aebabd2f9ff3fd03
content/47: dd231637d3d327f0daf546fe92594ac6
content/48: 97f32d4cd73f2375eb8540e71300dad1
content/49: 371d0e46b4bd2c23f559b8bc112f6955
content/50: ce131f6bcfe8a6aeb340229a107febc3
content/51: bcadfc362b69078beee0088e5936c98b
content/52: 67cb33e6ab252c7130cac02728311dc8
content/53: b3f310d5ef115bea5a8b75bf25d7ea9a
content/54: d2ca5a540458c526aebabd2f9ff3fd03
51862d3525bcbc53275ead2362197752:
meta/title: 64d1e9a0e5ae9fdb055a5366c22433fc
meta/description: 1f9e8e75ebe525fc5bb53d9f5e0dd3a8
@@ -732,7 +744,7 @@ checksums:
content/12: 8ee83eff32425b2c52929284e8485c20
content/13: 6cda87dc9837779f4572ed70b87a5654
content/14: 371d0e46b4bd2c23f559b8bc112f6955
content/15: 57e7f55217bb573b93ff0e6e37bd58a7
content/15: ba09630dea12ec37bbe8a4f490150c8a
content/16: bcadfc362b69078beee0088e5936c98b
content/17: 1f31e78210417a7f251f29e0b93a8528
content/18: 05540cb3028d4d781521c14e5f9e3835
@@ -803,8 +815,14 @@ checksums:
content/48: 5d7221454e6adf5eed5f0c02b24eb9e0
content/49: bcadfc362b69078beee0088e5936c98b
content/50: f42ef799c350c30117cb100b98a9d526
content/51: b3f310d5ef115bea5a8b75bf25d7ea9a
content/52: 6480fe7f4ab32b223c32deab16b6922b
content/51: a13d828344becb9f2f7c2a788dda30a5
content/52: 5d0ccd6bc37305555c6a48cec645fe48
content/53: 371d0e46b4bd2c23f559b8bc112f6955
content/54: bfdd461ff9444c6d81c5fb0b9cee3c97
content/55: bcadfc362b69078beee0088e5936c98b
content/56: ce194fa4c0560d03b31f53bbe0e1cf94
content/57: b3f310d5ef115bea5a8b75bf25d7ea9a
content/58: 6480fe7f4ab32b223c32deab16b6922b
d36fb89d311a649e49173c0998fad09f:
meta/title: 25b7006e238bd277acad0336b59e6581
meta/description: 4c972c767abaf134b90c2e9bf6619876
@@ -927,13 +945,13 @@ checksums:
content/17: f5bef3db56ed3a56395f7ae1fa41ecf3
content/18: 7ca733ac5374e92a9cc8ef35e1075fb1
content/19: 371d0e46b4bd2c23f559b8bc112f6955
content/20: 8ce52b8ffed51482dff6fa0f2846c498
content/20: 0eada001684acb8efe28fcfed38a5163
content/21: bcadfc362b69078beee0088e5936c98b
content/22: b875ec2f16d200917e9860b49a5a9772
content/23: c0c2276dd4207eb2b08d4dc9132e7ec3
content/24: 85de953906920f3fb4eafa8fdb918feb
content/25: 371d0e46b4bd2c23f559b8bc112f6955
content/26: f63654037687387924343d8f7453f379
content/26: b0cf90320ac6b98d5bf00b87052cd76e
content/27: bcadfc362b69078beee0088e5936c98b
content/28: e62b89406f01af79e2e293d352aa2499
content/29: b3f310d5ef115bea5a8b75bf25d7ea9a
@@ -1081,13 +1099,13 @@ checksums:
content/9: 822829fd1c0500496b72d5a0abafeb41
content/10: 4a8b7fc9ab62f88061e4b21ac5b10947
content/11: 371d0e46b4bd2c23f559b8bc112f6955
content/12: ba245342edd3cc56355ba84be1d45aef
content/12: 9edeb4b9fca066dd5bf11d0c3a2cb8db
content/13: bcadfc362b69078beee0088e5936c98b
content/14: 558c49a1186440a5a2254dcfbd7b74f7
content/15: 64a8e14453f9063bd8d89d43b7833fa8
content/16: c5800c27cab920bd65932ffc703e6fc6
content/17: 371d0e46b4bd2c23f559b8bc112f6955
content/18: 96832958c23fb2c9cefb35ee9a63cded
content/18: c886c72190889c7b55a8f38a294ecf38
content/19: bcadfc362b69078beee0088e5936c98b
content/20: 9f1a5d98944fc79dbcd0b01e0a82fe28
content/21: d80aeca589a53111bf1695cdd331cf5b
@@ -1140,7 +1158,7 @@ checksums:
content/10: 6df7e096bafa5efda818db1ab65841fd
content/11: 646990da68ff77ca02dd172f830f12f0
content/12: 371d0e46b4bd2c23f559b8bc112f6955
content/13: 6e6d228bc03c82d986ab0f60470fd1ea
content/13: 6979ff1359b3ede098d71e35fabd6a05
content/14: bcadfc362b69078beee0088e5936c98b
content/15: c25b7418fd96b560b79af512cba4e7f1
content/16: 3d44fa28ed12c73c2c9178b8570e516d
@@ -1340,7 +1358,7 @@ checksums:
content/15: 9a44ad2a020c00d5c50250ee0c543ae2
content/16: 3f013e8cf7537231614d510c9bcdf1b2
content/17: 371d0e46b4bd2c23f559b8bc112f6955
content/18: e0e86275deb46b5c7b516849de4d70fa
content/18: 48389c9abe6b4ab2f836686265618a0e
content/19: bcadfc362b69078beee0088e5936c98b
content/20: 5e472d191f58641d1b0416383875f22b
content/21: 25d767f79c8b785d24657d66091e479b
@@ -1352,7 +1370,7 @@ checksums:
content/27: 89ae14a70cbc288e4f816b710c7ef48e
content/28: 311c355c6e43246e52112ee300df8db5
content/29: 371d0e46b4bd2c23f559b8bc112f6955
content/30: f28566e14c56ba74700c17a6ddebc994
content/30: 44d1f81db519e167c575e2ac6d34048c
content/31: bcadfc362b69078beee0088e5936c98b
content/32: d977e473bf5c4e014362b2f7c5e4ae7b
content/33: b3f310d5ef115bea5a8b75bf25d7ea9a
@@ -1820,7 +1838,7 @@ checksums:
content/11: 871d6ecf3f593f3b20f5c3c8ded1ecc6
content/12: 30072675a0dffbddc0e85bd3e34764ec
content/13: 371d0e46b4bd2c23f559b8bc112f6955
content/14: fb8b01d27288339ac6e87c630abca238
content/14: f07ac61557b436d01cbc1fbc2684d39f
content/15: bcadfc362b69078beee0088e5936c98b
content/16: 1e23d729d38b5da93b6598e73e4ab612
content/17: 24991dd332b7a6b8f8091e3e219b542f
@@ -2165,7 +2183,7 @@ checksums:
meta/title: 06ec7d95ab44931ed9d1925e4063d703
meta/description: cc9ab492bdda4a2cb9085537d6e6a0c0
content/0: 1b031fb0c62c46b177aeed5c3d3f8f80
content/1: 73fb594a22fcf560087b53ea6aa592f6
content/1: f744e92fcc234d02bb9b352a2ab1e1e3
content/2: b229bf34f0106ccb5af6f0b2a044e21a
content/3: 45e7cee1fa342c4d13a1a6cb70733a14
content/4: 62db68be640983ea9a383ee162bd8463
@@ -2180,7 +2198,7 @@ checksums:
content/13: 4a01bece58a2e9ac96bea57ed39e35d5
content/14: f49c586052b88ec4bf80d844c0c7ca3e
content/15: 371d0e46b4bd2c23f559b8bc112f6955
content/16: f2a31106e2f78ba7e12a78e234ba1e9a
content/16: ff83558d232dd95d39838a2ca868dfed
content/17: bcadfc362b69078beee0088e5936c98b
content/18: 6b7691d4977f1b6520a8b3236b993358
content/19: 96f2aa27a8d3f74035575de3da6c47c4
@@ -2246,9 +2264,9 @@ checksums:
content/11: 3524f0dac9a9152db223bcc2682a842d
content/12: 341fbcb79af9a7cb1bf5ac653f51807c
content/13: 371d0e46b4bd2c23f559b8bc112f6955
content/14: 85aebdee44deb5b2f03e95112a776839
content/14: 6dba14b1346c18cd2342f502371a1042
content/15: bcadfc362b69078beee0088e5936c98b
content/16: 7062fc4e2ca6974003e0d209f2b52d9f
content/16: df68275133be883eac95664c3ed10063
content/17: b3f310d5ef115bea5a8b75bf25d7ea9a
content/18: 59815ce1d0dddd507d505b42aa01b648
44f1f9fe8d5081b7781dc70e012cb531:
@@ -4342,3 +4360,47 @@ checksums:
content/58: 74af50eceb2a5f514301c497a8e64030
content/59: b3f310d5ef115bea5a8b75bf25d7ea9a
content/60: 549a9bd7ff92264fbd18c9d6e616594b
65891ef7e29a3ad2464222a998549ff5:
meta/title: b35b5211a53c68cea3a3f0995099c24b
meta/description: c12cfd50357fba2ffebaf79750b7d76d
content/0: 1b031fb0c62c46b177aeed5c3d3f8f80
content/1: 49bca8f0502318620cbebb686a4fd5b3
content/2: 4d30444228f205f237d0c194fe4dd3d9
content/3: 8d8c30d8ee25edbf854d7d2ac1e2dbd8
content/4: e4d2f4146482f4724c177815103e026b
content/5: 68b1bf876a3ba2faf8fba18ae4e1bc19
content/6: 821e6394b0a953e2b0842b04ae8f3105
content/7: 22ab0fa161f448ca26998e101805e59e
content/8: 9c8aa3f09c9b2bd50ea4cdff3598ea4e
content/9: 5914baadfaf2ca26d54130a36dd5ed29
content/10: 25507380ac7d9c7f8cf9f5256c6a0dbb
content/11: 371d0e46b4bd2c23f559b8bc112f6955
content/12: e7fb612c3323c1e6b05eacfcea360d34
content/13: bcadfc362b69078beee0088e5936c98b
content/14: e5f830d6049ff79a318110098e5e0130
content/15: 711e90714806b91f93923018e82ad2e9
content/16: 0f3f7d9699d7397cb3a094c3229329ee
content/17: 371d0e46b4bd2c23f559b8bc112f6955
content/18: c53b5b8f901066e63fe159ad2fa5e6e0
content/19: bcadfc362b69078beee0088e5936c98b
content/20: 5f2afdd49c3ac13381401c69d1eca22a
content/21: cc4baa9096fafa4c6276f6136412ba66
content/22: 676f76e8a7154a576d7fa20b245cef70
content/23: 371d0e46b4bd2c23f559b8bc112f6955
content/24: c67c387eb7e274ee7c07b7e1748afce1
content/25: bcadfc362b69078beee0088e5936c98b
content/26: a6ffebda549ad5b903a66c7d9ac03a20
content/27: 0dadd51cde48d6ea75b29ec3ee4ade56
content/28: cdc74f6483a0b4e9933ecdd92ed7480f
content/29: 371d0e46b4bd2c23f559b8bc112f6955
content/30: 4cda10aa374e1a46d60ad14eeaa79100
content/31: bcadfc362b69078beee0088e5936c98b
content/32: 5f221421953a0e760ead7388cbf66561
content/33: a3c0372590cef72d5d983dbc8dbbc2cb
content/34: 1402e53c08bdd8a741f44b2d66fcd003
content/35: 371d0e46b4bd2c23f559b8bc112f6955
content/36: 028e579a28e55def4fbc59f39f4610b7
content/37: bcadfc362b69078beee0088e5936c98b
content/38: 4fe4260da2f137679ce2fa42cffcf56a
content/39: b3f310d5ef115bea5a8b75bf25d7ea9a
content/40: 89bdbd886b24f2aaec635a2b4119660a

View File

@@ -71,6 +71,12 @@ export default function SSOForm() {
}
}
// Pre-fill email if provided in URL (e.g., from deployed chat SSO)
const emailParam = searchParams.get('email')
if (emailParam) {
setEmail(emailParam)
}
// Check for SSO error from redirect
const error = searchParams.get('error')
if (error) {

View File

@@ -20,5 +20,4 @@ INTERNAL_API_SECRET=your_internal_api_secret # Use `openssl rand -hex 32` to gen
# If left commented out, emails will be logged to console instead
# Local AI Models (Optional)
# OLLAMA_URL=http://localhost:11434 # URL for local Ollama server - uncomment if using local models
# OLLAMA_URL=http://localhost:11434 # URL for local Ollama server - uncomment if using local models

View File

@@ -1,6 +1,6 @@
import { db } from '@sim/db'
import { subscription as subscriptionTable, user } from '@sim/db/schema'
import { and, eq } from 'drizzle-orm'
import { and, eq, or } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { requireStripeClient } from '@/lib/billing/stripe-client'
@@ -38,7 +38,10 @@ export async function POST(request: NextRequest) {
.where(
and(
eq(subscriptionTable.referenceId, organizationId),
eq(subscriptionTable.status, 'active')
or(
eq(subscriptionTable.status, 'active'),
eq(subscriptionTable.cancelAtPeriodEnd, true)
)
)
)
.limit(1)

View File

@@ -1,5 +1,5 @@
import { db } from '@sim/db'
import { chat, workflow } from '@sim/db/schema'
import { chat, workflow, workspace } from '@sim/db/schema'
import { eq } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { createLogger } from '@/lib/logs/console/logger'
@@ -94,11 +94,12 @@ export async function POST(
return addCorsHeaders(createErrorResponse('No input provided', 400), request)
}
// Get the workflow for this chat
// Get the workflow and workspace owner for this chat
const workflowResult = await db
.select({
isDeployed: workflow.isDeployed,
workspaceId: workflow.workspaceId,
variables: workflow.variables,
})
.from(workflow)
.where(eq(workflow.id, deployment.workflowId))
@@ -109,6 +110,22 @@ export async function POST(
return addCorsHeaders(createErrorResponse('Chat workflow is not available', 503), request)
}
let workspaceOwnerId = deployment.userId
if (workflowResult[0].workspaceId) {
const workspaceData = await db
.select({ ownerId: workspace.ownerId })
.from(workspace)
.where(eq(workspace.id, workflowResult[0].workspaceId))
.limit(1)
if (workspaceData.length === 0) {
logger.error(`[${requestId}] Workspace not found for workflow ${deployment.workflowId}`)
return addCorsHeaders(createErrorResponse('Workspace not found', 500), request)
}
workspaceOwnerId = workspaceData[0].ownerId
}
try {
const selectedOutputs: string[] = []
if (deployment.outputConfigs && Array.isArray(deployment.outputConfigs)) {
@@ -145,16 +162,19 @@ export async function POST(
}
}
const workflowForExecution = {
id: deployment.workflowId,
userId: deployment.userId,
workspaceId: workflowResult[0].workspaceId,
isDeployed: true,
variables: workflowResult[0].variables || {},
}
const stream = await createStreamingResponse({
requestId,
workflow: {
id: deployment.workflowId,
userId: deployment.userId,
workspaceId: workflowResult[0].workspaceId,
isDeployed: true,
},
workflow: workflowForExecution,
input: workflowInput,
executingUserId: deployment.userId,
executingUserId: workspaceOwnerId,
streamConfig: {
selectedOutputs,
isSecureMode: true,

View File

@@ -8,6 +8,7 @@ import { isDev } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console/logger'
import { getEmailDomain } from '@/lib/urls/utils'
import { encryptSecret } from '@/lib/utils'
import { deployWorkflow } from '@/lib/workflows/db-helpers'
import { checkChatAccess } from '@/app/api/chat/utils'
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
@@ -31,7 +32,7 @@ const chatUpdateSchema = z.object({
imageUrl: z.string().optional(),
})
.optional(),
authType: z.enum(['public', 'password', 'email']).optional(),
authType: z.enum(['public', 'password', 'email', 'sso']).optional(),
password: z.string().optional(),
allowedEmails: z.array(z.string()).optional(),
outputConfigs: z
@@ -134,6 +135,22 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
}
}
// Redeploy the workflow to ensure latest version is active
const deployResult = await deployWorkflow({
workflowId: existingChat[0].workflowId,
deployedBy: session.user.id,
})
if (!deployResult.success) {
logger.warn(
`Failed to redeploy workflow for chat update: ${deployResult.error}, continuing with chat update`
)
} else {
logger.info(
`Redeployed workflow ${existingChat[0].workflowId} for chat update (v${deployResult.version})`
)
}
let encryptedPassword
if (password) {
@@ -165,7 +182,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
updateData.allowedEmails = []
} else if (authType === 'password') {
updateData.allowedEmails = []
} else if (authType === 'email') {
} else if (authType === 'email' || authType === 'sso') {
updateData.password = null
}
}

View File

@@ -19,6 +19,7 @@ describe('Chat API Route', () => {
const mockCreateErrorResponse = vi.fn()
const mockEncryptSecret = vi.fn()
const mockCheckWorkflowAccessForChatCreation = vi.fn()
const mockDeployWorkflow = vi.fn()
beforeEach(() => {
vi.resetModules()
@@ -76,6 +77,14 @@ describe('Chat API Route', () => {
vi.doMock('@/app/api/chat/utils', () => ({
checkWorkflowAccessForChatCreation: mockCheckWorkflowAccessForChatCreation,
}))
vi.doMock('@/lib/workflows/db-helpers', () => ({
deployWorkflow: mockDeployWorkflow.mockResolvedValue({
success: true,
version: 1,
deployedAt: new Date(),
}),
}))
})
afterEach(() => {
@@ -236,7 +245,7 @@ describe('Chat API Route', () => {
it('should allow chat deployment when user owns workflow directly', async () => {
vi.doMock('@/lib/auth', () => ({
getSession: vi.fn().mockResolvedValue({
user: { id: 'user-id' },
user: { id: 'user-id', email: 'user@example.com' },
}),
}))
@@ -283,7 +292,7 @@ describe('Chat API Route', () => {
it('should allow chat deployment when user has workspace admin permission', async () => {
vi.doMock('@/lib/auth', () => ({
getSession: vi.fn().mockResolvedValue({
user: { id: 'user-id' },
user: { id: 'user-id', email: 'user@example.com' },
}),
}))
@@ -393,10 +402,10 @@ describe('Chat API Route', () => {
expect(mockCheckWorkflowAccessForChatCreation).toHaveBeenCalledWith('workflow-123', 'user-id')
})
it('should reject if workflow is not deployed', async () => {
it('should auto-deploy workflow if not already deployed', async () => {
vi.doMock('@/lib/auth', () => ({
getSession: vi.fn().mockResolvedValue({
user: { id: 'user-id' },
user: { id: 'user-id', email: 'user@example.com' },
}),
}))
@@ -415,6 +424,7 @@ describe('Chat API Route', () => {
hasAccess: true,
workflow: { userId: 'user-id', workspaceId: null, isDeployed: false },
})
mockReturning.mockResolvedValue([{ id: 'test-uuid' }])
const req = new NextRequest('http://localhost:3000/api/chat', {
method: 'POST',
@@ -423,11 +433,11 @@ describe('Chat API Route', () => {
const { POST } = await import('@/app/api/chat/route')
const response = await POST(req)
expect(response.status).toBe(400)
expect(mockCreateErrorResponse).toHaveBeenCalledWith(
'Workflow must be deployed before creating a chat',
400
)
expect(response.status).toBe(200)
expect(mockDeployWorkflow).toHaveBeenCalledWith({
workflowId: 'workflow-123',
deployedBy: 'user-id',
})
})
})
})

View File

@@ -9,6 +9,7 @@ import { isDev } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console/logger'
import { getBaseUrl } from '@/lib/urls/utils'
import { encryptSecret } from '@/lib/utils'
import { deployWorkflow } from '@/lib/workflows/db-helpers'
import { checkWorkflowAccessForChatCreation } from '@/app/api/chat/utils'
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
@@ -27,7 +28,7 @@ const chatSchema = z.object({
welcomeMessage: z.string(),
imageUrl: z.string().optional(),
}),
authType: z.enum(['public', 'password', 'email']).default('public'),
authType: z.enum(['public', 'password', 'email', 'sso']).default('public'),
password: z.string().optional(),
allowedEmails: z.array(z.string()).optional().default([]),
outputConfigs: z
@@ -98,6 +99,13 @@ export async function POST(request: NextRequest) {
)
}
if (authType === 'sso' && (!Array.isArray(allowedEmails) || allowedEmails.length === 0)) {
return createErrorResponse(
'At least one email or domain is required when using SSO access control',
400
)
}
// Check if identifier is available
const existingIdentifier = await db
.select()
@@ -119,11 +127,20 @@ export async function POST(request: NextRequest) {
return createErrorResponse('Workflow not found or access denied', 404)
}
// Verify the workflow is deployed (required for chat deployment)
if (!workflowRecord.isDeployed) {
return createErrorResponse('Workflow must be deployed before creating a chat', 400)
// Always deploy/redeploy the workflow to ensure latest version
const result = await deployWorkflow({
workflowId,
deployedBy: session.user.id,
})
if (!result.success) {
return createErrorResponse(result.error || 'Failed to deploy workflow', 500)
}
logger.info(
`${workflowRecord.isDeployed ? 'Redeployed' : 'Auto-deployed'} workflow ${workflowId} for chat (v${result.version})`
)
// Encrypt password if provided
let encryptedPassword = null
if (authType === 'password' && password) {
@@ -163,7 +180,7 @@ export async function POST(request: NextRequest) {
isActive: true,
authType,
password: encryptedPassword,
allowedEmails: authType === 'email' ? allowedEmails : [],
allowedEmails: authType === 'email' || authType === 'sso' ? allowedEmails : [],
outputConfigs,
createdAt: new Date(),
updatedAt: new Date(),

View File

@@ -262,7 +262,67 @@ export async function validateChatAuth(
}
}
// Unknown auth type
if (authType === 'sso') {
if (request.method === 'GET') {
return { authorized: false, error: 'auth_required_sso' }
}
try {
if (!parsedBody) {
return { authorized: false, error: 'SSO authentication is required' }
}
const { email, input, checkSSOAccess } = parsedBody
if (checkSSOAccess) {
if (!email) {
return { authorized: false, error: 'Email is required' }
}
const allowedEmails = deployment.allowedEmails || []
if (allowedEmails.includes(email)) {
return { authorized: true }
}
const domain = email.split('@')[1]
if (domain && allowedEmails.some((allowed: string) => allowed === `@${domain}`)) {
return { authorized: true }
}
return { authorized: false, error: 'Email not authorized for SSO access' }
}
const { auth } = await import('@/lib/auth')
const session = await auth.api.getSession({ headers: request.headers })
if (!session || !session.user) {
return { authorized: false, error: 'auth_required_sso' }
}
const userEmail = session.user.email
if (!userEmail) {
return { authorized: false, error: 'SSO session does not contain email' }
}
const allowedEmails = deployment.allowedEmails || []
if (allowedEmails.includes(userEmail)) {
return { authorized: true }
}
const domain = userEmail.split('@')[1]
if (domain && allowedEmails.some((allowed: string) => allowed === `@${domain}`)) {
return { authorized: true }
}
return { authorized: false, error: 'Your email is not authorized to access this chat' }
} catch (error) {
logger.error(`[${requestId}] Error validating SSO:`, error)
return { authorized: false, error: 'SSO authentication error' }
}
}
return { authorized: false, error: 'Unsupported authentication type' }
}

View File

@@ -121,10 +121,24 @@ export async function POST(request: NextRequest) {
}
if (!isUsingCloudStorage()) {
return NextResponse.json(
{ error: 'Direct uploads are only available when cloud storage is enabled' },
{ status: 400 }
logger.info(
`Local storage detected - batch presigned URLs not available, client will use API fallback`
)
return NextResponse.json({
files: files.map((file) => ({
fileName: file.fileName,
presignedUrl: '', // Empty URL signals fallback to API upload
fileInfo: {
path: '',
key: '',
name: file.fileName,
size: file.fileSize,
type: file.contentType,
},
directUploadSupported: false,
})),
directUploadSupported: false,
})
}
const storageProvider = getStorageProvider()

View File

@@ -25,7 +25,7 @@ describe('/api/files/presigned', () => {
})
describe('POST', () => {
it('should return error when cloud storage is not enabled', async () => {
it('should return graceful fallback response when cloud storage is not enabled', async () => {
setupFileApiMocks({
cloudEnabled: false,
storageProvider: 's3',
@@ -45,10 +45,14 @@ describe('/api/files/presigned', () => {
const response = await POST(request)
const data = await response.json()
expect(response.status).toBe(500)
expect(data.error).toBe('Direct uploads are only available when cloud storage is enabled')
expect(data.code).toBe('STORAGE_CONFIG_ERROR')
expect(response.status).toBe(200)
expect(data.directUploadSupported).toBe(false)
expect(data.presignedUrl).toBe('')
expect(data.fileName).toBe('test.txt')
expect(data.fileInfo).toBeDefined()
expect(data.fileInfo.name).toBe('test.txt')
expect(data.fileInfo.size).toBe(1024)
expect(data.fileInfo.type).toBe('text/plain')
})
it('should return error when fileName is missing', async () => {

View File

@@ -141,9 +141,21 @@ export async function POST(request: NextRequest) {
}
if (!isUsingCloudStorage()) {
throw new StorageConfigError(
'Direct uploads are only available when cloud storage is enabled'
logger.info(
`Local storage detected - presigned URL not available for ${fileName}, client will use API fallback`
)
return NextResponse.json({
fileName,
presignedUrl: '', // Empty URL signals fallback to API upload
fileInfo: {
path: '',
key: '',
name: fileName,
size: fileSize,
type: contentType,
},
directUploadSupported: false,
})
}
const storageProvider = getStorageProvider()

View File

@@ -90,16 +90,38 @@ export const POST = withMcpAuth('read')(
)
}
// Parse array arguments based on tool schema
// Cast arguments to their expected types based on tool schema
if (tool.inputSchema?.properties) {
for (const [paramName, paramSchema] of Object.entries(tool.inputSchema.properties)) {
const schema = paramSchema as any
const value = args[paramName]
if (value === undefined || value === null) {
continue
}
// Cast numbers
if (
schema.type === 'array' &&
args[paramName] !== undefined &&
typeof args[paramName] === 'string'
(schema.type === 'number' || schema.type === 'integer') &&
typeof value === 'string'
) {
const stringValue = args[paramName].trim()
const numValue =
schema.type === 'integer' ? Number.parseInt(value) : Number.parseFloat(value)
if (!Number.isNaN(numValue)) {
args[paramName] = numValue
}
}
// Cast booleans
else if (schema.type === 'boolean' && typeof value === 'string') {
if (value.toLowerCase() === 'true') {
args[paramName] = true
} else if (value.toLowerCase() === 'false') {
args[paramName] = false
}
}
// Cast arrays
else if (schema.type === 'array' && typeof value === 'string') {
const stringValue = value.trim()
if (stringValue) {
try {
// Try to parse as JSON first (handles ["item1", "item2"])

View File

@@ -1,4 +1,5 @@
import { type NextRequest, NextResponse } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { createLogger } from '@/lib/logs/console/logger'
import { validateImageUrl } from '@/lib/security/input-validation'
import { generateRequestId } from '@/lib/utils'
@@ -14,6 +15,12 @@ export async function GET(request: NextRequest) {
const imageUrl = url.searchParams.get('url')
const requestId = generateRequestId()
const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error(`[${requestId}] Authentication failed for image proxy:`, authResult.error)
return new NextResponse('Unauthorized', { status: 401 })
}
if (!imageUrl) {
logger.error(`[${requestId}] Missing 'url' parameter`)
return new NextResponse('Missing URL parameter', { status: 400 })

View File

@@ -1,4 +1,6 @@
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { generateInternalToken } from '@/lib/auth/internal'
import { isDev } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console/logger'
@@ -242,12 +244,18 @@ export async function GET(request: Request) {
}
}
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const requestId = generateRequestId()
const startTime = new Date()
const startTimeISO = startTime.toISOString()
try {
const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error(`[${requestId}] Authentication failed for proxy:`, authResult.error)
return createErrorResponse('Unauthorized', 401)
}
let requestBody
try {
requestBody = await request.json()
@@ -311,7 +319,6 @@ export async function POST(request: Request) {
error: result.error || 'Unknown error',
})
// Let the main executeTool handle error transformation to avoid double transformation
throw new Error(result.error || 'Tool execution failed')
}
@@ -319,10 +326,8 @@ export async function POST(request: Request) {
const endTimeISO = endTime.toISOString()
const duration = endTime.getTime() - startTime.getTime()
// Add explicit timing information directly to the response
const responseWithTimingData = {
...result,
// Add timing data both at root level and in nested timing object
startTime: startTimeISO,
endTime: endTimeISO,
duration,
@@ -335,7 +340,6 @@ export async function POST(request: Request) {
logger.info(`[${requestId}] Tool executed successfully: ${toolId} (${duration}ms)`)
// Return the response with CORS headers
return formatResponse(responseWithTimingData)
} catch (error: any) {
logger.error(`[${requestId}] Proxy request failed`, {
@@ -344,7 +348,6 @@ export async function POST(request: Request) {
name: error instanceof Error ? error.name : undefined,
})
// Add timing information even to error responses
const endTime = new Date()
const endTimeISO = endTime.toISOString()
const duration = endTime.getTime() - startTime.getTime()

View File

@@ -1,4 +1,6 @@
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { createLogger } from '@/lib/logs/console/logger'
import { validateAlphanumericId } from '@/lib/security/input-validation'
import { uploadFile } from '@/lib/uploads/storage-client'
@@ -6,19 +8,25 @@ import { getBaseUrl } from '@/lib/urls/utils'
const logger = createLogger('ProxyTTSAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error('Authentication failed for TTS proxy:', authResult.error)
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const { text, voiceId, apiKey, modelId = 'eleven_monolingual_v1' } = body
if (!text || !voiceId || !apiKey) {
return new NextResponse('Missing required parameters', { status: 400 })
return NextResponse.json({ error: 'Missing required parameters' }, { status: 400 })
}
const voiceIdValidation = validateAlphanumericId(voiceId, 'voiceId', 255)
if (!voiceIdValidation.isValid) {
logger.error(`Invalid voice ID: ${voiceIdValidation.error}`)
return new NextResponse(voiceIdValidation.error, { status: 400 })
return NextResponse.json({ error: voiceIdValidation.error }, { status: 400 })
}
logger.info('Proxying TTS request for voice:', voiceId)
@@ -41,16 +49,17 @@ export async function POST(request: Request) {
if (!response.ok) {
logger.error(`Failed to generate TTS: ${response.status} ${response.statusText}`)
return new NextResponse(`Failed to generate TTS: ${response.status} ${response.statusText}`, {
status: response.status,
})
return NextResponse.json(
{ error: `Failed to generate TTS: ${response.status} ${response.statusText}` },
{ status: response.status }
)
}
const audioBlob = await response.blob()
if (audioBlob.size === 0) {
logger.error('Empty audio received from ElevenLabs')
return new NextResponse('Empty audio received', { status: 422 })
return NextResponse.json({ error: 'Empty audio received' }, { status: 422 })
}
const audioBuffer = Buffer.from(await audioBlob.arrayBuffer())
@@ -67,11 +76,11 @@ export async function POST(request: Request) {
} catch (error) {
logger.error('Error proxying TTS:', error)
return new NextResponse(
`Internal Server Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
return NextResponse.json(
{
status: 500,
}
error: `Internal Server Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
{ status: 500 }
)
}
}

View File

@@ -1,4 +1,5 @@
import type { NextRequest } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { env } from '@/lib/env'
import { createLogger } from '@/lib/logs/console/logger'
import { validateAlphanumericId } from '@/lib/security/input-validation'
@@ -7,6 +8,12 @@ const logger = createLogger('ProxyTTSStreamAPI')
export async function POST(request: NextRequest) {
try {
const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error('Authentication failed for TTS stream proxy:', authResult.error)
return new Response('Unauthorized', { status: 401 })
}
const body = await request.json()
const { text, voiceId, modelId = 'eleven_turbo_v2_5' } = body

View File

@@ -0,0 +1,69 @@
import { type NextRequest, NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { createLogger } from '@/lib/logs/console/logger'
import { getOAuthToken } from '@/app/api/auth/oauth/utils'
const logger = createLogger('WebflowCollectionsAPI')
export const dynamic = 'force-dynamic'
export async function GET(request: NextRequest) {
try {
const session = await getSession()
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const siteId = searchParams.get('siteId')
if (!siteId) {
return NextResponse.json({ error: 'Missing siteId parameter' }, { status: 400 })
}
const accessToken = await getOAuthToken(session.user.id, 'webflow')
if (!accessToken) {
return NextResponse.json(
{ error: 'No Webflow access token found. Please connect your Webflow account.' },
{ status: 404 }
)
}
const response = await fetch(`https://api.webflow.com/v2/sites/${siteId}/collections`, {
headers: {
Authorization: `Bearer ${accessToken}`,
accept: 'application/json',
},
})
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
logger.error('Failed to fetch Webflow collections', {
status: response.status,
error: errorData,
siteId,
})
return NextResponse.json(
{ error: 'Failed to fetch Webflow collections', details: errorData },
{ status: response.status }
)
}
const data = await response.json()
const collections = data.collections || []
const formattedCollections = collections.map((collection: any) => ({
id: collection.id,
name: collection.displayName || collection.slug || collection.id,
}))
return NextResponse.json({ collections: formattedCollections }, { status: 200 })
} catch (error: any) {
logger.error('Error fetching Webflow collections', error)
return NextResponse.json(
{ error: 'Internal server error', details: error.message },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,61 @@
import { type NextRequest, NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { createLogger } from '@/lib/logs/console/logger'
import { getOAuthToken } from '@/app/api/auth/oauth/utils'
const logger = createLogger('WebflowSitesAPI')
export const dynamic = 'force-dynamic'
export async function GET(request: NextRequest) {
try {
const session = await getSession()
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const accessToken = await getOAuthToken(session.user.id, 'webflow')
if (!accessToken) {
return NextResponse.json(
{ error: 'No Webflow access token found. Please connect your Webflow account.' },
{ status: 404 }
)
}
const response = await fetch('https://api.webflow.com/v2/sites', {
headers: {
Authorization: `Bearer ${accessToken}`,
accept: 'application/json',
},
})
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
logger.error('Failed to fetch Webflow sites', {
status: response.status,
error: errorData,
})
return NextResponse.json(
{ error: 'Failed to fetch Webflow sites', details: errorData },
{ status: response.status }
)
}
const data = await response.json()
const sites = data.sites || []
const formattedSites = sites.map((site: any) => ({
id: site.id,
name: site.displayName || site.shortName || site.id,
}))
return NextResponse.json({ sites: formattedSites }, { status: 200 })
} catch (error: any) {
logger.error('Error fetching Webflow sites', error)
return NextResponse.json(
{ error: 'Internal server error', details: error.message },
{ status: 500 }
)
}
}

View File

@@ -3,6 +3,7 @@ import { checkHybridAuth } from '@/lib/auth/hybrid'
import { checkServerSideUsageLimits } from '@/lib/billing'
import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
import { getEffectiveCurrentPeriodCost } from '@/lib/billing/core/usage'
import { getUserStorageLimit, getUserStorageUsage } from '@/lib/billing/storage'
import { createLogger } from '@/lib/logs/console/logger'
import { createErrorResponse } from '@/app/api/workflows/utils'
import { RateLimiter } from '@/services/queue'
@@ -37,9 +38,11 @@ export async function GET(request: NextRequest) {
])
// Usage summary (current period cost + limit + plan)
const [usageCheck, effectiveCost] = await Promise.all([
const [usageCheck, effectiveCost, storageUsage, storageLimit] = await Promise.all([
checkServerSideUsageLimits(authenticatedUserId),
getEffectiveCurrentPeriodCost(authenticatedUserId),
getUserStorageUsage(authenticatedUserId),
getUserStorageLimit(authenticatedUserId),
])
const currentPeriodCost = effectiveCost
@@ -66,6 +69,11 @@ export async function GET(request: NextRequest) {
limit: usageCheck.limit,
plan: userSubscription?.plan || 'free',
},
storage: {
usedBytes: storageUsage,
limitBytes: storageLimit,
percentUsed: storageLimit > 0 ? (storageUsage / storageLimit) * 100 : 0,
},
})
} catch (error: any) {
logger.error('Error checking usage limits:', error)

View File

@@ -428,6 +428,26 @@ export async function POST(request: NextRequest) {
}
// --- End Outlook specific logic ---
// --- Webflow webhook setup ---
if (savedWebhook && provider === 'webflow') {
logger.info(
`[${requestId}] Webflow provider detected. Attempting to create webhook in Webflow.`
)
try {
await createWebflowWebhookSubscription(request, userId, savedWebhook, requestId)
} catch (err) {
logger.error(`[${requestId}] Error creating Webflow webhook`, err)
return NextResponse.json(
{
error: 'Failed to create webhook in Webflow',
details: err instanceof Error ? err.message : 'Unknown error',
},
{ status: 500 }
)
}
}
// --- End Webflow specific logic ---
const status = targetWebhookId ? 200 : 201
return NextResponse.json({ webhook: savedWebhook }, { status })
} catch (error: any) {
@@ -548,3 +568,136 @@ async function createAirtableWebhookSubscription(
)
}
}
// Helper function to create the webhook subscription in Webflow
async function createWebflowWebhookSubscription(
request: NextRequest,
userId: string,
webhookData: any,
requestId: string
) {
try {
const { path, providerConfig } = webhookData
const { siteId, triggerId, collectionId, formId } = providerConfig || {}
if (!siteId) {
logger.warn(`[${requestId}] Missing siteId for Webflow webhook creation.`, {
webhookId: webhookData.id,
})
throw new Error('Site ID is required to create Webflow webhook')
}
if (!triggerId) {
logger.warn(`[${requestId}] Missing triggerId for Webflow webhook creation.`, {
webhookId: webhookData.id,
})
throw new Error('Trigger type is required to create Webflow webhook')
}
const accessToken = await getOAuthToken(userId, 'webflow')
if (!accessToken) {
logger.warn(
`[${requestId}] Could not retrieve Webflow access token for user ${userId}. Cannot create webhook in Webflow.`
)
throw new Error(
'Webflow account connection required. Please connect your Webflow account in the trigger configuration and try again.'
)
}
const notificationUrl = `${getBaseUrl()}/api/webhooks/trigger/${path}`
// Map trigger IDs to Webflow trigger types
const triggerTypeMap: Record<string, string> = {
webflow_collection_item_created: 'collection_item_created',
webflow_collection_item_changed: 'collection_item_changed',
webflow_collection_item_deleted: 'collection_item_deleted',
webflow_form_submission: 'form_submission',
}
const webflowTriggerType = triggerTypeMap[triggerId]
if (!webflowTriggerType) {
logger.warn(`[${requestId}] Invalid triggerId for Webflow: ${triggerId}`, {
webhookId: webhookData.id,
})
throw new Error(`Invalid Webflow trigger type: ${triggerId}`)
}
const webflowApiUrl = `https://api.webflow.com/v2/sites/${siteId}/webhooks`
const requestBody: any = {
triggerType: webflowTriggerType,
url: notificationUrl,
}
// Add filter for collection-based triggers
if (collectionId && webflowTriggerType.startsWith('collection_item_')) {
requestBody.filter = {
resource_type: 'collection',
resource_id: collectionId,
}
}
// Add filter for form submissions
if (formId && webflowTriggerType === 'form_submission') {
requestBody.filter = {
resource_type: 'form',
resource_id: formId,
}
}
const webflowResponse = await fetch(webflowApiUrl, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
accept: 'application/json',
},
body: JSON.stringify(requestBody),
})
const responseBody = await webflowResponse.json()
if (!webflowResponse.ok || responseBody.error) {
const errorMessage = responseBody.message || responseBody.error || 'Unknown Webflow API error'
logger.error(
`[${requestId}] Failed to create webhook in Webflow for webhook ${webhookData.id}. Status: ${webflowResponse.status}`,
{ message: errorMessage, response: responseBody }
)
throw new Error(errorMessage)
}
logger.info(
`[${requestId}] Successfully created webhook in Webflow for webhook ${webhookData.id}.`,
{
webflowWebhookId: responseBody.id || responseBody._id,
}
)
// Store the Webflow webhook ID in the providerConfig
try {
const currentConfig = (webhookData.providerConfig as Record<string, any>) || {}
const updatedConfig = {
...currentConfig,
externalId: responseBody.id || responseBody._id,
}
await db
.update(webhook)
.set({ providerConfig: updatedConfig, updatedAt: new Date() })
.where(eq(webhook.id, webhookData.id))
} catch (dbError: any) {
logger.error(
`[${requestId}] Failed to store externalId in providerConfig for webhook ${webhookData.id}.`,
dbError
)
// Even if saving fails, the webhook exists in Webflow. Log and continue.
}
} catch (error: any) {
logger.error(
`[${requestId}] Exception during Webflow webhook creation for webhook ${webhookData.id}.`,
{
message: error.message,
stack: error.stack,
}
)
throw error
}
}

View File

@@ -1,10 +1,9 @@
import { apiKey, db, workflow, workflowDeploymentVersion } from '@sim/db'
import { and, desc, eq, sql } from 'drizzle-orm'
import { and, desc, eq } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { v4 as uuidv4 } from 'uuid'
import { createLogger } from '@/lib/logs/console/logger'
import { generateRequestId } from '@/lib/utils'
import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/db-helpers'
import { deployWorkflow } from '@/lib/workflows/db-helpers'
import { validateWorkflowPermissions } from '@/lib/workflows/utils'
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
@@ -138,37 +137,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
}
} catch (_err) {}
logger.debug(`[${requestId}] Getting current workflow state for deployment`)
const normalizedData = await loadWorkflowFromNormalizedTables(id)
if (!normalizedData) {
logger.error(`[${requestId}] Failed to load workflow from normalized tables`)
return createErrorResponse('Failed to load workflow state', 500)
}
const currentState = {
blocks: normalizedData.blocks,
edges: normalizedData.edges,
loops: normalizedData.loops,
parallels: normalizedData.parallels,
lastSaved: Date.now(),
}
logger.debug(`[${requestId}] Current state retrieved from normalized tables:`, {
blocksCount: Object.keys(currentState.blocks).length,
edgesCount: currentState.edges.length,
loopsCount: Object.keys(currentState.loops).length,
parallelsCount: Object.keys(currentState.parallels).length,
})
if (!currentState || !currentState.blocks) {
logger.error(`[${requestId}] Invalid workflow state retrieved`, { currentState })
throw new Error('Invalid workflow state: missing blocks')
}
const deployedAt = new Date()
logger.debug(`[${requestId}] Proceeding with deployment at ${deployedAt.toISOString()}`)
logger.debug(`[${requestId}] Validating API key for deployment`)
let keyInfo: { name: string; type: 'personal' | 'workspace' } | null = null
let matchedKey: {
@@ -260,46 +229,20 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
return createErrorResponse('Unable to determine deploying user', 400)
}
await db.transaction(async (tx) => {
const [{ maxVersion }] = await tx
.select({ maxVersion: sql`COALESCE(MAX("version"), 0)` })
.from(workflowDeploymentVersion)
.where(eq(workflowDeploymentVersion.workflowId, id))
const nextVersion = Number(maxVersion) + 1
await tx
.update(workflowDeploymentVersion)
.set({ isActive: false })
.where(
and(
eq(workflowDeploymentVersion.workflowId, id),
eq(workflowDeploymentVersion.isActive, true)
)
)
await tx.insert(workflowDeploymentVersion).values({
id: uuidv4(),
workflowId: id,
version: nextVersion,
state: currentState,
isActive: true,
createdAt: deployedAt,
createdBy: actorUserId,
})
const updateData: Record<string, unknown> = {
isDeployed: true,
deployedAt,
deployedState: currentState,
}
if (providedApiKey && matchedKey) {
updateData.pinnedApiKeyId = matchedKey.id
}
await tx.update(workflow).set(updateData).where(eq(workflow.id, id))
const deployResult = await deployWorkflow({
workflowId: id,
deployedBy: actorUserId,
pinnedApiKeyId: matchedKey?.id,
includeDeployedState: true,
workflowName: workflowData!.name,
})
if (!deployResult.success) {
return createErrorResponse(deployResult.error || 'Failed to deploy workflow', 500)
}
const deployedAt = deployResult.deployedAt!
if (matchedKey) {
try {
await db
@@ -313,31 +256,6 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
logger.info(`[${requestId}] Workflow deployed successfully: ${id}`)
// Track workflow deployment
try {
const { trackPlatformEvent } = await import('@/lib/telemetry/tracer')
// Aggregate block types to understand which blocks are being used
const blockTypeCounts: Record<string, number> = {}
for (const block of Object.values(currentState.blocks)) {
const blockType = (block as any).type || 'unknown'
blockTypeCounts[blockType] = (blockTypeCounts[blockType] || 0) + 1
}
trackPlatformEvent('platform.workflow.deployed', {
'workflow.id': id,
'workflow.name': workflowData!.name,
'workflow.blocks_count': Object.keys(currentState.blocks).length,
'workflow.edges_count': currentState.edges.length,
'workflow.has_loops': Object.keys(currentState.loops).length > 0,
'workflow.has_parallels': Object.keys(currentState.parallels).length > 0,
'workflow.api_key_type': keyInfo?.type || 'default',
'workflow.block_types': JSON.stringify(blockTypeCounts),
})
} catch (_e) {
// Silently fail
}
const responseApiKeyInfo = keyInfo ? `${keyInfo.name} (${keyInfo.type})` : 'Default key'
return createSuccessResponse({

View File

@@ -1,4 +1,4 @@
import { db, workflow, workflowDeploymentVersion } from '@sim/db'
import { apiKey, db, workflow, workflowDeploymentVersion } from '@sim/db'
import { and, eq } from 'drizzle-orm'
import type { NextRequest } from 'next/server'
import { createLogger } from '@/lib/logs/console/logger'
@@ -19,7 +19,11 @@ export async function POST(
const { id, version } = await params
try {
const { error } = await validateWorkflowPermissions(id, requestId, 'admin')
const {
error,
session,
workflow: workflowData,
} = await validateWorkflowPermissions(id, requestId, 'admin')
if (error) {
return createErrorResponse(error.message, error.status)
}
@@ -29,6 +33,52 @@ export async function POST(
return createErrorResponse('Invalid version', 400)
}
let providedApiKey: string | null = null
try {
const parsed = await request.json()
if (parsed && typeof parsed.apiKey === 'string' && parsed.apiKey.trim().length > 0) {
providedApiKey = parsed.apiKey.trim()
}
} catch (_err) {}
let pinnedApiKeyId: string | null = null
if (providedApiKey) {
const currentUserId = session?.user?.id
if (currentUserId) {
const [personalKey] = await db
.select({ id: apiKey.id })
.from(apiKey)
.where(
and(
eq(apiKey.id, providedApiKey),
eq(apiKey.userId, currentUserId),
eq(apiKey.type, 'personal')
)
)
.limit(1)
if (personalKey) {
pinnedApiKeyId = personalKey.id
} else if (workflowData!.workspaceId) {
const [workspaceKey] = await db
.select({ id: apiKey.id })
.from(apiKey)
.where(
and(
eq(apiKey.id, providedApiKey),
eq(apiKey.workspaceId, workflowData!.workspaceId),
eq(apiKey.type, 'workspace')
)
)
.limit(1)
if (workspaceKey) {
pinnedApiKeyId = workspaceKey.id
}
}
}
}
const now = new Date()
await db.transaction(async (tx) => {
@@ -57,10 +107,16 @@ export async function POST(
throw new Error('Deployment version not found')
}
await tx
.update(workflow)
.set({ isDeployed: true, deployedAt: now })
.where(eq(workflow.id, id))
const updateData: Record<string, unknown> = {
isDeployed: true,
deployedAt: now,
}
if (pinnedApiKeyId) {
updateData.pinnedApiKeyId = pinnedApiKeyId
}
await tx.update(workflow).set(updateData).where(eq(workflow.id, id))
})
return createSuccessResponse({ success: true, deployedAt: now })

View File

@@ -14,6 +14,7 @@ import {
ChatMessageContainer,
EmailAuth,
PasswordAuth,
SSOAuth,
VoiceInterface,
} from '@/app/chat/components'
import { CHAT_ERROR_MESSAGES, CHAT_REQUEST_TIMEOUT_MS } from '@/app/chat/constants'
@@ -32,7 +33,7 @@ interface ChatConfig {
welcomeMessage?: string
headerText?: string
}
authType?: 'public' | 'password' | 'email'
authType?: 'public' | 'password' | 'email' | 'sso'
outputConfigs?: Array<{ blockId: string; path?: string }>
}
@@ -119,7 +120,7 @@ export default function ChatClient({ identifier }: { identifier: string }) {
const [userHasScrolled, setUserHasScrolled] = useState(false)
const isUserScrollingRef = useRef(false)
const [authRequired, setAuthRequired] = useState<'password' | 'email' | null>(null)
const [authRequired, setAuthRequired] = useState<'password' | 'email' | 'sso' | null>(null)
const [isVoiceFirstMode, setIsVoiceFirstMode] = useState(false)
const { isStreamingResponse, abortControllerRef, stopStreaming, handleStreamedResponse } =
@@ -222,6 +223,10 @@ export default function ChatClient({ identifier }: { identifier: string }) {
setAuthRequired('email')
return
}
if (errorData.error === 'auth_required_sso') {
setAuthRequired('sso')
return
}
}
throw new Error(`Failed to load chat configuration: ${response.status}`)
@@ -500,6 +505,16 @@ export default function ChatClient({ identifier }: { identifier: string }) {
/>
)
}
if (authRequired === 'sso') {
return (
<SSOAuth
identifier={identifier}
onAuthSuccess={handleAuthSuccess}
title={title}
primaryColor={primaryColor}
/>
)
}
}
// Loading state while fetching config using the extracted component

View File

@@ -0,0 +1,209 @@
'use client'
import { type KeyboardEvent, useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { quickValidateEmail } from '@/lib/email/validation'
import { createLogger } from '@/lib/logs/console/logger'
import { cn } from '@/lib/utils'
import Nav from '@/app/(landing)/components/nav/nav'
import { inter } from '@/app/fonts/inter'
import { soehne } from '@/app/fonts/soehne/soehne'
const logger = createLogger('SSOAuth')
interface SSOAuthProps {
identifier: string
onAuthSuccess: () => void
title?: string
primaryColor?: string
}
const validateEmailField = (emailValue: string): string[] => {
const errors: string[] = []
if (!emailValue || !emailValue.trim()) {
errors.push('Email is required.')
return errors
}
const validation = quickValidateEmail(emailValue.trim().toLowerCase())
if (!validation.isValid) {
errors.push(validation.reason || 'Please enter a valid email address.')
}
return errors
}
export default function SSOAuth({
identifier,
onAuthSuccess,
title = 'chat',
primaryColor = 'var(--brand-primary-hover-hex)',
}: SSOAuthProps) {
const router = useRouter()
const [email, setEmail] = useState('')
const [emailErrors, setEmailErrors] = useState<string[]>([])
const [showEmailValidationError, setShowEmailValidationError] = useState(false)
const [buttonClass, setButtonClass] = useState('auth-button-gradient')
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
const checkCustomBrand = () => {
const computedStyle = getComputedStyle(document.documentElement)
const brandAccent = computedStyle.getPropertyValue('--brand-accent-hex').trim()
if (brandAccent && brandAccent !== '#6f3dfa') {
setButtonClass('auth-button-custom')
} else {
setButtonClass('auth-button-gradient')
}
}
checkCustomBrand()
window.addEventListener('resize', checkCustomBrand)
const observer = new MutationObserver(checkCustomBrand)
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['style', 'class'],
})
return () => {
window.removeEventListener('resize', checkCustomBrand)
observer.disconnect()
}
}, [])
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault()
handleAuthenticate()
}
}
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newEmail = e.target.value
setEmail(newEmail)
setShowEmailValidationError(false)
setEmailErrors([])
}
const handleAuthenticate = async () => {
const emailValidationErrors = validateEmailField(email)
setEmailErrors(emailValidationErrors)
setShowEmailValidationError(emailValidationErrors.length > 0)
if (emailValidationErrors.length > 0) {
return
}
setIsLoading(true)
try {
const checkResponse = await fetch(`/api/chat/${identifier}`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify({ email, checkSSOAccess: true }),
})
if (!checkResponse.ok) {
const errorData = await checkResponse.json()
setEmailErrors([errorData.error || 'Email not authorized for this chat'])
setShowEmailValidationError(true)
setIsLoading(false)
return
}
const callbackUrl = `/chat/${identifier}`
const ssoUrl = `/sso?email=${encodeURIComponent(email)}&callbackUrl=${encodeURIComponent(callbackUrl)}`
router.push(ssoUrl)
} catch (error) {
logger.error('SSO authentication error:', error)
setEmailErrors(['An error occurred during authentication'])
setShowEmailValidationError(true)
setIsLoading(false)
}
}
return (
<div className='bg-white'>
<Nav variant='auth' />
<div className='flex min-h-[calc(100vh-120px)] items-center justify-center px-4'>
<div className='w-full max-w-[410px]'>
<div className='flex flex-col items-center justify-center'>
{/* Header */}
<div className='space-y-1 text-center'>
<h1
className={`${soehne.className} font-medium text-[32px] text-black tracking-tight`}
>
SSO Authentication
</h1>
<p className={`${inter.className} font-[380] text-[16px] text-muted-foreground`}>
This chat requires SSO authentication
</p>
</div>
{/* Form */}
<form
onSubmit={(e) => {
e.preventDefault()
handleAuthenticate()
}}
className={`${inter.className} mt-8 w-full space-y-8`}
>
<div className='space-y-6'>
<div className='space-y-2'>
<div className='flex items-center justify-between'>
<Label htmlFor='email'>Work Email</Label>
</div>
<Input
id='email'
name='email'
required
type='email'
autoCapitalize='none'
autoComplete='email'
autoCorrect='off'
placeholder='Enter your work email'
value={email}
onChange={handleEmailChange}
onKeyDown={handleKeyDown}
className={cn(
'rounded-[10px] shadow-sm transition-colors focus:border-gray-400 focus:ring-2 focus:ring-gray-100',
showEmailValidationError &&
emailErrors.length > 0 &&
'border-red-500 focus:border-red-500 focus:ring-red-100 focus-visible:ring-red-500'
)}
autoFocus
/>
{showEmailValidationError && emailErrors.length > 0 && (
<div className='mt-1 space-y-1 text-red-400 text-xs'>
{emailErrors.map((error, index) => (
<p key={index}>{error}</p>
))}
</div>
)}
</div>
</div>
<Button
type='submit'
className={`${buttonClass} flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200`}
disabled={isLoading}
>
{isLoading ? 'Redirecting to SSO...' : 'Continue with SSO'}
</Button>
</form>
</div>
</div>
</div>
</div>
)
}

View File

@@ -1,5 +1,6 @@
export { default as EmailAuth } from './auth/email/email-auth'
export { default as PasswordAuth } from './auth/password/password-auth'
export { default as SSOAuth } from './auth/sso/sso-auth'
export { ChatErrorState } from './error-state/error-state'
export { ChatHeader } from './header/header'
export { ChatInput } from './input/input'

Some files were not shown because too many files have changed in this diff Show More