@mindstudio-ai/remy 0.1.134 → 0.1.136

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
@@ -165,7 +165,12 @@ async function sidecarRequest(endpoint, body = {}, options) {
165
165
  log2.error("Sidecar error", { endpoint, status: res.status });
166
166
  throw new Error(`Sidecar error: ${res.status}`);
167
167
  }
168
- return res.json();
168
+ const data = await res.json();
169
+ if (data?.success === false) {
170
+ const code = data.errorCode ? ` [${data.errorCode}]` : "";
171
+ throw new Error(`${data.error || "Unknown error"}${code}`);
172
+ }
173
+ return data;
169
174
  } catch (err) {
170
175
  if (err.message.startsWith("Sidecar error")) {
171
176
  throw err;
@@ -2602,6 +2607,39 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
2602
2607
  return JSON.stringify({ url, analysis, ...styleMap ? { styleMap } : {} });
2603
2608
  }
2604
2609
 
2610
+ // src/tools/_helpers/browserLock.ts
2611
+ var lockQueue = Promise.resolve();
2612
+ function acquireBrowserLock() {
2613
+ let release;
2614
+ const next = new Promise((res) => {
2615
+ release = res;
2616
+ });
2617
+ const wait = lockQueue;
2618
+ lockQueue = next;
2619
+ return wait.then(() => release);
2620
+ }
2621
+ async function checkBrowserConnected() {
2622
+ try {
2623
+ const status = await sidecarRequest(
2624
+ "/browser-status",
2625
+ {},
2626
+ { timeout: 5e3 }
2627
+ );
2628
+ if (!status.connected) {
2629
+ return {
2630
+ connected: false,
2631
+ error: "The browser preview is not connected. The user needs to open the preview."
2632
+ };
2633
+ }
2634
+ return { connected: true };
2635
+ } catch (err) {
2636
+ return {
2637
+ connected: false,
2638
+ error: err?.message || "Could not check browser status. The dev environment may not be running."
2639
+ };
2640
+ }
2641
+ }
2642
+
2605
2643
  // src/statusWatcher.ts
2606
2644
  function startStatusWatcher(config) {
2607
2645
  const { apiConfig, getContext, onStatus, interval = 3e3, signal } = config;
@@ -2743,6 +2781,9 @@ ${summaryBlock.text}
2743
2781
  return false;
2744
2782
  }
2745
2783
  }
2784
+ if (msg.role === "assistant" && Array.isArray(msg.content) && msg.content.length === 0) {
2785
+ return false;
2786
+ }
2746
2787
  if (msg.role === "user" && msg.toolCallId && !toolUseIds.has(msg.toolCallId)) {
2747
2788
  return false;
2748
2789
  }
@@ -3300,16 +3341,6 @@ ${appSpec}
3300
3341
 
3301
3342
  // src/subagents/browserAutomation/index.ts
3302
3343
  var log6 = createLogger("browser-automation");
