@anuma/sdk 6.39.0 → 6.39.2
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 +186 -59
- package/dist/expo/index.d.mts +133 -2
- package/dist/expo/index.d.ts +133 -2
- package/dist/expo/index.mjs +185 -59
- package/dist/index.cjs +50 -34
- package/dist/index.mjs +50 -34
- package/dist/react/index.cjs +186 -59
- package/dist/react/index.d.mts +133 -2
- package/dist/react/index.d.ts +133 -2
- package/dist/react/index.mjs +185 -59
- package/dist/server/index.cjs +50 -34
- package/dist/server/index.d.mts +5 -1
- package/dist/server/index.d.ts +5 -1
- package/dist/server/index.mjs +50 -34
- 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/react/index.mjs
CHANGED
|
@@ -6022,15 +6022,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
|
|
|
6022
6022
|
|
|
6023
6023
|
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.
|
|
6024
6024
|
|
|
6025
|
-
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.
|
|
6025
|
+
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.
|
|
6026
|
+
|
|
6027
|
+
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.
|
|
6026
6028
|
|
|
6027
6029
|
WORKFLOW:
|
|
6028
6030
|
1. NEVER output code as text or markdown. ALWAYS use tools.
|
|
6029
6031
|
2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
|
|
6030
6032
|
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.
|
|
6031
6033
|
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.
|
|
6032
|
-
5.
|
|
6033
|
-
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
|
|
6034
|
+
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.
|
|
6035
|
+
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.
|
|
6034
6036
|
7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
|
|
6035
6037
|
|
|
6036
6038
|
STRUCTURE:
|
|
@@ -6196,12 +6198,13 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
|
|
|
6196
6198
|
if (!cache) return true;
|
|
6197
6199
|
return Date.now() - cache.timestamp > expirationMs;
|
|
6198
6200
|
}
|
|
6199
|
-
function buildCacheEntry(tools, checksum) {
|
|
6201
|
+
function buildCacheEntry(tools, checksum, etag) {
|
|
6200
6202
|
return {
|
|
6201
6203
|
tools,
|
|
6202
6204
|
timestamp: Date.now(),
|
|
6203
6205
|
version: CACHE_VERSION,
|
|
6204
|
-
...checksum && { checksum }
|
|
6206
|
+
...checksum && { checksum },
|
|
6207
|
+
...etag && { etag }
|
|
6205
6208
|
};
|
|
6206
6209
|
}
|
|
6207
6210
|
function writeLocalStorageCache(entry) {
|
|
@@ -6236,19 +6239,36 @@ function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
|
|
|
6236
6239
|
const cachedChecksum = getToolsChecksum2(cache);
|
|
6237
6240
|
return cachedChecksum instanceof Promise ? cachedChecksum.then(decide) : decide(cachedChecksum);
|
|
6238
6241
|
}
|
|
6239
|
-
async function fetchServerToolsFromApi(baseUrl,
|
|
6240
|
-
const
|
|
6242
|
+
async function fetchServerToolsFromApi(baseUrl, authHeaders, etag) {
|
|
6243
|
+
const request = (validator) => fetch(`${baseUrl}/api/v1/tools`, {
|
|
6241
6244
|
method: "GET",
|
|
6242
6245
|
headers: {
|
|
6243
|
-
|
|
6244
|
-
"Content-Type": "application/json"
|
|
6246
|
+
...authHeaders,
|
|
6247
|
+
"Content-Type": "application/json",
|
|
6248
|
+
...validator && { "If-None-Match": validator }
|
|
6245
6249
|
}
|
|
6246
6250
|
});
|
|
6251
|
+
let response;
|
|
6252
|
+
try {
|
|
6253
|
+
response = await request(etag);
|
|
6254
|
+
} catch (error) {
|
|
6255
|
+
if (!etag || !(error instanceof TypeError)) throw error;
|
|
6256
|
+
etag = void 0;
|
|
6257
|
+
response = await request();
|
|
6258
|
+
}
|
|
6259
|
+
if (etag && response.status === 304) {
|
|
6260
|
+
return { notModified: true };
|
|
6261
|
+
}
|
|
6247
6262
|
if (!response.ok) {
|
|
6248
6263
|
throw new Error(`Failed to fetch server tools: ${response.status}`);
|
|
6249
6264
|
}
|
|
6250
6265
|
const data = await response.json();
|
|
6251
|
-
|
|
6266
|
+
const responseEtag = response.headers?.get("ETag") ?? void 0;
|
|
6267
|
+
return {
|
|
6268
|
+
notModified: false,
|
|
6269
|
+
...convertServerToolsResponse(data),
|
|
6270
|
+
...responseEtag && { etag: responseEtag }
|
|
6271
|
+
};
|
|
6252
6272
|
}
|
|
6253
6273
|
async function getServerTools(options) {
|
|
6254
6274
|
const {
|
|
@@ -6280,34 +6300,30 @@ async function getServerTools(options) {
|
|
|
6280
6300
|
try {
|
|
6281
6301
|
const { BASE_URL: BASE_URL2 } = await import("./clientConfig-VPOGQRNP.mjs");
|
|
6282
6302
|
const effectiveBaseUrl = baseUrl ?? BASE_URL2;
|
|
6303
|
+
const validator = cached && !forceRefresh ? cached.etag : void 0;
|
|
6304
|
+
let authHeaders;
|
|
6283
6305
|
if (apiKey) {
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
if (!
|
|
6292
|
-
|
|
6306
|
+
authHeaders = { "X-API-Key": apiKey };
|
|
6307
|
+
} else {
|
|
6308
|
+
if (!getToken) {
|
|
6309
|
+
getLogger().warn("[serverTools] No auth method available for fetching tools");
|
|
6310
|
+
return cached?.tools ?? [];
|
|
6311
|
+
}
|
|
6312
|
+
const token = await getToken();
|
|
6313
|
+
if (!token) {
|
|
6314
|
+
getLogger().warn("[serverTools] No auth token available for fetching tools");
|
|
6315
|
+
return cached?.tools ?? [];
|
|
6293
6316
|
}
|
|
6294
|
-
|
|
6295
|
-
const { tools: tools2, checksum: checksum2 } = convertServerToolsResponse(data);
|
|
6296
|
-
await persistCache(buildCacheEntry(tools2, checksum2));
|
|
6297
|
-
return tools2;
|
|
6317
|
+
authHeaders = { Authorization: `Bearer ${token}` };
|
|
6298
6318
|
}
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6319
|
+
const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
|
|
6320
|
+
if (result.notModified) {
|
|
6321
|
+
const confirmed = cached;
|
|
6322
|
+
await persistCache({ ...confirmed, timestamp: Date.now() });
|
|
6323
|
+
return confirmed.tools;
|
|
6302
6324
|
}
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
getLogger().warn("[serverTools] No auth token available for fetching tools");
|
|
6306
|
-
return cached?.tools ?? [];
|
|
6307
|
-
}
|
|
6308
|
-
const { tools, checksum } = await fetchServerToolsFromApi(effectiveBaseUrl, token);
|
|
6309
|
-
await persistCache(buildCacheEntry(tools, checksum));
|
|
6310
|
-
return tools;
|
|
6325
|
+
await persistCache(buildCacheEntry(result.tools, result.checksum, result.etag));
|
|
6326
|
+
return result.tools;
|
|
6311
6327
|
} catch (error) {
|
|
6312
6328
|
getLogger().error("[serverTools] Failed to fetch server tools:", error);
|
|
6313
6329
|
if (cached?.tools) {
|
|
@@ -30419,6 +30435,7 @@ function useChat(options) {
|
|
|
30419
30435
|
apiType: defaultApiType = "auto",
|
|
30420
30436
|
smoothing,
|
|
30421
30437
|
preProcessors,
|
|
30438
|
+
hooks,
|
|
30422
30439
|
piiRedaction,
|
|
30423
30440
|
onPiiRedacted
|
|
30424
30441
|
} = options || {};
|
|
@@ -30590,6 +30607,7 @@ function useChat(options) {
|
|
|
30590
30607
|
onToolCallArgumentsDelta,
|
|
30591
30608
|
onStepFinish,
|
|
30592
30609
|
preProcessors,
|
|
30610
|
+
hooks,
|
|
30593
30611
|
piiRedaction: requestPiiRedaction ?? resolvedPiiRedaction,
|
|
30594
30612
|
onPiiRedacted
|
|
30595
30613
|
});
|
|
@@ -30627,6 +30645,7 @@ function useChat(options) {
|
|
|
30627
30645
|
defaultApiType,
|
|
30628
30646
|
smoothing,
|
|
30629
30647
|
preProcessors,
|
|
30648
|
+
hooks,
|
|
30630
30649
|
resolvedPiiRedaction,
|
|
30631
30650
|
onPiiRedacted
|
|
30632
30651
|
]
|
|
@@ -31831,6 +31850,7 @@ function useChatStorage(options) {
|
|
|
31831
31850
|
minContentLength = DEFAULT_MIN_CONTENT_LENGTH,
|
|
31832
31851
|
mcpR2Domain = MCP_R2_DOMAIN,
|
|
31833
31852
|
preProcessors,
|
|
31853
|
+
hooks,
|
|
31834
31854
|
smoothing,
|
|
31835
31855
|
piiRedaction,
|
|
31836
31856
|
onPiiRedacted,
|
|
@@ -32405,6 +32425,7 @@ function useChatStorage(options) {
|
|
|
32405
32425
|
onStreamMeta,
|
|
32406
32426
|
apiType,
|
|
32407
32427
|
preProcessors,
|
|
32428
|
+
hooks,
|
|
32408
32429
|
smoothing,
|
|
32409
32430
|
piiRedaction: resolvedPiiRedaction,
|
|
32410
32431
|
onPiiRedacted
|
|
@@ -34824,6 +34845,128 @@ function useICloudBackup(options) {
|
|
|
34824
34845
|
|
|
34825
34846
|
// src/react/useModels.ts
|
|
34826
34847
|
import { useCallback as useCallback15, useEffect as useEffect10, useRef as useRef6, useState as useState12 } from "react";
|
|
34848
|
+
var MODELS_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
34849
|
+
var modelsCache = /* @__PURE__ */ new Map();
|
|
34850
|
+
var modelsInFlight = /* @__PURE__ */ new Map();
|
|
34851
|
+
var cacheGeneration = 0;
|
|
34852
|
+
function clearModelsCache() {
|
|
34853
|
+
cacheGeneration++;
|
|
34854
|
+
modelsCache.clear();
|
|
34855
|
+
modelsInFlight.clear();
|
|
34856
|
+
}
|
|
34857
|
+
function pruneStaleTokenEntries(newKey) {
|
|
34858
|
+
const [newBaseUrl, newProvider] = JSON.parse(newKey);
|
|
34859
|
+
for (const existingKey of modelsCache.keys()) {
|
|
34860
|
+
if (existingKey === newKey) continue;
|
|
34861
|
+
const [existingBaseUrl, existingProvider] = JSON.parse(existingKey);
|
|
34862
|
+
if (existingBaseUrl === newBaseUrl && existingProvider === newProvider) {
|
|
34863
|
+
modelsCache.delete(existingKey);
|
|
34864
|
+
}
|
|
34865
|
+
}
|
|
34866
|
+
}
|
|
34867
|
+
function fingerprintToken(token) {
|
|
34868
|
+
if (!token) return "anon";
|
|
34869
|
+
let h1 = 3735928559;
|
|
34870
|
+
let h2 = 1103547991;
|
|
34871
|
+
for (let i = 0; i < token.length; i++) {
|
|
34872
|
+
const ch = token.charCodeAt(i);
|
|
34873
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
34874
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
34875
|
+
}
|
|
34876
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
34877
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
34878
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
|
|
34879
|
+
}
|
|
34880
|
+
function modelsCacheKey(baseUrl, provider, token) {
|
|
34881
|
+
return JSON.stringify([baseUrl, provider ?? null, fingerprintToken(token)]);
|
|
34882
|
+
}
|
|
34883
|
+
async function fetchAllModelPages(baseUrl, provider, headers, previous, signal) {
|
|
34884
|
+
const pages = /* @__PURE__ */ new Map();
|
|
34885
|
+
const models = [];
|
|
34886
|
+
let pageToken;
|
|
34887
|
+
do {
|
|
34888
|
+
const pageKey = pageToken ?? "";
|
|
34889
|
+
const stored2 = previous?.pages.get(pageKey);
|
|
34890
|
+
const request = (etag) => getApiV1Models({
|
|
34891
|
+
baseUrl,
|
|
34892
|
+
headers: etag ? { ...headers, "If-None-Match": etag } : headers,
|
|
34893
|
+
query: { provider, page_token: pageToken },
|
|
34894
|
+
signal
|
|
34895
|
+
});
|
|
34896
|
+
let response = await request(stored2?.etag);
|
|
34897
|
+
if (stored2?.etag && !response.response && response.error) {
|
|
34898
|
+
response = await request();
|
|
34899
|
+
}
|
|
34900
|
+
let page;
|
|
34901
|
+
if (response.response?.status === 304) {
|
|
34902
|
+
if (!stored2) throw new Error("Failed to fetch models");
|
|
34903
|
+
page = stored2;
|
|
34904
|
+
} else {
|
|
34905
|
+
if (response.error) {
|
|
34906
|
+
const errorMsg = response.error.error ?? "Failed to fetch models";
|
|
34907
|
+
throw new Error(errorMsg);
|
|
34908
|
+
}
|
|
34909
|
+
page = {
|
|
34910
|
+
body: response.data ?? {},
|
|
34911
|
+
etag: response.response?.headers?.get("ETag") ?? void 0
|
|
34912
|
+
};
|
|
34913
|
+
}
|
|
34914
|
+
pages.set(pageKey, page);
|
|
34915
|
+
models.push(...page.body.data || []);
|
|
34916
|
+
pageToken = page.body.next_page_token;
|
|
34917
|
+
} while (pageToken);
|
|
34918
|
+
return { pages, models, fetchedAt: Date.now() };
|
|
34919
|
+
}
|
|
34920
|
+
function loadModels(key, baseUrl, provider, headers, force, signal) {
|
|
34921
|
+
const cached = modelsCache.get(key);
|
|
34922
|
+
if (cached && !force && Date.now() - cached.fetchedAt < MODELS_CACHE_TTL_MS) {
|
|
34923
|
+
return Promise.resolve([...cached.models]);
|
|
34924
|
+
}
|
|
34925
|
+
const shared = (force ? void 0 : modelsInFlight.get(key)) ?? startSharedRequest(key, baseUrl, provider, headers, cached);
|
|
34926
|
+
return waitForSharedRequest(key, shared, signal).then((models) => [...models]);
|
|
34927
|
+
}
|
|
34928
|
+
function startSharedRequest(key, baseUrl, provider, headers, previous) {
|
|
34929
|
+
const controller = new AbortController();
|
|
34930
|
+
const generation = cacheGeneration;
|
|
34931
|
+
const shared = {
|
|
34932
|
+
controller,
|
|
34933
|
+
waiters: 0,
|
|
34934
|
+
promise: Promise.resolve([])
|
|
34935
|
+
};
|
|
34936
|
+
shared.promise = fetchAllModelPages(baseUrl, provider, headers, previous, controller.signal).then((entry) => {
|
|
34937
|
+
if (modelsInFlight.get(key) === shared && generation === cacheGeneration) {
|
|
34938
|
+
pruneStaleTokenEntries(key);
|
|
34939
|
+
modelsCache.set(key, entry);
|
|
34940
|
+
}
|
|
34941
|
+
return entry.models;
|
|
34942
|
+
}).finally(() => {
|
|
34943
|
+
if (modelsInFlight.get(key) === shared) modelsInFlight.delete(key);
|
|
34944
|
+
});
|
|
34945
|
+
modelsInFlight.set(key, shared);
|
|
34946
|
+
return shared;
|
|
34947
|
+
}
|
|
34948
|
+
function waitForSharedRequest(key, shared, signal) {
|
|
34949
|
+
shared.waiters++;
|
|
34950
|
+
let left = false;
|
|
34951
|
+
const leave = () => {
|
|
34952
|
+
if (left) return;
|
|
34953
|
+
left = true;
|
|
34954
|
+
shared.waiters--;
|
|
34955
|
+
if (shared.waiters === 0) {
|
|
34956
|
+
shared.controller.abort();
|
|
34957
|
+
if (modelsInFlight.get(key) === shared) modelsInFlight.delete(key);
|
|
34958
|
+
}
|
|
34959
|
+
};
|
|
34960
|
+
if (signal.aborted) {
|
|
34961
|
+
leave();
|
|
34962
|
+
} else {
|
|
34963
|
+
signal.addEventListener("abort", leave, { once: true });
|
|
34964
|
+
}
|
|
34965
|
+
return shared.promise.finally(() => {
|
|
34966
|
+
left = true;
|
|
34967
|
+
signal.removeEventListener("abort", leave);
|
|
34968
|
+
});
|
|
34969
|
+
}
|
|
34827
34970
|
function useModels(options = {}) {
|
|
34828
34971
|
const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
|
|
34829
34972
|
const [models, setModels] = useState12([]);
|
|
@@ -34846,7 +34989,7 @@ function useModels(options = {}) {
|
|
|
34846
34989
|
}
|
|
34847
34990
|
};
|
|
34848
34991
|
}, []);
|
|
34849
|
-
const fetchModels = useCallback15(async () => {
|
|
34992
|
+
const fetchModels = useCallback15(async (force = false) => {
|
|
34850
34993
|
if (abortControllerRef.current) {
|
|
34851
34994
|
abortControllerRef.current.abort();
|
|
34852
34995
|
}
|
|
@@ -34865,35 +35008,17 @@ function useModels(options = {}) {
|
|
|
34865
35008
|
if (token) {
|
|
34866
35009
|
headers["Authorization"] = `Bearer ${token}`;
|
|
34867
35010
|
}
|
|
34868
|
-
|
|
34869
|
-
|
|
34870
|
-
|
|
34871
|
-
|
|
34872
|
-
const response = await getApiV1Models({
|
|
34873
|
-
baseUrl: baseUrlRef.current,
|
|
34874
|
-
headers,
|
|
34875
|
-
query: {
|
|
34876
|
-
provider: providerRef.current,
|
|
34877
|
-
page_token: nextPageToken
|
|
34878
|
-
},
|
|
34879
|
-
signal
|
|
34880
|
-
});
|
|
34881
|
-
if (response.error) {
|
|
34882
|
-
const errorMsg = response.error.error ?? "Failed to fetch models";
|
|
34883
|
-
throw new Error(errorMsg);
|
|
34884
|
-
}
|
|
34885
|
-
if (response.data) {
|
|
34886
|
-
const newModels = response.data.data || [];
|
|
34887
|
-
allModels = [...allModels, ...newModels];
|
|
34888
|
-
nextPageToken = response.data.next_page_token;
|
|
34889
|
-
}
|
|
34890
|
-
} while (nextPageToken);
|
|
35011
|
+
const baseUrl2 = baseUrlRef.current;
|
|
35012
|
+
const provider2 = providerRef.current;
|
|
35013
|
+
const key = modelsCacheKey(baseUrl2, provider2, token);
|
|
35014
|
+
const allModels = await loadModels(key, baseUrl2, provider2, headers, force, signal);
|
|
34891
35015
|
if (signal.aborted) return;
|
|
34892
35016
|
setModels(allModels);
|
|
34893
35017
|
} catch (err) {
|
|
34894
35018
|
if (err instanceof Error && err.name === "AbortError") {
|
|
34895
35019
|
return;
|
|
34896
35020
|
}
|
|
35021
|
+
if (signal.aborted) return;
|
|
34897
35022
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
34898
35023
|
} finally {
|
|
34899
35024
|
if (!signal.aborted) {
|
|
@@ -34906,7 +35031,7 @@ function useModels(options = {}) {
|
|
|
34906
35031
|
}, []);
|
|
34907
35032
|
const refetch = useCallback15(async () => {
|
|
34908
35033
|
setModels([]);
|
|
34909
|
-
await fetchModels();
|
|
35034
|
+
await fetchModels(true);
|
|
34910
35035
|
}, [fetchModels]);
|
|
34911
35036
|
const hasFetchedRef = useRef6(false);
|
|
34912
35037
|
useEffect10(() => {
|
|
@@ -36958,6 +37083,7 @@ export {
|
|
|
36958
37083
|
clearKeyPair,
|
|
36959
37084
|
clearLazyTitleCache,
|
|
36960
37085
|
clearMemoryTopicsOverrideOp,
|
|
37086
|
+
clearModelsCache,
|
|
36961
37087
|
clearNotionToken,
|
|
36962
37088
|
clearServerToolsCache,
|
|
36963
37089
|
consoleLogger,
|
package/dist/server/index.cjs
CHANGED
|
@@ -20430,15 +20430,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
|
|
|
20430
20430
|
|
|
20431
20431
|
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.
|
|
20432
20432
|
|
|
20433
|
-
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.
|
|
20433
|
+
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.
|
|
20434
|
+
|
|
20435
|
+
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.
|
|
20434
20436
|
|
|
20435
20437
|
WORKFLOW:
|
|
20436
20438
|
1. NEVER output code as text or markdown. ALWAYS use tools.
|
|
20437
20439
|
2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
|
|
20438
20440
|
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.
|
|
20439
20441
|
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.
|
|
20440
|
-
5.
|
|
20441
|
-
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
|
|
20442
|
+
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.
|
|
20443
|
+
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.
|
|
20442
20444
|
7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
|
|
20443
20445
|
|
|
20444
20446
|
STRUCTURE:
|
|
@@ -20584,12 +20586,13 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
|
|
|
20584
20586
|
if (!cache) return true;
|
|
20585
20587
|
return Date.now() - cache.timestamp > expirationMs;
|
|
20586
20588
|
}
|
|
20587
|
-
function buildCacheEntry(tools, checksum) {
|
|
20589
|
+
function buildCacheEntry(tools, checksum, etag) {
|
|
20588
20590
|
return {
|
|
20589
20591
|
tools,
|
|
20590
20592
|
timestamp: Date.now(),
|
|
20591
20593
|
version: CACHE_VERSION,
|
|
20592
|
-
...checksum && { checksum }
|
|
20594
|
+
...checksum && { checksum },
|
|
20595
|
+
...etag && { etag }
|
|
20593
20596
|
};
|
|
20594
20597
|
}
|
|
20595
20598
|
function writeLocalStorageCache(entry) {
|
|
@@ -20624,19 +20627,36 @@ function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
|
|
|
20624
20627
|
const cachedChecksum = getToolsChecksum(cache);
|
|
20625
20628
|
return cachedChecksum instanceof Promise ? cachedChecksum.then(decide) : decide(cachedChecksum);
|
|
20626
20629
|
}
|
|
20627
|
-
async function fetchServerToolsFromApi(baseUrl,
|
|
20628
|
-
const
|
|
20630
|
+
async function fetchServerToolsFromApi(baseUrl, authHeaders, etag) {
|
|
20631
|
+
const request = (validator) => fetch(`${baseUrl}/api/v1/tools`, {
|
|
20629
20632
|
method: "GET",
|
|
20630
20633
|
headers: {
|
|
20631
|
-
|
|
20632
|
-
"Content-Type": "application/json"
|
|
20634
|
+
...authHeaders,
|
|
20635
|
+
"Content-Type": "application/json",
|
|
20636
|
+
...validator && { "If-None-Match": validator }
|
|
20633
20637
|
}
|
|
20634
20638
|
});
|
|
20639
|
+
let response;
|
|
20640
|
+
try {
|
|
20641
|
+
response = await request(etag);
|
|
20642
|
+
} catch (error) {
|
|
20643
|
+
if (!etag || !(error instanceof TypeError)) throw error;
|
|
20644
|
+
etag = void 0;
|
|
20645
|
+
response = await request();
|
|
20646
|
+
}
|
|
20647
|
+
if (etag && response.status === 304) {
|
|
20648
|
+
return { notModified: true };
|
|
20649
|
+
}
|
|
20635
20650
|
if (!response.ok) {
|
|
20636
20651
|
throw new Error(`Failed to fetch server tools: ${response.status}`);
|
|
20637
20652
|
}
|
|
20638
20653
|
const data = await response.json();
|
|
20639
|
-
|
|
20654
|
+
const responseEtag = response.headers?.get("ETag") ?? void 0;
|
|
20655
|
+
return {
|
|
20656
|
+
notModified: false,
|
|
20657
|
+
...convertServerToolsResponse(data),
|
|
20658
|
+
...responseEtag && { etag: responseEtag }
|
|
20659
|
+
};
|
|
20640
20660
|
}
|
|
20641
20661
|
async function getServerTools(options) {
|
|
20642
20662
|
const {
|
|
@@ -20668,34 +20688,30 @@ async function getServerTools(options) {
|
|
|
20668
20688
|
try {
|
|
20669
20689
|
const { BASE_URL: BASE_URL2 } = await Promise.resolve().then(() => (init_clientConfig(), clientConfig_exports));
|
|
20670
20690
|
const effectiveBaseUrl = baseUrl ?? BASE_URL2;
|
|
20691
|
+
const validator = cached && !forceRefresh ? cached.etag : void 0;
|
|
20692
|
+
let authHeaders;
|
|
20671
20693
|
if (apiKey) {
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
|
|
20677
|
-
}
|
|
20678
|
-
});
|
|
20679
|
-
if (!response.ok) {
|
|
20680
|
-
throw new Error(`Failed to fetch server tools: ${response.status}`);
|
|
20694
|
+
authHeaders = { "X-API-Key": apiKey };
|
|
20695
|
+
} else {
|
|
20696
|
+
if (!getToken) {
|
|
20697
|
+
getLogger().warn("[serverTools] No auth method available for fetching tools");
|
|
20698
|
+
return cached?.tools ?? [];
|
|
20681
20699
|
}
|
|
20682
|
-
const
|
|
20683
|
-
|
|
20684
|
-
|
|
20685
|
-
|
|
20686
|
-
|
|
20687
|
-
|
|
20688
|
-
getLogger().warn("[serverTools] No auth method available for fetching tools");
|
|
20689
|
-
return cached?.tools ?? [];
|
|
20700
|
+
const token = await getToken();
|
|
20701
|
+
if (!token) {
|
|
20702
|
+
getLogger().warn("[serverTools] No auth token available for fetching tools");
|
|
20703
|
+
return cached?.tools ?? [];
|
|
20704
|
+
}
|
|
20705
|
+
authHeaders = { Authorization: `Bearer ${token}` };
|
|
20690
20706
|
}
|
|
20691
|
-
const
|
|
20692
|
-
if (
|
|
20693
|
-
|
|
20694
|
-
|
|
20707
|
+
const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
|
|
20708
|
+
if (result.notModified) {
|
|
20709
|
+
const confirmed = cached;
|
|
20710
|
+
await persistCache({ ...confirmed, timestamp: Date.now() });
|
|
20711
|
+
return confirmed.tools;
|
|
20695
20712
|
}
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
return tools;
|
|
20713
|
+
await persistCache(buildCacheEntry(result.tools, result.checksum, result.etag));
|
|
20714
|
+
return result.tools;
|
|
20699
20715
|
} catch (error) {
|
|
20700
20716
|
getLogger().error("[serverTools] Failed to fetch server tools:", error);
|
|
20701
20717
|
if (cached?.tools) {
|
package/dist/server/index.d.mts
CHANGED
|
@@ -6468,6 +6468,8 @@ interface CachedServerTools {
|
|
|
6468
6468
|
version: string;
|
|
6469
6469
|
/** Checksum from the server for cache invalidation */
|
|
6470
6470
|
checksum?: string;
|
|
6471
|
+
/** ETag from the server. The next refresh sends it in an If-None-Match header. */
|
|
6472
|
+
etag?: string;
|
|
6471
6473
|
}
|
|
6472
6474
|
/**
|
|
6473
6475
|
* Pluggable persistence for the fetched server-tools list.
|
|
@@ -6564,7 +6566,9 @@ declare function shouldRefreshTools(responseChecksum: string | undefined, cache:
|
|
|
6564
6566
|
* Flow:
|
|
6565
6567
|
* 1. Check the cache backend (localStorage by default; override via `cache`)
|
|
6566
6568
|
* 2. If cache valid and not force refresh, return cached tools
|
|
6567
|
-
* 3. Otherwise, fetch from API, cache, and return
|
|
6569
|
+
* 3. Otherwise, fetch from API, cache, and return. When the cache holds an ETag,
|
|
6570
|
+
* the request sends If-None-Match. On 304 the cached tools stay and only the
|
|
6571
|
+
* stored timestamp changes.
|
|
6568
6572
|
* 4. On fetch failure, return cached tools if available (stale-while-error)
|
|
6569
6573
|
*/
|
|
6570
6574
|
declare function getServerTools(options: ServerToolsOptions): Promise<ServerTool[]>;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -6468,6 +6468,8 @@ interface CachedServerTools {
|
|
|
6468
6468
|
version: string;
|
|
6469
6469
|
/** Checksum from the server for cache invalidation */
|
|
6470
6470
|
checksum?: string;
|
|
6471
|
+
/** ETag from the server. The next refresh sends it in an If-None-Match header. */
|
|
6472
|
+
etag?: string;
|
|
6471
6473
|
}
|
|
6472
6474
|
/**
|
|
6473
6475
|
* Pluggable persistence for the fetched server-tools list.
|
|
@@ -6564,7 +6566,9 @@ declare function shouldRefreshTools(responseChecksum: string | undefined, cache:
|
|
|
6564
6566
|
* Flow:
|
|
6565
6567
|
* 1. Check the cache backend (localStorage by default; override via `cache`)
|
|
6566
6568
|
* 2. If cache valid and not force refresh, return cached tools
|
|
6567
|
-
* 3. Otherwise, fetch from API, cache, and return
|
|
6569
|
+
* 3. Otherwise, fetch from API, cache, and return. When the cache holds an ETag,
|
|
6570
|
+
* the request sends If-None-Match. On 304 the cached tools stay and only the
|
|
6571
|
+
* stored timestamp changes.
|
|
6568
6572
|
* 4. On fetch failure, return cached tools if available (stale-while-error)
|
|
6569
6573
|
*/
|
|
6570
6574
|
declare function getServerTools(options: ServerToolsOptions): Promise<ServerTool[]>;
|