@sparkelf/dsh-dataops-managed 0.3.14 → 0.3.16

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/lib/client.js CHANGED
@@ -133,6 +133,26 @@ window.__ModuleLoader__.load({
133
133
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
134
134
  }
135
135
  /**
136
+ * A write DataOps refused, carrying the reason it gave.
137
+ *
138
+ * The message is written for the person who set the value, so the panel shows it as-is rather
139
+ * than replacing it with a generic failure notice.
140
+ */
141
+ var WorkspaceLimitsRejection = class extends Error {
142
+ constructor(message) {
143
+ super(message);
144
+ this.name = "WorkspaceLimitsRejection";
145
+ }
146
+ };
147
+ /** Read the reason from a refused response, falling back to the status line. */
148
+ async function refusalReason$1(response, fallback) {
149
+ try {
150
+ const error = readJson(await response.json())?.error;
151
+ if (typeof error === "string" && error.trim() !== "") return error;
152
+ } catch {}
153
+ return `${fallback} with HTTP ${String(response.status)}`;
154
+ }
155
+ /**
136
156
  * Read the workspace limits the panel shows.
137
157
  * @returns The status, or null when the workspace is not connected to DataOps.
138
158
  */
@@ -155,13 +175,63 @@ window.__ModuleLoader__.load({
155
175
  body: JSON.stringify(limits)
156
176
  });
157
177
  if (response.status === 503) return null;
158
- if (!response.ok) throw new Error(`Workspace limits write failed with HTTP ${String(response.status)}`);
178
+ if (response.status === 400) throw new WorkspaceLimitsRejection(await refusalReason$1(response, "Workspace limits write refused"));
179
+ if (!response.ok) throw new Error(await refusalReason$1(response, "Workspace limits write failed"));
159
180
  const body = readJson(await response.json());
160
181
  return body === null ? null : asStatus(body);
161
182
  }
162
183
  //#endregion
184
+ //#region src/client/tool-timeout-client.ts
185
+ /** Same-origin tool-call timeout calls from the DataOps settings surface. */
186
+ /** Route the plugin's Host half serves for the tool-call timeout. */
187
+ const TOOL_TIMEOUT_PATH = "/integrations/dataops/tool-timeout";
188
+ /** Narrow a response body to the timeout, rejecting anything else. */
189
+ function asTimeout(value) {
190
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
191
+ const ms = value.toolCallTimeoutMs;
192
+ return typeof ms === "number" && Number.isSafeInteger(ms) && ms > 0 ? { toolCallTimeoutMs: ms } : null;
193
+ }
194
+ /** Read the reason from a refused response, falling back to the status line. */
195
+ async function refusalReason(response, fallback) {
196
+ try {
197
+ const body = await response.json();
198
+ if (typeof body === "object" && body !== null && !Array.isArray(body)) {
199
+ const error = body.error;
200
+ if (typeof error === "string" && error.trim() !== "") return error;
201
+ }
202
+ } catch {}
203
+ return fallback + " with HTTP " + String(response.status);
204
+ }
205
+ /**
206
+ * Read the tool-call timeout the panel shows.
207
+ * @returns The timeout, or null when the workspace is not connected.
208
+ */
209
+ async function fetchToolTimeout() {
210
+ const response = await fetch(TOOL_TIMEOUT_PATH, { credentials: "same-origin" });
211
+ if (response.status === 503) return null;
212
+ if (!response.ok) throw new Error("Tool timeout read failed with HTTP " + String(response.status));
213
+ return asTimeout(await response.json());
214
+ }
215
+ /**
216
+ * Store a new tool-call timeout.
217
+ * @param milliseconds - How long one tool call may run.
218
+ * @returns The stored timeout, or null when the workspace is not connected.
219
+ */
220
+ async function saveToolTimeout(milliseconds) {
221
+ const response = await fetch(TOOL_TIMEOUT_PATH, {
222
+ method: "POST",
223
+ credentials: "same-origin",
224
+ headers: { "content-type": "application/json" },
225
+ body: JSON.stringify({ toolCallTimeoutMs: milliseconds })
226
+ });
227
+ if (response.status === 503) return null;
228
+ if (response.status === 400) throw new Error(await refusalReason(response, "Tool timeout write refused"));
229
+ if (!response.ok) throw new Error(await refusalReason(response, "Tool timeout write failed"));
230
+ return asTimeout(await response.json());
231
+ }
232
+ //#endregion
163
233
  //#region \0dsh-css:/root/projects/dsh-plugins-plus/packages/dataops-managed/src/client/ManagedDataOpsSection.module.css.mjs
