@anuma/sdk 6.38.0 → 6.39.1
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/expo/index.cjs +373 -155
- package/dist/expo/index.d.mts +5659 -5644
- package/dist/expo/index.d.ts +5659 -5644
- package/dist/expo/index.mjs +372 -155
- package/dist/index.cjs +50 -34
- package/dist/index.d.mts +62 -62
- package/dist/index.d.ts +62 -62
- package/dist/index.mjs +50 -34
- package/dist/react/index.cjs +373 -150
- package/dist/react/index.d.mts +7040 -7025
- package/dist/react/index.d.ts +7040 -7025
- package/dist/react/index.mjs +372 -150
- package/dist/server/index.cjs +141 -73
- package/dist/server/index.d.mts +6181 -6171
- package/dist/server/index.d.ts +6181 -6171
- package/dist/server/index.mjs +141 -73
- package/dist/tools/index.cjs +10 -8
- package/dist/tools/index.d.mts +10 -6
- package/dist/tools/index.d.ts +10 -6
- package/dist/tools/index.mjs +10 -8
- package/dist/tools/selection/index.cjs +50 -34
- package/dist/tools/selection/index.d.mts +5 -1
- package/dist/tools/selection/index.d.ts +5 -1
- package/dist/tools/selection/index.mjs +50 -34
- package/package.json +1 -1
package/dist/server/index.mjs
CHANGED
|
@@ -18764,15 +18764,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
|
|
|
18764
18764
|
|
|
18765
18765
|
Once the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.
|
|
18766
18766
|
|
|
18767
|
-
DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.
|
|
18767
|
+
DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.
|
|
18768
|
+
|
|
18769
|
+
EDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.
|
|
18768
18770
|
|
|
18769
18771
|
WORKFLOW:
|
|
18770
18772
|
1. NEVER output code as text or markdown. ALWAYS use tools.
|
|
18771
18773
|
2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
|
|
18772
18774
|
3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered "42: <text>" \u2014 the prefix is display-only; never copy it into "find". Each "find" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.
|
|
18773
18775
|
4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.
|
|
18774
|
-
5.
|
|
18775
|
-
6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip
|
|
18776
|
+
5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.
|
|
18777
|
+
6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.
|
|
18776
18778
|
7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
|
|
18777
18779
|
|
|
18778
18780
|
STRUCTURE:
|
|
@@ -18917,12 +18919,13 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
|
|
|
18917
18919
|
if (!cache) return true;
|
|
18918
18920
|
return Date.now() - cache.timestamp > expirationMs;
|
|
18919
18921
|
}
|
|
18920
|
-
function buildCacheEntry(tools, checksum) {
|
|
18922
|
+
function buildCacheEntry(tools, checksum, etag) {
|
|
18921
18923
|
return {
|
|
18922
18924
|
tools,
|
|
18923
18925
|
timestamp: Date.now(),
|
|
18924
18926
|
version: CACHE_VERSION,
|
|
18925
|
-
...checksum && { checksum }
|
|
18927
|
+
...checksum && { checksum },
|
|
18928
|
+
...etag && { etag }
|
|
18926
18929
|
};
|
|
18927
18930
|
}
|
|
18928
18931
|
function writeLocalStorageCache(entry) {
|
|
@@ -18957,19 +18960,36 @@ function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
|
|
|
18957
18960
|
const cachedChecksum = getToolsChecksum(cache);
|
|
18958
18961
|
return cachedChecksum instanceof Promise ? cachedChecksum.then(decide) : decide(cachedChecksum);
|
|
18959
18962
|
}
|
|
18960
|
-
async function fetchServerToolsFromApi(baseUrl,
|
|
18961
|
-
const
|
|
18963
|
+
async function fetchServerToolsFromApi(baseUrl, authHeaders, etag) {
|
|
18964
|
+
const request = (validator) => fetch(`${baseUrl}/api/v1/tools`, {
|
|
18962
18965
|
method: "GET",
|
|
18963
18966
|
headers: {
|
|
18964
|
-
|
|
18965
|
-
"Content-Type": "application/json"
|
|
18967
|
+
...authHeaders,
|
|
18968
|
+
"Content-Type": "application/json",
|
|
18969
|
+
...validator && { "If-None-Match": validator }
|
|
18966
18970
|
}
|
|
18967
18971
|
});
|
|
18972
|
+
let response;
|
|
18973
|
+
try {
|
|
18974
|
+
response = await request(etag);
|
|
18975
|
+
} catch (error) {
|
|
18976
|
+
if (!etag || !(error instanceof TypeError)) throw error;
|
|
18977
|
+
etag = void 0;
|
|
18978
|
+
response = await request();
|
|
18979
|
+
}
|
|
18980
|
+
if (etag && response.status === 304) {
|
|
18981
|
+
return { notModified: true };
|
|
18982
|
+
}
|
|
18968
18983
|
if (!response.ok) {
|
|
18969
18984
|
throw new Error(`Failed to fetch server tools: ${response.status}`);
|
|
18970
18985
|
}
|
|
18971
18986
|
const data = await response.json();
|
|
18972
|
-
|
|
18987
|
+
const responseEtag = response.headers?.get("ETag") ?? void 0;
|
|
18988
|
+
return {
|
|
18989
|
+
notModified: false,
|
|
18990
|
+
...convertServerToolsResponse(data),
|
|
18991
|
+
...responseEtag && { etag: responseEtag }
|
|
18992
|
+
};
|
|
18973
18993
|
}
|
|
18974
18994
|
async function getServerTools(options) {
|
|
18975
18995
|
const {
|
|
@@ -19001,34 +19021,30 @@ async function getServerTools(options) {
|
|
|
19001
19021
|
try {
|
|
19002
19022
|
const { BASE_URL: BASE_URL2 } = await import("./clientConfig-VIMT6Q32.mjs");
|
|
19003
19023
|
const effectiveBaseUrl = baseUrl ?? BASE_URL2;
|
|
19024
|
+
const validator = cached && !forceRefresh ? cached.etag : void 0;
|
|
19025
|
+
let authHeaders;
|
|
19004
19026
|
if (apiKey) {
|
|
19005
|
-
|
|
19006
|
-
|
|
19007
|
-
|
|
19008
|
-
|
|
19009
|
-
|
|
19010
|
-
}
|
|
19011
|
-
});
|
|
19012
|
-
if (!response.ok) {
|
|
19013
|
-
throw new Error(`Failed to fetch server tools: ${response.status}`);
|
|
19027
|
+
authHeaders = { "X-API-Key": apiKey };
|
|
19028
|
+
} else {
|
|
19029
|
+
if (!getToken) {
|
|
19030
|
+
getLogger().warn("[serverTools] No auth method available for fetching tools");
|
|
19031
|
+
return cached?.tools ?? [];
|
|
19014
19032
|
}
|
|
19015
|
-
const
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
|
|
19019
|
-
|
|
19020
|
-
|
|
19021
|
-
getLogger().warn("[serverTools] No auth method available for fetching tools");
|
|
19022
|
-
return cached?.tools ?? [];
|
|
19033
|
+
const token = await getToken();
|
|
19034
|
+
if (!token) {
|
|
19035
|
+
getLogger().warn("[serverTools] No auth token available for fetching tools");
|
|
19036
|
+
return cached?.tools ?? [];
|
|
19037
|
+
}
|
|
19038
|
+
authHeaders = { Authorization: `Bearer ${token}` };
|
|
19023
19039
|
}
|
|
19024
|
-
const
|
|
19025
|
-
if (
|
|
19026
|
-
|
|
19027
|
-
|
|
19040
|
+
const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
|
|
19041
|
+
if (result.notModified) {
|
|
19042
|
+
const confirmed = cached;
|
|
19043
|
+
await persistCache({ ...confirmed, timestamp: Date.now() });
|
|
19044
|
+
return confirmed.tools;
|
|
19028
19045
|
}
|
|
19029
|
-
|
|
19030
|
-
|
|
19031
|
-
return tools;
|
|
19046
|
+
await persistCache(buildCacheEntry(result.tools, result.checksum, result.etag));
|
|
19047
|
+
return result.tools;
|
|
19032
19048
|
} catch (error) {
|
|
19033
19049
|
getLogger().error("[serverTools] Failed to fetch server tools:", error);
|
|
19034
19050
|
if (cached?.tools) {
|
|
@@ -32242,7 +32258,6 @@ async function recall(query, ctx, options = {}) {
|
|
|
32242
32258
|
}
|
|
32243
32259
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
32244
32260
|
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
32245
|
-
const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
|
|
32246
32261
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
32247
32262
|
const prepStart = nowMs2();
|
|
32248
32263
|
let sharedEmbedMs = 0;
|
|
@@ -32271,13 +32286,12 @@ async function recall(query, ctx, options = {}) {
|
|
|
32271
32286
|
safeLane(
|
|
32272
32287
|
"graph",
|
|
32273
32288
|
() => graphLaneFailed = true,
|
|
32274
|
-
() => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(
|
|
32275
|
-
|
|
32276
|
-
|
|
32277
|
-
|
|
32278
|
-
|
|
32279
|
-
|
|
32280
|
-
})
|
|
32289
|
+
() => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(
|
|
32290
|
+
query,
|
|
32291
|
+
ctx,
|
|
32292
|
+
flags.traverse,
|
|
32293
|
+
graphTraversalOptions(options, flags.traverse)
|
|
32294
|
+
)
|
|
32281
32295
|
),
|
|
32282
32296
|
wantsTemporal ? safeLane(
|
|
32283
32297
|
"temporal",
|
|
@@ -32496,6 +32510,16 @@ function toFactMemory(r, now) {
|
|
|
32496
32510
|
updatedAt: r.updatedAt ?? /* @__PURE__ */ new Date(0)
|
|
32497
32511
|
};
|
|
32498
32512
|
}
|
|
32513
|
+
function graphTraversalOptions(options, traverse) {
|
|
32514
|
+
const refineNeighbors = traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
|
|
32515
|
+
return {
|
|
32516
|
+
...options.maxHops !== void 0 && { maxHops: options.maxHops },
|
|
32517
|
+
...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
|
|
32518
|
+
...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
|
|
32519
|
+
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
32520
|
+
...refineNeighbors && { refineNeighbors }
|
|
32521
|
+
};
|
|
32522
|
+
}
|
|
32499
32523
|
async function buildGraphLaneRanking(query, ctx, traverse = false, traversalOptions = {}) {
|
|
32500
32524
|
const entityCtx = ctx.entityCtx ?? ctx.vaultCtx?.entityCtx;
|
|
32501
32525
|
if (!entityCtx) return [];
|
|
@@ -32661,24 +32685,33 @@ function isDumpQuery(query) {
|
|
|
32661
32685
|
return false;
|
|
32662
32686
|
}
|
|
32663
32687
|
async function listRecentFacts(ctx, limit, toolOptions) {
|
|
32688
|
+
const store = toolOptions?.memoryStore;
|
|
32664
32689
|
const vaultCtx = ctx.vaultCtx;
|
|
32665
|
-
if (!vaultCtx) return [];
|
|
32666
|
-
const
|
|
32690
|
+
if (!vaultCtx && !store) return [];
|
|
32691
|
+
const read = (ids) => store ? store.list({ memoryIds: ids }) : getVaultMemoriesByIdsOp(vaultCtx, ids);
|
|
32692
|
+
const filters = {
|
|
32667
32693
|
...toolOptions?.scopes && { scopes: toolOptions.scopes },
|
|
32668
|
-
...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds }
|
|
32694
|
+
...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds }
|
|
32695
|
+
};
|
|
32696
|
+
const project = (size) => store ? store.listProjections({ ...filters, limit: size }) : getVaultRankingProjectionsOp(vaultCtx, {
|
|
32697
|
+
...filters,
|
|
32669
32698
|
...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId }
|
|
32670
32699
|
});
|
|
32671
32700
|
const readable = [];
|
|
32672
|
-
|
|
32673
|
-
|
|
32674
|
-
const
|
|
32675
|
-
|
|
32676
|
-
|
|
32677
|
-
|
|
32678
|
-
const
|
|
32679
|
-
|
|
32680
|
-
|
|
32701
|
+
let start = 0;
|
|
32702
|
+
for (let size = limit; readable.length < limit; size *= 2) {
|
|
32703
|
+
const ordered = await project(size);
|
|
32704
|
+
for (let i = start; i < ordered.length && readable.length < limit; i += limit) {
|
|
32705
|
+
const batch = ordered.slice(i, i + limit).map((p) => p.uniqueId);
|
|
32706
|
+
const byId = new Map((await read(batch)).map((m) => [m.uniqueId, m]));
|
|
32707
|
+
for (const id of batch) {
|
|
32708
|
+
const m = byId.get(id);
|
|
32709
|
+
if (m && !isEncrypted(m.content)) readable.push(m);
|
|
32710
|
+
if (readable.length >= limit) break;
|
|
32711
|
+
}
|
|
32681
32712
|
}
|
|
32713
|
+
if (!store || ordered.length < size) break;
|
|
32714
|
+
start = ordered.length;
|
|
32682
32715
|
}
|
|
32683
32716
|
return readable.map((m) => ({
|
|
32684
32717
|
id: m.uniqueId,
|
|
@@ -32695,6 +32728,8 @@ async function listRecentFacts(ctx, limit, toolOptions) {
|
|
|
32695
32728
|
}));
|
|
32696
32729
|
}
|
|
32697
32730
|
function createRecallTool(ctx, toolOptions, callbacks) {
|
|
32731
|
+
if (toolOptions?.memoryStore && toolOptions.folderId !== void 0)
|
|
32732
|
+
throw new Error("Folders are not supported with a memoryStore");
|
|
32698
32733
|
const defaultTypes = toolOptions?.types ?? ["fact", "chunk"];
|
|
32699
32734
|
const defaultLimit = toolOptions?.limit ?? DEFAULT_LIMIT2;
|
|
32700
32735
|
const defaultBudget = toolOptions?.budget ?? DEFAULT_BUDGET2;
|
|
@@ -32766,7 +32801,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
32766
32801
|
let surfaced = 0;
|
|
32767
32802
|
try {
|
|
32768
32803
|
let recallDegraded = [];
|
|
32769
|
-
const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && ctx.vaultCtx !== void 0;
|
|
32804
|
+
const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && (ctx.vaultCtx !== void 0 || toolOptions?.memoryStore !== void 0);
|
|
32770
32805
|
let result;
|
|
32771
32806
|
if (wantsRecent) {
|
|
32772
32807
|
result = { memories: await listRecentFacts(ctx, effectiveLimit, toolOptions) };
|
|
@@ -33268,6 +33303,7 @@ function createLocalMemoryStore(options) {
|
|
|
33268
33303
|
});
|
|
33269
33304
|
};
|
|
33270
33305
|
return {
|
|
33306
|
+
masksEmbeddingInput: options.embeddingOptions.maskInput !== void 0,
|
|
33271
33307
|
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
33272
33308
|
get: (id) => getVaultMemoryOp(vaultCtx, id),
|
|
33273
33309
|
listArchived: async () => {
|
|
@@ -33349,6 +33385,22 @@ function createLocalMemoryStore(options) {
|
|
|
33349
33385
|
{ vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
33350
33386
|
retainOptions
|
|
33351
33387
|
),
|
|
33388
|
+
factSource: {
|
|
33389
|
+
search: (query, searchOptions) => searchVaultMemoriesWithSize(
|
|
33390
|
+
query,
|
|
33391
|
+
vaultCtx,
|
|
33392
|
+
options.embeddingOptions,
|
|
33393
|
+
vaultCache,
|
|
33394
|
+
searchOptions
|
|
33395
|
+
),
|
|
33396
|
+
graphRanking: (query, traverse, recallOptions) => buildGraphLaneRanking(
|
|
33397
|
+
query,
|
|
33398
|
+
{ vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions },
|
|
33399
|
+
traverse,
|
|
33400
|
+
graphTraversalOptions(recallOptions, traverse)
|
|
33401
|
+
),
|
|
33402
|
+
temporalRanking: (query, now) => buildTemporalLaneRanking(query, vaultCtx, now)
|
|
33403
|
+
},
|
|
33352
33404
|
subscribe: (onChange, subscribeOptions) => {
|
|
33353
33405
|
const afterFirst = () => {
|
|
33354
33406
|
let first = true;
|
|
@@ -35039,19 +35091,20 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
35039
35091
|
const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
|
|
35040
35092
|
const folderId = searchOptions?.folderId ?? argFolderId;
|
|
35041
35093
|
if (searchOptions?.useFusion === false) {
|
|
35042
|
-
const
|
|
35094
|
+
const legacyOptions = {
|
|
35095
|
+
limit: requestLimit,
|
|
35096
|
+
minSimilarity,
|
|
35097
|
+
useFusion: false,
|
|
35098
|
+
...tuningForward,
|
|
35099
|
+
...folderId !== void 0 && { folderId },
|
|
35100
|
+
...searchOptions?.scopes && { scopes: searchOptions.scopes }
|
|
35101
|
+
};
|
|
35102
|
+
const { results: legacy, embeddingsUnavailable } = "retain" in vaultCtx ? await vaultCtx.factSource.search(query, legacyOptions) : await searchVaultMemoriesWithSize(
|
|
35043
35103
|
query,
|
|
35044
35104
|
vaultCtx,
|
|
35045
35105
|
embeddingOptions,
|
|
35046
35106
|
cache,
|
|
35047
|
-
|
|
35048
|
-
limit: requestLimit,
|
|
35049
|
-
minSimilarity,
|
|
35050
|
-
useFusion: false,
|
|
35051
|
-
...tuningForward,
|
|
35052
|
-
...folderId !== void 0 && { folderId },
|
|
35053
|
-
...searchOptions?.scopes && { scopes: searchOptions.scopes }
|
|
35054
|
-
}
|
|
35107
|
+
legacyOptions
|
|
35055
35108
|
);
|
|
35056
35109
|
if (legacy.length === 0) {
|
|
35057
35110
|
return embeddingsUnavailable ? EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL : "No relevant memories found in the vault.";
|
|
@@ -35070,7 +35123,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
35070
35123
|
let recallDegraded = [];
|
|
35071
35124
|
const result = await recall(
|
|
35072
35125
|
query,
|
|
35073
|
-
{ vaultCtx, embeddingOptions, vaultCache: cache },
|
|
35126
|
+
"retain" in vaultCtx ? { factSource: vaultCtx.factSource, embeddingOptions } : { vaultCtx, embeddingOptions, vaultCache: cache },
|
|
35074
35127
|
{
|
|
35075
35128
|
onDiagnostics: (d) => {
|
|
35076
35129
|
recallDegraded = d.degraded;
|
|
@@ -35150,8 +35203,10 @@ function describeWriteOutcome(outcome) {
|
|
|
35150
35203
|
}
|
|
35151
35204
|
}
|
|
35152
35205
|
function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
35206
|
+
const store = "retain" in vaultCtx ? vaultCtx : void 0;
|
|
35207
|
+
const ctx = "retain" in vaultCtx ? void 0 : vaultCtx;
|
|
35153
35208
|
const hasOnSave = !!options?.onSave;
|
|
35154
|
-
const folderNames = options?.folderMap ? Array.from(options.folderMap.keys()) : [];
|
|
35209
|
+
const folderNames = !store && options?.folderMap ? Array.from(options.folderMap.keys()) : [];
|
|
35155
35210
|
return {
|
|
35156
35211
|
type: "function",
|
|
35157
35212
|
function: {
|
|
@@ -35196,7 +35251,7 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
35196
35251
|
let previousContent;
|
|
35197
35252
|
const scope = options?.scope ?? "private";
|
|
35198
35253
|
if (isUpdate) {
|
|
35199
|
-
const existing = await getVaultMemoryOp(
|
|
35254
|
+
const existing = store ? await store.get(id) : await getVaultMemoryOp(ctx, id);
|
|
35200
35255
|
if (!existing) {
|
|
35201
35256
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
35202
35257
|
}
|
|
@@ -35217,9 +35272,18 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
35217
35272
|
return isUpdate ? `Memory update was cancelled by the user. The memory "${id}" was not modified.` : "Memory save was cancelled by the user. No memory was created.";
|
|
35218
35273
|
}
|
|
35219
35274
|
}
|
|
35220
|
-
if (isUpdate) {
|
|
35275
|
+
if (isUpdate && store) {
|
|
35276
|
+
const updated = await store.update(id, {
|
|
35277
|
+
content,
|
|
35278
|
+
...factType !== void 0 && { factType }
|
|
35279
|
+
});
|
|
35280
|
+
if (!updated) {
|
|
35281
|
+
return `Error: Failed to update memory "${id}".`;
|
|
35282
|
+
}
|
|
35283
|
+
return `Memory updated successfully (ID: ${updated.uniqueId}).`;
|
|
35284
|
+
} else if (isUpdate) {
|
|
35221
35285
|
const folderId = folderName ? options?.folderMap?.get(folderName) : void 0;
|
|
35222
|
-
const updated = await updateVaultMemoryOp(
|
|
35286
|
+
const updated = await updateVaultMemoryOp(ctx, id, {
|
|
35223
35287
|
content,
|
|
35224
35288
|
embedding: null,
|
|
35225
35289
|
folderId,
|
|
@@ -35234,7 +35298,7 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
35234
35298
|
content,
|
|
35235
35299
|
embeddingOptions,
|
|
35236
35300
|
cache,
|
|
35237
|
-
|
|
35301
|
+
ctx,
|
|
35238
35302
|
id,
|
|
35239
35303
|
updated.updatedAt
|
|
35240
35304
|
).catch(() => {
|
|
@@ -35254,18 +35318,22 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
35254
35318
|
await notifyWritten(options, input, outcome);
|
|
35255
35319
|
return describeWriteOutcome(outcome);
|
|
35256
35320
|
}
|
|
35257
|
-
const created = await
|
|
35321
|
+
const created = store ? await store.create({
|
|
35322
|
+
content,
|
|
35323
|
+
scope,
|
|
35324
|
+
...factType !== void 0 && { factType }
|
|
35325
|
+
}) : await createVaultMemoryOp(ctx, {
|
|
35258
35326
|
content,
|
|
35259
35327
|
scope,
|
|
35260
35328
|
folderId,
|
|
35261
35329
|
...factType !== void 0 && { factType }
|
|
35262
35330
|
});
|
|
35263
|
-
if (embeddingOptions && cache) {
|
|
35331
|
+
if (ctx && embeddingOptions && cache) {
|
|
35264
35332
|
eagerEmbedContent(
|
|
35265
35333
|
content,
|
|
35266
35334
|
embeddingOptions,
|
|
35267
35335
|
cache,
|
|
35268
|
-
|
|
35336
|
+
ctx,
|
|
35269
35337
|
created.uniqueId,
|
|
35270
35338
|
created.updatedAt
|
|
35271
35339
|
).catch(() => {
|
package/dist/tools/index.cjs
CHANGED
|
@@ -1554,15 +1554,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
|
|
|
1554
1554
|
|
|
1555
1555
|
Once the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.
|
|
1556
1556
|
|
|
1557
|
-
DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.
|
|
1557
|
+
DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.
|
|
1558
|
+
|
|
1559
|
+
EDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.
|
|
1558
1560
|
|
|
1559
1561
|
WORKFLOW:
|
|
1560
1562
|
1. NEVER output code as text or markdown. ALWAYS use tools.
|
|
1561
1563
|
2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
|
|
1562
1564
|
3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered "42: <text>" \u2014 the prefix is display-only; never copy it into "find". Each "find" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.
|
|
1563
1565
|
4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.
|
|
1564
|
-
5.
|
|
1565
|
-
6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip
|
|
1566
|
+
5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.
|
|
1567
|
+
6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.
|
|
1566
1568
|
7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
|
|
1567
1569
|
|
|
1568
1570
|
STRUCTURE:
|
|
@@ -1918,17 +1920,17 @@ var LIST_FILES_SCHEMA = {
|
|
|
1918
1920
|
};
|
|
1919
1921
|
var AUDIT_DESIGN_SCHEMA = {
|
|
1920
1922
|
name: "audit_design",
|
|
1921
|
-
description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this
|
|
1923
|
+
description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this on the initial build, when adding new UI, or after a user-requested design change, then patch only the actionable issues within the current user request. For text, logic, or data edits, skip this tool.",
|
|
1922
1924
|
arguments: { type: "object", properties: {}, required: [] }
|
|
1923
1925
|
};
|
|
1924
1926
|
var CRITIQUE_DESIGN_SCHEMA = {
|
|
1925
1927
|
name: "critique_design",
|
|
1926
|
-
description: "
|
|
1928
|
+
description: "Review the app after the initial build, when adding new UI, or a user-requested design change. Returns App.js, App.css, and questions about intent, hierarchy, distinctiveness, coherence, and weak design choices. Answer the questions and patch only weaknesses within the current user request. For text, logic, or data edits, skip this tool. Preserve styles, dependencies, and unrelated code on text edits. Use audit_design for mechanical and accessibility checks.",
|
|
1927
1929
|
arguments: { type: "object", properties: {}, required: [] }
|
|
1928
1930
|
};
|
|
1929
1931
|
var VERIFY_APP_SCHEMA = {
|
|
1930
1932
|
name: "verify_app",
|
|
1931
|
-
description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured \u2014 hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes \u2014 and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a
|
|
1933
|
+
description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured \u2014 hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes \u2014 and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a note. Preserve the current user request scope. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.",
|
|
1932
1934
|
arguments: { type: "object", properties: {}, required: [] }
|
|
1933
1935
|
};
|
|
1934
1936
|
var DEFAULT_DESIGN_CRITIQUE_RUBRIC = Object.freeze([
|
|
@@ -2361,7 +2363,7 @@ function createAppGenerationTools({
|
|
|
2361
2363
|
const appJs = files.find((f) => f.path === "App.js")?.content ?? files.find((f) => f.path === "App.jsx")?.content ?? "";
|
|
2362
2364
|
const appCss = files.find((f) => f.path === "App.css")?.content ?? "";
|
|
2363
2365
|
return {
|
|
2364
|
-
instruction: "
|
|
2366
|
+
instruction: "For text, logic, or data edits, skip this critique. Preserve styles, dependencies, and unrelated code on text edits. For the initial build, when adding new UI, or a user-requested design change, read App.js and App.css below, then answer each rubric question with specific lines and choices. Identify the 2-3 weakest items within that request. Patch only files and lines required by the current user request.",
|
|
2365
2367
|
rubric: designCritiqueRubric,
|
|
2366
2368
|
appJs: {
|
|
2367
2369
|
path: "App.js",
|
|
@@ -2390,7 +2392,7 @@ function createAppGenerationTools({
|
|
|
2390
2392
|
return {
|
|
2391
2393
|
rendered: true,
|
|
2392
2394
|
errors: [],
|
|
2393
|
-
note: "This host did not wire verify_app
|
|
2395
|
+
note: "This host did not wire verify_app. Runtime introspection is unavailable in this environment. Preserve the current user request scope. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes. Do not interpret the empty errors list as proof the app runs."
|
|
2394
2396
|
};
|
|
2395
2397
|
}
|
|
2396
2398
|
try {
|
package/dist/tools/index.d.mts
CHANGED
|
@@ -409,7 +409,9 @@ declare function buildConnectorErrorResult(code: ConnectorErrorCode, provider: s
|
|
|
409
409
|
* Returned as a structured AuditResult so the model (or a host) can
|
|
410
410
|
* read it programmatically: each issue has a path, line, severity,
|
|
411
411
|
* type, and human-readable message. The model is expected to call this
|
|
412
|
-
*
|
|
412
|
+
* on the initial build, when adding new UI, or after a user-requested
|
|
413
|
+
* design change, and patch only the actionable issues within the
|
|
414
|
+
* current request. For text, logic, or data edits, the audit is skipped.
|
|
413
415
|
*/
|
|
414
416
|
type AuditSeverity = "error" | "warn" | "info";
|
|
415
417
|
type AuditIssueType = "no-design-tokens" | "raw-color" | "inline-style-with-color" | "unused-token" | "missing-focus-state" | "focus-not-keyed" | "low-contrast" | "off-scale-spacing" | "orphaned-class" | "missing-aria-label" | "missing-alt" | "heading-order";
|
|
@@ -792,7 +794,7 @@ declare function exportAppToHtml(options: ExportAppOptions): string;
|
|
|
792
794
|
* prefix/head — so keep it byte-identical; see internal docs.
|
|
793
795
|
* Guarded by the backend-sync test in appBuilderPrompt.test.ts.
|
|
794
796
|
*/
|
|
795
|
-
declare const APP_BUILDER_PROMPT = "App Builder tools (create_file, patch_file, and the rest described below) are available this turn, but they are OPTIONAL \u2014 having them does not mean you should build anything.\n\nBuild ONLY when the user gives an explicit instruction to build, create, generate, or change an app, tool, or UI \u2014 e.g. \"build a todo app\", \"make a snake game\", \"add a footer to the app\", \"change the background to blue\". A bare app name or feature reference is NOT a build instruction: if the user just says \"todo app\", \"a snake game\", or \"qr code\", or asks a question about an app, do NOT generate anything \u2014 reply normally, or ask what they'd like you to build. The same holds for greetings, questions, stories, explanations, advice, or code that isn't a runnable app: respond normally and do not create files. When it's unclear whether the user actually wants an app built, ask instead of building.\n\nOnce the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.\n\nDESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: \"Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise\" is the kind of specificity that anchors the build. Default to nothing: don't pick \"safe modern productivity\" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.\n\nWORKFLOW:\n1. NEVER output code as text or markdown. ALWAYS use tools.\n2. Initial build: state your design brief, then create_file with a \"files\" array writing ALL files in one call. The preview renders automatically.\n3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered \"42: <text>\" \u2014 the prefix is display-only; never copy it into \"find\". Each \"find\" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.\n4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.\n5. After substantial changes, call critique_design first (taste, hierarchy, distinctiveness, weakest decision) and then audit_design (mechanical: tokens, focus states, aria-labels, alt, heading order). Patch what each surfaces. critique catches taste issues no checklist would; audit catches mechanics you'd miss. Run both; act on both.\n6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If `rendered` is false or `errors` is non-empty, fix every error before the next message. If the response includes a `note` that verify_app isn't wired in this host, skip \u2014 audit + critique are your feedback in that case.\n7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.\n\nSTRUCTURE:\n- App.js: default-export React component. For non-trivial apps, define small co-located helpers (Header, CardList, Card, EditDialog, \u2026) above the default export rather than one giant App.\n- App.css: all styles, imported in App.js. No inline style objects.\n- package.json: list ALL imported packages including react. No CDN script tags. Versions are auto-pinned.\n- Do NOT create index.js or index.html (auto-generated).\n\nSTATE & PERSISTENCE:\n- The code runs in the user's browser \u2014 standard browser APIs available (localStorage, URL hash, Date, fetch).\n- Persist user-created data (todos, cards, notes, settings) with localStorage so it survives refresh. Use a versioned key (\"kanban.v1\") and JSON.parse inside try/catch on read.\n- Treat persisted data as untrusted and possibly stale: a saved record may predate a field you just added (a timestamp, id, or setting), so default-fill or skip missing fields on read \u2014 never assume a loaded record has every field the current code expects. Bump the key version when the shape changes.\n- Lift state to App when multiple children need it; keep it local otherwise. Extract non-trivial logic into custom hooks (useTodos, useTimer).\n- useReducer for state shapes with several interrelated fields (cards + columns + filters + drag state).\n\nFILE & IMAGE UPLOAD:\n- Picker: `<input type=\"file\" accept=\"image/*\" multiple>` (vary accept by use case: `.csv,text/csv`, `.txt,.md,text/plain`, etc.).\n- Drag-and-drop: call `e.preventDefault()` in onDragOver (otherwise drop never fires); read files from `event.dataTransfer.files`. Drop and picker should coexist.\n- Previews: `<img src={URL.createObjectURL(file)} />`. Call `URL.revokeObjectURL` on unmount or before replacing \u2014 otherwise the browser leaks memory.\n- localStorage cannot hold large binary. Persist only metadata for big files; re-upload on next visit (or use IndexedDB if you really need durable binary storage).\n- Validate size and type before processing; reject files larger than the app can hold in memory.\n\nAI CAPABILITIES \u2014 `window.app.complete(prompt: string): Promise<string>` is available in this environment. Build for the real call.\n- When the app's core purpose is conversation, generation, grading, recommendation, or any natural-language task, this IS the implementation \u2014 call it. NEVER fake it: no hardcoded or canned replies, no random or `setTimeout` \"thinking\", no demo-mode stub. A chat app, tutor, or assistant that doesn't call `window.app.complete` is wrong, not a placeholder.\n- Don't force it where it isn't needed \u2014 a calculator, todo list, or timer has no reason to call it. Match the implementation to what the app actually does.\n- Async: wrap in try/catch, show a loading state, and disable dependent inputs while waiting. Surface failures gracefully (\"Couldn't reach the AI \u2014 try again\").\n- Structure prompts with clear sections (Role / Context / Task / Format) and pass the relevant state (e.g. the running conversation) as context. Render the response as untrusted text: `white-space: pre-wrap`, never dangerouslySetInnerHTML.\n- Skip the call only when the answer is genuinely static \u2014 no language or reasoning needed. Cache repeated prompts in component state when sensible.\n\nCODE QUALITY \u2014 write as a senior engineer would:\n- Handle edge cases (empty inputs, division by zero, invalid data). Show helpful error states, not crashes.\n- Never let formatting throw during render: guard `new Date(x)` / `Intl` / `toLocaleString` / `.toFixed` against missing or invalid values (e.g. `Number.isNaN(d.getTime())`) and return a fallback \u2014 one bad value from storage or state must not blank the whole app.\n- Semantic HTML: real headings, labels, buttons (not divs with onClick), form elements.\n- Accessible: aria-labels on icon buttons, focus-visible styles, keyboard navigable.\n- Extract into custom hooks or helpers when a component grows past ~80 lines.\n\nSTYLING \u2014 Tailwind is the CHASSIS, custom CSS carries the IDENTITY:\n- Tailwind (via Play CDN) for layout, spacing, state (hover/focus), responsive prefixes \u2014 uniform structure.\n- App.css carries the identity: @import the Google Fonts, declare CSS custom properties (--bg, --panel, --card, --ink, --muted, --accent, --hairline, --radius, --radius-sm, --shadow-card, --shadow-card-hi) in :root, gradients/textures/signature animations Tailwind can't express. Reference tokens from Tailwind via arbitrary values (`className=\"bg-[var(--bg)]\"`) when needed. A well-designed app has 60-200 lines of App.css \u2014 not zero.\n- Modern CSS is how apps stop reading as generic-AI-output: `color-mix(in oklab, var(--accent) 14%, transparent)` for tinting, `oklch()` / `oklab()` for perceptually-uniform color, `:has()`, `conic-gradient` / `radial-gradient`, `backdrop-filter`, `@container` queries, inline SVG `feTurbulence` for texture.\n- Don't pull additional CSS frameworks. Tailwind + custom CSS is enough.\n\nVISUAL DESIGN \u2014 every app should look like a real product, not a wireframe:\n- Let the chosen aesthetic drive every decision. \"Editorial\" wants italic display type and restrained color; \"retro arcade\" wants chunky shadows and saturated gradients. No safe-modern defaults.\n- Atmospheric depth: subtle radial wash, paper grain (inline SVG noise), warm/cool tint \u2014 every canvas should feel like a designed space, not a #fff rectangle.\n- Three shadow tiers (rest / hover / active). Pair drop shadows with inset highlights (`box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 6px 14px -10px ...`) for tactile feel.\n- Typography hierarchy: display font for headlines (italic accents on key words via `<em>`), body font for content, mono for metadata/labels \u2014 different families telegraph different information types.\n- Interactive polish: hover/active/focus on every clickable element, 200-300ms cubic-bezier transitions, keyboard shortcuts where natural (Esc to cancel, Cmd/Ctrl+Enter to commit), focus-visible rings keyed to the accent.\n- Light/dark mode if reasonable: a single CSS variable inversion under `[data-theme=\"dark\"]`.\n- Customization affordance for multi-session apps: small \"Tweaks\" panel with theme / density / accent. Skip for throwaway demos.\n- Responsive: Tailwind responsive prefixes (`sm:`, `md:`, `lg:`) and `@media` in App.css. Mobile-first.";
|
|
797
|
+
declare const APP_BUILDER_PROMPT = "App Builder tools (create_file, patch_file, and the rest described below) are available this turn, but they are OPTIONAL \u2014 having them does not mean you should build anything.\n\nBuild ONLY when the user gives an explicit instruction to build, create, generate, or change an app, tool, or UI \u2014 e.g. \"build a todo app\", \"make a snake game\", \"add a footer to the app\", \"change the background to blue\". A bare app name or feature reference is NOT a build instruction: if the user just says \"todo app\", \"a snake game\", or \"qr code\", or asks a question about an app, do NOT generate anything \u2014 reply normally, or ask what they'd like you to build. The same holds for greetings, questions, stories, explanations, advice, or code that isn't a runnable app: respond normally and do not create files. When it's unclear whether the user actually wants an app built, ask instead of building.\n\nOnce the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.\n\nDESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: \"Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise\" is the kind of specificity that anchors the build. Default to nothing: don't pick \"safe modern productivity\" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.\n\nEDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.\n\nWORKFLOW:\n1. NEVER output code as text or markdown. ALWAYS use tools.\n2. Initial build: state your design brief, then create_file with a \"files\" array writing ALL files in one call. The preview renders automatically.\n3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered \"42: <text>\" \u2014 the prefix is display-only; never copy it into \"find\". Each \"find\" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.\n4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.\n5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.\n6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If `rendered` is false or `errors` is non-empty, fix every error before the next message. If the response includes a `note` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.\n7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.\n\nSTRUCTURE:\n- App.js: default-export React component. For non-trivial apps, define small co-located helpers (Header, CardList, Card, EditDialog, \u2026) above the default export rather than one giant App.\n- App.css: all styles, imported in App.js. No inline style objects.\n- package.json: list ALL imported packages including react. No CDN script tags. Versions are auto-pinned.\n- Do NOT create index.js or index.html (auto-generated).\n\nSTATE & PERSISTENCE:\n- The code runs in the user's browser \u2014 standard browser APIs available (localStorage, URL hash, Date, fetch).\n- Persist user-created data (todos, cards, notes, settings) with localStorage so it survives refresh. Use a versioned key (\"kanban.v1\") and JSON.parse inside try/catch on read.\n- Treat persisted data as untrusted and possibly stale: a saved record may predate a field you just added (a timestamp, id, or setting), so default-fill or skip missing fields on read \u2014 never assume a loaded record has every field the current code expects. Bump the key version when the shape changes.\n- Lift state to App when multiple children need it; keep it local otherwise. Extract non-trivial logic into custom hooks (useTodos, useTimer).\n- useReducer for state shapes with several interrelated fields (cards + columns + filters + drag state).\n\nFILE & IMAGE UPLOAD:\n- Picker: `<input type=\"file\" accept=\"image/*\" multiple>` (vary accept by use case: `.csv,text/csv`, `.txt,.md,text/plain`, etc.).\n- Drag-and-drop: call `e.preventDefault()` in onDragOver (otherwise drop never fires); read files from `event.dataTransfer.files`. Drop and picker should coexist.\n- Previews: `<img src={URL.createObjectURL(file)} />`. Call `URL.revokeObjectURL` on unmount or before replacing \u2014 otherwise the browser leaks memory.\n- localStorage cannot hold large binary. Persist only metadata for big files; re-upload on next visit (or use IndexedDB if you really need durable binary storage).\n- Validate size and type before processing; reject files larger than the app can hold in memory.\n\nAI CAPABILITIES \u2014 `window.app.complete(prompt: string): Promise<string>` is available in this environment. Build for the real call.\n- When the app's core purpose is conversation, generation, grading, recommendation, or any natural-language task, this IS the implementation \u2014 call it. NEVER fake it: no hardcoded or canned replies, no random or `setTimeout` \"thinking\", no demo-mode stub. A chat app, tutor, or assistant that doesn't call `window.app.complete` is wrong, not a placeholder.\n- Don't force it where it isn't needed \u2014 a calculator, todo list, or timer has no reason to call it. Match the implementation to what the app actually does.\n- Async: wrap in try/catch, show a loading state, and disable dependent inputs while waiting. Surface failures gracefully (\"Couldn't reach the AI \u2014 try again\").\n- Structure prompts with clear sections (Role / Context / Task / Format) and pass the relevant state (e.g. the running conversation) as context. Render the response as untrusted text: `white-space: pre-wrap`, never dangerouslySetInnerHTML.\n- Skip the call only when the answer is genuinely static \u2014 no language or reasoning needed. Cache repeated prompts in component state when sensible.\n\nCODE QUALITY \u2014 write as a senior engineer would:\n- Handle edge cases (empty inputs, division by zero, invalid data). Show helpful error states, not crashes.\n- Never let formatting throw during render: guard `new Date(x)` / `Intl` / `toLocaleString` / `.toFixed` against missing or invalid values (e.g. `Number.isNaN(d.getTime())`) and return a fallback \u2014 one bad value from storage or state must not blank the whole app.\n- Semantic HTML: real headings, labels, buttons (not divs with onClick), form elements.\n- Accessible: aria-labels on icon buttons, focus-visible styles, keyboard navigable.\n- Extract into custom hooks or helpers when a component grows past ~80 lines.\n\nSTYLING \u2014 Tailwind is the CHASSIS, custom CSS carries the IDENTITY:\n- Tailwind (via Play CDN) for layout, spacing, state (hover/focus), responsive prefixes \u2014 uniform structure.\n- App.css carries the identity: @import the Google Fonts, declare CSS custom properties (--bg, --panel, --card, --ink, --muted, --accent, --hairline, --radius, --radius-sm, --shadow-card, --shadow-card-hi) in :root, gradients/textures/signature animations Tailwind can't express. Reference tokens from Tailwind via arbitrary values (`className=\"bg-[var(--bg)]\"`) when needed. A well-designed app has 60-200 lines of App.css \u2014 not zero.\n- Modern CSS is how apps stop reading as generic-AI-output: `color-mix(in oklab, var(--accent) 14%, transparent)` for tinting, `oklch()` / `oklab()` for perceptually-uniform color, `:has()`, `conic-gradient` / `radial-gradient`, `backdrop-filter`, `@container` queries, inline SVG `feTurbulence` for texture.\n- Don't pull additional CSS frameworks. Tailwind + custom CSS is enough.\n\nVISUAL DESIGN \u2014 every app should look like a real product, not a wireframe:\n- Let the chosen aesthetic drive every decision. \"Editorial\" wants italic display type and restrained color; \"retro arcade\" wants chunky shadows and saturated gradients. No safe-modern defaults.\n- Atmospheric depth: subtle radial wash, paper grain (inline SVG noise), warm/cool tint \u2014 every canvas should feel like a designed space, not a #fff rectangle.\n- Three shadow tiers (rest / hover / active). Pair drop shadows with inset highlights (`box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 6px 14px -10px ...`) for tactile feel.\n- Typography hierarchy: display font for headlines (italic accents on key words via `<em>`), body font for content, mono for metadata/labels \u2014 different families telegraph different information types.\n- Interactive polish: hover/active/focus on every clickable element, 200-300ms cubic-bezier transitions, keyboard shortcuts where natural (Esc to cancel, Cmd/Ctrl+Enter to commit), focus-visible rings keyed to the accent.\n- Light/dark mode if reasonable: a single CSS variable inversion under `[data-theme=\"dark\"]`.\n- Customization affordance for multi-session apps: small \"Tweaks\" panel with theme / density / accent. Skip for throwaway demos.\n- Responsive: Tailwind responsive prefixes (`sm:`, `md:`, `lg:`) and `@media` in App.css. Mobile-first.";
|
|
796
798
|
|
|
797
799
|
/** Strip leading slash and collapse traversal segments so paths are always clean relative paths. */
|
|
798
800
|
declare function normalizePath(p: string): string;
|
|
@@ -1018,7 +1020,7 @@ declare const LIST_FILES_SCHEMA: {
|
|
|
1018
1020
|
};
|
|
1019
1021
|
declare const AUDIT_DESIGN_SCHEMA: {
|
|
1020
1022
|
readonly name: "audit_design";
|
|
1021
|
-
readonly description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this
|
|
1023
|
+
readonly description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this on the initial build, when adding new UI, or after a user-requested design change, then patch only the actionable issues within the current user request. For text, logic, or data edits, skip this tool.";
|
|
1022
1024
|
readonly arguments: {
|
|
1023
1025
|
readonly type: "object";
|
|
1024
1026
|
readonly properties: {};
|
|
@@ -1027,7 +1029,7 @@ declare const AUDIT_DESIGN_SCHEMA: {
|
|
|
1027
1029
|
};
|
|
1028
1030
|
declare const CRITIQUE_DESIGN_SCHEMA: {
|
|
1029
1031
|
readonly name: "critique_design";
|
|
1030
|
-
readonly description: "
|
|
1032
|
+
readonly description: "Review the app after the initial build, when adding new UI, or a user-requested design change. Returns App.js, App.css, and questions about intent, hierarchy, distinctiveness, coherence, and weak design choices. Answer the questions and patch only weaknesses within the current user request. For text, logic, or data edits, skip this tool. Preserve styles, dependencies, and unrelated code on text edits. Use audit_design for mechanical and accessibility checks.";
|
|
1031
1033
|
readonly arguments: {
|
|
1032
1034
|
readonly type: "object";
|
|
1033
1035
|
readonly properties: {};
|
|
@@ -1036,7 +1038,7 @@ declare const CRITIQUE_DESIGN_SCHEMA: {
|
|
|
1036
1038
|
};
|
|
1037
1039
|
declare const VERIFY_APP_SCHEMA: {
|
|
1038
1040
|
readonly name: "verify_app";
|
|
1039
|
-
readonly description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured — hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes — and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a
|
|
1041
|
+
readonly description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured — hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes — and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a note. Preserve the current user request scope. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.";
|
|
1040
1042
|
readonly arguments: {
|
|
1041
1043
|
readonly type: "object";
|
|
1042
1044
|
readonly properties: {};
|
|
@@ -1133,7 +1135,9 @@ interface CreateAppGenerationToolsOptions {
|
|
|
1133
1135
|
* after substantial changes; the tool's executor invokes this hook
|
|
1134
1136
|
* and returns the result to the model. When NOT wired, the tool
|
|
1135
1137
|
* still exists but returns `{ rendered: true, errors: [], note: … }`
|
|
1136
|
-
* so the model degrades gracefully
|
|
1138
|
+
* so the model degrades gracefully — the note restates that
|
|
1139
|
+
* audit_design / critique_design stay gated to the initial build,
|
|
1140
|
+
* adding new UI, or user-requested design changes.
|
|
1137
1141
|
*
|
|
1138
1142
|
* Same host-hook pattern as `displayApp` and `onFileChange` — the
|
|
1139
1143
|
* SDK never executes anything itself.
|