@sema-agent/client-core 0.98.0 → 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +376 -0
- package/README.md +61 -35
- package/dist/adapt/arms.js +120 -55
- package/dist/adapt/panelTasks.d.ts +3 -2
- package/dist/adapt/panelTasks.js +34 -11
- package/dist/adapt/textStream.d.ts +1 -1
- package/dist/adapt/textStream.js +51 -28
- package/dist/adapter/activeRunSelfHeal.d.ts +11 -3
- package/dist/adapter/activeRunSelfHeal.js +210 -294
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
- package/dist/adapter/downstream/eventToSdkMessage.js +176 -12
- package/dist/adapter/downstream/terminalToSdkResult.js +10 -0
- package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
- package/dist/adapter/downstream/wiringManifestView.js +1 -0
- package/dist/adapter/runStream.js +82 -40
- package/dist/adapter/types.d.ts +2 -0
- package/dist/adapter/types.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
- package/dist/agentsWireCaps.d.ts +7 -3
- package/dist/agentsWireCaps.js +133 -39
- package/dist/cloudConfigWireCaps.d.ts +10 -1
- package/dist/cloudConfigWireCaps.js +181 -65
- package/dist/compactionStatus.d.ts +34 -0
- package/dist/compactionStatus.js +196 -0
- package/dist/controlRouter.d.ts +4 -2
- package/dist/controlRouter.js +39 -51
- package/dist/coreValuePorts.d.ts +26 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/corruptSessionCopy.d.ts +2 -1
- package/dist/corruptSessionCopy.js +3 -3
- package/dist/decideFailureNote.js +3 -3
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/detachWire.js +3 -2
- package/dist/devicesFace.d.ts +34 -0
- package/dist/devicesFace.js +90 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +153 -5
- package/dist/engineAgentPanelStore.d.ts +14 -4
- package/dist/engineAgentPanelStore.js +14 -0
- package/dist/engineCapReader.d.ts +2 -1
- package/dist/engineCapReader.js +7 -5
- package/dist/engineCapsCache.d.ts +8 -0
- package/dist/engineCapsCache.js +59 -6
- package/dist/engineCapsChange.d.ts +2 -0
- package/dist/engineCapsChange.js +9 -0
- package/dist/engineErrorCodes.d.ts +11 -2
- package/dist/engineErrorCodes.js +11 -12
- package/dist/engineRowRef.js +4 -0
- package/dist/engineSessionMessages.d.ts +1 -0
- package/dist/engineSessionMessages.js +7 -1
- package/dist/engineTargetSeat.d.ts +27 -0
- package/dist/engineTargetSeat.js +199 -0
- package/dist/engineToolDirectory.d.ts +3 -0
- package/dist/engineToolDirectory.js +4 -2
- package/dist/engineWireFor.js +3 -8
- package/dist/env/uiLanguage.d.ts +2 -1
- package/dist/env/uiLanguage.js +3 -2
- package/dist/eventLeg.d.ts +7 -5
- package/dist/eventLeg.js +68 -49
- package/dist/fileHistoryCaptureCapability.d.ts +2 -4
- package/dist/fileHistoryCaptureCapability.js +12 -22
- package/dist/fileHistoryLegNotice.d.ts +2 -1
- package/dist/fileHistoryLegNotice.js +3 -3
- package/dist/frameBinding.d.ts +3 -0
- package/dist/frameBinding.js +12 -0
- package/dist/gateOutcome.js +16 -2
- package/dist/gateVocabulary.d.ts +8 -7
- package/dist/gateVocabulary.js +71 -73
- package/dist/generated/engineFactTables.d.ts +18 -1
- package/dist/generated/engineFactTables.js +56 -0
- package/dist/generated/engineNoticeTables.js +12 -3
- package/dist/generated/settingsSchemaFns.d.ts +18 -0
- package/dist/generated/settingsSchemaFns.js +70 -0
- package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
- package/dist/generated/settingsSchemaTables.d.ts +2 -0
- package/dist/generated/settingsSchemaTables.js +9 -0
- package/dist/generated/settingsSchemaTypes.d.ts +133 -0
- package/dist/generated/settingsSchemaTypes.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +2 -1
- package/dist/hitl/allowRuleShadow.js +18 -15
- package/dist/hitl/approvalCardReasons.d.ts +3 -2
- package/dist/hitl/approvalCardReasons.js +29 -30
- package/dist/hitl/approvalHolds.d.ts +17 -0
- package/dist/hitl/approvalHolds.js +114 -29
- package/dist/hitl/askClassPair.d.ts +2 -2
- package/dist/hitl/askClassPair.js +16 -0
- package/dist/hitl/askGateWire.js +2 -1
- package/dist/hitl/askSettlementLine.d.ts +14 -4
- package/dist/hitl/askSettlementLine.js +67 -47
- package/dist/hitl/attributionLadder.d.ts +23 -0
- package/dist/hitl/attributionLadder.js +67 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
- package/dist/hitl/automaticAnswerVerdict.js +8 -8
- package/dist/hitl/crashConvergedNotice.d.ts +5 -4
- package/dist/hitl/crashConvergedNotice.js +28 -41
- package/dist/hitl/decisionLedger.d.ts +55 -0
- package/dist/hitl/decisionLedger.js +156 -0
- package/dist/hitl/decisionRefusal.d.ts +1 -0
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +113 -0
- package/dist/hitl/decisionSend.js +579 -0
- package/dist/hitl/frameRouter.js +7 -8
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +21 -9
- package/dist/hitl/persistedRulesWire.d.ts +6 -5
- package/dist/hitl/persistedRulesWire.js +55 -73
- package/dist/hitl/planReviewWire.d.ts +5 -0
- package/dist/hitl/planReviewWire.js +53 -76
- package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
- package/dist/hitl/sessionPolicyDeliverable.js +49 -9
- package/dist/hitl/sessionPolicyWire.d.ts +2 -1
- package/dist/hitl/sessionPolicyWire.js +23 -24
- package/dist/hitl/suspendedReopen.d.ts +2 -1
- package/dist/hitl/suspendedReopen.js +7 -10
- package/dist/hitl/toolApprovalWire.d.ts +17 -5
- package/dist/hitl/toolApprovalWire.js +120 -147
- package/dist/hooksWireCaps.js +145 -56
- package/dist/host.d.ts +21 -0
- package/dist/hostTurnSettings.d.ts +110 -0
- package/dist/hostTurnSettings.js +692 -0
- package/dist/humanTurn.d.ts +15 -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 +713 -0
- package/dist/i18n/messages.en.js +713 -0
- package/dist/i18n/messages.zh.js +854 -1
- package/dist/index.d.ts +45 -13
- package/dist/index.js +27 -9
- package/dist/inheritEnvCapability.d.ts +4 -2
- package/dist/inheritEnvCapability.js +12 -5
- package/dist/inheritEnvWire.d.ts +3 -2
- package/dist/inheritEnvWire.js +14 -16
- package/dist/injectionLaneNotice.d.ts +5 -0
- package/dist/injectionLaneNotice.js +46 -0
- package/dist/interactiveHalt.js +17 -6
- package/dist/liveModelCatalog.d.ts +2 -1
- package/dist/liveModelCatalog.js +14 -8
- package/dist/mcpPanel.d.ts +10 -1
- package/dist/mcpPanel.js +42 -13
- package/dist/mcpProbeCapability.d.ts +2 -1
- package/dist/mcpProbeCapability.js +7 -11
- package/dist/mcpProbeWire.d.ts +3 -1
- package/dist/mcpProbeWire.js +5 -0
- package/dist/mcpReconnect.js +2 -2
- package/dist/mcpToolToggles.d.ts +6 -0
- package/dist/mcpToolToggles.js +46 -0
- package/dist/mcpWireCaps.d.ts +43 -3
- package/dist/mcpWireCaps.js +194 -59
- package/dist/mcpWireTransport.d.ts +4 -0
- package/dist/mcpWireTransport.js +18 -0
- package/dist/memoryEntriesWire.js +5 -10
- package/dist/model/onboardJudgement.d.ts +93 -0
- package/dist/model/onboardJudgement.js +415 -0
- package/dist/model/tierVocabulary.d.ts +2 -0
- package/dist/model/tierVocabulary.js +17 -5
- package/dist/modelCapabilityProbe.d.ts +65 -0
- package/dist/modelCapabilityProbe.js +601 -0
- package/dist/modelIdentityResolvability.d.ts +5 -0
- package/dist/modelIdentityResolvability.js +49 -22
- package/dist/ownKey.d.ts +33 -0
- package/dist/ownKey.js +109 -0
- package/dist/panelReduce.d.ts +11 -1
- package/dist/panelReduce.js +95 -16
- package/dist/panelStateHolder.d.ts +1 -0
- package/dist/panelStateHolder.js +10 -1
- package/dist/permissionRuleIssue.d.ts +2 -1
- package/dist/permissionRuleIssue.js +23 -20
- package/dist/permissionRulesWriteCapability.d.ts +2 -1
- package/dist/permissionRulesWriteCapability.js +8 -6
- package/dist/pluginHooksWire.d.ts +46 -3
- package/dist/pluginHooksWire.js +220 -12
- package/dist/prepareRefusal.d.ts +8 -0
- package/dist/prepareRefusal.js +72 -0
- package/dist/printModelStatus.d.ts +63 -0
- package/dist/printModelStatus.js +155 -0
- package/dist/request/taskRequest.d.ts +16 -10
- package/dist/request/taskRequest.js +195 -58
- package/dist/resumeRefusalCopy.d.ts +14 -9
- package/dist/resumeRefusalCopy.js +89 -144
- package/dist/retryStatus.d.ts +55 -0
- package/dist/retryStatus.js +155 -19
- package/dist/ruleRefusalSentence.d.ts +4 -0
- package/dist/ruleRefusalSentence.js +58 -0
- package/dist/sandboxWire.d.ts +2 -1
- package/dist/sandboxWire.js +55 -21
- package/dist/scenarioRefusal.d.ts +10 -0
- package/dist/scenarioRefusal.js +111 -0
- package/dist/seam.d.ts +48 -9
- package/dist/seam.js +54 -5
- package/dist/seatContract.d.ts +272 -14
- package/dist/seatContract.js +711 -23
- package/dist/selfOrchestrationDenial.js +7 -19
- package/dist/sessionIdSegment.d.ts +6 -0
- package/dist/sessionIdSegment.js +24 -0
- package/dist/sessionMemoryStatus.js +6 -11
- package/dist/sessionPolicyCapability.d.ts +2 -1
- package/dist/sessionPolicyCapability.js +8 -6
- package/dist/settingsCredentialKeyPaths.d.ts +8 -0
- package/dist/settingsCredentialKeyPaths.js +219 -0
- package/dist/settingsHooksSalvage.d.ts +44 -0
- package/dist/settingsHooksSalvage.js +211 -0
- package/dist/skillToolListsCapability.d.ts +2 -1
- package/dist/skillToolListsCapability.js +8 -6
- package/dist/skillsWireCaps.d.ts +0 -3
- package/dist/skillsWireCaps.js +1 -2
- package/dist/sseIdleTriage.js +3 -2
- package/dist/subagent/engineSubagentResume.js +15 -9
- package/dist/subagentContentStore.d.ts +4 -0
- package/dist/subagentContentStore.js +157 -27
- package/dist/toolHistoryMismatch.js +3 -2
- package/dist/toolRoster.d.ts +3 -2
- package/dist/toolRoster.js +21 -20
- package/dist/toolsFlagNames.d.ts +8 -0
- package/dist/toolsFlagNames.js +110 -0
- package/dist/turnFailurePresentation.d.ts +12 -1
- package/dist/turnFailurePresentation.js +220 -15
- package/dist/usageAnalytics.js +6 -11
- package/dist/userAttachmentEnvelope.d.ts +1 -0
- package/dist/userAttachmentEnvelope.js +37 -7
- package/dist/userAttachmentSeat.d.ts +21 -0
- package/dist/userAttachmentSeat.js +75 -0
- package/dist/userInvokedSkillsCapability.d.ts +11 -1
- package/dist/userInvokedSkillsCapability.js +31 -7
- package/dist/wireErrorTriage.d.ts +7 -0
- package/dist/wireErrorTriage.js +23 -1
- package/dist/wireFailureShape.js +2 -1
- package/dist/wireRefusalCopy.d.ts +62 -16
- package/dist/wireRefusalCopy.js +307 -148
- package/dist/workflowsJournalCapability.d.ts +2 -1
- package/dist/workflowsJournalCapability.js +8 -6
- package/docs/INTEGRATION-CLIENTS.md +951 -42
- package/package.json +5 -5
package/dist/mcpPanel.js
CHANGED
|
@@ -3,6 +3,7 @@ import { isSessionIdPathSegment } from './sessionIdSegment.js';
|
|
|
3
3
|
import { projectMcpSection } from './adapter/downstream/eventToSdkMessage.js';
|
|
4
4
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
5
5
|
import { mcpLivenessRollupOf } from './mcpLiveness.js';
|
|
6
|
+
import { scenarioRefusalOf } from './scenarioRefusal.js';
|
|
6
7
|
const MCP_PANEL_ERROR_MAX = 200;
|
|
7
8
|
const MCP_PANEL_WORD_MAX = 40;
|
|
8
9
|
const MCP_PANEL_NAMES_MAX = 8;
|
|
@@ -40,19 +41,29 @@ export function projectMcpPanel(body) {
|
|
|
40
41
|
return undefined;
|
|
41
42
|
if (!nonEmpty(body.asOf))
|
|
42
43
|
return undefined;
|
|
43
|
-
|
|
44
|
+
const refusal = scenarioRefusalOf(body);
|
|
45
|
+
if (refusal === null)
|
|
44
46
|
return undefined;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
let view;
|
|
48
|
+
if (refusal !== undefined) {
|
|
49
|
+
view = { asOf: body.asOf, scenarioRefusal: refusal };
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
if (!Array.isArray(body.servers))
|
|
53
|
+
return undefined;
|
|
54
|
+
const servers = [];
|
|
55
|
+
for (const r of body.servers) {
|
|
56
|
+
const row = projectServerRow(r);
|
|
57
|
+
if (row !== undefined)
|
|
58
|
+
servers.push(row);
|
|
59
|
+
}
|
|
60
|
+
if (body.servers.length > 0 && servers.length === 0)
|
|
61
|
+
return undefined;
|
|
62
|
+
const sv = { asOf: body.asOf, servers };
|
|
63
|
+
if (body.degraded === true)
|
|
64
|
+
sv.degraded = true;
|
|
65
|
+
view = sv;
|
|
50
66
|
}
|
|
51
|
-
if (body.servers.length > 0 && servers.length === 0)
|
|
52
|
-
return undefined;
|
|
53
|
-
const view = { asOf: body.asOf, servers };
|
|
54
|
-
if (body.degraded === true)
|
|
55
|
-
view.degraded = true;
|
|
56
67
|
if ('lastLegMcp' in body) {
|
|
57
68
|
const leg = projectLastLeg(body.lastLegMcp);
|
|
58
69
|
if (leg !== undefined)
|
|
@@ -62,6 +73,20 @@ export function projectMcpPanel(body) {
|
|
|
62
73
|
}
|
|
63
74
|
return view;
|
|
64
75
|
}
|
|
76
|
+
export function mcpPanelRefusalOf(view) {
|
|
77
|
+
try {
|
|
78
|
+
if (view === null || typeof view !== 'object')
|
|
79
|
+
return undefined;
|
|
80
|
+
const d = Object.getOwnPropertyDescriptor(view, 'scenarioRefusal');
|
|
81
|
+
if (d === undefined || !('value' in d))
|
|
82
|
+
return undefined;
|
|
83
|
+
const r = d.value;
|
|
84
|
+
return r !== null && typeof r === 'object' && !Array.isArray(r) ? r : undefined;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
65
90
|
export async function fetchMcpPanel(client, sessionId, opts) {
|
|
66
91
|
if (!isSessionIdPathSegment(sessionId))
|
|
67
92
|
return undefined;
|
|
@@ -95,15 +120,19 @@ export function mcpPanelLastLegDetail(view, opts) {
|
|
|
95
120
|
}
|
|
96
121
|
const _mcpPanelShapePin = (p) => p;
|
|
97
122
|
void _mcpPanelShapePin;
|
|
123
|
+
const _mcpPanelRefusalPin = (p) => p;
|
|
124
|
+
void _mcpPanelRefusalPin;
|
|
98
125
|
export function mcpEngineLegPresence(view) {
|
|
99
126
|
if (view === undefined)
|
|
100
127
|
return 'unknown';
|
|
101
|
-
if (view.servers.length > 0)
|
|
102
|
-
return 'present';
|
|
103
128
|
if (view.lastLegMcp !== undefined)
|
|
104
129
|
return 'present';
|
|
105
130
|
if (view.lastLegMcpUnreadable === true)
|
|
106
131
|
return 'present';
|
|
132
|
+
if (!('servers' in view))
|
|
133
|
+
return 'unknown';
|
|
134
|
+
if (view.servers.length > 0)
|
|
135
|
+
return 'present';
|
|
107
136
|
if (view.degraded === true)
|
|
108
137
|
return 'present';
|
|
109
138
|
return 'absent';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
1
2
|
export type McpProbeReading = {
|
|
2
3
|
kind: 'unobserved';
|
|
3
4
|
} | {
|
|
@@ -12,4 +13,4 @@ export type McpProbeReading = {
|
|
|
12
13
|
export declare function projectMcpProbeCapability(caps: unknown): McpProbeReading | undefined;
|
|
13
14
|
export declare function observedMcpProbe(baseUrl?: string | undefined): McpProbeReading;
|
|
14
15
|
export declare function mcpProbeAvailable(reading: McpProbeReading): 'yes' | 'no' | 'unknown';
|
|
15
|
-
export declare function mcpProbeDoctorDetail(reading: McpProbeReading): string;
|
|
16
|
+
export declare function mcpProbeDoctorDetail(reading: McpProbeReading, lang?: UiLanguage): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
2
|
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
3
4
|
import { ownDataField } from './ownKey.js';
|
|
4
5
|
export function projectMcpProbeCapability(caps) {
|
|
5
6
|
try {
|
|
@@ -30,22 +31,17 @@ export function mcpProbeAvailable(reading) {
|
|
|
30
31
|
return 'no';
|
|
31
32
|
return 'unknown';
|
|
32
33
|
}
|
|
33
|
-
export function mcpProbeDoctorDetail(reading) {
|
|
34
|
+
export function mcpProbeDoctorDetail(reading, lang) {
|
|
34
35
|
switch (reading.kind) {
|
|
35
36
|
case 'unreadable':
|
|
36
|
-
return unreadableReadingDetail('
|
|
37
|
+
return unreadableReadingDetail(renderMessage(msg('notice.capability.subject.mcpProbe'), lang), lang);
|
|
37
38
|
case 'unobserved':
|
|
38
|
-
return ('
|
|
39
|
-
'this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)');
|
|
39
|
+
return renderMessage(msg('notice.capability.mcpProbe.unobserved'), lang);
|
|
40
40
|
case 'not_reported':
|
|
41
|
-
return ('
|
|
42
|
-
'(asking it usually answers with a machine-readable route-not-found, though a timeout or an uncoded gateway answer still says nothing either way); ' +
|
|
43
|
-
'prefer the session panel last-leg roster where that panel carries one, and otherwise show this reason rather than an entry that cannot answer');
|
|
41
|
+
return renderMessage(msg('notice.capability.mcpProbe.notReported'), lang);
|
|
44
42
|
case 'absent':
|
|
45
|
-
return ('
|
|
46
|
-
'this client does not guess why, and whether caller-supplied declarations are honored is a separate position with its own answer');
|
|
43
|
+
return renderMessage(msg('notice.capability.mcpProbe.absent'), lang);
|
|
47
44
|
case 'present':
|
|
48
|
-
return ('
|
|
49
|
-
'and a probe of caller-supplied declarations answers with the very same body shape');
|
|
45
|
+
return renderMessage(msg('notice.capability.mcpProbe.present'), lang);
|
|
50
46
|
}
|
|
51
47
|
}
|
package/dist/mcpProbeWire.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpProbeFace, McpServerSpec } from '@sema-agent/sdk';
|
|
2
2
|
import { type WiringManifestMcpEntryView } from './adapter/downstream/eventToSdkMessage.js';
|
|
3
3
|
import { type McpProbeReading } from './mcpProbeCapability.js';
|
|
4
|
+
import { type ScenarioRefusalReading } from './scenarioRefusal.js';
|
|
4
5
|
export interface McpProbeFacade {
|
|
5
6
|
mcpCapabilities(opts?: {
|
|
6
7
|
signal?: AbortSignal;
|
|
@@ -9,7 +10,7 @@ export interface McpProbeFacade {
|
|
|
9
10
|
signal?: AbortSignal;
|
|
10
11
|
}): Promise<McpProbeFace>;
|
|
11
12
|
}
|
|
12
|
-
export declare const MCP_PROBE_REFUSAL_CAUSES: readonly ["face_absent", "client_too_old", "unreadable_request", "injection_not_honored", "body_shape", "field_invalid", "body_unparseable", "payload_too_large", "rate_limited", "unauthorized", "principal_required", "principal_unverified"];
|
|
13
|
+
export declare const MCP_PROBE_REFUSAL_CAUSES: readonly ["face_absent", "client_too_old", "unreadable_request", "injection_not_honored", "body_shape", "field_invalid", "body_unparseable", "payload_too_large", "rate_limited", "unauthorized", "principal_required", "principal_unverified", "scenario_refused"];
|
|
13
14
|
export type McpProbeRefusalCause = (typeof MCP_PROBE_REFUSAL_CAUSES)[number];
|
|
14
15
|
export declare const MCP_PROBE_UNKNOWN_WHYS: readonly ["no_verdict", "probe_incomplete", "server_fault", "result_unreadable", "index_misaligned", "unclassified"];
|
|
15
16
|
export type McpProbeUnknownWhy = (typeof MCP_PROBE_UNKNOWN_WHYS)[number];
|
|
@@ -18,6 +19,7 @@ export type McpProbeRefused = {
|
|
|
18
19
|
cause: McpProbeRefusalCause;
|
|
19
20
|
message: string;
|
|
20
21
|
retryAfterSec?: number;
|
|
22
|
+
scenarioRefusal?: ScenarioRefusalReading;
|
|
21
23
|
};
|
|
22
24
|
export type McpProbeUnknown = {
|
|
23
25
|
status: 'unknown';
|
package/dist/mcpProbeWire.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { projectMcpSection } from './adapter/downstream/eventToSdkMessage.js';
|
|
2
2
|
import { wireFailureShapeOf } from './wireFailureShape.js';
|
|
3
3
|
import { mcpProbeAvailable } from './mcpProbeCapability.js';
|
|
4
|
+
import { scenarioRefusalFromError } from './scenarioRefusal.js';
|
|
4
5
|
export const MCP_PROBE_REFUSAL_CAUSES = Object.freeze([
|
|
5
6
|
'face_absent',
|
|
6
7
|
'client_too_old',
|
|
@@ -14,6 +15,7 @@ export const MCP_PROBE_REFUSAL_CAUSES = Object.freeze([
|
|
|
14
15
|
'unauthorized',
|
|
15
16
|
'principal_required',
|
|
16
17
|
'principal_unverified',
|
|
18
|
+
'scenario_refused',
|
|
17
19
|
]);
|
|
18
20
|
export const MCP_PROBE_UNKNOWN_WHYS = Object.freeze([
|
|
19
21
|
'no_verdict',
|
|
@@ -168,6 +170,9 @@ export async function readMcpCapabilities(facade, call, opts) {
|
|
|
168
170
|
res = await facade.mcpCapabilities(opts);
|
|
169
171
|
}
|
|
170
172
|
catch (e) {
|
|
173
|
+
const refusal = scenarioRefusalFromError(e);
|
|
174
|
+
if (refusal !== null)
|
|
175
|
+
return { ...refusedBy('scenario_refused', wireFailureShapeOf(e).message), scenarioRefusal: refusal };
|
|
171
176
|
return classifyMcpProbeFailure(e);
|
|
172
177
|
}
|
|
173
178
|
const narrowed = narrowProbeFace(res);
|
package/dist/mcpReconnect.js
CHANGED
|
@@ -187,14 +187,14 @@ export function mcpReconnectOutcomeDetail(view) {
|
|
|
187
187
|
const name = capForDisplay(view.server, RECONNECT_WORD_MAX);
|
|
188
188
|
switch (view.outcome) {
|
|
189
189
|
case 'accepted':
|
|
190
|
-
return `MCP server ${name} was re-dialed: ${view.toolCount} tool${view.toolCount === 1 ? '' : 's'} mounted (${view.added.length} added, ${view.removed.length} removed)`;
|
|
190
|
+
return `MCP server ${name} was re-dialed: ${view.toolCount} tool${view.toolCount === 1 ? '' : 's'} mounted for this run (${view.added.length} added, ${view.removed.length} removed)`;
|
|
191
191
|
case 'refused': {
|
|
192
192
|
const why = view.reason !== undefined ? ` — ${view.reason}` : '';
|
|
193
193
|
if (view.toolNames === undefined) {
|
|
194
194
|
return `MCP server ${name} was NOT re-dialed; its connection and tools were left untouched${why}`;
|
|
195
195
|
}
|
|
196
196
|
if (view.toolNames.length === 0) {
|
|
197
|
-
return `MCP server ${name} was NOT re-dialed
|
|
197
|
+
return `MCP server ${name} was NOT re-dialed; this run's tool list has no tools from it right now (the dial failed, or this run's tool settings let none of its tools through)${why}`;
|
|
198
198
|
}
|
|
199
199
|
return `MCP server ${name} was NOT re-dialed; the engine reports ${view.toolNames.length} tool${view.toolNames.length === 1 ? '' : 's'} for it after this attempt${why}`;
|
|
200
200
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface McpToolToggleKey {
|
|
2
|
+
readonly server: string;
|
|
3
|
+
readonly tool: string;
|
|
4
|
+
}
|
|
5
|
+
export type McpMountedServers = readonly string[] | 'unknown';
|
|
6
|
+
export declare function mcpToolTogglesToExcludeTools(keys: readonly McpToolToggleKey[], mountedServers: McpMountedServers): string[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { checkMcpToolToggleKey } from './seatContract.js';
|
|
2
|
+
function keyOf(key, index) {
|
|
3
|
+
const refuse = (why) => new TypeError(`mcpToolTogglesToExcludeTools: keys[${index}] 不是逐工具开关键 { server, tool }(${why})—— 值不回显。` +
|
|
4
|
+
'宿主存档读坏了请在读档处用 checkMcpToolToggleKey 判,不要交进来让它在每一回合被静默丢掉。');
|
|
5
|
+
const shape = checkMcpToolToggleKey(key);
|
|
6
|
+
if (shape !== true)
|
|
7
|
+
throw refuse(`${shape.reason}${shape.field !== undefined ? ` @ ${shape.field}` : ''}`);
|
|
8
|
+
let snap;
|
|
9
|
+
try {
|
|
10
|
+
snap = { server: Object.getOwnPropertyDescriptor(key, 'server')?.value, tool: Object.getOwnPropertyDescriptor(key, 'tool')?.value };
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw refuse('读不出');
|
|
14
|
+
}
|
|
15
|
+
const again = checkMcpToolToggleKey(snap);
|
|
16
|
+
if (again !== true)
|
|
17
|
+
throw refuse(`${again.reason}${again.field !== undefined ? ` @ ${again.field}` : ''};判形之后读到的值与判过的不一致`);
|
|
18
|
+
return Object.freeze({ server: snap.server, tool: snap.tool });
|
|
19
|
+
}
|
|
20
|
+
function mountedSetOf(mountedServers) {
|
|
21
|
+
if (mountedServers === 'unknown')
|
|
22
|
+
return 'unknown';
|
|
23
|
+
if (!Array.isArray(mountedServers) || !mountedServers.every((s) => typeof s === 'string')) {
|
|
24
|
+
throw new TypeError("mcpToolTogglesToExcludeTools: mountedServers 只接受服务器名(串)数组,或宿主判不出时交 'unknown' —— 收到别的形(值不回显)。" +
|
|
25
|
+
"不知道本回合挂了哪些时请交 'unknown'(全部出),不要交 [](那会把用户关掉的工具静默放回)。");
|
|
26
|
+
}
|
|
27
|
+
return new Set(mountedServers);
|
|
28
|
+
}
|
|
29
|
+
export function mcpToolTogglesToExcludeTools(keys, mountedServers) {
|
|
30
|
+
if (!Array.isArray(keys)) {
|
|
31
|
+
throw new TypeError('mcpToolTogglesToExcludeTools: keys 必须是逐工具开关键数组(值不回显)。');
|
|
32
|
+
}
|
|
33
|
+
const mounted = mountedSetOf(mountedServers);
|
|
34
|
+
const parts = keys.map((k, i) => keyOf(k, i));
|
|
35
|
+
const out = [];
|
|
36
|
+
const seen = new Set();
|
|
37
|
+
for (const { server, tool } of parts) {
|
|
38
|
+
if (mounted !== 'unknown' && !mounted.has(server))
|
|
39
|
+
continue;
|
|
40
|
+
if (seen.has(tool))
|
|
41
|
+
continue;
|
|
42
|
+
seen.add(tool);
|
|
43
|
+
out.push(tool);
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
package/dist/mcpWireCaps.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { McpServerSpec } from '@sema-agent/sdk';
|
|
2
|
+
import type { McpEntryKeyIssue } from './generated/settingsSchemaTypes.js';
|
|
3
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
2
4
|
export type { McpServerSpec };
|
|
3
|
-
export declare const MCP_CAPS: {
|
|
4
|
-
readonly items: 32;
|
|
5
|
-
};
|
|
6
5
|
export interface McpConfigLike {
|
|
7
6
|
type?: string;
|
|
8
7
|
command?: string;
|
|
@@ -13,8 +12,10 @@ export interface McpConfigLike {
|
|
|
13
12
|
principalHeader?: string;
|
|
14
13
|
assertionHeader?: string;
|
|
15
14
|
allowTools?: string[];
|
|
15
|
+
elicitation?: {} | null | undefined;
|
|
16
16
|
toolFaces?: unknown;
|
|
17
17
|
toolAxes?: unknown;
|
|
18
|
+
startupTimeoutMs?: number;
|
|
18
19
|
}
|
|
19
20
|
export type McpHttpIdentityHeaders = {
|
|
20
21
|
readonly kind: 'ok';
|
|
@@ -26,4 +27,43 @@ export type McpHttpIdentityHeaders = {
|
|
|
26
27
|
export declare function readMcpHttpIdentityHeaders(transport: object): McpHttpIdentityHeaders;
|
|
27
28
|
export declare function mcpConfigToSpec(name: string, c: McpConfigLike): McpServerSpec | null;
|
|
28
29
|
export declare function mcpConfigsToSpecs(servers: Record<string, McpConfigLike> | undefined): McpServerSpec[];
|
|
30
|
+
export type McpToolAxesVerdict = {
|
|
31
|
+
readonly kind: 'ok';
|
|
32
|
+
readonly toolAxes?: Readonly<Record<string, object>>;
|
|
33
|
+
} | {
|
|
34
|
+
readonly kind: 'bad';
|
|
35
|
+
readonly problem: string;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: 'unavailable';
|
|
38
|
+
};
|
|
39
|
+
export declare function mcpToolAxesVerdict(declared: {} | null | undefined): McpToolAxesVerdict;
|
|
40
|
+
export declare function mcpElicitationVerdict(declared: {} | null | undefined): {
|
|
41
|
+
readonly kind: 'ok';
|
|
42
|
+
readonly elicitation?: boolean;
|
|
43
|
+
} | {
|
|
44
|
+
readonly kind: 'bad';
|
|
45
|
+
};
|
|
46
|
+
export type McpConfigDropReason = 'name_blank' | 'name_edge_whitespace' | 'name_collides_after_trim' | 'name_too_long' | 'transport_invalid' | 'identity_headers_both_set' | 'tool_axes_invalid' | 'elicitation_invalid';
|
|
47
|
+
export interface McpConfigDropped {
|
|
48
|
+
readonly name: string;
|
|
49
|
+
readonly reason: McpConfigDropReason;
|
|
50
|
+
readonly problem?: string;
|
|
51
|
+
readonly path?: string;
|
|
52
|
+
readonly notice: string;
|
|
53
|
+
}
|
|
54
|
+
export interface McpConfigDegraded {
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly lost: readonly McpEntryKeyIssue[];
|
|
57
|
+
readonly notice: string;
|
|
58
|
+
}
|
|
59
|
+
export interface McpConfigProjection {
|
|
60
|
+
readonly specs: McpServerSpec[];
|
|
61
|
+
readonly dropped: readonly McpConfigDropped[];
|
|
62
|
+
readonly degraded: readonly McpConfigDegraded[];
|
|
63
|
+
}
|
|
64
|
+
export interface ProjectMcpConfigsOptions {
|
|
65
|
+
readonly sourceLabel?: (serverName: string) => string | undefined;
|
|
66
|
+
readonly lang?: UiLanguage;
|
|
67
|
+
}
|
|
68
|
+
export declare function projectMcpConfigs(servers: Record<string, McpConfigLike> | undefined, opts?: ProjectMcpConfigsOptions): McpConfigProjection;
|
|
29
69
|
export declare function mcpAssertionHeaderNotSentNotice(specs: readonly McpServerSpec[]): string | undefined;
|
package/dist/mcpWireCaps.js
CHANGED
|
@@ -1,79 +1,214 @@
|
|
|
1
|
+
import { SETTINGS_DESCRIBE_BAD_WIRE_NAME, SETTINGS_IS_USABLE_WIRE_NAME, SETTINGS_READ_MCP_IDENTITY_HEADERS, SETTINGS_READ_REQUEST_MCP_TRANSPORT, } from './generated/settingsSchemaFns.js';
|
|
2
|
+
import { snapshotArgs, wireTransportOf } from './mcpWireTransport.js';
|
|
1
3
|
import { guardedRead } from './ownKey.js';
|
|
4
|
+
import { readMcpToolAxes } from './coreValuePorts.js';
|
|
5
|
+
import { capForDisplay } from './fleetTaskDesc.js';
|
|
6
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
2
7
|
const _mcpServerSpecPin = true;
|
|
3
8
|
void _mcpServerSpecPin;
|
|
4
|
-
|
|
5
|
-
function transparentKeys(c) {
|
|
9
|
+
function transparentKeys(c, axes, elicitation) {
|
|
6
10
|
return {
|
|
7
11
|
...(c.toolFaces !== undefined ? { toolFaces: c.toolFaces } : {}),
|
|
8
|
-
...(
|
|
12
|
+
...(axes !== undefined ? { toolAxes: axes } : {}),
|
|
13
|
+
...(elicitation !== undefined ? { elicitation } : {}),
|
|
14
|
+
...(c.startupTimeoutMs !== undefined ? { startupTimeoutMs: c.startupTimeoutMs } : {}),
|
|
9
15
|
};
|
|
10
16
|
}
|
|
11
|
-
function presentHeaderName(v) {
|
|
12
|
-
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
13
|
-
}
|
|
14
17
|
export function readMcpHttpIdentityHeaders(transport) {
|
|
15
18
|
const t = transport;
|
|
16
|
-
const principalHeader =
|
|
17
|
-
const assertionHeader =
|
|
19
|
+
const principalHeader = t.principalHeader;
|
|
20
|
+
const assertionHeader = t.assertionHeader;
|
|
18
21
|
if (principalHeader !== undefined && assertionHeader !== undefined)
|
|
19
22
|
return { kind: 'both_set' };
|
|
20
|
-
return {
|
|
21
|
-
kind: 'ok',
|
|
22
|
-
...(principalHeader !== undefined ? { principalHeader } : {}),
|
|
23
|
-
...(assertionHeader !== undefined ? { assertionHeader } : {}),
|
|
24
|
-
};
|
|
23
|
+
return { kind: 'ok', ...SETTINGS_READ_MCP_IDENTITY_HEADERS({ principalHeader, assertionHeader }) };
|
|
25
24
|
}
|
|
26
25
|
export function mcpConfigToSpec(name, c) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
};
|
|
26
|
+
return mcpConfigEntry(name, c).spec;
|
|
27
|
+
}
|
|
28
|
+
function mcpConfigEntry(name, c) {
|
|
29
|
+
if (!nameUsable(name))
|
|
30
|
+
return { spec: null };
|
|
31
|
+
const declared = c.toolAxes;
|
|
32
|
+
const verdict = mcpToolAxesVerdict(declared);
|
|
33
|
+
const elDeclared = c.elicitation;
|
|
34
|
+
const elVerdict = mcpElicitationVerdict(elDeclared);
|
|
35
|
+
if (verdict.kind === 'bad' || elVerdict.kind === 'bad') {
|
|
36
|
+
const rest = specOf(name, c, undefined, undefined);
|
|
37
|
+
if (rest.kind === 'skip')
|
|
38
|
+
return { spec: null };
|
|
39
|
+
if (rest.kind === 'both_set')
|
|
40
|
+
return { spec: null, identityBothSet: true };
|
|
41
|
+
if (rest.kind === 'bad')
|
|
42
|
+
return { spec: null, transportBad: rest.issue };
|
|
43
|
+
return verdict.kind === 'bad' ? { spec: null, axesProblem: verdict.problem } : { spec: null, elicitationInvalid: true };
|
|
44
|
+
}
|
|
45
|
+
const read = specOf(name, c, verdict.kind === 'ok' ? verdict.toolAxes : declared, elVerdict.elicitation);
|
|
46
|
+
if (read.kind === 'skip')
|
|
47
|
+
return { spec: null };
|
|
48
|
+
if (read.kind === 'both_set')
|
|
49
|
+
return { spec: null, identityBothSet: true };
|
|
50
|
+
if (read.kind === 'bad')
|
|
51
|
+
return { spec: null, transportBad: read.issue };
|
|
52
|
+
return { spec: read.spec, ...(read.lost.length > 0 ? { transportLost: read.lost } : {}) };
|
|
53
|
+
}
|
|
54
|
+
function specOf(name, c, axes, elicitation) {
|
|
55
|
+
let candidate;
|
|
56
|
+
try {
|
|
57
|
+
const kind = c.type ?? 'stdio';
|
|
58
|
+
if (kind === 'stdio') {
|
|
59
|
+
const command = c.command;
|
|
60
|
+
const head = SETTINGS_READ_REQUEST_MCP_TRANSPORT({ kind: 'stdio', command });
|
|
61
|
+
if (!head.ok)
|
|
62
|
+
return { kind: 'bad', issue: head.issue };
|
|
63
|
+
candidate = { kind: 'stdio', command, args: snapshotArgs(c.args), env: c.env };
|
|
64
|
+
}
|
|
65
|
+
else if (kind === 'http') {
|
|
66
|
+
const url = c.url;
|
|
67
|
+
const head = SETTINGS_READ_REQUEST_MCP_TRANSPORT({ kind: 'http', url });
|
|
68
|
+
if (!head.ok)
|
|
69
|
+
return { kind: 'bad', issue: head.issue };
|
|
70
|
+
const principalHeader = c.principalHeader;
|
|
71
|
+
const assertionHeader = c.assertionHeader;
|
|
72
|
+
if (readMcpHttpIdentityHeaders({ principalHeader, assertionHeader }).kind === 'both_set')
|
|
73
|
+
return { kind: 'both_set' };
|
|
74
|
+
candidate = { kind: 'http', url, headers: c.headers, principalHeader, assertionHeader };
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return { kind: 'skip' };
|
|
78
|
+
}
|
|
45
79
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return null;
|
|
49
|
-
const id = readMcpHttpIdentityHeaders(c);
|
|
50
|
-
if (id.kind === 'both_set')
|
|
51
|
-
return null;
|
|
52
|
-
return {
|
|
53
|
-
name: n,
|
|
54
|
-
transport: {
|
|
55
|
-
kind: 'http',
|
|
56
|
-
url: c.url,
|
|
57
|
-
...(c.headers ? { headers: c.headers } : {}),
|
|
58
|
-
...(id.principalHeader !== undefined ? { principalHeader: id.principalHeader } : {}),
|
|
59
|
-
...(id.assertionHeader !== undefined ? { assertionHeader: id.assertionHeader } : {}),
|
|
60
|
-
},
|
|
61
|
-
...(c.allowTools && c.allowTools.length > 0 ? { allowTools: c.allowTools } : {}),
|
|
62
|
-
...transparentKeys(c),
|
|
63
|
-
};
|
|
80
|
+
catch {
|
|
81
|
+
return { kind: 'bad', issue: { path: 'transport', reason: renderMessage(msg('config.mcp.transportUnreadable')) } };
|
|
64
82
|
}
|
|
65
|
-
|
|
83
|
+
const read = SETTINGS_READ_REQUEST_MCP_TRANSPORT(candidate);
|
|
84
|
+
if (!read.ok)
|
|
85
|
+
return { kind: 'bad', issue: read.issue };
|
|
86
|
+
const spec = {
|
|
87
|
+
name,
|
|
88
|
+
transport: wireTransportOf(read.transport),
|
|
89
|
+
...(Array.isArray(c.allowTools) ? { allowTools: c.allowTools } : {}),
|
|
90
|
+
...transparentKeys(c, axes, elicitation),
|
|
91
|
+
};
|
|
92
|
+
return { kind: 'ok', spec, lost: read.lost };
|
|
66
93
|
}
|
|
67
94
|
export function mcpConfigsToSpecs(servers) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
95
|
+
return projectMcpConfigs(servers).specs;
|
|
96
|
+
}
|
|
97
|
+
export function mcpToolAxesVerdict(declared) {
|
|
98
|
+
if (declared === undefined)
|
|
99
|
+
return Object.freeze({ kind: 'ok' });
|
|
100
|
+
const read = readMcpToolAxes(declared);
|
|
101
|
+
if (read === undefined || read === null || typeof read !== 'object')
|
|
102
|
+
return Object.freeze({ kind: 'unavailable' });
|
|
103
|
+
if (read.ok === true) {
|
|
104
|
+
const copy = read.toolAxes;
|
|
105
|
+
return Object.freeze(typeof copy === 'object' && copy !== null ? { kind: 'ok', toolAxes: copy } : { kind: 'ok' });
|
|
106
|
+
}
|
|
107
|
+
if (read.ok === false) {
|
|
108
|
+
const problem = read.problem;
|
|
109
|
+
return Object.freeze({ kind: 'bad', problem: typeof problem === 'string' && problem.length > 0 ? problem : renderMessage(msg('config.mcp.toolAxesFallbackProblem')) });
|
|
110
|
+
}
|
|
111
|
+
return Object.freeze({ kind: 'unavailable' });
|
|
112
|
+
}
|
|
113
|
+
export function mcpElicitationVerdict(declared) {
|
|
114
|
+
if (declared === undefined)
|
|
115
|
+
return Object.freeze({ kind: 'ok' });
|
|
116
|
+
return typeof declared === 'boolean' ? Object.freeze({ kind: 'ok', elicitation: declared }) : Object.freeze({ kind: 'bad' });
|
|
117
|
+
}
|
|
118
|
+
const nameUsable = (name) => SETTINGS_IS_USABLE_WIRE_NAME(name);
|
|
119
|
+
function mcpNameDropReasonOf(name) {
|
|
120
|
+
if (typeof name !== 'string' || name.trim().length === 0)
|
|
121
|
+
return 'name_blank';
|
|
122
|
+
return name.trim() !== name ? 'name_edge_whitespace' : 'name_too_long';
|
|
123
|
+
}
|
|
124
|
+
const DROP_NAME_SHOWN = 80;
|
|
125
|
+
const DROP_LABEL_SHOWN = 140;
|
|
126
|
+
const DROP_PROBLEM_SHOWN = 300;
|
|
127
|
+
const DROP_BAD_NAME_SHOWN = 160;
|
|
128
|
+
const DEGRADED_LOST_SHOWN = 400;
|
|
129
|
+
function dropNotice(name, reason, problem, opts, path) {
|
|
130
|
+
let label;
|
|
131
|
+
try {
|
|
132
|
+
label = opts?.sourceLabel?.(name);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
label = undefined;
|
|
136
|
+
}
|
|
137
|
+
const where = typeof label === 'string' && label.length > 0 ? ` (${capForDisplay(label, DROP_LABEL_SHOWN)})` : '';
|
|
138
|
+
const quoted = `"${capForDisplay(name, DROP_NAME_SHOWN)}"`;
|
|
139
|
+
const badName = () => capForDisplay(SETTINGS_DESCRIBE_BAD_WIRE_NAME(name), DROP_BAD_NAME_SHOWN);
|
|
140
|
+
const ref = reason === 'tool_axes_invalid'
|
|
141
|
+
? msg('config.mcp.toolAxesInvalid', { name: quoted, where, problem: capForDisplay(problem ?? renderMessage(msg('config.mcp.toolAxesFallbackProblem')), DROP_PROBLEM_SHOWN) })
|
|
142
|
+
: reason === 'elicitation_invalid'
|
|
143
|
+
? msg('config.mcp.elicitationInvalid', { name: quoted, where })
|
|
144
|
+
: reason === 'identity_headers_both_set'
|
|
145
|
+
? msg('config.mcp.identityHeadersBothSet', { name: quoted, where })
|
|
146
|
+
: reason === 'transport_invalid'
|
|
147
|
+
? msg('config.mcp.transportInvalid', { name: quoted, where, path: capForDisplay(path ?? 'transport', DROP_NAME_SHOWN), problem: capForDisplay(problem ?? '', DROP_PROBLEM_SHOWN) })
|
|
148
|
+
: reason === 'name_blank'
|
|
149
|
+
? msg('config.mcp.nameBlank', { name: badName(), where })
|
|
150
|
+
: reason === 'name_collides_after_trim'
|
|
151
|
+
? msg('config.mcp.nameCollides', { name: badName(), where })
|
|
152
|
+
: reason === 'name_too_long'
|
|
153
|
+
? msg('config.mcp.nameTooLong', { name: badName(), where })
|
|
154
|
+
: msg('config.mcp.nameEdgeWhitespace', { name: badName(), where });
|
|
155
|
+
return renderMessage(ref, opts?.lang);
|
|
156
|
+
}
|
|
157
|
+
function degradedNotice(name, lost, opts) {
|
|
158
|
+
let label;
|
|
159
|
+
try {
|
|
160
|
+
label = opts?.sourceLabel?.(name);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
label = undefined;
|
|
164
|
+
}
|
|
165
|
+
const where = typeof label === 'string' && label.length > 0 ? ` (${capForDisplay(label, DROP_LABEL_SHOWN)})` : '';
|
|
166
|
+
const quoted = `"${capForDisplay(name, DROP_NAME_SHOWN)}"`;
|
|
167
|
+
const what = capForDisplay(lost.map((l) => `${l.path}: ${l.reason}`).join('; '), DEGRADED_LOST_SHOWN);
|
|
168
|
+
return renderMessage(msg('config.mcp.transportDegraded', { name: quoted, where, lost: what }), opts?.lang);
|
|
169
|
+
}
|
|
170
|
+
export function projectMcpConfigs(servers, opts) {
|
|
171
|
+
const specs = [];
|
|
172
|
+
const dropped = [];
|
|
173
|
+
const degraded = [];
|
|
174
|
+
const entries = Object.entries(servers ?? {});
|
|
175
|
+
const exactNames = new Set();
|
|
176
|
+
const trimmedCount = new Map();
|
|
177
|
+
for (const [name] of entries) {
|
|
178
|
+
if (nameUsable(name))
|
|
179
|
+
exactNames.add(name);
|
|
180
|
+
else if (mcpNameDropReasonOf(name) === 'name_edge_whitespace')
|
|
181
|
+
trimmedCount.set(name.trim(), (trimmedCount.get(name.trim()) ?? 0) + 1);
|
|
182
|
+
}
|
|
183
|
+
for (const [name, c] of entries) {
|
|
184
|
+
if (!nameUsable(name)) {
|
|
185
|
+
const flaw = mcpNameDropReasonOf(name);
|
|
186
|
+
const reason = flaw === 'name_edge_whitespace' && (exactNames.has(name.trim()) || (trimmedCount.get(name.trim()) ?? 0) > 1) ? 'name_collides_after_trim' : flaw;
|
|
187
|
+
dropped.push({ name, reason, notice: dropNotice(name, reason, undefined, opts) });
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const out = mcpConfigEntry(name, c);
|
|
191
|
+
if (out.spec !== null) {
|
|
192
|
+
specs.push(out.spec);
|
|
193
|
+
if (out.transportLost !== undefined)
|
|
194
|
+
degraded.push({ name, lost: Object.freeze([...out.transportLost]), notice: degradedNotice(name, out.transportLost, opts) });
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (out.identityBothSet === true) {
|
|
198
|
+
dropped.push({ name, reason: 'identity_headers_both_set', notice: dropNotice(name, 'identity_headers_both_set', undefined, opts) });
|
|
199
|
+
}
|
|
200
|
+
else if (out.transportBad !== undefined) {
|
|
201
|
+
const { path, reason: problem } = out.transportBad;
|
|
202
|
+
dropped.push({ name, reason: 'transport_invalid', problem, path, notice: dropNotice(name, 'transport_invalid', problem, opts, path) });
|
|
203
|
+
}
|
|
204
|
+
else if (out.axesProblem !== undefined) {
|
|
205
|
+
dropped.push({ name, reason: 'tool_axes_invalid', problem: out.axesProblem, notice: dropNotice(name, 'tool_axes_invalid', out.axesProblem, opts) });
|
|
206
|
+
}
|
|
207
|
+
else if (out.elicitationInvalid === true) {
|
|
208
|
+
dropped.push({ name, reason: 'elicitation_invalid', notice: dropNotice(name, 'elicitation_invalid', undefined, opts) });
|
|
209
|
+
}
|
|
75
210
|
}
|
|
76
|
-
return
|
|
211
|
+
return { specs, dropped: Object.freeze(dropped), degraded: Object.freeze(degraded) };
|
|
77
212
|
}
|
|
78
213
|
function assertionDeclaringServerName(spec) {
|
|
79
214
|
const t = spec?.transport;
|
|
@@ -97,6 +232,6 @@ export function mcpAssertionHeaderNotSentNotice(specs) {
|
|
|
97
232
|
const parts = distinct.slice(0, ASSERTION_NOTICE_NAMES_SHOWN).map((x) => `"${x}"`);
|
|
98
233
|
if (distinct.length > ASSERTION_NOTICE_NAMES_SHOWN)
|
|
99
234
|
parts.push(`+${distinct.length - ASSERTION_NOTICE_NAMES_SHOWN} more`);
|
|
100
|
-
return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.
|
|
235
|
+
return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.132.0 accept this setting but do not send the header, ` +
|
|
101
236
|
'and this client cannot tell whether the engine it uses sends it; a connector that requires the header will refuse requests from these servers');
|
|
102
237
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServerSpec } from '@sema-agent/sdk';
|
|
2
|
+
import type { RequestMcpTransport } from './generated/settingsSchemaTypes.js';
|
|
3
|
+
export declare function snapshotArgs(v: {} | null | undefined): {} | null | undefined;
|
|
4
|
+
export declare function wireTransportOf(t: RequestMcpTransport): McpServerSpec['transport'];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const ARGS_SNAPSHOT_MAX = 65_536;
|
|
2
|
+
export function snapshotArgs(v) {
|
|
3
|
+
if (!Array.isArray(v))
|
|
4
|
+
return v;
|
|
5
|
+
const n = v.length;
|
|
6
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0 || n > ARGS_SNAPSHOT_MAX)
|
|
7
|
+
return {};
|
|
8
|
+
const out = [];
|
|
9
|
+
for (let i = 0; i < n; i++)
|
|
10
|
+
out.push(v[i]);
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
export function wireTransportOf(t) {
|
|
14
|
+
if (t.kind === 'stdio') {
|
|
15
|
+
return { kind: 'stdio', command: t.command, ...(t.args !== undefined && t.args.length > 0 ? { args: t.args } : {}), ...(t.env !== undefined ? { env: t.env } : {}) };
|
|
16
|
+
}
|
|
17
|
+
return t;
|
|
18
|
+
}
|