@mindstudio-ai/remy 0.1.263 → 0.1.264

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,7 +30,9 @@ short docs that fit in a prompt.
30
30
  - **Limits apply**: 25 data sources per app, 5,000 documents per source, 10,000 chunks per
31
31
  document, 300 searches/minute. Well clear of normal use — but **source names must be fixed, not
32
32
  computed per user or per request**, since referencing one creates it. Partition inside a source
33
- with a metadata filter instead.
33
+ with document metadata instead: tag at add time
34
+ (`add(bytes, { filename, metadata: { userId } })`), narrow at search time
35
+ (`search(q, { filter: { metadata: { userId } } })`).
34
36
 
35
37
  ## Defining and searching
36
38
 
@@ -51,7 +53,22 @@ beside the answer. Retrieval is approximate; a user who can click through can ju
51
53
  An answer with no citation is an assertion.
52
54
 
53
55
  Created on first use, so searching a source the build hasn't populated returns no results rather than
54
- throwing. `search` options: `topK` (default 5, max 50), `scoreThreshold`, `rerank`, `hybrid`.
56
+ throwing. `search` options: `topK` (default 5, max 50), `scoreThreshold`, `filter`, `mode`,
57
+ `maxPerDocument`, `highlight`, `rerank`, `hybrid`.
58
+
59
+ **Filtering** narrows a search before ranking, and every condition only narrows:
60
+ `filter: { metadata: { department: 'legal', year: [2025, 2026] }, filename, documentIds,
61
+ pages: { min?, max? }, contains: 'all these words', phrase: 'exact adjacent sequence' }`.
62
+ Metadata is tagged at add time (scalars only, ≤16 keys); re-adding the same bytes with different
63
+ metadata updates the tags in place, free. Filters are the right tool for scoping retrieval
64
+ (per-user, per-category); they are NOT a substitute for a `db` query over structured data.
65
+
66
+ **Modes**: `mode: 'hybrid'` (default) fuses semantic and keyword retrieval; `'semantic'` is the
67
+ embedding alone; `'lexical'` is keyword-only with **no query embedding** — cheapest and fastest,
68
+ right when the query is an identifier (an error code, a SKU, a name) rather than a meaning.
69
+ `maxPerDocument: 2` stops one document monopolizing the results when the answer should draw on
70
+ several. `highlight: true` adds `matches` (`{start, end}` offsets into `text`) for rendering
71
+ highlighted excerpts.
55
72
 
56
73
  Search is deterministic for a fixed corpus and configuration, so eval sets and regression checks are
57
74
  meaningful — key them on `(documentId, chunkIndex)` rather than on chunk text.
@@ -69,7 +86,9 @@ set with the CLI, so code and reality can't drift.
69
86
 
70
87
  ```bash
71
88
  mindstudio-prod datasources add --source policies --wait docs/*.pdf
89
+ mindstudio-prod datasources add --source policies --metadata department=legal,year=2026 contract.pdf
72
90
  mindstudio-prod datasources search --source policies "what are the payment terms?" # sanity-check
91
+ mindstudio-prod datasources search --source policies --filter department=legal --mode lexical "ERR-7741X"
73
92
  mindstudio-prod datasources delete --source policies # whole source; --source is required, never defaulted
74
93
  ```
75
94
 
@@ -83,7 +102,11 @@ it needs no guard.
83
102
  Use the SDK's `add()` only when *users* upload documents that must become searchable:
84
103
 
85
104
  ```typescript
86
- await Policies.add(buffer, { filename: 'policy.pdf', contentType: 'application/pdf' });
105
+ await Policies.add(buffer, {
106
+ filename: 'policy.pdf',
107
+ contentType: 'application/pdf',
108
+ metadata: { department: 'legal' }, // filterable at search time
109
+ });
87
110
  const docs = await Policies.documents(); // 'processing' | 'done' | 'error'
88
111
  await Policies.remove(documentId);
89
112
  ```