3303
- var lockQueue = Promise.resolve();
3304
- function acquireBrowserLock() {
3305
- let release;
3306
- const next = new Promise((res) => {
3307
- release = res;
3308
- });
3309
- const wait = lockQueue;
3310
- lockQueue = next;
3311
- return wait.then(() => release);
3312
- }
3313
3344
  var browserAutomationTool = {
3314
3345
  clearable: true,
3315
3346
  definition: {
@@ -3332,17 +3363,9 @@ var browserAutomationTool = {
3332
3363
  }
3333
3364
  const release = await acquireBrowserLock();
3334
3365
  try {
3335
- try {
3336
- const status = await sidecarRequest(
3337
- "/browser-status",
3338
- {},
3339
- { timeout: 5e3 }
3340
- );
3341
- if (!status.connected) {
3342
- return "Error: the browser preview is not connected. The user needs to open the preview before browser tests can run.";
3343
- }
3344
- } catch {
3345
- return "Error: could not check browser status. The dev environment may not be running.";
3366
+ const browserStatus = await checkBrowserConnected();
3367
+ if (!browserStatus.connected) {
3368
+ return `Error: ${browserStatus.error}`;
3346
3369
  }
3347
3370
  try {
3348
3371
  await sidecarRequest("/reset-browser", {}, { timeout: 5e3 });
@@ -3516,11 +3539,20 @@ var screenshotTool = {
3516
3539
  ...styleMap ? { styleMap } : {}
3517
3540
  });
3518
3541
  }
3519
- return await captureAndAnalyzeScreenshot({
3520
- prompt: input.prompt,
3521
- path: input.path,
3522
- onLog: context?.onLog
3523
- });
3542
+ const release = await acquireBrowserLock();
3543
+ try {
3544
+ const browserStatus = await checkBrowserConnected();
3545
+ if (!browserStatus.connected) {
3546
+ return `Error: ${browserStatus.error}`;
3547
+ }
3548
+ return await captureAndAnalyzeScreenshot({
3549
+ prompt: input.prompt,
3550
+ path: input.path,
3551
+ onLog: context?.onLog
3552
+ });
3553
+ } finally {
3554
+ release();
3555
+ }
3524
3556
  } catch (err) {
3525
3557
  return `Error taking screenshot: ${err.message}`;
3526
3558
  }
@@ -3846,7 +3878,12 @@ async function execute5(input, onLog, context) {
3846
3878
  return `Error taking interactive screenshot: ${err.message}`;
3847
3879
  }
3848
3880
  }
3881
+ const release = await acquireBrowserLock();
3849
3882
  try {
3883
+ const browserStatus = await checkBrowserConnected();
3884
+ if (!browserStatus.connected) {
3885
+ return `Error: ${browserStatus.error}`;
3886
+ }
3850
3887
  return await captureAndAnalyzeScreenshot({
3851
3888
  prompt: input.prompt,
3852
3889
  path: input.path,
@@ -3854,6 +3891,8 @@ async function execute5(input, onLog, context) {
3854
3891
  });
3855
3892
  } catch (err) {
3856
3893
  return `Error taking screenshot: ${err.message}`;
3894
+ } finally {
3895
+ release();
3857
3896
  }
3858
3897
  }
3859
3898
 
@@ -5589,10 +5628,12 @@ async function runTurn(params) {
5589
5628
  saveSession(state);
5590
5629
  return;
5591
5630
  }
5592
- state.messages.push({
5593
- role: "assistant",
5594
- content: [...contentBlocks].sort((a, b) => a.startedAt - b.startedAt)
5595
- });
5631
+ if (contentBlocks.length > 0) {
5632
+ state.messages.push({
5633
+ role: "assistant",
5634
+ content: [...contentBlocks].sort((a, b) => a.startedAt - b.startedAt)
5635
+ });
5636
+ }
5596
5637
  const toolCalls = getToolCalls(contentBlocks);
5597
5638
  if (stopReason !== "tool_use" || toolCalls.length === 0) {
5598
5639
  statusWatcher.stop();
package/dist/index.js CHANGED
@@ -1986,7 +1986,12 @@ async function sidecarRequest(endpoint, body = {}, options) {
1986
1986
  log2.error("Sidecar error", { endpoint, status: res.status });
1987
1987
  throw new Error(`Sidecar error: ${res.status}`);
1988
1988
  }
1989
- return res.json();
1989
+ const data = await res.json();
1990
+ if (data?.success === false) {
1991
+ const code = data.errorCode ? ` [${data.errorCode}]` : "";
1992
+ throw new Error(`${data.error || "Unknown error"}${code}`);
1993
+ }
1994
+ return data;
1990
1995
  } catch (err) {
1991
1996
  if (err.message.startsWith("Sidecar error")) {
1992
1997
  throw err;
@@ -2306,6 +2311,46 @@ Respond only with your analysis as Markdown and absolutely no other text. Do not
2306
2311
  }
2307
2312
  });
2308
2313
 
