Skip to content

Commit 86a8553

Browse files
Merge remote-tracking branch 'origin/staging' into feat/remove-chat-ui
# Conflicts: # apps/sim/app/workspace/[workspaceId]/upgrade/upgrade.tsx # apps/sim/app/workspace/page.tsx
2 parents c3849ee + c0e7ea9 commit 86a8553

155 files changed

Lines changed: 7145 additions & 1491 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.

.claude/rules/sim-sandbox.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ about what must **never** live in that process.
2222
secrets, or any LLM / email / search provider API keys. If you catch yourself
2323
`require`'ing `@/lib/auth`, `@sim/db`, `@/lib/uploads/core/storage-service`,
2424
or anything that imports `env` directly inside the worker, stop and use a
25-
host-side broker instead.
25+
host-side broker instead. This includes the OS environment: the worker is
26+
spawned with the explicit allowlisted env from `buildWorkerEnv()` in
27+
`isolated-vm.ts` — never spawn it without an `env` option (Node would copy
28+
the app's full `process.env`, secrets included, into the worker).
2629

2730
2. **Host-side brokers own all credentialed work**. The worker can only access
2831
resources through `ivm.Reference` / `ivm.Callback` bridges back to the host
@@ -69,6 +72,10 @@ payload or `ivm.Reference` wrapper in the worker:
6972
- [ ] Did you update the broker limits (`IVM_MAX_BROKER_ARGS_JSON_CHARS`,
7073
`IVM_MAX_BROKER_RESULT_JSON_CHARS`, `IVM_MAX_BROKERS_PER_EXECUTION`) if
7174
the new broker can emit large payloads or fire frequently?
75+
- [ ] Does the worker read a new env var? Add it to the `buildWorkerEnv()`
76+
allowlist in `isolated-vm.ts` **and** to the allowlist regression test in
77+
`isolated-vm.test.ts` — the worker does not inherit the app environment,
78+
so an un-allowlisted var is simply absent in the child.
7279

7380
## What the worker *may* hold
7481

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ jobs:
252252
echo "ERROR: DEV_TRIGGER_ACCESS_TOKEN and TRIGGER_PROJECT_ID repo secrets must both be set" >&2
253253
exit 1
254254
fi
255-
bunx trigger.dev@4.4.3 deploy --env preview --branch dev-sim
255+
bunx trigger.dev@4.5.7 deploy --env preview --branch dev-sim
256256
257257
# Main/staging: build AMD64 images and push sha-tagged images to ECR + GHCR.
258258
# Runs in parallel with tests — only immutable sha tags are pushed here, and

.github/workflows/test-build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Setup Node
2626
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
2727
with:
28-
node-version: 22
28+
node-version: 24
2929

3030
# Cache keys are scoped by event name, and fork PRs get their own
3131
# namespace on top: untrusted fork runs must never share a cache with
@@ -250,7 +250,7 @@ jobs:
250250
- name: Setup Node
251251
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
252252
with:
253-
node-version: 22
253+
node-version: 24
254254

255255
- name: Mount Bun cache
256256
uses: ./.github/actions/cache-mount

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Search for similar content in a knowledge base using vector similarity
4343
| `query` | string | No | Search query text \(optional when using tag filters\) |
4444
| `topK` | number | No | Number of most similar results to return \(1-100\) |
4545
| `tagFilters` | array | No | Array of tag filters with tagName and tagValue properties |
46+
| `searchMode` | string | No | Retrieval mode: 'vector' \(default\) uses semantic similarity only, 'hybrid' also runs a full-text leg and fuses both |
4647
| `rerankerEnabled` | boolean | No | Whether to apply Cohere reranking to vector search results |
4748
| `rerankerModel` | string | No | Cohere rerank model to use \(one of: rerank-v4.0-pro, rerank-v4.0-fast, rerank-v3.5\) |
4849
| `rerankerInputCount` | number | No | Number of vector results sent to the Cohere reranker \(1–100\). Defaults to topK × 4 capped at 100. |

apps/docs/content/docs/en/knowledgebase/using-in-workflows.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ In our example, adding `Department equals "Billing"` makes the search consider o
3737

3838
Filters run before the vector comparison, so they make a search both more precise and cheaper. See [Tags and filtering](/knowledgebase/tags) for the full operator list by tag type.
3939

40+
## Retrieval Mode
41+
42+
**Retrieval Mode** is an advanced setting that chooses how matches are found.
43+
44+
| Mode | What it does |
45+
| --- | --- |
46+
| Vector only | The default. Ranks purely on meaning, as described above. |
47+
| Hybrid | Also runs a keyword search over the same chunks and blends the two rankings. |
48+
49+
Semantic search is strong on paraphrase and weak on literal strings: an error code, a ticket key like `PROJ-1234`, a SKU, or a rare product name carries little meaning for the model, so the chunk containing it may not rank near the top. Hybrid adds a keyword pass that matches those tokens exactly, then merges the two lists so a chunk found by either signal can surface.
50+
51+
Turn it on when your documents are full of identifiers, codes, or names people search for verbatim. Leave it off for prose-heavy bases where questions are asked in natural language. Hybrid costs no extra API calls — the keyword pass runs entirely in the database.
52+
4053
## Rerank Results
4154

4255
**Rerank Results** is an optional second pass. Vector search ranks by raw similarity; reranking re-scores the top matches with a dedicated relevance model (Cohere's rerank models) and reorders them, which sharpens the ordering when the best answer isn't the literal closest vector.
@@ -95,6 +108,7 @@ When the agent's answer is off, the cause is usually in retrieval, not the agent
95108
- **No results, or wrong documents.** A tag filter may be excluding what you want, or the documents may not be indexed yet. A document is only searchable once its processing status is `completed`; while it is `pending`, `processing`, or `failed`, its chunks won't appear.
96109
- **Low similarity scores across the board.** The query is too vague, or the information simply isn't in the base. Rewrite the query to match how the documents phrase things.
97110
- **Right documents, wrong order.** Turn on Rerank Results, or raise Number of Results so the relevant chunk is included.
111+
- **An exact code, ID, or name isn't found.** Switch Retrieval Mode to Hybrid so a keyword pass runs alongside the semantic one.
98112

99113
See [debugging retrieval](/knowledgebase/debugging-retrieval) for the full diagnostic path, and [chunking strategies](/knowledgebase/chunking-strategies) for how chunk boundaries shape what a search can return.
100114

apps/docs/content/docs/en/platform/self-hosting/object-storage.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ cat > /tmp/cors.json <<'EOF'
245245
"x-goog-meta-purpose",
246246
"x-goog-meta-userid",
247247
"x-goog-meta-workspaceid",
248+
"x-goog-meta-folderid",
248249
"x-goog-meta-workflowid",
249250
"x-goog-meta-executionid"
250251
],

apps/docs/content/docs/en/workflows/blocks/pi.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ The one case neither layer can rescue is a *first* prompt that already exceeds t
211211

212212
### Create PR [#setup-cloud-pr]
213213

214-
Create PR runs in a sandbox image with the Pi CLI and git baked in.
214+
Create PR runs in a sandbox image with the Pi CLI, Git, Node.js, and Bun baked in. Repository dependencies are not preinstalled; Pi can run `bun install` when a repository needs them.
215215

216216
1. **Enable sandbox execution.** On self-hosted Sim, set `E2B_ENABLED=true`, `E2B_API_KEY`, `E2B_PI_TEMPLATE_ID` (the Pi template id), and `NEXT_PUBLIC_E2B_ENABLED=true` (this reveals Create PR, Update PR, and Review Code in the UI). Build the template with `bun run apps/sim/scripts/build-pi-e2b-template.ts`. These modes stay hidden until `NEXT_PUBLIC_E2B_ENABLED` is set.
217217

apps/docs/openapi.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6040,7 +6040,7 @@
60406040
"post": {
60416041
"operationId": "searchKnowledgeBase",
60426042
"summary": "Search Knowledge Base",
6043-
"description": "Perform vector similarity search across one or more knowledge bases. Supports semantic search via query text, tag-based filtering, or a combination of both.",
6043+
"description": "Search across one or more knowledge bases. Supports semantic search via query text, tag-based filtering, or a combination of both. Set `searchMode` to `hybrid` to additionally run a full-text keyword leg and fuse it with the semantic results.",
60446044
"tags": ["Knowledge Bases"],
60456045
"x-codeSamples": [
60466046
{
@@ -6095,14 +6095,21 @@
60956095
"items": {
60966096
"$ref": "#/components/schemas/TagFilter"
60976097
}
6098+
},
6099+
"searchMode": {
6100+
"type": "string",
6101+
"enum": ["vector", "hybrid"],
6102+
"default": "vector",
6103+
"description": "Retrieval strategy. `vector` ranks purely on embedding similarity. `hybrid` also runs a full-text keyword search and fuses the two rankings by reciprocal rank, which retrieves exact tokens — error codes, ticket keys, identifiers, rare product names — that embeddings alone rank poorly. Ignored when only tagFilters are provided."
60986104
}
60996105
}
61006106
},
61016107
"example": {
61026108
"workspaceId": "wsp_abc123",
61036109
"knowledgeBaseIds": ["d2c8f4a6-1b3e-4c5d-9e7f-8a0b2c4d6e1f"],
61046110
"query": "How do I reset my password?",
6105-
"topK": 5
6111+
"topK": 5,
6112+
"searchMode": "hybrid"
61066113
}
61076114
}
61086115
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import type { IncomingMessage, ServerResponse } from 'http'
2+
import { describe, expect, it, vi } from 'vitest'
3+
import type { IRoomManager } from '@/rooms'
4+
import { createHttpHandler } from '@/routes/http'
5+
6+
function createMocks(req: Partial<IncomingMessage>) {
7+
const setHeader = vi.fn()
8+
const writeHead = vi.fn()
9+
const end = vi.fn()
10+
const logger = { info: vi.fn(), error: vi.fn(), debug: vi.fn(), warn: vi.fn() }
11+
const roomManager = {
12+
getTotalActiveConnections: vi.fn().mockResolvedValue(0),
13+
isReady: vi.fn().mockReturnValue(true),
14+
} as unknown as IRoomManager
15+
16+
return {
17+
handler: createHttpHandler(roomManager, logger),
18+
req: { headers: {}, ...req } as IncomingMessage,
19+
res: { setHeader, writeHead, end } as unknown as ServerResponse,
20+
setHeader,
21+
writeHead,
22+
end,
23+
}
24+
}
25+
26+
describe('createHttpHandler', () => {
27+
/**
28+
* `/health` is the only route on this server that returns 200 with a body, so
29+
* it is the only genuinely indexable surface on the `sockets.*` hostnames.
30+
* Node merges `setHeader` values into `writeHead`, and no branch here sets
31+
* `X-Robots-Tag`, so the handler-level call reaches every response.
32+
*/
33+
it.each([
34+
['health check', { method: 'GET', url: '/health' }],
35+
['unmatched route', { method: 'GET', url: '/' }],
36+
['unauthenticated internal API call', { method: 'POST', url: '/api/workflow-deleted' }],
37+
])('marks the %s noindex', async (_label, req) => {
38+
const { handler, req: request, res, setHeader } = createMocks(req)
39+
40+
await handler(request, res)
41+
42+
expect(setHeader).toHaveBeenCalledWith('X-Robots-Tag', 'noindex, nofollow')
43+
})
44+
45+
it('still serves the unmatched-route 404 unchanged', async () => {
46+
const { handler, req, res, writeHead, end } = createMocks({ method: 'GET', url: '/' })
47+
48+
await handler(req, res)
49+
50+
expect(writeHead).toHaveBeenCalledWith(404, { 'Content-Type': 'application/json' })
51+
expect(end).toHaveBeenCalledWith(JSON.stringify({ error: 'Not found' }))
52+
})
53+
54+
it('still serves the health check as 200', async () => {
55+
const { handler, req, res, writeHead } = createMocks({ method: 'GET', url: '/health' })
56+
57+
await handler(req, res)
58+
59+
expect(writeHead).toHaveBeenCalledWith(200, { 'Content-Type': 'application/json' })
60+
})
61+
})

apps/realtime/src/routes/http.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ function sendError(res: ServerResponse, message: string, status = 500): void {
5959
*/
6060
export function createHttpHandler(roomManager: IRoomManager, logger: Logger) {
6161
return async (req: IncomingMessage, res: ServerResponse) => {
62+
res.setHeader('X-Robots-Tag', 'noindex, nofollow')
63+
6264
// Health check doesn't require auth
6365
if (req.method === 'GET' && req.url === '/health') {
6466
try {

0 commit comments

Comments
 (0)