@@ -30,20 +30,35 @@ everywhere else, and the compiled system prompt must carry them explicitly:
30
30
  - **Spoken-form values.** "Forty-two fifty," not "$42.50". "Two fifteen in the afternoon," not
31
31
  "14:15". Read email addresses and confirmation codes character by character, and read them *back*
32
32
  for confirmation before acting on them — mishearing one digit of a phone number is the classic
33
- voice failure.
33
+ voice failure. Collect one value per turn; two asked together blend when spoken.
34
34
  - **Brevity is a hard rule, not a style preference.** One to two sentences per turn, one question at
35
35
  a time. A paragraph that reads fine in chat is a monologue on a call.
36
+ - **Vary the phrasing.** Repeated openers and acknowledgments sound convincing once and robotic by
37
+ the third turn — give the prompt an explicit variety rule, and treat any sample phrases as
38
+ anchors, never scripts.
36
39
  - **Handle unclear audio explicitly.** Give the prompt a rule for it: respond only to clear audio;
37
- if it's noisy or ambiguous, ask the user to repeat — never guess, and never call a tool on input
38
- the agent isn't sure it heard.
40
+ if it's noisy or ambiguous, ask the user to repeat — never guess, never call a tool on input the
41
+ agent isn't sure it heard, and don't reuse the same clarification line twice in a row.
39
42
  - **Pin the language.** State the response language in the prompt; don't let the model infer it from
40
- an accent.
43
+ an accent. If the app's domain has brand names or terms with non-obvious pronunciations, give
44
+ them a line ("pronounce SQL as 'sequel'").
41
45
 
42
46
  Beyond the mechanics, the persona itself should be *of the ear*: pacing, warmth, how it handles
43
47
  being interrupted, what it says when it needs a second. This is the fun part, same as the agent
44
48
  interface — a distinct character beats a generic assistant, and voice makes character land harder
45
49
  than any other surface.
46
50
 
51
+ ### The shape of `system.md`
52
+
53
+ Structure the compiled prompt as short **labeled sections** — Role & Objective, Personality & Tone,
54
+ Rules, and (when the app has a real call flow) Conversation Flow — with bullets over paragraphs;
55
+ realtime models find and follow sectioned rules far more reliably than prose. Scope rules
56
+ precisely: "confirm before any tool that changes data," not "always confirm everything" — blanket
57
+ `always`/`never` makes the agent rigid and unable to handle reasonable exceptions. And start
58
+ minimal: state the role, the boundaries, and the voice mechanics above, then add rules only for
59
+ behaviors that actually misfire in test calls (the transcripts in the call log are the feedback
60
+ loop) rather than front-loading a policy manual.
61
+
47
62
  ### The latency classes
48
63
 
49
64
  Every tool in the spec declares one of three classes. This is the voice-specific discipline — get it
@@ -83,6 +98,11 @@ about to happen and get a yes. Anything destructive or financial — read the de
83
98
  piece by piece. In voice there is no confirmation dialog to lean on; the conversation *is* the
84
99
  confirmation UI.
85
100
 