2314
+ // src/tools/_helpers/browserLock.ts
2315
+ function acquireBrowserLock() {
2316
+ let release;
2317
+ const next = new Promise((res) => {
2318
+ release = res;
2319
+ });
2320
+ const wait = lockQueue;
2321
+ lockQueue = next;
2322
+ return wait.then(() => release);
2323
+ }
2324
+ async function checkBrowserConnected() {
2325
+ try {
2326
+ const status = await sidecarRequest(
2327
+ "/browser-status",
2328
+ {},
2329
+ { timeout: 5e3 }
2330
+ );
2331
+ if (!status.connected) {
2332
+ return {
2333
+ connected: false,
2334
+ error: "The browser preview is not connected. The user needs to open the preview."
2335
+ };
2336
+ }
2337
+ return { connected: true };
2338
+ } catch (err) {
2339
+ return {
2340
+ connected: false,
2341
+ error: err?.message || "Could not check browser status. The dev environment may not be running."
2342
+ };
2343
+ }
2344
+ }
2345
+ var lockQueue;
2346
+ var init_browserLock = __esm({
2347
+ "src/tools/_helpers/browserLock.ts"() {
2348
+ "use strict";
2349
+ init_sidecar();
2350
+ lockQueue = Promise.resolve();
2351
+ }
2352
+ });
2353
+
2309
2354
  // src/statusWatcher.ts
2310
2355
  function startStatusWatcher(config) {
2311
2356
  const { apiConfig, getContext, onStatus, interval = 3e3, signal } = config;
@@ -2452,6 +2497,9 @@ ${summaryBlock.text}
2452
2497
  return false;
2453
2498
  }
2454
2499
  }
2500
+ if (msg.role === "assistant" && Array.isArray(msg.content) && msg.content.length === 0) {
2501
+ return false;
2502
+ }
2455
2503
  if (msg.role === "user" && msg.toolCallId && !toolUseIds.has(msg.toolCallId)) {
2456
2504
  return false;
2457
2505
  }
@@ -3079,16 +3127,7 @@ var init_prompt = __esm({
3079
3127
  });
3080
3128
 
3081
3129
  // src/subagents/browserAutomation/index.ts
