@sema-agent/client-core 0.110.0 → 0.112.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 +244 -0
- package/README.md +59 -18
- package/dist/abortableSleep.d.ts +7 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +25 -4
- package/dist/adapt/toolCards.d.ts +3 -1
- package/dist/adapt/toolCards.js +4 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
- package/dist/adapter/activeRunSelfHeal.js +171 -3
- package/dist/adapter/downstream/eventToSdkMessage.js +10 -10
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
- package/dist/adapter/runStream.d.ts +5 -0
- package/dist/adapter/runStream.js +15 -3
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
- package/dist/attachmentRoute.d.ts +20 -0
- package/dist/attachmentRoute.js +39 -0
- package/dist/attachmentsWireCaps.js +1 -1
- package/dist/builtinOutputStyles.d.ts +12 -0
- package/dist/builtinOutputStyles.js +147 -0
- package/dist/checkpointRowVerdict.d.ts +3 -0
- package/dist/checkpointRowVerdict.js +14 -1
- package/dist/compactionStatus.d.ts +9 -0
- package/dist/compactionStatus.js +29 -5
- package/dist/consoleCaPin.d.ts +136 -0
- package/dist/consoleCaPin.js +827 -0
- package/dist/controlRouter.js +2 -1
- package/dist/coreValuePorts.d.ts +39 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/deviceRebind.js +3 -3
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +6 -0
- package/dist/effectiveFacts.d.ts +9 -0
- package/dist/effectiveFacts.js +33 -0
- package/dist/engineAddress.d.ts +1 -0
- package/dist/engineAddress.js +4 -1
- package/dist/engineCredentialRelease.d.ts +54 -0
- package/dist/engineCredentialRelease.js +146 -0
- package/dist/engineErrorCodes.d.ts +1 -0
- package/dist/engineErrorCodes.js +1 -0
- package/dist/engineHealthProbeVerdict.d.ts +24 -0
- package/dist/engineHealthProbeVerdict.js +123 -0
- package/dist/engineNoticeCodes.js +5 -7
- package/dist/engineRepoint.d.ts +12 -5
- package/dist/engineRepoint.js +44 -19
- package/dist/engineRowRef.d.ts +3 -0
- package/dist/engineRowRef.js +11 -1
- package/dist/engineSwapCrossing.d.ts +57 -0
- package/dist/engineSwapCrossing.js +297 -0
- package/dist/engineUnavailable.d.ts +45 -0
- package/dist/engineUnavailable.js +496 -0
- package/dist/engineUrl.js +4 -2
- package/dist/eventLeg.js +3 -3
- package/dist/gateFailureCodes.js +2 -2
- package/dist/generated/sdkFactTables.d.ts +2 -1
- package/dist/generated/sdkFactTables.js +14 -0
- package/dist/generated/settingsSchemaFns.d.ts +1 -0
- package/dist/generated/settingsSchemaFns.js +3 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +38 -9
- package/dist/generated/settingsSchemaTables.d.ts +56 -0
- package/dist/generated/settingsSchemaTables.js +19 -0
- package/dist/generated/settingsSchemaTypes.d.ts +23 -13
- package/dist/generated/settingsSchemaUrlShape.d.ts +1 -0
- package/dist/generated/settingsSchemaUrlShape.js +17 -0
- package/dist/hitl/approvalDelivery.d.ts +1 -0
- package/dist/hitl/approvalDelivery.js +1 -1
- package/dist/hitl/approvalResolution.d.ts +1 -1
- package/dist/hitl/approvalResolution.js +2 -1
- package/dist/hitl/askGateWire.js +5 -6
- package/dist/hitl/decisionRefusal.d.ts +6 -0
- package/dist/hitl/decisionRefusal.js +19 -10
- package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
- package/dist/hitl/decisionRefusalCarrier.js +348 -0
- package/dist/hitl/decisionSend.d.ts +7 -0
- package/dist/hitl/decisionSend.js +34 -12
- package/dist/hitl/editedApprovalAcceptance.js +1 -1
- package/dist/hitl/elicitationRefusal.d.ts +4 -0
- package/dist/hitl/elicitationRefusal.js +23 -0
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +8 -15
- package/dist/hitl/gateIdentity.d.ts +5 -0
- package/dist/hitl/gateIdentity.js +23 -0
- package/dist/hitl/hitlBridge.d.ts +6 -0
- package/dist/hitl/hitlBridge.js +10 -4
- package/dist/hitl/hitlHostSurface.d.ts +2 -1
- package/dist/hitl/hitlHostSurface.js +7 -2
- package/dist/hitl/localAllowRedemption.d.ts +70 -0
- package/dist/hitl/localAllowRedemption.js +276 -0
- package/dist/hitl/parkOwnership.js +2 -1
- package/dist/hitl/parkResolver.js +14 -4
- package/dist/hitl/persistedRulesWire.d.ts +16 -0
- package/dist/hitl/persistedRulesWire.js +70 -0
- package/dist/hitl/planReviewWire.d.ts +3 -0
- package/dist/hitl/planReviewWire.js +23 -6
- package/dist/hitl/policyDenyCause.d.ts +1 -1
- package/dist/hitl/policyDenyCause.js +1 -1
- package/dist/hitl/resumeRunningCard.d.ts +1 -0
- package/dist/hitl/resumeRunningCard.js +1 -0
- package/dist/hitl/screenCardCarriers.d.ts +15 -0
- package/dist/hitl/screenCardCarriers.js +41 -0
- package/dist/hitl/screenDecisionCards.d.ts +98 -0
- package/dist/hitl/screenDecisionCards.js +363 -0
- package/dist/hitl/sessionPolicyWire.js +2 -2
- package/dist/hitl/standingRows.d.ts +6 -2
- package/dist/hitl/standingRows.js +27 -2
- package/dist/hitl/toolApprovalWire.d.ts +30 -8
- package/dist/hitl/toolApprovalWire.js +264 -121
- package/dist/hooksReaderGenerations.js +1 -1
- package/dist/hooksWireCaps.js +3 -3
- package/dist/hostSettingNoticeArm.d.ts +3 -0
- package/dist/hostSettingNoticeArm.js +12 -0
- package/dist/hostTurnSettings.d.ts +3 -0
- package/dist/hostTurnSettings.js +38 -5
- package/dist/humanTurnRead.js +11 -1
- package/dist/i18n/messages.en.d.ts +292 -0
- package/dist/i18n/messages.en.js +298 -7
- package/dist/i18n/messages.zh.js +316 -6
- package/dist/i18n/translate.d.ts +3 -0
- package/dist/i18n/translate.js +78 -10
- package/dist/i18n/zh.d.ts +1 -0
- package/dist/i18n/zh.js +1 -0
- package/dist/index.d.ts +71 -20
- package/dist/index.js +44 -13
- package/dist/interactiveHalt.js +2 -1
- package/dist/interactiveInterrupt.js +20 -2
- package/dist/liveModelCatalog.d.ts +4 -0
- package/dist/liveModelCatalog.js +12 -3
- package/dist/localConfig/documents.d.ts +61 -0
- package/dist/localConfig/documents.js +51 -0
- package/dist/localConfig/kernel.d.ts +149 -0
- package/dist/localConfig/kernel.js +597 -0
- package/dist/localConfig/mcp/edit.d.ts +161 -0
- package/dist/localConfig/mcp/edit.js +846 -0
- package/dist/localConfig/mcp/servers.d.ts +165 -0
- package/dist/localConfig/mcp/servers.js +776 -0
- package/dist/localConfig/mcp/views.d.ts +170 -0
- package/dist/localConfig/mcp/views.js +429 -0
- package/dist/localConfig/modelPool.d.ts +262 -0
- package/dist/localConfig/modelPool.js +1489 -0
- package/dist/localConfig/modelPoolWords.d.ts +13 -0
- package/dist/localConfig/modelPoolWords.js +20 -0
- package/dist/localConfig/receiptShape.d.ts +7 -0
- package/dist/localConfig/receiptShape.js +135 -0
- package/dist/localConfig/settingsWrite.d.ts +127 -0
- package/dist/localConfig/settingsWrite.js +237 -0
- package/dist/localConfig/skills.d.ts +124 -0
- package/dist/localConfig/skills.js +397 -0
- package/dist/localConfig/skillsWords.d.ts +10 -0
- package/dist/localConfig/skillsWords.js +5 -0
- package/dist/localEngineSeatReading.d.ts +2 -2
- package/dist/localEngineSeatReading.js +5 -3
- package/dist/localEngineSpawn.d.ts +0 -7
- package/dist/localEngineSpawn.js +0 -92
- package/dist/localEngineStep.d.ts +2 -2
- package/dist/localEngineStep.js +2 -0
- package/dist/mcpProbeWire.js +2 -1
- package/dist/mcpReconnect.js +3 -3
- package/dist/mcpWireCaps.js +1 -1
- package/dist/memoryVerbsWire.js +3 -2
- package/dist/model/engineModelWords.d.ts +3 -0
- package/dist/model/engineModelWords.js +13 -0
- package/dist/model/onboardJudgement.d.ts +14 -4
- package/dist/model/onboardJudgement.js +91 -139
- package/dist/model/subagentModelWord.d.ts +21 -2
- package/dist/model/subagentModelWord.js +100 -29
- package/dist/modelCapabilityProbe.js +3 -40
- package/dist/modelConfigGapNotice.d.ts +20 -0
- package/dist/modelConfigGapNotice.js +102 -0
- package/dist/modsKernelIdentity.js +2 -47
- package/dist/notifications.d.ts +19 -0
- package/dist/notifications.js +114 -12
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +71 -8
- package/dist/pendingUserRow.d.ts +4 -0
- package/dist/pendingUserRow.js +16 -0
- package/dist/permissionsDeclaration.d.ts +3 -1
- package/dist/permissionsDeclaration.js +33 -9
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +52 -2
- package/dist/pluginHooksWire.d.ts +9 -1
- package/dist/pluginHooksWire.js +40 -6
- package/dist/printToolResultFrame.js +4 -2
- package/dist/promptBlockedCopy.js +12 -7
- package/dist/promptSuggestionBatch.d.ts +7 -0
- package/dist/promptSuggestionBatch.js +9 -0
- package/dist/promptSuggestionsTail.d.ts +39 -0
- package/dist/promptSuggestionsTail.js +116 -0
- package/dist/request/taskRequest.js +10 -6
- package/dist/requestCoordinate.d.ts +1 -0
- package/dist/requestCoordinate.js +13 -0
- package/dist/resumeRefusalCopy.d.ts +3 -1
- package/dist/resumeRefusalCopy.js +12 -4
- package/dist/rewindArchiveReading.js +4 -4
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +1 -0
- package/dist/runLedgerSnapshot.js +3 -3
- package/dist/runPermissionModeSwitch.js +3 -4
- package/dist/scenarioRefusal.js +11 -13
- package/dist/scenarioSkills.js +11 -6
- package/dist/seam.d.ts +16 -2
- package/dist/seam.js +10 -0
- package/dist/seatContract.d.ts +259 -9
- package/dist/seatContract.js +444 -15
- package/dist/sessionCostReading.d.ts +70 -0
- package/dist/sessionCostReading.js +150 -0
- package/dist/sessionHooksRoster.d.ts +4 -0
- package/dist/sessionHooksRoster.js +158 -0
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +4 -1
- package/dist/sessionMemoryErase.js +2 -1
- package/dist/sessionMemoryStatus.js +2 -2
- package/dist/sessionReadRedaction.d.ts +7 -0
- package/dist/sessionReadRedaction.js +26 -0
- package/dist/sessionSyncFileHistory.js +8 -9
- package/dist/settingsHooksSalvage.js +2 -1
- package/dist/sha256Bytes.d.ts +1 -0
- package/dist/sha256Bytes.js +46 -0
- package/dist/skillOverrideChain.d.ts +83 -0
- package/dist/skillOverrideChain.js +378 -0
- package/dist/skillsWireCaps.d.ts +3 -0
- package/dist/skillsWireCaps.js +16 -1
- package/dist/sseIdleTriage.js +2 -1
- package/dist/storeDurabilityWord.d.ts +15 -0
- package/dist/storeDurabilityWord.js +18 -0
- package/dist/storePostureCapability.d.ts +7 -3
- package/dist/storePostureCapability.js +69 -39
- package/dist/subagent/engineSubagentResume.js +2 -2
- package/dist/subagent/engineSubagentTail.js +2 -1
- package/dist/subagentContentStore.d.ts +11 -0
- package/dist/subagentContentStore.js +28 -2
- package/dist/toolResult.d.ts +1 -0
- package/dist/toolResult.js +2 -0
- package/dist/turnFailurePresentation.js +4 -10
- package/dist/userAttachmentEnvelope.d.ts +2 -1
- package/dist/userAttachmentEnvelope.js +10 -0
- package/dist/wireErrorTriage.js +2 -1
- package/dist/wireFailureShape.d.ts +4 -0
- package/dist/wireFailureShape.js +141 -19
- package/dist/wireRefusalCopy.d.ts +6 -5
- package/dist/wireRefusalCopy.js +49 -92
- package/docs/INTEGRATION-CLIENTS.md +2718 -17
- package/package.json +7 -3
package/dist/mcpWireCaps.js
CHANGED
|
@@ -448,6 +448,6 @@ export function mcpAssertionHeaderNotSentNotice(specs) {
|
|
|
448
448
|
const parts = distinct.slice(0, ASSERTION_NOTICE_NAMES_SHOWN).map((x) => `"${x}"`);
|
|
449
449
|
if (distinct.length > ASSERTION_NOTICE_NAMES_SHOWN)
|
|
450
450
|
parts.push(`+${distinct.length - ASSERTION_NOTICE_NAMES_SHOWN} more`);
|
|
451
|
-
return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.
|
|
451
|
+
return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.149.0 accept this setting but do not send the header, ` +
|
|
452
452
|
'and this client cannot tell whether the engine it uses sends it; a connector that requires the header will refuse requests from these servers');
|
|
453
453
|
}
|
package/dist/memoryVerbsWire.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { wireFailureShapeOf } from './wireFailureShape.js';
|
|
2
|
+
import { CAPABILITY_OPERATOR_PRINCIPALS_REQUIRED, MEMORY_CONTROL_PLANE_CORRUPT } from './engineErrorCodes.js';
|
|
2
3
|
import { memoryComplianceVerbsAvailable } from './memoryComplianceCapability.js';
|
|
3
4
|
import { memoryOriginVerbsAvailable } from './memoryOriginCapability.js';
|
|
4
5
|
import { readMemoryEraseReceipt, readMemoryOriginClearanceReceipt } from './memoryEntriesWire.js';
|
|
@@ -53,7 +54,7 @@ export function classifyMemoryFailure(e) {
|
|
|
53
54
|
return refusedBy('unauthorized', message);
|
|
54
55
|
case 'auth.operator_only':
|
|
55
56
|
return refusedBy('operator_only', message);
|
|
56
|
-
case
|
|
57
|
+
case CAPABILITY_OPERATOR_PRINCIPALS_REQUIRED:
|
|
57
58
|
return refusedBy('operators_unconfigured', message);
|
|
58
59
|
case 'auth.service_token_required':
|
|
59
60
|
return refusedBy('service_token_required', message);
|
|
@@ -94,7 +95,7 @@ export function classifyMemoryFailure(e) {
|
|
|
94
95
|
case 'memory.target_outside_store':
|
|
95
96
|
case 'memory.scope_home_not_directory':
|
|
96
97
|
return unknownBy('store_form_refused', message);
|
|
97
|
-
case
|
|
98
|
+
case MEMORY_CONTROL_PLANE_CORRUPT:
|
|
98
99
|
return unknownBy('control_plane_corrupt', message);
|
|
99
100
|
default:
|
|
100
101
|
break;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CC_TIER_ALIASES, TIER_ORDER } from './tierVocabulary.js';
|
|
2
|
+
export const ENGINE_MODEL_WORDS = Object.freeze([...TIER_ORDER, ...Object.keys(CC_TIER_ALIASES), 'best', 'default']);
|
|
3
|
+
export function engineModelWordKindOf(word) {
|
|
4
|
+
if (typeof word !== 'string')
|
|
5
|
+
return undefined;
|
|
6
|
+
if (TIER_ORDER.includes(word))
|
|
7
|
+
return 'tier';
|
|
8
|
+
if (Object.hasOwn(CC_TIER_ALIASES, word))
|
|
9
|
+
return 'cc-alias';
|
|
10
|
+
if (word === 'best')
|
|
11
|
+
return 'best';
|
|
12
|
+
return word === 'default' ? 'default' : undefined;
|
|
13
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { OnboardCatalogIssue, OnboardProbeResult, OnboardProbeVerdict, OnboardRefusal } from '../seatContract.js';
|
|
1
|
+
import { type ModelApiWord } from './providerPresets.js';
|
|
2
|
+
import type { ModelDiscoveryResult, OnboardCatalogIssue, OnboardProbeResult, OnboardProbeVerdict, OnboardRefusal } from '../seatContract.js';
|
|
3
|
+
import type { SettingsDocument } from '../host.js';
|
|
3
4
|
import { type ModelProbeResult } from '../modelCapabilityProbe.js';
|
|
4
5
|
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
6
|
+
export declare function onboardKeyCarriedBy(text: string, key: string | undefined): boolean;
|
|
7
|
+
export declare function onboardRedactKey(text: string, key: string | undefined): string;
|
|
5
8
|
export declare function onboardBaseUrlProblem(url: string, lang?: UiLanguage): string | undefined;
|
|
6
9
|
export interface OnboardProbeTarget {
|
|
7
10
|
readonly baseUrl: string;
|
|
@@ -42,6 +45,13 @@ export interface OnboardProbeDeps {
|
|
|
42
45
|
readonly firstTokenMs?: number | undefined;
|
|
43
46
|
}
|
|
44
47
|
export declare function probeModelEndpoint(target: OnboardProbeTarget, deps?: OnboardProbeDeps): Promise<OnboardProbeResult>;
|
|
48
|
+
export interface OnboardDiscoveryTarget {
|
|
49
|
+
readonly baseUrl: string;
|
|
50
|
+
readonly api: ModelApiWord;
|
|
51
|
+
readonly apiKey?: string | undefined;
|
|
52
|
+
readonly auth?: 'bearer' | 'x-api-key' | undefined;
|
|
53
|
+
}
|
|
54
|
+
export declare function discoverEndpointModels(target: OnboardDiscoveryTarget, deps?: OnboardProbeDeps): Promise<ModelDiscoveryResult>;
|
|
45
55
|
export type OnboardWriteVerdict = {
|
|
46
56
|
readonly write: true;
|
|
47
57
|
readonly unverified: boolean;
|
|
@@ -49,10 +59,11 @@ export type OnboardWriteVerdict = {
|
|
|
49
59
|
readonly write: false;
|
|
50
60
|
readonly refusal: 'probe_failed' | 'probe_unverified';
|
|
51
61
|
};
|
|
52
|
-
export declare function onboardWriteVerdict(verdict: OnboardProbeVerdict, acceptUnverified?: boolean): OnboardWriteVerdict;
|
|
62
|
+
export declare function onboardWriteVerdict(verdict: OnboardProbeVerdict | undefined, acceptUnverified?: boolean): OnboardWriteVerdict;
|
|
53
63
|
export declare const KEY_SLOT_PREFIX = "SEMA_MODEL_KEY_";
|
|
54
64
|
export declare function keyEnvNameForEntry(entryName: string): string;
|
|
55
65
|
export declare function poolEntryNameOf(modelId: string, channel: string, taken: ReadonlySet<string>): string;
|
|
66
|
+
export declare function onboardEntryCredentialIssue(m: SettingsDocument, env: Readonly<Record<string, string | undefined>>): string | undefined;
|
|
56
67
|
export interface OnboardPlanEntry {
|
|
57
68
|
readonly modelId: string;
|
|
58
69
|
readonly api: ModelApiWord;
|
|
@@ -90,5 +101,4 @@ export type OnboardWritePlan = {
|
|
|
90
101
|
readonly refusal: Extract<OnboardRefusal, 'input' | 'catalog_unreadable' | 'credential_unpaired' | 'engine_is_remote' | 'env_catalog_present'>;
|
|
91
102
|
readonly detail: string;
|
|
92
103
|
};
|
|
93
|
-
export declare function onboardWritePlan(input: OnboardWritePlanInput): OnboardWritePlan;
|
|
94
104
|
export declare function onboardRefusalText(refusal: OnboardRefusal, lang?: UiLanguage): string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { inferFamily } from './providerPresets.js';
|
|
1
2
|
import { ONBOARD_REFUSALS } from '../seatContract.js';
|
|
2
|
-
import { joinRequestUrl, routeKeyOf } from '../coreValuePorts.js';
|
|
3
|
-
import {
|
|
3
|
+
import { adjudicateModelRoute, joinRequestUrl, routeKeyOf } from '../coreValuePorts.js';
|
|
4
|
+
import { settleWithinDeadline } from '../abortableSleep.js';
|
|
5
|
+
import { probeModelLiveness, probeVerdictNotice } from '../modelCapabilityProbe.js';
|
|
4
6
|
import { ownDataField } from '../ownKey.js';
|
|
5
7
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
6
8
|
const field = (v, key) => {
|
|
@@ -57,6 +59,9 @@ function safeDecode(t) {
|
|
|
57
59
|
return t;
|
|
58
60
|
}
|
|
59
61
|
}
|
|
62
|
+
export function onboardKeyCarriedBy(text, key) {
|
|
63
|
+
return carriesKey(text, key);
|
|
64
|
+
}
|
|
60
65
|
function carriesKey(text, key) {
|
|
61
66
|
if (key === undefined || key === '')
|
|
62
67
|
return false;
|
|
@@ -69,6 +74,9 @@ function carriesKey(text, key) {
|
|
|
69
74
|
function looksLikeSecret(val) {
|
|
70
75
|
return /^(sk|ak|pk|rk)[-_]/i.test(val) || (val.length >= 20 && /[A-Za-z]/.test(val) && /[0-9]/.test(val) && /^[A-Za-z0-9._~+/=-]+$/.test(val));
|
|
71
76
|
}
|
|
77
|
+
export function onboardRedactKey(text, key) {
|
|
78
|
+
return redact(text, key);
|
|
79
|
+
}
|
|
72
80
|
function redact(text, key) {
|
|
73
81
|
if (key === undefined || key === '')
|
|
74
82
|
return text;
|
|
@@ -197,7 +205,71 @@ export async function probeModelEndpoint(target, deps) {
|
|
|
197
205
|
});
|
|
198
206
|
if (v.verdict === 'unreachable' && seen.redirected !== undefined)
|
|
199
207
|
return out('unreachable', seen.redirected);
|
|
200
|
-
|
|
208
|
+
const firstOutputMs = v.verdict === 'ok' && typeof v.waitedMs === 'number' && Number.isFinite(v.waitedMs) && v.waitedMs >= 0 ? Math.round(v.waitedMs) : undefined;
|
|
209
|
+
const r = out(v.verdict, probeDetailOf(v));
|
|
210
|
+
return firstOutputMs === undefined ? r : Object.freeze({ ...r, firstOutputMs });
|
|
211
|
+
}
|
|
212
|
+
const DISCOVERY_MAX = 512;
|
|
213
|
+
export async function discoverEndpointModels(target, deps) {
|
|
214
|
+
const apiKey = field(target, 'apiKey');
|
|
215
|
+
const key = typeof apiKey === 'string' && apiKey !== '' ? apiKey : undefined;
|
|
216
|
+
const fail = (verdict, detail) => Object.freeze({ ok: false, verdict, detail: capText(redact(detail, key?.trim() || undefined)) });
|
|
217
|
+
const baseUrl = field(target, 'baseUrl');
|
|
218
|
+
const api = field(target, 'api');
|
|
219
|
+
const auth = field(target, 'auth');
|
|
220
|
+
if (typeof baseUrl !== 'string' || (api !== 'anthropic-messages' && api !== 'openai-completions'))
|
|
221
|
+
return fail('other', en('onboard.probe.incomplete'));
|
|
222
|
+
const f = (field(deps, 'fetchImpl') ?? globalThis.fetch);
|
|
223
|
+
if (typeof f !== 'function')
|
|
224
|
+
return fail('unreachable', en('onboard.probe.noFetch'));
|
|
225
|
+
const root = baseUrl.trim();
|
|
226
|
+
let url;
|
|
227
|
+
try {
|
|
228
|
+
url = joinRequestUrl(root, 'models');
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return fail('other', en('onboard.baseUrl.invalid'));
|
|
232
|
+
}
|
|
233
|
+
if (url === undefined)
|
|
234
|
+
return fail('other', en('onboard.probe.judgeAbsent'));
|
|
235
|
+
const t = field(deps, 'timeoutMs');
|
|
236
|
+
const budget = typeof t === 'number' && Number.isFinite(t) && t > 0 ? t : 10_000;
|
|
237
|
+
const headers = { ...(api === 'anthropic-messages' ? { 'anthropic-version': '2023-06-01' } : {}), ...keyHeaders(api, key, auth === 'bearer' || auth === 'x-api-key' ? auth : undefined) };
|
|
238
|
+
const settled = await settleWithinDeadline(budget, async (signal) => {
|
|
239
|
+
const res = await f(url, { method: 'GET', headers, redirect: 'manual', signal });
|
|
240
|
+
const redirected = redirectRefusal(res, url, key);
|
|
241
|
+
if (redirected !== undefined)
|
|
242
|
+
return fail('unreachable', redirected);
|
|
243
|
+
if (res.status === 401 || res.status === 403)
|
|
244
|
+
return fail('auth', en('model.pool.discover.status', { status: res.status }));
|
|
245
|
+
if (res.status < 200 || res.status >= 300)
|
|
246
|
+
return fail('other', en('model.pool.discover.status', { status: res.status }));
|
|
247
|
+
let body;
|
|
248
|
+
try {
|
|
249
|
+
body = JSON.parse(await res.text());
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return fail('shape', en('model.pool.discover.notList'));
|
|
253
|
+
}
|
|
254
|
+
const data = field(body, 'data');
|
|
255
|
+
if (!Array.isArray(data))
|
|
256
|
+
return fail('shape', en('model.pool.discover.notList'));
|
|
257
|
+
const out = [];
|
|
258
|
+
for (let i = 0; i < data.length && out.length < DISCOVERY_MAX; i++) {
|
|
259
|
+
const id = field(field(data, String(i)), 'id');
|
|
260
|
+
if (typeof id !== 'string' || id.trim() === '' || id.length > 512 || carriesKey(id, key) || out.some((c) => c.id === id))
|
|
261
|
+
continue;
|
|
262
|
+
const fam = inferFamily(id);
|
|
263
|
+
const exact = fam !== undefined && fam.perModelCap !== undefined;
|
|
264
|
+
out.push(Object.freeze({ id, ...(exact ? { contextWindow: fam.contextWindow, maxTokens: fam.maxTokens } : {}) }));
|
|
265
|
+
}
|
|
266
|
+
return Object.freeze({ ok: true, candidates: Object.freeze(out) });
|
|
267
|
+
});
|
|
268
|
+
if (settled.kind === 'deadline')
|
|
269
|
+
return fail('unreachable', en('model.pool.discover.timeout'));
|
|
270
|
+
if (settled.kind === 'error')
|
|
271
|
+
return fail('unreachable', en('model.pool.discover.unreachable', { cause: settled.detail }));
|
|
272
|
+
return settled.value;
|
|
201
273
|
}
|
|
202
274
|
export function onboardWriteVerdict(verdict, acceptUnverified) {
|
|
203
275
|
if (verdict === 'ok')
|
|
@@ -224,6 +296,9 @@ export function poolEntryNameOf(modelId, channel, taken) {
|
|
|
224
296
|
candidate = `${name}-${channel}-${i}`;
|
|
225
297
|
return candidate;
|
|
226
298
|
}
|
|
299
|
+
export function onboardEntryCredentialIssue(m, env) {
|
|
300
|
+
return entryCredentialIssue(m, env);
|
|
301
|
+
}
|
|
227
302
|
function entryCredentialIssue(m, env) {
|
|
228
303
|
const name = typeof m['name'] === 'string' ? m['name'] : '?';
|
|
229
304
|
if (m['sealedApiKey'] !== undefined && m['sealedApiKey'] !== null)
|
|
@@ -239,6 +314,19 @@ function entryCredentialIssue(m, env) {
|
|
|
239
314
|
const api = typeof m['api'] === 'string' ? m['api'] : 'openai-completions';
|
|
240
315
|
const rootKey = api === 'anthropic-messages' ? 'ANTHROPIC_BASE_URL' : 'MODEL_GATEWAY_BASEURL';
|
|
241
316
|
const root = env[rootKey];
|
|
317
|
+
if (api !== 'anthropic-messages' && (typeof root !== 'string' || root.trim() === '')) {
|
|
318
|
+
let keyless;
|
|
319
|
+
try {
|
|
320
|
+
keyless = adjudicateModelRoute({ id: typeof m['id'] === 'string' ? m['id'] : name, baseUrl: base }, { source: 'absent' }, {});
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
keyless = undefined;
|
|
324
|
+
}
|
|
325
|
+
if (keyless === undefined)
|
|
326
|
+
return en('onboard.catalog.judgeAbsent', { name });
|
|
327
|
+
if (keyless.ok)
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
242
330
|
let paired;
|
|
243
331
|
try {
|
|
244
332
|
const a = routeKeyOf(base);
|
|
@@ -262,142 +350,6 @@ function entryCredentialIssue(m, env) {
|
|
|
262
350
|
const rootText = typeof root === 'string' && root !== '' ? `${rootKey} (${hostOf(root)})` : en('onboard.catalog.noRoot', { rootKey });
|
|
263
351
|
return en('onboard.catalog.unpaired', { name, host: hostOf(base), root: rootText });
|
|
264
352
|
}
|
|
265
|
-
function migrateLegacyDefaultKey(doc) {
|
|
266
|
-
const legacy = doc['default'];
|
|
267
|
-
if (typeof legacy !== 'string' || legacy.length === 0)
|
|
268
|
-
return doc;
|
|
269
|
-
const { default: _legacy, ...rest } = doc;
|
|
270
|
-
void _legacy;
|
|
271
|
-
const prevRoles = rest['roles'];
|
|
272
|
-
const roles = prevRoles !== null && typeof prevRoles === 'object' && !Array.isArray(prevRoles) ? { ...prevRoles } : {};
|
|
273
|
-
roles['default'] = { model: legacy };
|
|
274
|
-
return { ...rest, roles };
|
|
275
|
-
}
|
|
276
|
-
export function onboardWritePlan(input) {
|
|
277
|
-
const rawKey = field(field(input, 'entry'), 'apiKey');
|
|
278
|
-
const planKey = typeof rawKey === 'string' && rawKey !== '' ? rawKey : undefined;
|
|
279
|
-
const say = (text) => redact(text, planKey);
|
|
280
|
-
const refuse = (refusal, detail) => Object.freeze({ ok: false, refusal, detail: say(detail) });
|
|
281
|
-
try {
|
|
282
|
-
if (input.engineMode === 'cloud')
|
|
283
|
-
return refuse('engine_is_remote', en('onboard.refusal.engineIsRemote'));
|
|
284
|
-
const rawDoc = input.modelsDoc;
|
|
285
|
-
if (rawDoc !== undefined && (rawDoc === null || typeof rawDoc !== 'object' || Array.isArray(rawDoc)))
|
|
286
|
-
return refuse('catalog_unreadable', en('onboard.plan.notObject'));
|
|
287
|
-
const doc = migrateLegacyDefaultKey(rawDoc === undefined ? {} : { ...rawDoc });
|
|
288
|
-
const rawModels = doc['models'];
|
|
289
|
-
if (rawModels !== undefined && !Array.isArray(rawModels))
|
|
290
|
-
return refuse('catalog_unreadable', en('onboard.plan.modelsNotList'));
|
|
291
|
-
const list = Array.isArray(rawModels) ? rawModels : [];
|
|
292
|
-
if (list.some((m) => m === null || typeof m !== 'object' || Array.isArray(m)))
|
|
293
|
-
return refuse('catalog_unreadable', en('onboard.plan.modelsItemNotObject'));
|
|
294
|
-
const models = list.map((m) => ({ ...m }));
|
|
295
|
-
const envModel = [input.effectiveEnv?.['MODEL_ID'], input.effectiveEnv?.['MODEL_CHEAP_ID']].find((v) => typeof v === 'string' && v.trim() !== '');
|
|
296
|
-
if (envModel !== undefined && !models.some((m) => m['enabled'] !== false)) {
|
|
297
|
-
return refuse('env_catalog_present', en('onboard.plan.envCatalogPresent', { model: envModel }));
|
|
298
|
-
}
|
|
299
|
-
const rawEnv = input.settingsEnv;
|
|
300
|
-
if (rawEnv !== undefined && (rawEnv === null || typeof rawEnv !== 'object' || Array.isArray(rawEnv)))
|
|
301
|
-
return refuse('catalog_unreadable', en('onboard.plan.envNotObject'));
|
|
302
|
-
const prevEnv = rawEnv === undefined ? {} : { ...rawEnv };
|
|
303
|
-
const e = input.entry;
|
|
304
|
-
const isShellSlot = (ref) => typeof ref === 'string' && ref.startsWith(KEY_SLOT_PREFIX) && typeof prevEnv[ref] === 'string';
|
|
305
|
-
const targetKey = routeKeyOf(e.baseUrl);
|
|
306
|
-
if (targetKey === undefined)
|
|
307
|
-
return refuse('credential_unpaired', en('onboard.catalog.judgeAbsent', { name: e.modelId }));
|
|
308
|
-
const sameTarget = (m) => m['id'] === e.modelId && m['api'] === e.api && typeof m['baseUrl'] === 'string' && routeKeyOf(m['baseUrl']) === targetKey;
|
|
309
|
-
const existingIdx = models.findIndex((m) => sameTarget(m) && m['enabled'] !== false && m['sealedApiKey'] === undefined && (m['apiKeyEnv'] === undefined || isShellSlot(m['apiKeyEnv'])));
|
|
310
|
-
const taken = new Set(models.map((m) => (typeof m['name'] === 'string' ? m['name'] : '')).filter((n) => n !== ''));
|
|
311
|
-
const name = existingIdx >= 0 ? String(models[existingIdx]['name']) : poolEntryNameOf(e.modelId, e.channel, taken);
|
|
312
|
-
const existingRef = existingIdx >= 0 ? models[existingIdx]['apiKeyEnv'] : undefined;
|
|
313
|
-
const sharedByOther = typeof existingRef === 'string' &&
|
|
314
|
-
models.some((m, i) => i !== existingIdx && typeof m['apiKeyEnv'] === 'string' && m['apiKeyEnv'].toUpperCase() === existingRef.toUpperCase());
|
|
315
|
-
let keyEnv;
|
|
316
|
-
if (isShellSlot(existingRef) && !sharedByOther) {
|
|
317
|
-
keyEnv = existingRef;
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
const used = new Set();
|
|
321
|
-
for (const m of models)
|
|
322
|
-
if (typeof m['apiKeyEnv'] === 'string')
|
|
323
|
-
used.add(m['apiKeyEnv'].toUpperCase());
|
|
324
|
-
for (const k of Object.keys(prevEnv))
|
|
325
|
-
used.add(k.toUpperCase());
|
|
326
|
-
for (const [k, v] of Object.entries(input.effectiveEnv ?? {}))
|
|
327
|
-
if (typeof v === 'string')
|
|
328
|
-
used.add(k.toUpperCase());
|
|
329
|
-
const baseSlot = keyEnvNameForEntry(name);
|
|
330
|
-
keyEnv = baseSlot;
|
|
331
|
-
for (let i = 2; used.has(keyEnv.toUpperCase()); i++)
|
|
332
|
-
keyEnv = `${baseSlot}_${i}`;
|
|
333
|
-
}
|
|
334
|
-
if (carriesKey(name, e.apiKey) || carriesKey(keyEnv, e.apiKey))
|
|
335
|
-
return refuse('input', en('onboard.input.keyInFields'));
|
|
336
|
-
const base = existingIdx >= 0 ? models[existingIdx] : {};
|
|
337
|
-
let entry = {
|
|
338
|
-
...base,
|
|
339
|
-
name,
|
|
340
|
-
id: e.modelId,
|
|
341
|
-
provider: e.api === 'anthropic-messages' ? 'anthropic' : 'gateway',
|
|
342
|
-
api: e.api,
|
|
343
|
-
baseUrl: e.baseUrl,
|
|
344
|
-
contextWindow: typeof base['contextWindow'] === 'number' ? base['contextWindow'] : e.contextWindow,
|
|
345
|
-
maxTokens: typeof base['maxTokens'] === 'number' ? base['maxTokens'] : e.maxTokens,
|
|
346
|
-
apiKeyEnv: keyEnv,
|
|
347
|
-
semaChannel: typeof base['semaChannel'] === 'string' ? base['semaChannel'] : e.channel,
|
|
348
|
-
semaLabel: typeof base['semaLabel'] === 'string' ? base['semaLabel'] : e.providerName,
|
|
349
|
-
semaProbe: input.probe.verdict,
|
|
350
|
-
semaProbeAt: input.now,
|
|
351
|
-
};
|
|
352
|
-
if (input.thinking !== undefined) {
|
|
353
|
-
const probed = applyProbeToEntry({ ...(typeof entry['reasoning'] === 'boolean' ? { reasoning: entry['reasoning'] } : {}), ...(entry['compat'] !== undefined ? { compat: entry['compat'] } : {}) }, input.thinking);
|
|
354
|
-
const next = { ...entry };
|
|
355
|
-
if (typeof probed.reasoning === 'boolean')
|
|
356
|
-
next['reasoning'] = probed.reasoning;
|
|
357
|
-
if (probed.compat !== undefined)
|
|
358
|
-
next['compat'] = probed.compat;
|
|
359
|
-
else
|
|
360
|
-
delete next['compat'];
|
|
361
|
-
entry = next;
|
|
362
|
-
}
|
|
363
|
-
const envView = { ...input.effectiveEnv, [keyEnv]: e.apiKey };
|
|
364
|
-
const issue = entryCredentialIssue(entry, envView);
|
|
365
|
-
if (issue !== undefined)
|
|
366
|
-
return refuse('credential_unpaired', issue);
|
|
367
|
-
if (existingIdx >= 0)
|
|
368
|
-
models[existingIdx] = entry;
|
|
369
|
-
else
|
|
370
|
-
models.push(entry);
|
|
371
|
-
const nextDoc = { ...doc, models };
|
|
372
|
-
if (input.makeDefault) {
|
|
373
|
-
const prevRoles = doc['roles'];
|
|
374
|
-
const roles = prevRoles !== null && typeof prevRoles === 'object' && !Array.isArray(prevRoles) ? { ...prevRoles } : {};
|
|
375
|
-
roles['default'] = { model: name };
|
|
376
|
-
nextDoc['roles'] = roles;
|
|
377
|
-
}
|
|
378
|
-
const otherIssues = [];
|
|
379
|
-
for (const m of models) {
|
|
380
|
-
if (m['enabled'] === false || m['name'] === name)
|
|
381
|
-
continue;
|
|
382
|
-
const other = entryCredentialIssue(m, envView);
|
|
383
|
-
if (other !== undefined) {
|
|
384
|
-
otherIssues.push(Object.freeze({ name: typeof m['name'] === 'string' ? m['name'] : '?', modelId: typeof m['id'] === 'string' ? m['id'] : '?', issue: say(other) }));
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
return Object.freeze({
|
|
388
|
-
ok: true,
|
|
389
|
-
entryName: name,
|
|
390
|
-
keyEnv,
|
|
391
|
-
updatedExisting: existingIdx >= 0,
|
|
392
|
-
nextModelsDoc: nextDoc,
|
|
393
|
-
nextSettingsEnv: { ...prevEnv, [keyEnv]: e.apiKey },
|
|
394
|
-
otherIssues: Object.freeze(otherIssues),
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
catch {
|
|
398
|
-
return refuse('input', en('onboard.refusal.input'));
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
353
|
const REFUSAL_KEYS = {
|
|
402
354
|
input: 'onboard.refusal.input',
|
|
403
355
|
probe_failed: 'onboard.refusal.probeFailed',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type LiveModelCatalog } from '../liveModelCatalog.js';
|
|
2
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';
|
|
3
|
+
export type SubagentModelWordKind = 'inherit' | 'catalog' | 'tier' | 'cc-alias' | 'best' | 'default' | 'model-id' | 'passthrough' | 'catalog-unknown' | 'ambiguous' | 'unbound';
|
|
4
4
|
export type SubagentModelWordProblem = 'tiers-inert' | 'chain-unbound' | 'binding-not-in-catalog';
|
|
5
5
|
export interface SubagentModelLocalEngine {
|
|
6
|
-
readonly engine: 'started-by-this-process';
|
|
6
|
+
readonly engine: 'reads-this-config' | 'started-by-this-process';
|
|
7
7
|
readonly tiers: Readonly<Record<string, string>> | undefined;
|
|
8
8
|
readonly pool?: readonly {
|
|
9
9
|
readonly name: string;
|
|
@@ -29,3 +29,22 @@ export interface SubagentModelWordReading {
|
|
|
29
29
|
}
|
|
30
30
|
export declare function resolveSubagentModelWord(input: SubagentModelWordInput | null | undefined): SubagentModelWordReading;
|
|
31
31
|
export declare function subagentModelWordProblemLine(word: string, reading: SubagentModelWordReading, lang?: UiLanguage): string | undefined;
|
|
32
|
+
export declare function subagentModelCallRefusalReason(word: string, reading: SubagentModelWordReading, lang?: UiLanguage): string | undefined;
|
|
33
|
+
export type SubagentModelAdmission = {
|
|
34
|
+
readonly verdict: 'accepted';
|
|
35
|
+
readonly why: 'not_sent';
|
|
36
|
+
} | {
|
|
37
|
+
readonly verdict: 'accepted';
|
|
38
|
+
readonly why: 'served';
|
|
39
|
+
readonly model: string;
|
|
40
|
+
} | {
|
|
41
|
+
readonly verdict: 'refused';
|
|
42
|
+
readonly why: 'not_listed' | 'not_served' | 'disabled';
|
|
43
|
+
readonly model: string;
|
|
44
|
+
} | {
|
|
45
|
+
readonly verdict: 'unknown';
|
|
46
|
+
readonly why: 'catalog_absent' | 'catalog_unreadable' | 'catalog_incomplete' | 'reserved_word';
|
|
47
|
+
readonly model: string;
|
|
48
|
+
};
|
|
49
|
+
export declare function subagentModelAdmissionOf(input: SubagentModelWordInput | null | undefined): SubagentModelAdmission;
|
|
50
|
+
export declare function subagentModelAdmissionLine(word: string, admission: SubagentModelAdmission, lang?: UiLanguage): string | undefined;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { CC_TIER_ALIASES, TIER_ORDER } from './tierVocabulary.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ENGINE_MODEL_WORDS, engineModelWordKindOf } from './engineModelWords.js';
|
|
3
|
+
import { liveModelRowsOf, modelAcceptanceOf } from '../liveModelCatalog.js';
|
|
3
4
|
import { quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
4
5
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
5
|
-
const
|
|
6
|
+
const READS_THIS_CONFIG = 'reads-this-config';
|
|
7
|
+
const LEGACY_LOCAL_ENGINE_WORD = 'started-by-this-process';
|
|
6
8
|
function ownData(v, key) {
|
|
7
9
|
if (v === null || typeof v !== 'object')
|
|
8
10
|
return undefined;
|
|
@@ -46,7 +48,8 @@ function localOf(input) {
|
|
|
46
48
|
const local = ownData(input, 'local');
|
|
47
49
|
if (local === null || typeof local !== 'object')
|
|
48
50
|
return undefined;
|
|
49
|
-
|
|
51
|
+
const engine = ownData(local, 'engine');
|
|
52
|
+
return engine === READS_THIS_CONFIG || engine === LEGACY_LOCAL_ENGINE_WORD ? local : undefined;
|
|
50
53
|
}
|
|
51
54
|
function catalogOf(input, local) {
|
|
52
55
|
const live = ownData(input, 'liveCatalog');
|
|
@@ -115,14 +118,7 @@ function tiersOf(local) {
|
|
|
115
118
|
}
|
|
116
119
|
return out;
|
|
117
120
|
}
|
|
118
|
-
const
|
|
119
|
-
function builtinKindOf(w) {
|
|
120
|
-
if (TIER_ORDER.includes(w))
|
|
121
|
-
return 'tier';
|
|
122
|
-
if (Object.hasOwn(CC_TIER_ALIASES, w))
|
|
123
|
-
return 'cc-alias';
|
|
124
|
-
return w === 'best' ? 'best' : undefined;
|
|
125
|
-
}
|
|
121
|
+
const builtinKindOf = engineModelWordKindOf;
|
|
126
122
|
class BrokenBinding {
|
|
127
123
|
}
|
|
128
124
|
function landingOf(word, kind, tiers, cat) {
|
|
@@ -203,21 +199,22 @@ function resolveIn(input) {
|
|
|
203
199
|
return { kind, model: w, landing: { name: l.name, via: l.via, source: 'local-config' }, label: `${l.name} (${label})` };
|
|
204
200
|
};
|
|
205
201
|
const asCatalog = (name) => ({ kind: 'catalog', model: name, label: name });
|
|
202
|
+
const asDefault = (w) => ({ kind: 'default', model: w, label: w });
|
|
203
|
+
const vocab = (w, b) => (b === 'default' ? asDefault(w) : tierClass(w, b));
|
|
206
204
|
const classify = (k) => {
|
|
207
205
|
if (cat?.nameSet.has(k))
|
|
208
206
|
return asCatalog(k);
|
|
209
|
-
|
|
210
|
-
return tierClass(k, b ?? 'tier');
|
|
207
|
+
return vocab(k, builtinKindOf(k) ?? 'tier');
|
|
211
208
|
};
|
|
212
209
|
if (cat?.nameSet.has(word))
|
|
213
210
|
return freezeReading(asCatalog(word));
|
|
214
211
|
const exact = builtinKindOf(word);
|
|
215
212
|
if (exact !== undefined)
|
|
216
|
-
return freezeReading(
|
|
213
|
+
return freezeReading(vocab(word, exact));
|
|
217
214
|
if (tiers?.has(word))
|
|
218
215
|
return freezeReading(tierClass(word, 'tier'));
|
|
219
216
|
const lower = word.toLowerCase();
|
|
220
|
-
const space = new Set([...(cat?.names ?? []), ...
|
|
217
|
+
const space = new Set([...(cat?.names ?? []), ...ENGINE_MODEL_WORDS, ...customTierKeys]);
|
|
221
218
|
const ciMatches = [...space].filter((k) => k.toLowerCase() === lower);
|
|
222
219
|
if (builtinKindOf(lower) !== undefined) {
|
|
223
220
|
return freezeReading(ciMatches.length === 1 ? classify(ciMatches[0]) : { kind: 'ambiguous' });
|
|
@@ -241,21 +238,95 @@ export function resolveSubagentModelWord(input) {
|
|
|
241
238
|
return freezeReading(word === '' ? { kind: 'inherit' } : { kind: 'catalog-unknown', model: word, label: word });
|
|
242
239
|
}
|
|
243
240
|
}
|
|
244
|
-
|
|
245
|
-
const ref = problemRefOf(word, reading);
|
|
246
|
-
return ref === undefined ? undefined : renderMessage(ref, lang);
|
|
247
|
-
}
|
|
248
|
-
function problemRefOf(word, reading) {
|
|
241
|
+
function wordCauseOf(reading) {
|
|
249
242
|
const kind = ownData(reading, 'kind');
|
|
250
|
-
if (kind !== 'unbound' && kind !== 'ambiguous')
|
|
251
|
-
return undefined;
|
|
252
|
-
const quoted = quoteUntrustedForSentence(typeof word === 'string' ? word.trim() : '', 80) ?? '""';
|
|
253
243
|
if (kind === 'ambiguous')
|
|
254
|
-
return
|
|
244
|
+
return 'ambiguous';
|
|
245
|
+
if (kind !== 'unbound')
|
|
246
|
+
return undefined;
|
|
255
247
|
const problem = ownData(reading, 'problem');
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
248
|
+
return problem === 'tiers-inert' || problem === 'binding-not-in-catalog' ? problem : 'chain-unbound';
|
|
249
|
+
}
|
|
250
|
+
const PROBLEM_LINE_KEYS = Object.freeze({
|
|
251
|
+
ambiguous: 'model.subagent.ambiguous',
|
|
252
|
+
'tiers-inert': 'model.subagent.tiersInert',
|
|
253
|
+
'chain-unbound': 'model.subagent.chainUnbound',
|
|
254
|
+
'binding-not-in-catalog': 'model.subagent.bindingNotInCatalog',
|
|
255
|
+
});
|
|
256
|
+
const CALL_REFUSAL_KEYS = Object.freeze({
|
|
257
|
+
ambiguous: 'model.subagent.call.ambiguous',
|
|
258
|
+
'tiers-inert': 'model.subagent.call.tiersInert',
|
|
259
|
+
'chain-unbound': 'model.subagent.call.chainUnbound',
|
|
260
|
+
'binding-not-in-catalog': 'model.subagent.call.bindingNotInCatalog',
|
|
261
|
+
});
|
|
262
|
+
const WORD_SHOWN_MAX = 80;
|
|
263
|
+
function quotedWord(word) {
|
|
264
|
+
return quoteUntrustedForSentence(typeof word === 'string' ? word.trim() : '', WORD_SHOWN_MAX) ?? '""';
|
|
265
|
+
}
|
|
266
|
+
export function subagentModelWordProblemLine(word, reading, lang) {
|
|
267
|
+
const cause = wordCauseOf(reading);
|
|
268
|
+
return cause === undefined ? undefined : renderMessage(msg(PROBLEM_LINE_KEYS[cause], { word: quotedWord(word) }), lang);
|
|
269
|
+
}
|
|
270
|
+
export function subagentModelCallRefusalReason(word, reading, lang) {
|
|
271
|
+
try {
|
|
272
|
+
const cause = wordCauseOf(reading);
|
|
273
|
+
if (cause === undefined)
|
|
274
|
+
return undefined;
|
|
275
|
+
const label = ownData(reading, 'label');
|
|
276
|
+
const tier = typeof label === 'string' && label.trim() !== '' ? label : word;
|
|
277
|
+
return renderMessage(msg(CALL_REFUSAL_KEYS[cause], { word: quotedWord(word), tier: quotedWord(tier) }), lang);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const notSent = () => Object.freeze({ verdict: 'accepted', why: 'not_sent' });
|
|
284
|
+
const isVocabKind = (k) => k === 'tier' || k === 'cc-alias' || k === 'best' || k === 'default';
|
|
285
|
+
function admissionIn(input) {
|
|
286
|
+
const reading = resolveIn(input);
|
|
287
|
+
const model = reading.model;
|
|
288
|
+
if (model === undefined)
|
|
289
|
+
return notSent();
|
|
290
|
+
const live = ownData(input, 'liveCatalog');
|
|
291
|
+
if (live === undefined || live === null)
|
|
292
|
+
return Object.freeze({ verdict: 'unknown', why: 'catalog_absent', model });
|
|
293
|
+
const a = modelAcceptanceOf(model, live);
|
|
294
|
+
if (a.verdict === 'accepted')
|
|
295
|
+
return Object.freeze({ verdict: 'accepted', why: 'served', model });
|
|
296
|
+
if (a.verdict === 'refused') {
|
|
297
|
+
if (a.why === 'not_at_mentionable')
|
|
298
|
+
return Object.freeze({ verdict: 'accepted', why: 'served', model });
|
|
299
|
+
if (a.why === 'disabled')
|
|
300
|
+
return Object.freeze({ verdict: 'refused', why: 'disabled', model });
|
|
301
|
+
return Object.freeze({ verdict: 'refused', why: isVocabKind(reading.kind) ? 'not_served' : 'not_listed', model });
|
|
302
|
+
}
|
|
303
|
+
return Object.freeze({ verdict: 'unknown', why: a.why === 'model_absent' ? 'catalog_unreadable' : a.why, model });
|
|
304
|
+
}
|
|
305
|
+
export function subagentModelAdmissionOf(input) {
|
|
306
|
+
try {
|
|
307
|
+
return admissionIn(input);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
const w = ownData(input, 'word');
|
|
311
|
+
const word = typeof w === 'string' ? w.trim() : '';
|
|
312
|
+
return word === '' ? notSent() : Object.freeze({ verdict: 'unknown', why: 'catalog_unreadable', model: word });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const ADMISSION_LINE_KEYS = Object.freeze({
|
|
316
|
+
not_listed: 'model.subagent.refused.notListed',
|
|
317
|
+
not_served: 'model.subagent.refused.notServed',
|
|
318
|
+
disabled: 'model.subagent.refused.disabled',
|
|
319
|
+
});
|
|
320
|
+
export function subagentModelAdmissionLine(word, admission, lang) {
|
|
321
|
+
try {
|
|
322
|
+
if (ownData(admission, 'verdict') !== 'refused')
|
|
323
|
+
return undefined;
|
|
324
|
+
const why = ownData(admission, 'why');
|
|
325
|
+
if (why !== 'not_listed' && why !== 'not_served' && why !== 'disabled')
|
|
326
|
+
return undefined;
|
|
327
|
+
return renderMessage(msg(ADMISSION_LINE_KEYS[why], { word: quotedWord(word) }), lang);
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
261
332
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
2
|
-
import {
|
|
2
|
+
import { requestDeadline } from './abortableSleep.js';
|
|
3
3
|
import { causeSlotProtected, walkCauseChain } from './engineWireFor.js';
|
|
4
4
|
import { readThrownSlot } from './wireFailureShape.js';
|
|
5
5
|
import { guardedRead, readOwnDataValue } from './ownKey.js';
|
|
@@ -522,45 +522,8 @@ function shownCause(e, redact) {
|
|
|
522
522
|
const shown = displayUntrusted(masked, { max: 160 });
|
|
523
523
|
return shown.trim() === '' ? undefined : shown;
|
|
524
524
|
}
|
|
525
|
-
const MAX_TIMER_MS = 2_147_483_647;
|
|
526
|
-
function probeDeadline(ms, cancel) {
|
|
527
|
-
const ctl = new AbortController();
|
|
528
|
-
const stop = new AbortController();
|
|
529
|
-
let expired = false;
|
|
530
|
-
const gone = new Promise((_resolve, reject) => {
|
|
531
|
-
const fire = () => reject(Object.assign(new Error('aborted'), { name: 'AbortError' }));
|
|
532
|
-
if (ctl.signal.aborted)
|
|
533
|
-
fire();
|
|
534
|
-
else
|
|
535
|
-
ctl.signal.addEventListener('abort', fire, { once: true });
|
|
536
|
-
});
|
|
537
|
-
gone.catch(() => undefined);
|
|
538
|
-
void abortableSleep(Math.min(ms, MAX_TIMER_MS), stop.signal).then(() => {
|
|
539
|
-
if (stop.signal.aborted)
|
|
540
|
-
return;
|
|
541
|
-
expired = true;
|
|
542
|
-
ctl.abort();
|
|
543
|
-
});
|
|
544
|
-
const onCancel = () => ctl.abort();
|
|
545
|
-
if (cancel !== undefined) {
|
|
546
|
-
if (cancel.aborted)
|
|
547
|
-
ctl.abort();
|
|
548
|
-
else
|
|
549
|
-
cancel.addEventListener('abort', onCancel, { once: true });
|
|
550
|
-
}
|
|
551
|
-
return {
|
|
552
|
-
signal: ctl.signal,
|
|
553
|
-
expired: () => expired,
|
|
554
|
-
abort: () => {
|
|
555
|
-
stop.abort();
|
|
556
|
-
cancel?.removeEventListener('abort', onCancel);
|
|
557
|
-
ctl.abort();
|
|
558
|
-
},
|
|
559
|
-
race: (p) => Promise.race([p, gone]),
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
525
|
async function getCatalogText(fetchIt, url, headers, timeoutMs, cancel) {
|
|
563
|
-
const d =
|
|
526
|
+
const d = requestDeadline(timeoutMs, cancel);
|
|
564
527
|
try {
|
|
565
528
|
const res = await d.race(fetchIt(url, { method: 'GET', headers, signal: d.signal }));
|
|
566
529
|
let text = '';
|
|
@@ -577,7 +540,7 @@ async function getCatalogText(fetchIt, url, headers, timeoutMs, cancel) {
|
|
|
577
540
|
}
|
|
578
541
|
}
|
|
579
542
|
async function postForFirstToken(fetchIt, api, url, path, headers, body, deadlineMs, cancel, now, redact) {
|
|
580
|
-
const d =
|
|
543
|
+
const d = requestDeadline(deadlineMs, cancel);
|
|
581
544
|
const startedAt = now();
|
|
582
545
|
try {
|
|
583
546
|
const res = await d.race(fetchIt(url, { method: 'POST', headers, body, signal: d.signal }));
|