Skip to content

Commit 82ee2e6

Browse files
authored
v0.8.19: desktop app upgrade flow improvements, monday.com OAuth fix
2 parents 5fb3c07 + d4542e4 commit 82ee2e6

273 files changed

Lines changed: 32134 additions & 2157 deletions

File tree

Some content is hidden

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

.agents/skills/add-block/SKILL.md

Lines changed: 17 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,9 @@ When the user asks you to create a block:
1515
2. Configure all subBlocks with proper types, conditions, and dependencies
1616
3. Wire up tools correctly
1717

18-
## Hard Rule: No Guessed Tool Outputs
18+
## No guessed tool outputs
1919

20-
Blocks depend on tool outputs. If the underlying tool response schema is not documented or live-verified, you MUST tell the user instead of guessing block outputs.
21-
22-
When block work changes tool execution, same-process work must use a registered
23-
`InternalToolConfig.operation`. Never add a Sim `/api/...` self-hop or the retired
24-
`directExecution` property.
25-
26-
- Do NOT invent block outputs for undocumented tool responses
27-
- Do NOT describe unknown JSON shapes as if they were confirmed
28-
- Do NOT wire fields into the block just because they seem likely to exist
29-
30-
If the tool outputs are not known, do one of these instead:
31-
1. Ask the user for sample tool responses
32-
2. Ask the user for test credentials so the tool responses can be verified
33-
3. Limit the block to operations whose outputs are documented
34-
4. Leave uncertain outputs out and explicitly tell the user what remains unknown
20+
Block outputs mirror tool outputs. When a tool's response schema is neither documented nor live-verified, don't infer field names or JSON shapes — ask the user for sample responses or test credentials, limit the block to operations whose outputs are documented, or leave the uncertain outputs out and say exactly what remains unknown.
3521

3622
## Block Configuration Structure
3723

