@sema-agent/client-core 0.98.0 → 0.99.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 +199 -0
- package/README.md +35 -22
- package/dist/adapt/arms.js +61 -20
- package/dist/adapt/panelTasks.d.ts +1 -1
- package/dist/adapt/panelTasks.js +2 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +4 -3
- package/dist/adapter/activeRunSelfHeal.js +162 -293
- package/dist/adapter/downstream/eventToSdkMessage.js +52 -4
- package/dist/adapter/runStream.js +52 -37
- package/dist/adapter/types.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
- package/dist/agentsWireCaps.d.ts +0 -3
- package/dist/agentsWireCaps.js +33 -24
- package/dist/cloudConfigWireCaps.d.ts +1 -1
- package/dist/cloudConfigWireCaps.js +26 -4
- package/dist/controlRouter.d.ts +4 -2
- package/dist/controlRouter.js +39 -51
- package/dist/coreValuePorts.d.ts +26 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/corruptSessionCopy.d.ts +2 -1
- package/dist/corruptSessionCopy.js +3 -3
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/detachWire.js +3 -2
- package/dist/devicesFace.d.ts +34 -0
- package/dist/devicesFace.js +90 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +3 -0
- package/dist/engineAgentPanelStore.d.ts +7 -0
- package/dist/engineAgentPanelStore.js +14 -0
- package/dist/engineCapReader.d.ts +2 -1
- package/dist/engineCapReader.js +7 -5
- package/dist/engineCapsCache.d.ts +8 -0
- package/dist/engineCapsCache.js +59 -6
- package/dist/engineCapsChange.d.ts +2 -0
- package/dist/engineCapsChange.js +9 -0
- package/dist/engineErrorCodes.d.ts +2 -1
- package/dist/engineErrorCodes.js +2 -7
- package/dist/engineRowRef.js +3 -0
- package/dist/engineSessionMessages.d.ts +1 -0
- package/dist/engineSessionMessages.js +7 -1
- package/dist/engineTargetSeat.d.ts +27 -0
- package/dist/engineTargetSeat.js +199 -0
- package/dist/engineWireFor.js +3 -8
- package/dist/env/uiLanguage.d.ts +2 -1
- package/dist/env/uiLanguage.js +3 -2
- package/dist/eventLeg.d.ts +8 -0
- package/dist/eventLeg.js +61 -41
- package/dist/fileHistoryCaptureCapability.d.ts +2 -1
- package/dist/fileHistoryCaptureCapability.js +12 -18
- package/dist/fileHistoryLegNotice.d.ts +2 -1
- package/dist/fileHistoryLegNotice.js +3 -3
- package/dist/frameBinding.d.ts +3 -0
- package/dist/frameBinding.js +12 -0
- package/dist/gateOutcome.js +16 -2
- package/dist/gateVocabulary.d.ts +8 -7
- package/dist/gateVocabulary.js +71 -73
- package/dist/generated/engineFactTables.d.ts +17 -1
- package/dist/generated/engineFactTables.js +29 -0
- package/dist/generated/engineNoticeTables.js +9 -3
- package/dist/generated/settingsSchemaFns.d.ts +6 -0
- package/dist/generated/settingsSchemaFns.js +57 -0
- package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
- package/dist/generated/settingsSchemaTables.d.ts +1 -0
- package/dist/generated/settingsSchemaTables.js +4 -0
- package/dist/generated/settingsSchemaTypes.d.ts +105 -0
- package/dist/generated/settingsSchemaTypes.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +2 -1
- package/dist/hitl/allowRuleShadow.js +17 -14
- package/dist/hitl/approvalCardReasons.d.ts +3 -2
- package/dist/hitl/approvalCardReasons.js +27 -28
- package/dist/hitl/approvalHolds.d.ts +3 -0
- package/dist/hitl/approvalHolds.js +73 -29
- package/dist/hitl/askClassPair.d.ts +1 -1
- package/dist/hitl/askClassPair.js +16 -0
- package/dist/hitl/askGateWire.js +2 -1
- package/dist/hitl/askSettlementLine.d.ts +14 -4
- package/dist/hitl/askSettlementLine.js +67 -47
- package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
- package/dist/hitl/automaticAnswerVerdict.js +8 -8
- package/dist/hitl/crashConvergedNotice.d.ts +5 -4
- package/dist/hitl/crashConvergedNotice.js +28 -41
- package/dist/hitl/frameRouter.js +7 -8
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +3 -3
- package/dist/hitl/persistedRulesWire.d.ts +6 -5
- package/dist/hitl/persistedRulesWire.js +55 -73
- package/dist/hitl/planReviewWire.d.ts +5 -0
- package/dist/hitl/planReviewWire.js +8 -0
- package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
- package/dist/hitl/sessionPolicyDeliverable.js +46 -3
- package/dist/hitl/sessionPolicyWire.d.ts +2 -1
- package/dist/hitl/sessionPolicyWire.js +23 -24
- package/dist/hitl/suspendedReopen.d.ts +2 -1
- package/dist/hitl/suspendedReopen.js +7 -10
- package/dist/hitl/toolApprovalWire.d.ts +17 -5
- package/dist/hitl/toolApprovalWire.js +79 -40
- package/dist/hooksWireCaps.js +145 -56
- package/dist/host.d.ts +21 -0
- package/dist/hostTurnSettings.d.ts +71 -0
- package/dist/hostTurnSettings.js +291 -0
- package/dist/humanTurn.d.ts +14 -1
- package/dist/humanTurn.js +100 -12
- package/dist/humanTurnRead.d.ts +2 -0
- package/dist/humanTurnRead.js +22 -1
- package/dist/i18n/messages.en.d.ts +582 -0
- package/dist/i18n/messages.en.js +582 -0
- package/dist/i18n/messages.zh.js +718 -1
- package/dist/index.d.ts +29 -13
- package/dist/index.js +18 -9
- package/dist/inheritEnvCapability.d.ts +3 -2
- package/dist/inheritEnvCapability.js +3 -3
- package/dist/inheritEnvWire.d.ts +3 -2
- package/dist/inheritEnvWire.js +12 -14
- package/dist/interactiveHalt.js +17 -6
- package/dist/liveModelCatalog.d.ts +2 -1
- package/dist/liveModelCatalog.js +14 -8
- package/dist/mcpPanel.d.ts +10 -1
- package/dist/mcpPanel.js +40 -13
- package/dist/mcpProbeCapability.d.ts +2 -1
- package/dist/mcpProbeCapability.js +7 -11
- package/dist/mcpProbeWire.d.ts +3 -1
- package/dist/mcpProbeWire.js +5 -0
- package/dist/mcpWireCaps.d.ts +34 -0
- package/dist/mcpWireCaps.js +117 -17
- package/dist/memoryEntriesWire.js +5 -10
- package/dist/model/onboardJudgement.d.ts +93 -0
- package/dist/model/onboardJudgement.js +415 -0
- package/dist/model/tierVocabulary.d.ts +2 -0
- package/dist/model/tierVocabulary.js +17 -5
- package/dist/modelCapabilityProbe.d.ts +64 -0
- package/dist/modelCapabilityProbe.js +600 -0
- package/dist/modelIdentityResolvability.d.ts +3 -0
- package/dist/modelIdentityResolvability.js +26 -17
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +34 -0
- package/dist/panelReduce.d.ts +6 -1
- package/dist/panelReduce.js +50 -3
- package/dist/permissionRuleIssue.js +2 -0
- package/dist/permissionRulesWriteCapability.d.ts +2 -1
- package/dist/permissionRulesWriteCapability.js +8 -6
- package/dist/pluginHooksWire.d.ts +46 -3
- package/dist/pluginHooksWire.js +217 -11
- package/dist/printModelStatus.d.ts +63 -0
- package/dist/printModelStatus.js +155 -0
- package/dist/request/taskRequest.d.ts +11 -5
- package/dist/request/taskRequest.js +112 -16
- package/dist/resumeRefusalCopy.d.ts +12 -9
- package/dist/resumeRefusalCopy.js +70 -143
- package/dist/retryStatus.d.ts +37 -0
- package/dist/retryStatus.js +79 -0
- package/dist/scenarioRefusal.d.ts +9 -0
- package/dist/scenarioRefusal.js +111 -0
- package/dist/seam.d.ts +25 -1
- package/dist/seam.js +10 -1
- package/dist/seatContract.d.ts +260 -10
- package/dist/seatContract.js +692 -19
- package/dist/selfOrchestrationDenial.js +7 -19
- package/dist/sessionIdSegment.d.ts +6 -0
- package/dist/sessionIdSegment.js +24 -0
- package/dist/sessionMemoryStatus.js +6 -11
- package/dist/sessionPolicyCapability.d.ts +2 -1
- package/dist/sessionPolicyCapability.js +8 -6
- package/dist/settingsHooksSalvage.d.ts +44 -0
- package/dist/settingsHooksSalvage.js +211 -0
- package/dist/skillToolListsCapability.d.ts +2 -1
- package/dist/skillToolListsCapability.js +8 -6
- package/dist/sseIdleTriage.js +3 -2
- package/dist/subagent/engineSubagentResume.js +15 -9
- package/dist/subagentContentStore.d.ts +3 -0
- package/dist/subagentContentStore.js +22 -0
- package/dist/toolHistoryMismatch.js +3 -2
- package/dist/toolRoster.d.ts +3 -2
- package/dist/toolRoster.js +21 -20
- package/dist/turnFailurePresentation.d.ts +12 -1
- package/dist/turnFailurePresentation.js +212 -15
- package/dist/usageAnalytics.js +6 -11
- package/dist/userAttachmentEnvelope.d.ts +1 -0
- package/dist/userAttachmentEnvelope.js +37 -7
- package/dist/userAttachmentSeat.d.ts +21 -0
- package/dist/userAttachmentSeat.js +75 -0
- package/dist/userInvokedSkillsCapability.d.ts +11 -1
- package/dist/userInvokedSkillsCapability.js +31 -7
- package/dist/wireErrorTriage.d.ts +7 -0
- package/dist/wireErrorTriage.js +23 -1
- package/dist/wireFailureShape.js +2 -1
- package/dist/wireRefusalCopy.d.ts +13 -1
- package/dist/wireRefusalCopy.js +24 -28
- package/dist/workflowsJournalCapability.d.ts +2 -1
- package/dist/workflowsJournalCapability.js +8 -6
- package/docs/INTEGRATION-CLIENTS.md +542 -30
- package/package.json +5 -5
package/dist/toolRoster.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
2
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
2
3
|
import { HANDS_REASON_NO_EXECUTION_ENV, projectHandsSection } from './handsSeam.js';
|
|
3
4
|
const str = (v) => typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
4
5
|
const strArr = (v) => Array.isArray(v) ? v.filter((x) => typeof x === 'string') : undefined;
|
|
@@ -144,55 +145,55 @@ export function handsSeamReadingOf(view) {
|
|
|
144
145
|
return { kind: 'mounted' };
|
|
145
146
|
return seam.reason !== undefined ? { kind: 'not_mounted', reason: seam.reason } : { kind: 'not_mounted' };
|
|
146
147
|
}
|
|
147
|
-
const HANDS_NONE_STEM = 'this leg of the run was assembled with NO built-in file-and-shell tools';
|
|
148
|
-
const HANDS_NONE_TAIL = "so on this leg the model had no tool of the engine's own for editing files or running commands (tools mounted by other conditions, such as external servers, and sub-runs delegated to other legs are not covered by this reading)";
|
|
149
148
|
const HANDS_REASON_DISPLAY_MAX = 64;
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
function handsNotReported(lang) {
|
|
150
|
+
return renderMessage(msg('notice.capability.hands.notReported'), lang);
|
|
151
|
+
}
|
|
152
|
+
export function handsSeamDetail(reading, lang) {
|
|
152
153
|
const kind = typeof reading === 'object' && reading !== null ? reading.kind : undefined;
|
|
153
154
|
switch (kind) {
|
|
154
155
|
case 'mounted':
|
|
155
|
-
return '
|
|
156
|
+
return renderMessage(msg('notice.capability.hands.seamMounted'), lang);
|
|
156
157
|
case 'not_mounted': {
|
|
157
158
|
const raw = reading.reason;
|
|
158
159
|
const reason = typeof raw === 'string' && raw.length > 0 ? raw : undefined;
|
|
159
160
|
const why = reason === undefined
|
|
160
|
-
? '
|
|
161
|
+
? msg('notice.capability.hands.whyNoReason')
|
|
161
162
|
: reason === HANDS_REASON_NO_EXECUTION_ENV
|
|
162
|
-
? '
|
|
163
|
-
:
|
|
164
|
-
return
|
|
163
|
+
? msg('notice.capability.hands.whyNoExecutionEnv')
|
|
164
|
+
: msg('notice.capability.hands.whyUnknownReason', { reason: displayUntrusted(reason, { max: HANDS_REASON_DISPLAY_MAX }) });
|
|
165
|
+
return renderMessage(msg('notice.capability.hands.noneLine', { stem: msg('notice.capability.hands.noneStem'), why, tail: msg('notice.capability.hands.noneTail') }), lang);
|
|
165
166
|
}
|
|
166
167
|
default:
|
|
167
|
-
return
|
|
168
|
+
return handsNotReported(lang);
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
|
-
export function handsMountedDetail(reading) {
|
|
171
|
+
export function handsMountedDetail(reading, lang) {
|
|
171
172
|
const r = reading;
|
|
172
173
|
const kind = typeof r === 'object' && r !== null ? r.kind : undefined;
|
|
173
174
|
switch (kind) {
|
|
174
175
|
case 'mounted': {
|
|
175
176
|
const rows = r.rows;
|
|
176
177
|
if (typeof rows === 'number' && Number.isInteger(rows) && rows > 0)
|
|
177
|
-
return
|
|
178
|
-
return
|
|
178
|
+
return renderMessage(msg('notice.capability.hands.rosterMounted', { rows }), lang);
|
|
179
|
+
return handsNotReported(lang);
|
|
179
180
|
}
|
|
180
181
|
case 'not-mounted':
|
|
181
|
-
return
|
|
182
|
+
return renderMessage(msg('notice.capability.hands.rosterNotMounted', { stem: msg('notice.capability.hands.noneStem'), tail: msg('notice.capability.hands.noneTail') }), lang);
|
|
182
183
|
case 'unknown':
|
|
183
184
|
switch (r.why) {
|
|
184
185
|
case 'no-manifest':
|
|
185
|
-
return '
|
|
186
|
+
return renderMessage(msg('notice.capability.hands.unknownNoManifest'), lang);
|
|
186
187
|
case 'no-roster':
|
|
187
|
-
return '
|
|
188
|
+
return renderMessage(msg('notice.capability.hands.unknownNoRoster'), lang);
|
|
188
189
|
case 'roster-unreadable':
|
|
189
|
-
return '
|
|
190
|
+
return renderMessage(msg('notice.capability.hands.unknownRosterUnreadable'), lang);
|
|
190
191
|
case 'mount-condition-absent':
|
|
191
|
-
return '
|
|
192
|
+
return renderMessage(msg('notice.capability.hands.unknownMountConditionAbsent'), lang);
|
|
192
193
|
}
|
|
193
|
-
return
|
|
194
|
+
return handsNotReported(lang);
|
|
194
195
|
}
|
|
195
|
-
return
|
|
196
|
+
return handsNotReported(lang);
|
|
196
197
|
}
|
|
197
198
|
export function toolRosterNames(roster) {
|
|
198
199
|
return roster?.entries.map((e) => e.name) ?? [];
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
1
2
|
import { type TurnWireErrorVerdict } from './wireErrorTriage.js';
|
|
3
|
+
import { type LiveModelCatalog } from './liveModelCatalog.js';
|
|
4
|
+
import type { TaskRequestLike } from './request/taskRequest.js';
|
|
2
5
|
export type TurnFailureCategory = 'auth' | 'billing' | 'rate_limited' | 'invalid_request' | 'capability_unavailable' | 'timeout' | 'server_error' | 'connection_lost' | 'parked' | 'internal';
|
|
3
6
|
export declare const TURN_FAILURE_CATEGORIES: readonly TurnFailureCategory[];
|
|
4
7
|
export interface TurnFailureRetry {
|
|
@@ -15,11 +18,19 @@ export interface TurnFailurePresentation {
|
|
|
15
18
|
readonly name?: string;
|
|
16
19
|
readonly retry: TurnFailureRetry;
|
|
17
20
|
readonly waitSec?: number;
|
|
21
|
+
readonly notes: readonly string[];
|
|
22
|
+
readonly waitNote?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface TurnFailureNotesContext {
|
|
25
|
+
readonly requestedScenario?: string;
|
|
26
|
+
readonly sentRequest?: TaskRequestLike;
|
|
27
|
+
readonly modelCatalog?: LiveModelCatalog | null;
|
|
28
|
+
readonly nowMs?: number;
|
|
18
29
|
}
|
|
19
30
|
export declare function turnFailurePresentation(err: {} | null | undefined, evidence?: {
|
|
20
31
|
readonly bound?: boolean;
|
|
21
32
|
readonly reopened?: boolean;
|
|
22
|
-
}): TurnFailurePresentation;
|
|
33
|
+
}, notesCtx?: TurnFailureNotesContext, lang?: UiLanguage): TurnFailurePresentation;
|
|
23
34
|
export type SeatTurnFailure = Pick<TurnFailurePresentation, 'category' | 'retry' | 'waitSec' | 'headline' | 'errorCode'>;
|
|
24
35
|
export declare function seatTurnFailureOf(err: {} | null | undefined, evidence?: {
|
|
25
36
|
readonly bound?: boolean;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
1
2
|
import { classifyTurnWireError, effectiveWireErrorCode, isPreStreamDrainingReject } from './wireErrorTriage.js';
|
|
2
3
|
import { isSseIdleError } from './sseIdleTriage.js';
|
|
3
4
|
import { isCodeClassifiedGateFailure } from './gateFailureCodes.js';
|
|
4
5
|
import { CORRUPT_ROW_ERROR_CODE, CORRUPT_SESSION_ERROR_CODE, MEMORY_CONTROL_PLANE_CORRUPT, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE } from './engineErrorCodes.js';
|
|
5
|
-
import { toolDeclarationRefusalFromError } from './wireRefusalCopy.js';
|
|
6
|
+
import { bodyShapeRefusalFromError, bodyShapeRefusalTouchesSettings, fleetLeaseUnavailableContent, fleetLeaseUnavailableFromError, hostPostureRefusalContent, hostPostureRefusalFromError, settingsPermissionBucketRefusalContent, settingsPermissionBucketRefusalFromError, toolDeclarationRefusalContent, toolDeclarationRefusalFromError, usageWindowExhaustedContent, usageWindowExhaustedFromError, } from './wireRefusalCopy.js';
|
|
6
7
|
import { THROWN_SLOT_UNREADABLE, readErrorNumber, readThrownSlot, wireFailureTextsOf } from './wireFailureShape.js';
|
|
7
8
|
import { provablyNotSent } from './engineWireFor.js';
|
|
9
|
+
import { corruptStoredRowContent, scenarioDenyFromError, scenarioNotAllowedContent } from './wireErrorTriage.js';
|
|
10
|
+
import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, requireExistingSessionRefusalContent, requireExistingSessionRefusalFromError, resumeContextUnavailableContent, resumeContextUnavailableFromError, resumePolicyBlockContent, resumePolicyBlockFromError, resumeRefusalContent, resumeRefusalFromError, } from './resumeRefusalCopy.js';
|
|
11
|
+
import { resumeReopenContent, resumeReopenFromError } from './hitl/suspendedReopen.js';
|
|
12
|
+
import { isCorruptSessionError } from './corruptSession.js';
|
|
13
|
+
import { corruptSessionContent } from './corruptSessionCopy.js';
|
|
14
|
+
import { inheritEnvRefusalContent, inheritEnvRefusalFromError } from './inheritEnvWire.js';
|
|
15
|
+
import { modelCandidateRejectedContent, modelCandidateRejectedOf } from './liveModelCatalog.js';
|
|
8
16
|
const CATEGORY_TABLE = Object.freeze({
|
|
9
17
|
auth: true,
|
|
10
18
|
billing: true,
|
|
@@ -18,12 +26,12 @@ const CATEGORY_TABLE = Object.freeze({
|
|
|
18
26
|
internal: true,
|
|
19
27
|
});
|
|
20
28
|
export const TURN_FAILURE_CATEGORIES = Object.freeze(Object.keys(CATEGORY_TABLE));
|
|
21
|
-
const
|
|
22
|
-
connection_lost_not_sent: '
|
|
23
|
-
connection_lost: '
|
|
24
|
-
timeout: '
|
|
25
|
-
parked: '
|
|
26
|
-
internal: '
|
|
29
|
+
const TURN_FAILURE_HEADLINE_KEYS = Object.freeze({
|
|
30
|
+
connection_lost_not_sent: 'notice.failure.headline.connectionLostNotSent',
|
|
31
|
+
connection_lost: 'notice.failure.headline.connectionLost',
|
|
32
|
+
timeout: 'notice.failure.headline.timeout',
|
|
33
|
+
parked: 'notice.failure.headline.parked',
|
|
34
|
+
internal: 'notice.failure.headline.internal',
|
|
27
35
|
});
|
|
28
36
|
function waitSecOf(err) {
|
|
29
37
|
const ms = readThrownSlot(err, 'retryAfterMs', 'data');
|
|
@@ -88,43 +96,43 @@ function connectionLostBeforeSend(err, evidence) {
|
|
|
88
96
|
return false;
|
|
89
97
|
return typeof err === 'object' && err !== null && provablyNotSent(err);
|
|
90
98
|
}
|
|
91
|
-
export function turnFailurePresentation(err, evidence) {
|
|
99
|
+
export function turnFailurePresentation(err, evidence, notesCtx, lang) {
|
|
92
100
|
const verdict = classifyTurnWireError(err);
|
|
93
101
|
let shape;
|
|
94
|
-
let
|
|
102
|
+
let headlineKey;
|
|
95
103
|
let detail;
|
|
96
104
|
let name;
|
|
97
105
|
if (verdict.kind === 'http') {
|
|
98
106
|
shape = httpShapeOf(err, verdict);
|
|
99
107
|
detail = verdict.message;
|
|
100
108
|
if (shape.category === 'internal')
|
|
101
|
-
|
|
109
|
+
headlineKey = TURN_FAILURE_HEADLINE_KEYS.internal;
|
|
102
110
|
}
|
|
103
111
|
else if (verdict.kind === 'stream-ended-without-terminal') {
|
|
104
112
|
shape = { category: 'parked', offer: false };
|
|
105
|
-
|
|
113
|
+
headlineKey = TURN_FAILURE_HEADLINE_KEYS.parked;
|
|
106
114
|
detail = wireFailureTextsOf(err).reason;
|
|
107
115
|
}
|
|
108
116
|
else if (verdict.kind === 'transport') {
|
|
109
117
|
const notSent = connectionLostBeforeSend(err, evidence);
|
|
110
118
|
shape = { category: 'connection_lost', offer: notSent };
|
|
111
|
-
|
|
119
|
+
headlineKey = notSent ? TURN_FAILURE_HEADLINE_KEYS.connection_lost_not_sent : TURN_FAILURE_HEADLINE_KEYS.connection_lost;
|
|
112
120
|
detail = verdict.detail;
|
|
113
121
|
}
|
|
114
122
|
else if (isIdleWatchdog(err)) {
|
|
115
123
|
shape = { category: 'timeout', offer: true };
|
|
116
|
-
|
|
124
|
+
headlineKey = TURN_FAILURE_HEADLINE_KEYS.timeout;
|
|
117
125
|
detail = verdict.detail;
|
|
118
126
|
}
|
|
119
127
|
else if (BROWSER_FETCH_FAILURE.test(verdict.detail)) {
|
|
120
128
|
const notSent = connectionLostBeforeSend(err, evidence);
|
|
121
129
|
shape = { category: 'connection_lost', offer: notSent };
|
|
122
|
-
|
|
130
|
+
headlineKey = notSent ? TURN_FAILURE_HEADLINE_KEYS.connection_lost_not_sent : TURN_FAILURE_HEADLINE_KEYS.connection_lost;
|
|
123
131
|
detail = verdict.detail;
|
|
124
132
|
}
|
|
125
133
|
else {
|
|
126
134
|
shape = { category: 'internal', offer: false };
|
|
127
|
-
|
|
135
|
+
headlineKey = TURN_FAILURE_HEADLINE_KEYS.internal;
|
|
128
136
|
detail = verdict.detail;
|
|
129
137
|
name = verdict.name;
|
|
130
138
|
}
|
|
@@ -133,6 +141,8 @@ export function turnFailurePresentation(err, evidence) {
|
|
|
133
141
|
const wireRetriable = readThrownSlot(err, 'retriable', 'data') === true && !isCodeClassifiedGateFailure(errorCode, true);
|
|
134
142
|
const retry = wireRetriable && shape.category !== 'parked' ? { offer: true, basis: 'wire' } : { offer: shape.offer, basis: 'category' };
|
|
135
143
|
const waitSec = waitSecOf(err);
|
|
144
|
+
const chain = turnFailureNotesOf(err, verdict, notesCtx, waitSec, lang);
|
|
145
|
+
const headline = headlineKey !== undefined ? renderMessage(msg(headlineKey), lang) : undefined;
|
|
136
146
|
return Object.freeze({
|
|
137
147
|
category: shape.category,
|
|
138
148
|
kind: verdict.kind,
|
|
@@ -143,8 +153,195 @@ export function turnFailurePresentation(err, evidence) {
|
|
|
143
153
|
...(name !== undefined ? { name } : {}),
|
|
144
154
|
retry: Object.freeze(retry),
|
|
145
155
|
...(waitSec !== undefined ? { waitSec } : {}),
|
|
156
|
+
notes: chain.notes,
|
|
157
|
+
...(chain.waitNote !== undefined ? { waitNote: chain.waitNote } : {}),
|
|
146
158
|
});
|
|
147
159
|
}
|
|
160
|
+
function quotaDetailOf(err) {
|
|
161
|
+
if (readThrownSlot(err, 'status', 'data') !== 429 || readThrownSlot(err, 'errorCode', 'data') !== 'quota_exhausted')
|
|
162
|
+
return null;
|
|
163
|
+
const detail = readThrownSlot(err, 'detail', 'data');
|
|
164
|
+
const slot = (key) => (typeof detail === 'object' && detail !== null ? readThrownSlot(detail, key, 'data') : undefined);
|
|
165
|
+
const windowType = slot('windowType');
|
|
166
|
+
const remaining = slot('remaining');
|
|
167
|
+
const resetAt = slot('resetAt');
|
|
168
|
+
const isEstimate = slot('isEstimate');
|
|
169
|
+
const pool = slot('pool');
|
|
170
|
+
return {
|
|
171
|
+
...(windowType === 'fiveHour' || windowType === 'weekly' || windowType === 'budget' ? { windowType } : {}),
|
|
172
|
+
...(typeof remaining === 'number' && Number.isFinite(remaining) ? { remaining } : {}),
|
|
173
|
+
...(typeof resetAt === 'string' || resetAt === null ? { resetAt } : {}),
|
|
174
|
+
...(typeof isEstimate === 'boolean' ? { isEstimate } : {}),
|
|
175
|
+
...(typeof pool === 'string' && pool.length > 0 ? { pool } : {}),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const MONTH_KEYS = [
|
|
179
|
+
'notice.failure.month.jan',
|
|
180
|
+
'notice.failure.month.feb',
|
|
181
|
+
'notice.failure.month.mar',
|
|
182
|
+
'notice.failure.month.apr',
|
|
183
|
+
'notice.failure.month.may',
|
|
184
|
+
'notice.failure.month.jun',
|
|
185
|
+
'notice.failure.month.jul',
|
|
186
|
+
'notice.failure.month.aug',
|
|
187
|
+
'notice.failure.month.sep',
|
|
188
|
+
'notice.failure.month.oct',
|
|
189
|
+
'notice.failure.month.nov',
|
|
190
|
+
'notice.failure.month.dec',
|
|
191
|
+
];
|
|
192
|
+
function quotaResetInstant(resetAtIso, nowMs, lang) {
|
|
193
|
+
const t = Date.parse(resetAtIso);
|
|
194
|
+
if (!Number.isFinite(t))
|
|
195
|
+
return undefined;
|
|
196
|
+
const d = new Date(t);
|
|
197
|
+
const now = new Date(nowMs);
|
|
198
|
+
const hm = `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
|
|
199
|
+
const sameDay = d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth() && d.getDate() === now.getDate();
|
|
200
|
+
if (sameDay)
|
|
201
|
+
return hm;
|
|
202
|
+
const monthKey = MONTH_KEYS[d.getMonth()];
|
|
203
|
+
return renderMessage(msg('notice.failure.quota.instantOtherDay', { month: monthKey === undefined ? '' : msg(monthKey), day: d.getDate(), time: hm }), lang);
|
|
204
|
+
}
|
|
205
|
+
function quotaExhaustedLine(detail, nowMs, lang) {
|
|
206
|
+
const part = (key, params) => renderMessage(msg(key, params), lang);
|
|
207
|
+
const parts = [];
|
|
208
|
+
if (detail.windowType === 'fiveHour')
|
|
209
|
+
parts.push(part('notice.failure.quota.fiveHour'));
|
|
210
|
+
else if (detail.windowType === 'weekly')
|
|
211
|
+
parts.push(part('notice.failure.quota.weekly'));
|
|
212
|
+
else if (detail.windowType === 'budget') {
|
|
213
|
+
if (detail.pool === 'personal')
|
|
214
|
+
parts.push(part('notice.failure.quota.budgetPersonal'));
|
|
215
|
+
else if (detail.pool)
|
|
216
|
+
parts.push(part('notice.failure.quota.budgetPool', { pool: detail.pool }));
|
|
217
|
+
else
|
|
218
|
+
parts.push(part('notice.failure.quota.budget'));
|
|
219
|
+
}
|
|
220
|
+
else
|
|
221
|
+
parts.push(part('notice.failure.quota.usage'));
|
|
222
|
+
if (typeof detail.remaining === 'number' && Number.isFinite(detail.remaining)) {
|
|
223
|
+
parts.push(detail.windowType === 'budget'
|
|
224
|
+
? part('notice.failure.quota.remainingBudget', { amount: `$${(detail.remaining / 1_000_000).toFixed(2)}` })
|
|
225
|
+
: part('notice.failure.quota.remainingTokens', { count: detail.remaining.toLocaleString('en-US') }));
|
|
226
|
+
}
|
|
227
|
+
const resetText = typeof detail.resetAt === 'string' ? quotaResetInstant(detail.resetAt, nowMs, lang) : undefined;
|
|
228
|
+
if (resetText)
|
|
229
|
+
parts.push(detail.isEstimate === false ? part('notice.failure.quota.resetAt', { time: resetText }) : part('notice.failure.quota.resetAround', { time: resetText }));
|
|
230
|
+
parts.push(part('notice.failure.quota.refresh'));
|
|
231
|
+
parts.push(part('notice.failure.quota.noBypass'));
|
|
232
|
+
return parts.join(part('notice.failure.quota.join'));
|
|
233
|
+
}
|
|
234
|
+
function protectiveSettingsAtRisk(sent, lang) {
|
|
235
|
+
const out = [];
|
|
236
|
+
const permsRaw = sent.permissions;
|
|
237
|
+
const perms = typeof permsRaw === 'object' && permsRaw !== null ? permsRaw : {};
|
|
238
|
+
const deny = Array.isArray(perms.deny) ? perms.deny.length : 0;
|
|
239
|
+
const ask = Array.isArray(perms.ask) ? perms.ask.length : 0;
|
|
240
|
+
if (deny > 0)
|
|
241
|
+
out.push(renderMessage(msg(deny === 1 ? 'notice.failure.settings.denyRules.one' : 'notice.failure.settings.denyRules.other', { count: deny }), lang));
|
|
242
|
+
if (ask > 0)
|
|
243
|
+
out.push(renderMessage(msg(ask === 1 ? 'notice.failure.settings.askRules.one' : 'notice.failure.settings.askRules.other', { count: ask }), lang));
|
|
244
|
+
if (perms.disableBypassPermissionsMode !== undefined)
|
|
245
|
+
out.push('permissions.disableBypassPermissionsMode');
|
|
246
|
+
if (perms.disableAutoMode !== undefined)
|
|
247
|
+
out.push('permissions.disableAutoMode');
|
|
248
|
+
if (typeof perms.defaultMode === 'string')
|
|
249
|
+
out.push('permissions.defaultMode');
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
function settingsBodyShapeNote(err, sentRequest, lang) {
|
|
253
|
+
if (readThrownSlot(err, 'status', 'data') !== 400 || readThrownSlot(err, 'errorCode', 'data') !== 'request.body_shape')
|
|
254
|
+
return undefined;
|
|
255
|
+
const touches = bodyShapeRefusalTouchesSettings(bodyShapeRefusalFromError(err), sentRequest);
|
|
256
|
+
if (touches === false)
|
|
257
|
+
return undefined;
|
|
258
|
+
const rawSettings = sentRequest === undefined ? undefined : readThrownSlot(sentRequest, 'settings', 'data');
|
|
259
|
+
if (typeof rawSettings !== 'object' || rawSettings === null || Array.isArray(rawSettings))
|
|
260
|
+
return undefined;
|
|
261
|
+
const sentSettings = rawSettings;
|
|
262
|
+
if (Object.keys(sentSettings).length === 0)
|
|
263
|
+
return undefined;
|
|
264
|
+
const lines = [renderMessage(msg('notice.failure.settings.lead'), lang)];
|
|
265
|
+
const atRisk = protectiveSettingsAtRisk(sentSettings, lang);
|
|
266
|
+
if (atRisk.length > 0) {
|
|
267
|
+
lines.push(renderMessage(msg('notice.failure.settings.safety', { risks: atRisk.join(renderMessage(msg('notice.failure.settings.riskJoin'), lang)) }), lang));
|
|
268
|
+
lines.push(renderMessage(msg('notice.failure.settings.stillLocal'), lang));
|
|
269
|
+
}
|
|
270
|
+
return lines.join('\n');
|
|
271
|
+
}
|
|
272
|
+
function isRefusedRequest(err) {
|
|
273
|
+
const status = readThrownSlot(err, 'status', 'data');
|
|
274
|
+
return typeof status === 'number' && status >= 400 && status < 500;
|
|
275
|
+
}
|
|
276
|
+
function waitSentence(sec, lang) {
|
|
277
|
+
return renderMessage(sec === 1 ? msg('notice.failure.wait.one') : msg('notice.failure.wait.other', { seconds: sec }), lang);
|
|
278
|
+
}
|
|
279
|
+
function turnFailureNotesOf(err, verdict, ctx, waitSec, lang) {
|
|
280
|
+
const lines = [];
|
|
281
|
+
try {
|
|
282
|
+
const sentRequest = ctx === undefined ? undefined : ctx.sentRequest;
|
|
283
|
+
const nowMs = ctx !== undefined && typeof ctx.nowMs === 'number' && Number.isFinite(ctx.nowMs) ? ctx.nowMs : Date.now();
|
|
284
|
+
const quota = quotaDetailOf(err);
|
|
285
|
+
if (quota)
|
|
286
|
+
lines.push(quotaExhaustedLine(quota, nowMs, lang));
|
|
287
|
+
const scenarioDeny = quota ? null : scenarioDenyFromError(err);
|
|
288
|
+
if (scenarioDeny)
|
|
289
|
+
lines.push(scenarioNotAllowedContent(scenarioDeny, ctx?.requestedScenario));
|
|
290
|
+
const resumeRefusal = quota || scenarioDeny ? null : resumeRefusalFromError(err);
|
|
291
|
+
if (resumeRefusal)
|
|
292
|
+
lines.push(resumeRefusalContent(resumeRefusal, lang));
|
|
293
|
+
const requireExisting = quota || scenarioDeny || resumeRefusal ? null : requireExistingSessionRefusalFromError(err);
|
|
294
|
+
if (requireExisting)
|
|
295
|
+
lines.push(requireExistingSessionRefusalContent(requireExisting, lang));
|
|
296
|
+
const resumeReopen = quota || scenarioDeny || resumeRefusal || requireExisting ? null : resumeReopenFromError(err);
|
|
297
|
+
if (resumeReopen)
|
|
298
|
+
lines.push(resumeReopenContent(resumeReopen, lang));
|
|
299
|
+
const resumeGone = quota || scenarioDeny || resumeRefusal || requireExisting || resumeReopen ? null : resumeContextUnavailableFromError(err);
|
|
300
|
+
if (resumeGone)
|
|
301
|
+
lines.push(resumeContextUnavailableContent(resumeGone, lang));
|
|
302
|
+
const checkpointUnsupported = quota || scenarioDeny || resumeRefusal || requireExisting || resumeReopen || resumeGone ? null : checkpointUnsupportedVersionFromError(err);
|
|
303
|
+
if (checkpointUnsupported)
|
|
304
|
+
lines.push(checkpointUnsupportedVersionContent(checkpointUnsupported, undefined, lang));
|
|
305
|
+
const storedRowWhere = quota || scenarioDeny || resumeRefusal || resumeReopen || resumeGone ? undefined : verdict.kind === 'http' ? verdict.storedRowWhere : undefined;
|
|
306
|
+
if (storedRowWhere !== undefined)
|
|
307
|
+
lines.push(corruptStoredRowContent(storedRowWhere));
|
|
308
|
+
if (storedRowWhere === undefined && isCorruptSessionError(err))
|
|
309
|
+
lines.push(corruptSessionContent(lang));
|
|
310
|
+
const usageWindow = quota || scenarioDeny || resumeRefusal || resumeReopen || resumeGone ? null : usageWindowExhaustedFromError(err);
|
|
311
|
+
if (usageWindow)
|
|
312
|
+
lines.push(usageWindowExhaustedContent(usageWindow));
|
|
313
|
+
const hostPosture = quota || scenarioDeny || resumeRefusal || resumeReopen || resumeGone || storedRowWhere !== undefined ? null : hostPostureRefusalFromError(err, sentRequest);
|
|
314
|
+
if (hostPosture)
|
|
315
|
+
lines.push(hostPostureRefusalContent(hostPosture));
|
|
316
|
+
const inheritEnv = hostPosture ? null : inheritEnvRefusalFromError(err, sentRequest);
|
|
317
|
+
if (inheritEnv)
|
|
318
|
+
lines.push(inheritEnvRefusalContent(inheritEnv, lang));
|
|
319
|
+
const bucket = inheritEnv ? null : settingsPermissionBucketRefusalFromError(err);
|
|
320
|
+
const toolDecl = toolDeclarationRefusalFromError(err);
|
|
321
|
+
if (toolDecl)
|
|
322
|
+
lines.push(toolDeclarationRefusalContent(toolDecl));
|
|
323
|
+
const lease = fleetLeaseUnavailableFromError(err);
|
|
324
|
+
if (lease)
|
|
325
|
+
lines.push(fleetLeaseUnavailableContent(lease));
|
|
326
|
+
const policyBlock = quota || scenarioDeny || resumeRefusal || resumeReopen || resumeGone || usageWindow || hostPosture ? null : resumePolicyBlockFromError(err);
|
|
327
|
+
if (policyBlock)
|
|
328
|
+
lines.push(resumePolicyBlockContent(policyBlock, lang));
|
|
329
|
+
if (bucket)
|
|
330
|
+
lines.push(settingsPermissionBucketRefusalContent(bucket));
|
|
331
|
+
const settingsRefusal = settingsBodyShapeNote(err, sentRequest, lang);
|
|
332
|
+
if (settingsRefusal !== undefined)
|
|
333
|
+
lines.push(settingsRefusal);
|
|
334
|
+
if (isRefusedRequest(err) && ctx !== undefined && ctx.modelCatalog !== undefined) {
|
|
335
|
+
const rejected = modelCandidateRejectedContent(modelCandidateRejectedOf(ctx.modelCatalog), lang);
|
|
336
|
+
if (rejected !== undefined)
|
|
337
|
+
lines.push(rejected);
|
|
338
|
+
}
|
|
339
|
+
return Object.freeze({ notes: Object.freeze(lines), ...(waitSec !== undefined && !lease && !usageWindow ? { waitNote: waitSentence(waitSec, lang) } : {}) });
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
return Object.freeze({ notes: Object.freeze(lines) });
|
|
343
|
+
}
|
|
344
|
+
}
|
|
148
345
|
export function seatTurnFailureOf(err, evidence) {
|
|
149
346
|
const p = turnFailurePresentation(err, evidence);
|
|
150
347
|
return {
|
package/dist/usageAnalytics.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readThrownSlot, THROWN_SLOT_UNREADABLE } from './wireFailureShape.js';
|
|
1
2
|
export const USAGE_SENTENCES = Object.freeze({
|
|
2
3
|
analyticsUnavailable: 'Usage analytics aren’t available on this backend.',
|
|
3
4
|
analyticsUnread: 'Usage analytics couldn’t be read just now.',
|
|
@@ -10,18 +11,12 @@ const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v)
|
|
|
10
11
|
const nonNeg = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
11
12
|
const nonEmpty = (v) => typeof v === 'string' && v.length > 0;
|
|
12
13
|
export function classifyUsageFailure(e) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const o = e;
|
|
17
|
-
const rawCode = o?.errorCode;
|
|
18
|
-
const rawStatus = o?.status;
|
|
19
|
-
code = typeof rawCode === 'string' ? rawCode : undefined;
|
|
20
|
-
status = typeof rawStatus === 'number' ? rawStatus : undefined;
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
14
|
+
const rawCode = readThrownSlot(e, 'errorCode', 'data');
|
|
15
|
+
const rawStatus = readThrownSlot(e, 'status', 'data');
|
|
16
|
+
if (rawCode === THROWN_SLOT_UNREADABLE || rawStatus === THROWN_SLOT_UNREADABLE)
|
|
23
17
|
return { kind: 'failed', error: e };
|
|
24
|
-
|
|
18
|
+
const code = typeof rawCode === 'string' ? rawCode : undefined;
|
|
19
|
+
const status = typeof rawStatus === 'number' ? rawStatus : undefined;
|
|
25
20
|
if (code !== undefined) {
|
|
26
21
|
if (code.startsWith('capability.'))
|
|
27
22
|
return { kind: 'unavailable', why: 'capability' };
|
|
@@ -78,5 +78,6 @@ export type UserAttachmentDescriptor = {
|
|
|
78
78
|
};
|
|
79
79
|
export declare function showAttachmentName(s: string): string;
|
|
80
80
|
export declare function mintEnvelopeOf(d: DescriptorView, imageDelivery: 'attached' | 'not-attached'): string;
|
|
81
|
+
export declare function seatTextOf(d: DescriptorView): string | undefined;
|
|
81
82
|
export declare function mintReferenceOf(d: DescriptorView): string;
|
|
82
83
|
export declare function mintUserAttachmentEnvelope(descriptor: UserAttachmentDescriptor): string;
|
|
@@ -83,11 +83,7 @@ function mintText(d) {
|
|
|
83
83
|
: `Full path: ${path} (lines ${d.startLine}–${d.startLine + n - 1} of ${d.totalLines}; the other lines are not included). The client read it from disk and copied those lines between the two fence lines below. ${dataNote(d.source, "the file's contents")}`;
|
|
84
84
|
return fenced(anyEscaped ? [l1, l2, ESCAPE_NOTE] : [l1, l2], body);
|
|
85
85
|
}
|
|
86
|
-
function
|
|
87
|
-
const path = showAttachmentName(d.path);
|
|
88
|
-
const l1 = firstLine(d.source, 'a Jupyter notebook', d.name);
|
|
89
|
-
if (d.cells.length === 0)
|
|
90
|
-
return `${l1}\nFull path: ${path} (0 cells). The client read it from disk; it has no cells.`;
|
|
86
|
+
function notebookBody(d) {
|
|
91
87
|
let cellsWithImages = 0;
|
|
92
88
|
let cellsWithOversized = 0;
|
|
93
89
|
const parts = [];
|
|
@@ -113,9 +109,16 @@ function mintNotebook(d) {
|
|
|
113
109
|
if (hasImage)
|
|
114
110
|
cellsWithImages++;
|
|
115
111
|
}
|
|
112
|
+
return { text: parts.join('\n'), cellsWithImages, cellsWithOversized };
|
|
113
|
+
}
|
|
114
|
+
function mintNotebook(d) {
|
|
115
|
+
const path = showAttachmentName(d.path);
|
|
116
|
+
const l1 = firstLine(d.source, 'a Jupyter notebook', d.name);
|
|
117
|
+
if (d.cells.length === 0)
|
|
118
|
+
return `${l1}\nFull path: ${path} (0 cells). The client read it from disk; it has no cells.`;
|
|
119
|
+
const { text, cellsWithImages, cellsWithOversized } = notebookBody(d);
|
|
116
120
|
let anyEscaped = false;
|
|
117
|
-
const body =
|
|
118
|
-
.join('\n')
|
|
121
|
+
const body = text
|
|
119
122
|
.split('\n')
|
|
120
123
|
.map((line, i) => {
|
|
121
124
|
const shown = showBodyLine(line);
|
|
@@ -281,6 +284,33 @@ function referenceSentence(d) {
|
|
|
281
284
|
}
|
|
282
285
|
return `The user mentioned the ${what} ${name} (${path}) in this message; its contents are not included here.`;
|
|
283
286
|
}
|
|
287
|
+
export function seatTextOf(d) {
|
|
288
|
+
let text;
|
|
289
|
+
switch (d.kind) {
|
|
290
|
+
case 'text':
|
|
291
|
+
if (d.source !== 'at-mention' || !d.complete || d.lines.length === 0)
|
|
292
|
+
return undefined;
|
|
293
|
+
text = d.lines.join('\n');
|
|
294
|
+
break;
|
|
295
|
+
case 'notebook': {
|
|
296
|
+
if (d.source !== 'at-mention' || d.cells.length === 0)
|
|
297
|
+
return undefined;
|
|
298
|
+
const body = notebookBody(d);
|
|
299
|
+
if (body.cellsWithImages > 0 || body.cellsWithOversized > 0)
|
|
300
|
+
return undefined;
|
|
301
|
+
text = body.text;
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
case 'directory':
|
|
305
|
+
if (d.entries.length === 0 || d.totalEntries > d.entries.length)
|
|
306
|
+
return undefined;
|
|
307
|
+
text = d.entries.map(showAttachmentName).join('\n');
|
|
308
|
+
break;
|
|
309
|
+
default:
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
return text.length > 0 ? text : undefined;
|
|
313
|
+
}
|
|
284
314
|
export function mintReferenceOf(d) {
|
|
285
315
|
return `${TAG_OPEN}${tagAttributes(d)} />\n${referenceSentence(d)}`;
|
|
286
316
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface UserAttachmentSeatLimits {
|
|
2
|
+
readonly maxEntries: number;
|
|
3
|
+
readonly maxRenderedTextChars: number;
|
|
4
|
+
}
|
|
5
|
+
export interface UserAttachmentSeatPresent {
|
|
6
|
+
readonly kind: 'present';
|
|
7
|
+
readonly entries: readonly string[];
|
|
8
|
+
readonly kinds: readonly string[];
|
|
9
|
+
readonly supplies: readonly string[];
|
|
10
|
+
readonly limits: UserAttachmentSeatLimits;
|
|
11
|
+
}
|
|
12
|
+
export type UserAttachmentSeatReading = {
|
|
13
|
+
kind: 'unobserved';
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'unreadable';
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'not_reported';
|
|
18
|
+
} | UserAttachmentSeatPresent;
|
|
19
|
+
export declare function projectUserAttachmentSeatCapability(caps: {} | null | undefined): UserAttachmentSeatReading | undefined;
|
|
20
|
+
export declare function observedUserAttachmentSeat(baseUrl?: string | undefined): UserAttachmentSeatReading;
|
|
21
|
+
export declare function userAttachmentSeatAdmits(reading: UserAttachmentSeatReading | undefined): 'yes' | 'no' | 'unknown';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
+
import { createEngineCapReader } from './engineCapReader.js';
|
|
3
|
+
import { ownDataField, readOwnDataValue } from './ownKey.js';
|
|
4
|
+
const _seatPin = [true, true];
|
|
5
|
+
void _seatPin;
|
|
6
|
+
function stringList(v) {
|
|
7
|
+
if (!Array.isArray(v))
|
|
8
|
+
return undefined;
|
|
9
|
+
const n = ownDataField(v, 'length');
|
|
10
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0)
|
|
11
|
+
return undefined;
|
|
12
|
+
const out = [];
|
|
13
|
+
for (let i = 0; i < n; i += 1) {
|
|
14
|
+
const d = Object.getOwnPropertyDescriptor(v, i);
|
|
15
|
+
if (d === undefined || !('value' in d) || typeof d.value !== 'string')
|
|
16
|
+
return undefined;
|
|
17
|
+
out.push(d.value);
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
const positiveInt = (v) => (typeof v === 'number' && Number.isSafeInteger(v) && v >= 1 ? v : undefined);
|
|
22
|
+
const isPlainRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
23
|
+
export function projectUserAttachmentSeatCapability(caps) {
|
|
24
|
+
try {
|
|
25
|
+
if (!isPlainRecord(caps))
|
|
26
|
+
return undefined;
|
|
27
|
+
const seat = ownDataField(caps, 'userAttachments');
|
|
28
|
+
if (seat === undefined)
|
|
29
|
+
return { kind: 'not_reported' };
|
|
30
|
+
if (!isPlainRecord(seat))
|
|
31
|
+
return undefined;
|
|
32
|
+
const entries = stringList(ownDataField(seat, 'entries'));
|
|
33
|
+
const kinds = stringList(ownDataField(seat, 'kinds'));
|
|
34
|
+
const supplies = stringList(ownDataField(seat, 'supplies'));
|
|
35
|
+
const limits = ownDataField(seat, 'limits');
|
|
36
|
+
if (entries === undefined || kinds === undefined || supplies === undefined || !isPlainRecord(limits))
|
|
37
|
+
return undefined;
|
|
38
|
+
const maxEntries = positiveInt(ownDataField(limits, 'maxEntries'));
|
|
39
|
+
const maxRenderedTextChars = positiveInt(ownDataField(limits, 'maxRenderedTextChars'));
|
|
40
|
+
if (maxEntries === undefined || maxRenderedTextChars === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
return { kind: 'present', entries, kinds, supplies, limits: { maxEntries, maxRenderedTextChars } };
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const reader = createEngineCapReader({ name: 'userAttachments', project: projectUserAttachmentSeatCapability });
|
|
49
|
+
export function observedUserAttachmentSeat(baseUrl = engineWireTarget()?.baseUrl) {
|
|
50
|
+
return reader.observed(baseUrl);
|
|
51
|
+
}
|
|
52
|
+
export function userAttachmentSeatAdmits(reading) {
|
|
53
|
+
try {
|
|
54
|
+
if (!isPlainRecord(reading))
|
|
55
|
+
return 'unknown';
|
|
56
|
+
const kind = readOwnDataValue(reading, 'kind');
|
|
57
|
+
if (kind === 'not_reported')
|
|
58
|
+
return 'no';
|
|
59
|
+
if (kind !== 'present')
|
|
60
|
+
return 'unknown';
|
|
61
|
+
const has = (key, word) => {
|
|
62
|
+
const list = stringList(readOwnDataValue(reading, key));
|
|
63
|
+
return list === undefined ? undefined : list.includes(word);
|
|
64
|
+
};
|
|
65
|
+
const objective = has('entries', 'objective');
|
|
66
|
+
const text = has('supplies', 'content_text');
|
|
67
|
+
const client = has('kinds', 'client_text');
|
|
68
|
+
if (objective === undefined || text === undefined || client === undefined)
|
|
69
|
+
return 'unknown';
|
|
70
|
+
return objective && text && client ? 'yes' : 'no';
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return 'unknown';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
1
2
|
export type UserInvokedSkillsReading = {
|
|
2
3
|
kind: 'unobserved';
|
|
3
4
|
} | {
|
|
@@ -12,4 +13,13 @@ export type UserInvokedSkillsReading = {
|
|
|
12
13
|
export declare function projectUserInvokedSkillsCapability(caps: unknown): UserInvokedSkillsReading | undefined;
|
|
13
14
|
export declare function observedUserInvokedSkills(baseUrl?: string | undefined): UserInvokedSkillsReading;
|
|
14
15
|
export declare function userInvokedSkillsAvailable(reading: UserInvokedSkillsReading): 'yes' | 'no' | 'unknown';
|
|
15
|
-
export declare function userInvokedSkillsDoctorDetail(reading: UserInvokedSkillsReading): string;
|
|
16
|
+
export declare function userInvokedSkillsDoctorDetail(reading: UserInvokedSkillsReading, lang?: UiLanguage): string;
|
|
17
|
+
export interface UserInvokedSkillsDeclaration {
|
|
18
|
+
readonly field: {
|
|
19
|
+
readonly userInvokedSkills?: readonly string[];
|
|
20
|
+
};
|
|
21
|
+
readonly withheld?: {
|
|
22
|
+
readonly cause: Exclude<UserInvokedSkillsReading['kind'], 'present'>;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare function userInvokedSkillsDeclaration(names: readonly string[] | null | undefined, reading: UserInvokedSkillsReading): UserInvokedSkillsDeclaration;
|