Skip to content

Commit dc5bab6

Browse files
feat(embeddings): multi-provider Embeddings block on a shared core (#6317)
* feat(embeddings): multi-provider Embeddings block on a shared core The Embeddings block was OpenAI-only with a bare fetch: no batching, no retry, no metering, and no hosted-key support. Meanwhile the knowledge-base indexing path already had a real multi-provider engine. Nothing bridged the two, so the block could not reach Gemini and the KB engine could not be reached from a workflow. Extract the shared core into lib/embeddings/ first, then build breadth on top of it, so both the KB path and the block resolve models and providers from one catalog and one set of adapters instead of a third parallel implementation. - lib/embeddings/: catalog, client, key resolution, batching, L2 normalization, and adapters for OpenAI, Azure OpenAI, Gemini, Cohere, and Mistral - lib/knowledge/embeddings.ts becomes a thin KB wrapper with its exported signatures unchanged; the 1536-dimension vector invariant does not move - one tool per provider from a shared factory, behind a single /api/tools/embeddings route and contract - new `embeddings` block type; the `openai` block is left functionally untouched and only leaves the discovery surfaces via hideFromToolbar plus sunset.replacedBy, so placed instances keep working unmigrated - openai_embeddings is now an alias of embeddings_openai, so legacy instances pick up batching, retry, and metering with no visible change * fix(embeddings): report an unsupported dimension as a client error The route validated the model and the provider match up front but left `dimensions` to be checked inside embed(), where resolveDimensions throws and the generic catch maps it to 502. A typo in the block's dimension field, or a reference expression resolving to an out-of-range value, was reported as an upstream gateway failure rather than bad input. Resolve dimensions in the route alongside the other boundary checks and return 400. The throw stays the single source of the message, so the two call sites cannot drift. Adds route tests covering auth, the response shape, each boundary rejection, input normalization, and the 502 path for genuine provider failures. * fix(embeddings): only send a dimension when the caller asked to reduce resolveDimensions() returns the model's native size when no reduction is requested, and that resolved value was handed straight to the adapter. The adapters guard on `dimensions !== undefined`, so the field was always populated and always sent. Models that support Matryoshka reduction accept their own native size, so this was invisible for text-embedding-3-*, gemini-embedding-001, embed-v4.0, and codestral-embed. Models that do not support the parameter at all reject it outright: every unreduced request to text-embedding-ada-002 and mistral-embed failed with a 400, which is both of the models whose catalog entry has no supportedDimensions. Track the caller's explicit reduction separately from the resolved dimensionality. The resolved value still drives reporting and billing; only the requested one reaches the wire. Found by driving the live provider matrix against all four providers. * test(knowledge): de-flake the sync-engine suite Every test dynamically imported the module under test, so the first one to run paid the whole cold-load cost inside its own 10s timeout and failed intermittently under load. The dynamic imports were working around a hoisting problem: mockMapTags is a top-level const read by a vi.mock factory, and vi.mock is hoisted above it, so a static import of the module under test crashes with a use-before-initialization error. Declaring the mock through vi.hoisted() removes that constraint, which is the pattern the testing guidelines already call for. One static import replaces 42 dynamic ones. The file drops from ~15s to ~2s and passed 5 consecutive runs. * fix(embeddings): drop a capability the selected model no longer offers The per-model Dimensions and Task Type dropdowns each share one subblock id, and nothing clears a stored subblock value when its dependsOn fields change — dependsOn only feeds rendering. A choice made for one model therefore outlives a switch to another. Picking 3072 on text-embedding-3-large and switching to -3-small left 3072 stored while the dropdown offered at most 1536, and the block forwarded it. Same for a task type: 'similarity' chosen on Gemini survived a switch to Cohere, which has no equivalent input type. The guards only checked that the model declared the capability at all, not that the value was one it lists. Check membership so a stale value falls back to the model's native size, or is omitted, instead of being sent and rejected. The user cannot have deliberately chosen an option the dropdown stopped presenting. * feat(embeddings): use the latent-constellation mark for the block icon Replaces the scatter-plot-on-axes placeholder with a centre node, four neighbours, and the rays between them — a point and its nearest neighbours in embedding space, which is what the block actually produces. The axes mark read as a generic chart and said nothing specific to embeddings. Nodes are filled so they hold their shape at small sizes. The rays carry less weight than the nodes to keep the hierarchy, but at 1.6/0.9 rather than the 1.4/0.75 they were drawn at, so they do not thin out to loose dots in the 14px block-search row. Kept byte-identical between the app and docs icon sets. * fix(embeddings): declare the outputs the legacy openai block returns openai_embeddings became an alias of embeddings_openai, so the legacy block's runtime payload gained `provider` and `dimensions`. Its declared outputs still listed only embeddings/model/usage, so the tag picker never offered two fields every run demonstrably returns, and downstream blocks could not reference them. Declaring them is additive and does not touch execution. Asserts the legacy block's output keys match the replacement's, since both run the same tool and neither should expose fields the other lacks. * fix(copilot): resolve same-id subblock variants before validating A block may declare one field id several times, each variant conditioned on another field — the embeddings block declares model, dimensions, and taskType once per provider, and the image and video generators do the same. Validation keyed a map by id alone, so whichever variant was declared last silently became the validator for every write to that field. Programmatic edits to an embeddings block were therefore checked against Mistral's option lists whatever the saved provider: `text-embedding-3-small` was rejected as not one of mistral-embed/codestral-embed, and dimensions valid only elsewhere (3072, 768) could not be set at all. Values that happened to overlap the last variant passed, so automation saw partial success rather than a clean failure. Keep every candidate per id and pick the one whose condition holds, evaluating against the mutation's inputs merged over the block's saved values so a partial write still resolves. When no condition matches, fall back to the union of all variants' options rather than guessing. Conditions still never gate whether a field may be written — that was a deliberate choice and a hidden field stays writable. They only select which definition describes the field, and an unresolved condition widens the accepted set instead of narrowing it. * fix(copilot): prefer a conditioned variant over an unconditioned catch-all An unconditioned same-id variant matches every set of values, so it would shadow a genuinely selected variant purely by being declared first. Prefer a variant that actually asserted something about the current values. No block in the registry currently declares a catch-all ahead of a conditioned variant on a field where it would change validation, so this is a guard against the pattern rather than a fix for a live case. * chore(embeddings): scope this branch to the multi-provider block Two changes made while building the Embeddings block are not part of it and ship separately, so their files are restored to staging here: - copilot edit-workflow validation resolving same-id conditional subblock variants. The embeddings block surfaced it, but it is a platform fix affecting ~20 blocks that declare a field id more than once, and it narrows what programmatic edits accept — that deserves its own review. - the sync-engine test de-flake, which is unrelated test hygiene. Both are preserved in full on feat/embeddings-full-snapshot. Note this restores the reported bug where a programmatic edit to an embeddings block validates model/dimensions against the last-declared provider variant. The block is unaffected in the editor and at runtime. * fix(embeddings): honor per-model token limits and bound the JSON input path Review round 1. Batching used one 8,000-token constant for every model, inherited from the knowledge-base engine this branch extracted. `batchByTokenLimit` truncates any single text above the limit it is given, so that constant both sent oversized input to models with a lower ceiling and silently dropped content models with a higher one accept: - Gemini declares 2,048, so a 3,000-token text passed through whole and the provider rejected it, surfacing as a 502. This also affected knowledge-base indexing on staging, which uses the same constant. - Cohere declares 128,000, so anything past 8,000 was truncated for no reason. Batch against the selected model's own `maxInputTokens` instead. Using the per-input ceiling as the per-batch budget also keeps every individual text within it. The contract bounds the array arm of `input`, but a JSON-encoded array arrives as a plain string and `normalizeInput` only expands it after validation — so neither the 1,000-input cap nor the non-empty checks applied to the reference-expression path the route was written to accept. `"[]"` also reported success with no vectors. Re-check the normalized list so the bounds hold for both shapes. * chore(embeddings): regenerate tool metadata for the new embedding tools CI's tool-metadata:check gate failed: registering embeddings_openai, embeddings_gemini, embeddings_cohere, and embeddings_mistral left the generated tool-ids/metadata/outputs artifacts stale. * fix(embeddings): project before batching, and keep the sunset block's docs icon Review round 2. Projection ran inside callEmbeddingAPI, after batchByTokenLimit had already measured and truncated the original text. The projector rewrites resolved secrets to placeholders, which changes length, so batching sized against a string that was never sent: a lengthening projection then pushed input past the model's ceiling and the provider rejected it, and a shortening one discarded document content that would have fit. Project once up front, then batch the projected text, so truncation measures what actually goes to the provider. This also keeps projection to exactly one call per embed(), so no retry can re-project. Separately, marking the legacy openai block hideFromToolbar dropped it from the generated docs icon map, which only retains hidden blocks when they are versioned. integrations/openai.mdx is deliberately kept — docsLink is baked into every placed instance — so BlockInfoCard lost its icon and fell back to a text tile. A sunset block keeps its docs page for the same reason a hidden versioned block does, so the generator now treats it the same way. The sim-side integrations map still omits it, which is intended: that feeds the discovery page a sunset block should not appear on, and placed blocks render from the registry's own icon reference. * fix(embeddings): override stale block params instead of omitting them Review round 3. The generic handler merges the params() result over the original inputs (`{ ...inputs, ...transformedParams }`), so omitting a key leaves the stale value in place. The previous round dropped an unsupported taskType or dimensions by omission, which was therefore a no-op through the executor path: a reduction or task type chosen for one model still reached the tool after a model switch. Rewrite each stale field to an explicit `undefined`, which does override in a spread. Same class of bug for `model` itself, which was forwarded whenever present without checking it belongs to the selected provider. Every provider's model dropdown shares the `model` id, so switching provider kept the previous provider's model and failed at the route as a mismatch. It now falls back to the provider's default unless the saved model actually belongs to it. Tests assert the merged result rather than the returned object, since the return shape alone cannot distinguish an omitted key from an overridden one — which is exactly why the previous fix looked correct and was not. * fix(embeddings): discount the batch ceiling when the tokenizer is foreign Review round 4. Batching measures with tiktoken, which only has encodings for OpenAI models — every other id falls back to cl100k_base. Gemini's 2048, Cohere's 128k, and Mistral's 8192 were therefore enforced in OpenAI token units, so an input near one of those ceilings could still be rejected upstream or trimmed more than needed. A true fix needs per-provider tokenizers, which the repo does not have: estimateTokenCount is a chars-per-token heuristic, and truncation needs a real encode/decode pair to slice on a token boundary. So the ceiling is discounted for foreign tokenizers rather than trusted exactly. The discount is one-sided on purpose. Overshooting means the provider rejects the whole request; undershooting only trims a text that was already at the limit, so the margin errs toward the second. resolveBatchTokenCeiling is a pure function tested directly, rather than inferred from truncation behavior, so the guarantee holds per model as the catalog grows. * fix(embeddings): keep the batch ceiling exact and warn before truncating Review round 5. Reverts the safety margin from round 4. The two review findings were in direct tension: round 4 flagged that a foreign model's ceiling is measured in tiktoken units, and the margin added to absorb that error reintroduced the round 3 harm — valid content truncated below the provider's declared limit. The margin was the wrong trade. It swapped a loud failure for a silent one: an undercount surfaces as a provider rejection the caller can see and act on, while shortening an embedding's input produces a degraded vector that is indistinguishable from a good one at every layer above it. Silent quality loss in a retrieval index is the worse outcome, and it is also the harder one to ever notice. So the declared ceiling is applied exactly, and truncation is no longer silent: an input above the limit now logs a warning naming the model, the limit, and whether the count was approximate. hasApproximateTokenCount records which models are counted with a foreign tokenizer without being used to shrink anything. The tokenizer imprecision itself remains, and cannot be fixed without per-provider BPE the repo does not have — estimateTokenCount is a chars-per-token heuristic, and truncation needs a real encode/decode pair to slice on a token boundary. * refactor(embeddings): drop dead surface and enforce OpenAI's item cap Audit follow-ups on the multi-provider embeddings work: - Enforce OpenAI's documented 2048-entry `input` array cap in the OpenAI and Azure adapters. Nothing bounded item count on the OpenAI path — batching bounds tokens per request, so a batch of many short inputs could exceed it. - Make the provider item cap single-source. It was declared both on the catalog entry and on the adapter, read through a `??`; the adapter is the wire-protocol owner, so the catalog copy is gone. - Have the knowledge-base view call `getKbEligibleModels()` instead of re-deriving the same `kbEligible` filter inline. - Remove dead surface: the unused `EMBEDDING_TASK_TYPES` constant, `EmbeddingToolDefinition`, `HOSTED_KEY_PROVIDERS`, and the five request-body fields (`workspaceId`, `workflowId`, `executionId`, `userId`, `useHostedCostTracking`) the route never reads. - Trim `@/lib/embeddings` to what callers outside the module use. - Drop the route's manual request-id plumbing; `withRouteHandler` supplies it. - Fix two comments that had drifted onto the wrong declaration. * fix(embeddings): normalize reduced Cohere output; correct OpenAI token ceiling Second validation pass against provider documentation. - Cohere: normalize locally when `output_dimension` reduces below native. Cohere documents the parameter as Matryoshka truncation but never states that it renormalizes, and an unnormalized vector silently skews cosine similarity. `l2Normalize` is idempotent, so this is a no-op if Cohere already returns unit vectors and a correctness fix if it does not. Covered by a test that fails without it. - OpenAI: raise the per-input ceiling from 8191 to the 8192 the API reference documents, so a maximal input is no longer truncated by one token. - Share the OpenAI response type with the Azure adapter instead of declaring an identical copy, mirroring how the mail providers share `_nodemailer`. - Rewrite the Gemini item-cap comment to say the 100-item limit is observed rather than documented, which is what Google's reference actually supports. Docs: add a manual intro to the Embeddings page covering providers, models, inputs, outputs, and comparability rules. The generated Input tables are empty because `createEmbeddingTool` builds params programmatically and the docs generator only reads literals, so the manual section carries that reference. * fix(embeddings): split per-input and per-request token limits; close provider gaps Four gaps found in the validation pass. Gemini token counts were estimated, not measured. `BatchEmbedContentsResponse` carries `usageMetadata.promptTokenCount`; without reading it the client fell back to tiktoken, which has no Gemini encoding and silently used `cl100k_base` — the wrong tokenizer on a count knowledge-base runs bill against. `maxInputTokens` was doing two jobs: the per-input ceiling that decides truncation, and the per-request budget that decides how many inputs share a batch. These are different provider limits, and conflating them meant Cohere packed batches against its 128k per-document ceiling while OpenAI's documented 300,000-token request cap went unenforced. They are now separate fields. Truncation moves out of `batchByTokenLimit` and into `embed`, so it happens once, against the per-input ceiling, and always logs. The request budget is floored at that ceiling — a budget below it would truncate inputs the provider accepts. Batch sizes are unchanged everywhere except Gemini, which rises from 2048 to the 8192 the other providers already used. codestral-embed now offers its documented 3072 maximum. Its API default is 1536, so the offered sizes straddle the default; the catalog invariant relaxes from "native size first" to "native size present", which is what the block relies on. The Mistral API-key field no longer differs from the other three. Sim stocks `MISTRAL_API_KEY` — `mistral_parse` already hides its key field on hosted — so one field with `hideWhenHosted` replaces the conditional pair. Docs: correct the API-key row, which described the old Mistral-only behavior. * refactor(embeddings): derive block options from the catalog; use shared helpers Findings from a four-angle quality review. Reuse: `splitByItemLimit` and `processWithConcurrency` were reimplementations of `chunkArray` (`@sim/utils`) and `mapWithConcurrency` (`@/lib/core/utils/concurrency`), so `lib/embeddings/batching.ts` is gone. That helper's doc forbade a throwing mapper; embedding legitimately wants a failed batch to fail the call, since a partial vector set is not a usable result, so the contract is reworded to cover both intents rather than forked. The block no longer hand-copies the catalog. Its model, task-type, and dimension dropdowns are derived from `EMBEDDING_MODELS`, which deletes roughly 150 lines of literals that had to be kept in step by a drift test. The comment claiming this was impossible was wrong: `generate-docs.ts` only reads `subBlocks` looking for an `id: 'operation'` entry, which this block does not have. Verified by regenerating — `embeddings.mdx` and `integrations.json` come out byte-identical. Single-sourced two maps that were stated twice: BYOK provider ids (which encode the non-obvious gemini -> google mapping) and the per-provider default model. The route previously took its default from `getModelsForProvider(provider)[0]`, which silently depended on catalog key order. Azure's `endpoint` and `apiVersion` are required on their own context type instead of optional on the shared one, so the adapter can no longer be built without them and emit an `undefined/...` URL. Also: contract enums now `satisfies` the catalog unions so they cannot drift, the barrel exports only what callers outside the module use, the redundant `requestedDimensions` field is a parameter, the bare `getEmbeddingModelInfo()` call is a named `assertKbEmbeddingModel`, and the route checks payload size before scanning entries rather than copying the body first. * docs(embeddings): correct comments that drifted from the code A comment pass over the feature found four that no longer matched what they sat on, all introduced by earlier rounds of this work. The contract's `satisfies` note promised that adding a catalog provider could not leave the wire enum stale. It cannot deliver that: `satisfies` proves every listed member is valid, not that the list is exhaustive, so an addition stays silently absent. Reworded to say what it does and does not catch. The client cited Gemini as a provider that omits usage, which the Gemini adapter now contradicts — it reads `usageMetadata.promptTokenCount`. Every adapter defines `parseTokens`, so the fallback is about a response lacking a usage block, not about a particular provider. `l2Normalize` documented only Gemini, though Cohere now calls it for a different and stronger reason, and "normalizes in place" read as mutation when the function returns a copy. The route's new size-guard comment claimed it avoids copying the payload; nothing there copies. The real reason is that summing lengths gates before the per-entry character scan. Also: split the derived-sub-block TSDoc so both constants carry hover text, gave the payload cap its own doc, dropped one comment that restated a signature, and tightened two long blocks without losing a fact. * fix(docs): generate tool inputs for factory-built tools The four embeddings tools rendered header-only Input tables. `extractToolInfo` finds a tool's `params` by regex over the tool's own file, and these files hold nothing but a `createEmbeddingTool({...})` call — the params live in the factory's module. There was already a fallback for a same-file `...spread` base, so this adds the cross-module equivalent: follow the factory's import and read `params` from there. Two things surfaced once the tables populated. `hosting` was not in the set of keys that terminate the `params` capture, so the non-greedy match ran past it to `request:` and swallowed the whole hosting block. Every tool with a `hosting:` section between `params:` and `request:` was publishing `pricing` and `rateLimit` as if they were user-facing inputs — this drops those rows from eight unrelated integration pages as well. The shared apiKey description was a template literal, which the regex emitted verbatim as `${name} API key`. It is now a static string, matching how every other tool in the repo declares one. Docs: the Embeddings page keeps a prose intro in its MANUAL-CONTENT block like other integrations, with the hand-written input/output tables removed now that the generated ones are correct. The sunset `openai` page loses its `encodingFormat` row — page generation skips hidden blocks, so that page is frozen and would otherwise keep advertising a parameter the aliased tool no longer accepts. --------- Co-authored-by: Waleed Latif <walif6@gmail.com>
1 parent 9ba51f9 commit dc5bab6

61 files changed

Lines changed: 3562 additions & 553 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/components/icons.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,36 @@ export function ImageIcon(props: SVGProps<SVGSVGElement>) {
24122412
)
24132413
}
24142414

