cozyclay 3.1.2 → 3.1.3
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/CHANGELOG.md +25 -0
- package/README.md +1 -1
- package/bin/agent/agent-runner.mjs +160 -151
- package/bin/agent/agent-stream.mjs +86 -0
- package/bin/agent/anthropic-subscription-events.mjs +120 -0
- package/bin/agent/anthropic-subscription-prompt.mjs +116 -0
- package/bin/agent/anthropic-subscription-stream.mjs +251 -0
- package/bin/agent/anthropic-subscription.mjs +73 -0
- package/bin/agent/claude-code-executable.mjs +93 -0
- package/bin/agent/cliproxy-provider.mjs +25 -11
- package/bin/agent/model-roles.mjs +112 -0
- package/bin/agent/openai-compatible-provider.mjs +95 -0
- package/bin/agent/pi-tools.mjs +19 -10
- package/bin/agent/provider-login.mjs +3 -1
- package/bin/agent/provider-routes.mjs +2 -0
- package/bin/agent/providers.mjs +35 -130
- package/dist/app/index.html +5 -5
- package/dist/assets/TaskBoard-U1Yl-4F1.js +1 -0
- package/dist/assets/app-BdRlMf4J.css +1 -0
- package/dist/assets/app-DwETmoQZ.js +5144 -0
- package/dist/assets/{motion3-compile-dgGhrvPK.js → motion3-compile-DDG3wklD.js} +1 -1
- package/dist/assets/scene-asset-sync-Bz59Ghdz.js +13 -0
- package/dist/assets/task-board-DFfNa0xg.js +15 -0
- package/dist/assets/{workflow-C87p6E1E.js → workflow-BMJGd_gZ.js} +1 -1
- package/dist/cozyclay-package.json +1 -1
- package/dist/workflow/index.html +3 -3
- package/package.json +6 -4
- package/src/App.jsx +28 -28
- package/src/agent-image-client.js +2 -2
- package/src/asset-pane.jsx +14 -14
- package/src/character-kind.js +13 -12
- package/src/commands/project.js +2 -1
- package/src/commands/shot.js +1 -1
- package/src/commands/view.js +2 -2
- package/src/domains/cast.js +15 -15
- package/src/domains/motion/motion-range-pin-rules.js +1 -1
- package/src/domains/motion.js +11 -11
- package/src/domains/objects.js +20 -30
- package/src/domains/scenes.js +14 -21
- package/src/domains/shots.js +3 -3
- package/src/first-success-guide.jsx +19 -3
- package/src/hierarchy-panel.jsx +6 -7
- package/src/locale-zh/app.js +124 -0
- package/src/locale-zh/domains.js +36 -0
- package/src/locale-zh/labels.js +148 -0
- package/src/locale-zh/panels.js +225 -0
- package/src/locale-zh/shell.js +230 -0
- package/src/locale-zh/timeline.js +145 -0
- package/src/locale-zh/workflow.js +104 -0
- package/src/locale-zh/workspace.js +190 -0
- package/src/locale-zh.js +21 -0
- package/src/locale.js +16 -6
- package/src/main.jsx +1 -1
- package/src/motion/beat-board-model.js +4 -4
- package/src/motion/beat-board.jsx +1 -1
- package/src/motion/ik-pick.js +24 -0
- package/src/motion/take-segments.jsx +5 -5
- package/src/motion/timeline.jsx +30 -40
- package/src/motion/waypoints.js +6 -6
- package/src/object-catalog.jsx +4 -5
- package/src/panels/CameraPanel.jsx +3 -3
- package/src/panels/HdrEnvironmentControls.jsx +2 -1
- package/src/panels/ObjectTransformPanel.jsx +19 -29
- package/src/panels/PoseImagePanel.jsx +8 -8
- package/src/panels/PosePanel.jsx +2 -2
- package/src/panels/ReferenceImageField.jsx +2 -2
- package/src/panels/RigControlPanel.jsx +2 -2
- package/src/panels/SculptPanel.jsx +9 -9
- package/src/panels/SubjectBox.jsx +3 -3
- package/src/panels/SubjectsPanel.jsx +1 -1
- package/src/posestudio.jsx +10 -8
- package/src/project-browser.css +7 -6
- package/src/project-browser.jsx +7 -6
- package/src/project-open-file.js +19 -0
- package/src/qa-label.js +1 -1
- package/src/range-pin-panel.jsx +14 -14
- package/src/resource-status.jsx +3 -3
- package/src/result-modal.jsx +10 -10
- package/src/settings-menu.jsx +4 -1
- package/src/shell/BoardSlot.jsx +5 -5
- package/src/shell/CompositionGuideButton.jsx +1 -1
- package/src/shell/GhostsMenuGroup.jsx +1 -1
- package/src/shell/StatusBar.jsx +4 -4
- package/src/shell/ViewportToolbar.jsx +3 -3
- package/src/shell/add-camera-shot.js +2 -2
- package/src/shell/details-selection.js +1 -1
- package/src/shell/preference-controls.jsx +2 -1
- package/src/shot-guides.js +5 -5
- package/src/stage-hdr.js +3 -3
- package/src/stage-labels-ko.js +2 -2
- package/src/stage-startup-defaults.js +3 -3
- package/src/studio-actions.js +2 -2
- package/src/styles/tokens.css +1 -1
- package/src/styles.css +1 -1
- package/src/use-case-question.jsx +18 -18
- package/src/workflow/AgentPanel.jsx +4 -4
- package/src/workflow/AgentPlanCard.jsx +1 -1
- package/src/workflow/AgentProgressCard.jsx +4 -4
- package/src/workflow/AgentTurnSteps.jsx +1 -1
- package/src/workflow/LoginPanel.jsx +1 -1
- package/src/workflow/TaskBoard.jsx +1 -1
- package/src/workflow/TaskInline.jsx +1 -1
- package/src/workflow/agent-client.js +1 -1
- package/src/workflow/agent-turn.js +5 -5
- package/src/workflow/task-board.js +4 -4
- package/tools/loc-baseline.json +1 -1
- package/tools/run-tests.mjs +4 -4
- package/dist/assets/TaskBoard-GR8xZm5c.js +0 -1
- package/dist/assets/app-Bhe0TpGz.css +0 -1
- package/dist/assets/app-C4QTcDcb.js +0 -5144
- package/dist/assets/scene-asset-sync-qoxcdrhj.js +0 -13
- package/dist/assets/task-board-BqReHzOi.js +0 -15
package/bin/agent/providers.mjs
CHANGED
|
@@ -5,6 +5,9 @@ import { createCredentialStore } from "./credential-store.mjs";
|
|
|
5
5
|
import { readCredentials } from "./provider-keys.mjs";
|
|
6
6
|
import { cliproxyBase, cliproxyProvider, extendCliproxyProvider, registryLiveCliproxy } from "./cliproxy-provider.mjs";
|
|
7
7
|
export { cliproxyLiveModel } from "./cliproxy-provider.mjs";
|
|
8
|
+
import { OPENAI_COMPATIBLE_ID, openaiCompatibleProvider, refreshOpenAICompatible } from "./openai-compatible-provider.mjs";
|
|
9
|
+
import { rolesByMain } from "./model-roles.mjs";
|
|
10
|
+
export { MODEL_ROLES, fallbackChain, resolveRoleModels } from "./model-roles.mjs";
|
|
8
11
|
|
|
9
12
|
// #379 (F2 pass 5 finding 4): pi never forwards a per-request `fetch` to the
|
|
10
13
|
// codex API module — `pi-agent-core`'s `createRequestOptions` (the options
|
|
@@ -58,30 +61,38 @@ function ensureCodexFetchPatched() {
|
|
|
58
61
|
export const PROVIDERS = [
|
|
59
62
|
{ id: "openai-codex", label: "ChatGPT (OpenAI Codex)", auth: "chatgpt-oauth", env: [] },
|
|
60
63
|
{ id: "anthropic", label: "Anthropic", auth: "api_key", env: ["ANTHROPIC_API_KEY"] },
|
|
64
|
+
// #claude-subscription: Claude Pro/Max OAuth sign-in; requests run through the official
|
|
65
|
+
// Claude Code binary (anthropic-subscription.mjs), never against the API with a raw token.
|
|
66
|
+
{ id: "anthropic-subscription", label: "Claude (Anthropic)", auth: "oauth", env: [] },
|
|
61
67
|
{ id: "openai", label: "OpenAI", auth: "api_key", env: ["OPENAI_API_KEY"] },
|
|
62
68
|
{ id: "google", label: "Google Gemini", auth: "api_key", env: ["GEMINI_API_KEY", "GOOGLE_API_KEY"] },
|
|
69
|
+
{ id: "minimax", label: "MiniMax", auth: "api_key", env: ["MINIMAX_API_KEY"] }, { id: "minimax-cn", label: "MiniMax (China)", auth: "api_key", env: ["MINIMAX_CN_API_KEY"] },
|
|
63
70
|
{ id: "openrouter", label: "OpenRouter", auth: "api_key", env: ["OPENROUTER_API_KEY"] },
|
|
64
71
|
{ id: "cliproxy", label: "CLIProxyAPI", auth: "api_key", env: ["CLIPROXY_API_KEY"] },
|
|
72
|
+
// #885: LM Studio, Ollama or any OpenAI-compatible server; its address rides the stored credential
|
|
73
|
+
{ id: OPENAI_COMPATIBLE_ID, label: "OpenAI-compatible server", auth: "api_key", env: [] },
|
|
65
74
|
];
|
|
66
75
|
|
|
67
76
|
const factories = {
|
|
68
|
-
"openai-codex": "openaiCodexProvider",
|
|
69
|
-
anthropic: "anthropicProvider",
|
|
70
|
-
openai: "openaiProvider",
|
|
71
|
-
google: "googleProvider",
|
|
77
|
+
"openai-codex": "openaiCodexProvider", openai: "openaiProvider", google: "googleProvider", minimax: "minimaxProvider", "minimax-cn": "minimaxCnProvider",
|
|
72
78
|
openrouter: "openrouterProvider",
|
|
73
79
|
};
|
|
74
80
|
|
|
75
81
|
const providerConfig = (id) => PROVIDERS.find((provider) => provider.id === id);
|
|
76
82
|
|
|
77
|
-
export async function loadProvider(id,
|
|
78
|
-
|
|
79
|
-
const config = providerConfig(id);
|
|
80
|
-
if (!config) throw Object.assign(new Error(`Unknown provider: ${id}`), { code: "UNKNOWN_PROVIDER" });
|
|
83
|
+
export async function loadProvider(id, { baseUrl, env = process.env } = {}) {
|
|
84
|
+
if (!providerConfig(id)) throw Object.assign(new Error(`Unknown provider: ${id}`), { code: "UNKNOWN_PROVIDER" });
|
|
81
85
|
if (id === "openai-codex") ensureCodexFetchPatched();
|
|
86
|
+
// Both Anthropic lanes come from CozyClay's own module: the subscription lane, and pi-ai's
|
|
87
|
+
// API-key lane minus the OAuth login it also advertises (see anthropicLaneProvider).
|
|
82
88
|
const provider = id === "cliproxy"
|
|
83
89
|
? await cliproxyProvider({ baseUrl, env })
|
|
84
|
-
: await
|
|
90
|
+
: id === OPENAI_COMPATIBLE_ID ? await openaiCompatibleProvider() : id === "anthropic" || id === "anthropic-subscription"
|
|
91
|
+
? await import("./anthropic-subscription.mjs").then((module) => module.anthropicLaneProvider(id))
|
|
92
|
+
: await import(`@earendil-works/pi-ai/providers/${id}`).then((module) => module[factories[id]]());
|
|
93
|
+
// pi 0.99 gave the API-key OpenAI lane a ChatGPT sign-in too; CozyClay's ChatGPT sign-in is the
|
|
94
|
+
// openai-codex lane, so the panel keeps showing one ChatGPT button.
|
|
95
|
+
if (id === "openai") provider.auth = { ...provider.auth, oauth: undefined };
|
|
85
96
|
if (baseUrl && id !== "cliproxy") {
|
|
86
97
|
provider.baseUrl = baseUrl;
|
|
87
98
|
const getModels = provider.getModels.bind(provider);
|
|
@@ -95,19 +106,18 @@ const piEffort = (level) => level === "none" ? "off" : level === "ultra" ? "max"
|
|
|
95
106
|
const wireEffort = (level) => (level === "off" ? "none" : level);
|
|
96
107
|
|
|
97
108
|
const registryCatalogueState = new WeakMap();
|
|
98
|
-
|
|
99
109
|
function catalogueState(models) {
|
|
100
110
|
let state = registryCatalogueState.get(models);
|
|
101
111
|
if (!state) {
|
|
102
|
-
state = { fetch: null, models: [], extendedProviders: new WeakSet(), cliproxyFetch: null };
|
|
112
|
+
state = { fetch: null, models: [], extendedProviders: new WeakSet(), cliproxyFetch: null, cliproxyFetchError: null };
|
|
103
113
|
registryCatalogueState.set(models, state);
|
|
104
114
|
}
|
|
105
115
|
return state;
|
|
106
116
|
}
|
|
107
|
-
|
|
108
117
|
function livePiModel(model, template) {
|
|
109
118
|
const supported = new Set(model.efforts.map(piEffort));
|
|
110
|
-
|
|
119
|
+
// map values are what goes on the wire: pi sends a model's off mapping, and Codex calls it "none"
|
|
120
|
+
const thinkingLevelMap = Object.fromEntries(PI_EFFORT_LEVELS.map((level) => [level, supported.has(level) ? wireEffort(level) : null]));
|
|
111
121
|
return { ...template, id: model.id, name: model.label, thinkingLevelMap };
|
|
112
122
|
}
|
|
113
123
|
|
|
@@ -171,6 +181,8 @@ export async function resolveModel(requested, options = {}) {
|
|
|
171
181
|
if (!modelId) throw unknownModel(requested);
|
|
172
182
|
const models = options.models ?? await createModels(options);
|
|
173
183
|
if (!providerConfig(provider) && !models.getProvider?.(provider)) throw unknownModel(requested);
|
|
184
|
+
// a custom server's models are its live /v1/models list, read again when a turn names one not listed yet (#885)
|
|
185
|
+
if (provider === OPENAI_COMPATIBLE_ID && !models.getModel(provider, modelId)) await refreshOpenAICompatible(models);
|
|
174
186
|
const model = models.getModel(provider, modelId);
|
|
175
187
|
if (!model) throw unknownModel(requested);
|
|
176
188
|
return { provider, modelId, model };
|
|
@@ -207,7 +219,8 @@ function resolveAuthSource(provider, { auth, saved, env }) {
|
|
|
207
219
|
}
|
|
208
220
|
|
|
209
221
|
export function providerStatus({ auth = defaultAuth, keys = defaultKeys, env = process.env } = {}) {
|
|
210
|
-
|
|
222
|
+
// a stored API key (keys file) and an OAuth sign-in such as a subscription (auth.json) both count
|
|
223
|
+
const saved = { ...keys.readKeys(), ...readCredentials() };
|
|
211
224
|
return PROVIDERS.map((provider) => {
|
|
212
225
|
const authSource = resolveAuthSource(provider, { auth, saved, env });
|
|
213
226
|
return { id: provider.id, label: provider.label, authSource, signedIn: !!authSource };
|
|
@@ -254,119 +267,6 @@ function liveModelsCodex(result) {
|
|
|
254
267
|
}).filter((model) => model.id);
|
|
255
268
|
}
|
|
256
269
|
|
|
257
|
-
// --- model roles (#717) ------------------------------------------------------
|
|
258
|
-
//
|
|
259
|
-
// One picked model (main) implies the rest of the lineup a turn may lean on: a
|
|
260
|
-
// cheap helper, a mid-tier advisor, a model that can see images, and the
|
|
261
|
-
// ordered alternatives to try when main fails. Subscription accounts usually
|
|
262
|
-
// have exactly one signed-in provider, so every derived role stays on main's
|
|
263
|
-
// provider; only the fallback chain may cross to another signed-in provider
|
|
264
|
-
// that serves the very same model id. Both functions are pure over a
|
|
265
|
-
// listAgentModels-shaped `{ providers }` catalog and never throw.
|
|
266
|
-
|
|
267
|
-
export const MODEL_ROLES = ["main", "helper", "vision", "advisor"];
|
|
268
|
-
|
|
269
|
-
const CLAUDE_TIERS = ["opus", "sonnet", "haiku"];
|
|
270
|
-
const GPT_MINI_CLASS = /mini|nano/;
|
|
271
|
-
const newestFirst = (a, b) => b.id.localeCompare(a.id, undefined, { numeric: true });
|
|
272
|
-
|
|
273
|
-
function splitModelKey(key) {
|
|
274
|
-
const slash = typeof key === "string" ? key.indexOf("/") : -1;
|
|
275
|
-
return slash > 0 ? { providerId: key.slice(0, slash), modelId: key.slice(slash + 1) } : null;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const modelFamily = (id) => /^claude-/.test(id) ? "claude" : /^gpt-/.test(id) ? "gpt" : null;
|
|
279
|
-
const claudeTier = (id) => CLAUDE_TIERS.find((tier) => id.startsWith(`claude-${tier}`)) ?? null;
|
|
280
|
-
const takesImages = (model) => Array.isArray(model?.input) && model.input.includes("image");
|
|
281
|
-
const modelKeyOf = (providerId, model) => model.key ?? `${providerId}/${model.id}`;
|
|
282
|
-
|
|
283
|
-
/** main's provider entry, main's own model entry and the same-family models on that provider. */
|
|
284
|
-
function locateMain(mainKey, catalog) {
|
|
285
|
-
const parts = splitModelKey(mainKey);
|
|
286
|
-
const providers = Array.isArray(catalog?.providers) ? catalog.providers : [];
|
|
287
|
-
const provider = parts && providers.find((entry) => entry?.id === parts.providerId);
|
|
288
|
-
const models = Array.isArray(provider?.models) ? provider.models.filter((model) => typeof model?.id === "string") : [];
|
|
289
|
-
const main = parts && models.find((model) => model.id === parts.modelId);
|
|
290
|
-
if (!main) return null;
|
|
291
|
-
const family = modelFamily(main.id);
|
|
292
|
-
return { providers, provider, models, main, family, sameFamily: family ? models.filter((model) => modelFamily(model.id) === family) : [] };
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/** The first preference that matches a model: an exact id, or the newest id a pattern matches. */
|
|
296
|
-
function pickModel(models, preferences) {
|
|
297
|
-
for (const preference of preferences) {
|
|
298
|
-
const match = typeof preference === "string"
|
|
299
|
-
? models.find((model) => model.id === preference)
|
|
300
|
-
: [...models].filter((model) => preference.test(model.id)).sort(newestFirst)[0];
|
|
301
|
-
if (match) return match;
|
|
302
|
-
}
|
|
303
|
-
return null;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/** One tier of a Claude lineup, preferring main's own version (opus-5-5 -> sonnet-5-5). */
|
|
307
|
-
function claudeTierModel(models, mainId, tier) {
|
|
308
|
-
const current = claudeTier(mainId);
|
|
309
|
-
return pickModel(models, [current ? mainId.replace(`claude-${current}`, `claude-${tier}`) : null, new RegExp(`^claude-${tier}`)].filter(Boolean));
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
export function resolveRoleModels(mainKey, catalog) {
|
|
313
|
-
const main = typeof mainKey === "string" ? mainKey : "";
|
|
314
|
-
const found = locateMain(main, catalog);
|
|
315
|
-
if (!found) return { main, helper: main, vision: main, advisor: main };
|
|
316
|
-
const { provider, models, main: model, family, sameFamily } = found;
|
|
317
|
-
const key = (entry) => (entry ? modelKeyOf(provider.id, entry) : main);
|
|
318
|
-
const helper = family === "claude" ? pickModel(sameFamily, ["claude-haiku-5-5", /^claude-haiku/, /^claude-sonnet/])
|
|
319
|
-
: family === "gpt" ? pickModel(sameFamily, [GPT_MINI_CLASS, /luna/])
|
|
320
|
-
: null;
|
|
321
|
-
const advisor = family === "claude" ? pickModel(sameFamily, ["claude-sonnet-5-5", /^claude-sonnet/])
|
|
322
|
-
: family === "gpt" ? pickModel(sameFamily, ["gpt-6-astra"])
|
|
323
|
-
: null;
|
|
324
|
-
const vision = takesImages(model) ? model : models.find(takesImages);
|
|
325
|
-
return { main, helper: key(helper), vision: key(vision), advisor: key(advisor) };
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
export function fallbackChain(mainKey, catalog) {
|
|
329
|
-
const found = locateMain(mainKey, catalog);
|
|
330
|
-
if (!found) return [];
|
|
331
|
-
const { providers, provider, main, family, sameFamily } = found;
|
|
332
|
-
const chain = [];
|
|
333
|
-
// The same model served by another signed-in provider is the closest substitute there is.
|
|
334
|
-
for (const other of providers) {
|
|
335
|
-
if (other === provider || !other?.signedIn || !Array.isArray(other.models)) continue;
|
|
336
|
-
const same = other.models.find((model) => model?.id === main.id);
|
|
337
|
-
if (same) chain.push(modelKeyOf(other.id, same));
|
|
338
|
-
}
|
|
339
|
-
// Then a step down main's own family on main's provider.
|
|
340
|
-
if (family === "claude") {
|
|
341
|
-
const tier = CLAUDE_TIERS.indexOf(claudeTier(main.id));
|
|
342
|
-
if (tier !== -1) {
|
|
343
|
-
for (const lower of CLAUDE_TIERS.slice(tier + 1)) {
|
|
344
|
-
const model = claudeTierModel(sameFamily, main.id, lower);
|
|
345
|
-
if (model) chain.push(modelKeyOf(provider.id, model));
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
} else if (family === "gpt" && !GPT_MINI_CLASS.test(main.id)) {
|
|
349
|
-
for (const model of [pickModel(sameFamily, ["gpt-6-astra"]), pickModel(sameFamily, [GPT_MINI_CLASS])]) {
|
|
350
|
-
if (model) chain.push(modelKeyOf(provider.id, model));
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
const mainKeyFound = modelKeyOf(provider.id, main);
|
|
354
|
-
return [...new Set(chain)].filter((key) => key !== mainKeyFound).slice(0, 3);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/** `roles.byMain` for listAgentModels: every model of every signed-in provider. */
|
|
358
|
-
function rolesByMain(catalog) {
|
|
359
|
-
const byMain = {};
|
|
360
|
-
for (const provider of catalog.providers) {
|
|
361
|
-
if (!provider.signedIn) continue;
|
|
362
|
-
for (const model of provider.models) {
|
|
363
|
-
const { helper, vision, advisor } = resolveRoleModels(model.key, catalog);
|
|
364
|
-
byMain[model.key] = { helper, vision, advisor, fallback: fallbackChain(model.key, catalog) };
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return { byMain };
|
|
368
|
-
}
|
|
369
|
-
|
|
370
270
|
const astraFirst = (a, b) => Number(b.id === "gpt-6-astra") - Number(a.id === "gpt-6-astra");
|
|
371
271
|
const cliproxyFirst = (a, b) => astraFirst(a, b) || Number(b.id === "claude-fable-5-1") - Number(a.id === "claude-fable-5-1");
|
|
372
272
|
|
|
@@ -379,7 +279,8 @@ const cliproxyFirst = (a, b) => astraFirst(a, b) || Number(b.id === "claude-fabl
|
|
|
379
279
|
export async function listAgentModels({ models, codex, auth = defaultAuth, keys = defaultKeys, env = process.env } = {}) {
|
|
380
280
|
const { getSupportedThinkingLevels } = await import("@earendil-works/pi-ai");
|
|
381
281
|
const resolvedModels = models ?? await createModels({ auth, keys, env });
|
|
382
|
-
|
|
282
|
+
// a stored API key (keys file) and an OAuth sign-in such as a subscription (auth.json) both count
|
|
283
|
+
const saved = { ...keys.readKeys(), ...readCredentials() };
|
|
383
284
|
const providers = [];
|
|
384
285
|
for (const provider of PROVIDERS) {
|
|
385
286
|
const authResult = await resolvedModels.getAuth(provider.id).catch(() => undefined);
|
|
@@ -408,14 +309,18 @@ export async function listAgentModels({ models, codex, auth = defaultAuth, keys
|
|
|
408
309
|
}
|
|
409
310
|
}
|
|
410
311
|
list = [...list].sort(cliproxyFirst);
|
|
312
|
+
const error = catalogueState(resolvedModels).cliproxyFetchError; providers.push({ id: provider.id, label: provider.label, signedIn, authSource, models: list, ...(error ? { error } : {}) }); continue;
|
|
313
|
+
} else if (provider.id === OPENAI_COMPATIBLE_ID && signedIn) {
|
|
314
|
+
// the server's own /v1/models is the lineup, read on every listing so a model loaded since then shows up
|
|
315
|
+
const error = await refreshOpenAICompatible(resolvedModels);
|
|
316
|
+
providers.push({ id: provider.id, label: provider.label, signedIn, authSource, models: catalogModels(resolvedModels, provider.id, getSupportedThinkingLevels), ...(error ? { error } : {}) }); continue;
|
|
411
317
|
}
|
|
412
318
|
providers.push({ id: provider.id, label: provider.label, signedIn, authSource, models: list });
|
|
413
319
|
}
|
|
414
320
|
// a provider outside the curated list joins the picker once a pi login stored its credential here (#pi-login); ambient
|
|
415
321
|
// credentials (an AWS profile, cloud ADC files) alone do not list it, so the picker shows what the author connected
|
|
416
|
-
const stored = new Set([...Object.keys(readCredentials()), ...Object.keys(saved)]);
|
|
417
322
|
for (const provider of resolvedModels.getProviders?.() ?? []) {
|
|
418
|
-
const check = providerConfig(provider.id) || !
|
|
323
|
+
const check = providerConfig(provider.id) || !(provider.id in saved) ? undefined : await resolvedModels.checkAuth?.(provider.id).catch(() => undefined);
|
|
419
324
|
if (check) providers.push({ id: provider.id, label: provider.name ?? provider.id, signedIn: true, authSource: check.type === "oauth" || /stored/i.test(check.source ?? "") ? "file" : "env", models: catalogModels(resolvedModels, provider.id, getSupportedThinkingLevels) });
|
|
420
325
|
}
|
|
421
326
|
// The flat union is what the panel's dropdown reads today (`models[].id`);
|
package/dist/app/index.html
CHANGED
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
<title>CozyClay Studio — 3D staging and previs in your browser</title>
|
|
35
35
|
|
|
36
36
|
<script defer src="https://static.cloudflareinsights.com/beacon.min.js" data-cf-beacon='{"token": "6a4384d1375d4ffc8a30a6346a8ad1a0"}'></script>
|
|
37
|
-
<script type="module" crossorigin src="/assets/app-
|
|
37
|
+
<script type="module" crossorigin src="/assets/app-DwETmoQZ.js"></script>
|
|
38
38
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-hePW80VL.js">
|
|
39
39
|
<link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-P2Xu9kJm.js">
|
|
40
|
-
<link rel="modulepreload" crossorigin href="/assets/task-board-
|
|
40
|
+
<link rel="modulepreload" crossorigin href="/assets/task-board-DFfNa0xg.js">
|
|
41
41
|
<link rel="modulepreload" crossorigin href="/assets/fflate.module-KbGj5-H6.js">
|
|
42
|
-
<link rel="modulepreload" crossorigin href="/assets/scene-asset-sync-
|
|
43
|
-
<link rel="modulepreload" crossorigin href="/assets/motion3-compile-
|
|
42
|
+
<link rel="modulepreload" crossorigin href="/assets/scene-asset-sync-Bz59Ghdz.js">
|
|
43
|
+
<link rel="modulepreload" crossorigin href="/assets/motion3-compile-DDG3wklD.js">
|
|
44
44
|
<link rel="stylesheet" crossorigin href="/assets/scene-asset-sync-BEjjhNEo.css">
|
|
45
|
-
<link rel="stylesheet" crossorigin href="/assets/app-
|
|
45
|
+
<link rel="stylesheet" crossorigin href="/assets/app-BdRlMf4J.css">
|
|
46
46
|
</head>
|
|
47
47
|
<body>
|
|
48
48
|
<div id="root">
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{Ti as t,c as n,d as r,f as i,fa as a,l as o,m as s,o as c,v as l}from"./task-board-DFfNa0xg.js";import{o as u,r as d,t as f}from"./motion3-compile-DDG3wklD.js";var p=e(a(),1),m=2e3,h=(e,t)=>new Promise(n=>{let r=setTimeout(n,e);t.addEventListener(`abort`,()=>{clearTimeout(r),n()},{once:!0})});function g(e,n){(0,p.useEffect)(()=>{let r=new Map;for(let[t,i]of Object.entries(e))for(let e of i)r.set(e,n[t]??t);let i=()=>{for(let e of document.querySelectorAll(`[data-node-id]`)){let n=r.get(e.getAttribute(`data-node-id`));n?(e.setAttribute(`data-task-scope`,n),e.setAttribute(`title`,t(`In task: ${n}`,`작업 중: ${n}`,`任务中:${n}`))):e.hasAttribute(`data-task-scope`)&&(e.removeAttribute(`data-task-scope`),e.removeAttribute(`title`))}};i();let a=new MutationObserver(i);return a.observe(document.body,{childList:!0,subtree:!0}),()=>{a.disconnect(),r.clear(),i()}},[e,n])}function _({sessionId:e,pulse:t,labelOf:a,onMainNote:_}){let v=(0,p.useMemo)(()=>c(),[]),y=u(),[b,x]=(0,p.useReducer)((e,t)=>t.seed?s(e,t.seed):t.reset?n():r(e,t.event),void 0,n),[S,C]=(0,p.useState)({}),[w,T]=(0,p.useState)(f),E=(0,p.useRef)(0),D=(0,p.useRef)(_);(0,p.useEffect)(()=>{E.current=b.after,D.current=_},[b.after,_]),(0,p.useEffect)(()=>{x({reset:!0}),E.current=0},[e]),(0,p.useEffect)(()=>d(T),[]),(0,p.useEffect)(()=>y.subscribe(e=>{typeof e?.type!=`string`||!e.type.startsWith(`task.`)||(C(t=>i(t,e)),(e.type===`task.userEdit`||e.type===`task.undone`)&&x({event:e}))}),[y]),(0,p.useEffect)(()=>{if(!e)return;let t=new AbortController;return(async()=>{for(;!t.signal.aborted;){try{let{tasks:n}=await v.board(e);x({seed:n}),await v.events(e,E.current,e=>{if(e.type===`main.turn`&&e.turnId){let n=``;v.frames(e.turnId,e=>{e.type===`text.delta`&&(n+=e.text??``),e.type===`tool.start`&&(n=``)},t.signal).then(()=>D.current?.(n),()=>{})}x({event:e})},t.signal)}catch{}await h(m,t.signal)}})(),()=>t.abort()},[v,e,t]);let O=b.order.filter(e=>b.tasks[e]?.status===`running`&&b.tasks[e]?.turnId),k=O.map(e=>`${e}:${b.tasks[e].turnId}`).join();return(0,p.useEffect)(()=>{let e=O.map(e=>{let t=new AbortController,{turnId:n}=b.tasks[e];return v.frames(n,t=>{let n=o(t,a);n&&x({event:{type:`task.progress`,taskId:e,status:`running`,progress:n}})},t.signal).catch(()=>{}),t});return()=>e.forEach(e=>e.abort())},[v,k,a]),g(S,(0,p.useMemo)(()=>Object.fromEntries(b.order.map(e=>[e,b.tasks[e].title])),[b])),(0,p.useEffect)(()=>{l.set({client:v,labelOf:a,undo:async e=>{let t=await y.run(`task.undo`,{taskId:e});if(t?.ok===!1)throw Error(t.message??t.code);x({event:{type:`task.undone`,taskId:e}})}})},[y,v,a]),(0,p.useEffect)(()=>{l.set({board:b,activity:w})},[b,w]),(0,p.useEffect)(()=>()=>l.set({board:n(),open:null}),[e]),null}export{_ as default};
|