164
- const css$2 = "._2dqzjG_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:14px;display:flex}._2dqzjG_title{margin:0;font-size:16px;font-weight:500;line-height:24px}._2dqzjG_statusRow{align-items:center;gap:8px;min-height:24px;font-size:14px;line-height:22px;display:flex}._2dqzjG_description{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}._2dqzjG_details{margin:2px 0 0}._2dqzjG_detailRow{grid-template-columns:minmax(140px,2fr) minmax(0,3fr);gap:20px;padding:12px 0;display:grid}._2dqzjG_detailRow+._2dqzjG_detailRow{border-top:1px solid var(--dsw-alias-border-l2)}._2dqzjG_detailRow dt,._2dqzjG_detailRow dd{margin:0;font-size:14px;line-height:22px}._2dqzjG_detailRow dt{color:var(--dsw-alias-label-secondary)}._2dqzjG_detailRow dd{color:var(--dsw-alias-label-primary)}._2dqzjG_brandingRow{border-top:1px solid var(--dsw-alias-border-l2);align-items:center;gap:20px;padding:14px 0 12px;display:flex}._2dqzjG_brandingCopy{flex-direction:column;flex:1;gap:3px;min-width:0;display:flex}._2dqzjG_brandingCopy strong{font-size:14px;font-weight:500;line-height:22px}._2dqzjG_brandingCopy span{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}._2dqzjG_switch{background:var(--dsw-alias-border-l1);cursor:pointer;border:0;border-radius:10px;flex:none;width:34px;height:20px;padding:0;transition:background-color .12s;position:relative}._2dqzjG_switch>span{background:var(--dsw-alias-bg-base);border-radius:50%;width:14px;height:14px;transition:transform .12s;position:absolute;top:3px;left:3px;box-shadow:0 1px 2px #0003}._2dqzjG_switch[data-checked=true]{background:var(--dsw-alias-state-business-primary)}._2dqzjG_switch[data-checked=true]>span{transform:translate(14px)}._2dqzjG_switch:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}@media (prefers-reduced-motion:reduce){._2dqzjG_switch,._2dqzjG_switch>span{transition:none}}._2dqzjG_modelPanel{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding:14px 0 12px;display:flex}._2dqzjG_modelTitle{margin:0;font-size:14px;font-weight:500;line-height:22px}._2dqzjG_modelDescription{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}._2dqzjG_modelList{flex-direction:column;gap:8px;padding-top:4px;display:flex}._2dqzjG_modelListTitle{font-size:13px;font-weight:500;line-height:20px}._2dqzjG_modelListDescription{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}._2dqzjG_modelRow{align-items:center;gap:16px;min-height:28px;display:flex}._2dqzjG_modelId{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;line-height:20px;overflow:hidden}._2dqzjG_modelAction{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:6px;flex:none;padding:5px 12px;font-size:13px;line-height:20px}._2dqzjG_modelAction:hover:not(:disabled){background:var(--dsw-alias-bg-hover)}._2dqzjG_modelAction:disabled,._2dqzjG_switch:disabled{cursor:default;opacity:.5}._2dqzjG_limitsInput{border:1px solid var(--dsw-alias-border-l2);width:6rem;color:var(--dsw-alias-label-primary);background:0 0;border-radius:6px;padding:4px 8px;font-size:13px;line-height:20px}";
234
+ const css$2 = "._2dqzjG_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}._2dqzjG_title{margin:0;font-size:18px;font-weight:600;line-height:28px}._2dqzjG_status{color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;font-size:13px;line-height:22px;display:flex}._2dqzjG_card{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-xl);background:var(--dsw-alias-settings-card-fill);flex-direction:column;gap:12px;padding:12px 16px;display:flex}._2dqzjG_heading{margin:0;font-size:13px;font-weight:600;line-height:22px}._2dqzjG_row{justify-content:space-between;align-items:center;gap:16px;display:flex}._2dqzjG_copy{flex-direction:column;min-width:0;display:flex}._2dqzjG_label{font-size:13px;line-height:22px}._2dqzjG_meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}._2dqzjG_fields{grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:0 16px;display:grid}._2dqzjG_fields>div{min-width:0}._2dqzjG_fields input{font-variant-numeric:tabular-nums;min-width:0}._2dqzjG_actions{justify-content:flex-end;align-items:center;gap:12px;display:flex}._2dqzjG_refusal{color:var(--dsw-alias-state-error-primary);align-items:flex-start;gap:6px;margin-right:auto;font-size:12px;line-height:18px;display:flex}";
165
235
  const tagId$2 = "@sparkelf/dsh-dataops-managed/ManagedDataOpsSection.module.css";
166
236
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
167
237
  const tag = document.createElement("style");
@@ -171,30 +241,43 @@ window.__ModuleLoader__.load({
171
241
  document.head.appendChild(tag);
172
242
  }
173
243
  var ManagedDataOpsSection_module_css_default = {
174
- "brandingCopy": "_2dqzjG_brandingCopy",
175
- "modelTitle": "_2dqzjG_modelTitle",
176
- "details": "_2dqzjG_details",
177
- "limitsInput": "_2dqzjG_limitsInput",
178
- "modelPanel": "_2dqzjG_modelPanel",
179
- "section": "_2dqzjG_section",
180
- "statusRow": "_2dqzjG_statusRow",
181
- "switch": "_2dqzjG_switch",
182
- "description": "_2dqzjG_description",
183
- "modelListDescription": "_2dqzjG_modelListDescription",
184
- "modelRow": "_2dqzjG_modelRow",
244
+ "card": "_2dqzjG_card",
245
+ "status": "_2dqzjG_status",
246
+ "label": "_2dqzjG_label",
185
247
  "title": "_2dqzjG_title",
186
- "modelList": "_2dqzjG_modelList",
187
- "brandingRow": "_2dqzjG_brandingRow",
188
- "detailRow": "_2dqzjG_detailRow",
189
- "modelAction": "_2dqzjG_modelAction",
190
- "modelId": "_2dqzjG_modelId",
191
- "modelListTitle": "_2dqzjG_modelListTitle",
192
- "modelDescription": "_2dqzjG_modelDescription"
248
+ "refusal": "_2dqzjG_refusal",
249
+ "row": "_2dqzjG_row",
250
+ "section": "_2dqzjG_section",
251
+ "heading": "_2dqzjG_heading",
252
+ "copy": "_2dqzjG_copy",
253
+ "meta": "_2dqzjG_meta",
254
+ "fields": "_2dqzjG_fields",
255
+ "actions": "_2dqzjG_actions"
193
256
  };
194
257
  //#endregion
195
258
  //#region src/client/ManagedDataOpsSection.tsx
259
+ /** The panel's unit, so a stored byte count survives a round trip through the input. */
260
+ const BYTES_PER_MIB = 1048576;
261
+ /** Render a byte ceiling as the whole MiB the input shows. */
262
+ function toMib(bytes) {
263
+ return String(Math.round(bytes / BYTES_PER_MIB * 100) / 100);
264
+ }
265
+ /** Parse a MiB draft into a byte ceiling, or null when it is not a positive count. */
266
+ function toBytes(text) {
267
+ if (text.trim() === "") return null;
268
+ const mib = Number(text);
269
+ if (!Number.isFinite(mib) || mib <= 0) return null;
270
+ const bytes = Math.round(mib * BYTES_PER_MIB);
271
+ return Number.isSafeInteger(bytes) && bytes > 0 ? bytes : null;
272
+ }
273
+ /** Format a stored publication time for the row, or nothing when it never published. */
274
+ function publishedText(publishedAt) {
275
+ const at = new Date(publishedAt);
276
+ return Number.isNaN(at.getTime()) ? null : at.toLocaleString();
277
+ }
196
278
  /**
197
- * Explain the DataOps-managed JWT and permission owner, and share model configuration.
279
+ * The DataOps settings this workspace owns: its connection state, its branding, its file ceilings,
280
+ * and the default configuration it publishes to other workspaces.
198
281
  * @param props - Settings slot injection values.
199
282
  * @returns The localized managed DataOps section, or nothing before injection.
200
283
  */
@@ -210,171 +293,222 @@ window.__ModuleLoader__.load({
210
293
  children: t("title")
211
294
  }),
212
295
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
213
- className: ManagedDataOpsSection_module_css_default.statusRow,
214
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "done" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("managed") })]
296
+ className: ManagedDataOpsSection_module_css_default.status,
297
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "done" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("managed") })]
215
298
  }),