3082
- function acquireBrowserLock() {
3083
- let release;
3084
- const next = new Promise((res) => {
3085
- release = res;
3086
- });
3087
- const wait = lockQueue;
3088
- lockQueue = next;
3089
- return wait.then(() => release);
3090
- }
3091
- var log4, lockQueue, browserAutomationTool;
3130
+ var log4, browserAutomationTool;
3092
3131
  var init_browserAutomation = __esm({
3093
3132
  "src/subagents/browserAutomation/index.ts"() {
3094
3133
  "use strict";
@@ -3096,11 +3135,11 @@ var init_browserAutomation = __esm({
3096
3135
  init_tools();
3097
3136
  init_prompt();
3098
3137
  init_sidecar();
3138
+ init_browserLock();
3099
3139
  init_screenshot();
3100
3140
  init_runCli();
3101
3141
  init_logger();
3102
3142
  log4 = createLogger("browser-automation");
3103
- lockQueue = Promise.resolve();
3104
3143
  browserAutomationTool = {
3105
3144
  clearable: true,
3106
3145
  definition: {
@@ -3123,17 +3162,9 @@ var init_browserAutomation = __esm({
3123
3162
  }
3124
3163
  const release = await acquireBrowserLock();
3125
3164
  try {
3126
- try {
3127
- const status = await sidecarRequest(
3128
- "/browser-status",
3129
- {},
3130
- { timeout: 5e3 }
3131
- );
3132
- if (!status.connected) {
3133
- return "Error: the browser preview is not connected. The user needs to open the preview before browser tests can run.";
3134
- }
3135
- } catch {
3136
- return "Error: could not check browser status. The dev environment may not be running.";
3165
+ const browserStatus = await checkBrowserConnected();
3166
+ if (!browserStatus.connected) {
3167
+ return `Error: ${browserStatus.error}`;
3137
3168
  }
3138
3169
  try {
3139
3170
  await sidecarRequest("/reset-browser", {}, { timeout: 5e3 });
@@ -3247,6 +3278,7 @@ var init_screenshot2 = __esm({
3247
3278
  "src/tools/code/screenshot.ts"() {
3248
3279
  "use strict";
3249
3280
  init_screenshot();
3281
+ init_browserLock();
3250
3282
  init_analyzeImage();
3251
3283
  init_browserAutomation();
3252
3284
  screenshotTool = {
@@ -3316,11 +3348,20 @@ var init_screenshot2 = __esm({
3316
3348
  ...styleMap ? { styleMap } : {}
3317
3349
  });
3318
3350
  }
3319
- return await captureAndAnalyzeScreenshot({
3320
- prompt: input.prompt,
3321
- path: input.path,
3322
- onLog: context?.onLog
3323
- });
3351
+ const release = await acquireBrowserLock();
3352
+ try {
3353
+ const browserStatus = await checkBrowserConnected();
3354
+ if (!browserStatus.connected) {
3355
+ return `Error: ${browserStatus.error}`;
3356
+ }
3357
+ return await captureAndAnalyzeScreenshot({
3358
+ prompt: input.prompt,
3359
+ path: input.path,
3360
+ onLog: context?.onLog
3361
+ });
3362
+ } finally {
3363
+ release();
3364
+ }
3324
3365
  } catch (err) {
3325
3366
  return `Error taking screenshot: ${err.message}`;
3326
3367
  }
@@ -3662,7 +3703,12 @@ async function execute5(input, onLog, context) {
3662
3703
  return `Error taking interactive screenshot: ${err.message}`;
3663
3704
  }
3664
3705
  }
3706
+ const release = await acquireBrowserLock();
3665
3707
  try {
3708
+ const browserStatus = await checkBrowserConnected();
3709
+ if (!browserStatus.connected) {
3710
+ return `Error: ${browserStatus.error}`;
3711
+ }
3666
3712
  return await captureAndAnalyzeScreenshot({
3667
3713
  prompt: input.prompt,
3668
3714
  path: input.path,
@@ -3670,6 +3716,8 @@ async function execute5(input, onLog, context) {
3670
3716
  });
3671
3717
  } catch (err) {
3672
3718
  return `Error taking screenshot: ${err.message}`;
3719
+ } finally {
3720
+ release();
3673
3721
  }
3674
3722
  }
3675
3723
  var definition5;
@@ -3677,6 +3725,7 @@ var init_screenshot3 = __esm({
3677
3725
  "src/subagents/designExpert/tools/screenshot.ts"() {
3678
3726
  "use strict";
3679
3727
  init_screenshot();
3728
+ init_browserLock();
3680
3729
  init_analyzeImage();
3681
3730
  init_browserAutomation();
3682
3731
  definition5 = {
@@ -5651,10 +5700,12 @@ async function runTurn(params) {
5651
5700
  saveSession(state);
5652
5701
  return;
5653
5702
  }
5654
- state.messages.push({
5655
- role: "assistant",
5656
- content: [...contentBlocks].sort((a, b) => a.startedAt - b.startedAt)
5657
- });
5703
+ if (contentBlocks.length > 0) {
5704
+ state.messages.push({
5705
+ role: "assistant",
5706
+ content: [...contentBlocks].sort((a, b) => a.startedAt - b.startedAt)
5707
+ });
5708
+ }
5658
5709
  const toolCalls = getToolCalls(contentBlocks);
5659
5710
  if (stopReason !== "tool_use" || toolCalls.length === 0) {
5660
5711
  statusWatcher.stop();
@@ -69,7 +69,7 @@ From research into v0, Lovable, Bolt, and Anthropic's `<frontend_aesthetics>` co
69
69
 
70
70
  ## SDK Usage
71
71
 
72
- The source docs originally showed `mindstudio.executeStep('generateText', ...)` which was wrong. The correct API is `new MindStudioAgent()` with direct method calls (`agent.generateText(...)`, `agent.sendEmail(...)`, etc.). No constructor args needed inside methods — credentials come from the execution environment. We fixed both the compiled fragment and the upstream source doc in youai-api.
72
+ The canonical import pattern for MindStudio app methods is `import { mindstudio } from '@mindstudio-ai/agent'` with `mindstudio.generateText(...)`, `mindstudio.runTask(...)`, etc. The `mindstudio` singleton handles auth automatically. `new MindStudioAgent({ apiKey })` is only for external usage outside MindStudio apps.
73
73
 
74
74
  The SDK ships `llms.txt` at the package root with full signatures for all 170+ actions. The compiled fragment references this path (`dist/methods/node_modules/@mindstudio-ai/agent/llms.txt`) so the agent knows where to look up specific action details.
75
75
 
@@ -343,13 +343,16 @@ Roles are declared in the manifest, stored as an array column on the user table,
343
343
 
344
344
  Apps without `auth` in the manifest use anonymous guest sessions. No login, no user identity, no roles. This is the default and works fine for single-user apps, internal tools, and simple utilities.
345
345
 
346
- ## Designing Auth in Web Interfaces
346
+ ## Important: Designing Auth in Web Interfaces
347
+
347
348
  The most imporant user experience consideration with auth is that authentication moments must feel natural and intuitive - they should not feel jarring or surprising. Take care to integrate them into the entire experience when building.
348
349
 
349
350
  For the overwhelming majority of apps, a user should never land on auth at the root of an app when opening it for the first time (except in cases where the app is, e.g., an internal tool or some other protected experience - and even then it should feel more like a welcome/splash screen than an error state). Users should be able to explore public resources, or at least encounter some kind of landing/introduction moment, before they get hit with a signup/login screen. Make auth feel like a natural moment in the user's journey.
350
351
 
351
352
  Login and signup screens set the tone for the user's entire experience with the app and are important to get right - they should feel like exciting entry points into the next level of the user journy. A janky login form with misaligned inputs and no feedback dminishes excitement and undermines trust before the user even gets in.
352
353
 
354
+ Login and signup are separate moments - even if the underlying code is the same for both. A new user signing up should feel like they are creating a new account. A user logging in should feel like they are being welcomed back. Auth is always a pain for users, even when it's as frictionless as this, so take care to use Sign Up screens as moments to communicate value and help the user get excited about what they are joining.
355
+
353
356
  Consult the `visualDesignExpert` to help you work through authentication at a high level, including when and where to show auth, and the design of specific screens.
354
357
 
355
358
  ### Rules for Building Auth Screens
@@ -25,7 +25,7 @@ Interfaces run fullscreen in the user's browser or a wrapped webview mobile app.
25
25
  - **No long scrolling pages.** Use structured layouts: cards, split panes, steppers, tabs, grouped sections that fit the viewport. The interface should feel like an award winning iOS or macOS app, not a document.
26
26
  - **On mobile**, scrolling may be necessary, but use sticky headers, fixed CTAs, and anchored navigation to keep key actions within reach. Always use "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" to make sure apps feel like apps.
27
27
  - Think of every screen as something the user opens, uses, and closes — not something they read.
28
- - Pay attention to details that will make things feel app-like - set user-select: none on specific app-like layout elements, use motion, use iOS/macOS design language and patterns.
28
+ - Pay attention to details that will make things feel app-like - set user-select: none on specific app-like layout elements like navigation bars, use motion, use iOS/macOS design language and patterns.
29
29
 
30
30
  ## Layout Stability
31
31
 
@@ -50,6 +50,7 @@ Every interface must work on both desktop and mobile. Think about how the app wi
50
50
  - Even for mobile-first apps, make sure to set desktop or larger device breakpoints - nothing looks jankier than opening a mobile-designed site in a desktop browser and seeing a full width bottom tab bar with nav icons stretching 1000px wide. Don't make sloppy, amateur mistakes or omissions like this - the user will notice them and be disappointed.
51
51
 
52
52
  ## Images
53
+
53
54
  The `designExpert` can create and source amazing, high quality images, graphics, illustrations, and logos to use in the interface - both with and without transparency. This is a huge level for upgrading the premium look, feel, and quality of the app. Use image logos directly instead of plain text wordmarks; use images for empty states, onboarding screens, full-screen loading, and more.
54
55
 
55
56
  ## Forms
@@ -65,38 +65,36 @@ export async function getDashboard(input: {
65
65
 
66
66
  ## Platform Capabilities
67
67
 
68
- The `@mindstudio-ai/agent` SDK provides access to 200+ AI models and 1,000+ actions (email, SMS, web scraping, file uploads, third-party integrations, and more). Inside a method, create an instance and call actions directly. No constructor arguments needed — credentials are picked up automatically from the execution environment:
68
+ The `@mindstudio-ai/agent` SDK provides access to 200+ AI models and 1,000+ actions (email, SMS, web scraping, file uploads, third-party integrations, and more). Inside a method, use the `mindstudio` singleton — credentials come from the execution environment automatically:
69
69
 
70
70
  ```typescript
71
- import { MindStudioAgent } from '@mindstudio-ai/agent';
72
-
73
- const agent = new MindStudioAgent();
71
+ import { mindstudio } from '@mindstudio-ai/agent';
74
72
 
75
73
  // AI text generation
76
- const { content } = await agent.generateText({
74
+ const { content } = await mindstudio.generateText({
77
75
  message: 'Summarize this invoice...',
78
76
  });
79
77
 
80
78
  // AI image generation
81
- const { imageUrl } = await agent.generateImage({
79
+ const { imageUrl } = await mindstudio.generateImage({
82
80
  prompt: 'A professional headshot placeholder',
83
81
  });
84
82
 
85
83
  // Send email
86
- await agent.sendEmail({
84
+ await mindstudio.sendEmail({
87
85
  to: 'user@example.com',
88
86
  subject: 'Your invoice',
89
87
  body: content,
90
88
  });
91
89
 
92
90
  // Upload files
93
- const { url } = await agent.uploadFile({
91
+ const { url } = await mindstudio.uploadFile({
94
92
  data: buffer,
95
93
  fileName: 'report.pdf',
96
94
  });
97
95
 
98
96
  // Web scraping
99
- const { markdown } = await agent.scrapeUrl({
97
+ const { markdown } = await mindstudio.scrapeUrl({
100
98
  url: 'https://example.com',
101
99
  });
102
100
 
@@ -126,7 +124,7 @@ For errors from external services or internal failures (API calls, AI generation
126
124
 
127
125
  ```typescript
128
126
  try {
129
- const result = await agent.generateVideo({ ... });
127
+ const result = await mindstudio.generateVideo({ ... });
130
128
  return { videoUrl: result.url };
131
129
  } catch (err) {
132
130
  console.error('Video generation failed:', err);
@@ -210,7 +208,7 @@ export async function enrichRestaurant(input: { id: string; name: string }) {
210
208
  await Restaurants.update(input.id, { status: 'enriching' });
211
209
 
212
210
  // Fire — don't await
213
- agent.runTask<RestaurantData>({
211
+ mindstudio.runTask<RestaurantData>({
214
212
  prompt: '...',
215
213
  input: { name: input.name },
216
214
  tools: ['searchGoogle', 'fetchUrl', 'generateImage'],
@@ -192,13 +192,15 @@ styles:
192
192
  ```
193
193
  ```
194
194
 
195
- Roadmap item example (one file per feature in `src/roadmap/`):
195
+ Roadmap item examples (one file per feature in `src/roadmap/`):
196
+
197
+ Built item (status updated to `done` after build, with History appended):
196
198
 
197
199
  ```markdown
198
200
  ---
199
201
  name: Share & Export
200
202
  type: roadmap
201
- status: not-started
203
+ status: done
202
204
  description: Share haikus as image cards to social media or download as prints.
203
205
  requires: []
204
206
  effort: medium
@@ -220,3 +222,20 @@ clipboard fallback for unsupported browsers.
220
222
  - **2026-03-22** — Built card generation using generateImage.
221
223
  Added share button to haiku detail view.
222
224
  ```
225
+
226
+ Unbuilt item:
227
+
228
+ ```markdown
229
+ ---
230
+ name: Daily Prompt Engine
231
+ type: roadmap
232
+ status: not-started
233
+ description: A new writing prompt every day, tuned to the user's style and interests.
234
+ requires: []
235
+ effort: small
236
+ ---
237
+
238
+ Generate a personalized daily writing prompt based on the user's past haikus,
239
+ preferred themes, and seasonal context. Surface it as a gentle nudge on the
240
+ home screen, not a notification.
241
+ ```
@@ -6,24 +6,18 @@ There is a huge amount of capability here: hundreds of text generation models (O
6
6
 
7
7
  ## Usage in Methods
8
8
 
9
- Inside a MindStudio app method, create an instance with no arguments — credentials come from the execution environment:
9
+ Inside a MindStudio app method, use the `mindstudio` singleton — credentials come from the execution environment automatically:
10
10
 
11
11
  ```typescript
12
- import { MindStudioAgent } from '@mindstudio-ai/agent';
12
+ import { mindstudio } from '@mindstudio-ai/agent';
13
13
 
14
- const agent = new MindStudioAgent();
15
- ```
16
-
17
- Every action is a method on the agent instance:
18
-
19
- ```typescript
20
- const { content } = await agent.generateText({ message: 'Summarize this...' });
14
+ const { content } = await mindstudio.generateText({ message: 'Summarize this...' });
21
15
  ```
22
16
 
23
17
  Results are returned flat — output fields at the top level alongside metadata:
24
18
 
25
19
  ```typescript
26
- const result = await agent.generateText({ message: 'Hello' });
20
+ const result = await mindstudio.generateText({ message: 'Hello' });
27
21
  result.content; // step-specific output
28
22
  result.$billingCost; // cost in credits (if applicable)
29
23
  ```
@@ -104,13 +98,13 @@ For other services, use `runFromConnectorRegistry`:
104
98
 
105
99
  ```typescript
106
100
  // Discover available connectors
107
- const { connectors } = await agent.listConnectors();
101
+ const { connectors } = await mindstudio.listConnectors();
108
102
 
109
103
  // Get action details
110
- const action = await agent.getConnectorAction('hubspot', 'create-contact');
104
+ const action = await mindstudio.getConnectorAction('hubspot', 'create-contact');
111
105
 
112
106
  // Execute
113
- const result = await agent.runFromConnectorRegistry({
107
+ const result = await mindstudio.runFromConnectorRegistry({
114
108
  serviceId: 'hubspot',
115
109
  actionId: 'create-contact',
116
110
  input: { email: 'user@example.com', firstName: 'Alice' },
@@ -122,7 +116,7 @@ const result = await agent.runFromConnectorRegistry({
122
116
  Override the default model for any AI action. Each model has its own config options (dimensions, seed, inference steps, etc.) so always use `askMindStudioSdk` to look up the correct config before specifying a model override:
123
117
 
124
118
  ```typescript
125
- const { content } = await agent.generateText({
119
+ const { content } = await mindstudio.generateText({
126
120
  message: 'Hello',
127
121
  modelOverride: {
128
122
  model: 'claude-sonnet-4-6',
@@ -139,7 +133,7 @@ Make sure to prioritize new, popular models. MindStudio has a ton of models avai
139
133
  Run up to 50 actions in parallel:
140
134
 
141
135
  ```typescript
142
- const result = await agent.executeStepBatch([
136
+ const result = await mindstudio.executeStepBatch([
143
137
  { stepType: 'generateImage', step: { prompt: 'a sunset' } },
144
138
  { stepType: 'textToSpeech', step: { text: 'hello world' } },
145
139
  ]);
@@ -1,4 +1,4 @@
1
- # Task Agents (`MindStudioAgent runTask`)
1
+ # Task Agents (`mindstudio.runTask`)
2
2
 
3
3
  A user types the name of a restaurant into your app, or uploads a photo of a storefront. The API call returns early, and in the background, a task agent searches Google, finds the official website, scrapes the address, gets the official social media accounts, and generates a stylized watercolor postcard of the exterior from images it found online. The user gets back a rich, illustrated card with the canonical name, website, address, and a custom image. A few tool calls (some in parallel), fully autonomous.
4
4
 
@@ -26,11 +26,9 @@ Run tasks in the background — depending on complexity they can take time to co
26
26
  ## Usage
27
27
 
28
28
  ```typescript
29
- import { MindStudioAgent } from '@mindstudio-ai/agent';
29
+ import { mindstudio } from '@mindstudio-ai/agent';
30
30
 
31
- const agent = new MindStudioAgent();
32
-
33
- const result = await agent.runTask<{
31
+ const result = await mindstudio.runTask<{
34
32
  name: string;
35
33
  url: string;
36
34
  address: string;
@@ -74,7 +72,7 @@ console.log(result.output.photoUrl); // URL to the generated illustration
74
72
  `runTask()` can return successfully with garbage output — fields null, data echoed back, or raw text instead of JSON. The result includes `parsedSuccessfully` to make this explicit. Always check it before using the output:
75
73
 
76
74
  ```typescript
77
- const result = await agent.runTask<MyType>({ ... });
75
+ const result = await mindstudio.runTask<MyType>({ ... });
78
76
 
79
77
  if (!result.parsedSuccessfully) {
80
78
  console.error('Task output was not valid JSON:', result.outputRaw);
@@ -106,6 +104,10 @@ tools: [
106
104
 
107
105
  When the model calls a tool, the platform deep-merges the model's arguments with the developer's defaults. The model decides what to do (prompt, query, parameters), the developer controls which model/config to use. If the model needs to search and generate an image and those are independent, it will call both tools in the same turn (parallel execution server-side).
108
106
 
107
+ ## Voice & Tone in Prompts
108
+
109
+ When a task agent produces user-facing text, the prompt must include a note voice and tone constraints. Make sure to specify no emojis, em dashes, and other "ai-isms" in the prompt, as well as the desired tone and voice of the output.
110
+
109
111
  ## Options
110
112
 
111
113
  | Field | Required | Default | Description |
@@ -150,7 +152,7 @@ When something goes wrong, `toolCalls` is the first thing to check. If it's empt
150
152
  Pass an `onEvent` callback to get real-time events:
151
153
 
152
154
  ```typescript
153
- const result = await agent.runTask({
155
+ const result = await mindstudio.runTask({
154
156
  // ... same options ...
155
157
  onEvent: (event) => {
156
158
  if (event.type === 'text') console.log('Agent:', event.text);
@@ -173,7 +175,7 @@ Without `onEvent`, the SDK uses async polling (returns silently when complete).
173
175
 
174
176
  ```typescript
175
177
  try {
176
- const result = await agent.runTask({ ... });
178
+ const result = await mindstudio.runTask({ ... });
177
179
  if (!result.parsedSuccessfully) {
178
180
  // Task completed but output wasn't valid JSON
179
181
  console.error('Raw output:', result.outputRaw);
@@ -45,6 +45,9 @@ For multi-step tasks with branching logic (research, enrichment, content pipelin
45
45
  - Use container queries for components that need to adapt to their container rather than the viewport.
46
46
  - For canvas-based UIs (games, visualizations, interactive graphics): size the canvas to fill its container, account for `devicePixelRatio` for Retina sharpness, and scale all objects relative to the viewport — not in fixed pixel sizes - otherwise they are going to be tiny and unusable.
47
47
 
48
+ ### Copy & Prose
49
+ - Landing pages, hero sections, onboarding flows, and other long-form prose need a human voice. Write plainly and specifically. Avoid promotional filler, hollow intensifiers, and chatbot enthusiasm. Avoid em dashes, emojis, and other "ai-isms" in your writing.
50
+
48
51
  ### Error Visibility
49
52
  - Runtime errors must render visibly on screen, not produce a blank white page. User and agent must be able to visibly debug and spot them.
50
53
 
@@ -63,7 +66,7 @@ When integrating with external services that have programmable setup APIs (webho
63
66
  Before installing a package you haven't used in this project, do a quick web search to confirm it's still the best option. The JavaScript ecosystem moves fast — the package you remember from training may have been superseded by something smaller, faster, or better maintained. A 10-second search beats debugging a deprecated library.
64
67
 
65
68
  ### MindStudio SDK CLI
66
- You have access to the `mindstudio` CLI, which exposes every SDK action as a command-line tool. Use it via bash for one-off tasks: generating images, scraping URLs, sending emails, running AI completions, or anything else the SDK can do. Every JavaScript SDK method has a corresponding CLI command. Run `askMindStudioSdk` to discover commands for CLI usage.
69
+ You have access to the `mindstudio` CLI, which exposes every SDK action as a command-line tool. Use it via bash for one-off tasks: generating images, video, or audio, scraping URLs, sending emails, running AI completions, or anything else the SDK can do. Every JavaScript SDK method has a corresponding CLI command. Run `askMindStudioSdk` to discover commands for CLI usage.
67
70
 
68
71
  ### Production App Management
69
72
  You have access to `mindstudio-prod`, a CLI for managing the user's production MindStudio 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.134",
3
+ "version": "0.1.136",
4
4
  "description": "MindStudio coding agent",
5
5
  "repository": {
6
6
  "type": "git",