@@ -323,12 +309,10 @@ When several fields are mutually exclusive alternatives, mark them all `required
323309
"exactly one" at execution — a conditionally-required canonical pair rejects the workflow before the
324310
other paths ever get a chance to supply the value.
325311

326-
**Critical constraints:**
327-
- `canonicalParamId` must NOT match any subblock's `id` in the same block
328-
- A canonical group is **block-wide**, not per-operation: `buildCanonicalIndex` keys groups by
329-
`canonicalParamId` across every subblock, and a group has exactly one `basicId`. Two operations
330-
that each need a file pair need two distinct `canonicalParamId` values.
331-
- All members of a group must share the same `required` status
312+
**Constraints (block-wide):**
313+
- `canonicalParamId` must not equal any subblock `id` in the block.
314+
- One canonical id links exactly one basic/advanced pair for one logical parameter. Groups are keyed by canonical id across every subblock and hold one `basicId`, so two operations that each need a pair need two canonical ids.
315+
- All members of a group share the same `required` status.
332316

333317
### Normalizing File Input in tools.config
334318

@@ -548,12 +532,6 @@ Maps multiple UI fields to a single serialized parameter:
548532
- In advanced mode: `channelId` input value → `params.channel`
549533
- The serializer consolidates based on current mode
550534

551-
**Critical constraints:**
552-
- `canonicalParamId` must NOT match any other subblock's `id` in the same block (causes conflicts)
553-
- A `canonicalParamId` links exactly one basic/advanced pair for a single logical parameter. Do NOT reuse the same `canonicalParamId` for different parameters, even under mutually-exclusive conditions/operations
554-
- ONLY use `canonicalParamId` to link basic/advanced mode alternatives for the same logical parameter
555-
- Do NOT use it for any other purpose
556-
557535
## WandConfig Pattern
558536

559537
Enables AI-assisted field generation.
@@ -581,9 +559,9 @@ Enables AI-assisted field generation.
581559
- `'sql-query'` - SQL statements
582560
- `'timestamp'` - Adds current date/time context
583561

584-
## Tools Configuration
562+
Use `wandConfig` on fields that are hard to fill by hand — timestamps (`generationType: 'timestamp'` injects the current date), comma-separated ID lists, complex query strings. Keep the prompt specific about the return format (e.g. 'Return ONLY the ISO 8601 timestamp string').
585563

586-
**Important:** `tools.config.tool` runs during serialization before variable resolution. Put `Number()` and other type coercions in `tools.config.params` instead, which runs at execution time after variables are resolved.
564+
## Tools Configuration
587565

588566
**Preferred:** Use tool names directly as dropdown option IDs to avoid switch cases:
589567
```typescript
@@ -654,19 +632,12 @@ outputs: {
654632
// Use type: 'json' for complex objects or arrays (NOT type: 'array' with items)
655633
items: { type: 'json', description: 'List of items' },
656634
metadata: { type: 'json', description: 'Response metadata' },
657-
658-
// Nested outputs (for structured data)
659-
user: {
660-
id: { type: 'string', description: 'User ID' },
661-
name: { type: 'string', description: 'User name' },
662-
email: { type: 'string', description: 'User email' },
663-
},
664635
}
665636
```
666637

667638
### Typed JSON Outputs
668639

669-
When using `type: 'json'` and you know the object shape in advance, **describe the inner fields in the description** so downstream blocks know what properties are available. Block outputs have no nested `properties` form — always keep the output flat and put the shape in the `description`:
640+
When using `type: 'json'` and you know the object shape in advance, **describe the inner fields in the description** so downstream blocks know what properties are available. Keep the output flat and put the shape in the `description`:
670641

671642
```typescript
672643
outputs: {
@@ -681,10 +652,6 @@ outputs: {
681652
}
682653
```
683654

684-
Nested object outputs (`plan: { id: { type: 'string' }, ... }`) are a **tool-output** feature only — `OutputFieldDefinition` for blocks does not allow them and they fail TypeScript at build time.
685-
686-
If the output shape is unknown because the underlying tool response is undocumented, you MUST tell the user and stop. Unknown is not the same as variable. Never guess block outputs.
687-
688655
## V2 Block Pattern
689656

690657
When creating V2 blocks (alongside legacy V1):
@@ -727,7 +694,7 @@ export const ServiceV2Block: BlockConfig = {
727694

728695
## Registering Blocks
729696

730-
After creating the block, remind the user to register it in `apps/sim/blocks/registry-maps.ts` (the data maps live here; `registry.ts` holds only the accessor functions). Add the import and an entry to each map alphabetically:
697+
Register the block in `apps/sim/blocks/registry-maps.ts` — add the import and an entry to each map alphabetically:
731698

732699
```typescript
733700
import { ServiceBlock, ServiceBlockMeta } from '@/blocks/blocks/service'
@@ -887,41 +854,6 @@ Optional fields that are rarely used should be set to `mode: 'advanced'` so they
887854
}
888855
```
889856

890-
## WandConfig for Complex Inputs
891-
892-
Use `wandConfig` for fields that are hard to fill out manually, such as timestamps, comma-separated lists, and complex query strings. This gives users an AI-assisted input experience.
893-
894-
```typescript
895-
// Timestamps - use generationType: 'timestamp' to inject current date context
896-
{
897-
id: 'startTime',
898-
title: 'Start Time',
899-
type: 'short-input',
900-
mode: 'advanced',
901-
wandConfig: {
902-
enabled: true,
903-
prompt: 'Generate an ISO 8601 timestamp based on the user description. Return ONLY the timestamp string.',
904-
generationType: 'timestamp',
905-
},
906-
}
907-
908-
// Comma-separated lists - simple prompt without generationType
909-
{
910-
id: 'mediaIds',
911-
title: 'Media IDs',
912-
type: 'short-input',
913-
mode: 'advanced',
914-
wandConfig: {
915-
enabled: true,
916-
prompt: 'Generate a comma-separated list of media IDs. Return ONLY the comma-separated values.',
917-
},
918-
}
919-
```
920-
921-
## Naming Convention
922-
923-
All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MUST use `snake_case` (e.g., `x_create_tweet`, `slack_send_message`). Never use camelCase or PascalCase.
924-
925857
## BlockMeta (Required)
926858

927859
Every block file must export a `{Service}BlockMeta` alongside the block — **minimum 7 templates**. Look at existing examples in `apps/sim/blocks/blocks/` (e.g. `browser_use.ts`, `google_sheets.ts`) for the pattern.
@@ -998,7 +930,7 @@ bun run apps/sim/scripts/check-canvas-sentences.ts --block={service}
998930
Adding a block on its own needs no **tool metadata** regeneration — a block references existing
999931
tool IDs through `tools.access` and does not change any tool's shape.
1000932

1001-
But if the same change also adds, edits **or removes** a tool, run `bun run tool-metadata:generate` and commit the result, or CI fails on stale artifacts. That matters here because a block's `outputs` are authored to match its tools' outputs, and the UI now reads those from the generated metadata rather than the executable registry — an unregenerated tool change makes the block's outputs disagree with what the panel renders. See `.agents/skills/tool-registry-boundary/SKILL.md`.
933+
But if the same change also adds, edits **or removes** a tool, run `bun run tool-metadata:generate` and commit the result, or CI fails on stale artifacts. That matters here because a block's `outputs` are authored to match its tools' outputs, and the UI reads those from the generated metadata, not the executable registry — an unregenerated tool change makes the block's outputs disagree with what the panel renders. See `.agents/skills/tool-registry-boundary/SKILL.md`.
1002934

1003935
A visible integration block does require the generated integration catalog and docs to be refreshed.
1004936
After adding or changing one, run:
@@ -1052,9 +984,9 @@ changes.
1052984

1053985
## Final Validation (Required)
1054986

1055-
After creating the block, you MUST validate it against every tool it references:
987+
Validate the block against every tool in `tools.access`:
1056988

1057-
1. **Read every tool definition** that appears in `tools.access` — do not skip any
989+
1. **Read each tool definition** in `tools.access`
1058990
2. **For each tool, verify the block has correct:**
1059991
- SubBlock inputs that cover all required tool params (with correct `condition` to show for that operation)
1060992
- SubBlock input types that match the tool param types (e.g., dropdown for enums, short-input for strings)
@@ -1063,11 +995,11 @@ After creating the block, you MUST validate it against every tool it references:
1063995
3. **Verify block outputs** cover the key fields returned by all tools
1064996
4. **Verify conditions** — each subBlock should only show for the operations that actually use it
1065997
5. **Verify `{Service}BlockMeta` is exported** with at least 7 templates, each having `icon`, `title`, `prompt`, `modules`, `category`, and `tags`
1066-
6. **If any tool outputs are still unknown**, explicitly tell the user instead of guessing block outputs
998+
6. **List any tool outputs still unknown** rather than guessing block outputs
1067999
7. **Verify the tool execution boundary** — blocks never create or call API routes. Every referenced
10681000
tool must already be either a registered `InternalToolConfig.operation` or an absolute external
1069-
HTTP(S) `ToolConfig.request`. If transport needs to change, use the `add-tools` skill; do not add a
1070-
same-origin `/api/...` hop from the block.
1001+
HTTP(S) `ToolConfig.request`. If transport needs to change, use the `add-tools` skill; never add a
1002+
same-origin `/api/...` hop or a `directExecution` property from the block.
10711003

10721004
## Option Lists: `selectorKey` or `options`, never a per-block fetcher
10731005

@@ -1103,7 +1035,7 @@ options: (params) => {
11031035
}
11041036
```
11051037