216
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
217
- className: ManagedDataOpsSection_module_css_default.description,
218
- children: t("description")
299
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BrandingRow, {
300
+ t,
301
+ enabled: branding.enabled
219
302
  }),
220
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
221
- className: ManagedDataOpsSection_module_css_default.brandingRow,
222
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
223
- className: ManagedDataOpsSection_module_css_default.brandingCopy,
224
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("brandingTitle") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("brandingDescription") })]
225
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
226
- type: "button",
227
- className: ManagedDataOpsSection_module_css_default.switch,
228
- role: "switch",
229
- "aria-label": t("brandingToggle"),
230
- "aria-checked": branding.enabled,
231
- "data-checked": branding.enabled,
232
- onClick: () => {
233
- setWanxiangBrandEnabled(!branding.enabled);
234
- },
235
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {})
236
- })]
237
- }),
238
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PublishDefaults, { t }),
239
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceLimitsPanel, { t }),
240
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
241
- className: ManagedDataOpsSection_module_css_default.details,
242
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
243
- className: ManagedDataOpsSection_module_css_default.detailRow,
244
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("identityLabel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: t("identityValue") })]
245
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
246
- className: ManagedDataOpsSection_module_css_default.detailRow,
247
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("toolsLabel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: t("toolsValue") })]
248
- })]
249
- })
303
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LimitsCard, { t }),
304
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TimeoutCard, { t }),
305
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultsCard, { t })
250
306
  ]
251
307
  });
252
308
  }
309
+ /** The branding toggle as one settings row. */
310
+ function BrandingRow({ t, enabled }) {
311
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
312
+ className: ManagedDataOpsSection_module_css_default.card,
313
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
314
+ className: ManagedDataOpsSection_module_css_default.row,
315
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
316
+ className: ManagedDataOpsSection_module_css_default.label,
317
+ children: t("brandingTitle")
318
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
319
+ checked: enabled,
320
+ label: t("brandingToggle"),
321
+ onChange: (next) => {
322
+ setWanxiangBrandEnabled(next);
323
+ }
324
+ })]
325
+ })
326
+ });
327
+ }
328
+ /** The one row a card renders while it cannot offer its controls. */
329
+ function UnavailableCard({ title, t, state }) {
330
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
331
+ className: ManagedDataOpsSection_module_css_default.card,
332
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
333
+ className: ManagedDataOpsSection_module_css_default.heading,
334
+ children: title
335
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
336
+ className: ManagedDataOpsSection_module_css_default.status,
337
+ role: state === "failed" ? "alert" : void 0,
338
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: state === "failed" ? "error" : "idle" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: state === "failed" ? t("loadFailed") : t("unavailable") })]
339
+ })]
340
+ });
341
+ }
253
342
  /**
254
- * Publish this workspace's configuration as the default other users start from.
343
+ * The file ceilings DataOps enforces on this workspace.
255
344
  *
256
- * One action rather than a set of controls: the configuration is whatever this workspace already
257
- * holds -- the models, the permission default, the general settings -- and the button copies it to
258
- * DataOps. Every other user's workspace takes that copy as its starting values and may then change
259
- * anything, at which point their own version wins and this button never reaches it again.
345
+ * The values live in DataOps and are read through the plugin, which holds the JWT; the panel only
346
+ * ever holds what the administrator is allowed to see.
260
347
  * @param props - Translate function from the section.
261
- * @returns The publish row.
348
+ * @returns The limits card.
262
349
  */
263
- function PublishDefaults({ t }) {
350
+ function LimitsCard({ t }) {
264
351
  const [state, setState] = (0, react.useState)({ kind: "loading" });
352
+ const [fileReadMib, setFileReadMib] = (0, react.useState)("");
353
+ const [uploadMib, setUploadMib] = (0, react.useState)("");
354
+ /** The ceilings the draft started from, so Save stays off until one of them changes. */
355
+ const [saved, setSaved] = (0, react.useState)("");
356
+ /** Why DataOps refused the last save, kept beside the draft it refused. */
357
+ const [refusal, setRefusal] = (0, react.useState)(null);
265
358
  const [busy, setBusy] = (0, react.useState)(false);
359
+ const fileReadId = (0, react.useId)();
360
+ const uploadId = (0, react.useId)();
361
+ const apply = (0, react.useCallback)((status) => {
362
+ setState({
363
+ kind: "ready",
364
+ status
365
+ });
366
+ const file = toMib(status.limits.fileReadMaxBytes);
367
+ const upload = toMib(status.limits.uploadMaxBytes);
368
+ setFileReadMib(file);
369
+ setUploadMib(upload);
370
+ setSaved(file + "|" + upload);
371
+ setRefusal(null);
372
+ }, []);
266
373
  const refresh = (0, react.useCallback)(async () => {
267
374
  try {
268
- const status = await fetchModelSyncStatus();
269
- setState(status === null ? { kind: "unavailable" } : {
270
- kind: "ready",
271
- status
272
- });
375
+ const status = await fetchWorkspaceLimits();
376
+ if (status === null) setState({ kind: "unavailable" });
377
+ else apply(status);
273
378
  } catch {
274
379
  setState({ kind: "failed" });
275
380
  }
276
- }, []);
381
+ }, [apply]);
277
382
  (0, react.useEffect)(() => {
278
383
  refresh();
279
384
  }, [refresh]);
