@mindstudio-ai/remy 0.1.280 → 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)}`;
@@ -93,21 +93,13 @@ The project uses `"jsx": "react-jsx"` (automatic JSX transform) — do not `impo
93
93
 
94
94
  On deploy, the platform runs `npm install && npm run build` in the web directory and hosts the output on CDN.
95
95
 
96
- Two serving conventions every web interface must follow:
97
-
98
- 1. **Assets via `MS_ASSET_BASE_URL`.** The platform build sets this env var to a release-addressed CDN origin. Point the bundler's public path at it so asset URLs work on any host or mount path:
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.
99
97
 
100
98
  ```ts
101
99
  // vite.config.ts
102
- export default defineConfig({
103
- base: process.env.MS_ASSET_BASE_URL || '/',
104
- // ...
105
- });
106
- ```
100
+ base: process.env.MS_ASSET_BASE_URL || '/',
107
101
 
108
- 2. **Router basename from `platform.basePath`.** The platform injects the path prefix the page is served under ('' on the app's own hosts, the mount path when another app mounts this one). The SDK prefixes its own calls automatically; app code must feed it to the router and avoid hardcoded root-absolute URLs (`<img src="/logo.png">`, raw `location.assign('/about')`):
109
-
110
- ```ts
102
+ // router
111
103
  createBrowserRouter(routes, { basename: platform.basePath || '/' });
112
104
  ```
113
105
 
@@ -157,18 +149,7 @@ await prerender.invalidate(['/u/abc']); // omit arg to purge all
157
149
 
158
150
  ### Mounting other apps
159
151
 
160
- A web interface can serve other apps from the same workspace under path prefixes of its own hosts (the multi-zone pattern e.g. a marketing site serving a self-contained demo app at `/demos/vector-search` instead of linking to its subdomain):
161
-
162
- ```json
163
- { "web": { "mounts": [{ "path": "/demos/vector-search", "app": "vector-search-demo" }] } }
164
- ```
165
-
166
- - `path`: non-root mount prefix; mounts must be disjoint (none may prefix another).
167
- - `app`: the target's `custom_subdomain` or appId — a v2 app in the same workspace, validated at build.
168
-
169
- Under the mount everything is the child's, served first-class (its live bundle, session, backend, auth, telemetry, frame policy). The child needs no mount-specific config and keeps working at its own subdomain; deploys stay independent. Mount-safety = the two serving conventions above (`MS_ASSET_BASE_URL` assets + `platform.basePath` basename, no hardcoded root-absolute URLs); the parent's build log warns when a target's build isn't mount-safe.
170
-
171
- Caveats: prerendering for mounted paths is declared in the PARENT's `prerender.paths`; the auth cookie is per-host, so don't mount an auth-enabled app on a parent that also uses auth; a mount whose target has no live web build falls through to the parent's SPA.
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.
172
153
 
173
154
  ## API Interface
174
155
 
@@ -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.280",
3
+ "version": "0.1.281",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",