1106-
**Never fetch inside `options`, and never reach into the stores from a block definition.** A fetcher that resolves its credential with `readSubBlockValue(blockId, ...)` only works on the canvas — every surface that is not the editor gets an empty list. `fetchOptions`/`fetchOptionById` were removed for exactly this reason.
1038+
**Never fetch inside `options`, and never reach into the stores from a block definition.** A fetcher that resolves its credential with `readSubBlockValue(blockId, ...)` only works on the canvas — every surface that is not the editor gets an empty list.
11071039

11081040
Two rules the checks enforce:
11091041

.agents/skills/add-column-type/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ argument-hint: <type-name>
88

99
A column type is **one file** in `apps/sim/lib/table/column-types/` plus a registry entry. Everything that varies per type — label, icon, storage cast, coercion, validation, conversion compatibility, formatting, editor, filter operators — lives on that one object, so no consumer needs editing.
1010

11-
This was not always true: adding `currency` originally took ~40 edits across 32 `switch` arms and 26 UI branches, each of which failed **silently** when missed. The registry exists to make that impossible, so the rule is absolute: **if you find yourself adding a `case 'yourtype':` anywhere outside `column-types/`, the registry is missing a field. Add the field instead.**
11+
A `case 'yourtype':` outside `column-types/` fails **silently** when missed (a wrong `jsonbCast` breaks every filter on the column). The registry exists to make that impossible, so the rule is absolute with one documented exception (`import.ts`'s `coerceValue`, see "Traps" below): **if you find yourself adding a `case 'yourtype':` anywhere else outside `column-types/`, the registry is missing a field. Add the field instead.**
1212

1313
## Hard Rule: the compiler tells you what to do
1414

@@ -116,9 +116,9 @@ Prefer set-based SQL. When the transform genuinely needs JS (`currency`'s separa
116116

117117
## Watch out
118118

119-
- **Import cycles.** `column-types/select.ts` imports `select-values.ts`, so `select-values.ts` must **not** import the registry — that closes a cycle and fails at module init. Inside a type's own helper module the string literal is the implementation, not a config leak.
119+
- **Import cycles.** `column-types/select.ts` imports `lib/table/select-values.ts`, so `select-values.ts` must **not** import the registry — that closes a cycle and fails at module init. Inside a type's own helper module the string literal is the implementation, not a config leak.
120120
- **The client-safe boundary.** `registry.ts` and everything it imports must stay free of `@sim/db`, `drizzle-orm`, and `next/server` — the tables grid imports it directly. A React icon is fine (it's a component *reference*, never called server-side). Only `registry.server.ts` may touch drizzle.
121-
- **Don't re-export the registry from `@/lib/table`.** 44 server modules import that barrel; routing this through it pulls `@sim/emcn/icons` into all of them. Deep-import `@/lib/table/column-types`.
121+
- **Don't re-export the registry from `@/lib/table`.** Dozens of server modules import that barrel; routing this through it pulls `@sim/emcn/icons` into all of them. Deep-import `@/lib/table/column-types`.
122122
- **`import.ts`'s `coerceValue` is a SECOND write path and is not opt-in.** Importing into a column of your type always hits it, and its `default` arm silently `String(value)`s — so a missing `case` stores text in a column whose `jsonbCast` is numeric, and then every filter and sort on that column errors in Postgres. Add a `case`, even though the switch compiles without one. (It is deliberately separate from the registry's `coerce`: an import wants an unparseable value to survive as its raw string so the row error can name it.)
123123
- **CSV inference** is an ordered heuristic in `import.ts`, deliberately not registry-driven. A new type is not inferred from a CSV unless you extend `inferColumnType` — usually you should not, since inference cannot supply configuration (an option set, a currency code).
124124

.agents/skills/add-connector/SKILL.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ The assigned mapping (`semantic id → slot`) is stored in `sourceConfig.tagSlot
469469

470470
## `@/connectors/utils` Helpers
471471

472-
Reuse these instead of inlining the same logic (the validator enforces them):
472+
Reuse these instead of inlining the same logic:
473473

474474
- `htmlToPlainText(html)` — strip HTML to plain text before indexing `ExternalDocument.content`. Never index raw HTML.
475475
- `computeContentHash(content)` — stable content hash for change detection.
@@ -538,7 +538,7 @@ If `ExternalDocument.sourceUrl` is set, the sync engine stores it on the documen
538538

539539
If `listDocuments` can ever return **less than the full source set** on a non-incremental sync — a `maxItems`/`maxDocuments`-style cap, or a transient per-item error that drops a still-existing document from the listing — it MUST set `syncContext.listingCapped = true` when that happens.
540540

541-
The sync engine reconciles deletions by comparing the full listing against stored documents: anything not seen is **hard-deleted** (sync-engine.ts, gated on `!syncContext?.listingCapped`). A truncated listing without this flag deletes every real document beyond the cap. This was the single most common bug found when auditing connectors — do not omit it.
541+
The sync engine reconciles deletions by comparing the full listing against stored documents (`shouldReconcileDeletions` in `lib/knowledge/connectors/sync-engine.ts`, gated on `!syncContext?.listingCapped`). Anything not seen is tombstoned on that sync and hard-deleted when the next sync still does not see it — so a truncated listing without this flag eventually removes every real document beyond the cap.
542542

543543
```typescript
544544
if (hitLimit && syncContext) {
@@ -565,7 +565,7 @@ You never need to modify the sync engine when adding a connector.
565565

566566
## Icon
567567

568-
The `icon` field on `ConnectorConfig` is used throughout the UI — in the connector list, the add-connector modal, and as the document icon in the knowledge base table (replacing the generic file type icon for connector-sourced documents). The icon is read from `CONNECTOR_REGISTRY[connectorType].icon` at runtime — no separate icon map to maintain.
568+
The `icon` field on `ConnectorConfig` is used throughout the UI — in the connector list, the add-connector modal, and as the document icon in the knowledge base table (replacing the generic file type icon for connector-sourced documents). The icon is read from `CONNECTOR_META_REGISTRY[connectorType].icon` (the client-safe registry) at runtime — no separate icon map to maintain.
569569

570570
If the service already has an icon in `apps/sim/components/icons.tsx` (from a tool integration), reuse it. Otherwise, ask the user to provide the SVG.
571571

@@ -602,7 +602,8 @@ export const CONNECTOR_META_REGISTRY: ConnectorMetaRegistry = {
602602
- **OAuth + contentDeferred**: `apps/sim/connectors/google-drive/google-drive.ts` — file download with metadata-based hash, `orderBy` for deterministic pagination
603603
- **OAuth + contentDeferred (blocks API)**: `apps/sim/connectors/notion/notion.ts` — complex block content extraction deferred to `getDocument`
604604
- **OAuth + contentDeferred (git)**: `apps/sim/connectors/github/github.ts` — blob SHA hash, tree listing
605-
- **OAuth + inline content**: `apps/sim/connectors/confluence/confluence.ts` — multiple config field types, `mapTags`, label fetching
605+
- **OAuth + inline content**: `apps/sim/connectors/slack/slack.ts` — list API returns message content inline, metadata-derived `contentHash`
606+
- **OAuth + contentDeferred + config fields**: `apps/sim/connectors/confluence/confluence.ts` — multiple config field types, `mapTags`, label fetching
606607
- **API key**: `apps/sim/connectors/fireflies/fireflies.ts` — GraphQL API with Bearer token auth
607608

608609
## Checklist

0 commit comments

Comments
 (0)