280
- const publish = (0, react.useCallback)(async () => {
385
+ const fileReadBytes = toBytes(fileReadMib);
386
+ const uploadBytes = toBytes(uploadMib);
387
+ const writable = state.kind === "ready" && state.status.canWrite;
388
+ const dirty = fileReadMib + "|" + uploadMib !== saved;
389
+ const ready = fileReadBytes !== null && uploadBytes !== null && dirty;
390
+ /** Edit one ceiling, dropping a refusal that no longer describes what is in the field. */
391
+ const edit = (0, react.useCallback)((set) => (text) => {
392
+ set(text);
393
+ setRefusal(null);
394
+ }, []);
395
+ const submit = (0, react.useCallback)(async () => {
396
+ if (fileReadBytes === null || uploadBytes === null) return;
281
397
  setBusy(true);
398
+ setRefusal(null);
282
399
  try {
283
- const status = await postModelSyncAction({ action: "publish-defaults" });
284
- if (status !== null) setState({
285
- kind: "ready",
286
- status
400
+ const status = await saveWorkspaceLimits({
401
+ fileReadMaxBytes: fileReadBytes,
402
+ uploadMaxBytes: uploadBytes
287
403
  });
288
- } catch {
289
- setState({ kind: "failed" });
404
+ if (status === null) setState({ kind: "unavailable" });
405
+ else apply(status);
406
+ } catch (error) {
407
+ if (error instanceof WorkspaceLimitsRejection) setRefusal(error.message);
408
+ else setState({ kind: "failed" });
290
409
  } finally {
291
410
  setBusy(false);
292
411
  }
293
- }, []);
412
+ }, [
413
+ fileReadBytes,
414
+ uploadBytes,
415
+ apply
416
+ ]);
294
417
  if (state.kind === "loading") return null;
295
- if (state.kind === "unavailable" || state.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
296
- className: ManagedDataOpsSection_module_css_default.modelPanel,
297
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
298
- className: ManagedDataOpsSection_module_css_default.modelTitle,
299
- children: t("defaultsTitle")
300
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
301
- className: ManagedDataOpsSection_module_css_default.modelDescription,
302
- role: state.kind === "failed" ? "alert" : void 0,
303
- children: state.kind === "failed" ? t("loadFailed") : t("modelsUnavailable")
304
- })]
418
+ if (state.kind !== "ready") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnavailableCard, {
419
+ title: t("limitsTitle"),
420
+ t,
421
+ state: state.kind
305
422
  });
306
- const { status } = state;
307
- if (!status.canPublish) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
308
- className: ManagedDataOpsSection_module_css_default.modelPanel,
309
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
310
- className: ManagedDataOpsSection_module_css_default.modelTitle,
311
- children: t("defaultsTitle")
312
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
313
- className: ManagedDataOpsSection_module_css_default.modelDescription,
314
- children: t("defaultsNotAdmin")
315
- })]
316
- });
317
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
318
- className: ManagedDataOpsSection_module_css_default.modelPanel,
423
+ const disabled = busy || !writable;
424
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
425
+ className: ManagedDataOpsSection_module_css_default.card,
319
426
  children: [
320
427
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
321
- className: ManagedDataOpsSection_module_css_default.modelTitle,
322
- children: t("defaultsTitle")
428
+ className: ManagedDataOpsSection_module_css_default.heading,
429
+ children: t("limitsTitle")
323
430
  }),
324
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
325
- className: ManagedDataOpsSection_module_css_default.modelDescription,
326
- children: t("defaultsDescription")
431
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
432
+ className: ManagedDataOpsSection_module_css_default.fields,
433
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
434
+ id: fileReadId,
435
+ label: t("limitsFileReadLabel"),
436
+ text: fileReadMib,
437
+ numeric: true,
438
+ invalid: fileReadBytes === null,
439
+ overridden: false,
440
+ overriddenLabel: "",
441
+ resetLabel: "",
442
+ invalidLabel: t("limitsInvalid"),
443
+ disabled,
444
+ onEdit: edit(setFileReadMib),
445
+ onReset: () => void 0
446
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
447
+ id: uploadId,
448
+ label: t("limitsUploadLabel"),
449
+ text: uploadMib,
450
+ numeric: true,
451
+ invalid: uploadBytes === null,
452
+ overridden: false,
453
+ overriddenLabel: "",
454
+ resetLabel: "",
455
+ invalidLabel: t("limitsInvalid"),
456
+ disabled,
457
+ onEdit: edit(setUploadMib),
458
+ onReset: () => void 0
459
+ }) })]
327
460
  }),
328
461
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
329
- className: ManagedDataOpsSection_module_css_default.brandingRow,
330
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
331
- className: ManagedDataOpsSection_module_css_default.brandingCopy,
332
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("defaultsActionTitle") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: status.publishedAt === null ? t("defaultsNeverPublished") : t("defaultsPublishedAt") + " " + status.publishedAt })]
333
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
334
- type: "button",
335
- className: ManagedDataOpsSection_module_css_default.modelAction,
336
- disabled: busy,
462
+ className: ManagedDataOpsSection_module_css_default.actions,
463
+ children: [refusal === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
464
+ className: ManagedDataOpsSection_module_css_default.refusal,
465
+ role: "alert",
466
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: refusal })]
467
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
468
+ variant: "primary",
469
+ size: "sm",
470
+ disabled: disabled || !ready,
337
471
  onClick: () => {
338
- publish();
472
+ submit();
339
473
  },
