@mindstudio-ai/remy 0.1.276 → 0.1.278
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 +112 -33
- package/dist/index.js +135 -35
- package/dist/prompt/compiled/methods.md +6 -8
- package/dist/prompt/skills/agentInterfaces.md +13 -39
- package/dist/prompt/skills/auth.md +1 -7
- package/dist/prompt/skills/dataSources.md +20 -66
- package/dist/prompt/skills/files.md +17 -47
- package/dist/prompt/skills/inboundEmail.md +11 -32
- package/dist/prompt/skills/mcpInterfaces.md +21 -63
- package/dist/prompt/skills/restApi.md +7 -21
- package/dist/prompt/skills/scenarios.md +3 -7
- package/dist/prompt/skills/scheduledJobs.md +3 -8
- package/dist/prompt/skills/taskAgents.md +47 -34
- package/dist/prompt/skills/voiceInterfaces.md +117 -366
- package/dist/prompt/skills/webhooks.md +10 -31
- package/dist/prompt/static/authoring.md +1 -2
- package/dist/subagents/browserAutomation/prompt.md +6 -22
- package/dist/subagents/codeSanityCheck/prompt.md +4 -5
- package/dist/subagents/designExpert/prompt.md +0 -3
- package/dist/subagents/designExpert/prompts/ui-patterns.md +7 -21
- package/dist/subagents/designExpert/skills/authExperience.md +60 -0
- package/dist/subagents/designExpert/skills/chatExperience.md +59 -0
- package/dist/subagents/designExpert/skills/dataViz.md +82 -0
- package/dist/subagents/designExpert/{prompts → skills}/images.md +6 -0
- package/dist/subagents/designExpert/skills/voiceExperience.md +103 -0
- package/dist/subagents/productVision/prompt.md +2 -0
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -681,10 +681,9 @@ The user has approved your implementation plan in .remy-plan.md. You may referen
|
|
|
681
681
|
}
|
|
682
682
|
}
|
|
683
683
|
|
|
684
|
-
// src/
|
|
684
|
+
// src/skillCatalog.ts
|
|
685
685
|
import fs5 from "fs";
|
|
686
686
|
import path3 from "path";
|
|
687
|
-
var SKILLS_DIR = assetPath("prompt", "skills");
|
|
688
687
|
function parseFrontmatter(content) {
|
|
689
688
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
690
689
|
if (!match) {
|
|
@@ -699,16 +698,16 @@ function parseFrontmatter(content) {
|
|
|
699
698
|
}
|
|
700
699
|
return fields;
|
|
701
700
|
}
|
|
702
|
-
function
|
|
701
|
+
function buildSkillCatalog(opts) {
|
|
703
702
|
let files;
|
|
704
703
|
try {
|
|
705
|
-
files = fs5.readdirSync(
|
|
704
|
+
files = fs5.readdirSync(opts.dir).filter((f) => f.endsWith(".md"));
|
|
706
705
|
} catch {
|
|
707
|
-
|
|
706
|
+
files = [];
|
|
708
707
|
}
|
|
709
708
|
const skills = [];
|
|
710
709
|
for (const file of files.sort()) {
|
|
711
|
-
const full = path3.join(
|
|
710
|
+
const full = path3.join(opts.dir, file);
|
|
712
711
|
const id = file.replace(/\.md$/, "");
|
|
713
712
|
const fields = parseFrontmatter(fs5.readFileSync(full, "utf-8"));
|
|
714
713
|
if (!fields.name || !fields.what || !fields.when) {
|
|
@@ -722,38 +721,58 @@ function loadCatalog() {
|
|
|
722
721
|
path: full
|
|
723
722
|
});
|
|
724
723
|
}
|
|
725
|
-
return
|
|
724
|
+
return {
|
|
725
|
+
skills,
|
|
726
|
+
ids: skills.map((s) => s.id),
|
|
727
|
+
get(id) {
|
|
728
|
+
return skills.find((s) => s.id === id);
|
|
729
|
+
},
|
|
730
|
+
readBody(skill) {
|
|
731
|
+
return fs5.readFileSync(skill.path, "utf-8").replace(/^---[\s\S]*?---\s*/, "").trim();
|
|
732
|
+
},
|
|
733
|
+
renderCatalogBlock() {
|
|
734
|
+
if (skills.length === 0) {
|
|
735
|
+
return "";
|
|
736
|
+
}
|
|
737
|
+
const entries = skills.map(
|
|
738
|
+
(s) => [
|
|
739
|
+
`### ${s.name} (\`${s.id}\`)`,
|
|
740
|
+
s.what,
|
|
741
|
+
"",
|
|
742
|
+
`When to load: ${s.when}`,
|
|
743
|
+
`Reference: ${s.path}`
|
|
744
|
+
].join("\n")
|
|
745
|
+
);
|
|
746
|
+
return `<${opts.tag}>
|
|
747
|
+
${opts.intro}
|
|
748
|
+
|
|
749
|
+
${entries.join("\n\n")}
|
|
750
|
+
</${opts.tag}>`;
|
|
751
|
+
}
|
|
752
|
+
};
|
|
726
753
|
}
|
|
727
|
-
|
|
728
|
-
|
|
754
|
+
|
|
755
|
+
// src/prompt/skills/_catalog.ts
|
|
756
|
+
var INTRO = `Platform capabilities most apps don't use, so their references are kept out of this prompt rather than competing for your attention on every task \u2014 not because they're marginal.
|
|
757
|
+
|
|
758
|
+
Read what follows as part of what the platform can do, not as a lookup table. Recognising that one of these fits a feature is your job, and proposing one is fair game \u2014 several of them are the difference between an app that works and an app worth showing off. When a trigger fires, load the reference with loadSkill before writing the code rather than after. Loading is cheap and expected; guessing at one of these APIs is not.
|
|
759
|
+
|
|
760
|
+
A loaded reference drops out of the conversation once it ages out. Re-read it at the path listed with readFile whenever you need it again.`;
|
|
761
|
+
var catalog = buildSkillCatalog({
|
|
762
|
+
dir: assetPath("prompt", "skills"),
|
|
763
|
+
tag: "available_skills",
|
|
764
|
+
intro: INTRO
|
|
765
|
+
});
|
|
766
|
+
var SKILLS = catalog.skills;
|
|
767
|
+
var SKILL_IDS = catalog.ids;
|
|
729
768
|
function getSkill(id) {
|
|
730
|
-
return
|
|
769
|
+
return catalog.get(id);
|
|
731
770
|
}
|
|
732
771
|
function readSkillBody(skill) {
|
|
733
|
-
return
|
|
772
|
+
return catalog.readBody(skill);
|
|
734
773
|
}
|
|
735
774
|
function loadSkillsCatalog() {
|
|
736
|
-
|
|
737
|
-
return "";
|
|
738
|
-
}
|
|
739
|
-
const entries = SKILLS.map(
|
|
740
|
-
(s) => [
|
|
741
|
-
`### ${s.name} (\`${s.id}\`)`,
|
|
742
|
-
s.what,
|
|
743
|
-
"",
|
|
744
|
-
`When to load: ${s.when}`,
|
|
745
|
-
`Reference: ${s.path}`
|
|
746
|
-
].join("\n")
|
|
747
|
-
);
|
|
748
|
-
return `<available_skills>
|
|
749
|
-
Platform capabilities most apps don't use, so their references are kept out of this prompt rather than competing for your attention on every task \u2014 not because they're marginal.
|
|
750
|
-
|
|
751
|
-
Read what follows as part of what the platform can do, not as a lookup table. Recognising that one of these fits a feature is your job, and proposing one is fair game \u2014 several of them are the difference between an app that works and an app worth showing off. When a trigger fires, load the reference with loadSkill before writing the code rather than after. Loading is cheap and expected; guessing at one of these APIs is not.
|
|
752
|
-
|
|
753
|
-
A loaded reference drops out of the conversation once it ages out. Re-read it at the path listed with readFile whenever you need it again.
|
|
754
|
-
|
|
755
|
-
${entries.join("\n\n")}
|
|
756
|
-
</available_skills>`;
|
|
775
|
+
return catalog.renderCatalogBlock();
|
|
757
776
|
}
|
|
758
777
|
|
|
759
778
|
// src/prompt/index.ts
|
|
@@ -5452,6 +5471,59 @@ async function execute8(input, _onLog, context) {
|
|
|
5452
5471
|
return copyEditorTool.execute(input, context);
|
|
5453
5472
|
}
|
|
5454
5473
|
|
|
5474
|
+
// src/subagents/designExpert/tools/loadSkill.ts
|
|
5475
|
+
var loadSkill_exports = {};
|
|
5476
|
+
__export(loadSkill_exports, {
|
|
5477
|
+
definition: () => definition9,
|
|
5478
|
+
execute: () => execute9
|
|
5479
|
+
});
|
|
5480
|
+
|
|
5481
|
+
// src/subagents/designExpert/skills/_catalog.ts
|
|
5482
|
+
var INTRO2 = `Deep craft references for specific surfaces, kept out of this prompt so they can go far beyond what a resident section could \u2014 full technique recipes, worked examples, quality bars. Recognising that one of these fits the brief is part of your job as much as the design work itself: when a trigger fires, load the reference with loadSkill before designing in that area, not after. The craft in these docs is the difference between a defaulted artifact and a designed one.
|
|
5483
|
+
|
|
5484
|
+
A loaded reference drops out of the conversation once it ages out. Re-read it at the path listed with readFile whenever you need it again.`;
|
|
5485
|
+
var designSkillCatalog = buildSkillCatalog({
|
|
5486
|
+
dir: assetPath("subagents/designExpert", "skills"),
|
|
5487
|
+
tag: "available_skills",
|
|
5488
|
+
intro: INTRO2
|
|
5489
|
+
});
|
|
5490
|
+
|
|
5491
|
+
// src/subagents/designExpert/tools/loadSkill.ts
|
|
5492
|
+
var definition9 = {
|
|
5493
|
+
name: "loadSkill",
|
|
5494
|
+
description: "Load the full craft reference for a design surface that isn't in your prompt. The available skills and the trigger for each are listed in <available_skills>. Load one before designing in its area, not after \u2014 these are hard-won technique recipes, and the defaulted version of these surfaces is exactly what they exist to prevent. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it.",
|
|
5495
|
+
inputSchema: {
|
|
5496
|
+
type: "object",
|
|
5497
|
+
properties: {
|
|
5498
|
+
skill: {
|
|
5499
|
+
type: "string",
|
|
5500
|
+
// Omitted when the catalog is empty: an empty enum is a schema no
|
|
5501
|
+
// provider accepts, and failing one tool call beats failing every
|
|
5502
|
+
// request if the docs ever go missing from a build.
|
|
5503
|
+
...designSkillCatalog.ids.length > 0 ? { enum: designSkillCatalog.ids } : {},
|
|
5504
|
+
description: "The skill id, as listed in <available_skills>."
|
|
5505
|
+
}
|
|
5506
|
+
},
|
|
5507
|
+
required: ["skill"]
|
|
5508
|
+
}
|
|
5509
|
+
};
|
|
5510
|
+
async function execute9(input) {
|
|
5511
|
+
const id = String(input.skill ?? "");
|
|
5512
|
+
const skill = designSkillCatalog.get(id);
|
|
5513
|
+
if (!skill) {
|
|
5514
|
+
return `Error: unknown skill "${id}". Available: ${designSkillCatalog.ids.join(", ") || "(none)"}`;
|
|
5515
|
+
}
|
|
5516
|
+
try {
|
|
5517
|
+
const body = designSkillCatalog.readBody(skill);
|
|
5518
|
+
return `${body}
|
|
5519
|
+
|
|
5520
|
+
---
|
|
5521
|
+
This reference lives at ${skill.path}. Re-read it with readFile if you need it again later \u2014 it won't stay in the conversation.`;
|
|
5522
|
+
} catch (err) {
|
|
5523
|
+
return `Error loading skill "${id}": ${err.message}`;
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
|
|
5455
5527
|
// src/subagents/designExpert/tools/index.ts
|
|
5456
5528
|
var tools = {
|
|
5457
5529
|
searchGoogle: searchGoogle_exports,
|
|
@@ -5465,7 +5537,8 @@ var tools = {
|
|
|
5465
5537
|
generateImages: generateImages_exports,
|
|
5466
5538
|
editImages: editImages_exports,
|
|
5467
5539
|
renderImage: renderImage_exports,
|
|
5468
|
-
polishCopy: polishCopy_exports
|
|
5540
|
+
polishCopy: polishCopy_exports,
|
|
5541
|
+
loadSkill: loadSkill_exports
|
|
5469
5542
|
};
|
|
5470
5543
|
var DESIGN_EXPERT_TOOLS = [
|
|
5471
5544
|
...COMMON_READ_TOOLS,
|
|
@@ -5661,6 +5734,12 @@ function getDesignExpertPrompt(onboardingState, opts) {
|
|
|
5661
5734
|
"{{ui_case_studies}}",
|
|
5662
5735
|
getUiInspirationSample(indices.uiInspiration)
|
|
5663
5736
|
);
|
|
5737
|
+
const skillsBlock = designSkillCatalog.renderCatalogBlock();
|
|
5738
|
+
if (skillsBlock) {
|
|
5739
|
+
prompt += `
|
|
5740
|
+
|
|
5741
|
+
${skillsBlock}`;
|
|
5742
|
+
}
|
|
5664
5743
|
prompt += "\n\n<!-- cache_breakpoint -->";
|
|
5665
5744
|
if (specContext) {
|
|
5666
5745
|
prompt += `
|
package/dist/index.js
CHANGED
|
@@ -3015,7 +3015,7 @@ var init_compactConversation = __esm({
|
|
|
3015
3015
|
}
|
|
3016
3016
|
});
|
|
3017
3017
|
|
|
3018
|
-
// src/
|
|
3018
|
+
// src/skillCatalog.ts
|
|
3019
3019
|
import fs11 from "fs";
|
|
3020
3020
|
import path5 from "path";
|
|
3021
3021
|
function parseFrontmatter(content) {
|
|
@@ -3032,16 +3032,16 @@ function parseFrontmatter(content) {
|
|
|
3032
3032
|
}
|
|
3033
3033
|
return fields;
|
|
3034
3034
|
}
|
|
3035
|
-
function
|
|
3035
|
+
function buildSkillCatalog(opts) {
|
|
3036
3036
|
let files;
|
|
3037
3037
|
try {
|
|
3038
|
-
files = fs11.readdirSync(
|
|
3038
|
+
files = fs11.readdirSync(opts.dir).filter((f) => f.endsWith(".md"));
|
|
3039
3039
|
} catch {
|
|
3040
|
-
|
|
3040
|
+
files = [];
|
|
3041
3041
|
}
|
|
3042
3042
|
const skills = [];
|
|
3043
3043
|
for (const file of files.sort()) {
|
|
3044
|
-
const full = path5.join(
|
|
3044
|
+
const full = path5.join(opts.dir, file);
|
|
3045
3045
|
const id = file.replace(/\.md$/, "");
|
|
3046
3046
|
const fields = parseFrontmatter(fs11.readFileSync(full, "utf-8"));
|
|
3047
3047
|
if (!fields.name || !fields.what || !fields.when) {
|
|
@@ -3055,45 +3055,70 @@ function loadCatalog() {
|
|
|
3055
3055
|
path: full
|
|
3056
3056
|
});
|
|
3057
3057
|
}
|
|
3058
|
-
return
|
|
3058
|
+
return {
|
|
3059
|
+
skills,
|
|
3060
|
+
ids: skills.map((s) => s.id),
|
|
3061
|
+
get(id) {
|
|
3062
|
+
return skills.find((s) => s.id === id);
|
|
3063
|
+
},
|
|
3064
|
+
readBody(skill) {
|
|
3065
|
+
return fs11.readFileSync(skill.path, "utf-8").replace(/^---[\s\S]*?---\s*/, "").trim();
|
|
3066
|
+
},
|
|
3067
|
+
renderCatalogBlock() {
|
|
3068
|
+
if (skills.length === 0) {
|
|
3069
|
+
return "";
|
|
3070
|
+
}
|
|
3071
|
+
const entries = skills.map(
|
|
3072
|
+
(s) => [
|
|
3073
|
+
`### ${s.name} (\`${s.id}\`)`,
|
|
3074
|
+
s.what,
|
|
3075
|
+
"",
|
|
3076
|
+
`When to load: ${s.when}`,
|
|
3077
|
+
`Reference: ${s.path}`
|
|
3078
|
+
].join("\n")
|
|
3079
|
+
);
|
|
3080
|
+
return `<${opts.tag}>
|
|
3081
|
+
${opts.intro}
|
|
3082
|
+
|
|
3083
|
+
${entries.join("\n\n")}
|
|
3084
|
+
</${opts.tag}>`;
|
|
3085
|
+
}
|
|
3086
|
+
};
|
|
3059
3087
|
}
|
|
3088
|
+
var init_skillCatalog = __esm({
|
|
3089
|
+
"src/skillCatalog.ts"() {
|
|
3090
|
+
"use strict";
|
|
3091
|
+
}
|
|
3092
|
+
});
|
|
3093
|
+
|
|
3094
|
+
// src/prompt/skills/_catalog.ts
|
|
3060
3095
|
function getSkill(id) {
|
|
3061
|
-
return
|
|
3096
|
+
return catalog.get(id);
|
|
3062
3097
|
}
|
|
3063
3098
|
function readSkillBody(skill) {
|
|
3064
|
-
return
|
|
3099
|
+
return catalog.readBody(skill);
|
|
3065
3100
|
}
|
|
3066
3101
|
function loadSkillsCatalog() {
|
|
3067
|
-
|
|
3068
|
-
return "";
|
|
3069
|
-
}
|
|
3070
|
-
const entries = SKILLS.map(
|
|
3071
|
-
(s) => [
|
|
3072
|
-
`### ${s.name} (\`${s.id}\`)`,
|
|
3073
|
-
s.what,
|
|
3074
|
-
"",
|
|
3075
|
-
`When to load: ${s.when}`,
|
|
3076
|
-
`Reference: ${s.path}`
|
|
3077
|
-
].join("\n")
|
|
3078
|
-
);
|
|
3079
|
-
return `<available_skills>
|
|
3080
|
-
Platform capabilities most apps don't use, so their references are kept out of this prompt rather than competing for your attention on every task \u2014 not because they're marginal.
|
|
3081
|
-
|
|
3082
|
-
Read what follows as part of what the platform can do, not as a lookup table. Recognising that one of these fits a feature is your job, and proposing one is fair game \u2014 several of them are the difference between an app that works and an app worth showing off. When a trigger fires, load the reference with loadSkill before writing the code rather than after. Loading is cheap and expected; guessing at one of these APIs is not.
|
|
3083
|
-
|
|
3084
|
-
A loaded reference drops out of the conversation once it ages out. Re-read it at the path listed with readFile whenever you need it again.
|
|
3085
|
-
|
|
3086
|
-
${entries.join("\n\n")}
|
|
3087
|
-
</available_skills>`;
|
|
3102
|
+
return catalog.renderCatalogBlock();
|
|
3088
3103
|
}
|
|
3089
|
-
var
|
|
3104
|
+
var INTRO, catalog, SKILLS, SKILL_IDS;
|
|
3090
3105
|
var init_catalog = __esm({
|
|
3091
|
-
"src/prompt/skills/
|
|
3106
|
+
"src/prompt/skills/_catalog.ts"() {
|
|
3092
3107
|
"use strict";
|
|
3108
|
+
init_skillCatalog();
|
|
3093
3109
|
init_assets();
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3110
|
+
INTRO = `Platform capabilities most apps don't use, so their references are kept out of this prompt rather than competing for your attention on every task \u2014 not because they're marginal.
|
|
3111
|
+
|
|
3112
|
+
Read what follows as part of what the platform can do, not as a lookup table. Recognising that one of these fits a feature is your job, and proposing one is fair game \u2014 several of them are the difference between an app that works and an app worth showing off. When a trigger fires, load the reference with loadSkill before writing the code rather than after. Loading is cheap and expected; guessing at one of these APIs is not.
|
|
3113
|
+
|
|
3114
|
+
A loaded reference drops out of the conversation once it ages out. Re-read it at the path listed with readFile whenever you need it again.`;
|
|
3115
|
+
catalog = buildSkillCatalog({
|
|
3116
|
+
dir: assetPath("prompt", "skills"),
|
|
3117
|
+
tag: "available_skills",
|
|
3118
|
+
intro: INTRO
|
|
3119
|
+
});
|
|
3120
|
+
SKILLS = catalog.skills;
|
|
3121
|
+
SKILL_IDS = catalog.ids;
|
|
3097
3122
|
}
|
|
3098
3123
|
});
|
|
3099
3124
|
|
|
@@ -6613,6 +6638,72 @@ var init_polishCopy = __esm({
|
|
|
6613
6638
|
}
|
|
6614
6639
|
});
|
|
6615
6640
|
|
|
6641
|
+
// src/subagents/designExpert/skills/_catalog.ts
|
|
6642
|
+
var INTRO2, designSkillCatalog;
|
|
6643
|
+
var init_catalog2 = __esm({
|
|
6644
|
+
"src/subagents/designExpert/skills/_catalog.ts"() {
|
|
6645
|
+
"use strict";
|
|
6646
|
+
init_skillCatalog();
|
|
6647
|
+
init_assets();
|
|
6648
|
+
INTRO2 = `Deep craft references for specific surfaces, kept out of this prompt so they can go far beyond what a resident section could \u2014 full technique recipes, worked examples, quality bars. Recognising that one of these fits the brief is part of your job as much as the design work itself: when a trigger fires, load the reference with loadSkill before designing in that area, not after. The craft in these docs is the difference between a defaulted artifact and a designed one.
|
|
6649
|
+
|
|
6650
|
+
A loaded reference drops out of the conversation once it ages out. Re-read it at the path listed with readFile whenever you need it again.`;
|
|
6651
|
+
designSkillCatalog = buildSkillCatalog({
|
|
6652
|
+
dir: assetPath("subagents/designExpert", "skills"),
|
|
6653
|
+
tag: "available_skills",
|
|
6654
|
+
intro: INTRO2
|
|
6655
|
+
});
|
|
6656
|
+
}
|
|
6657
|
+
});
|
|
6658
|
+
|
|
6659
|
+
// src/subagents/designExpert/tools/loadSkill.ts
|
|
6660
|
+
var loadSkill_exports = {};
|
|
6661
|
+
__export(loadSkill_exports, {
|
|
6662
|
+
definition: () => definition9,
|
|
6663
|
+
execute: () => execute9
|
|
6664
|
+
});
|
|
6665
|
+
async function execute9(input) {
|
|
6666
|
+
const id = String(input.skill ?? "");
|
|
6667
|
+
const skill = designSkillCatalog.get(id);
|
|
6668
|
+
if (!skill) {
|
|
6669
|
+
return `Error: unknown skill "${id}". Available: ${designSkillCatalog.ids.join(", ") || "(none)"}`;
|
|
6670
|
+
}
|
|
6671
|
+
try {
|
|
6672
|
+
const body = designSkillCatalog.readBody(skill);
|
|
6673
|
+
return `${body}
|
|
6674
|
+
|
|
6675
|
+
---
|
|
6676
|
+
This reference lives at ${skill.path}. Re-read it with readFile if you need it again later \u2014 it won't stay in the conversation.`;
|
|
6677
|
+
} catch (err) {
|
|
6678
|
+
return `Error loading skill "${id}": ${err.message}`;
|
|
6679
|
+
}
|
|
6680
|
+
}
|
|
6681
|
+
var definition9;
|
|
6682
|
+
var init_loadSkill2 = __esm({
|
|
6683
|
+
"src/subagents/designExpert/tools/loadSkill.ts"() {
|
|
6684
|
+
"use strict";
|
|
6685
|
+
init_catalog2();
|
|
6686
|
+
definition9 = {
|
|
6687
|
+
name: "loadSkill",
|
|
6688
|
+
description: "Load the full craft reference for a design surface that isn't in your prompt. The available skills and the trigger for each are listed in <available_skills>. Load one before designing in its area, not after \u2014 these are hard-won technique recipes, and the defaulted version of these surfaces is exactly what they exist to prevent. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it.",
|
|
6689
|
+
inputSchema: {
|
|
6690
|
+
type: "object",
|
|
6691
|
+
properties: {
|
|
6692
|
+
skill: {
|
|
6693
|
+
type: "string",
|
|
6694
|
+
// Omitted when the catalog is empty: an empty enum is a schema no
|
|
6695
|
+
// provider accepts, and failing one tool call beats failing every
|
|
6696
|
+
// request if the docs ever go missing from a build.
|
|
6697
|
+
...designSkillCatalog.ids.length > 0 ? { enum: designSkillCatalog.ids } : {},
|
|
6698
|
+
description: "The skill id, as listed in <available_skills>."
|
|
6699
|
+
}
|
|
6700
|
+
},
|
|
6701
|
+
required: ["skill"]
|
|
6702
|
+
}
|
|
6703
|
+
};
|
|
6704
|
+
}
|
|
6705
|
+
});
|
|
6706
|
+
|
|
6616
6707
|
// src/subagents/designExpert/tools/index.ts
|
|
6617
6708
|
async function executeDesignExpertTool(name, input, context, toolCallId, onLog) {
|
|
6618
6709
|
const tool = tools[name];
|
|
@@ -6636,6 +6727,7 @@ var init_tools4 = __esm({
|
|
|
6636
6727
|
init_editImages();
|
|
6637
6728
|
init_renderImage();
|
|
6638
6729
|
init_polishCopy();
|
|
6730
|
+
init_loadSkill2();
|
|
6639
6731
|
init_screenshot2();
|
|
6640
6732
|
tools = {
|
|
6641
6733
|
searchGoogle: searchGoogle_exports,
|
|
@@ -6649,7 +6741,8 @@ var init_tools4 = __esm({
|
|
|
6649
6741
|
generateImages: generateImages_exports,
|
|
6650
6742
|
editImages: editImages_exports,
|
|
6651
6743
|
renderImage: renderImage_exports,
|
|
6652
|
-
polishCopy: polishCopy_exports
|
|
6744
|
+
polishCopy: polishCopy_exports,
|
|
6745
|
+
loadSkill: loadSkill_exports
|
|
6653
6746
|
};
|
|
6654
6747
|
DESIGN_EXPERT_TOOLS = [
|
|
6655
6748
|
...COMMON_READ_TOOLS,
|
|
@@ -6918,6 +7011,12 @@ function getDesignExpertPrompt(onboardingState, opts) {
|
|
|
6918
7011
|
"{{ui_case_studies}}",
|
|
6919
7012
|
getUiInspirationSample(indices.uiInspiration)
|
|
6920
7013
|
);
|
|
7014
|
+
const skillsBlock = designSkillCatalog.renderCatalogBlock();
|
|
7015
|
+
if (skillsBlock) {
|
|
7016
|
+
prompt += `
|
|
7017
|
+
|
|
7018
|
+
${skillsBlock}`;
|
|
7019
|
+
}
|
|
6921
7020
|
prompt += "\n\n<!-- cache_breakpoint -->";
|
|
6922
7021
|
if (specContext) {
|
|
6923
7022
|
prompt += `
|
|
@@ -6952,6 +7051,7 @@ var init_prompt2 = __esm({
|
|
|
6952
7051
|
"src/subagents/designExpert/prompt.ts"() {
|
|
6953
7052
|
"use strict";
|
|
6954
7053
|
init_assets();
|
|
7054
|
+
init_catalog2();
|
|
6955
7055
|
init_context();
|
|
6956
7056
|
init_orgContext();
|
|
6957
7057
|
init_sampleCache();
|
|
@@ -202,25 +202,23 @@ export async function createPurchaseOrder(input: {
|
|
|
202
202
|
|
|
203
203
|
A method can return immediately while kicking off slow work (like `runTask()`) that continues in the background. Don't await the slow call — use `.then()` / `.catch()` to update the record when it completes, and return an early result to the caller. The frontend polls the record's status to track progress. Wrap background chains other than `runTask()` in `mindstudio.waitUntil(...)` so the platform keeps the sandbox alive for them and records an interruption if they're cut short — `runTask()` registers itself automatically.
|
|
204
204
|
|
|
205
|
-
The example below shows the fire-and-forget shape, not a complete `runTask()` call. Load the `taskAgents` skill before writing one — configuring its tools,
|
|
205
|
+
The example below shows the fire-and-forget shape, not a complete `runTask()` call. Load the `taskAgents` skill before writing one — configuring its tools, the `outputSchema` output contract, and handling failures are all there, and none of them are visible here.
|
|
206
206
|
|
|
207
207
|
```typescript
|
|
208
208
|
export async function enrichRestaurant(input: { id: string; name: string }) {
|
|
209
209
|
await Restaurants.update(input.id, { status: 'enriching' });
|
|
210
210
|
|
|
211
211
|
// Fire — don't await
|
|
212
|
-
mindstudio.runTask
|
|
212
|
+
mindstudio.runTask({
|
|
213
213
|
prompt: '...',
|
|
214
214
|
input: { name: input.name },
|
|
215
215
|
tools: ['searchGoogle', 'fetchUrl', 'generateImage'],
|
|
216
|
-
|
|
216
|
+
outputSchema: { type: 'object', properties: { /* ... */ }, required: [/* ... */] },
|
|
217
217
|
model: 'claude-5-sonnet',
|
|
218
218
|
}).then(async (result) => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
await Restaurants.update(input.id, { status: 'failed' });
|
|
223
|
-
}
|
|
219
|
+
// outputSchema means result.output is validated and typed — a task that
|
|
220
|
+
// can't produce conforming output rejects into the .catch instead.
|
|
221
|
+
await Restaurants.update(input.id, { ...result.output, status: 'complete' });
|
|
224
222
|
}).catch(async () => {
|
|
225
223
|
await Restaurants.update(input.id, { status: 'failed' });
|
|
226
224
|
});
|
|
@@ -112,13 +112,7 @@ await chat.deleteThread(thread.id);
|
|
|
112
112
|
await chat.claimThread(thread.id);
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
**Client tools** — a tool whose effect happens in the browser (open a sheet, navigate, highlight)
|
|
116
|
-
is declared with `target: "client"` and a `name` + inline `inputSchema` instead of a `method`
|
|
117
|
-
(names must not collide with method ids; the schema is authored — there's no method contract to
|
|
118
|
-
derive it from). The agent's invocation arrives as the `client_tool_call` stream event / the
|
|
119
|
-
`onClientToolCall` callback on `sendMessage`; run the action there. Fire-and-forget on this
|
|
120
|
-
surface: the agent is told the action was displayed and keeps going — the user's next message
|
|
121
|
-
closes the loop.
|
|
115
|
+
**Client tools** — a tool whose effect happens in the browser (open a sheet, navigate, highlight) is declared with `target: "client"` and a `name` + inline `inputSchema` instead of a `method` (names must not collide with method ids; the schema is authored — there's no method contract to derive it from). The agent's invocation arrives as the `client_tool_call` stream event / the `onClientToolCall` callback on `sendMessage`; run the action there. Fire-and-forget on this surface: the agent is told the action was displayed and keeps going — the user's next message closes the loop.
|
|
122
116
|
|
|
123
117
|
```js
|
|
124
118
|
await chat.sendMessage(thread.id, text, {
|
|
@@ -183,7 +177,7 @@ Images are sent as vision input; documents have their text extracted server-side
|
|
|
183
177
|
|
|
184
178
|
### Layout
|
|
185
179
|
|
|
186
|
-
|
|
180
|
+
The chat UI is a first-class design deliverable, not a bolted-on widget. Bring in `visualDesignExpert` for the chat experience as a whole — message design, streaming behavior, tool-activity presentation, the composer, and the empty state, composed as one surface (it has a dedicated craft reference for exactly this) — and implement what it prescribes. The rules below are the floor, not the direction.
|
|
187
181
|
|
|
188
182
|
User messages visually distinct from assistant messages (right-aligned, different background, or both). Keep it clean — no avatars unless they add meaning. Generous vertical spacing between messages so the conversation breathes. Use clean, beautiful animation where it is additive.
|
|
189
183
|
|
|
@@ -236,8 +230,7 @@ The chat UI uses the app's design system — colors, typography, voice from `@br
|
|
|
236
230
|
|
|
237
231
|
## Spec: `src/interfaces/agent.md`
|
|
238
232
|
|
|
239
|
-
The human-readable spec. Frontmatter contains structured fields; the prose body is the behavioral spec —
|
|
240
|
-
voice, personality, capabilities, rules — written in MSFM.
|
|
233
|
+
The human-readable spec. Frontmatter contains structured fields; the prose body is the behavioral spec — voice, personality, capabilities, rules — written in MSFM.
|
|
241
234
|
|
|
242
235
|
```yaml
|
|
243
236
|
---
|
|
@@ -250,15 +243,10 @@ description: Conversational agent that helps users manage their to-do list.
|
|
|
250
243
|
Frontmatter fields:
|
|
251
244
|
|
|
252
245
|
- `name` — agent display name
|
|
253
|
-
- `model` — JSON string with `model` (MindStudio model ID), `temperature`, `maxResponseTokens`, and
|
|
254
|
-
optional `config` (model-specific settings like `reasoning`, `tools`, etc.). Ask `askMindStudioSdk`
|
|
255
|
-
for available model IDs and their config options — MindStudio's ids don't match vendor ids, so treat
|
|
256
|
-
any id in this document's examples as illustrative rather than current. The user's UI has a visual picker for changing it later, so only validate
|
|
257
|
-
the model when you're setting it; if the value changes afterwards, assume it's correct.
|
|
246
|
+
- `model` — JSON string with `model` (MindStudio model ID), `temperature`, `maxResponseTokens`, and optional `config` (model-specific settings like `reasoning`, `tools`, etc.). Ask `askMindStudioSdk` for available model IDs and their config options — MindStudio's ids don't match vendor ids, so treat any id in this document's examples as illustrative rather than current. The user's UI has a visual picker for changing it later, so only validate the model when you're setting it; if the value changes afterwards, assume it's correct.
|
|
258
247
|
- `description` — one-liner for agent card/listing
|
|
259
248
|
|
|
260
|
-
The prose body contains sections like Voice & Personality, Capabilities, Behavior — whatever structure
|
|
261
|
-
serves the agent's character. This is compiled into the system prompt and tool descriptions.
|
|
249
|
+
The prose body contains sections like Voice & Personality, Capabilities, Behavior — whatever structure serves the agent's character. This is compiled into the system prompt and tool descriptions.
|
|
262
250
|
|
|
263
251
|
## Compiled Output: `dist/interfaces/agent/`
|
|
264
252
|
|
|
@@ -291,9 +279,7 @@ dist/interfaces/agent/
|
|
|
291
279
|
}
|
|
292
280
|
```
|
|
293
281
|
|
|
294
|
-
**The token-limit field is renamed during compilation.** The spec frontmatter calls it
|
|
295
|
-
`maxResponseTokens`; the compiled `agent.json` calls it `maxTokens`. Same value, two names — carry it
|
|
296
|
-
across rather than copying the key.
|
|
282
|
+
**The token-limit field is renamed during compilation.** The spec frontmatter calls it `maxResponseTokens`; the compiled `agent.json` calls it `maxTokens`. Same value, two names — carry it across rather than copying the key.
|
|
297
283
|
|
|
298
284
|
| Field | Description |
|
|
299
285
|
|-------|-------------|
|
|
@@ -313,29 +299,17 @@ Declare it in `mindstudio.json`:
|
|
|
313
299
|
|
|
314
300
|
## Auth
|
|
315
301
|
|
|
316
|
-
**Every agent config declares an `auth` block.** Agent chat spends the owner's money on every
|
|
317
|
-
message without necessarily touching a backend method, so the platform gates the lobby itself —
|
|
318
|
-
enforced at thread creation and message send:
|
|
302
|
+
**Every agent config declares an `auth` block.** Agent chat spends the owner's money on every message without necessarily touching a backend method, so the platform gates the lobby itself — enforced at thread creation and message send:
|
|
319
303
|
|
|
320
304
|
```json
|
|
321
305
|
"auth": { "requireUser": true, "requireRole": ["support-agent", "admin"] }
|
|
322
306
|
```
|
|
323
307
|
|
|
324
|
-
- `requireUser: true` — only authenticated app users may chat; `false` — anyone, including
|
|
325
|
-
|
|
326
|
-
-
|
|
327
|
-
(OR semantics, same as the backend `auth.requireRole(...)`). Omit or leave empty for no role
|
|
328
|
-
gate. Requires `requireUser: true`. Unknown role ids fail the build.
|
|
329
|
-
- Denials surface to the frontend SDK as `MindStudioInterfaceError` with code `auth_required`
|
|
330
|
-
(401) or `role_required` (403).
|
|
308
|
+
- `requireUser: true` — only authenticated app users may chat; `false` — anyone, including anonymous visitors. Most apps want `true`; choose `false` deliberately (a public concierge).
|
|
309
|
+
- `requireRole` (optional) — the user must hold **at least one** of the listed manifest role ids (OR semantics, same as the backend `auth.requireRole(...)`). Omit or leave empty for no role gate. Requires `requireUser: true`. Unknown role ids fail the build.
|
|
310
|
+
- Denials surface to the frontend SDK as `MindStudioInterfaceError` with code `auth_required` (401) or `role_required` (403).
|
|
331
311
|
- Dev preview is exempt — the builder is never locked out while testing.
|
|
332
|
-
- Older compiled apps without the block fall back to the manifest's `auth.enabled` (auth-enabled →
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
Once inside, agent chat runs as the **authenticated user**, not as a system role — tool calls
|
|
336
|
-
carry that user's roles, so a method gated with `auth.requireRole` behaves exactly as it would if
|
|
337
|
-
the user had called it from the web frontend. That's what makes exposing real methods safe; it's
|
|
338
|
-
also why role restrictions belong in the tool descriptions, so the agent can decline gracefully
|
|
339
|
-
instead of surfacing a rejection. Anonymous visitors (when allowed) are scoped by a per-browser
|
|
340
|
-
visitor identity: their threads are private to their browser, and gated methods still reject.
|
|
312
|
+
- Older compiled apps without the block fall back to the manifest's `auth.enabled` (auth-enabled → users only; no auth → public). New configs always declare it explicitly.
|
|
313
|
+
|
|
314
|
+
Once inside, agent chat runs as the **authenticated user**, not as a system role — tool calls carry that user's roles, so a method gated with `auth.requireRole` behaves exactly as it would if the user had called it from the web frontend. That's what makes exposing real methods safe; it's also why role restrictions belong in the tool descriptions, so the agent can decline gracefully instead of surfacing a rejection. Anonymous visitors (when allowed) are scoped by a per-browser visitor identity: their threads are private to their browser, and gated methods still reject.
|
|
341
315
|
|
|
@@ -390,13 +390,7 @@ Roles are declared in the manifest, stored as an array column on the user table,
|
|
|
390
390
|
|
|
391
391
|
## Interface-Level Auth (Agent + Voice)
|
|
392
392
|
|
|
393
|
-
Agent and voice interfaces additionally declare auth **in their config** (a required `auth` key:
|
|
394
|
-
`{ "requireUser": boolean, "requireRole"?: string[] }`) because those sessions spend money without
|
|
395
|
-
necessarily calling a backend method — the platform gates the lobby itself, before any model or
|
|
396
|
-
media spend. `requireRole` uses the same manifest role ids with OR semantics. Denials reach the
|
|
397
|
-
frontend SDK as `MindStudioInterfaceError` codes `auth_required` (401) and `role_required` (403) —
|
|
398
|
-
route them to the app's login flow. See the `agentInterfaces` / `voiceInterfaces` skills for the
|
|
399
|
-
full contract. Method-level `auth.requireRole(...)` checks still apply to every tool call inside.
|
|
393
|
+
Agent and voice interfaces additionally declare auth **in their config** (a required `auth` key: `{ "requireUser": boolean, "requireRole"?: string[] }`) because those sessions spend money without necessarily calling a backend method — the platform gates the lobby itself, before any model or media spend. `requireRole` uses the same manifest role ids with OR semantics. Denials reach the frontend SDK as `MindStudioInterfaceError` codes `auth_required` (401) and `role_required` (403) — route them to the app's login flow. See the `agentInterfaces` / `voiceInterfaces` skills for the full contract. Method-level `auth.requireRole(...)` checks still apply to every tool call inside.
|
|
400
394
|
|
|
401
395
|
## Apps Without Auth
|
|
402
396
|
|