Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6f90d89
fix(mcp): stream pinned transport under Bun (providers + self-hosted-…
waleedlatif1 Jul 23, 2026
3796e9d
improvement(access-control): edit group details, filter by status, an…
waleedlatif1 Jul 23, 2026
96c67e9
feat(sandbox): add Daytona as a manual-flip failover for E2B (#5860)
TheodoreSpeaks Jul 23, 2026
79c57bf
improvement(content): surface last-verified and updated dates, codify…
waleedlatif1 Jul 23, 2026
dbbfce8
fix(landing): restore single-paragraph hero copy on home and enterpri…
waleedlatif1 Jul 24, 2026
877dc9e
fix(landing): lead enterprise summary with Sim so product schema name…
waleedlatif1 Jul 24, 2026
1ffd4f0
improvement(landing): close remaining SEO keyword gaps on home and en…
waleedlatif1 Jul 24, 2026
ca2ea00
improvement(library): add citations and internal links, correct stale…
waleedlatif1 Jul 24, 2026
d48722a
fix(helm): correct chart docs, examples, and dead config across the b…
waleedlatif1 Jul 24, 2026
03adc8f
fix(chat): rotate fork chat split icon 90 degrees (#5914)
j15z Jul 24, 2026
d24bc7e
feat(agent-stream): thinking and tool streaming (#5671)
BillLeoutsakosvl346 Jul 24, 2026
6dcc65b
feat(skills): add skill editors (#5705)
icecrasher321 Jul 24, 2026
bee4562
refactor(skills): one definition of the skill fields across every sur…
waleedlatif1 Jul 24, 2026
7120cdc
fix(providers): final regenerated stream must not re-call tools (empt…
icecrasher321 Jul 24, 2026
e6eef4a
feat(library): What Is an MCP Server? (#5919)
icecrasher321 Jul 24, 2026
444c415
improvement(data-retention): docs for overrides + PII redaction, fix …
TheodoreSpeaks Jul 24, 2026
513292f
feat(sso): DNS domain verification gating org SSO registration (#5909)
waleedlatif1 Jul 24, 2026
70313cd
feat(providers): add Claude Opus 5 model (#5925)
waleedlatif1 Jul 24, 2026
e83d8b8
content(library): add observability, procurement, and MCP security gu…
waleedlatif1 Jul 24, 2026
6105376
improvement(ship): pre-flight regenerate artifacts + parallel audit s…
waleedlatif1 Jul 24, 2026
5a8d219
fix(sso): surface DNS verification failures and the provider auto-app…
waleedlatif1 Jul 24, 2026
91a9c20
fix(deps): build isolated-vm on install via root trustedDependencies …
waleedlatif1 Jul 24, 2026
f224d02
improvement(library): align enterprise copy with canonical source (#5…
waleedlatif1 Jul 24, 2026
f0f9870
refactor(blocks): rename Sim block to 'Sim Chat' for clarity (#5933)
mzxchandra Jul 24, 2026
90f6708
improvement(helm): hygiene pass — CI gating, strict values schema, ES…
waleedlatif1 Jul 24, 2026
6ec2385
chore(ci): run companion-pr-check on Blacksmith (#5943)
waleedlatif1 Jul 24, 2026
290e52c
fix(ci): build app on 16vcpu runner to stop cold-cache OOM kills (#5944)
waleedlatif1 Jul 24, 2026
17d7779
feat(providers): prompt caching capability + usage-based cache pricin…
icecrasher321 Jul 24, 2026
d64739c
fix(ci): unblock @next/swc, lockfile-keyed node_modules, per-image ru…
waleedlatif1 Jul 24, 2026
fe184d3
improvement(whatsapp): validate + improve integration skill for file …
icecrasher321 Jul 24, 2026
9666533
fix(chat): sweep the text shimmer left-to-right again (#5926)
TheodoreSpeaks Jul 24, 2026
f43b52c
fix(realtime): evict revoked collaborators from live workflow rooms (…
icecrasher321 Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
82 changes: 64 additions & 18 deletions .agents/skills/add-block/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,48 +257,94 @@ When your block accepts file uploads, use the basic/advanced mode pattern with `
},
```

**Keep the pair to one logical thing.** Basic is the file upload, advanced is *only* a reference to
a file from a previous block. Gmail attachments are the reference implementation
(`apps/sim/blocks/blocks/gmail.ts` — `attachmentFiles` / `attachments`).

Do not overload the advanced side with alternate identifiers (a remote URL, a provider asset ID, a
path). A subblock whose meaning changes based on what the string looks like is impossible to reason
about, forces the params function to sniff the value, and makes the field's type meaningless. Give
each alternative its own subblock outside the pair:

```typescript
// ✓ Good — the pair is "a file"; other sources are their own fields
{ id: 'mediaFile', type: 'file-upload', canonicalParamId: 'media', mode: 'basic' },
{ id: 'mediaFileRef', type: 'short-input', canonicalParamId: 'media', mode: 'advanced' },
{ id: 'mediaId', type: 'short-input', mode: 'advanced' }, // separate concept
{ id: 'mediaLink', type: 'short-input', mode: 'advanced' }, // separate concept

// ✗ Bad — one field meaning three things, resolved by guessing
{ id: 'mediaRef', type: 'short-input', canonicalParamId: 'media', mode: 'advanced',
placeholder: 'File reference, media ID, or public URL' },
```

When several fields are mutually exclusive alternatives, mark them all `required: false` and enforce
"exactly one" at execution — a conditionally-required canonical pair rejects the workflow before the
other paths ever get a chance to supply the value.

**Critical constraints:**
- `canonicalParamId` must NOT match any subblock's `id` in the same block
- Values are stored under subblock `id`, not `canonicalParamId`
- A canonical group is **block-wide**, not per-operation: `buildCanonicalIndex` keys groups by
`canonicalParamId` across every subblock, and a group has exactly one `basicId`. Two operations
that each need a file pair need two distinct `canonicalParamId` values.
- All members of a group must share the same `required` status

### Normalizing File Input in tools.config

Use `normalizeFileInput` to handle all input variants:
Put the normalization in `tools.config.params`, never in `tools.config.tool` — `tool` runs at
serialization, before variable resolution, so a `<block.output>` file reference is not yet a value
there.

```typescript
import { normalizeFileInput } from '@/blocks/utils'

tools: {
access: ['service_upload'],
config: {
tool: (params) => {
// Check all field IDs: uploadFile (basic), fileRef (advanced), fileContent (legacy)
const normalizedFile = normalizeFileInput(
params.uploadFile || params.fileRef || params.fileContent,
{ single: true }
)
if (normalizedFile) {
params.file = normalizedFile
tool: (params) => `service_${params.operation}`,
params: (params) => {
// Read the CANONICAL id, not the subblock ids
const { file: fileParam, ...rest } = params
const file = normalizeFileInput(fileParam, { single: true })
return {
...rest,
...(file ? { file } : {}),
}
return `service_${params.operation}`
},
},
}
```

**Why this pattern?**
- Values come through as `params.uploadFile` or `params.fileRef` (the subblock IDs)
- `canonicalParamId` only controls UI/schema mapping, not runtime values
- `normalizeFileInput` handles JSON strings from advanced mode template resolution
**Where the value actually lives at runtime.** The subblock `id` is where the UI *stores* the value,
but it is not what the params function receives. `extractBlockParams`
(`apps/sim/serializer/index.ts`) collapses each canonical group at serialization time:

```typescript
const sourceIds = [group.basicId, ...group.advancedIds].filter(Boolean)
sourceIds.forEach((id) => delete params[id]) // subblock ids are deleted
if (chosen !== undefined) params[group.canonicalId] = chosen
```

So by the time `tools.config.params(inputs)` runs (`executor/handlers/generic/generic-handler.ts`),
`params.uploadFile` and `params.fileRef` are **gone** and the value is under `params.file`. Reading a
subblock id there yields `undefined` and silently sends no file.

Only the active mode's value survives — `getCanonicalValues` returns the basic value in basic mode
and the first non-empty advanced value in advanced mode, so a stale value in the dormant mode can
never leak. `normalizeFileInput` then handles the JSON string that advanced-mode template resolution
produces.

Note that `generic-handler` merges rather than replaces (`{ ...inputs, ...transformedParams }`), so
omitting a key from the returned object does not strip it from what the tool receives. Tools simply
ignore params they do not declare.

### File Input Types in `inputs`

Use `type: 'json'` for file inputs:
Declare the **canonical** id with `type: 'json'` — the subblock ids never reach `inputs`:

```typescript
inputs: {
uploadFile: { type: 'json', description: 'Uploaded file (UserFile)' },
fileRef: { type: 'json', description: 'File reference from previous block' },
file: { type: 'json', description: 'File to upload (UserFile or reference)' },
// Legacy field for backwards compatibility
fileContent: { type: 'string', description: 'Legacy: base64 encoded content' },
}
Expand Down
15 changes: 12 additions & 3 deletions .agents/skills/add-integration/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const {Service}Block: BlockConfig = {
```typescript
// Basic: Visual selector
{
id: 'channel',
id: 'channelSelector',
type: 'channel-selector',
mode: 'basic',
canonicalParamId: 'channel',
Expand All @@ -228,10 +228,19 @@ export const {Service}Block: BlockConfig = {
}
```

Note neither subblock `id` is `channel` — the canonical id is a third name that both members map
onto, and it is the only one that survives serialization.

**Critical Canonical Param Rules:**
- `canonicalParamId` must NOT match any subblock's `id` in the block
- `canonicalParamId` must be unique per operation/condition context
- Only use `canonicalParamId` to link basic/advanced alternatives for the same logical parameter
- `canonicalParamId` must be unique **block-wide**, not per operation. `buildCanonicalIndex` keys
groups by `canonicalParamId` across all subblocks and a group holds exactly one `basicId`, so two
operations that each need their own pair must use two different canonical ids
- Only use `canonicalParamId` to link basic/advanced alternatives for the same logical parameter.
A pair carries ONE concept — for files that means upload (basic) + file reference (advanced), as
in Gmail attachments (`blocks/blocks/gmail.ts`). Never overload the advanced side with alternate
identifiers like a URL or a provider asset ID; give those their own subblocks, mark all the
mutually exclusive sources `required: false`, and enforce "exactly one" at execution
- `mode` only controls UI visibility, NOT serialization. Without `canonicalParamId`, both basic and advanced field values would be sent
- Every subblock `id` must be unique within the block. Duplicate IDs cause conflicts even with different conditions
- **Required consistency:** If one subblock in a canonical group has `required: true`, ALL subblocks in that group must have `required: true` (prevents bypassing validation by switching modes)
Expand Down
12 changes: 12 additions & 0 deletions .agents/skills/add-model/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Use a precise WebFetch prompt: *"Extract for {model_id}: exact model id string,
| `reasoningEffort` | `openai/core.ts`, `azure-openai`, `anthropic/core.ts` (mapped to thinking), `gemini/core.ts` | **Dead on xai, deepseek, mistral, groq, cerebras, openrouter, fireworks, bedrock, vertex** unless their core consumes it — re-grep before assuming |
| `verbosity` | `openai/core.ts`, `azure-openai/index.ts` only | Dead elsewhere |
| `thinking` | `anthropic/core.ts`, `gemini/core.ts` | Dead elsewhere |
| `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** (`agent-stream-docs:check` fails without it); other families fall back to provider defaults |
| `nativeStructuredOutputs` | `anthropic/core.ts`, `fireworks/index.ts`, `openrouter/index.ts` | Dead on openai, xai, google, vertex, bedrock, azure-openai, deepseek, mistral, groq, cerebras |
| `maxOutputTokens` | Read by UI + executor for token estimation | Always meaningful — set if provider documents a cap |
| `computerUse` | `anthropic/core.ts` | Dead elsewhere |
Expand Down Expand Up @@ -146,6 +147,15 @@ If anything matches, run the affected provider tests and update assertions as ne

The Consumption Matrix (Step 2) tells you which capability *flags* are honored by existing provider code. But if the new model needs **net-new** request handling that the provider doesn't implement yet — a new beta header (e.g. Anthropic's `anthropic-beta` structured-outputs header in `anthropic/index.ts`), a new thinking/reasoning encoding, a Responses-API quirk — you must edit `apps/sim/providers/<provider>/core.ts` / `index.ts`. Setting a flag whose behavior isn't implemented is a silent no-op. When you do edit provider code, reuse the shared helpers rather than hand-rolling: streaming responses are assembled via `createStreamingExecution` (`@/providers/streaming-execution`) and tool schemas via `adaptOpenAIChatToolSchema` / `adaptAnthropicToolSchema` (`@/providers/tool-schema-adapter`).

### Thinking/reasoning models: `streamed` visibility + generated docs

If the entry has `capabilities.thinking` or `capabilities.reasoningEffort`, it appears in the autogenerated "Streamed thinking and tool calls" table on the Agent block docs page:

- **Anthropic-family (`anthropic`, `azure-anthropic`) thinking models MUST declare `capabilities.thinking.streamed`** (`'full' | 'summary' | 'none'`). Verify against Anthropic's current thinking-display and streaming docs: visible thinking returned by the API is summarized, including when Sim opts models whose default display is `omitted` into `display: 'summarized'` on agent-events runs, so current Claude thinking models use `'summary'`. Use `'full'` only if future official API docs explicitly guarantee raw thinking deltas. `bun run agent-stream-docs:check` (CI) fails if the field is missing.
- Other families usually omit the field and inherit the provider default in `getThinkingStreamVisibility` (Gemini/OpenAI → summaries; Bedrock/Meta → none; OpenAI-compatible vendors with documented reasoning fields → full deltas). Set it explicitly only when the model deviates from its family.
- After inserting the entry, run `bun run agent-stream-docs:generate` and commit the regenerated `apps/docs/content/docs/en/workflows/blocks/agent.mdx` — CI diffs it.
- Include the `streamed` value (with its source URL) in the verification report when set.

### Wrong family entirely?

- **Embedding or rerank model** → it does NOT go in the `models[]` array. Use `EMBEDDING_MODEL_PRICING` / `RERANK_MODEL_PRICING` in `models.ts` instead.
Expand All @@ -155,6 +165,7 @@ The Consumption Matrix (Step 2) tells you which capability *flags* are honored b

```bash
bun run lint
bun run agent-stream-docs:generate # only when the entry has thinking/reasoningEffort
```

Lint must pass before reporting done. **If lint fails:** read the error, fix the syntax/typing issue in the entry you just wrote (do not delete the entry — it's the work product), re-run lint, and note the fix in a "Lint adjustments" line in the verification report. Never report done with lint failing.
Expand Down Expand Up @@ -201,6 +212,7 @@ Omitting a field is **not the same as verifying it**. Any field you cannot confi
- ❌ Trusting a marketing email (xAI's grok-4.3 email claimed "3 reasoning efforts" but the API rejects `reasoning_effort` — verified by official docs only)
- ❌ Setting `nativeStructuredOutputs: true` on xai/openai/google (dead — only anthropic/fireworks/openrouter consume it)
- ❌ Setting `thinking` on non-Anthropic/non-Gemini providers
- ❌ Adding an Anthropic-family thinking model without `thinking.streamed` (CI `agent-stream-docs:check` fails), or skipping `bun run agent-stream-docs:generate` after adding any thinking/reasoning model
- ❌ Setting `verbosity` on anything other than OpenAI gpt-5.x
- ❌ Copying `pricing.updatedAt` from a sibling instead of using today's date
- ❌ Inventing a `cachedInput` price by dividing input by 4 (varies by provider — find an explicit number)
Expand Down
45 changes: 41 additions & 4 deletions .agents/skills/ship/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,47 @@ When the user runs `/ship`:
5. **Run migration safety** — only if the diff touches `packages/db/migrations/**` or `packages/db/schema.ts`:
- Run `/db-migrate` to review the migration for zero-downtime safety (expand/contract phasing, backward-compatibility with the deployed app version).
- `bun run check:migrations origin/staging` must pass (staging is the PR base). Do not silence a flagged statement with a `-- migration-safe:` annotation unless `/db-migrate` confirmed the old code no longer depends on it; otherwise split the destructive change into a later deploy.
6. **Run pre-ship checks** from the repo root before staging:
- `bun run lint` to fix formatting issues
- `bun run check:api-validation:strict` to catch boundary contract failures before CI
7. **Stage and commit** the changes with the generated message
6. **Run pre-ship checks** from the repo root before staging. This has two phases: first **regenerate** every committed artifact so generated files never drift into a CI failure (this is what catches things like `agent-stream-docs` going stale after a `models.ts` edit), then run the **full audit suite** CI's `Lint and Test` job enforces. Both phases parallelize — but only across commands that write **disjoint** outputs — and a bare `wait` swallows child exit codes, so both phases below explicitly collect each job's status and abort ship if any failed.

**Phase A — regenerate the always-in-repo committed artifacts (parallel), then let step 7 stage whatever changed.** Regenerate only the generators whose inputs live entirely in this repo and that any ordinary code change can drift — `agent-stream-docs:generate` (derives from the provider model registry) and `skills:sync` (derives from `.agents/skills/**`). They write disjoint trees (`apps/docs/…/agent.mdx` vs the `.claude`/`.cursor` command projections), so they parallelize safely, and each is idempotent (a no-op when already in sync):
```bash
rm -f /tmp/ship-gen-results
for g in agent-stream-docs:generate skills:sync; do
( bun run "$g" >"/tmp/ship-gen-${g//:/-}.log" 2>&1; echo "$? $g" >>/tmp/ship-gen-results ) &
done
wait
# any non-zero line is a FAILED generator — read /tmp/ship-gen-<name>.log and fix before shipping;
# a silently-failed generate leaves a stale artifact that Phase B / CI then rejects.
# The `exit 1` makes this block itself exit non-zero on failure, so anything gating on the
# command's status (an agent, or a wrapping script) actually stops — do NOT collapse it to
# `grep … && echo ❌ || echo ✅`, which always exits 0 and silently lets ship continue.
if grep -vE '^0 ' /tmp/ship-gen-results; then echo "❌ generator(s) failed — do not ship"; exit 1; fi
echo "✅ artifacts regenerated"
```
Then `git status --short` to see what regenerated — those files must be staged in step 7 alongside your own changes.

**Do NOT blanket-run the domain generators here.** `mship:generate` (`generate-mship-contracts.ts`) is an **umbrella** that drives all nine mothership contract generators (`mship-contracts`, `billing-protocol-contract`, `mship-tools`, the four `trace-*`, `metrics-contract`, `vfs-snapshot-contract`) and biome-formats `apps/sim/lib/copilot/generated/` — never run it *and* its constituents (they write the same files and corrupt each other in parallel), and never run it on an ordinary ship: it reads an **external** copilot-contract source that isn't checked out in most worktrees, so it hard-fails with `ENOENT` and would abort ship for an unrelated reason. `generate:pi-model-catalog` (under `apps/sim`) likewise regenerates from the installed Pi package, not repo source. Only when **this PR's diff actually touches** a domain generator's input do you regenerate it deliberately and run its matching `:check` (`bun run mship:check` / the individual `*:check`) — with the external source present.

**Phase B — run lint + every audit CI enforces, in parallel, and abort ship if any fails.** `bun run lint` first (it autofixes formatting and mutates files, so don't parallelize it with the read-only audits), then fan the rest out and collect exit codes. This is exactly the read-only audit set from CI's `Lint and Test` job (all in-repo, runnable in any worktree):
```bash
# autofix formatting first (mutating; not parallel-safe with the audits). Gate its exit too —
# a non-zero lint (unfixable errors) must abort before the audits run, not be ignored.
bun run lint || { echo "❌ lint failed — do not ship"; exit 1; }
rm -f /tmp/ship-audit-results
for s in check:boundaries check:api-validation:strict check:utils check:zustand-v5 \
check:react-query check:client-boundary check:bare-icons check:icon-paths \
check:realtime-prune skills:check agent-stream-docs:check; do
( bun run "$s" >"/tmp/ship-audit-${s//:/-}.log" 2>&1; echo "$? $s" >>/tmp/ship-audit-results ) &
done
wait
# any non-zero line is a failing audit — read its /tmp/ship-audit-<name>.log and fix before shipping.
# `exit 1` on failure preserves the original sequential checks' semantics (their non-zero exit is
# what an agent gates on); never use `grep … && echo ❌ || echo ✅` here — it always exits 0.
if grep -vE '^0 ' /tmp/ship-audit-results; then echo "❌ audit(s) failed — do not ship"; exit 1; fi
echo "✅ all audits passed"
```
If Phase A regenerated a file, its matching `:check` in Phase B now passes trivially — that parity is the point. Do not ship with any generator or audit failing; fix the cause (never silence it) and re-run. `check:migrations` and `type-check` are covered by steps 5 and CI respectively and are not repeated here.
7. **Stage and commit** the changes with the generated message — including any files Phase A regenerated in step 6
8. **Push to origin** using the current branch name — `--force-with-lease` if step 2's sync
check did any history rewrite (a clean rebase or a cherry-pick rebuild) on a branch that had
already been pushed once; a plain push would be rejected in exactly the polluted-remote case
Expand Down
1 change: 1 addition & 0 deletions .agents/skills/validate-model/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ For each model, evaluate every row. Statuses: ✓ matches docs, ✗ disagrees,
- [ ] `reasoningEffort.values` — list matches docs; **omitted** for always-reasoning models that reject the parameter (e.g., grok-4.3, where xAI docs explicitly state `reasoning_effort` is not supported). Verify per model — some always-reasoning models (e.g., OpenAI's o-series) DO accept `reasoning_effort` and should keep the flag.
- [ ] `verbosity.values` — only on OpenAI gpt-5.x family; values match docs
- [ ] `thinking.levels` + `thinking.default` — only on Anthropic/Gemini; values match docs
- [ ] `thinking.streamed` — REQUIRED on Anthropic-family thinking models (`'full'` for generations returning full thinking deltas, `'summary'` for omitted-display generations like Opus 4.7+/Sonnet 5/Fable 5 where Sim requests `display: 'summarized'`); verify against the provider's thinking-display docs. After any change, run `bun run agent-stream-docs:generate` so the Agent block docs table stays in sync (CI diffs it)
- [ ] `nativeStructuredOutputs` — only on anthropic/fireworks/openrouter; provider must document Structured Outputs / JSON-mode for this model
- [ ] `toolUsageControl` — provider supports `tool_choice` semantics
- [ ] `computerUse` — provider implements computer-use loop AND model is a computer-use SKU
Expand Down
Loading
Loading