101
+ And give failure a script: never speak a raw error. When a lookup misses or a tool fails, read back
102
+ the value it used ("I couldn't find an order ending three-one-two-five — did I get part of that
103
+ wrong?"), offer one retry, then move to an alternate path — in character, without blaming the
104
+ caller.
105
+
86
106
  ### Choosing the model
87
107
 
88
108
  Two shapes, one `model` field:
@@ -210,6 +230,116 @@ app's voice ("Booking your appointment…"), never raw names or JSON.
210
230
  - Rendering user-side captions as authoritative ("you said X") — they're recognition output.
211
231
  - Auto-starting a session on page load. Microphone access is always a deliberate user action.
212
232
 
233
+ ## Outbound calls (`voice.call`)
234
+
235
+ The agent can call the user. Backend methods (and crons) place outbound phone calls with the
236
+ agent SDK's `voice` namespace — the platform dials the number and connects the callee to this
237
+ app's voice agent (same persona, engine, and tools as the web sessions):
238
+
239
+ ```ts
240
+ import { voice, auth } from '@mindstudio-ai/agent';
241
+
242
+ export async function callMeAboutMyOrder(input: { phone: string }) {
243
+ auth.requireRole('member');
244
+ const call = await voice.call({ to: input.phone, assumeIdentity: true });
245
+ return { calling: call.to, from: call.from };
246
+ }
247
+ ```
248
+
249
+ - **The method is the authorization gate.** The voice interface's `auth` block does not apply to
250
+ calls the backend places deliberately — gate the *method* with `auth.requireRole(...)` exactly
251
+ as you would any sensitive action.
252
+ - **`assumeIdentity: true`** runs the call as the user who invoked the method: the agent knows
253
+ who it's talking to (Current User block) and every tool call carries their roles — regardless
254
+ of which number was dialed (the user types any number into a field; identity comes from their
255
+ session, not the phone). Omitted/false → anonymous call; role-gated tools decline.
256
+ System/cron invocations have no human identity and always run anonymously.
257
+ - **Production needs a dedicated phone number.** The app owner attaches one ($2/month) via the
258
+ dashboard or `mindstudio-prod voice numbers` (see "Managing the phone side from the CLI"
259
+ below) — it becomes the caller ID for every call, in dev sessions too, so users always see
260
+ the same number. Without one, deployed calls throw `phone_out_requires_dedicated_number`, and
261
+ dev sessions fall back to a shared platform test number that varies per call (tighter limits
262
+ apply on the shared pool).
263
+ - **Outcome is on the call record**, not the return value: `voice.call` returns as soon as
264
+ dialing starts (`{ sessionId, status: 'dialing', from, to }`); answered/busy/no-answer land on
265
+ the session in the app's call log (`voice.listSessions()` / the dashboard).
266
+ - **Limits**: the app's concurrent-session policy, a daily outbound-call cap, a per-call
267
+ duration ceiling, and one active call per callee number (`voice_callee_busy`).
268
+ - **Compliance**: automated calls require prior consent. Call your own users who opted in to
269
+ calls from this app, honor reasonable calling hours, never dial purchased or cold lists —
270
+ design the consent moment into the product (a "call me" button IS consent; a scraped list is
271
+ not).
272
+
273
+ ## Inbound calls
274
+
275
+ Once the app has a dedicated phone number, people can call it — the same voice agent answers
276
+ (same persona, engine, and tools). Nothing extra to author for the basic case; the number in the
277
+ app's settings is the whole switch.
278
+
279
+ How answering works:
280
+
281
+ - **Inbound always runs the live release.** There is no dev inbound — test the agent over the
282
+ normal WebRTC session in the editor; the phone is the same interface with a different
283
+ transport. An app with no live voice interface (or at its concurrency limit) doesn't answer.
284
+ - **Callers are anonymous until verified.** The `auth` block still applies, but a phone call
285
+ can't show a login page — so the platform answers first, and `requireUser` becomes an
286
+ in-call verification flow. The agent can serve whatever anonymous callers are allowed, and
287
+ offers verification when the caller wants something account-bound.
288
+ - **Verification uses the app's own auth methods** (`sms-code` / `email-code` from the
289
+ manifest), existing accounts only — there is no sign-up over the phone:
290
+ - SMS: a code is texted to the number the caller is calling from, if an account has that
291
+ number on file. No other number is possible by design.
292
+ - Email: the caller says their address; the platform matches it against the app's users
293
+ (transcription-tolerant — no letter-by-letter spelling ceremony) and emails the account's
294
+ stored address a code.
295
+ - The flow never confirms or denies that an account exists — a code is "sent if an account
296
+ matches", always phrased that neutrally. The persona should offer verification naturally
297
+ when it unlocks something, never as a robotic gate.
298
+ - **Verified mid-call, upgraded mid-call**: once the code checks out, the session becomes that
299
+ user's — Current User block, roles on every tool call — without redialing.
300
+
301
+ ### `phone.trustCallerId`
302
+
303
+ For apps whose users are known by phone number, the interface config may opt into treating
304
+ caller ID as identity:
305
+
306
+ ```json
307
+ "phone": { "trustCallerId": true }
308
+ ```
309
+
310
+ A caller whose number exactly matches an app user's phone starts the call already verified —
311
+ no code. This is a real security tradeoff: **caller ID can be spoofed**, so a motivated
312
+ attacker who knows a user's phone number can impersonate them to this agent. Before enabling
313
+ it, you MUST surface that risk to the user and get their explicit confirmation — it's the
314
+ right call for convenience-first, low-stakes apps (a family assistant, a status line), and the
315
+ wrong one wherever the agent's tools can move money, reveal sensitive records, or take
316
+ destructive actions. It lives in the interface config deliberately: enabling it is a code
317
+ change, visible in review and auditable via deploys, not a dashboard toggle.
318
+
319
+ ## Managing the phone side from the CLI
320
+
321
+ The `mindstudio-prod voice` family covers numbers, the call log, and voice policy:
322
+
323
+ ```bash
324
+ mindstudio-prod voice numbers search --area-code 310 # available numbers to offer the user
325
+ mindstudio-prod voice numbers buy +13105551234 # buy + attach ($2/month — see below)
326
+ mindstudio-prod voice numbers release +13105551234 # permanent; no refund, ~15-day quarantine
327
+ mindstudio-prod voice sessions list --limit 10 # call log: web / phone-out / phone-in
328
+ mindstudio-prod voice sessions get <sessionId> # full transcript + cost breakdown
329
+ ```
330
+
331
+ Also `voice numbers list`, `voice settings get`/`set` (concurrency, per-visitor,
332
+ max duration). `--help` for flags.
333
+
334
+ **Never buy a number without the user's explicit confirmation** — it starts a recurring
335
+ $2/month workspace charge. Search first, present the options with the price, and only run
336
+ `numbers buy` after they've picked one and said yes.
337
+
338
+ Transcripts are how you iterate on a voice persona: after the user test-calls the agent, read
339
+ `voice sessions get` for what was actually said — misheard input, interruptions, tools declining
340
+ — and fix the spec from evidence rather than guesses. (Dev-session test calls carry a
341
+ `devSessionId` in the list, so you can tell them from live traffic.)
342
+
213
343
  ---
