@sema-agent/client-core 0.97.1 → 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 +607 -0
- package/README.md +96 -46
- package/dist/adapt/arms.d.ts +1 -0
- package/dist/adapt/arms.js +188 -53
- package/dist/adapt/ids.d.ts +12 -1
- package/dist/adapt/ids.js +59 -8
- package/dist/adapt/instanceLedger.d.ts +50 -0
- package/dist/adapt/instanceLedger.js +147 -0
- package/dist/adapt/panelTasks.d.ts +1 -1
- package/dist/adapt/panelTasks.js +2 -2
- package/dist/adapt/textStream.d.ts +1 -0
- package/dist/adapt/textStream.js +24 -7
- package/dist/adapt/toolCards.d.ts +27 -5
- package/dist/adapt/toolCards.js +39 -6
- package/dist/adapt/wireShapes.js +6 -2
- package/dist/adapt.d.ts +2 -0
- package/dist/adapt.js +8 -3
- package/dist/adapter/activeRunSelfHeal.d.ts +9 -3
- package/dist/adapter/activeRunSelfHeal.js +205 -313
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +77 -36
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
- package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
- package/dist/adapter/runStream.js +79 -48
- package/dist/adapter/types.d.ts +4 -4
- package/dist/adapter/types.js +2 -1
- package/dist/agentSession/backgroundView.js +2 -1
- package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
- package/dist/agentSession/engineAgentRegistryRead.js +12 -13
- package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
- package/dist/agentsWireCaps.d.ts +8 -11
- package/dist/agentsWireCaps.js +196 -194
- package/dist/approvalDecidedByCapability.d.ts +0 -4
- package/dist/approvalDecidedByCapability.js +0 -6
- package/dist/approvalsStreamLiveCapability.d.ts +0 -4
- package/dist/approvalsStreamLiveCapability.js +0 -6
- package/dist/assistantInbox.d.ts +34 -0
- package/dist/assistantInbox.js +118 -0
- package/dist/centerWiringCapability.js +9 -1
- package/dist/clientSlice.d.ts +0 -9
- package/dist/clientSlice.js +0 -3
- package/dist/cloudConfigWireCaps.d.ts +5 -3
- package/dist/cloudConfigWireCaps.js +106 -64
- package/dist/compensations.js +1 -1
- package/dist/connectorStatus.d.ts +21 -0
- package/dist/connectorStatus.js +112 -0
- package/dist/controlRouter.d.ts +18 -3
- package/dist/controlRouter.js +106 -67
- package/dist/coreValuePorts.d.ts +29 -4
- package/dist/coreValuePorts.js +10 -0
- package/dist/corruptSessionCopy.d.ts +2 -1
- package/dist/corruptSessionCopy.js +3 -3
- package/dist/decideReceipt.d.ts +2 -2
- package/dist/decideReceipt.js +5 -2
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/detachWire.js +3 -2
- package/dist/deviceExecutorManagementCapability.d.ts +0 -4
- package/dist/deviceExecutorManagementCapability.js +0 -6
- package/dist/deviceRebind.d.ts +49 -1
- package/dist/deviceRebind.js +221 -3
- package/dist/devicesFace.d.ts +34 -0
- package/dist/devicesFace.js +90 -0
- package/dist/displayUntrusted.d.ts +2 -0
- package/dist/displayUntrusted.js +253 -76
- package/dist/engineAgentAbsence.d.ts +1 -1
- package/dist/engineAgentPanelStore.d.ts +12 -4
- package/dist/engineAgentPanelStore.js +16 -11
- package/dist/engineCapReader.d.ts +2 -5
- package/dist/engineCapReader.js +8 -10
- package/dist/engineCapsCache.d.ts +12 -0
- package/dist/engineCapsCache.js +76 -18
- package/dist/engineCapsChange.d.ts +2 -0
- package/dist/engineCapsChange.js +9 -0
- package/dist/engineClosedSets.d.ts +1 -0
- package/dist/engineClosedSets.js +4 -1
- package/dist/engineErrorCodes.d.ts +11 -3
- package/dist/engineErrorCodes.js +11 -8
- package/dist/engineIdentity.d.ts +1 -0
- package/dist/engineIdentity.js +8 -0
- package/dist/engineRowRef.d.ts +28 -0
- package/dist/engineRowRef.js +114 -0
- package/dist/engineSessionMessages.d.ts +68 -0
- package/dist/engineSessionMessages.js +370 -0
- package/dist/engineTargetSeat.d.ts +27 -0
- package/dist/engineTargetSeat.js +199 -0
- package/dist/engineToolDirectory.d.ts +0 -9
- package/dist/engineToolDirectory.js +1 -94
- package/dist/engineUrl.d.ts +18 -0
- package/dist/engineUrl.js +52 -0
- package/dist/engineWireFor.js +3 -8
- package/dist/env/uiLanguage.d.ts +11 -1
- package/dist/env/uiLanguage.js +38 -2
- package/dist/eventLeg.d.ts +100 -0
- package/dist/eventLeg.js +305 -0
- package/dist/executionLaneCapability.d.ts +0 -4
- package/dist/executionLaneCapability.js +3 -16
- package/dist/fileHistoryCaptureCapability.d.ts +2 -5
- package/dist/fileHistoryCaptureCapability.js +13 -21
- package/dist/fileHistoryLegNotice.d.ts +2 -1
- package/dist/fileHistoryLegNotice.js +3 -3
- package/dist/fleet/fleetLedger.d.ts +0 -3
- package/dist/fleet/fleetLedger.js +21 -36
- package/dist/fleet/fleetProjection.d.ts +2 -2
- package/dist/fleet/fleetProjection.js +10 -8
- package/dist/frameBinding.d.ts +8 -0
- package/dist/frameBinding.js +35 -0
- package/dist/gateFailureCodes.d.ts +2 -0
- package/dist/gateFailureCodes.js +15 -0
- package/dist/gateOutcome.d.ts +3 -1
- package/dist/gateOutcome.js +41 -8
- package/dist/gateVocabulary.d.ts +10 -4
- package/dist/gateVocabulary.js +107 -47
- package/dist/generated/engineAskFaceTables.js +2 -2
- package/dist/generated/engineFactTables.d.ts +22 -3
- package/dist/generated/engineFactTables.js +51 -4
- package/dist/generated/engineNoticeTables.js +18 -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/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +8 -2
- package/dist/hitl/allowRuleShadow.js +36 -29
- package/dist/hitl/approvalCardReading.d.ts +15 -0
- package/dist/hitl/approvalCardReading.js +154 -0
- package/dist/hitl/approvalCardReasons.d.ts +14 -0
- package/dist/hitl/approvalCardReasons.js +119 -0
- package/dist/hitl/approvalHolds.d.ts +50 -15
- package/dist/hitl/approvalHolds.js +177 -27
- package/dist/hitl/approvalResolution.d.ts +51 -26
- package/dist/hitl/approvalResolution.js +86 -122
- package/dist/hitl/approvalsFeed.js +6 -18
- package/dist/hitl/askClassPair.d.ts +2 -0
- package/dist/hitl/askClassPair.js +17 -0
- package/dist/hitl/askGateWire.d.ts +20 -2
- package/dist/hitl/askGateWire.js +50 -1
- package/dist/hitl/askParkRowRouting.d.ts +5 -0
- package/dist/hitl/askParkRowRouting.js +32 -1
- package/dist/hitl/askSettlementLine.d.ts +28 -0
- package/dist/hitl/askSettlementLine.js +99 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +3 -2
- package/dist/hitl/automaticAnswerVerdict.js +29 -13
- package/dist/hitl/crashConverged.d.ts +11 -20
- package/dist/hitl/crashConverged.js +56 -0
- package/dist/hitl/crashConvergedNotice.d.ts +6 -3
- package/dist/hitl/crashConvergedNotice.js +48 -24
- package/dist/hitl/decisionConflict.js +3 -10
- package/dist/hitl/decisionRefusal.d.ts +40 -1
- package/dist/hitl/decisionRefusal.js +199 -42
- package/dist/hitl/frameRouter.d.ts +5 -2
- package/dist/hitl/frameRouter.js +27 -24
- package/dist/hitl/gateLedger.d.ts +2 -0
- package/dist/hitl/gateLedger.js +50 -13
- package/dist/hitl/hitlBridge.d.ts +2 -2
- package/dist/hitl/hitlBridge.js +13 -10
- package/dist/hitl/livePendingAsk.d.ts +3 -3
- package/dist/hitl/livePendingAsk.js +7 -18
- package/dist/hitl/parkResolver.d.ts +2 -24
- package/dist/hitl/parkResolver.js +61 -97
- package/dist/hitl/persistedRulesWire.d.ts +25 -0
- package/dist/hitl/persistedRulesWire.js +104 -2
- package/dist/hitl/planReviewWire.d.ts +31 -13
- package/dist/hitl/planReviewWire.js +120 -78
- package/dist/hitl/refusedToolNameProse.d.ts +0 -1
- package/dist/hitl/refusedToolNameProse.js +0 -3
- package/dist/hitl/replayedApproval.d.ts +4 -3
- package/dist/hitl/replayedApproval.js +7 -4
- package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
- package/dist/hitl/sessionPolicyDeliverable.js +48 -7
- package/dist/hitl/sessionPolicyWire.d.ts +34 -21
- package/dist/hitl/sessionPolicyWire.js +179 -70
- package/dist/hitl/standingRows.d.ts +20 -2
- package/dist/hitl/standingRows.js +69 -8
- package/dist/hitl/suspendedReopen.d.ts +2 -1
- package/dist/hitl/suspendedReopen.js +7 -10
- package/dist/hitl/toolApprovalWire.d.ts +103 -156
- package/dist/hitl/toolApprovalWire.js +661 -411
- package/dist/hookMatcherVerdict.d.ts +6 -1
- package/dist/hookMatcherVerdict.js +14 -7
- package/dist/hooksWireCaps.d.ts +2 -2
- package/dist/hooksWireCaps.js +174 -81
- 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 +703 -0
- package/dist/i18n/messages.en.js +701 -0
- package/dist/i18n/messages.zh.d.ts +3 -0
- package/dist/i18n/messages.zh.js +837 -0
- package/dist/i18n/translate.d.ts +25 -0
- package/dist/i18n/translate.js +127 -0
- package/dist/index.d.ts +78 -29
- package/dist/index.js +54 -18
- package/dist/inheritEnvCapability.d.ts +32 -0
- package/dist/inheritEnvCapability.js +104 -0
- package/dist/inheritEnvWire.d.ts +3 -2
- package/dist/inheritEnvWire.js +12 -14
- package/dist/interactiveHalt.js +17 -6
- package/dist/liveModelCatalog.d.ts +3 -3
- package/dist/liveModelCatalog.js +15 -13
- package/dist/liveQuestionStore.d.ts +2 -21
- package/dist/mcpLiveness.d.ts +2 -1
- 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 +9 -2
- package/dist/mcpProbeWire.js +6 -1
- package/dist/mcpWireCaps.d.ts +47 -2
- package/dist/mcpWireCaps.js +164 -16
- package/dist/memoryEntriesWire.d.ts +4 -9
- package/dist/memoryEntriesWire.js +5 -10
- package/dist/model/modelSupplyRules.d.ts +0 -2
- package/dist/model/modelSupplyRules.js +3 -12
- package/dist/model/modelsPolicy.d.ts +0 -5
- package/dist/model/modelsPolicy.js +6 -36
- package/dist/model/onboardJudgement.d.ts +93 -0
- package/dist/model/onboardJudgement.js +415 -0
- package/dist/model/subagentModelWord.d.ts +31 -0
- package/dist/model/subagentModelWord.js +261 -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/notifications.d.ts +6 -0
- package/dist/notifications.js +71 -23
- package/dist/outputStyleSeatCapability.d.ts +0 -3
- package/dist/outputStyleSeatCapability.js +0 -3
- package/dist/ownKey.d.ts +22 -0
- package/dist/ownKey.js +94 -3
- package/dist/panelReduce.d.ts +21 -10
- package/dist/panelReduce.js +728 -550
- package/dist/panelStateHolder.d.ts +3 -7
- package/dist/panelStateHolder.js +14 -130
- package/dist/peerLaneCapability.d.ts +0 -4
- package/dist/peerLaneCapability.js +0 -6
- package/dist/permissionRuleIssue.js +2 -0
- package/dist/permissionRulesWriteCapability.d.ts +2 -5
- package/dist/permissionRulesWriteCapability.js +8 -12
- package/dist/permissionWireCaps.d.ts +2 -2
- package/dist/permissionWireCaps.js +2 -0
- package/dist/permissionsAllowGrantCapability.d.ts +0 -4
- package/dist/permissionsAllowGrantCapability.js +0 -6
- package/dist/permissionsDeclaration.d.ts +0 -11
- package/dist/permissionsDeclaration.js +60 -53
- package/dist/pluginHooksWire.d.ts +46 -3
- package/dist/pluginHooksWire.js +219 -16
- package/dist/preemptWire.d.ts +44 -0
- package/dist/preemptWire.js +83 -0
- package/dist/printModelStatus.d.ts +63 -0
- package/dist/printModelStatus.js +155 -0
- package/dist/printToolResultFrame.js +15 -4
- package/dist/replayBody.d.ts +3 -0
- package/dist/replayBody.js +14 -0
- package/dist/request/taskRequest.d.ts +11 -6
- package/dist/request/taskRequest.js +112 -19
- package/dist/resumeRefusalCopy.d.ts +13 -9
- package/dist/resumeRefusalCopy.js +81 -118
- package/dist/retryStatus.d.ts +45 -0
- package/dist/retryStatus.js +185 -1
- package/dist/rewindArchiveCapability.d.ts +0 -4
- package/dist/rewindArchiveCapability.js +2 -10
- package/dist/rewindArchiveReading.d.ts +0 -1
- package/dist/rewindArchiveReading.js +0 -3
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +4 -2
- package/dist/runReattachPolicy.d.ts +31 -0
- package/dist/runReattachPolicy.js +46 -0
- package/dist/runTerminal.d.ts +3 -6
- package/dist/runTerminal.js +8 -9
- package/dist/sandboxWire.d.ts +3 -1
- package/dist/sandboxWire.js +76 -27
- package/dist/scenarioRefusal.d.ts +9 -0
- package/dist/scenarioRefusal.js +111 -0
- package/dist/scenarioWire.js +1 -1
- package/dist/seam.d.ts +48 -2
- package/dist/seam.js +25 -4
- package/dist/seatContract.d.ts +311 -18
- package/dist/seatContract.js +824 -100
- 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 -5
- package/dist/sessionPolicyCapability.js +8 -12
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
- package/dist/sessionSyncFileHistoryCapability.js +0 -3
- package/dist/settingsHooksSalvage.d.ts +44 -0
- package/dist/settingsHooksSalvage.js +211 -0
- package/dist/skillToolListsCapability.d.ts +2 -4
- package/dist/skillToolListsCapability.js +8 -9
- package/dist/sqlEngineCapability.d.ts +0 -4
- package/dist/sqlEngineCapability.js +0 -6
- package/dist/sseIdleTriage.js +3 -2
- package/dist/steerPriorityCapability.d.ts +0 -3
- package/dist/steerPriorityCapability.js +0 -3
- package/dist/streamDrainingLegs.d.ts +4 -0
- package/dist/streamDrainingLegs.js +6 -1
- package/dist/subagent/engineCompactWire.d.ts +0 -1
- package/dist/subagent/engineCompactWire.js +7 -5
- package/dist/subagent/engineSubagentResume.js +15 -9
- package/dist/subagent/engineTaskHandleWire.js +4 -7
- package/dist/subagentContentStore.d.ts +3 -0
- package/dist/subagentContentStore.js +22 -10
- package/dist/submitReopen.d.ts +24 -0
- package/dist/submitReopen.js +75 -0
- package/dist/terminalStatuses.d.ts +3 -0
- package/dist/terminalStatuses.js +10 -2
- package/dist/toolHistoryMismatch.js +3 -2
- package/dist/toolResult.d.ts +10 -1
- package/dist/toolResult.js +34 -6
- package/dist/toolRoster.d.ts +3 -4
- package/dist/toolRoster.js +21 -22
- package/dist/turnFailurePresentation.d.ts +39 -0
- package/dist/turnFailurePresentation.js +402 -0
- 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 -4
- package/dist/userInvokedSkillsCapability.js +31 -10
- package/dist/webSearchBackendCapability.d.ts +0 -4
- package/dist/webSearchBackendCapability.js +0 -6
- package/dist/wireErrorTriage.d.ts +7 -0
- package/dist/wireErrorTriage.js +26 -23
- package/dist/wireFailureShape.d.ts +62 -5
- package/dist/wireFailureShape.js +106 -5
- package/dist/wireRefusalCopy.d.ts +25 -3
- package/dist/wireRefusalCopy.js +74 -80
- package/dist/workflowsJournalCapability.d.ts +2 -5
- package/dist/workflowsJournalCapability.js +8 -12
- package/dist/writeProtectionCapability.d.ts +0 -4
- package/dist/writeProtectionCapability.js +0 -6
- package/docs/INTEGRATION-CLIENTS.md +1775 -56
- package/package.json +6 -5
- package/dist/attachmentSeatCapability.d.ts +0 -12
- package/dist/attachmentSeatCapability.js +0 -23
- package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
- package/dist/hitl/approvalOutcomeNote.js +0 -29
- package/dist/sessionReadRedactionCapability.d.ts +0 -13
- package/dist/sessionReadRedactionCapability.js +0 -35
|
@@ -34,53 +34,23 @@ function atMentionOf(v) {
|
|
|
34
34
|
return undefined;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
function atModelAllowlistOf(v) {
|
|
38
|
-
if (!Array.isArray(v))
|
|
39
|
-
return { kind: 'unreadable', from: 'atModelAllowlist' };
|
|
40
|
-
const names = [];
|
|
41
|
-
let bad = 0;
|
|
42
|
-
for (let i = 0; i < v.length; i += 1) {
|
|
43
|
-
const d = Object.getOwnPropertyDescriptor(v, i);
|
|
44
|
-
const x = d !== undefined && 'value' in d ? d.value : undefined;
|
|
45
|
-
if (typeof x === 'string' && x.length > 0)
|
|
46
|
-
names.push(x);
|
|
47
|
-
else
|
|
48
|
-
bad += 1;
|
|
49
|
-
}
|
|
50
|
-
const value = names.length > 0 ? { mode: 'only', models: names } : { mode: 'all' };
|
|
51
|
-
return { kind: 'read', value, from: 'atModelAllowlist', unreadableEntries: bad };
|
|
52
|
-
}
|
|
53
37
|
export function modelsPolicyOf(doc) {
|
|
54
38
|
try {
|
|
55
39
|
if (!isRecord(doc))
|
|
56
40
|
return {};
|
|
57
41
|
let defaultModel;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
else
|
|
64
|
-
defaultUnreadable = true;
|
|
65
|
-
}
|
|
66
|
-
if (defaultModel === undefined && !defaultUnreadable) {
|
|
67
|
-
const roles = ownData(doc, 'roles');
|
|
68
|
-
const rd = isRecord(roles) ? ownData(roles, 'default') : undefined;
|
|
69
|
-
const model = isRecord(rd) ? ownData(rd, 'model') : undefined;
|
|
70
|
-
if (typeof model === 'string' && model.length > 0)
|
|
71
|
-
defaultModel = { name: model, from: 'roles.default' };
|
|
72
|
-
}
|
|
42
|
+
const roles = ownData(doc, 'roles');
|
|
43
|
+
const rd = isRecord(roles) ? ownData(roles, 'default') : undefined;
|
|
44
|
+
const model = isRecord(rd) ? ownData(rd, 'model') : undefined;
|
|
45
|
+
if (typeof model === 'string' && model.length > 0)
|
|
46
|
+
defaultModel = { name: model };
|
|
73
47
|
let atMention;
|
|
74
48
|
if (Object.hasOwn(doc, 'atMention')) {
|
|
75
49
|
const am = atMentionOf(ownData(doc, 'atMention'));
|
|
76
|
-
atMention = am === undefined ? { kind: 'unreadable'
|
|
77
|
-
}
|
|
78
|
-
else if (Object.hasOwn(doc, 'atModelAllowlist')) {
|
|
79
|
-
atMention = atModelAllowlistOf(ownData(doc, 'atModelAllowlist'));
|
|
50
|
+
atMention = am === undefined ? { kind: 'unreadable' } : { kind: 'read', value: am };
|
|
80
51
|
}
|
|
81
52
|
return {
|
|
82
53
|
...(defaultModel !== undefined ? { defaultModel } : {}),
|
|
83
|
-
...(defaultUnreadable ? { defaultUnreadable: true } : {}),
|
|
84
54
|
...(atMention !== undefined ? { atMention } : {}),
|
|
85
55
|
};
|
|
86
56
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { ModelApiWord } from './providerPresets.js';
|
|
2
|
+
import type { OnboardCatalogIssue, OnboardProbeResult, OnboardProbeVerdict, OnboardRefusal } from '../seatContract.js';
|
|
3
|
+
import { type ModelProbeResult } from '../modelCapabilityProbe.js';
|
|
4
|
+
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
5
|
+
export declare function onboardBaseUrlProblem(url: string, lang?: UiLanguage): string | undefined;
|
|
6
|
+
export interface OnboardProbeTarget {
|
|
7
|
+
readonly baseUrl: string;
|
|
8
|
+
readonly api: ModelApiWord;
|
|
9
|
+
readonly modelId?: string | undefined;
|
|
10
|
+
readonly apiKey?: string | undefined;
|
|
11
|
+
readonly auth?: 'bearer' | 'x-api-key' | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface OnboardProbeRequestInit {
|
|
14
|
+
method?: string;
|
|
15
|
+
headers: Record<string, string>;
|
|
16
|
+
body?: string;
|
|
17
|
+
redirect: 'manual';
|
|
18
|
+
signal: AbortSignal;
|
|
19
|
+
}
|
|
20
|
+
export interface OnboardProbeBodyReader {
|
|
21
|
+
read(): Promise<{
|
|
22
|
+
readonly done: boolean;
|
|
23
|
+
readonly value?: Uint8Array | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
cancel(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export interface OnboardProbeResponse {
|
|
28
|
+
readonly status: number;
|
|
29
|
+
readonly ok: boolean;
|
|
30
|
+
readonly headers: {
|
|
31
|
+
get(name: string): string | null;
|
|
32
|
+
};
|
|
33
|
+
readonly body?: {
|
|
34
|
+
getReader(): OnboardProbeBodyReader;
|
|
35
|
+
} | null | undefined;
|
|
36
|
+
text(): Promise<string>;
|
|
37
|
+
}
|
|
38
|
+
export type OnboardProbeFetch = (url: string, init: OnboardProbeRequestInit) => Promise<OnboardProbeResponse>;
|
|
39
|
+
export interface OnboardProbeDeps {
|
|
40
|
+
readonly fetchImpl?: OnboardProbeFetch | undefined;
|
|
41
|
+
readonly timeoutMs?: number | undefined;
|
|
42
|
+
readonly firstTokenMs?: number | undefined;
|
|
43
|
+
}
|
|
44
|
+
export declare function probeModelEndpoint(target: OnboardProbeTarget, deps?: OnboardProbeDeps): Promise<OnboardProbeResult>;
|
|
45
|
+
export type OnboardWriteVerdict = {
|
|
46
|
+
readonly write: true;
|
|
47
|
+
readonly unverified: boolean;
|
|
48
|
+
} | {
|
|
49
|
+
readonly write: false;
|
|
50
|
+
readonly refusal: 'probe_failed' | 'probe_unverified';
|
|
51
|
+
};
|
|
52
|
+
export declare function onboardWriteVerdict(verdict: OnboardProbeVerdict, acceptUnverified?: boolean): OnboardWriteVerdict;
|
|
53
|
+
export declare function keyEnvNameForEntry(entryName: string): string;
|
|
54
|
+
export declare function poolEntryNameOf(modelId: string, channel: string, taken: ReadonlySet<string>): string;
|
|
55
|
+
export interface OnboardPlanEntry {
|
|
56
|
+
readonly modelId: string;
|
|
57
|
+
readonly api: ModelApiWord;
|
|
58
|
+
readonly baseUrl: string;
|
|
59
|
+
readonly apiKey: string;
|
|
60
|
+
readonly providerName: string;
|
|
61
|
+
readonly contextWindow: number;
|
|
62
|
+
readonly maxTokens: number;
|
|
63
|
+
readonly channel: string;
|
|
64
|
+
}
|
|
65
|
+
export interface OnboardJsonObject {
|
|
66
|
+
readonly [key: string]: {} | null;
|
|
67
|
+
}
|
|
68
|
+
export interface OnboardWritePlanInput {
|
|
69
|
+
readonly modelsDoc: OnboardJsonObject | undefined;
|
|
70
|
+
readonly settingsEnv: OnboardJsonObject | undefined;
|
|
71
|
+
readonly effectiveEnv: Readonly<Record<string, string | undefined>>;
|
|
72
|
+
readonly entry: OnboardPlanEntry;
|
|
73
|
+
readonly probe: OnboardProbeResult;
|
|
74
|
+
readonly makeDefault: boolean;
|
|
75
|
+
readonly now: number;
|
|
76
|
+
readonly thinking?: ModelProbeResult | undefined;
|
|
77
|
+
readonly engineMode?: 'local' | 'cloud' | undefined;
|
|
78
|
+
}
|
|
79
|
+
export type OnboardWritePlan = {
|
|
80
|
+
readonly ok: true;
|
|
81
|
+
readonly entryName: string;
|
|
82
|
+
readonly keyEnv: string;
|
|
83
|
+
readonly updatedExisting: boolean;
|
|
84
|
+
readonly nextModelsDoc: OnboardJsonObject;
|
|
85
|
+
readonly nextSettingsEnv: OnboardJsonObject;
|
|
86
|
+
readonly otherIssues: readonly OnboardCatalogIssue[];
|
|
87
|
+
} | {
|
|
88
|
+
readonly ok: false;
|
|
89
|
+
readonly refusal: Extract<OnboardRefusal, 'input' | 'catalog_unreadable' | 'credential_unpaired' | 'engine_is_remote' | 'env_catalog_present'>;
|
|
90
|
+
readonly detail: string;
|
|
91
|
+
};
|
|
92
|
+
export declare function onboardWritePlan(input: OnboardWritePlanInput): OnboardWritePlan;
|
|
93
|
+
export declare function onboardRefusalText(refusal: OnboardRefusal, lang?: UiLanguage): string;
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import { ONBOARD_REFUSALS } from '../seatContract.js';
|
|
2
|
+
import { joinRequestUrl, routeKeyOf } from '../coreValuePorts.js';
|
|
3
|
+
import { applyProbeToEntry, probeModelLiveness, probeVerdictNotice } from '../modelCapabilityProbe.js';
|
|
4
|
+
import { ownDataField } from '../ownKey.js';
|
|
5
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
6
|
+
const field = (v, key) => {
|
|
7
|
+
if (v === null || typeof v !== 'object')
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
return ownDataField(v, key);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const en = (key, params) => renderMessage(msg(key, params));
|
|
17
|
+
function decodeLenient(t) {
|
|
18
|
+
let cur = t;
|
|
19
|
+
for (let i = 0; i < 16; i++) {
|
|
20
|
+
const next = cur.replace(/(?:%[0-9A-Fa-f]{2})+/g, (m) => {
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(m);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return m.replace(/%([0-9A-Fa-f]{2})/g, (_x, h) => String.fromCharCode(parseInt(h, 16)));
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
if (next === cur)
|
|
29
|
+
return cur;
|
|
30
|
+
cur = next;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
function decodeDeep(t) {
|
|
35
|
+
let cur = t;
|
|
36
|
+
for (let i = 0; i < 16; i++) {
|
|
37
|
+
if (!cur.includes('%'))
|
|
38
|
+
return cur;
|
|
39
|
+
let next;
|
|
40
|
+
try {
|
|
41
|
+
next = decodeURIComponent(cur);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
if (next === cur)
|
|
47
|
+
return cur;
|
|
48
|
+
cur = next;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
function safeDecode(t) {
|
|
53
|
+
try {
|
|
54
|
+
return decodeURIComponent(t);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return t;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function carriesKey(text, key) {
|
|
61
|
+
if (key === undefined || key === '')
|
|
62
|
+
return false;
|
|
63
|
+
const d = decodeDeep(text);
|
|
64
|
+
if (d === undefined)
|
|
65
|
+
return true;
|
|
66
|
+
const k = key.toLowerCase();
|
|
67
|
+
return text.toLowerCase().includes(k) || d.toLowerCase().includes(k);
|
|
68
|
+
}
|
|
69
|
+
function looksLikeSecret(val) {
|
|
70
|
+
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
|
+
}
|
|
72
|
+
function redact(text, key) {
|
|
73
|
+
if (key === undefined || key === '')
|
|
74
|
+
return text;
|
|
75
|
+
const out = text.split(key).join('****');
|
|
76
|
+
const k = key.toLowerCase();
|
|
77
|
+
const d = decodeLenient(out);
|
|
78
|
+
return d === undefined || out.toLowerCase().includes(k) || d.toLowerCase().includes(k) ? en('onboard.probe.keyEchoed') : out;
|
|
79
|
+
}
|
|
80
|
+
const capText = (text) => (text.length > 400 ? `${text.slice(0, 400)}…` : text);
|
|
81
|
+
export function onboardBaseUrlProblem(url, lang) {
|
|
82
|
+
const say = (key) => renderMessage(msg(key), lang);
|
|
83
|
+
if (typeof url !== 'string')
|
|
84
|
+
return say('onboard.baseUrl.invalid');
|
|
85
|
+
if (/\s/.test(url.trim()))
|
|
86
|
+
return say('onboard.baseUrl.spaces');
|
|
87
|
+
let u;
|
|
88
|
+
try {
|
|
89
|
+
u = new URL(url.trim());
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return say('onboard.baseUrl.invalid');
|
|
93
|
+
}
|
|
94
|
+
if (u.protocol !== 'http:' && u.protocol !== 'https:')
|
|
95
|
+
return say('onboard.baseUrl.scheme');
|
|
96
|
+
if (u.username !== '' || u.password !== '')
|
|
97
|
+
return say('onboard.baseUrl.userinfo');
|
|
98
|
+
if (u.hash !== '')
|
|
99
|
+
return say('onboard.baseUrl.fragment');
|
|
100
|
+
if (u.pathname.split('/').some((seg) => /^(sk|ak|pk|rk)[-_]/i.test(safeDecode(seg))))
|
|
101
|
+
return say('onboard.baseUrl.pathKey');
|
|
102
|
+
for (const [k, val] of u.searchParams) {
|
|
103
|
+
if (/key|token|secret|auth|sig|pass/i.test(k))
|
|
104
|
+
return say('onboard.baseUrl.queryKey');
|
|
105
|
+
if (looksLikeSecret(val))
|
|
106
|
+
return say('onboard.baseUrl.queryValueKey');
|
|
107
|
+
}
|
|
108
|
+
if (decodeDeep(url.trim()) === undefined)
|
|
109
|
+
return say('onboard.baseUrl.encoding');
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
function keyHeaders(api, key, auth) {
|
|
113
|
+
const h = {};
|
|
114
|
+
if (key !== undefined && key !== '') {
|
|
115
|
+
if (auth !== 'x-api-key' || api !== 'anthropic-messages')
|
|
116
|
+
h['authorization'] = `Bearer ${key}`;
|
|
117
|
+
if (api === 'anthropic-messages' && auth !== 'bearer')
|
|
118
|
+
h['x-api-key'] = key;
|
|
119
|
+
}
|
|
120
|
+
return h;
|
|
121
|
+
}
|
|
122
|
+
class OnboardRedirect extends Error {
|
|
123
|
+
}
|
|
124
|
+
function redirectRefusal(res, url, key) {
|
|
125
|
+
if (res.status < 300 || res.status >= 400)
|
|
126
|
+
return undefined;
|
|
127
|
+
let where = en('onboard.probe.anotherAddress');
|
|
128
|
+
try {
|
|
129
|
+
const to = res.headers.get('location');
|
|
130
|
+
if (to)
|
|
131
|
+
where = redact(to, key) === to ? new URL(to, url).host : en('onboard.probe.anotherAddress');
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
where = en('onboard.probe.anotherAddress');
|
|
135
|
+
}
|
|
136
|
+
return en('onboard.probe.redirected', { status: res.status, where });
|
|
137
|
+
}
|
|
138
|
+
function probeDetailOf(v) {
|
|
139
|
+
if (v.verdict === 'ok' && v.waitedMs === undefined && v.path !== undefined && v.httpStatus !== undefined) {
|
|
140
|
+
return en('onboard.probe.endpointReachable', { method: v.path === '/models' ? 'GET' : 'POST', path: v.path, status: v.httpStatus });
|
|
141
|
+
}
|
|
142
|
+
const line = probeVerdictNotice(v).line;
|
|
143
|
+
const tail = v.apiError ?? v.cause;
|
|
144
|
+
const detail = tail === undefined ? line : `${line}: ${tail}`;
|
|
145
|
+
return v.nearModelId === undefined ? detail : en('onboard.probe.modelSuggest', { error: detail, near: v.nearModelId });
|
|
146
|
+
}
|
|
147
|
+
export async function probeModelEndpoint(target, deps) {
|
|
148
|
+
const apiKey = field(target, 'apiKey');
|
|
149
|
+
const key = typeof apiKey === 'string' ? apiKey : undefined;
|
|
150
|
+
const redactKey = key?.trim() || undefined;
|
|
151
|
+
const out = (verdict, detail) => Object.freeze({ verdict, detail: capText(redact(detail, redactKey)) });
|
|
152
|
+
const baseUrl = field(target, 'baseUrl');
|
|
153
|
+
const api = field(target, 'api');
|
|
154
|
+
const rawModel = field(target, 'modelId');
|
|
155
|
+
const modelId = typeof rawModel === 'string' && rawModel.trim() !== '' ? rawModel.trim() : undefined;
|
|
156
|
+
const auth = field(target, 'auth');
|
|
157
|
+
if (typeof baseUrl !== 'string' || (api !== 'anthropic-messages' && api !== 'openai-completions'))
|
|
158
|
+
return out('other', en('onboard.probe.incomplete'));
|
|
159
|
+
const f = (field(deps, 'fetchImpl') ?? globalThis.fetch);
|
|
160
|
+
if (typeof f !== 'function')
|
|
161
|
+
return out('unreachable', en('onboard.probe.noFetch'));
|
|
162
|
+
const num = (k) => {
|
|
163
|
+
const v = field(deps, k);
|
|
164
|
+
return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : undefined;
|
|
165
|
+
};
|
|
166
|
+
const timeoutMs = num('timeoutMs');
|
|
167
|
+
const deadlineMs = num('firstTokenMs') ?? timeoutMs ?? 15_000;
|
|
168
|
+
const root = baseUrl.trim();
|
|
169
|
+
try {
|
|
170
|
+
if (joinRequestUrl(root, 'models') === undefined)
|
|
171
|
+
return out('other', en('onboard.probe.judgeAbsent'));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return out('other', en('onboard.baseUrl.invalid'));
|
|
175
|
+
}
|
|
176
|
+
const secret = keyHeaders(api, key, auth === 'bearer' || auth === 'x-api-key' ? auth : undefined);
|
|
177
|
+
const seen = {};
|
|
178
|
+
const fetchWithKey = async (url, init) => {
|
|
179
|
+
const res = await f(url, { method: init.method, headers: { ...init.headers, ...secret }, ...(init.body !== undefined ? { body: init.body } : {}), redirect: 'manual', signal: init.signal });
|
|
180
|
+
const refusal = redirectRefusal(res, url, redactKey);
|
|
181
|
+
if (refusal !== undefined) {
|
|
182
|
+
if (init.method === 'POST' || api === 'openai-completions')
|
|
183
|
+
seen.redirected = refusal;
|
|
184
|
+
throw new OnboardRedirect(refusal);
|
|
185
|
+
}
|
|
186
|
+
return { status: res.status, headers: res.headers, body: res.body ?? null, text: () => res.text() };
|
|
187
|
+
};
|
|
188
|
+
const v = await probeModelLiveness({
|
|
189
|
+
api,
|
|
190
|
+
baseUrl: root,
|
|
191
|
+
...(modelId !== undefined ? { modelId } : {}),
|
|
192
|
+
fetch: fetchWithKey,
|
|
193
|
+
firstTokenBudgetMs: deadlineMs,
|
|
194
|
+
catalogBudgetMs: timeoutMs ?? (api === 'anthropic-messages' ? 8000 : 10_000),
|
|
195
|
+
requestUrl: (path) => joinRequestUrl(root, path),
|
|
196
|
+
redact: (text) => redact(text, redactKey),
|
|
197
|
+
});
|
|
198
|
+
if (v.verdict === 'unreachable' && seen.redirected !== undefined)
|
|
199
|
+
return out('unreachable', seen.redirected);
|
|
200
|
+
return out(v.verdict, probeDetailOf(v));
|
|
201
|
+
}
|
|
202
|
+
export function onboardWriteVerdict(verdict, acceptUnverified) {
|
|
203
|
+
if (verdict === 'ok')
|
|
204
|
+
return Object.freeze({ write: true, unverified: false });
|
|
205
|
+
if (verdict === 'auth' || verdict === 'model' || verdict === 'shape')
|
|
206
|
+
return Object.freeze({ write: false, refusal: 'probe_failed' });
|
|
207
|
+
return acceptUnverified === true ? Object.freeze({ write: true, unverified: true }) : Object.freeze({ write: false, refusal: 'probe_unverified' });
|
|
208
|
+
}
|
|
209
|
+
const KEY_SLOT_PREFIX = 'SEMA_MODEL_KEY_';
|
|
210
|
+
export function keyEnvNameForEntry(entryName) {
|
|
211
|
+
const base = String(entryName).toUpperCase().replace(/[^A-Z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'ENTRY';
|
|
212
|
+
return `${KEY_SLOT_PREFIX}${base}`;
|
|
213
|
+
}
|
|
214
|
+
export function poolEntryNameOf(modelId, channel, taken) {
|
|
215
|
+
let name = String(modelId).toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^[._-]+/, '');
|
|
216
|
+
if (!name)
|
|
217
|
+
name = 'model';
|
|
218
|
+
if (name === 'default')
|
|
219
|
+
name = 'm-default';
|
|
220
|
+
let candidate = name;
|
|
221
|
+
if (taken.has(candidate))
|
|
222
|
+
candidate = `${name}-${channel}`;
|
|
223
|
+
for (let i = 2; taken.has(candidate); i++)
|
|
224
|
+
candidate = `${name}-${channel}-${i}`;
|
|
225
|
+
return candidate;
|
|
226
|
+
}
|
|
227
|
+
function entryCredentialIssue(m, env) {
|
|
228
|
+
const name = typeof m['name'] === 'string' ? m['name'] : '?';
|
|
229
|
+
if (m['sealedApiKey'] !== undefined && m['sealedApiKey'] !== null)
|
|
230
|
+
return undefined;
|
|
231
|
+
const keyEnv = typeof m['apiKeyEnv'] === 'string' && m['apiKeyEnv'] !== '' ? m['apiKeyEnv'] : undefined;
|
|
232
|
+
if (keyEnv !== undefined) {
|
|
233
|
+
const v = env[keyEnv];
|
|
234
|
+
return typeof v === 'string' && v.length > 0 ? undefined : en('onboard.catalog.keyEnvUnset', { name, keyEnv });
|
|
235
|
+
}
|
|
236
|
+
const base = typeof m['baseUrl'] === 'string' ? m['baseUrl'] : '';
|
|
237
|
+
if (base.trim() === '')
|
|
238
|
+
return undefined;
|
|
239
|
+
const api = typeof m['api'] === 'string' ? m['api'] : 'openai-completions';
|
|
240
|
+
const rootKey = api === 'anthropic-messages' ? 'ANTHROPIC_BASE_URL' : 'MODEL_GATEWAY_BASEURL';
|
|
241
|
+
const root = env[rootKey];
|
|
242
|
+
let paired;
|
|
243
|
+
try {
|
|
244
|
+
const a = routeKeyOf(base);
|
|
245
|
+
if (a === undefined)
|
|
246
|
+
return en('onboard.catalog.judgeAbsent', { name });
|
|
247
|
+
paired = typeof root === 'string' && root !== '' && a === routeKeyOf(root);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
paired = false;
|
|
251
|
+
}
|
|
252
|
+
if (paired)
|
|
253
|
+
return undefined;
|
|
254
|
+
const hostOf = (u) => {
|
|
255
|
+
try {
|
|
256
|
+
return new URL(u).host;
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
return en('onboard.catalog.unparseableHost');
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const rootText = typeof root === 'string' && root !== '' ? `${rootKey} (${hostOf(root)})` : en('onboard.catalog.noRoot', { rootKey });
|
|
263
|
+
return en('onboard.catalog.unpaired', { name, host: hostOf(base), root: rootText });
|
|
264
|
+
}
|
|
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
|
+
const REFUSAL_KEYS = {
|
|
402
|
+
input: 'onboard.refusal.input',
|
|
403
|
+
probe_failed: 'onboard.refusal.probeFailed',
|
|
404
|
+
probe_unverified: 'onboard.refusal.probeUnverified',
|
|
405
|
+
credential_unpaired: 'onboard.refusal.credentialUnpaired',
|
|
406
|
+
catalog_unreadable: 'onboard.refusal.catalogUnreadable',
|
|
407
|
+
write_conflict: 'onboard.refusal.writeConflict',
|
|
408
|
+
write_failed: 'onboard.refusal.writeFailed',
|
|
409
|
+
engine_is_remote: 'onboard.refusal.engineIsRemote',
|
|
410
|
+
env_catalog_present: 'onboard.refusal.envCatalogPresent',
|
|
411
|
+
};
|
|
412
|
+
export function onboardRefusalText(refusal, lang) {
|
|
413
|
+
const known = ONBOARD_REFUSALS.find((w) => w === refusal) ?? 'input';
|
|
414
|
+
return renderMessage(msg(REFUSAL_KEYS[known]), lang);
|
|
415
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type LiveModelCatalog } from '../liveModelCatalog.js';
|
|
2
|
+
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
3
|
+
export type SubagentModelWordKind = 'inherit' | 'catalog' | 'tier' | 'cc-alias' | 'best' | 'model-id' | 'passthrough' | 'catalog-unknown' | 'ambiguous' | 'unbound';
|
|
4
|
+
export type SubagentModelWordProblem = 'tiers-inert' | 'chain-unbound' | 'binding-not-in-catalog';
|
|
5
|
+
export interface SubagentModelLocalEngine {
|
|
6
|
+
readonly engine: 'started-by-this-process';
|
|
7
|
+
readonly tiers: Readonly<Record<string, string>> | undefined;
|
|
8
|
+
readonly pool?: readonly {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly id?: string;
|
|
11
|
+
}[];
|
|
12
|
+
}
|
|
13
|
+
export interface SubagentModelWordInput {
|
|
14
|
+
readonly word?: string | null | undefined;
|
|
15
|
+
readonly liveCatalog?: LiveModelCatalog | null | undefined;
|
|
16
|
+
readonly local?: SubagentModelLocalEngine | null | undefined;
|
|
17
|
+
}
|
|
18
|
+
export interface SubagentModelLanding {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly via: readonly string[];
|
|
21
|
+
readonly source: 'local-config';
|
|
22
|
+
}
|
|
23
|
+
export interface SubagentModelWordReading {
|
|
24
|
+
readonly kind: SubagentModelWordKind;
|
|
25
|
+
readonly model?: string;
|
|
26
|
+
readonly landing?: SubagentModelLanding;
|
|
27
|
+
readonly problem?: SubagentModelWordProblem;
|
|
28
|
+
readonly label?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function resolveSubagentModelWord(input: SubagentModelWordInput | null | undefined): SubagentModelWordReading;
|
|
31
|
+
export declare function subagentModelWordProblemLine(word: string, reading: SubagentModelWordReading, lang?: UiLanguage): string | undefined;
|