340
- children: busy ? t("defaultsPublishing") : t("defaultsPublish")
474
+ children: busy ? t("limitsSaving") : t("limitsSave")
341
475
  })]
342
476
  })
343
477
  ]
344
478
  });
345
479
  }
346
- /** The panel's unit, so a stored byte count survives a round trip through the input. */
347
- const BYTES_PER_MIB = 1048576;
348
- /** Render a byte ceiling as the whole MiB the input shows. */
349
- function toMib(bytes) {
350
- return String(Math.round(bytes / BYTES_PER_MIB * 100) / 100);
351
- }
352
480
  /**
353
- * Read and change the file-size ceilings DataOps enforces on this workspace.
481
+ * How long one tool call may run before it is abandoned.
354
482
  *
355
- * The values live in DataOps and are read through the plugin, which holds the JWT; the panel only
356
- * ever holds what the administrator is allowed to see.
483
+ * The value lives in this plugin's own configuration, so it is per workspace and survives a
484
+ * restart. It is edited in seconds because that is the unit an operator reasons in; the plugin
485
+ * stores milliseconds and converts on the way through.
357
486
  * @param props - Translate function from the section.
358
- * @returns The limits panel.
487
+ * @returns The tool-call timeout card.
359
488
  */
360
- function WorkspaceLimitsPanel({ t }) {
489
+ function TimeoutCard({ t }) {
361
490
  const [state, setState] = (0, react.useState)({ kind: "loading" });
362
- const [fileReadMib, setFileReadMib] = (0, react.useState)("");
363
- const [uploadMib, setUploadMib] = (0, react.useState)("");
491
+ const [seconds, setSeconds] = (0, react.useState)("");
492
+ /** The value the draft started from, so Save stays off until it changes. */
493
+ const [saved, setSaved] = (0, react.useState)("");
494
+ const [refusal, setRefusal] = (0, react.useState)(null);
364
495
  const [busy, setBusy] = (0, react.useState)(false);
365
- const apply = (0, react.useCallback)((status) => {
496
+ const id = (0, react.useId)();
497
+ const apply = (0, react.useCallback)((milliseconds) => {
366
498
  setState({
367
499
  kind: "ready",
368
- status
500
+ status: milliseconds
369
501
  });
370
- setFileReadMib(toMib(status.limits.fileReadMaxBytes));
371
- setUploadMib(toMib(status.limits.uploadMaxBytes));
502
+ const text = String(Math.round(milliseconds / 1e3));
503
+ setSeconds(text);
504
+ setSaved(text);
505
+ setRefusal(null);
372
506
  }, []);
373
507
  const refresh = (0, react.useCallback)(async () => {
374
508
  try {
375
- const status = await fetchWorkspaceLimits();
509
+ const status = await fetchToolTimeout();
376
510
  if (status === null) setState({ kind: "unavailable" });
377
- else apply(status);
511
+ else apply(status.toolCallTimeoutMs);
378
512
  } catch {
379
513
  setState({ kind: "failed" });
380
514
  }
@@ -382,93 +516,72 @@ window.__ModuleLoader__.load({
382
516
  (0, react.useEffect)(() => {
383
517
  refresh();
384
518
  }, [refresh]);
519
+ const parsed = Number(seconds);
520
+ const valid = seconds.trim() !== "" && Number.isFinite(parsed) && parsed >= 1 && parsed <= 3600;
521
+ const dirty = seconds !== saved;
522
+ const disabled = busy;
385
523
  const submit = (0, react.useCallback)(async () => {
386
- const fileReadMaxBytes = Math.round(Number(fileReadMib) * BYTES_PER_MIB);
387
- const uploadMaxBytes = Math.round(Number(uploadMib) * BYTES_PER_MIB);
388
- if (!Number.isSafeInteger(fileReadMaxBytes) || fileReadMaxBytes <= 0) return;
389
- if (!Number.isSafeInteger(uploadMaxBytes) || uploadMaxBytes <= 0) return;
524
+ if (!valid) return;
390
525
  setBusy(true);
526
+ setRefusal(null);
391
527
  try {
392
- const status = await saveWorkspaceLimits({
393
- fileReadMaxBytes,
394
- uploadMaxBytes
395
- });
528
+ const status = await saveToolTimeout(Math.round(parsed * 1e3));
396
529
  if (status === null) setState({ kind: "unavailable" });
397
- else apply(status);
398
- } catch {
399
- setState({ kind: "failed" });
530
+ else apply(status.toolCallTimeoutMs);
531
+ } catch (error) {
532
+ if (error instanceof Error) setRefusal(error.message);
533
+ else setState({ kind: "failed" });
400
534
  } finally {
401
535
  setBusy(false);
402
536
  }
403
537
  }, [
404
- fileReadMib,
405
- uploadMib,
538
+ valid,
539
+ parsed,
406
540
  apply
407
541
  ]);
408
542
  if (state.kind === "loading") return null;
409
- if (state.kind !== "ready") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
410
- className: ManagedDataOpsSection_module_css_default.modelPanel,
411
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
412
- className: ManagedDataOpsSection_module_css_default.modelTitle,
413
- children: t("limitsTitle")
414
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
415
- className: ManagedDataOpsSection_module_css_default.modelDescription,
416
- role: state.kind === "failed" ? "alert" : void 0,
417
- children: state.kind === "failed" ? t("loadFailed") : t("limitsUnavailable")
418
- })]
543
+ if (state.kind !== "ready") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnavailableCard, {
544
+ title: t("timeoutTitle"),
545
+ t,
546
+ state: state.kind
419
547
  });
420
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
421
- className: ManagedDataOpsSection_module_css_default.modelPanel,
548
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
549
+ className: ManagedDataOpsSection_module_css_default.card,
422
550
  children: [
423
551
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
424
- className: ManagedDataOpsSection_module_css_default.modelTitle,
425
- children: t("limitsTitle")
552
+ className: ManagedDataOpsSection_module_css_default.heading,
553
+ children: t("timeoutTitle")
426
554
  }),
427
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
428
- className: ManagedDataOpsSection_module_css_default.modelDescription,
429
- children: t("limitsDescription")
430
- }),
431
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
432
- className: ManagedDataOpsSection_module_css_default.details,
433
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
434
- className: ManagedDataOpsSection_module_css_default.detailRow,
435
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("limitsFileReadLabel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
436
- className: ManagedDataOpsSection_module_css_default.limitsInput,
437
- type: "number",
438
- min: "1",
439
- step: "1",
440
- "aria-label": t("limitsFileReadLabel"),
441
- value: fileReadMib,
442
- disabled: busy || !state.status.canWrite,
443
- onChange: (event) => {
444
- setFileReadMib(event.target.value);
445
- }
446
- })]
447
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
448
- className: ManagedDataOpsSection_module_css_default.detailRow,
449
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("limitsUploadLabel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
450
- className: ManagedDataOpsSection_module_css_default.limitsInput,
451
- type: "number",
452
- min: "1",
453
- step: "1",
454
- "aria-label": t("limitsUploadLabel"),
455
- value: uploadMib,
456
- disabled: busy || !state.status.canWrite,
457
- onChange: (event) => {
458
- setUploadMib(event.target.value);
459
- }
460
- })]
461
- })]
555
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
556
+ className: ManagedDataOpsSection_module_css_default.fields,
557
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
558
+ id,
559
+ label: t("timeoutLabel"),
560
+ text: seconds,
561
+ numeric: true,
562
+ invalid: !valid,
563
+ overridden: false,
564
+ overriddenLabel: "",
565
+ resetLabel: "",
566
+ invalidLabel: t("timeoutInvalid"),
567
+ disabled,
568
+ onEdit: (text) => {
569
+ setSeconds(text);
570
+ setRefusal(null);
571
+ },
572
+ onReset: () => void 0
573
+ }) })
462
574
  }),