214
344
 
215
345
  # The wiring
@@ -307,6 +437,8 @@ The top-level key must match the interface type (`voice`):
307
437
  | `greeting` | Optional spoken opener |
308
438
  | `systemPrompt` | Relative path to the compiled system prompt |
309
439
  | `auth` | **Required.** Who may start a session: `{ "requireUser": boolean, "requireRole"?: string[] }`. See the Auth section below |
440
+ | `phone` | Optional telephony options: `{ "trustCallerId"?: boolean }` — see "Inbound calls" above. Only add it after the user has confirmed the spoofing tradeoff |
441
+ | `context` | Optional session context: `{ "method": <method id> }` — auto-fired in the background at session start; see "Session context" below |
310
442
  | `tools` | `{ method, latency, description }` — method `id` from the manifest, a latency class, and a relative path to the tool's markdown |
311
443
  | `webInterfacePath` | Optional. Where the voice layer lives in the web interface, for the editor preview |
312
444
 
@@ -316,6 +448,30 @@ Declare it in `mindstudio.json`:
316
448
  { "type": "voice", "path": "dist/interfaces/voice/interface.json" }
317
449
  ```
318
450
 
451
+ ## Session context (auto-loaded)
452
+
453
+ When the config declares `"context": { "method": "session-context" }`, the platform fires that
454
+ backend method automatically when a session starts — in the background, so the greeting is
455
+ never delayed — and appends its return to the system prompt as a `## Session Context` block.
456
+ Use it for situational state that should color every turn: the caller's open orders, account
457
+ standing, where they left off. Timing: the method runs while the greeting audio plays, so the
458
+ agent has the context by roughly the first exchange and is guaranteed to have it shortly
459
+ after — it is NOT guaranteed for the literal first utterance. On inbound phone calls it
460
+ re-fires after the caller verifies mid-call, so the context recomputes for the now-known user.
461
+
462
+ The method contract:
463
+ - Runs as the session's user (same identity/RBAC as a tool call); anonymous sessions run it
464
+ anonymously — return generic or empty content for them.
465
+ - Return a short markdown **string** (a few lines). Results are capped at 4,000 characters;
466
+ keep it situational context, not documents — deep or on-demand data belongs in tools or
467
+ data sources.
468
+ - It is never a model-visible tool, and failures degrade silently to the generic prompt —
469
+ never make correctness depend on it.
470
+
471
+ Rule of thumb: `context` for always-relevant state the agent should just know; tools for
472
+ anything looked up on demand. Identity itself (name, roles) is already injected via the
473
+ Current User block — don't re-fetch it in the context method.
474
+
319
475
  ## Platform Behavior
