@sema-agent/client-core 0.111.0 → 0.112.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/README.md +16 -7
  3. package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
  4. package/dist/checkpointRowVerdict.d.ts +3 -0
  5. package/dist/checkpointRowVerdict.js +14 -1
  6. package/dist/consoleCaPin.d.ts +136 -0
  7. package/dist/consoleCaPin.js +827 -0
  8. package/dist/decideReceipt.d.ts +2 -1
  9. package/dist/deviceRebind.js +3 -3
  10. package/dist/effectiveFacts.d.ts +9 -0
  11. package/dist/effectiveFacts.js +33 -0
  12. package/dist/engineAddress.d.ts +1 -0
  13. package/dist/engineAddress.js +4 -1
  14. package/dist/engineCredentialRelease.d.ts +54 -0
  15. package/dist/engineCredentialRelease.js +146 -0
  16. package/dist/engineErrorCodes.d.ts +1 -0
  17. package/dist/engineErrorCodes.js +1 -0
  18. package/dist/engineHealthFacts.d.ts +0 -11
  19. package/dist/engineHealthFacts.js +0 -21
  20. package/dist/engineHealthProbeVerdict.d.ts +1 -0
  21. package/dist/engineHealthProbeVerdict.js +21 -13
  22. package/dist/engineUnavailable.d.ts +3 -2
  23. package/dist/engineUnavailable.js +16 -12
  24. package/dist/engineUrl.js +4 -2
  25. package/dist/gateFailureCodes.js +2 -2
  26. package/dist/generated/sdkFactTables.d.ts +1 -0
  27. package/dist/generated/sdkFactTables.js +13 -0
  28. package/dist/generated/settingsSchemaFns.d.ts +1 -0
  29. package/dist/generated/settingsSchemaFns.js +3 -0
  30. package/dist/generated/settingsSchemaHooksClassifier.js +38 -9
  31. package/dist/generated/settingsSchemaTables.d.ts +52 -0
  32. package/dist/generated/settingsSchemaTables.js +18 -0
  33. package/dist/generated/settingsSchemaTypes.d.ts +23 -13
  34. package/dist/generated/settingsSchemaUrlShape.d.ts +1 -0
  35. package/dist/generated/settingsSchemaUrlShape.js +17 -0
  36. package/dist/hitl/decisionRefusal.d.ts +4 -0
  37. package/dist/hitl/decisionRefusal.js +12 -2
  38. package/dist/hitl/hitlBridge.d.ts +1 -0
  39. package/dist/hitl/hitlBridge.js +17 -4
  40. package/dist/hitl/localAllowRedemption.d.ts +9 -6
  41. package/dist/hitl/localAllowRedemption.js +20 -0
  42. package/dist/hitl/parkOwnership.js +2 -1
  43. package/dist/hitl/parkResolver.js +7 -0
  44. package/dist/hitl/planReviewCard.d.ts +3 -2
  45. package/dist/hitl/planReviewCard.js +2 -0
  46. package/dist/hitl/planReviewWire.d.ts +4 -2
  47. package/dist/hitl/planReviewWire.js +134 -97
  48. package/dist/hitl/screenDecisionCards.js +3 -2
  49. package/dist/hitl/sessionPolicyWire.js +2 -2
  50. package/dist/hitl/standingRows.d.ts +4 -2
  51. package/dist/hitl/standingRows.js +10 -3
  52. package/dist/hooksReaderGenerations.js +1 -1
  53. package/dist/i18n/messages.en.d.ts +165 -0
  54. package/dist/i18n/messages.en.js +166 -1
  55. package/dist/i18n/messages.zh.js +177 -1
  56. package/dist/index.d.ts +30 -5
  57. package/dist/index.js +15 -2
  58. package/dist/liveModelCatalog.d.ts +4 -0
  59. package/dist/liveModelCatalog.js +10 -1
  60. package/dist/localConfig/documents.d.ts +61 -0
  61. package/dist/localConfig/documents.js +51 -0
  62. package/dist/localConfig/kernel.d.ts +149 -0
  63. package/dist/localConfig/kernel.js +597 -0
  64. package/dist/localConfig/mcp/edit.d.ts +161 -0
  65. package/dist/localConfig/mcp/edit.js +846 -0
  66. package/dist/localConfig/mcp/servers.d.ts +165 -0
  67. package/dist/localConfig/mcp/servers.js +776 -0
  68. package/dist/localConfig/mcp/views.d.ts +170 -0
  69. package/dist/localConfig/mcp/views.js +429 -0
  70. package/dist/localConfig/modelPool.d.ts +262 -0
  71. package/dist/localConfig/modelPool.js +1489 -0
  72. package/dist/localConfig/modelPoolWords.d.ts +13 -0
  73. package/dist/localConfig/modelPoolWords.js +20 -0
  74. package/dist/localConfig/receiptShape.d.ts +7 -0
  75. package/dist/localConfig/receiptShape.js +135 -0
  76. package/dist/localConfig/settingsWrite.d.ts +127 -0
  77. package/dist/localConfig/settingsWrite.js +237 -0
  78. package/dist/localConfig/skills.d.ts +124 -0
  79. package/dist/localConfig/skills.js +397 -0
  80. package/dist/localConfig/skillsWords.d.ts +10 -0
  81. package/dist/localConfig/skillsWords.js +5 -0
  82. package/dist/mcpProbeWire.js +2 -1
  83. package/dist/mcpWireCaps.js +1 -1
  84. package/dist/memoryVerbsWire.js +3 -2
  85. package/dist/model/onboardJudgement.d.ts +14 -4
  86. package/dist/model/onboardJudgement.js +91 -139
  87. package/dist/modelConfigGapNotice.d.ts +20 -0
  88. package/dist/modelConfigGapNotice.js +102 -0
  89. package/dist/modsKernelIdentity.js +2 -47
  90. package/dist/notifications.js +14 -12
  91. package/dist/ownKey.d.ts +1 -0
  92. package/dist/ownKey.js +40 -8
  93. package/dist/permissionsDeclaration.d.ts +2 -1
  94. package/dist/permissionsDeclaration.js +31 -17
  95. package/dist/planReviewOutcomeCause.d.ts +2 -0
  96. package/dist/planReviewOutcomeCause.js +12 -0
  97. package/dist/promptBlockedCopy.js +2 -2
  98. package/dist/resumeRefusalCopy.d.ts +3 -1
  99. package/dist/resumeRefusalCopy.js +12 -4
  100. package/dist/runLedgerSnapshot.js +3 -3
  101. package/dist/runPermissionModeSwitch.js +2 -3
  102. package/dist/seatContract.d.ts +154 -4
  103. package/dist/seatContract.js +228 -2
  104. package/dist/sessionIdSegment.d.ts +1 -0
  105. package/dist/sessionIdSegment.js +4 -1
  106. package/dist/sessionMemoryErase.js +2 -1
  107. package/dist/sha256Bytes.d.ts +1 -0
  108. package/dist/sha256Bytes.js +46 -0
  109. package/dist/skillOverrideChain.d.ts +83 -0
  110. package/dist/skillOverrideChain.js +378 -0
  111. package/dist/skillsWireCaps.d.ts +3 -0
  112. package/dist/skillsWireCaps.js +16 -1
  113. package/dist/turnFailurePresentation.js +4 -10
  114. package/docs/INTEGRATION-CLIENTS.md +680 -14
  115. package/package.json +3 -3