2415+
export function EmbeddingsIcon(props: SVGProps<SVGSVGElement>) {
2416+
return (
2417+
<svg
2418+
{...props}
2419+
width='26'
2420+
height='26'
2421+
viewBox='0 0 26 26'
2422+
fill='none'
2423+
xmlns='http://www.w3.org/2000/svg'
2424+
stroke='currentColor'
2425+
strokeWidth='2'
2426+
strokeLinecap='round'
2427+
strokeLinejoin='round'
2428+
>
2429+
{/* Rays sit below the nodes in weight, but not so far below that they
2430+
wash out to loose dots at the 14px search-row size. */}
2431+
<path
2432+
d='M13 13L5.5 6.5M13 13L21 7M13 13L6.5 20M13 13L21 19'
2433+
strokeWidth='1.6'
2434+
opacity='0.9'
2435+
/>
2436+
<circle cx='13' cy='13' r='3.1' fill='currentColor' stroke='none' />
2437+
<circle cx='5.5' cy='6.5' r='1.9' fill='currentColor' stroke='none' />
2438+
<circle cx='21' cy='7' r='1.9' fill='currentColor' stroke='none' />
2439+
<circle cx='6.5' cy='20' r='1.9' fill='currentColor' stroke='none' />
2440+
<circle cx='21' cy='19' r='1.9' fill='currentColor' stroke='none' />
2441+
</svg>
2442+
)
2443+
}
2444+
24152445
export function TypeformIcon(props: SVGProps<SVGSVGElement>) {
24162446
return (
24172447
<svg

apps/docs/components/ui/icon-mapping.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import {
6666
ElasticsearchIcon,
6767
ElevenLabsIcon,
6868
EmailBisonIcon,
69+
EmbeddingsIcon,
6970
EnrichmentIcon,
7071
EnrichSoIcon,
7172
EnrowIcon,
@@ -317,6 +318,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
317318
elasticsearch: ElasticsearchIcon,
318319
elevenlabs: ElevenLabsIcon,
319320
emailbison: EmailBisonIcon,
321+
embeddings: EmbeddingsIcon,
320322
enrich: EnrichSoIcon,
321323
enrichment: EnrichmentIcon,
322324
enrow: EnrowIcon,
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
title: Embeddings
3+
description: Generate embeddings
4+
---
5+
6+
import { BlockInfoCard } from "@/components/ui/block-info-card"
7+
8+
<BlockInfoCard
9+
type="embeddings"
10+
color="#7B4DFF"
11+
/>
12+
13+
{/* MANUAL-CONTENT-START:intro */}
14+
An embedding turns a piece of text into a list of numbers that captures its meaning. Two texts that mean similar things get similar numbers, so you can compare meaning directly instead of matching keywords. That is what powers semantic search, grouping related items, and spotting near-duplicates that are worded differently.
15+
16+
The Embeddings block generates those numbers using OpenAI, Google Gemini, Cohere, or Mistral. Pick a provider, pick one of its models, pass in text, and get a vector back — one vector per input, in the order you supplied them. You can embed a single string or a list of strings in one call.
17+
18+
Models differ in what they are good at and what they cost. `text-embedding-3-small` is the cost-efficient general choice, `gemini-embedding-001` gives the highest retrieval quality, `embed-v4.0` handles multilingual content, and `codestral-embed` is tuned for source code. Some models also let you trade vector size against quality, and some accept a task type so the vector is conditioned for how it will be used — the block only offers those controls for the models that actually support them.
19+
20+
Two things worth knowing before you build on it. Vectors are only comparable when they come from the same model at the same size, so changing either means re-embedding everything you intend to compare. And input longer than the model's limit is shortened to fit rather than rejected, with a warning in the run, so chunk long documents yourself when the tail matters.
21+
22+
Sim's knowledge bases embed separately, at a fixed vector width and from a smaller set of models. This block is for embedding text yourself inside a workflow.
23+
{/* MANUAL-CONTENT-END */}
24+
25+
26+
## Usage Instructions
27+
28+
Turn text into embedding vectors for semantic search, clustering, and similarity. Supports OpenAI, Google Gemini, Cohere, and Mistral embedding models.
29+
30+
31+
32+
## Actions
33+
34+
### `embeddings_openai`
35+
36+
Generate embeddings from text using OpenAI's embedding models
37+
38+
#### Input
39+
40+
| Parameter | Type | Required | Description |
41+
| --------- | ---- | -------- | ----------- |
42+
| `input` | string | Yes | Text to embed, or an array of texts to embed in one call |
43+
| `model` | string | No | Embedding model to use |
44+
| `taskType` | string | No | What the embedding is for, when the model supports task conditioning: document, query, similarity, classification, or clustering |
45+
| `dimensions` | number | No | Output dimensions, when the model supports truncation. Defaults to native. |
46+
| `apiKey` | string | Yes | API key for the selected embedding provider |
47+
48+
#### Output
49+
50+
| Parameter | Type | Description |
51+
| --------- | ---- | ----------- |
52+
| `embeddings` | json | Generated embeddings |
53+
| `model` | string | Model used |
54+
| `provider` | string | Provider used |
55+
| `dimensions` | number | Dimensionality of each vector |
56+
| `usage` | json | Token usage |
57+
58+
### `embeddings_gemini`
59+
60+
Generate embeddings from text using Google's Gemini embedding models
61+
62+
#### Input
63+
64+
| Parameter | Type | Required | Description |
65+
| --------- | ---- | -------- | ----------- |
66+
| `input` | string | Yes | Text to embed, or an array of texts to embed in one call |
67+
| `model` | string | No | Embedding model to use |
68+
| `taskType` | string | No | What the embedding is for, when the model supports task conditioning: document, query, similarity, classification, or clustering |
69+
| `dimensions` | number | No | Output dimensions, when the model supports truncation. Defaults to native. |
70+
| `apiKey` | string | Yes | API key for the selected embedding provider |
71+
72+
#### Output
73+
74+
| Parameter | Type | Description |
75+
| --------- | ---- | ----------- |
76+
| `embeddings` | json | Generated embeddings |
77+
| `model` | string | Model used |
78+
| `provider` | string | Provider used |
79+
| `dimensions` | number | Dimensionality of each vector |
80+
| `usage` | json | Token usage |
81+
82+
### `embeddings_cohere`
83+
84+
Generate embeddings from text using Cohere's embedding models
85+
86+
#### Input
87+
88+
| Parameter | Type | Required | Description |
89+
| --------- | ---- | -------- | ----------- |
90+
| `input` | string | Yes | Text to embed, or an array of texts to embed in one call |
91+
| `model` | string | No | Embedding model to use |
92+
| `taskType` | string | No | What the embedding is for, when the model supports task conditioning: document, query, similarity, classification, or clustering |
93+
| `dimensions` | number | No | Output dimensions, when the model supports truncation. Defaults to native. |
94+
| `apiKey` | string | Yes | API key for the selected embedding provider |
95+
96+
#### Output
97+
98+
| Parameter | Type | Description |
99+
| --------- | ---- | ----------- |
100+
| `embeddings` | json | Generated embeddings |
101+
| `model` | string | Model used |
102+
| `provider` | string | Provider used |
103+
| `dimensions` | number | Dimensionality of each vector |
104+
| `usage` | json | Token usage |
105+
106+
### `embeddings_mistral`
107+
108+
Generate embeddings from text using Mistral's embedding models
109+
110+
#### Input
111+
112+
| Parameter | Type | Required | Description |
113+
| --------- | ---- | -------- | ----------- |
114+
| `input` | string | Yes | Text to embed, or an array of texts to embed in one call |
115+
| `model` | string | No | Embedding model to use |
116+
| `taskType` | string | No | What the embedding is for, when the model supports task conditioning: document, query, similarity, classification, or clustering |
117+
| `dimensions` | number | No | Output dimensions, when the model supports truncation. Defaults to native. |
118+
| `apiKey` | string | Yes | API key for the selected embedding provider |
119+
120+
#### Output
121+
122+
| Parameter | Type | Description |
123+
| --------- | ---- | ----------- |
124+
| `embeddings` | json | Generated embeddings |
125+
| `model` | string | Model used |
126+
| `provider` | string | Provider used |
127+
| `dimensions` | number | Dimensionality of each vector |
128+
| `usage` | json | Token usage |
129+
130+

apps/docs/content/docs/en/integrations/exa.mdx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ Search the web using Exa AI. Returns relevant search results with titles, URLs,
7171
| `startCrawlDate` | string | No | Deprecated: use startPublishedDate. Only include results crawled on or after this ISO 8601 date |
7272
| `endCrawlDate` | string | No | Deprecated: use endPublishedDate. Only include results crawled on or before this ISO 8601 date |
7373
| `apiKey` | string | Yes | Exa AI API Key |
74-
| `pricing` | custom | No | No description |
75-
| `rateLimit` | string | No | No description |
7674

7775
#### Output
7876

@@ -120,8 +118,6 @@ Retrieve the contents of webpages using Exa AI. Returns the title, text content,
120118
| `livecrawlTimeout` | number | No | Live crawl timeout in milliseconds \(max 90000\). Default: 10000 |
121119
| `livecrawl` | string | No | Deprecated: use maxAgeHours instead. Live crawling mode: never, fallback, always, or preferred |
122120
| `apiKey` | string | Yes | Exa AI API Key |
123-
| `pricing` | custom | No | No description |
124-
| `rateLimit` | string | No | No description |
125121

126122
#### Output
127123

@@ -162,8 +158,6 @@ Find webpages similar to a given URL using Exa AI. Deprecated by Exa in favor of
162158
| `livecrawlTimeout` | number | No | Live crawl timeout in milliseconds \(max 90000\). Default: 10000 |
163159
| `livecrawl` | string | No | Deprecated: use maxAgeHours instead. Live crawling mode: never, fallback, always, or preferred |
164160
| `apiKey` | string | Yes | Exa AI API Key |
165-
| `pricing` | custom | No | No description |
166-
| `rateLimit` | string | No | No description |
167161

168162
#### Output
169163

@@ -191,8 +185,6 @@ Get an AI-generated answer to a question with citations from the web using Exa A
191185
| `text` | boolean | No | Include the full page text of each cited source \(default: false\). This does not affect the answer itself. |
192186
| `outputSchema` | json | No | JSON Schema describing the answer shape. When supplied, the answer is returned as a structured object instead of a string. |
193187
| `apiKey` | string | Yes | Exa AI API Key |
194-
| `pricing` | custom | No | No description |
195-
| `rateLimit` | string | No | No description |
196188

197189
#### Output
198190

@@ -222,8 +214,6 @@ Run a deep research task with Exa Agent. Handles multi-step list building, enric
222214
| `systemPrompt` | string | No | Additional guidance for how the agent should behave or format its answer |
223215
| `previousRunId` | string | No | ID of a completed agent run to continue from, for follow-up questions |
224216
| `apiKey` | string | Yes | Exa AI API Key |
225-
| `pricing` | custom | No | No description |
226-
| `rateLimit` | string | No | No description |
227217

228218
#### Output
229219

apps/docs/content/docs/en/integrations/google_books.mdx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ Search for books using the Google Books API
4646
| `startIndex` | number | No | Index of the first result to return \(for pagination\) |
4747
| `maxResults` | number | No | Maximum number of results to return \(1-40\) |
4848
| `langRestrict` | string | No | Restrict results to a specific language \(ISO 639-1 code\) |
49-
| `pricing` | per_request | No | No description |
50-
| `rateLimit` | string | No | No description |
5149

5250
#### Output
5351

@@ -84,8 +82,6 @@ Get detailed information about a specific book volume
8482
| `apiKey` | string | Yes | Google Books API key |
8583
| `volumeId` | string | Yes | The ID of the volume to retrieve |
8684
| `projection` | string | No | Projection level \(full, lite\) |
87-
| `pricing` | per_request | No | No description |
88-
| `rateLimit` | string | No | No description |
8985

9086
#### Output
9187

apps/docs/content/docs/en/integrations/google_maps.mdx

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ Get current air quality data for a location
5050
| `lat` | number | Yes | Latitude coordinate |
5151
| `lng` | number | Yes | Longitude coordinate |
5252
| `languageCode` | string | No | Language code for the response \(e.g., "en", "es"\) |
53-
| `pricing` | per_request | No | No description |
54-
| `rateLimit` | string | No | No description |
5553

5654
#### Output
5755

@@ -93,8 +91,6 @@ Get directions and route information between two locations
9391
| `waypoints` | json | No | Array of intermediate waypoints |
9492
| `units` | string | No | Unit system: metric or imperial |
9593
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
96-
| `pricing` | per_request | No | No description |
97-
| `rateLimit` | string | No | No description |
9894

9995
#### Output
10096

@@ -139,8 +135,6 @@ Calculate travel distance and time between multiple origins and destinations
139135
| `avoid` | string | No | Features to avoid: tolls, highways, or ferries |
140136
| `units` | string | No | Unit system: metric or imperial |
141137
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
142-
| `pricing` | custom | No | No description |
143-
| `rateLimit` | string | No | No description |
144138

145139
#### Output
146140

@@ -169,8 +163,6 @@ Get elevation data for a location
169163
| `apiKey` | string | Yes | Google Maps API key |
170164
| `lat` | number | Yes | Latitude coordinate |
171165
| `lng` | number | Yes | Longitude coordinate |
172-
| `pricing` | per_request | No | No description |
173-
| `rateLimit` | string | No | No description |
174166

175167
#### Output
176168

@@ -193,8 +185,6 @@ Convert an address into geographic coordinates (latitude and longitude)
193185
| `address` | string | Yes | The address to geocode |
194186
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
195187
| `region` | string | No | Region bias as a ccTLD code \(e.g., us, uk\) |
196-
| `pricing` | per_request | No | No description |
197-
| `rateLimit` | string | No | No description |
198188

199189
#### Output
200190

@@ -227,8 +217,6 @@ Geolocate a device using WiFi access points, cell towers, or IP address
227217
| `considerIp` | boolean | No | Whether to use IP address for geolocation \(default: true\) |
228218
| `cellTowers` | array | No | Array of cell tower objects with cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode |
229219
| `wifiAccessPoints` | array | No | Array of WiFi access point objects with macAddress \(required\), signalStrength, etc. |
230-
| `pricing` | per_request | No | No description |
231-
| `rateLimit` | string | No | No description |
232220

233221
#### Output
234222

@@ -250,8 +238,6 @@ Get detailed information about a specific place
250238
| `placeId` | string | Yes | Google Place ID |
251239
| `fields` | string | No | Comma-separated list of fields to return |
252240
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
253-
| `pricing` | per_request | No | No description |
254-
| `rateLimit` | string | No | No description |
255241

256242
#### Output
257243

@@ -306,8 +292,6 @@ Search for places of a given type within a radius of a location
306292
| `rankPreference` | string | No | How to rank results: POPULARITY \(default\) or DISTANCE |
307293
| `languageCode` | string | No | Language code for the response \(e.g., en, es\) |
308294
| `regionCode` | string | No | Region bias as a ccTLD code \(e.g., us, uk\) |
309-
| `pricing` | per_request | No | No description |
310-
| `rateLimit` | string | No | No description |
311295

312296
#### Output
313297

@@ -342,8 +326,6 @@ Search for places using a text query
342326
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
343327
| `region` | string | No | Region bias as a ccTLD code \(e.g., us, uk\) |
344328
| `pageToken` | string | No | Token from a previous search response to fetch the next page of results. Wait a couple seconds after receiving the token before using it, or the API returns INVALID_REQUEST |
345-
| `pricing` | per_request | No | No description |
346-
| `rateLimit` | string | No | No description |
347329

348330
#### Output
349331

@@ -378,8 +360,6 @@ Get a daily pollen forecast (grass, tree, weed) for a location
378360
| `days` | number | No | Number of forecast days to return \(1-5, defaults to 1\) |
379361
| `languageCode` | string | No | Language code for the response \(e.g., "en", "es"\) |
380362
| `plantsDescription` | boolean | No | Include detailed plant descriptions \(defaults to true\) |
381-
| `pricing` | per_request | No | No description |
382-
| `rateLimit` | string | No | No description |
383363

384364
#### Output
385365

@@ -413,8 +393,6 @@ Convert geographic coordinates (latitude and longitude) into a human-readable ad
413393
| `lat` | number | Yes | Latitude coordinate |
414394
| `lng` | number | Yes | Longitude coordinate |
415395
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
416-
| `pricing` | per_request | No | No description |
417-
| `rateLimit` | string | No | No description |
418396

419397
#### Output
420398

@@ -439,8 +417,6 @@ Snap GPS coordinates to the nearest road segment
439417
| `apiKey` | string | Yes | Google Maps API key with Roads API enabled |
440418
| `path` | string | Yes | Pipe-separated list of lat,lng coordinates \(e.g., "60.170880,24.942795\|60.170879,24.942796"\) |
441419
| `interpolate` | boolean | No | Whether to interpolate additional points along the road |
442-
| `pricing` | per_request | No | No description |
443-
| `rateLimit` | string | No | No description |
444420

445421
#### Output
446422

@@ -466,8 +442,6 @@ Get solar potential and panel insights for the building nearest a location
466442
| `lat` | number | Yes | Latitude coordinate |
467443
| `lng` | number | Yes | Longitude coordinate |
468444
| `requiredQuality` | string | No | Minimum imagery quality to accept \(HIGH, MEDIUM, or BASE\) |
469-
| `pricing` | per_request | No | No description |
470-
| `rateLimit` | string | No | No description |
471445

472446
#### Output
473447

@@ -525,8 +499,6 @@ Get timezone information for a location
525499
| `lng` | number | Yes | Longitude coordinate |
526500
| `timestamp` | number | No | Unix timestamp to determine DST offset \(defaults to current time\) |
527501
| `language` | string | No | Language code for timezone name \(e.g., en, es, fr\) |
528-
| `pricing` | per_request | No | No description |
529-
| `rateLimit` | string | No | No description |
530502

531503
#### Output
532504

@@ -552,8 +524,6 @@ Validate and standardize a postal address
552524
| `regionCode` | string | No | ISO 3166-1 alpha-2 country code \(e.g., "US", "CA"\) |
553525
| `locality` | string | No | City or locality name |
554526
| `enableUspsCass` | boolean | No | Enable USPS CASS validation for US addresses |
555-
| `pricing` | per_request | No | No description |
556-
| `rateLimit` | string | No | No description |
557527

558528
#### Output
559529

apps/docs/content/docs/en/integrations/google_pagespeed.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ Analyze a webpage for performance, accessibility, SEO, and best practices using
5555
| `category` | string | No | Lighthouse categories to analyze \(comma-separated\): performance, accessibility, best-practices, seo |
5656
| `strategy` | string | No | Analysis strategy: desktop or mobile |
5757
| `locale` | string | No | Locale for results \(e.g., en, fr, de\) |
58-
| `pricing` | per_request | No | No description |
59-
| `rateLimit` | string | No | No description |
6058

6159
#### Output
6260

0 commit comments

Comments
 (0)