320
476
 
321
477
  - Input schemas are derived from each method's contract — never hand-written.
@@ -347,6 +503,8 @@ creation itself:
347
503
  (OR semantics, same as the backend `auth.requireRole(...)`). Omit or leave empty for no role
348
504
  gate. Requires `requireUser: true`. Unknown role ids fail the build.
349
505
  - Denials reject `startSession()` with code `auth_required` (401) or `role_required` (403).
506
+ - On the phone channel there is no login page to bounce to, so `requireUser` becomes
507
+ answer-then-verify — see "Inbound calls" above.
350
508
  - Dev preview is exempt — the builder is never locked out while testing.
351
509
  - Older compiled apps without the block fall back to the manifest's `auth.enabled` (auth-enabled →
352
510
  users only; no auth → public). New configs always declare it explicitly.
@@ -81,6 +81,6 @@ You have access to the `mindstudio` CLI, which exposes every SDK action as a com
81
81
  ### Production App Management
82
82
  You have access to `mindstudio-prod`, a CLI for managing the user's production app. Use it via your bash tool. All output is JSON. Run `mindstudio-prod --help` or `mindstudio-prod <command> --help` to discover usage and available options.
83
83
 
84
- Available commands: `requests` (server-side request logs, error rates, latency), `crashes` (frontend browser errors — grouped issues + drill-down to individual events), `analytics` (traffic, top pages/referrers/geo, AI-referral attribution, live counters), `releases` (deploy status, history), `domains` (custom subdomains and fully custom domains), `users` (list, set roles), `db` (query production sql db), `data` (live db operations like lift-from-dev), `methods` (list, invoke), `secrets` (list, get, set, delete), `issues` (reference and manage externally-reported bugs and issues. Do not use this to track work you are doing with the user - only read from it and resolve issues if the user asks for help fixing a bug from the issues tracker).
84
+ Available commands: `requests` (server-side request logs, error rates, latency), `crashes` (frontend browser errors — grouped issues + drill-down to individual events), `analytics` (traffic, top pages/referrers/geo, AI-referral attribution, live counters), `releases` (deploy status, history), `diagnostics` (post-deploy Lighthouse audit), `domains` (custom subdomains and fully custom domains), `users` (list, set roles), `db` (query production sql db), `data` (live db operations like lift-from-dev), `methods` (list, invoke), `secrets` (list, get, set, delete), `files` (upload + manage CDN files), `datasources` (build and query document corpora), `prerender` (bot/crawler snapshots), `voice` (dedicated phone numbers: search/buy/release — buying bills $2/month, so never buy without the user's explicit confirmation; call log + transcripts; voice policy settings), `issues` (reference and manage externally-reported bugs and issues. Do not use this to track work you are doing with the user - only read from it and resolve issues if the user asks for help fixing a bug from the issues tracker).
85
85
 
86
86
  Use when the user asks about production behavior (server errors via `requests`, browser crashes via `crashes`, traffic/engagement via `analytics`), wants to manage their live app (domains, users, roles), needs to seed or query production data, or wants to check release status.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.263",
3
+ "version": "0.1.264",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",