463
575
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
464
- className: ManagedDataOpsSection_module_css_default.brandingRow,
465
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
466
- className: ManagedDataOpsSection_module_css_default.modelDescription,
467
- children: t("limitsUnit")
468
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
469
- type: "button",
470
- className: ManagedDataOpsSection_module_css_default.modelAction,
471
- disabled: busy || !state.status.canWrite,
576
+ className: ManagedDataOpsSection_module_css_default.actions,
577
+ children: [refusal === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
578
+ className: ManagedDataOpsSection_module_css_default.refusal,
579
+ role: "alert",
580
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: refusal })]
581
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
582
+ variant: "primary",
583
+ size: "sm",
584
+ disabled: disabled || !valid || !dirty,
472
585
  onClick: () => {
473
586
  submit();
474
587
  },
@@ -478,6 +591,81 @@ window.__ModuleLoader__.load({
478
591
  ]
479
592
  });
480
593
  }
594
+ /**
595
+ * Publish this workspace's configuration as the default other users start from.
596
+
597
+ * One action rather than a set of controls: the configuration is whatever this workspace already
598
+ * holds, and the button copies it to DataOps.
599
+ * @param props - Translate function from the section.
600
+ * @returns The default-configuration card.
601
+ */
602
+ function DefaultsCard({ t }) {
603
+ const [state, setState] = (0, react.useState)({ kind: "loading" });
604
+ const [busy, setBusy] = (0, react.useState)(false);
605
+ const refresh = (0, react.useCallback)(async () => {
606
+ try {
607
+ const status = await fetchModelSyncStatus();
608
+ setState(status === null ? { kind: "unavailable" } : {
609
+ kind: "ready",
610
+ status
611
+ });
612
+ } catch {
613
+ setState({ kind: "failed" });
614
+ }
615
+ }, []);
616
+ (0, react.useEffect)(() => {
617
+ refresh();
618
+ }, [refresh]);
619
+ const publish = (0, react.useCallback)(async () => {
620
+ setBusy(true);
621
+ try {
622
+ const status = await postModelSyncAction({ action: "publish-defaults" });
623
+ if (status === null) setState({ kind: "unavailable" });
624
+ else setState({
625
+ kind: "ready",
626
+ status
627
+ });
628
+ } catch {
629
+ setState({ kind: "failed" });
630
+ } finally {
631
+ setBusy(false);
632
+ }
633
+ }, []);
634
+ if (state.kind === "loading") return null;
635
+ if (state.kind !== "ready") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnavailableCard, {
636
+ title: t("defaultsTitle"),
637
+ t,
638
+ state: state.kind
639
+ });
640
+ const published = state.status.publishedAt === null ? null : publishedText(state.status.publishedAt);
641
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
642
+ className: ManagedDataOpsSection_module_css_default.card,
643
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
644
+ className: ManagedDataOpsSection_module_css_default.row,
645
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
646
+ className: ManagedDataOpsSection_module_css_default.copy,
647
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
648
+ className: ManagedDataOpsSection_module_css_default.label,
649
+ children: t("defaultsTitle")
650
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
651
+ className: ManagedDataOpsSection_module_css_default.meta,
652
+ children: published === null ? t("defaultsNeverPublished") : t("defaultsPublishedAt") + " · " + published
653
+ })]
654
+ }), state.status.canPublish ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
655
+ variant: "outline",
656
+ size: "sm",
657
+ disabled: busy,
658
+ onClick: () => {
659
+ publish();
660
+ },
661
+ children: busy ? t("defaultsPublishing") : t("defaultsPublish")
662
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
663
+ className: ManagedDataOpsSection_module_css_default.meta,
664
+ children: t("defaultsNotAdmin")
665
+ })]
666
+ })
667
+ });
668
+ }
481
669
  //#endregion
482
670
  //#region src/client/skill-plaza-client.ts
483
671
  /** Same-origin skill plaza calls from the DataOps skill center section. */
