You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit fb08094
Browse filesBrowse the repository at this point in the historyBrowse files
docs(agents): align agent guidance with code and enforced checks (#8887)
* docs(agents): align agent guidance with code and enforced checks
- contracts: export the contract; export a schema or type only when imported
- testing: mock-assertion ban matches test-audit; .dom.test convention; runner commands
- imports: biome organizeImports owns order
- stores: devtools for new stores; reset() + registerUserDataReset
- add apps/sim/CLAUDE.md and (landing)/AGENTS.md symlinks; name db-migrate skill
- skills: safeUrlPathSegment for path segments, hmacSha256Hex and bounded reads in
trigger templates, hosted-key per_request/enabledWhen, stale identifiers fixed,
pressure markers removed
- CONTRIBUTING: commit types and format match history
* docs(add-model): keep the check:/generate: script names from staging
* docs(emcn-design-review): list only the Chip variants its props accept
Copy file name to clipboardExpand all lines: .agents/skills/add-column-type/SKILL.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -98,7 +98,7 @@ The three that are easy to get wrong:
98
98
99
99
Add the entry to `COLUMN_TYPE_REGISTRY` in `registry.ts`**and**`COLUMN_TYPE_SERVER_REGISTRY` in `registry.server.ts`.
100
100
101
-
`COLUMN_TYPES` is declared in `types.ts` (not derived from the registry — the registry is annotated `Record<ColumnType, …>` against it, which is the gate). `constants.ts` re-exports it, so `columnTypeSchema = z.enum(COLUMN_TYPES)` picks your type up with no edit. **Type-specific metadata does not** — see the next step.
101
+
`COLUMN_TYPES` is declared in `types.ts` (not derived from the registry — the registry is annotated `Record<ColumnType, …>` against it, which is the gate). `columnTypeSchema` in `lib/api/contracts/tables.ts` is `z.enum(COLUMN_TYPES)`, so it picks your type up with no edit. **Type-specific metadata does not** — see the next step.
102
102
103
103
## Step 5: Migrations (only if the stored bytes change)
104
104
@@ -131,6 +131,7 @@ Registering the *type* is compiler-enforced. Registering its *metadata* is not,
131
131
|`lib/table/types.ts``ColumnDefinition`| (this one DOES fail — the ownership loop indexes it) |
132
132
|`column-types/types.ts``TYPE_SPECIFIC_COLUMN_KEYS`| it is never stripped on conversion, and poisons the target type |
133
133
|`lib/api/contracts/tables.ts` — the schema slot in all three column schemas, plus `refineColumnOptions`| zod strips it at the boundary; silently never saved |
134
+
|`lib/api/contracts/v2/tables.ts` and `lib/table/application/columns.ts` — the same slots for the v2 API and its use cases | the v2 API silently drops it |
134
135
|`columns/service.ts``addTableColumn` param type | callers cannot pass it |
135
136
| A metadata-only update in `lib/table/columns/service.ts` (`updateColumnCurrency` is the model) + a branch in `performUpdateTableColumn` in `lib/table/orchestration/columns.ts`| changing it on an existing column is a silent 200 no-op |
Copy file name to clipboardExpand all lines: .agents/skills/add-enrichment/SKILL.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,7 +37,7 @@ For each output the enrichment produces, decide which existing tool provides it.
37
37
- Its `params` accept what you can derive from table columns (read the tool's `params`).
38
38
- Its `outputs` / `transformResponse` actually expose the field you need (read the real output shape — don't assume).
39
39
40
-
Order providers **cheapest / most-likely-to-hit first**; the cascade stops at the first non-empty result. Apollo / LinkedIn are not hosted-safe (ToS) — don't use them.
40
+
Order providers **cheapest / most-likely-to-hit first**; the cascade stops at the first non-empty result. Apollo and LinkedIn APIs are not hosted-safe (ToS) — never call them as providers.
41
41
42
42
## Step 2: Verify hosted-key support — chain to `/add-hosted-key` if missing
43
43
@@ -109,7 +109,7 @@ export { myEnrichment } from './my-enrichment'
109
109
```
110
110
111
111
Rules:
112
-
- Keep the file **client-safe**: import only `@sim/emcn/icons`, `@sim/utils/*`, `@/enrichments/providers`, and the types. **Never import `@/tools`** here — the runner does the tool call.
112
+
- Keep the file **client-safe**: import only `@sim/emcn/icons`, `@sim/utils/*`, `@/enrichments/providers`, `@/enrichments/provider-failures/*`, and the types. **Never import `@/tools`** here — the runner does the tool call.
113
113
-`buildParams` returns `null` when inputs are insufficient (provider skipped). `mapOutput` returns `null`/empty for a miss (falls through). Use `filterUndefined` when assembling optional tool params; coerce numbers explicitly (don't pass `''` to number outputs).
114
114
- Output `id`s are the keys `mapOutput` returns; output `name`s are the default column names (the user can rename them in the config).
Copy file name to clipboardExpand all lines: .agents/skills/add-hosted-key/SKILL.md
+14Lines changed: 14 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -154,6 +154,20 @@ pricing: {
154
154
155
155
**`getCost` must always throw** if it cannot determine cost. Never silently fall back to a default — this would hide billing inaccuracies.
156
156
157
+
**When the provider charges a flat price per call** — use `per_request` instead of `getCost` (as `tools/brandfetch/get_brand.ts` does):
158
+
159
+
```typescript
160
+
pricing: {
161
+
type: 'per_request',
162
+
// $0.04 per call — from https://example.com/pricing
163
+
cost: 0.04,
164
+
},
165
+
```
166
+
167
+
### Hosted Keys for Some Parameter Combinations
168
+
169
+
When only some calls can use the hosted key (for example, one provider of several), gate the config with `enabled: hostedKeyEnabledWhen<Params>({ field: 'provider', operator: 'equals', value: 'falai' })` from `@/tools/hosting` (`operator: 'one_of'` takes `values`); `tools/image/generate.ts` is the reference.
170
+
157
171
### Capturing Cost Data from the API
158
172
159
173
If the API returns cost info, capture it in `transformResponse` so `getCost` can read it from the output:
Copy file name to clipboardExpand all lines: .agents/skills/add-model/SKILL.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,13 +49,13 @@ Use a precise WebFetch prompt: *"Extract for {model_id}: exact model id string,
49
49
|---|---|---|
50
50
|`temperature`| All providers (passed through if set) | Safe but inert on always-reasoning models that reject it |
51
51
|`toolUsageControl`| All providers (provider-level default) | Override per model only when that model differs |
52
-
|`forcedToolUse`|`anthropic/core.ts` (anthropic, azure-anthropic, kie); defaults to `toolUsageControl`| Ignored by every other provider; set `false` only on a model behind that core that cannot force tools |
52
+
|`forcedToolUse`|`anthropic/core.ts` (anthropic, azure-anthropic, kie) defaults it to `toolUsageControl`and reads `thinking.forcedToolUse` for forcing while thinking; `openai/core.ts` and `bedrock/index.ts` treat only an explicit `false` as "cannot force" | Ignored by every other provider; set `false` only on a model that cannot force tools |
53
53
|`promptCaching`| Caller-placed cache breakpoints | Set only where the vendor charges for opt-in caching (absent for OpenAI/Gemini implicit caching) |
54
54
|`reasoningEffort`|`openai/core.ts`, `azure-openai`, `xai`, `deepseek`, `groq`, `zai`, `kimi`, `cerebras`, `meta`, `litellm` (each `index.ts`) | Not read by anthropic/gemini (they use `thinking`) or by mistral, openrouter, fireworks, vertex — re-grep before assuming |
55
55
|`verbosity`|`openai/core.ts`, `azure-openai/index.ts` only | Dead elsewhere |
56
56
|`thinking`|`anthropic/core.ts`, `gemini/core.ts`; `deepseek`, `groq`, `zai`, `kimi` (each `index.ts`) read the resolved `thinkingLevel`| Dead elsewhere |
57
57
|`thinking.streamed`| Docs generator + `getThinkingStreamVisibility` (`models.ts`); `anthropic/core.ts` uses `'summary'` to request `display: 'summarized'` on agent-events runs |**Mandatory on Anthropic-family thinking models** (`check:agent-stream-docs` fails without it); other families fall back to provider defaults |
58
-
|`nativeStructuredOutputs`|`anthropic/core.ts`, `bedrock/index.ts` (via `models.ts``supportsNativeStructuredOutputs`, which reads the flag) | Dead elsewhere — fireworks/baseten/together/openrouter call their own provider-level `supportsNativeStructuredOutputs` that ignores the model flag (always on, always off, or OpenRouter API metadata) |
58
+
|`nativeStructuredOutputs`|`anthropic/core.ts`, `bedrock/index.ts` (via `models.ts``supportsNativeStructuredOutputs`, which reads the flag), `nebius/index.ts`, `nvidia/index.ts` (via `getModelCapabilities`)| Dead elsewhere — fireworks/baseten/together/openrouter call their own provider-level `supportsNativeStructuredOutputs` that ignores the model flag (always on, always off, or OpenRouter API metadata) |
59
59
|`maxOutputTokens`| Read by UI + executor for token estimation | Always meaningful — set if provider documents a cap |
60
60
|`computerUse`|`providers/utils.ts` (`getComputerUseModels` → `computerUseModels` routing) | Set only on actual computer-use SKUs |
61
61
|`deepResearch`| UI flag for routing to deep-research SKUs | Set only on actual deep-research model IDs |
@@ -190,7 +188,7 @@ fallback, or caller-controlled `_context` authority.
190
188
191
189
A required `'hidden'` param needs an `oauth` declaration or `hosting.apiKeyParam` to supply it (`bun run check:tool-param-reachability`).
192
190
193
-
A declared `timeout` param is an ordinary tool input — put it in the request body or URL yourself if the provider expects it; it becomes Sim's millisecond request deadline only when the tool sets `timeoutParamIsDeadline: true` (`http_request`). A `method` param on a tool with a fixed `request.method` would be sent as the HTTP verb, so the same audit rejects it.
191
+
A declared `timeout` param is an ordinary tool input — put it in the request body or URL yourself if the provider expects it; it becomes Sim's millisecond request deadline only when the tool sets `timeoutParamIsDeadline: true` (e.g. `http_request`). A `method` param on a tool with a fixed `request.method` would be sent as the HTTP verb, so the same audit rejects it.
194
192
195
193
### Parameter Types
196
194
-`'string'` - Text values
@@ -362,7 +360,7 @@ Only use bare `type: 'json'` without `properties` when the shape is truly dynami
362
360
## Critical Rules for transformResponse
363
361
364
362
### Handle Nullable Fields
365
-
ALWAYS use`?? null` for fields that may be undefined:
363
+
Use`?? null` for fields that may be undefined:
366
364
```typescript
367
365
transformResponse: async (response:Response) => {
368
366
const data =awaitresponse.json()
@@ -465,7 +463,7 @@ these are regenerated — and CI fails on stale artifacts. Commit the result. Se
465
463
466
464
## Wiring Tools into the Block (Required)
467
465
468
-
After registering in `tools/registry.ts`, you MUST also update the block definition at `apps/sim/blocks/blocks/{service}.ts`. This is not optional — tools are only usable from the UI if they are wired into the block.
466
+
After registering in `tools/registry.ts`, also update the block definition at `apps/sim/blocks/blocks/{service}.ts`: a tool is usable from the UI only once the block wires it.
@@ -299,6 +298,7 @@ If they differ: the tag dropdown shows fields that don't exist, or actual data h
299
298
If the service API supports programmatic webhook creation, implement `createSubscription` and `deleteSubscription` on the handler. The orchestration layer calls these automatically — **no code touches `route.ts`, `provider-subscriptions.ts`, or `deploy.ts`**.
Copy file name to clipboardExpand all lines: .agents/skills/council/SKILL.md
+1-8Lines changed: 1 addition & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,13 +2,6 @@
2
2
name: council
3
3
description: Spawn parallel task agents to explore a given area of the codebase from multiple angles, then use their findings to answer the question or build a plan. Use when a task needs broad fan-out exploration across many files before acting.
4
4
argument-hint: <area-of-interest>
5
-
# No agents/openai.yaml by design: council is a meta/exploration utility (like cleanup, ship, you-might-not-need-*), not a service-integration builder, so it intentionally ships no standalone agent card.
6
5
---
7
6
8
-
Based on the given area of interest, please:
9
-
10
-
1. Dig around the codebase in terms of that given area of interest, gather general information such as keywords and architecture overview.
11
-
2. Spawn off n=10 (unless specified otherwise) task agents to dig deeper into the codebase in terms of that given area of interest, some of them should be out of the box for variance.
12
-
3. Once the task agents are done, use the information to do what the user wants.
13
-
14
-
If user is in plan mode, use the information to create the plan.
7
+
Map the area of interest first (keywords, architecture), then fan out parallel agents, each exploring a distinct angle, including a few unconventional ones. Size the fan-out to the area (the user may name a number). Use their findings to answer the question, or to write the plan in plan mode.
Copy file name to clipboardExpand all lines: .agents/skills/db-migrate/SKILL.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,7 +33,7 @@ Never put expand and contract in the same PR. If this PR both removes the code t
33
33
| Drop a column/table | stop all reads/writes in code; ship it |`DROP` (annotate) |
34
34
| Change a column type | add a new column of the new type; dual-write | backfill, swap reads, drop old |
35
35
| Add FK / CHECK |`ADD CONSTRAINT ... NOT VALID`|`VALIDATE CONSTRAINT` separately |
36
-
| Index an existing table |`COMMIT;` breakpoint → `SET lock_timeout = 0` → `CREATE INDEX CONCURRENTLY IF NOT EXISTS` (see `packages/db/scripts/migrate.ts`) | — |
36
+
| Index an existing table |`COMMIT;` breakpoint → `SET lock_timeout = 0` → `CREATE INDEX CONCURRENTLY IF NOT EXISTS`→ `SET lock_timeout = '5s'`(see `packages/db/scripts/migrate.ts`) | — |
37
37
| Drop an index |`COMMIT;` breakpoint → `DROP INDEX CONCURRENTLY IF EXISTS` — plain `DROP INDEX` takes ACCESS EXCLUSIVE on the table | — |
0 commit comments