@sema-agent/client-core 0.99.0 → 0.100.0
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 +177 -0
- package/README.md +32 -19
- package/dist/adapt/arms.js +60 -36
- package/dist/adapt/panelTasks.d.ts +2 -1
- package/dist/adapt/panelTasks.js +32 -9
- package/dist/adapt/textStream.d.ts +1 -1
- package/dist/adapt/textStream.js +51 -28
- package/dist/adapter/activeRunSelfHeal.d.ts +7 -0
- package/dist/adapter/activeRunSelfHeal.js +58 -11
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
- package/dist/adapter/downstream/eventToSdkMessage.js +125 -9
- package/dist/adapter/downstream/terminalToSdkResult.js +10 -0
- package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
- package/dist/adapter/downstream/wiringManifestView.js +1 -0
- package/dist/adapter/runStream.js +32 -5
- package/dist/adapter/types.d.ts +2 -0
- package/dist/agentsWireCaps.d.ts +7 -0
- package/dist/agentsWireCaps.js +100 -15
- package/dist/cloudConfigWireCaps.d.ts +10 -1
- package/dist/cloudConfigWireCaps.js +156 -62
- package/dist/compactionStatus.d.ts +34 -0
- package/dist/compactionStatus.js +196 -0
- package/dist/decideFailureNote.js +3 -3
- package/dist/displayUntrusted.js +150 -5
- package/dist/engineAgentPanelStore.d.ts +7 -4
- package/dist/engineErrorCodes.d.ts +9 -1
- package/dist/engineErrorCodes.js +9 -5
- package/dist/engineRowRef.js +1 -0
- package/dist/engineToolDirectory.d.ts +3 -0
- package/dist/engineToolDirectory.js +4 -2
- package/dist/eventLeg.d.ts +1 -7
- package/dist/eventLeg.js +7 -8
- package/dist/fileHistoryCaptureCapability.d.ts +0 -3
- package/dist/fileHistoryCaptureCapability.js +0 -4
- package/dist/generated/engineFactTables.d.ts +1 -0
- package/dist/generated/engineFactTables.js +27 -0
- package/dist/generated/engineNoticeTables.js +3 -0
- package/dist/generated/settingsSchemaFns.d.ts +12 -0
- package/dist/generated/settingsSchemaFns.js +13 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
- package/dist/generated/settingsSchemaTables.d.ts +1 -0
- package/dist/generated/settingsSchemaTables.js +5 -0
- package/dist/generated/settingsSchemaTypes.d.ts +28 -0
- package/dist/hitl/allowRuleShadow.js +2 -2
- package/dist/hitl/approvalCardReasons.js +2 -2
- package/dist/hitl/approvalHolds.d.ts +14 -0
- package/dist/hitl/approvalHolds.js +41 -0
- package/dist/hitl/askClassPair.d.ts +2 -2
- package/dist/hitl/askClassPair.js +2 -2
- package/dist/hitl/attributionLadder.d.ts +23 -0
- package/dist/hitl/attributionLadder.js +67 -0
- package/dist/hitl/decisionLedger.d.ts +55 -0
- package/dist/hitl/decisionLedger.js +156 -0
- package/dist/hitl/decisionRefusal.d.ts +1 -0
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +113 -0
- package/dist/hitl/decisionSend.js +579 -0
- package/dist/hitl/hitlBridge.js +18 -6
- package/dist/hitl/planReviewWire.js +45 -76
- package/dist/hitl/sessionPolicyDeliverable.js +3 -6
- package/dist/hitl/toolApprovalWire.js +43 -109
- package/dist/hostTurnSettings.d.ts +46 -7
- package/dist/hostTurnSettings.js +408 -7
- package/dist/humanTurn.d.ts +2 -1
- package/dist/humanTurn.js +3 -3
- package/dist/i18n/messages.en.d.ts +131 -0
- package/dist/i18n/messages.en.js +143 -12
- package/dist/i18n/messages.zh.js +148 -12
- package/dist/index.d.ts +18 -2
- package/dist/index.js +10 -1
- package/dist/inheritEnvCapability.d.ts +1 -0
- package/dist/inheritEnvCapability.js +9 -2
- package/dist/inheritEnvWire.js +2 -2
- package/dist/injectionLaneNotice.d.ts +5 -0
- package/dist/injectionLaneNotice.js +46 -0
- package/dist/mcpPanel.js +2 -0
- package/dist/mcpReconnect.js +2 -2
- package/dist/mcpToolToggles.d.ts +6 -0
- package/dist/mcpToolToggles.js +46 -0
- package/dist/mcpWireCaps.d.ts +10 -4
- package/dist/mcpWireCaps.js +106 -71
- package/dist/mcpWireTransport.d.ts +4 -0
- package/dist/mcpWireTransport.js +18 -0
- package/dist/modelCapabilityProbe.d.ts +2 -1
- package/dist/modelCapabilityProbe.js +10 -9
- package/dist/modelIdentityResolvability.d.ts +2 -0
- package/dist/modelIdentityResolvability.js +23 -5
- package/dist/ownKey.d.ts +26 -0
- package/dist/ownKey.js +75 -0
- package/dist/panelReduce.d.ts +5 -0
- package/dist/panelReduce.js +45 -13
- package/dist/panelStateHolder.d.ts +1 -0
- package/dist/panelStateHolder.js +10 -1
- package/dist/permissionRuleIssue.d.ts +2 -1
- package/dist/permissionRuleIssue.js +22 -21
- package/dist/pluginHooksWire.js +12 -10
- package/dist/prepareRefusal.d.ts +8 -0
- package/dist/prepareRefusal.js +72 -0
- package/dist/request/taskRequest.d.ts +10 -10
- package/dist/request/taskRequest.js +106 -65
- package/dist/resumeRefusalCopy.d.ts +3 -1
- package/dist/resumeRefusalCopy.js +22 -4
- package/dist/retryStatus.d.ts +18 -0
- package/dist/retryStatus.js +76 -19
- package/dist/ruleRefusalSentence.d.ts +4 -0
- package/dist/ruleRefusalSentence.js +58 -0
- package/dist/sandboxWire.d.ts +2 -1
- package/dist/sandboxWire.js +55 -21
- package/dist/scenarioRefusal.d.ts +2 -1
- package/dist/scenarioRefusal.js +5 -5
- package/dist/seam.d.ts +24 -9
- package/dist/seam.js +44 -4
- package/dist/seatContract.d.ts +16 -8
- package/dist/seatContract.js +21 -6
- package/dist/settingsCredentialKeyPaths.d.ts +8 -0
- package/dist/settingsCredentialKeyPaths.js +219 -0
- package/dist/skillsWireCaps.d.ts +0 -3
- package/dist/skillsWireCaps.js +1 -2
- package/dist/subagentContentStore.d.ts +1 -0
- package/dist/subagentContentStore.js +135 -27
- package/dist/toolsFlagNames.d.ts +8 -0
- package/dist/toolsFlagNames.js +110 -0
- package/dist/turnFailurePresentation.js +15 -7
- package/dist/wireRefusalCopy.d.ts +51 -17
- package/dist/wireRefusalCopy.js +298 -135
- package/docs/INTEGRATION-CLIENTS.md +423 -26
- package/package.json +4 -4
|
@@ -4,7 +4,7 @@ import { retiredAttachmentsKeyOf } from '../taskRequestWords.js';
|
|
|
4
4
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
5
5
|
import { outputStyleSeatAdmitted } from '../outputStyleSeatCapability.js';
|
|
6
6
|
import { refuseBadApprovalReach } from '../approvalReachWire.js';
|
|
7
|
-
import { HOST_SUPPLIED_KEYS, HostSettingsRefused, buildHostTurnSettings, hostTurnSettingsOf, rethrowHostResolvedDeferred, } from '../hostTurnSettings.js';
|
|
7
|
+
import { HOST_SUPPLIED_KEYS, HostSettingsRefused, UNWIRED_HOST_TURN_SETTINGS, buildHostTurnSettings, hostIntakeSnapshotOf, hostProjectionNotice, hostTurnSettingsOf, intersectHostHooks, rethrowHostResolvedDeferred, } from '../hostTurnSettings.js';
|
|
8
8
|
export const REQUEST_FIELD_MATRIX = [
|
|
9
9
|
{ field: 'objective', lanes: ['interactive', 'print', 'utility'], live: false, why: '本 turn 的真实输入,每条车道都必需', whyUtilityLane: '恒座:三条车道都必须带上本次提交的模型面输入' },
|
|
10
10
|
{ field: 'sessionId', lanes: ['interactive', 'print', 'utility'], live: false, why: '单命名空间(TP-A Step 2):壳 id 即引擎 session id;print 在非 live 下保留 mock 常量', whyUtilityLane: '恒座:side-channel 提交走**独立**会话 id(壳另铸一个,绝不复用用户会话那一个 —— 复用会把这次提交的转录混进用户会话)' },
|
|
@@ -168,8 +168,6 @@ const INPUT_KEY_ROUTES = {
|
|
|
168
168
|
why: '思考 token 数上限:sdk `TaskRequest` 上思考强度只有档位词(`reasoningEffort` 七词闭集),没有 token 数这一位;把数字折成档位词 = 替用户编一个他没说过的档位',
|
|
169
169
|
},
|
|
170
170
|
memoryCapture: row('memoryCapture'),
|
|
171
|
-
memory: row('memory'),
|
|
172
|
-
fileHistory: row('fileHistory'),
|
|
173
171
|
inheritEnv: row('inheritEnv'),
|
|
174
172
|
requireExistingSession: row('requireExistingSession'),
|
|
175
173
|
disableSkills: row('disableSkills'),
|
|
@@ -179,8 +177,16 @@ const INPUT_KEY_ROUTES = {
|
|
|
179
177
|
hostSettings: { via: 'control' },
|
|
180
178
|
settings: { via: 'settings' },
|
|
181
179
|
};
|
|
180
|
+
const HOST_TOP_KEY_ROUTES = {
|
|
181
|
+
memory: row('memory'),
|
|
182
|
+
fileHistory: row('fileHistory'),
|
|
183
|
+
};
|
|
184
|
+
const HOST_TOP_KEYS = Object.freeze(Object.keys(HOST_TOP_KEY_ROUTES));
|
|
185
|
+
const _hostTopKeysPin = [true];
|
|
186
|
+
void _hostTopKeysPin;
|
|
187
|
+
const HOST_TOP_ASK_AFTER = 'memoryCapture';
|
|
182
188
|
const HOST_SETTINGS_SUBKEYS = Object.freeze(HOST_SUPPLIED_KEYS.filter((k) => k.startsWith('settings.')).map((k) => k.slice('settings.'.length)));
|
|
183
|
-
const _hostSubkeysPin = [true, true, true
|
|
189
|
+
const _hostSubkeysPin = [true, true, true];
|
|
184
190
|
void _hostSubkeysPin;
|
|
185
191
|
const SETTINGS_KEY_ROUTES = {
|
|
186
192
|
resolved: row('settings.<resolved>'),
|
|
@@ -195,6 +201,8 @@ const liveDefaultKeyNames = () => new Set(LIVE_DEFAULT_FIELDS.flatMap(item => it
|
|
|
195
201
|
const routeOfTopLevelKey = (key) => {
|
|
196
202
|
if (hasOwn(INPUT_KEY_ROUTES, key))
|
|
197
203
|
return INPUT_KEY_ROUTES[key];
|
|
204
|
+
if (hasOwn(HOST_TOP_KEY_ROUTES, key))
|
|
205
|
+
return HOST_TOP_KEY_ROUTES[key];
|
|
198
206
|
if (!key.includes('.') && liveDefaultKeyNames().has(key))
|
|
199
207
|
return { via: 'fixed', cause: 'other_channel' };
|
|
200
208
|
return undefined;
|
|
@@ -221,15 +229,16 @@ const OMISSION_JUDGES = {
|
|
|
221
229
|
not_live: (s, _lane, live) => s.via === 'matrix' && s.spec.live && !live,
|
|
222
230
|
};
|
|
223
231
|
const omissionCauseOf = (s, lane, live) => TASK_REQUEST_OMISSION_CAUSES.find(cause => OMISSION_JUDGES[cause](s, lane, live));
|
|
224
|
-
const hostRefusalNoticeOf = (
|
|
232
|
+
const hostRefusalNoticeOf = (intake, lane, live) => {
|
|
233
|
+
const verdictNotice = intake.notice ?? hostProjectionNotice();
|
|
225
234
|
try {
|
|
226
|
-
const refusing =
|
|
235
|
+
const refusing = intake.refusingKeys;
|
|
227
236
|
if (refusing.length === 0)
|
|
228
237
|
return verdictNotice;
|
|
229
|
-
const turnNotices =
|
|
230
|
-
const aligned = turnNotices.length === refusing.length;
|
|
231
|
-
for (const [i,
|
|
232
|
-
if (!hostRefuseRowSeated(
|
|
238
|
+
const turnNotices = intake.turnNotices;
|
|
239
|
+
const aligned = turnNotices !== undefined && turnNotices.length === refusing.length;
|
|
240
|
+
for (const [i, key] of refusing.entries()) {
|
|
241
|
+
if (!hostRefuseRowSeated(key, lane, live))
|
|
233
242
|
continue;
|
|
234
243
|
return aligned ? (turnNotices[i] ?? verdictNotice) : verdictNotice;
|
|
235
244
|
}
|
|
@@ -240,6 +249,12 @@ const hostRefusalNoticeOf = (host, lane, live, verdictNotice) => {
|
|
|
240
249
|
}
|
|
241
250
|
};
|
|
242
251
|
const hostRefuseRowSeated = (key, lane, live) => {
|
|
252
|
+
if (hasOwn(HOST_TOP_KEY_ROUTES, key)) {
|
|
253
|
+
const top = HOST_TOP_KEY_ROUTES[key];
|
|
254
|
+
return top === undefined || (top.via !== 'matrix' && top.via !== 'fixed') || omissionCauseOf(standingOf(top), lane, live) === undefined;
|
|
255
|
+
}
|
|
256
|
+
if (!key.startsWith('settings.'))
|
|
257
|
+
return true;
|
|
243
258
|
const sub = key.slice('settings.'.length);
|
|
244
259
|
if (!hasOwn(SETTINGS_KEY_ROUTES, sub))
|
|
245
260
|
return true;
|
|
@@ -444,16 +459,49 @@ const resolvedSnapshotForWire = (resolved) => {
|
|
|
444
459
|
return out;
|
|
445
460
|
};
|
|
446
461
|
export function hostTurnSettings(input) {
|
|
447
|
-
return buildHostTurnSettings(input, (snapshot) => resolvedSnapshotForWire(snapshot));
|
|
462
|
+
return buildHostTurnSettings(input, { materialize: (snapshot) => resolvedSnapshotForWire(snapshot), memoryOffDeclared });
|
|
463
|
+
}
|
|
464
|
+
export function refilterHostSettings(request, fresh, lane) {
|
|
465
|
+
refuseBadLane(lane);
|
|
466
|
+
const host = hostTurnSettingsOf(fresh);
|
|
467
|
+
const intake = host === undefined || host === UNWIRED_HOST_TURN_SETTINGS ? undefined : hostIntakeSnapshotOf(host);
|
|
468
|
+
if (host === undefined || intake === undefined) {
|
|
469
|
+
throw new TypeError(renderMessage(msg('config.taskRequest.hostSettingsMalformed', { shape: coarseShape(fresh) })));
|
|
470
|
+
}
|
|
471
|
+
const refuseNotice = () => intake.notice ?? hostProjectionNotice();
|
|
472
|
+
if (intake.refuses) {
|
|
473
|
+
const refusing = hostRefusalNoticeOf(intake, lane, true);
|
|
474
|
+
if (refusing !== undefined)
|
|
475
|
+
return Object.freeze({ kind: 'refuse', notice: refusing });
|
|
476
|
+
}
|
|
477
|
+
const settings = request.settings;
|
|
478
|
+
if (!isPlainRecord(settings) || !Object.hasOwn(settings, 'hooks'))
|
|
479
|
+
return Object.freeze({ kind: 'send', request, hooksDropped: 0 });
|
|
480
|
+
const disposition = intake.dispositions['settings.hooks'];
|
|
481
|
+
if (disposition === 'unwired')
|
|
482
|
+
return Object.freeze({ kind: 'send', request, hooksDropped: 0 });
|
|
483
|
+
const now = intake.carried.hooks;
|
|
484
|
+
const sentHooks = settings.hooks;
|
|
485
|
+
if (!isPlainRecord(sentHooks))
|
|
486
|
+
return Object.freeze({ kind: 'refuse', notice: refuseNotice() });
|
|
487
|
+
const cut = intersectHostHooks(sentHooks, now);
|
|
488
|
+
if (!cut.judged)
|
|
489
|
+
return Object.freeze({ kind: 'refuse', notice: refuseNotice() });
|
|
490
|
+
if (cut.dropped === 0)
|
|
491
|
+
return Object.freeze({ kind: 'send', request, hooksDropped: 0 });
|
|
492
|
+
const { hooks: _sentHooks, ...restSettings } = settings;
|
|
493
|
+
void _sentHooks;
|
|
494
|
+
const nextSettings = cut.hooks === undefined ? restSettings : { ...restSettings, hooks: cut.hooks };
|
|
495
|
+
const { settings: _sentSettings, ...restRequest } = request;
|
|
496
|
+
void _sentSettings;
|
|
497
|
+
const next = Object.keys(nextSettings).length > 0 ? { ...restRequest, settings: nextSettings } : restRequest;
|
|
498
|
+
return Object.freeze({ kind: 'send', request: next, hooksDropped: cut.dropped });
|
|
448
499
|
}
|
|
449
500
|
export const MEMORY_CAPTURE_OFF = 'off';
|
|
450
501
|
export function memoryCaptureDeclarationField(declared) {
|
|
451
502
|
return declared ? { memoryCapture: MEMORY_CAPTURE_OFF } : {};
|
|
452
503
|
}
|
|
453
504
|
export const MEMORY_OFF = 'off';
|
|
454
|
-
export function memoryOffDeclarationField(declared) {
|
|
455
|
-
return declared ? { memory: MEMORY_OFF } : {};
|
|
456
|
-
}
|
|
457
505
|
export const FILE_HISTORY_DISABLED = 'disabled';
|
|
458
506
|
export const INHERIT_ENV_WORDS = Object.freeze(['all', 'scrub']);
|
|
459
507
|
export function isInheritEnvWord(v) {
|
|
@@ -481,16 +529,6 @@ export function memoryOffDeclared(input) {
|
|
|
481
529
|
}
|
|
482
530
|
return flag === MEMORY_OFF || fromSettings;
|
|
483
531
|
}
|
|
484
|
-
const refuseBadMemoryOff = (v) => {
|
|
485
|
-
if (v === undefined || v === null)
|
|
486
|
-
return;
|
|
487
|
-
if (v === 'off')
|
|
488
|
-
return;
|
|
489
|
-
throw new TypeError('buildTaskRequest: memory 只接受字面量 `\'off\'` 或缺席(undefined/null)—— ' +
|
|
490
|
-
`收到 ${coarseShape(v)}。这一位是**请求级整面开关**(「这一次别给我记忆」),上游是**单成员闭集**(没有 ` +
|
|
491
|
-
'`"on"`,`{ enabled: false }` 对象形也不是 wire 拼法)且对坏拼写**响亮拒**(server 400 `request.field_invalid`)。' +
|
|
492
|
-
'本层若静默删键,这一次运行会照常挂上记忆面而声明人不会知道 —— 与 memoryCapture 同一条纪律。错误文本只报形状,不回显值。');
|
|
493
|
-
};
|
|
494
532
|
const withoutRetiredAttachmentsKeys = (v) => {
|
|
495
533
|
if (typeof v !== 'object' || v === null)
|
|
496
534
|
return v;
|
|
@@ -598,15 +636,6 @@ const refuseBadExcludeAllTools = (v) => {
|
|
|
598
636
|
`收到 ${coarseShape(v)}。这一位是**整只工具面卸载**的收紧声明:本层若把坏值静默删键,这一次运行会挂上声明人以为已经卸掉的全部工具。` +
|
|
599
637
|
'错误文本只报形状,不回显值。');
|
|
600
638
|
};
|
|
601
|
-
const refuseBadFileHistory = (v) => {
|
|
602
|
-
if (v === undefined || v === null)
|
|
603
|
-
return;
|
|
604
|
-
if (v === FILE_HISTORY_DISABLED)
|
|
605
|
-
return;
|
|
606
|
-
throw new TypeError('buildTaskRequest: fileHistory 只接受字面量 `\'disabled\'` 或缺席(undefined/null)—— ' +
|
|
607
|
-
`收到 ${coarseShape(v)}。这一位是「这一次运行别捕获文件历史」的收紧声明,上游是**单成员闭集**(没有第二个词)且对坏值` +
|
|
608
|
-
'**响亮拒**。本层若静默删键,这一次运行照常捕获而声明人不会知道。错误文本只报形状,不回显值。');
|
|
609
|
-
};
|
|
610
639
|
const refuseBadInheritEnv = (v) => {
|
|
611
640
|
if (v === undefined || v === null)
|
|
612
641
|
return;
|
|
@@ -704,7 +733,7 @@ export function parseMaxCostUsd(text) {
|
|
|
704
733
|
return { ok: false, why: 'not_positive' };
|
|
705
734
|
return { ok: true, value };
|
|
706
735
|
}
|
|
707
|
-
const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', '
|
|
736
|
+
const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'hostSettings', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'inheritEnv', 'requireExistingSession', 'disableSkills', 'approvalReach', 'allowTools', 'userInvokedSkills'];
|
|
708
737
|
const MATERIALIZE_AT_READ = Object.freeze({ allowTools: (v) => allowToolsSnapshot(v), userInvokedSkills: (v) => allowToolsSnapshot(v) });
|
|
709
738
|
function dataFirstSnapshot(input, afterData) {
|
|
710
739
|
let descs;
|
|
@@ -742,25 +771,28 @@ export function assembleTaskRequest(input, lane) {
|
|
|
742
771
|
let resolvedMaterialized;
|
|
743
772
|
let resolvedMaterializeError;
|
|
744
773
|
let resolvedHookRan = false;
|
|
774
|
+
let intakeEarly;
|
|
775
|
+
const materializeAtRead = (product) => (raw) => {
|
|
776
|
+
resolvedInEarly = raw;
|
|
777
|
+
try {
|
|
778
|
+
rethrowHostResolvedDeferred(product);
|
|
779
|
+
resolvedMaterialized = resolvedSnapshotForWire(resolvedInEarly);
|
|
780
|
+
}
|
|
781
|
+
catch (e) {
|
|
782
|
+
resolvedMaterializeError = e;
|
|
783
|
+
}
|
|
784
|
+
};
|
|
745
785
|
const src = dataFirstSnapshot(input, (bag) => {
|
|
746
786
|
if (!Object.hasOwn(bag, 'hostSettings'))
|
|
747
787
|
return;
|
|
748
788
|
const product = hostTurnSettingsOf(bag['hostSettings'], 'shape');
|
|
749
789
|
if (product !== undefined) {
|
|
750
790
|
resolvedHookRan = true;
|
|
751
|
-
|
|
752
|
-
try {
|
|
753
|
-
rethrowHostResolvedDeferred(product);
|
|
754
|
-
resolvedMaterialized = resolvedSnapshotForWire(resolvedInEarly);
|
|
755
|
-
}
|
|
756
|
-
catch (e) {
|
|
757
|
-
resolvedMaterializeError = e;
|
|
758
|
-
}
|
|
791
|
+
intakeEarly = hostIntakeSnapshotOf(product, materializeAtRead(product));
|
|
759
792
|
}
|
|
760
793
|
});
|
|
761
794
|
const live = src.live;
|
|
762
795
|
const memoryCaptureIn = src.memoryCapture;
|
|
763
|
-
const memoryIn = src.memory;
|
|
764
796
|
const settingsIn = src.settings;
|
|
765
797
|
if (present(settingsIn) && (typeof settingsIn !== 'object' || Array.isArray(settingsIn))) {
|
|
766
798
|
throw new TypeError(`buildTaskRequest: settings 只接受对象或缺席(undefined/null)—— 收到 ${coarseShape(settingsIn)}。` +
|
|
@@ -772,19 +804,19 @@ export function assembleTaskRequest(input, lane) {
|
|
|
772
804
|
if (host === undefined) {
|
|
773
805
|
throw new TypeError(renderMessage(msg('config.taskRequest.hostSettingsMalformed', { shape: coarseShape(hostIn) })));
|
|
774
806
|
}
|
|
775
|
-
const
|
|
807
|
+
const intake = resolvedHookRan ? intakeEarly : hostIntakeSnapshotOf(host, materializeAtRead(host));
|
|
808
|
+
if (intake === undefined)
|
|
809
|
+
throw new TypeError(renderMessage(msg('config.taskRequest.hostSettingsMalformed', { shape: coarseShape(hostIn) })));
|
|
810
|
+
const resolvedIn = resolvedInEarly;
|
|
776
811
|
const resolvedRoute = SETTINGS_KEY_ROUTES.resolved;
|
|
777
812
|
const resolvedOpen = resolvedRoute.via === 'matrix' && omissionCauseOf(standingOf(resolvedRoute), lane, live) === undefined;
|
|
778
|
-
if (resolvedOpen &&
|
|
813
|
+
if (resolvedOpen && resolvedMaterializeError !== undefined)
|
|
779
814
|
throw resolvedMaterializeError;
|
|
780
|
-
if (resolvedOpen && !resolvedHookRan)
|
|
781
|
-
rethrowHostResolvedDeferred(host);
|
|
782
815
|
const resolvedWire = resolvedOpen ? (resolvedMaterialized ?? resolvedSnapshotForWire(resolvedIn)) : {};
|
|
783
816
|
const maxCostUsdIn = src.maxCostUsd;
|
|
784
817
|
const excludeAllToolsIn = src.excludeAllTools;
|
|
785
818
|
const maxTokensIn = src.maxTokens;
|
|
786
819
|
const outputRetriesIn = src.outputRetries;
|
|
787
|
-
const fileHistoryIn = src.fileHistory;
|
|
788
820
|
const inheritEnvIn = src.inheritEnv;
|
|
789
821
|
const requireExistingSessionIn = src.requireExistingSession;
|
|
790
822
|
const disableSkillsIn = src.disableSkills;
|
|
@@ -794,12 +826,10 @@ export function assembleTaskRequest(input, lane) {
|
|
|
794
826
|
const i = snapshotByName(src, INPUT_KEYS, {
|
|
795
827
|
live,
|
|
796
828
|
memoryCapture: memoryCaptureIn,
|
|
797
|
-
memory: memoryIn,
|
|
798
829
|
maxCostUsd: maxCostUsdIn,
|
|
799
830
|
maxTokens: maxTokensIn,
|
|
800
831
|
excludeAllTools: excludeAllToolsIn,
|
|
801
832
|
outputRetries: outputRetriesIn,
|
|
802
|
-
fileHistory: fileHistoryIn,
|
|
803
833
|
inheritEnv: inheritEnvIn,
|
|
804
834
|
requireExistingSession: requireExistingSessionIn,
|
|
805
835
|
disableSkills: disableSkillsIn,
|
|
@@ -809,20 +839,19 @@ export function assembleTaskRequest(input, lane) {
|
|
|
809
839
|
});
|
|
810
840
|
const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
|
|
811
841
|
const hostSettingsKeysIn = HOST_SETTINGS_SUBKEYS.filter((k) => hasOwn(settingsObj, k) && present(Reflect.get(settingsObj, k)));
|
|
842
|
+
const hostTopKeysIn = HOST_TOP_KEYS.filter((k) => hasOwn(src, k) && present(Reflect.get(src, k)));
|
|
812
843
|
const s = {
|
|
813
844
|
resolved: resolvedIn,
|
|
814
|
-
webSearch:
|
|
845
|
+
webSearch: intake.carried.webSearch,
|
|
815
846
|
ultracode: snapshotByName(settingsObj, ['ultracode']).ultracode,
|
|
816
|
-
hooks:
|
|
817
|
-
outputStyle:
|
|
847
|
+
hooks: intake.carried.hooks,
|
|
848
|
+
outputStyle: intake.carried.outputStyle,
|
|
818
849
|
};
|
|
819
850
|
refuseBadMemoryCapture(memoryCaptureIn);
|
|
820
|
-
refuseBadMemoryOff(memoryIn);
|
|
821
851
|
refuseBadMaxCostUsd(maxCostUsdIn);
|
|
822
852
|
refuseBadExcludeAllTools(excludeAllToolsIn);
|
|
823
853
|
refuseBadMaxTokens(maxTokensIn);
|
|
824
854
|
refuseBadOutputRetries(outputRetriesIn);
|
|
825
|
-
refuseBadFileHistory(fileHistoryIn);
|
|
826
855
|
refuseBadInheritEnv(inheritEnvIn);
|
|
827
856
|
refuseBadRequireExistingSession(requireExistingSessionIn);
|
|
828
857
|
refuseBadDisableSkills(disableSkillsIn, 'buildTaskRequest');
|
|
@@ -856,6 +885,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
856
885
|
for (const key of Object.keys(src)) {
|
|
857
886
|
if (hasOwn(INPUT_KEY_ROUTES, key))
|
|
858
887
|
continue;
|
|
888
|
+
if (hasOwn(HOST_TOP_KEY_ROUTES, key))
|
|
889
|
+
continue;
|
|
859
890
|
const stray = Reflect.get(src, key);
|
|
860
891
|
if (!present(stray))
|
|
861
892
|
continue;
|
|
@@ -895,10 +926,10 @@ export function assembleTaskRequest(input, lane) {
|
|
|
895
926
|
'处置:删掉这个键;要在回退会话时一并还原文件,改交 ' +
|
|
896
927
|
'rewind.restoreFiles: true(必须与 rewind.resumeAt 同交);只还原文件、不动会话,交 rewind.rewindFilesTo。错误文本只报键名,不回显值。');
|
|
897
928
|
}
|
|
898
|
-
if (hostSettingsKeysIn.length > 0) {
|
|
929
|
+
if (hostSettingsKeysIn.length > 0 || hostTopKeysIn.length > 0) {
|
|
899
930
|
throw new TypeError(renderMessage(msg('config.taskRequest.hostSuppliedKeysByHand', {
|
|
900
|
-
keys: hostSettingsKeysIn.map((k) => `settings.${k}`).join(', '),
|
|
901
|
-
fields: hostSettingsKeysIn.map((k) => `${k}: …`).join(', '),
|
|
931
|
+
keys: [...hostSettingsKeysIn.map((k) => `settings.${k}`), ...hostTopKeysIn].join(', '),
|
|
932
|
+
fields: [...hostSettingsKeysIn, ...hostTopKeysIn].map((k) => `${k}: …`).join(', '),
|
|
902
933
|
})));
|
|
903
934
|
}
|
|
904
935
|
if (unknownKeys.length > 0) {
|
|
@@ -914,8 +945,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
914
945
|
refuseRequireExistingWithoutSession(requireExistingSessionIn, i.sessionId);
|
|
915
946
|
refuseDisableSkillsConflict(disableSkillsIn, i.skills, Reflect.get(src, 'agents'), 'buildTaskRequest');
|
|
916
947
|
refuseUtilityWithoutToolUnload(lane, excludeAllToolsIn);
|
|
917
|
-
if (
|
|
918
|
-
const refusing = hostRefusalNoticeOf(
|
|
948
|
+
if (intake.refuses) {
|
|
949
|
+
const refusing = hostRefusalNoticeOf(intake, lane, live);
|
|
919
950
|
if (refusing !== undefined)
|
|
920
951
|
throw new HostSettingsRefused(refusing);
|
|
921
952
|
}
|
|
@@ -933,15 +964,25 @@ export function assembleTaskRequest(input, lane) {
|
|
|
933
964
|
return false;
|
|
934
965
|
};
|
|
935
966
|
const gate = Object.create(null);
|
|
936
|
-
|
|
967
|
+
const askInput = (key) => {
|
|
937
968
|
const route = INPUT_KEY_ROUTES[key];
|
|
938
969
|
if (route.via === 'settings') {
|
|
939
970
|
for (const sub of SETTINGS_KEYS)
|
|
940
971
|
gate[`settings.${sub}`] = carries(SETTINGS_KEY_ROUTES[sub], s[sub], `settings.${sub}`);
|
|
941
|
-
|
|
972
|
+
return;
|
|
942
973
|
}
|
|
943
974
|
gate[key] = carries(route, key === 'rewind' ? rewindForGate : i[key], key);
|
|
944
|
-
}
|
|
975
|
+
};
|
|
976
|
+
const anchorAt = INPUT_KEYS.indexOf(HOST_TOP_ASK_AFTER);
|
|
977
|
+
const hostTopAt = anchorAt < 0 ? INPUT_KEYS.length : anchorAt + 1;
|
|
978
|
+
for (const key of INPUT_KEYS.slice(0, hostTopAt))
|
|
979
|
+
askInput(key);
|
|
980
|
+
const hostTopGate = {
|
|
981
|
+
memory: carries(HOST_TOP_KEY_ROUTES.memory, intake.carried.memory, 'memory'),
|
|
982
|
+
fileHistory: carries(HOST_TOP_KEY_ROUTES.fileHistory, intake.carried.fileHistory, 'fileHistory'),
|
|
983
|
+
};
|
|
984
|
+
for (const key of INPUT_KEYS.slice(hostTopAt))
|
|
985
|
+
askInput(key);
|
|
945
986
|
const on = (key) => gate[key] === true;
|
|
946
987
|
const onSetting = (sub) => gate[`settings.${sub}`] === true;
|
|
947
988
|
const settingsOut = {
|
|
@@ -989,8 +1030,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
989
1030
|
...(on('maxCostUsd') ? { maxCostUsd: maxCostUsdIn } : {}),
|
|
990
1031
|
...(on('maxTokens') ? { maxTokens: i.maxTokens } : {}),
|
|
991
1032
|
...(on('memoryCapture') ? { memoryCapture: 'off' } : {}),
|
|
992
|
-
...(
|
|
993
|
-
...(
|
|
1033
|
+
...(hostTopGate.memory ? { memory: 'off' } : {}),
|
|
1034
|
+
...(hostTopGate.fileHistory ? { fileHistory: FILE_HISTORY_DISABLED } : {}),
|
|
994
1035
|
...(on('inheritEnv') ? { inheritEnv: inheritEnvIn } : {}),
|
|
995
1036
|
...(on('requireExistingSession') ? { requireExistingSession: true } : {}),
|
|
996
1037
|
...(on('disableSkills') ? { disableSkills: true } : {}),
|
|
@@ -48,7 +48,7 @@ export interface ParkedResumeStartupDetail {
|
|
|
48
48
|
denyStaysOpen: true;
|
|
49
49
|
}
|
|
50
50
|
declare const RESUME_CAUSE_CORE_AHEAD: readonly ["transcript_corrupt"];
|
|
51
|
-
type ResumeCauseCoreAhead = (typeof RESUME_CAUSE_CORE_AHEAD)[number]
|
|
51
|
+
type ResumeCauseCoreAhead = Exclude<(typeof RESUME_CAUSE_CORE_AHEAD)[number], ResumeStartupCause>;
|
|
52
52
|
export declare function parkedResumeStartupFromError(err: unknown, decision?: ParkedResumeStartupDecision): ParkedResumeStartupDetail | null;
|
|
53
53
|
export declare function parkedResumeStartupContent(detail: ParkedResumeStartupDetail, lang?: UiLanguage): string;
|
|
54
54
|
export interface CheckpointUnsupportedVersionDetail {
|
|
@@ -69,6 +69,8 @@ export interface RefusedParkFacts {
|
|
|
69
69
|
readonly code: RefusedParkCode;
|
|
70
70
|
readonly field?: string;
|
|
71
71
|
readonly stillPending?: boolean;
|
|
72
|
+
readonly blockedBy?: string;
|
|
73
|
+
readonly reason?: string;
|
|
72
74
|
}
|
|
73
75
|
export declare function refusedParkFromError(failure: unknown): RefusedParkFacts | null;
|
|
74
76
|
export interface RefusedParkContentInput {
|
|
@@ -238,6 +238,7 @@ export function checkpointUnsupportedVersionContent(detail, ctx, lang) {
|
|
|
238
238
|
return renderMessage(msg('resume.refusal.checkpoint.content', { outlet }), lang);
|
|
239
239
|
}
|
|
240
240
|
const REFUSED_PARK_FIELD_TOKEN = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
|
|
241
|
+
const REFUSED_PARK_CODE_TOKEN = /^(?=.{1,128}$)[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)*$/;
|
|
241
242
|
export function refusedParkFromError(failure) {
|
|
242
243
|
if (typeof failure !== 'object' || failure === null)
|
|
243
244
|
return null;
|
|
@@ -258,10 +259,22 @@ export function refusedParkFromError(failure) {
|
|
|
258
259
|
const stillPending = reading === true ? true : status === 409 && reading === false ? false : undefined;
|
|
259
260
|
const rawField = code === CHECKPOINT_CONFIG_REFUSED ? readErrorString(failure, 'field') : undefined;
|
|
260
261
|
const field = rawField !== undefined && REFUSED_PARK_FIELD_TOKEN.test(rawField) ? rawField : undefined;
|
|
262
|
+
let blockedBy;
|
|
263
|
+
try {
|
|
264
|
+
const b = readBlockedBy(failure);
|
|
265
|
+
blockedBy = b.kind === 'named' && REFUSED_PARK_CODE_TOKEN.test(b.code) ? b.code : undefined;
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
blockedBy = undefined;
|
|
269
|
+
}
|
|
270
|
+
const rawReason = readErrorString(failure, 'reason');
|
|
271
|
+
const reason = rawReason !== undefined && REFUSED_PARK_FIELD_TOKEN.test(rawReason) ? rawReason : undefined;
|
|
261
272
|
return Object.freeze({
|
|
262
273
|
code,
|
|
263
274
|
...(field !== undefined ? { field } : {}),
|
|
264
275
|
...(stillPending !== undefined ? { stillPending } : {}),
|
|
276
|
+
...(blockedBy !== undefined ? { blockedBy } : {}),
|
|
277
|
+
...(reason !== undefined ? { reason } : {}),
|
|
265
278
|
});
|
|
266
279
|
}
|
|
267
280
|
function refusedParkShownRunId(runId) {
|
|
@@ -272,6 +285,8 @@ function refusedParkWhy(code, field) {
|
|
|
272
285
|
case CHECKPOINT_WALLTIME_AXIS_RETIRED:
|
|
273
286
|
return msg('resume.refusal.park.whyWalltime');
|
|
274
287
|
case CHECKPOINT_CONFIG_REFUSED:
|
|
288
|
+
if (field === 'deps')
|
|
289
|
+
return msg('resume.refusal.park.whyDeps');
|
|
275
290
|
return msg(field === 'inheritedGate' ? 'resume.refusal.park.whyInheritedGate' : 'resume.refusal.park.whyConfigRefused');
|
|
276
291
|
default:
|
|
277
292
|
return msg('resume.refusal.park.whyUnsupported');
|
|
@@ -284,6 +299,7 @@ export function refusedParkContent(input, lang) {
|
|
|
284
299
|
let rawCode;
|
|
285
300
|
let field;
|
|
286
301
|
let stillPending;
|
|
302
|
+
let blockedBy;
|
|
287
303
|
try {
|
|
288
304
|
what = input.what;
|
|
289
305
|
lane = input.lane;
|
|
@@ -297,21 +313,23 @@ export function refusedParkContent(input, lang) {
|
|
|
297
313
|
rawCode = facts.code;
|
|
298
314
|
field = facts.field;
|
|
299
315
|
stillPending = facts.stillPending;
|
|
316
|
+
blockedBy = facts.blockedBy;
|
|
300
317
|
}
|
|
301
318
|
catch {
|
|
302
|
-
rawCode = field = stillPending = undefined;
|
|
319
|
+
rawCode = field = stillPending = blockedBy = undefined;
|
|
303
320
|
}
|
|
304
321
|
const code = rawCode === CHECKPOINT_WALLTIME_AXIS_RETIRED || rawCode === CHECKPOINT_CONFIG_REFUSED ? rawCode : CHECKPOINT_UNSUPPORTED_VERSION;
|
|
305
322
|
const shownWhat = typeof what === 'string' && what !== '' ? capForDisplay(what, 40) : msg('resume.refusal.park.whatDefault');
|
|
306
323
|
const why = refusedParkWhy(code, typeof field === 'string' ? field : undefined);
|
|
307
324
|
const shownRun = refusedParkShownRunId(runId);
|
|
308
325
|
const head = msg('resume.refusal.park.head', { what: shownWhat, why });
|
|
309
|
-
const configMayReturn = code === CHECKPOINT_CONFIG_REFUSED && field !== 'inheritedGate' ? msg('resume.refusal.park.configMayReturn') : '';
|
|
326
|
+
const configMayReturn = code === CHECKPOINT_CONFIG_REFUSED && field !== 'inheritedGate' ? msg(field === 'deps' ? 'resume.refusal.park.depsMayReturn' : 'resume.refusal.park.configMayReturn') : '';
|
|
310
327
|
if (lane === 'print') {
|
|
328
|
+
const blocked = typeof blockedBy === 'string' && REFUSED_PARK_CODE_TOKEN.test(blockedBy) ? msg('resume.refusal.park.blockedByTail', { blockedBy }) : '';
|
|
311
329
|
if (stillPending === false)
|
|
312
|
-
return renderMessage(msg('resume.refusal.park.printEnded', { head, code }), lang);
|
|
330
|
+
return renderMessage(msg('resume.refusal.park.printEnded', { head, code, blocked }), lang);
|
|
313
331
|
const cancel = `POST /v1/runs/${shownRun ?? '<run id>'}/cancel`;
|
|
314
|
-
return renderMessage(msg('resume.refusal.park.printHolds', { head, configMayReturn, code, cancel }), lang);
|
|
332
|
+
return renderMessage(msg('resume.refusal.park.printHolds', { head, configMayReturn, code, cancel, blocked }), lang);
|
|
315
333
|
}
|
|
316
334
|
if (stillPending === false)
|
|
317
335
|
return renderMessage(msg('resume.refusal.park.interactiveEnded', { head }), lang);
|
package/dist/retryStatus.d.ts
CHANGED
|
@@ -93,6 +93,24 @@ export interface RetryStatusNotice {
|
|
|
93
93
|
readonly recourse?: 'switch_model' | 'wait' | 'fix_request';
|
|
94
94
|
readonly phase: 'retrying' | 'reconnecting' | 'waiting_first_token' | 'gave_up' | 'cleared';
|
|
95
95
|
}
|
|
96
|
+
export interface RetryStatusParts {
|
|
97
|
+
readonly phase: RetryStatusNotice['phase'];
|
|
98
|
+
readonly model?: string;
|
|
99
|
+
readonly condition?: string;
|
|
100
|
+
readonly resendNote?: string;
|
|
101
|
+
readonly httpStatus?: number;
|
|
102
|
+
readonly source?: string;
|
|
103
|
+
readonly attempt?: number;
|
|
104
|
+
readonly maxAttempts?: number;
|
|
105
|
+
readonly elapsedMs?: number;
|
|
106
|
+
readonly timeoutMs?: number;
|
|
107
|
+
readonly retryAtMs?: number;
|
|
108
|
+
readonly detail?: string;
|
|
109
|
+
readonly recourse?: RetryStatusNotice['recourse'];
|
|
110
|
+
}
|
|
111
|
+
export declare function retryStatusParts(status: RetryStatus | null, ctx?: {
|
|
112
|
+
readonly modelName?: string;
|
|
113
|
+
}): RetryStatusParts;
|
|
96
114
|
export declare function retryStatusNotice(status: RetryStatus | null, ctx?: {
|
|
97
115
|
readonly modelName?: string;
|
|
98
116
|
}): RetryStatusNotice;
|
package/dist/retryStatus.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
2
2
|
import { guardedRead, readOwnDataFiniteNumber, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
|
|
3
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
3
4
|
export const BRAIN_STATUS_PHASES = [
|
|
4
5
|
'rate_limited',
|
|
5
6
|
'retrying',
|
|
@@ -172,11 +173,38 @@ function noticeAttemptTail(attempt, maxRetries) {
|
|
|
172
173
|
function sealNotice(line, phase, recourse) {
|
|
173
174
|
return Object.freeze(recourse === undefined ? { line, phase } : { line, recourse, phase });
|
|
174
175
|
}
|
|
175
|
-
|
|
176
|
+
const SOURCE_PHRASES = Object.freeze({
|
|
177
|
+
unified_header: 'notice.retry.source.unifiedHeader',
|
|
178
|
+
provider_code: 'notice.retry.source.providerCode',
|
|
179
|
+
status: 'notice.retry.source.status',
|
|
180
|
+
});
|
|
181
|
+
function sourcePhraseOf(word) {
|
|
182
|
+
if (word === undefined || !Object.hasOwn(SOURCE_PHRASES, word))
|
|
183
|
+
return undefined;
|
|
184
|
+
return renderMessage(msg(SOURCE_PHRASES[word]));
|
|
185
|
+
}
|
|
186
|
+
function sealParts(p) {
|
|
187
|
+
return Object.freeze({
|
|
188
|
+
phase: p.phase,
|
|
189
|
+
...(p.model !== undefined ? { model: p.model } : {}),
|
|
190
|
+
...(p.condition !== undefined ? { condition: p.condition } : {}),
|
|
191
|
+
...(p.resendNote !== undefined ? { resendNote: p.resendNote } : {}),
|
|
192
|
+
...(p.httpStatus !== undefined ? { httpStatus: p.httpStatus } : {}),
|
|
193
|
+
...(p.source !== undefined ? { source: p.source } : {}),
|
|
194
|
+
...(p.attempt !== undefined ? { attempt: p.attempt } : {}),
|
|
195
|
+
...(p.maxAttempts !== undefined ? { maxAttempts: p.maxAttempts } : {}),
|
|
196
|
+
...(p.elapsedMs !== undefined ? { elapsedMs: p.elapsedMs } : {}),
|
|
197
|
+
...(p.timeoutMs !== undefined ? { timeoutMs: p.timeoutMs } : {}),
|
|
198
|
+
...(p.retryAtMs !== undefined ? { retryAtMs: p.retryAtMs } : {}),
|
|
199
|
+
...(p.detail !== undefined ? { detail: p.detail } : {}),
|
|
200
|
+
...(p.recourse !== undefined ? { recourse: p.recourse } : {}),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
export function retryStatusParts(status, ctx) {
|
|
176
204
|
const modelName = washedText(noticeText(ctx, 'modelName'))?.trim();
|
|
177
|
-
const
|
|
205
|
+
const model = modelName === undefined || modelName === '' ? undefined : modelName;
|
|
178
206
|
if (status === null)
|
|
179
|
-
return
|
|
207
|
+
return sealParts({ phase: 'cleared' });
|
|
180
208
|
const armWord = noticeText(status, 'kind');
|
|
181
209
|
const kind = armWord === 'stalled' || armWord === 'waiting' ? armWord : 'error';
|
|
182
210
|
if (kind === 'waiting') {
|
|
@@ -184,10 +212,8 @@ export function retryStatusNotice(status, ctx) {
|
|
|
184
212
|
const timeoutRaw = noticeNumber(status, 'timeoutMs');
|
|
185
213
|
const elapsed = elapsedRaw !== undefined && elapsedRaw >= 0 && elapsedRaw <= Number.MAX_SAFE_INTEGER ? elapsedRaw : undefined;
|
|
186
214
|
const ceiling = timeoutRaw !== undefined && timeoutRaw > 0 && timeoutRaw <= Number.MAX_SAFE_INTEGER ? timeoutRaw : undefined;
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
const text = `${prefix}Waiting for the model's first token${progress.length === 0 ? '' : ` — ${progress.join(', ')}`}${offerSwitch ? '; keep waiting or switch model' : ''}`;
|
|
190
|
-
return sealNotice(text, 'waiting_first_token', offerSwitch ? 'switch_model' : 'wait');
|
|
215
|
+
const offerSwitch = model !== undefined && elapsed !== undefined && ceiling !== undefined && elapsed >= ceiling * WAIT_SWITCH_FRACTION;
|
|
216
|
+
return sealParts({ phase: 'waiting_first_token', model, elapsedMs: elapsed, timeoutMs: ceiling, recourse: offerSwitch ? 'switch_model' : 'wait' });
|
|
191
217
|
}
|
|
192
218
|
const terminal = kind === 'error' && noticeValue(status, 'terminal') === true;
|
|
193
219
|
const reading = conditionReadingOf(noticeText(status, 'providerCondition'));
|
|
@@ -195,18 +221,9 @@ export function retryStatusNotice(status, ctx) {
|
|
|
195
221
|
const attempt = noticeCount(noticeNumber(status, 'attempt'));
|
|
196
222
|
const maxRetries = noticeCount(noticeNumber(status, 'maxRetries'));
|
|
197
223
|
const engineWords = kind === 'stalled' ? noticeText(status, 'detail') : noticeText(noticeValue(status, 'error'), 'formatted');
|
|
198
|
-
const httpPart = http === undefined ? '' : ` (HTTP ${http})`;
|
|
199
|
-
let first;
|
|
200
|
-
if (terminal) {
|
|
201
|
-
const after = attempt === undefined ? '' : ` after ${attempt} attempt${attempt === 1 ? '' : 's'}`;
|
|
202
|
-
const why = reading === undefined ? '' : `: ${reading.clause}${reading.resendNote === undefined ? '' : `, and ${reading.resendNote}`}`;
|
|
203
|
-
first = `Stopped${after}${why}${httpPart}`;
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
const head = reading !== undefined ? `${reading.clause.charAt(0).toUpperCase()}${reading.clause.slice(1)}` : http !== undefined || kind === 'error' ? 'Request failed' : 'Waiting for the API response';
|
|
207
|
-
first = `${head}${httpPart} — ${kind === 'stalled' ? 'will retry' : 'retrying'}${noticeAttemptTail(attempt, maxRetries)}`;
|
|
208
|
-
}
|
|
209
224
|
const note = washedText(engineWords);
|
|
225
|
+
const source = reading === undefined ? undefined : sourcePhraseOf(noticeText(status, 'providerConditionSource'));
|
|
226
|
+
const condition = reading === undefined ? undefined : `${reading.clause.charAt(0).toUpperCase()}${reading.clause.slice(1)}`;
|
|
210
227
|
const serviceSide = http !== undefined && (http === 429 || (http >= 500 && http <= 599));
|
|
211
228
|
const knownArm = armWord === 'stalled' || armWord === 'error';
|
|
212
229
|
const recourse = !knownArm
|
|
@@ -218,7 +235,47 @@ export function retryStatusNotice(status, ctx) {
|
|
|
218
235
|
: !terminal
|
|
219
236
|
? 'wait'
|
|
220
237
|
: undefined;
|
|
221
|
-
|
|
238
|
+
const deadlineRaw = knownArm && !terminal && noticeNumber(status, 'retryAtMs') !== undefined ? noticeNumber(status, 'deadline') : undefined;
|
|
239
|
+
const retryAtMs = deadlineRaw !== undefined && deadlineRaw > 0 ? deadlineRaw : undefined;
|
|
240
|
+
return sealParts({
|
|
241
|
+
phase: kind === 'stalled' ? 'reconnecting' : terminal ? 'gave_up' : 'retrying',
|
|
242
|
+
model,
|
|
243
|
+
condition,
|
|
244
|
+
resendNote: terminal ? reading?.resendNote : undefined,
|
|
245
|
+
httpStatus: http,
|
|
246
|
+
source,
|
|
247
|
+
attempt,
|
|
248
|
+
maxAttempts: maxRetries,
|
|
249
|
+
retryAtMs,
|
|
250
|
+
detail: note,
|
|
251
|
+
recourse,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
function retryLineOfParts(parts) {
|
|
255
|
+
if (parts.phase === 'cleared')
|
|
256
|
+
return '';
|
|
257
|
+
const prefix = parts.model === undefined ? '' : `${parts.model}: `;
|
|
258
|
+
if (parts.phase === 'waiting_first_token') {
|
|
259
|
+
const progress = [...(parts.elapsedMs === undefined ? [] : [`${spanText(parts.elapsedMs)} so far`]), ...(parts.timeoutMs === undefined ? [] : [`limit ${spanText(parts.timeoutMs)}`])];
|
|
260
|
+
const offerSwitch = parts.recourse === 'switch_model';
|
|
261
|
+
return `${prefix}Waiting for the model's first token${progress.length === 0 ? '' : ` — ${progress.join(', ')}`}${offerSwitch ? '; keep waiting or switch model' : ''}`;
|
|
262
|
+
}
|
|
263
|
+
const httpPart = parts.httpStatus === undefined ? '' : ` (HTTP ${parts.httpStatus})`;
|
|
264
|
+
let first;
|
|
265
|
+
if (parts.phase === 'gave_up') {
|
|
266
|
+
const after = parts.attempt === undefined ? '' : ` after ${parts.attempt} attempt${parts.attempt === 1 ? '' : 's'}`;
|
|
267
|
+
const why = parts.condition === undefined ? '' : `: ${parts.condition.charAt(0).toLowerCase()}${parts.condition.slice(1)}${parts.resendNote === undefined ? '' : `, and ${parts.resendNote}`}`;
|
|
268
|
+
first = `Stopped${after}${why}${httpPart}`;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
const head = parts.condition !== undefined ? parts.condition : parts.httpStatus !== undefined || parts.phase === 'retrying' ? 'Request failed' : 'Waiting for the API response';
|
|
272
|
+
first = `${head}${httpPart} — ${parts.phase === 'reconnecting' ? 'will retry' : 'retrying'}${noticeAttemptTail(parts.attempt, parts.maxAttempts)}`;
|
|
273
|
+
}
|
|
274
|
+
return `${prefix}${first}${parts.detail === undefined ? '' : ` · ${parts.detail}`}`;
|
|
275
|
+
}
|
|
276
|
+
export function retryStatusNotice(status, ctx) {
|
|
277
|
+
const parts = retryStatusParts(status, ctx);
|
|
278
|
+
return sealNotice(retryLineOfParts(parts), parts.phase, parts.recourse);
|
|
222
279
|
}
|
|
223
280
|
const API_ERROR_PROVIDER_TEXT_MAX = 200;
|
|
224
281
|
function isRecordObject(v) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
2
|
+
import type { PermissionsKeptRule } from './permissionsDeclaration.js';
|
|
3
|
+
export type RuleRefusalRow = Pick<PermissionsKeptRule, 'rule' | 'reason' | 'code' | 'message'>;
|
|
4
|
+
export declare function ruleRefusalSentence(rows: readonly RuleRefusalRow[], lang?: UiLanguage): string | undefined;
|