@@ -1,6 +1,8 @@
1
+ import { inferFamily } from './providerPresets.js';
1
2
  import { ONBOARD_REFUSALS } from '../seatContract.js';
2
- import { joinRequestUrl, routeKeyOf } from '../coreValuePorts.js';
3
- import { applyProbeToEntry, probeModelLiveness, probeVerdictNotice } from '../modelCapabilityProbe.js';
3
+ import { adjudicateModelRoute, joinRequestUrl, routeKeyOf } from '../coreValuePorts.js';
4
+ import { settleWithinDeadline } from '../abortableSleep.js';
5
+ import { probeModelLiveness, probeVerdictNotice } from '../modelCapabilityProbe.js';
4
6
  import { ownDataField } from '../ownKey.js';
5
7
  import { msg, renderMessage } from '../i18n/translate.js';
6
8
  const field = (v, key) => {
@@ -57,6 +59,9 @@ function safeDecode(t) {
57
59
  return t;
58
60
  }
59
61
  }
62
+ export function onboardKeyCarriedBy(text, key) {
63
+ return carriesKey(text, key);
64
+ }
60
65
  function carriesKey(text, key) {
61
66
  if (key === undefined || key === '')
62
67
  return false;
@@ -69,6 +74,9 @@ function carriesKey(text, key) {
69
74
  function looksLikeSecret(val) {
70
75
  return /^(sk|ak|pk|rk)[-_]/i.test(val) || (val.length >= 20 && /[A-Za-z]/.test(val) && /[0-9]/.test(val) && /^[A-Za-z0-9._~+/=-]+$/.test(val));
71
76
  }
77
+ export function onboardRedactKey(text, key) {
78
+ return redact(text, key);
79
+ }
72
80
  function redact(text, key) {
73
81
  if (key === undefined || key === '')
74
82
  return text;
@@ -197,7 +205,71 @@ export async function probeModelEndpoint(target, deps) {
197
205
  });
198
206
  if (v.verdict === 'unreachable' && seen.redirected !== undefined)
199
207
  return out('unreachable', seen.redirected);
200
- return out(v.verdict, probeDetailOf(v));
208
+ const firstOutputMs = v.verdict === 'ok' && typeof v.waitedMs === 'number' && Number.isFinite(v.waitedMs) && v.waitedMs >= 0 ? Math.round(v.waitedMs) : undefined;
209
+ const r = out(v.verdict, probeDetailOf(v));
210
+ return firstOutputMs === undefined ? r : Object.freeze({ ...r, firstOutputMs });
211
+ }
212
+ const DISCOVERY_MAX = 512;
213
+ export async function discoverEndpointModels(target, deps) {
214
+ const apiKey = field(target, 'apiKey');
215
+ const key = typeof apiKey === 'string' && apiKey !== '' ? apiKey : undefined;
216
+ const fail = (verdict, detail) => Object.freeze({ ok: false, verdict, detail: capText(redact(detail, key?.trim() || undefined)) });
217
+ const baseUrl = field(target, 'baseUrl');
218
+ const api = field(target, 'api');
219
+ const auth = field(target, 'auth');
220
+ if (typeof baseUrl !== 'string' || (api !== 'anthropic-messages' && api !== 'openai-completions'))
221
+ return fail('other', en('onboard.probe.incomplete'));
222
+ const f = (field(deps, 'fetchImpl') ?? globalThis.fetch);
223
+ if (typeof f !== 'function')
224
+ return fail('unreachable', en('onboard.probe.noFetch'));
225
+ const root = baseUrl.trim();
226
+ let url;
227
+ try {
228
+ url = joinRequestUrl(root, 'models');
229
+ }
230
+ catch {
231
+ return fail('other', en('onboard.baseUrl.invalid'));
232
+ }
233
+ if (url === undefined)
234
+ return fail('other', en('onboard.probe.judgeAbsent'));
235
+ const t = field(deps, 'timeoutMs');
236
+ const budget = typeof t === 'number' && Number.isFinite(t) && t > 0 ? t : 10_000;
237
+ const headers = { ...(api === 'anthropic-messages' ? { 'anthropic-version': '2023-06-01' } : {}), ...keyHeaders(api, key, auth === 'bearer' || auth === 'x-api-key' ? auth : undefined) };
238
+ const settled = await settleWithinDeadline(budget, async (signal) => {
239
+ const res = await f(url, { method: 'GET', headers, redirect: 'manual', signal });
240
+ const redirected = redirectRefusal(res, url, key);
241
+ if (redirected !== undefined)
242
+ return fail('unreachable', redirected);
243
+ if (res.status === 401 || res.status === 403)
244
+ return fail('auth', en('model.pool.discover.status', { status: res.status }));
245
+ if (res.status < 200 || res.status >= 300)
246
+ return fail('other', en('model.pool.discover.status', { status: res.status }));
247
+ let body;
248
+ try {
249
+ body = JSON.parse(await res.text());
250
+ }
251
+ catch {
252
+ return fail('shape', en('model.pool.discover.notList'));
253
+ }
254
+ const data = field(body, 'data');
255
+ if (!Array.isArray(data))
256
+ return fail('shape', en('model.pool.discover.notList'));
257
+ const out = [];
258
+ for (let i = 0; i < data.length && out.length < DISCOVERY_MAX; i++) {
259
+ const id = field(field(data, String(i)), 'id');
260
+ if (typeof id !== 'string' || id.trim() === '' || id.length > 512 || carriesKey(id, key) || out.some((c) => c.id === id))
261
+ continue;
262
+ const fam = inferFamily(id);
263
+ const exact = fam !== undefined && fam.perModelCap !== undefined;
264
+ out.push(Object.freeze({ id, ...(exact ? { contextWindow: fam.contextWindow, maxTokens: fam.maxTokens } : {}) }));
265
+ }
266
+ return Object.freeze({ ok: true, candidates: Object.freeze(out) });
267
+ });
268
+ if (settled.kind === 'deadline')
269
+ return fail('unreachable', en('model.pool.discover.timeout'));
270
+ if (settled.kind === 'error')
271
+ return fail('unreachable', en('model.pool.discover.unreachable', { cause: settled.detail }));
272
+ return settled.value;
201
273
  }
202
274
  export function onboardWriteVerdict(verdict, acceptUnverified) {
203
275
  if (verdict === 'ok')
@@ -224,6 +296,9 @@ export function poolEntryNameOf(modelId, channel, taken) {
224
296
  candidate = `${name}-${channel}-${i}`;
225
297
  return candidate;
226
298
  }
299
+ export function onboardEntryCredentialIssue(m, env) {
300
+ return entryCredentialIssue(m, env);
301
+ }
227
302
  function entryCredentialIssue(m, env) {
228
303
  const name = typeof m['name'] === 'string' ? m['name'] : '?';
229
304
  if (m['sealedApiKey'] !== undefined && m['sealedApiKey'] !== null)
@@ -239,6 +314,19 @@ function entryCredentialIssue(m, env) {
239
314
  const api = typeof m['api'] === 'string' ? m['api'] : 'openai-completions';
240
315
  const rootKey = api === 'anthropic-messages' ? 'ANTHROPIC_BASE_URL' : 'MODEL_GATEWAY_BASEURL';
241
316
  const root = env[rootKey];
317
+ if (api !== 'anthropic-messages' && (typeof root !== 'string' || root.trim() === '')) {
318
+ let keyless;
319
+ try {
320
+ keyless = adjudicateModelRoute({ id: typeof m['id'] === 'string' ? m['id'] : name, baseUrl: base }, { source: 'absent' }, {});
321
+ }
322
+ catch {
323
+ keyless = undefined;
324
+ }
325
+ if (keyless === undefined)
326
+ return en('onboard.catalog.judgeAbsent', { name });
327
+ if (keyless.ok)
328
+ return undefined;
329
+ }
242
330
  let paired;
243
331
  try {
244
332
  const a = routeKeyOf(base);
@@ -262,142 +350,6 @@ function entryCredentialIssue(m, env) {
262
350
  const rootText = typeof root === 'string' && root !== '' ? `${rootKey} (${hostOf(root)})` : en('onboard.catalog.noRoot', { rootKey });
263
351
  return en('onboard.catalog.unpaired', { name, host: hostOf(base), root: rootText });
264
352
  }
265
- function migrateLegacyDefaultKey(doc) {
266
- const legacy = doc['default'];
267
- if (typeof legacy !== 'string' || legacy.length === 0)
268
- return doc;
269
- const { default: _legacy, ...rest } = doc;
270
- void _legacy;
271
- const prevRoles = rest['roles'];
272
- const roles = prevRoles !== null && typeof prevRoles === 'object' && !Array.isArray(prevRoles) ? { ...prevRoles } : {};
273
- roles['default'] = { model: legacy };
274
- return { ...rest, roles };
275
- }
276
- export function onboardWritePlan(input) {
277
- const rawKey = field(field(input, 'entry'), 'apiKey');
278
- const planKey = typeof rawKey === 'string' && rawKey !== '' ? rawKey : undefined;
279
- const say = (text) => redact(text, planKey);
280
- const refuse = (refusal, detail) => Object.freeze({ ok: false, refusal, detail: say(detail) });
281
- try {
282
- if (input.engineMode === 'cloud')
283
- return refuse('engine_is_remote', en('onboard.refusal.engineIsRemote'));
284
- const rawDoc = input.modelsDoc;
285
- if (rawDoc !== undefined && (rawDoc === null || typeof rawDoc !== 'object' || Array.isArray(rawDoc)))
286
- return refuse('catalog_unreadable', en('onboard.plan.notObject'));
287
- const doc = migrateLegacyDefaultKey(rawDoc === undefined ? {} : { ...rawDoc });
288
- const rawModels = doc['models'];
289
- if (rawModels !== undefined && !Array.isArray(rawModels))
290
- return refuse('catalog_unreadable', en('onboard.plan.modelsNotList'));
291
- const list = Array.isArray(rawModels) ? rawModels : [];
292
- if (list.some((m) => m === null || typeof m !== 'object' || Array.isArray(m)))
293
- return refuse('catalog_unreadable', en('onboard.plan.modelsItemNotObject'));
294
- const models = list.map((m) => ({ ...m }));
295
- const envModel = [input.effectiveEnv?.['MODEL_ID'], input.effectiveEnv?.['MODEL_CHEAP_ID']].find((v) => typeof v === 'string' && v.trim() !== '');
296
- if (envModel !== undefined && !models.some((m) => m['enabled'] !== false)) {
297
- return refuse('env_catalog_present', en('onboard.plan.envCatalogPresent', { model: envModel }));
298
- }
299
- const rawEnv = input.settingsEnv;
300
- if (rawEnv !== undefined && (rawEnv === null || typeof rawEnv !== 'object' || Array.isArray(rawEnv)))
301
- return refuse('catalog_unreadable', en('onboard.plan.envNotObject'));
302
- const prevEnv = rawEnv === undefined ? {} : { ...rawEnv };
303
- const e = input.entry;
304
- const isShellSlot = (ref) => typeof ref === 'string' && ref.startsWith(KEY_SLOT_PREFIX) && typeof prevEnv[ref] === 'string';
305
- const targetKey = routeKeyOf(e.baseUrl);
306
- if (targetKey === undefined)
307
- return refuse('credential_unpaired', en('onboard.catalog.judgeAbsent', { name: e.modelId }));
308
- const sameTarget = (m) => m['id'] === e.modelId && m['api'] === e.api && typeof m['baseUrl'] === 'string' && routeKeyOf(m['baseUrl']) === targetKey;
309
- const existingIdx = models.findIndex((m) => sameTarget(m) && m['enabled'] !== false && m['sealedApiKey'] === undefined && (m['apiKeyEnv'] === undefined || isShellSlot(m['apiKeyEnv'])));
310
- const taken = new Set(models.map((m) => (typeof m['name'] === 'string' ? m['name'] : '')).filter((n) => n !== ''));
311
- const name = existingIdx >= 0 ? String(models[existingIdx]['name']) : poolEntryNameOf(e.modelId, e.channel, taken);
312
- const existingRef = existingIdx >= 0 ? models[existingIdx]['apiKeyEnv'] : undefined;
313
- const sharedByOther = typeof existingRef === 'string' &&
314
- models.some((m, i) => i !== existingIdx && typeof m['apiKeyEnv'] === 'string' && m['apiKeyEnv'].toUpperCase() === existingRef.toUpperCase());
315
- let keyEnv;
316
- if (isShellSlot(existingRef) && !sharedByOther) {
317
- keyEnv = existingRef;
318
- }
319
- else {
320
- const used = new Set();
321
- for (const m of models)
322
- if (typeof m['apiKeyEnv'] === 'string')
323
- used.add(m['apiKeyEnv'].toUpperCase());
324
- for (const k of Object.keys(prevEnv))
325
- used.add(k.toUpperCase());
326
- for (const [k, v] of Object.entries(input.effectiveEnv ?? {}))
327
- if (typeof v === 'string')
328
- used.add(k.toUpperCase());
329
- const baseSlot = keyEnvNameForEntry(name);
330
- keyEnv = baseSlot;
331
- for (let i = 2; used.has(keyEnv.toUpperCase()); i++)
332
- keyEnv = `${baseSlot}_${i}`;
333
- }
334
- if (carriesKey(name, e.apiKey) || carriesKey(keyEnv, e.apiKey))
335
- return refuse('input', en('onboard.input.keyInFields'));
336
- const base = existingIdx >= 0 ? models[existingIdx] : {};
337
- let entry = {
338
- ...base,
339
- name,
340
- id: e.modelId,
341
- provider: e.api === 'anthropic-messages' ? 'anthropic' : 'gateway',
342
- api: e.api,
343
- baseUrl: e.baseUrl,
344
- contextWindow: typeof base['contextWindow'] === 'number' ? base['contextWindow'] : e.contextWindow,
345
- maxTokens: typeof base['maxTokens'] === 'number' ? base['maxTokens'] : e.maxTokens,
346
- apiKeyEnv: keyEnv,
347
- semaChannel: typeof base['semaChannel'] === 'string' ? base['semaChannel'] : e.channel,
348
- semaLabel: typeof base['semaLabel'] === 'string' ? base['semaLabel'] : e.providerName,
349
- semaProbe: input.probe.verdict,
350
- semaProbeAt: input.now,
351
- };
352
- if (input.thinking !== undefined) {
353
- const probed = applyProbeToEntry({ ...(typeof entry['reasoning'] === 'boolean' ? { reasoning: entry['reasoning'] } : {}), ...(entry['compat'] !== undefined ? { compat: entry['compat'] } : {}) }, input.thinking);
354
- const next = { ...entry };
355
- if (typeof probed.reasoning === 'boolean')
356
- next['reasoning'] = probed.reasoning;
357
- if (probed.compat !== undefined)
358
- next['compat'] = probed.compat;
359
- else
360
- delete next['compat'];
361
- entry = next;
362
- }
363
- const envView = { ...input.effectiveEnv, [keyEnv]: e.apiKey };
364
- const issue = entryCredentialIssue(entry, envView);
365
- if (issue !== undefined)
366
- return refuse('credential_unpaired', issue);
367
- if (existingIdx >= 0)
368
- models[existingIdx] = entry;
369
- else
370
- models.push(entry);
371
- const nextDoc = { ...doc, models };
372
- if (input.makeDefault) {
373
- const prevRoles = doc['roles'];
374
- const roles = prevRoles !== null && typeof prevRoles === 'object' && !Array.isArray(prevRoles) ? { ...prevRoles } : {};
375
- roles['default'] = { model: name };
376
- nextDoc['roles'] = roles;
377
- }
378
- const otherIssues = [];
379
- for (const m of models) {
380
- if (m['enabled'] === false || m['name'] === name)
381
- continue;
382
- const other = entryCredentialIssue(m, envView);
383
- if (other !== undefined) {
384
- otherIssues.push(Object.freeze({ name: typeof m['name'] === 'string' ? m['name'] : '?', modelId: typeof m['id'] === 'string' ? m['id'] : '?', issue: say(other) }));
385
- }
386
- }
387
- return Object.freeze({
388
- ok: true,
389
- entryName: name,
390
- keyEnv,
391
- updatedExisting: existingIdx >= 0,
392
- nextModelsDoc: nextDoc,
393
- nextSettingsEnv: { ...prevEnv, [keyEnv]: e.apiKey },
394
- otherIssues: Object.freeze(otherIssues),
395
- });
396
- }
397
- catch {
398
- return refuse('input', en('onboard.refusal.input'));
399
- }
400
- }
401
353
  const REFUSAL_KEYS = {
402
354
  input: 'onboard.refusal.input',
403
355
  probe_failed: 'onboard.refusal.probeFailed',
@@ -0,0 +1,20 @@
1
+ import type { UiLanguage } from './env/uiLanguage.js';
2
+ type ModelConfigPartTuple = readonly ['model', 'gateway-url', 'api-key'];
3
+ export type ModelConfigPart = ModelConfigPartTuple[number];
4
+ export type ModelConfigKeyChannel = 'anthropic';
5
+ export interface ModelConfigGap {
6
+ readonly parts: readonly ModelConfigPart[];
7
+ readonly keyChannel?: ModelConfigKeyChannel;
8
+ readonly catalogEntries?: number;
9
+ }
10
+ export type ModelConfigGapNotice = {
11
+ readonly kind: 'gap';
12
+ readonly head: string;
13
+ readonly detail: string;
14
+ } | {
15
+ readonly kind: 'none';
16
+ } | {
17
+ readonly kind: 'malformed';
18
+ };
19
+ export declare function modelConfigGapNotice(missing: ModelConfigGap, lang?: UiLanguage): ModelConfigGapNotice;
20
+ export {};
@@ -0,0 +1,102 @@
1
+ import { msg, renderMessage } from './i18n/translate.js';
2
+ import { guardedRead, ownDataField } from './ownKey.js';
3
+ function partOrder() {
4
+ return ['model', 'gateway-url', 'api-key'];
5
+ }
6
+ function isPart(v) {
7
+ return v === 'model' || v === 'gateway-url' || v === 'api-key';
8
+ }
9
+ const MALFORMED = Object.freeze({ kind: 'malformed' });
10
+ const NONE = Object.freeze({ kind: 'none' });
11
+ function readGap(missing) {
12
+ try {
13
+ if (missing === null || typeof missing !== 'object' || Array.isArray(missing))
14
+ return undefined;
15
+ const raw = ownDataField(missing, 'parts');
16
+ if (!Array.isArray(raw))
17
+ return undefined;
18
+ const order = partOrder();
19
+ const length = ownDataField(raw, 'length');
20
+ if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0 || length > order.length)
21
+ return undefined;
22
+ const present = new Set();
23
+ for (let i = 0; i < length; i++) {
24
+ const word = ownDataField(raw, String(i));
25
+ if (!isPart(word) || present.has(word))
26
+ return undefined;
27
+ present.add(word);
28
+ }
29
+ const parts = order.filter((p) => present.has(p));
30
+ const channel = guardedRead(() => ownDataField(missing, 'keyChannel'));
31
+ const count = guardedRead(() => ownDataField(missing, 'catalogEntries'));
32
+ return {
33
+ parts,
34
+ anthropicKey: channel === 'anthropic' && present.has('api-key'),
35
+ entries: typeof count === 'number' && Number.isSafeInteger(count) && count >= 1 ? count : undefined,
36
+ };
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ }
42
+ const HEAD_KEYS = Object.freeze({
43
+ model: 'model.configGap.head.model',
44
+ gatewayUrl: 'model.configGap.head.gatewayUrl',
45
+ apiKey: 'model.configGap.head.apiKey',
46
+ anthropicKey: 'model.configGap.head.anthropicKey',
47
+ incomplete: 'model.configGap.head.incomplete',
48
+ });
49
+ function headKeyOf(r) {
50
+ if (r.parts.includes('model'))
51
+ return HEAD_KEYS.model;
52
+ if (r.parts.includes('gateway-url'))
53
+ return r.parts.includes('api-key') ? HEAD_KEYS.incomplete : HEAD_KEYS.gatewayUrl;
54
+ return r.anthropicKey ? HEAD_KEYS.anthropicKey : HEAD_KEYS.apiKey;
55
+ }
56
+ function itemRef(part, anthropicKey) {
57
+ switch (part) {
58
+ case 'model':
59
+ return msg('model.configGap.item.model');
60
+ case 'gateway-url':
61
+ return msg('model.configGap.item.gatewayUrl');
62
+ case 'api-key':
63
+ return msg(anthropicKey ? 'model.configGap.item.anthropicKey' : 'model.configGap.item.apiKey');
64
+ }
65
+ }
66
+ function leadRef(first, second, third, anthropicKey) {
67
+ const a = itemRef(first, anthropicKey);
68
+ if (second === undefined)
69
+ return msg('model.configGap.lead.one', { a });
70
+ const b = itemRef(second, anthropicKey);
71
+ if (third === undefined)
72
+ return msg('model.configGap.lead.two', { a, b });
73
+ return msg('model.configGap.lead.three', { a, b, c: itemRef(third, anthropicKey) });
74
+ }
75
+ function reasonRef(r) {
76
+ if (r.parts.includes('model'))
77
+ return msg('model.configGap.reason.noModel');
78
+ const n = r.entries;
79
+ if (n === undefined)
80
+ return undefined;
81
+ if (r.anthropicKey)
82
+ return n === 1 ? msg('model.configGap.reason.anthropicCatalog.one') : msg('model.configGap.reason.anthropicCatalog.other', { count: n });
83
+ if (r.parts.includes('gateway-url'))
84
+ return n === 1 ? msg('model.configGap.reason.gatewayCatalog.one') : msg('model.configGap.reason.gatewayCatalog.other', { count: n });
85
+ return undefined;
86
+ }
87
+ export function modelConfigGapNotice(missing, lang) {
88
+ const r = readGap(missing);
89
+ if (r === undefined)
90
+ return MALFORMED;
91
+ const [first, second, third] = r.parts;
92
+ if (first === undefined)
93
+ return NONE;
94
+ const lead = leadRef(first, second, third, r.anthropicKey);
95
+ const reason = reasonRef(r);
96
+ const detail = reason === undefined ? lead : msg('model.configGap.detail.withReason', { missing: lead, reason });
97
+ return Object.freeze({
98
+ kind: 'gap',
99
+ head: renderMessage(msg(headKeyOf(r)), lang),
100
+ detail: renderMessage(detail, lang),
101
+ });
102
+ }
@@ -1,4 +1,5 @@
1
1
  import { KERNEL_CONTRACT_VERSION, MOD_EVENT_TABLE } from '@sema-agent/mods-kernel';
2
+ import { sha256BytesHex } from './sha256Bytes.js';
2
3
  const MAX_DEPTH = 16;
3
4
  const MAX_NODES = 100_000;
4
5
  function canonical(v, depth, budget) {
@@ -35,52 +36,6 @@ function canonical(v, depth, budget) {
35
36
  }
36
37
  throw new TypeError('modsKernelIdentity: the event table holds a value that is not plain data');
37
38
  }
38
- function sha256Hex(msg) {
39
- const k = [
40
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
41
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
42
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
43
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
44
- ];
45
- const h = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
46
- const len = msg.length;
47
- const padded = new Uint8Array(((len + 8) >>> 6) * 64 + 64);
48
- padded.set(msg);
49
- padded[len] = 0x80;
50
- const view = new DataView(padded.buffer);
51
- view.setUint32(padded.length - 8, Math.floor(len / 0x20000000));
52
- view.setUint32(padded.length - 4, (len << 3) >>> 0);
53
- const w = new Array(64).fill(0);
54
- const rotr = (x, n) => (x >>> n) | (x << (32 - n));
55
- for (let off = 0; off < padded.length; off += 64) {
56
- for (let t = 0; t < 16; t++)
57
- w[t] = view.getUint32(off + t * 4);
58
- for (let t = 16; t < 64; t++) {
59
- const x = w[t - 15] ?? 0;
60
- const y = w[t - 2] ?? 0;
61
- const s0 = rotr(x, 7) ^ rotr(x, 18) ^ (x >>> 3);
62
- const s1 = rotr(y, 17) ^ rotr(y, 19) ^ (y >>> 10);
63
- w[t] = ((w[t - 16] ?? 0) + s0 + (w[t - 7] ?? 0) + s1) | 0;
64
- }
65
- let [a, b, c, d, e, f, g, hh] = h;
66
- for (let t = 0; t < 64; t++) {
67
- const t1 = (hh + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + ((e & f) ^ (~e & g)) + (k[t] ?? 0) + (w[t] ?? 0)) | 0;
68
- const t2 = ((rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) | 0;
69
- hh = g;
70
- g = f;
71
- f = e;
72
- e = (d + t1) | 0;
73
- d = c;
74
- c = b;
75
- b = a;
76
- a = (t1 + t2) | 0;
77
- }
78
- const next = [a, b, c, d, e, f, g, hh];
79
- for (let i = 0; i < 8; i++)
80
- h[i] = ((h[i] ?? 0) + (next[i] ?? 0)) | 0;
81
- }
82
- return h.map((x) => (x >>> 0).toString(16).padStart(8, '0')).join('');
83
- }
84
39
  export function modsKernelIdentity(kernel = { KERNEL_CONTRACT_VERSION, MOD_EVENT_TABLE }) {
85
40
  try {
86
41
  if (typeof kernel !== 'object' || kernel === null)
@@ -93,7 +48,7 @@ export function modsKernelIdentity(kernel = { KERNEL_CONTRACT_VERSION, MOD_EVENT
93
48
  if (typeof table !== 'object' || table === null || Array.isArray(table)) {
94
49
  throw new TypeError('modsKernelIdentity: the source carries no readable event table');
95
50
  }
96
- return { contractVersion, tableDigest: sha256Hex(new TextEncoder().encode(canonical(table, 0, { nodes: 0 }))) };
51
+ return { contractVersion, tableDigest: sha256BytesHex(new TextEncoder().encode(canonical(table, 0, { nodes: 0 }))) };
97
52
  }
98
53
  catch (e) {
99
54
  if (e instanceof TypeError)
@@ -1,4 +1,5 @@
1
1
  import { hostEnv } from './hostEnv.js';
2
+ import { planReviewOutcomeCauseOf } from './planReviewOutcomeCause.js';
2
3
  import { unrefTimer } from './unrefTimer.js';
3
4
  import { clearEnginePanelTaskResidentByWire, publishEngineAgentPanelEvent, } from './engineAgentPanelStore.js';
4
5
  import { panelEndFact } from './panelReduce.js';
@@ -432,21 +433,22 @@ export function enqueuePlanReviewOutcome(value, meta) {
432
433
  priority: 'later',
433
434
  isMeta: true,
434
435
  workload: 'plan-review',
435
- ...(meta !== undefined
436
- ? {
437
- _sema_planReviewOutcome: Object.freeze({
438
- taskId: meta.taskId,
439
- dispatchNo: meta.dispatchNo,
440
- decision: meta.decision,
441
- effect: meta.effect,
442
- ...(meta.effect === 'still_parked' && meta.cause === 'stored_form_unsupported' ? { cause: meta.cause } : {}),
443
- ...(questionId !== undefined ? { questionId } : {}),
444
- }),
445
- }
446
- : {}),
436
+ ...(meta !== undefined ? { _sema_planReviewOutcome: planReviewOutcomeRefrozen(meta, questionId) } : {}),
447
437
  });
448
438
  return true;
449
439
  }
440
+ function planReviewOutcomeRefrozen(meta, questionId) {
441
+ const effect = meta.effect;
442
+ const cause = planReviewOutcomeCauseOf(effect, meta.cause);
443
+ return Object.freeze({
444
+ taskId: meta.taskId,
445
+ dispatchNo: meta.dispatchNo,
446
+ decision: meta.decision,
447
+ effect,
448
+ ...(cause !== undefined ? { cause } : {}),
449
+ ...(questionId !== undefined ? { questionId } : {}),
450
+ });
451
+ }
450
452
  export function resupplyTruncatedSentence(facts, lang) {
451
453
  try {
452
454
  const f = resupplyTruncatedFactsOf(facts);
package/dist/ownKey.d.ts CHANGED
@@ -75,6 +75,7 @@ export interface SampledRecord {
75
75
  export declare function ownSnapshotWhenTyped<V>(value: V, word: string): SampledJson;
76
76
  export declare function ownSnapshotTyped<T extends object>(value: T): T | undefined;
77
77
  export declare function ownSnapshotRecord<V>(value: V): SampledRecord | undefined;
78
+ export declare function ownSnapshotRecordFaithful<V>(value: V): SampledRecord | undefined;
78
79
  export declare function workflowCompletionExtrasOf(c: object): {
79
80
  completionId?: string;
80
81
  diagnostics?: string;
package/dist/ownKey.js CHANGED
@@ -291,6 +291,7 @@ export function promptManifestIdentityOf(raw) {
291
291
  }
292
292
  }
293
293
  const SAMPLED = new WeakSet();
294
+ const LOSSY = new WeakSet();
294
295
  const SAMPLE_MAX_DEPTH = 256;
295
296
  export function isOwnSnapshot(v) {
296
297
  return isBranded(v);
@@ -311,7 +312,7 @@ function snapshotOf(value) {
311
312
  if (typeof value === 'object' && value !== null) {
312
313
  if (SAMPLED.has(value))
313
314
  return value;
314
- return sampleObject(value, 0, { done: new Map(), path: new Set(), seen: new Set(), rework: 0, depthCuts: 0 });
315
+ return sampleObject(value, 0, { done: new Map(), path: new Set(), seen: new Set(), rework: 0, depthCuts: 0, lost: 0 });
315
316
  }
316
317
  return samplePrimitive(value);
317
318
  }
@@ -342,6 +343,10 @@ export function ownSnapshotTyped(value) {
342
343
  export function ownSnapshotRecord(value) {
343
344
  return recordOf(value);
344
345
  }
346
+ export function ownSnapshotRecordFaithful(value) {
347
+ const s = recordOf(value);
348
+ return s === undefined || LOSSY.has(s) ? undefined : s;
349
+ }
345
350
  function recordOf(value) {
346
351
  const s = snapshotOf(value);
347
352
  return typeof s === 'object' && s !== null && !Array.isArray(s) ? s : undefined;
@@ -357,19 +362,29 @@ function sampleValue(v, depth, run) {
357
362
  }
358
363
  function sampleObject(src, depth, run) {
359
364
  const hit = run.done.get(src);
360
- if (hit !== undefined)
365
+ if (hit !== undefined) {
366
+ if (hit === null || LOSSY.has(hit))
367
+ run.lost++;
361
368
  return hit ?? undefined;
362
- if (SAMPLED.has(src))
369
+ }
370
+ if (SAMPLED.has(src)) {
371
+ if (LOSSY.has(src))
372
+ run.lost++;
363
373
  return src;
364
- if (run.path.has(src))
374
+ }
375
+ if (run.path.has(src)) {
376
+ run.lost++;
365
377
  return undefined;
378
+ }
366
379
  if (depth >= SAMPLE_MAX_DEPTH) {
367
380
  run.depthCuts++;
381
+ run.lost++;
368
382
  return undefined;
369
383
  }
370
384
  if (run.seen.has(src)) {
371
385
  if (++run.rework > SAMPLE_MAX_REWORK) {
372
386
  run.depthCuts++;
387
+ run.lost++;
373
388
  return undefined;
374
389
  }
375
390
  }
@@ -384,10 +399,12 @@ function sampleObject(src, depth, run) {
384
399
  }
385
400
  catch {
386
401
  run.done.set(src, null);
402
+ run.lost++;
387
403
  return undefined;
388
404
  }
389
405
  run.path.add(src);
390
406
  const cutsBefore = run.depthCuts;
407
+ const lostBefore = run.lost;
391
408
  try {
392
409
  const rec = {};
393
410
  const arr = [];
@@ -409,18 +426,29 @@ function sampleObject(src, depth, run) {
409
426
  const index = isArray ? arrayIndexOfKey(k) : undefined;
410
427
  if (isArray && index === undefined)
411
428
  continue;
412
- if (index !== undefined && index >= SAMPLE_MAX_INDEX)
429
+ if (index !== undefined && index >= SAMPLE_MAX_INDEX) {
430
+ run.lost++;
413
431
  continue;
432
+ }
414
433
  if (index !== undefined && index + 1 > tail)
415
434
  tail = index + 1;
416
435
  const d = guardedRead(() => Object.getOwnPropertyDescriptor(src, k));
417
- if (d === undefined)
436
+ if (d === undefined) {
437
+ run.lost++;
418
438
  continue;
419
- if (d.enumerable !== true || !Object.hasOwn(d, 'value'))
439
+ }
440
+ if (d.enumerable !== true)
441
+ continue;
442
+ if (!Object.hasOwn(d, 'value')) {
443
+ run.lost++;
420
444
  continue;
445
+ }
421
446
  const child = sampleValue(d.value, depth + 1, run);
422
- if (child === undefined)
447
+ if (child === undefined) {
448
+ if (typeof d.value === 'bigint')
449
+ run.lost++;
423
450
  continue;
451
+ }
424
452
  if (index !== undefined) {
425
453
  Object.defineProperty(arr, index, { value: child, writable: true, enumerable: true, configurable: true });
426
454
  if (index + 1 > good)
@@ -431,12 +459,16 @@ function sampleObject(src, depth, run) {
431
459
  }
432
460
  if (isArray) {
433
461
  const want = Math.max(good, Math.min(Math.max(tail, declared), good + SAMPLE_MAX_TRAILING_HOLES));
462
+ if (Math.max(tail, declared) > want)
463
+ run.lost++;
434
464
  if (arr.length < want)
435
465
  arr.length = want;
436
466
  }
437
467
  const out = isArray ? arr : rec;
438
468
  Object.freeze(out);
439
469
  SAMPLED.add(out);
470
+ if (run.lost !== lostBefore)
471
+ LOSSY.add(out);
440
472
  if (run.depthCuts === cutsBefore)
441
473
  run.done.set(src, out);
442
474
  return out;
@@ -1,5 +1,6 @@
1
1
  import { type CoreValuePortName } from './coreValuePorts.js';
2
2
  import { type PermissionsAllowGrantReading } from './permissionsAllowGrantCapability.js';
3
+ import type { UiLanguage } from './env/uiLanguage.js';
3
4
  declare const SETTINGS_SOURCE_TIERS: Readonly<{
4
5
  readonly policySettings: "managed";
5
6
  readonly flagSettings: "global";
@@ -118,5 +119,5 @@ export interface PermissionsAllowKeptFacts {
118
119
  readonly managedPolicyFetch?: 'in_progress' | 'failed' | 'unknown';
119
120
  readonly where?: string;
120
121
  }
121
- export declare function permissionsAllowKeptNotice(report: Pick<PermissionsDeclarationReport, 'kept'>, settingsRead: 'clean' | 'partial' | 'unreadable', facts?: PermissionsAllowKeptFacts): string | undefined;
122
+ export declare function permissionsAllowKeptNotice(report: Pick<PermissionsDeclarationReport, 'kept'>, settingsRead: 'clean' | 'partial' | 'unreadable', facts?: PermissionsAllowKeptFacts, lang?: UiLanguage): string | undefined;
122
123
  export {};