@mindstudio-ai/remy 0.1.279 → 0.1.281

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.
package/dist/headless.js CHANGED
@@ -2897,13 +2897,13 @@ var lspDiagnosticsTool = {
2897
2897
  var restartProcessTool = {
2898
2898
  definition: {
2899
2899
  name: "restartProcess",
2900
- description: "Restart a managed sandbox process. Use this after running npm install or changing package.json to restart the dev server so it picks up new dependencies.",
2900
+ description: 'Restart a managed sandbox process. "devServer": after running npm install or changing package.json in the app frontend, so the dev server picks up new dependencies. "methodsWorker": after upgrading @mindstudio-ai/agent in the methods package \u2014 the long-lived methods worker caches the SDK module and will not pick up the new version otherwise (method source and other dependencies are always fresh; only an SDK upgrade needs this).',
2901
2901
  inputSchema: {
2902
2902
  type: "object",
2903
2903
  properties: {
2904
2904
  name: {
2905
2905
  type: "string",
2906
- description: 'Process name to restart. Currently supported: "devServer".'
2906
+ description: 'Process name to restart: "devServer" or "methodsWorker".'
2907
2907
  }
2908
2908
  },
2909
2909
  required: ["name"]
@@ -2912,7 +2912,9 @@ var restartProcessTool = {
2912
2912
  async execute(input) {
2913
2913
  const data = await lspRequest("/restart-process", { name: input.name });
2914
2914
  if (data.ok) {
2915
- await new Promise((resolve4) => setTimeout(resolve4, 5e3));
2915
+ if (input.name !== "methodsWorker") {
2916
+ await new Promise((resolve4) => setTimeout(resolve4, 5e3));
2917
+ }
2916
2918
  return `Restarted ${input.name}.`;
2917
2919
  }
2918
2920
  return `Error: unexpected response: ${JSON.stringify(data)}`;
package/dist/index.js CHANGED
@@ -4044,13 +4044,13 @@ var init_restartProcess = __esm({
4044
4044
  restartProcessTool = {
4045
4045
  definition: {
4046
4046
  name: "restartProcess",
4047
- description: "Restart a managed sandbox process. Use this after running npm install or changing package.json to restart the dev server so it picks up new dependencies.",
4047
+ description: 'Restart a managed sandbox process. "devServer": after running npm install or changing package.json in the app frontend, so the dev server picks up new dependencies. "methodsWorker": after upgrading @mindstudio-ai/agent in the methods package \u2014 the long-lived methods worker caches the SDK module and will not pick up the new version otherwise (method source and other dependencies are always fresh; only an SDK upgrade needs this).',
4048
4048
  inputSchema: {
4049
4049
  type: "object",
4050
4050
  properties: {
4051
4051
  name: {
4052
4052
  type: "string",
4053
- description: 'Process name to restart. Currently supported: "devServer".'
4053
+ description: 'Process name to restart: "devServer" or "methodsWorker".'
4054
4054
  }
4055
4055
  },
4056
4056
  required: ["name"]
@@ -4059,7 +4059,9 @@ var init_restartProcess = __esm({
4059
4059
  async execute(input) {
4060
4060
  const data = await lspRequest("/restart-process", { name: input.name });
4061
4061
  if (data.ok) {
4062
- await new Promise((resolve4) => setTimeout(resolve4, 5e3));
4062
+ if (input.name !== "methodsWorker") {
4063
+ await new Promise((resolve4) => setTimeout(resolve4, 5e3));
4064
+ }
4063
4065
  return `Restarted ${input.name}.`;
4064
4066
  }
4065
4067
  return `Error: unexpected response: ${JSON.stringify(data)}`;
@@ -44,6 +44,7 @@ All fields are nested under the `"web"` key.
44
44
  | `devCommand` | `string` | `"npm run dev"` | Command to start the dev server |
45
45
  | `defaultPreviewMode` | `"desktop"` \| `"mobile"` | `"desktop"` | Default preview viewport in the editor. Set to `"mobile"` for mobile-first apps. |
46
46
  | `prerender` | `object` | — | Opt into prerendering the listed routes/patterns for crawlers/unfurlers. See "Prerendering" below. |
47
+ | `mounts` | `array` | — | Serve other same-workspace apps under path prefixes of this app's hosts. See "Mounting other apps" below. |
47
48
 
48
49
  ### Frontend SDK
49
50
 
@@ -92,6 +93,16 @@ The project uses `"jsx": "react-jsx"` (automatic JSX transform) — do not `impo
92
93
 
93
94
  On deploy, the platform runs `npm install && npm run build` in the web directory and hosts the output on CDN.
94
95
 
96
+ Two serving conventions: set the bundler's public path from `MS_ASSET_BASE_URL` (platform-set at build, unset locally), and take the router basename from `platform.basePath` — don't hardcode root-absolute URLs in app code.
97
+
98
+ ```ts
99
+ // vite.config.ts
100
+ base: process.env.MS_ASSET_BASE_URL || '/',
101
+
102
+ // router
103
+ createBrowserRouter(routes, { basename: platform.basePath || '/' });
104
+ ```
105
+
95
106
  #### Error Handling and Analytics
96
107
 
97
108
  The SDK automatically reports uncaught errors, unhandled promise rejections, and pageviews to a per-app dashboard the owner gets for free. No setup required. The analytics dashboard covers visits, unique visitors, top pages, referrers, UTM breakdowns, country-level geo, device/browser/OS, new vs returning, and live online count.
@@ -136,6 +147,10 @@ await prerender.invalidate(['/u/abc']); // omit arg to purge all
136
147
 
137
148
  `mindstudio-prod prerender` can help you verify/manage snapshots during development.
138
149
 
150
+ ### Mounting other apps
151
+
152
+ Rare: `mounts` serves another same-workspace app under a path prefix of this app's hosts — `{ "web": { "mounts": [{ "path": "/docs", "app": "docs-site" }] } }` (`app` = the target's `custom_subdomain` or appId). The child is served first-class (its own bundle, session, backend) and needs no mount-specific config; the two serving conventions above are what make an app mountable.
153
+
139
154
  ## API Interface
140
155
 
141
156
  REST endpoints for external consumers — other services, mobile apps, integrations. This is separate from the web frontend's internal RPC (`@mindstudio-ai/interface` calls `/_/methods` directly and does not use the API interface). The API interface lives at `/_/api/` and exposes only the methods you choose to route.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Files, Storage & CDN
3
- what: Per-app blob storage the database doesn't model — user uploads, generated documents, marketing images. Stores are private by default (reads authed by the app session, or short-lived signed share links) or deliberately public — public files are CDN-served on the app's own domain and images resize on the fly via query params (width, height, crop, format, dpr), so the frontend requests the size it displays instead of CSS-scaling originals. User uploads go client-direct: the backend mints a token and the browser uploads straight to storage, bytes never pass through a method. SDK actions that produce files (generateImage, generatePdf, …) can write straight into a store, and the CLI uploads build-time assets (heroes, logos, OG images) so binaries never land in git. One store is shared across dev and prod on purpose.
3
+ what: Per-app blob storage the database doesn't model — user uploads, generated documents, marketing images. Stores are private by default (reads authed by the app session, or short-lived signed share links) or deliberately public — public files are CDN-served on the app's own domain with caching set per put via `cacheControl`, and images resize on the fly via query params (width, height, crop, format, dpr), so the frontend requests the size it displays instead of CSS-scaling originals. User uploads go client-direct: the backend mints a token and the browser uploads straight to storage, bytes never pass through a method. SDK actions that produce files (generateImage, generatePdf, …) can write straight into a store, and the CLI uploads build-time assets (heroes, logos, OG images) so binaries never land in git. One store is shared across dev and prod on purpose.
4
4
  when: Before defining a file store or writing any upload, download, share-link, or image-serving code — user uploads, generated documents, marketing assets, config blobs, anything durable the app stores outside the database.
5
5
  ---
6
6
 
@@ -45,7 +45,7 @@ const { files, cursor } = await Uploads.list({ prefix: 'reports/', limit: 100 })
45
45
  await Uploads.delete(key);
46
46
  ```
47
47
 
48
- - `put(content, { key?, contentType?, filename?, contentAddressed? })` → `StoredFile` (`{ key, url, size?, contentType?, updatedAt?, shareUrl() }`). Omit `key` → UUID; `contentAddressed: true` → a `<sha256>.<ext>` key (immutable/idempotent, for baked-in public assets).
48
+ - `put(content, { key?, contentType?, filename?, contentAddressed?, cacheControl? })` → `StoredFile` (`{ key, url, size?, contentType?, updatedAt?, shareUrl() }`). Omit `key` → UUID; `contentAddressed: true` → a `<sha256>.<ext>` key (immutable/idempotent, for baked-in public assets). `cacheControl` sets a public object's CDN caching — defaults: auto-minted keys (UUID / content-addressed, never reused) → immutable cache-forever; named keys → `public, max-age=300`.
49
49
  - **`file.url`** is a plain relative string — don't await it. To display a user *their own* file, hand them `file.url`; don't `get()` the bytes and stream them yourself.
50
50
  - **`await file.shareUrl({ expiresIn })`** → an absolute signed link that works with **no session** (email / cross-site embed). Private stores only; default 24h.
51
51
 
@@ -85,7 +85,11 @@ Public files are world-readable, served on the app's own domain, and **images re
85
85
 
86
86
  Combine freely: `…/hero.jpg?w=200&h=200&fit=crop&fm=avif`.
87
87
 
88
- Lightweight-config pattern: a public store + a stable `key` is a file the frontend can `fetch` with no DB hit and the backend can overwrite (`Config.put(json, { key: 'config/latest.json' })`).
88
+ ### How public caching works
89
+
90
+ A public `file.url` resolves through a short-lived redirect (cached ~5 min, stable target) to the CDN object, which is cached per its own `Cache-Control` — set at put time via `cacheControl`. Auto-minted keys (UUID / content-addressed / CLI uploads) are never reused, so they default to `public, max-age=31536000, immutable`; named (overwritable) keys default to `public, max-age=300`, so an overwrite is publicly visible within ~5 minutes. Tune per put: `'public, max-age=60'` for near-live data, `'no-store'` to revalidate every read, `immutable` for a named key you promise never to overwrite. Private files never edge-cache (reads are short-lived signed URLs).
91
+
92
+ Lightweight-config pattern: a public store + a stable `key` is a file the frontend can `fetch` with no DB hit and the backend can overwrite (`Config.put(json, { key: 'config/latest.json' })`). Overwrites propagate within ~5 minutes by default — pass `cacheControl` if the app needs tighter freshness.
89
93
 
90
94
  ## Build-time / marketing assets
91
95
 
@@ -116,7 +116,13 @@ export default defineJewel(categorizeRecord, {
116
116
  maxTurns: 6,
117
117
  });
118
118
  if (!task.output.category) return { input: null, reasoning: task.output.rationale };
119
- return { input: { recordId, category: task.output.category }, reasoning: task.output.rationale };
119
+ return {
120
+ input: { recordId, category: task.output.category },
121
+ reasoning: task.output.rationale,
122
+ // Preserves the model transcript with the pair: the training row,
123
+ // and at auto the audit trail.
124
+ trace: task.traceId,
125
+ };
120
126
  } catch (err) {
121
127
  // Couldn't produce conforming output; abstain with the evidence. Fail closed.
122
128
  return { input: null, reasoning: `Task agent failed: ${err instanceof Error ? err.message : String(err)}` };
@@ -137,6 +143,7 @@ To preserve signal integrity, the task prompt inside `propose` addresses the mod
137
143
  - **Context is plain imports plus tools.** Prefetch what every run needs (the row, its history, the inventory of valid values) into the task input; expose the app's own read methods as tools for what the agent should decide to look up (precedent, comparables). Tool calls are recorded with the pair.
138
144
  - **Use `runTask` with `outputSchema` for the judgment.** Build enums at runtime: a candidate-id enum means the agent structurally cannot reference a row that doesn't exist, and a known-values enum means it cannot invent a category. Put `null` in the enum so abstention is a first-class output rather than a formatting accident.
139
145
  - **Catch everything; abstain on failure.** A jewel that can't decide returns `{ input: null, reasoning }` with the evidence. It never throws to say "I don't know."
146
+ - **Attach the deciding task's trace.** `trace: task.traceId` on the success return preserves the full model transcript with the pair; use an array when the story has chapters (`trace: [first.traceId, escalation.traceId]`). Helper and formatting calls stay unattached; the attachment is the label for which run WAS the decision. A pair without a trace still grades, but it is thin as evidence and as training data.
140
147
  - **Propose a subset when that's the honest scope.** A jewel that never sets `assigneeId` and never proposes `closed` (it can't know a fix shipped) is expressing policy through its output shape.
141
148
  - **Reasoning is audit-log prose.** Two or three plain sentences a teammate would find useful; name the evidence. No headers, bullets, or emojis.
142
149
 
@@ -182,8 +189,8 @@ grade: async ({ proposed, actual }) => {
182
189
  });
183
190
  const c = rubric.output;
184
191
  return c.sameResolution && c.noContradiction
185
- ? { verdict: 'agree' }
186
- : { verdict: 'disagree', notes: `Failed: ${[!c.sameResolution && 'sameResolution', !c.noContradiction && 'noContradiction'].filter(Boolean).join(', ')}` };
192
+ ? { verdict: 'agree', trace: rubric.traceId }
193
+ : { verdict: 'disagree', notes: `Failed: ${[!c.sameResolution && 'sameResolution', !c.noContradiction && 'noContradiction'].filter(Boolean).join(', ')}`, trace: rubric.traceId };
187
194
  } catch (err) {
188
195
  return { verdict: 'skip', notes: `Judge failed: ${err instanceof Error ? err.message : String(err)}` };
189
196
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.279",
3
+ "version": "0.1.281",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",