@@ -552,28 +740,28 @@ window.__ModuleLoader__.load({
552
740
  document.head.appendChild(tag);
553
741
  }
554
742
  var SkillPlazaSection_module_css_default = {
743
+ "empty": "_9FdZvq_empty",
744
+ "notice": "_9FdZvq_notice",
745
+ "head": "_9FdZvq_head",
555
746
  "search": "_9FdZvq_search",
556
- "titleIcon": "_9FdZvq_titleIcon",
557
- "cardMarks": "_9FdZvq_cardMarks",
558
- "emptyText": "_9FdZvq_emptyText",
747
+ "cardEnd": "_9FdZvq_cardEnd",
559
748
  "cardHead": "_9FdZvq_cardHead",
749
+ "card": "_9FdZvq_card",
560
750
  "emptyIcon": "_9FdZvq_emptyIcon",
561
- "toolbar": "_9FdZvq_toolbar",
562
- "head": "_9FdZvq_head",
563
751
  "intro": "_9FdZvq_intro",
564
- "section": "_9FdZvq_section",
565
- "title": "_9FdZvq_title",
566
- "card": "_9FdZvq_card",
752
+ "toolbar": "_9FdZvq_toolbar",
753
+ "cardIcon": "_9FdZvq_cardIcon",
754
+ "cardMain": "_9FdZvq_cardMain",
755
+ "titleIcon": "_9FdZvq_titleIcon",
756
+ "emptyText": "_9FdZvq_emptyText",
757
+ "mine": "_9FdZvq_mine",
567
758
  "tagBar": "_9FdZvq_tagBar",
759
+ "cardDesc": "_9FdZvq_cardDesc",
760
+ "cardMarks": "_9FdZvq_cardMarks",
568
761
  "cards": "_9FdZvq_cards",
569
- "cardMain": "_9FdZvq_cardMain",
570
762
  "cardTitle": "_9FdZvq_cardTitle",
571
- "mine": "_9FdZvq_mine",
572
- "notice": "_9FdZvq_notice",
573
- "empty": "_9FdZvq_empty",
574
- "cardEnd": "_9FdZvq_cardEnd",
575
- "cardIcon": "_9FdZvq_cardIcon",
576
- "cardDesc": "_9FdZvq_cardDesc"
763
+ "title": "_9FdZvq_title",
764
+ "section": "_9FdZvq_section"
577
765
  };
578
766
  //#endregion
579
767
  //#region src/client/SkillPlazaSection.tsx
@@ -825,18 +1013,18 @@ window.__ModuleLoader__.load({
825
1013
  document.head.appendChild(tag);
826
1014
  }
827
1015
  var WanxiangBrand_module_css_default = {
1016
+ "unitLeft": "s0HPxG_unitLeft",
828
1017
  "animatedMark": "s0HPxG_animatedMark",
1018
+ "unitCore": "s0HPxG_unitCore",
1019
+ "unitTop": "s0HPxG_unitTop",
1020
+ "unit-right": "s0HPxG_unit-right",
829
1021
  "unitRight": "s0HPxG_unitRight",
1022
+ "unit-top": "s0HPxG_unit-top",
830
1023
  "sidebarName": "s0HPxG_sidebarName",
831
- "unit-core": "s0HPxG_unit-core",
832
- "unitCore": "s0HPxG_unitCore",
833
1024
  "mark": "s0HPxG_mark",
1025
+ "unit-left": "s0HPxG_unit-left",
834
1026
  "harness": "s0HPxG_harness",
835
- "unit-top": "s0HPxG_unit-top",
836
- "unit-right": "s0HPxG_unit-right",
837
- "unitLeft": "s0HPxG_unitLeft",
838
- "unitTop": "s0HPxG_unitTop",
839
- "unit-left": "s0HPxG_unit-left"
1027
+ "unit-core": "s0HPxG_unit-core"
840
1028
  };
841
1029
  //#endregion
842
1030
  //#region src/client/WanxiangBrand.tsx
@@ -1112,27 +1300,26 @@ window.__ModuleLoader__.load({
1112
1300
  const en = {
1113
1301
  nav: "DataOps",
1114
1302
  title: "DataOps",
1115
- managed: "Managed by this DataOps workspace",
1116
- description: "DSH uses your current DataOps session JWT. DataOps applies its role and resource permissions to every tool request.",
1117
- identityLabel: "Identity and permissions",
1118
- identityValue: "Current DataOps JWT",
1119
- toolsLabel: "DataOps tools",
1120
- toolsValue: "Authorized by DataOps on every request",
1121
- brandingTitle: "Apply Wanxiang branding",
1122
- brandingDescription: "Use the Wanxiang Data Platform identity in navigation, the New Session welcome view, browser title, and favicon.",
1123
- brandingToggle: "Apply Wanxiang branding",
1124
- modelsTitle: "Model configuration",
1125
- modelsDescription: "Share the models configured here with other users, and choose which of them they may use.",
1126
- modelsUnavailable: "Model configuration is unavailable until this workspace is connected to DataOps.",
1303
+ managed: "Connected to DataOps",
1304
+ unavailable: "DataOps is not connected.",
1305
+ loadFailed: "Loading failed. Try again.",
1306
+ brandingTitle: "Wanxiang branding",
1307
+ brandingToggle: "Wanxiang branding",
1308
+ limitsTitle: "File size limits",
1309
+ limitsFileReadLabel: "Largest file to read (MiB)",
1310
+ limitsUploadLabel: "Largest file to upload (MiB)",
1311
+ limitsInvalid: "Enter a size in MiB.",
1312
+ limitsSave: "Save",
1313
+ limitsSaving: "Saving…",
1314
+ timeoutTitle: "Tool call timeout",
1315
+ timeoutLabel: "Longest single call (seconds)",
1316
+ timeoutInvalid: "Enter 1 to 3600 seconds.",
1127
1317
  defaultsTitle: "Default configuration",
1128
- defaultsDescription: "Publish the configuration this workspace holds — models, permissions, and general settings — as the values other users start from. Their workspace takes that copy once and may then change anything, and a change they make is never overwritten.",
1129
- defaultsActionTitle: "Publish as the default",
1130
- defaultsNotAdmin: "Only an administrator may publish the default configuration.",
1131
- defaultsNeverPublished: "Not published yet.",
1132
- defaultsPublishedAt: "Last published:",
1133
- defaultsPublish: "Publish default configuration",
1318
+ defaultsPublish: "Publish",
1134
1319
  defaultsPublishing: "Publishing…",
1135
- loadFailed: "The model configuration could not be loaded. Try again.",
1320
+ defaultsPublishedAt: "Last published",
1321
+ defaultsNeverPublished: "Not published yet",
1322
+ defaultsNotAdmin: "Administrators only",
1136
1323
  plazaTitle: "Skill plaza",
1137
1324
  plazaIntro: "Skills other users shared. Install one to use it in this workspace, or share a skill of your own.",
1138
1325
  plazaSearch: "Search skills",
@@ -1148,41 +1335,32 @@ window.__ModuleLoader__.load({
1148
1335
  plazaLoadFailed: "The skill plaza could not be loaded. Try again.",
1149
1336
  plazaActionFailed: "The action could not be completed. Try again.",
1150
1337
  plazaRetry: "Try again",
1151
- plazaRefresh: "Refresh",
1152
- limitsTitle: "Workspace limits",
1153
- limitsDescription: "The largest files this workspace may read and upload. Set by an administrator in DataOps.",
1154
- limitsUnavailable: "Workspace limits are available once this workspace is connected to DataOps.",
1155
- limitsFileReadLabel: "Largest file to read",
1156
- limitsUploadLabel: "Largest file to upload",
1157
- limitsUnit: "Units are MiB.",
1158
- limitsSave: "Save limits",
1159
- limitsSaving: "Saving…"
1338
+ plazaRefresh: "Refresh"
1160
1339
  };
1161
1340
  /** Chinese managed DataOps Settings copy. */
1162
1341
  const zh = {
1163
1342
  nav: "DataOps",
1164
1343
  title: "DataOps",
1165
- managed: "由当前 DataOps 工作区托管",
1166
- description: "DSH 使用当前 DataOps 会话 JWT;DataOps 对每次工具请求应用角色与资源权限。",
1167
- identityLabel: "身份与权限",
1168
- identityValue: "当前 DataOps JWT",
1169
- toolsLabel: "DataOps 工具",
1170
- toolsValue: "每次请求均由 DataOps 授权",
1344
+ managed: "已连接 DataOps",
1345
+ unavailable: "未连接 DataOps。",
1346
+ loadFailed: "加载失败,请重试。",
1171
1347
  brandingTitle: "应用万相品牌",
1172
- brandingDescription: "在导航、新会话欢迎页、浏览器标题和图标中使用万相数据平台品牌。",
1173
1348
  brandingToggle: "应用万相品牌",
1174
- modelsTitle: "模型配置共享",
1175
- modelsDescription: "把这里配置的模型共享给其他用户,并决定他们可以使用其中哪些。",
1176
- modelsUnavailable: "工作区接入 DataOps 后即可使用模型配置共享。",
1349
+ limitsTitle: "文件大小限制",
1350
+ limitsFileReadLabel: "最大读取文件(MiB)",
1351
+ limitsUploadLabel: "最大上传文件(MiB)",
1352
+ limitsInvalid: "请输入以 MiB 为单位的大小。",
1353
+ limitsSave: "保存",
1354
+ timeoutTitle: "工具调用超时",
1355
+ timeoutLabel: "单次调用上限(秒)",
1356
+ timeoutInvalid: "请输入 1 到 3600 秒。",
1357
+ limitsSaving: "保存中…",
1177
1358
  defaultsTitle: "默认配置",
1178
- defaultsDescription: "把本工作区当前的配置(模型、权限、通用设置)发布为其他用户的初始值。对方工作区只取用一次,之后可以随意修改,改过的内容不会被覆盖。",
1179
- defaultsActionTitle: "发布为默认值",
1180
- defaultsNotAdmin: "只有管理员可以发布默认配置。",
1181
- defaultsNeverPublished: "尚未发布。",
1182
- defaultsPublishedAt: "上次发布:",
1183
- defaultsPublish: "发布默认配置",
1359
+ defaultsPublish: "发布",
1184
1360
  defaultsPublishing: "发布中…",
1185
- loadFailed: "模型配置加载失败,请重试。",
1361
+ defaultsPublishedAt: "上次发布",
1362
+ defaultsNeverPublished: "尚未发布",
1363
+ defaultsNotAdmin: "仅管理员可发布",
1186
1364
  plazaTitle: "技能广场",
1187
1365
  plazaIntro: "其他用户共享的技能。装载后即可在本工作区使用,也可以把自己的技能共享出去。",
1188
1366
  plazaSearch: "搜索技能",
@@ -1198,15 +1376,7 @@ window.__ModuleLoader__.load({
1198
1376
  plazaLoadFailed: "技能广场加载失败,请重试。",
1199
1377
  plazaActionFailed: "操作未完成,请重试。",
1200
1378
  plazaRetry: "重试",
1201
- plazaRefresh: "刷新",
1202
- limitsTitle: "工作区限制",
1203
- limitsDescription: "本工作区可读取与上传的最大文件。由 DataOps 管理员设置。",
1204
- limitsUnavailable: "工作区连接到 DataOps 后可用。",
1205
- limitsFileReadLabel: "最大读取文件",
1206
- limitsUploadLabel: "最大上传文件",
1207
- limitsUnit: "单位:MiB。",
1208
- limitsSave: "保存限制",
1209
- limitsSaving: "保存中…"
1379
+ plazaRefresh: "刷新"
1210
1380
  };
1211
1381
  //#endregion
1212
1382
  //#region src/client/index.ts