@sema-agent/client-core 0.99.0 → 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +177 -0
- package/README.md +32 -19
- package/dist/adapt/arms.js +60 -36
- package/dist/adapt/panelTasks.d.ts +2 -1
- package/dist/adapt/panelTasks.js +32 -9
- package/dist/adapt/textStream.d.ts +1 -1
- package/dist/adapt/textStream.js +51 -28
- package/dist/adapter/activeRunSelfHeal.d.ts +7 -0
- package/dist/adapter/activeRunSelfHeal.js +58 -11
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
- package/dist/adapter/downstream/eventToSdkMessage.js +125 -9
- package/dist/adapter/downstream/terminalToSdkResult.js +10 -0
- package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
- package/dist/adapter/downstream/wiringManifestView.js +1 -0
- package/dist/adapter/runStream.js +32 -5
- package/dist/adapter/types.d.ts +2 -0
- package/dist/agentsWireCaps.d.ts +7 -0
- package/dist/agentsWireCaps.js +100 -15
- package/dist/cloudConfigWireCaps.d.ts +10 -1
- package/dist/cloudConfigWireCaps.js +156 -62
- package/dist/compactionStatus.d.ts +34 -0
- package/dist/compactionStatus.js +196 -0
- package/dist/decideFailureNote.js +3 -3
- package/dist/displayUntrusted.js +150 -5
- package/dist/engineAgentPanelStore.d.ts +7 -4
- package/dist/engineErrorCodes.d.ts +9 -1
- package/dist/engineErrorCodes.js +9 -5
- package/dist/engineRowRef.js +1 -0
- package/dist/engineToolDirectory.d.ts +3 -0
- package/dist/engineToolDirectory.js +4 -2
- package/dist/eventLeg.d.ts +1 -7
- package/dist/eventLeg.js +7 -8
- package/dist/fileHistoryCaptureCapability.d.ts +0 -3
- package/dist/fileHistoryCaptureCapability.js +0 -4
- package/dist/generated/engineFactTables.d.ts +1 -0
- package/dist/generated/engineFactTables.js +27 -0
- package/dist/generated/engineNoticeTables.js +3 -0
- package/dist/generated/settingsSchemaFns.d.ts +12 -0
- package/dist/generated/settingsSchemaFns.js +13 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
- package/dist/generated/settingsSchemaTables.d.ts +1 -0
- package/dist/generated/settingsSchemaTables.js +5 -0
- package/dist/generated/settingsSchemaTypes.d.ts +28 -0
- package/dist/hitl/allowRuleShadow.js +2 -2
- package/dist/hitl/approvalCardReasons.js +2 -2
- package/dist/hitl/approvalHolds.d.ts +14 -0
- package/dist/hitl/approvalHolds.js +41 -0
- package/dist/hitl/askClassPair.d.ts +2 -2
- package/dist/hitl/askClassPair.js +2 -2
- package/dist/hitl/attributionLadder.d.ts +23 -0
- package/dist/hitl/attributionLadder.js +67 -0
- package/dist/hitl/decisionLedger.d.ts +55 -0
- package/dist/hitl/decisionLedger.js +156 -0
- package/dist/hitl/decisionRefusal.d.ts +1 -0
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +113 -0
- package/dist/hitl/decisionSend.js +579 -0
- package/dist/hitl/hitlBridge.js +18 -6
- package/dist/hitl/planReviewWire.js +45 -76
- package/dist/hitl/sessionPolicyDeliverable.js +3 -6
- package/dist/hitl/toolApprovalWire.js +43 -109
- package/dist/hostTurnSettings.d.ts +46 -7
- package/dist/hostTurnSettings.js +408 -7
- package/dist/humanTurn.d.ts +2 -1
- package/dist/humanTurn.js +3 -3
- package/dist/i18n/messages.en.d.ts +131 -0
- package/dist/i18n/messages.en.js +143 -12
- package/dist/i18n/messages.zh.js +148 -12
- package/dist/index.d.ts +18 -2
- package/dist/index.js +10 -1
- package/dist/inheritEnvCapability.d.ts +1 -0
- package/dist/inheritEnvCapability.js +9 -2
- package/dist/inheritEnvWire.js +2 -2
- package/dist/injectionLaneNotice.d.ts +5 -0
- package/dist/injectionLaneNotice.js +46 -0
- package/dist/mcpPanel.js +2 -0
- package/dist/mcpReconnect.js +2 -2
- package/dist/mcpToolToggles.d.ts +6 -0
- package/dist/mcpToolToggles.js +46 -0
- package/dist/mcpWireCaps.d.ts +10 -4
- package/dist/mcpWireCaps.js +106 -71
- package/dist/mcpWireTransport.d.ts +4 -0
- package/dist/mcpWireTransport.js +18 -0
- package/dist/modelCapabilityProbe.d.ts +2 -1
- package/dist/modelCapabilityProbe.js +10 -9
- package/dist/modelIdentityResolvability.d.ts +2 -0
- package/dist/modelIdentityResolvability.js +23 -5
- package/dist/ownKey.d.ts +26 -0
- package/dist/ownKey.js +75 -0
- package/dist/panelReduce.d.ts +5 -0
- package/dist/panelReduce.js +45 -13
- package/dist/panelStateHolder.d.ts +1 -0
- package/dist/panelStateHolder.js +10 -1
- package/dist/permissionRuleIssue.d.ts +2 -1
- package/dist/permissionRuleIssue.js +22 -21
- package/dist/pluginHooksWire.js +12 -10
- package/dist/prepareRefusal.d.ts +8 -0
- package/dist/prepareRefusal.js +72 -0
- package/dist/request/taskRequest.d.ts +10 -10
- package/dist/request/taskRequest.js +106 -65
- package/dist/resumeRefusalCopy.d.ts +3 -1
- package/dist/resumeRefusalCopy.js +22 -4
- package/dist/retryStatus.d.ts +18 -0
- package/dist/retryStatus.js +76 -19
- package/dist/ruleRefusalSentence.d.ts +4 -0
- package/dist/ruleRefusalSentence.js +58 -0
- package/dist/sandboxWire.d.ts +2 -1
- package/dist/sandboxWire.js +55 -21
- package/dist/scenarioRefusal.d.ts +2 -1
- package/dist/scenarioRefusal.js +5 -5
- package/dist/seam.d.ts +24 -9
- package/dist/seam.js +44 -4
- package/dist/seatContract.d.ts +16 -8
- package/dist/seatContract.js +21 -6
- package/dist/settingsCredentialKeyPaths.d.ts +8 -0
- package/dist/settingsCredentialKeyPaths.js +219 -0
- package/dist/skillsWireCaps.d.ts +0 -3
- package/dist/skillsWireCaps.js +1 -2
- package/dist/subagentContentStore.d.ts +1 -0
- package/dist/subagentContentStore.js +135 -27
- package/dist/toolsFlagNames.d.ts +8 -0
- package/dist/toolsFlagNames.js +110 -0
- package/dist/turnFailurePresentation.js +15 -7
- package/dist/wireRefusalCopy.d.ts +51 -17
- package/dist/wireRefusalCopy.js +298 -135
- package/docs/INTEGRATION-CLIENTS.md +423 -26
- package/package.json +4 -4
|
@@ -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,9 +1,7 @@
|
|
|
1
1
|
import type { McpServerSpec } from '@sema-agent/sdk';
|
|
2
|
+
import type { McpEntryKeyIssue } from './generated/settingsSchemaTypes.js';
|
|
2
3
|
import type { UiLanguage } from './env/uiLanguage.js';
|
|
3
4
|
export type { McpServerSpec };
|
|
4
|
-
export declare const MCP_CAPS: {
|
|
5
|
-
readonly items: 32;
|
|
6
|
-
};
|
|
7
5
|
export interface McpConfigLike {
|
|
8
6
|
type?: string;
|
|
9
7
|
command?: string;
|
|
@@ -17,6 +15,7 @@ export interface McpConfigLike {
|
|
|
17
15
|
elicitation?: {} | null | undefined;
|
|
18
16
|
toolFaces?: unknown;
|
|
19
17
|
toolAxes?: unknown;
|
|
18
|
+
startupTimeoutMs?: number;
|
|
20
19
|
}
|
|
21
20
|
export type McpHttpIdentityHeaders = {
|
|
22
21
|
readonly kind: 'ok';
|
|
@@ -44,16 +43,23 @@ export declare function mcpElicitationVerdict(declared: {} | null | undefined):
|
|
|
44
43
|
} | {
|
|
45
44
|
readonly kind: 'bad';
|
|
46
45
|
};
|
|
47
|
-
export type McpConfigDropReason = 'name_blank' | 'name_edge_whitespace' | 'name_collides_after_trim' | 'tool_axes_invalid' | 'elicitation_invalid';
|
|
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';
|
|
48
47
|
export interface McpConfigDropped {
|
|
49
48
|
readonly name: string;
|
|
50
49
|
readonly reason: McpConfigDropReason;
|
|
51
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[];
|
|
52
57
|
readonly notice: string;
|
|
53
58
|
}
|
|
54
59
|
export interface McpConfigProjection {
|
|
55
60
|
readonly specs: McpServerSpec[];
|
|
56
61
|
readonly dropped: readonly McpConfigDropped[];
|
|
62
|
+
readonly degraded: readonly McpConfigDegraded[];
|
|
57
63
|
}
|
|
58
64
|
export interface ProjectMcpConfigsOptions {
|
|
59
65
|
readonly sourceLabel?: (serverName: string) => string | undefined;
|
package/dist/mcpWireCaps.js
CHANGED
|
@@ -1,37 +1,32 @@
|
|
|
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';
|
|
2
4
|
import { readMcpToolAxes } from './coreValuePorts.js';
|
|
3
5
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
4
6
|
import { msg, renderMessage } from './i18n/translate.js';
|
|
5
7
|
const _mcpServerSpecPin = true;
|
|
6
8
|
void _mcpServerSpecPin;
|
|
7
|
-
export const MCP_CAPS = { items: 32 };
|
|
8
9
|
function transparentKeys(c, axes, elicitation) {
|
|
9
10
|
return {
|
|
10
11
|
...(c.toolFaces !== undefined ? { toolFaces: c.toolFaces } : {}),
|
|
11
12
|
...(axes !== undefined ? { toolAxes: axes } : {}),
|
|
12
13
|
...(elicitation !== undefined ? { elicitation } : {}),
|
|
14
|
+
...(c.startupTimeoutMs !== undefined ? { startupTimeoutMs: c.startupTimeoutMs } : {}),
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
|
-
function presentHeaderName(v) {
|
|
16
|
-
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
17
|
-
}
|
|
18
17
|
export function readMcpHttpIdentityHeaders(transport) {
|
|
19
18
|
const t = transport;
|
|
20
|
-
const principalHeader =
|
|
21
|
-
const assertionHeader =
|
|
19
|
+
const principalHeader = t.principalHeader;
|
|
20
|
+
const assertionHeader = t.assertionHeader;
|
|
22
21
|
if (principalHeader !== undefined && assertionHeader !== undefined)
|
|
23
22
|
return { kind: 'both_set' };
|
|
24
|
-
return {
|
|
25
|
-
kind: 'ok',
|
|
26
|
-
...(principalHeader !== undefined ? { principalHeader } : {}),
|
|
27
|
-
...(assertionHeader !== undefined ? { assertionHeader } : {}),
|
|
28
|
-
};
|
|
23
|
+
return { kind: 'ok', ...SETTINGS_READ_MCP_IDENTITY_HEADERS({ principalHeader, assertionHeader }) };
|
|
29
24
|
}
|
|
30
25
|
export function mcpConfigToSpec(name, c) {
|
|
31
26
|
return mcpConfigEntry(name, c).spec;
|
|
32
27
|
}
|
|
33
28
|
function mcpConfigEntry(name, c) {
|
|
34
|
-
if (
|
|
29
|
+
if (!nameUsable(name))
|
|
35
30
|
return { spec: null };
|
|
36
31
|
const declared = c.toolAxes;
|
|
37
32
|
const verdict = mcpToolAxesVerdict(declared);
|
|
@@ -39,49 +34,62 @@ function mcpConfigEntry(name, c) {
|
|
|
39
34
|
const elVerdict = mcpElicitationVerdict(elDeclared);
|
|
40
35
|
if (verdict.kind === 'bad' || elVerdict.kind === 'bad') {
|
|
41
36
|
const rest = specOf(name, c, undefined, undefined);
|
|
42
|
-
if (rest ===
|
|
37
|
+
if (rest.kind === 'skip')
|
|
43
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 };
|
|
44
43
|
return verdict.kind === 'bad' ? { spec: null, axesProblem: verdict.problem } : { spec: null, elicitationInvalid: true };
|
|
45
44
|
}
|
|
46
|
-
|
|
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 } : {}) };
|
|
47
53
|
}
|
|
48
|
-
function specOf(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
kind: '
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
+
}
|
|
64
79
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return null;
|
|
68
|
-
const id = readMcpHttpIdentityHeaders(c);
|
|
69
|
-
if (id.kind === 'both_set')
|
|
70
|
-
return null;
|
|
71
|
-
return {
|
|
72
|
-
name: n,
|
|
73
|
-
transport: {
|
|
74
|
-
kind: 'http',
|
|
75
|
-
url: c.url,
|
|
76
|
-
...(c.headers ? { headers: c.headers } : {}),
|
|
77
|
-
...(id.principalHeader !== undefined ? { principalHeader: id.principalHeader } : {}),
|
|
78
|
-
...(id.assertionHeader !== undefined ? { assertionHeader: id.assertionHeader } : {}),
|
|
79
|
-
},
|
|
80
|
-
...(Array.isArray(c.allowTools) ? { allowTools: c.allowTools } : {}),
|
|
81
|
-
...transparentKeys(c, axes, elicitation),
|
|
82
|
-
};
|
|
80
|
+
catch {
|
|
81
|
+
return { kind: 'bad', issue: { path: 'transport', reason: renderMessage(msg('config.mcp.transportUnreadable')) } };
|
|
83
82
|
}
|
|
84
|
-
|
|
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 };
|
|
85
93
|
}
|
|
86
94
|
export function mcpConfigsToSpecs(servers) {
|
|
87
95
|
return projectMcpConfigs(servers).specs;
|
|
@@ -107,18 +115,18 @@ export function mcpElicitationVerdict(declared) {
|
|
|
107
115
|
return Object.freeze({ kind: 'ok' });
|
|
108
116
|
return typeof declared === 'boolean' ? Object.freeze({ kind: 'ok', elicitation: declared }) : Object.freeze({ kind: 'bad' });
|
|
109
117
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const t = name.trim();
|
|
114
|
-
if (t.length === 0)
|
|
118
|
+
const nameUsable = (name) => SETTINGS_IS_USABLE_WIRE_NAME(name);
|
|
119
|
+
function mcpNameDropReasonOf(name) {
|
|
120
|
+
if (typeof name !== 'string' || name.trim().length === 0)
|
|
115
121
|
return 'name_blank';
|
|
116
|
-
return
|
|
122
|
+
return name.trim() !== name ? 'name_edge_whitespace' : 'name_too_long';
|
|
117
123
|
}
|
|
118
124
|
const DROP_NAME_SHOWN = 80;
|
|
119
125
|
const DROP_LABEL_SHOWN = 140;
|
|
120
126
|
const DROP_PROBLEM_SHOWN = 300;
|
|
121
|
-
|
|
127
|
+
const DROP_BAD_NAME_SHOWN = 160;
|
|
128
|
+
const DEGRADED_LOST_SHOWN = 400;
|
|
129
|
+
function dropNotice(name, reason, problem, opts, path) {
|
|
122
130
|
let label;
|
|
123
131
|
try {
|
|
124
132
|
label = opts?.sourceLabel?.(name);
|
|
@@ -128,35 +136,53 @@ function dropNotice(name, reason, problem, opts) {
|
|
|
128
136
|
}
|
|
129
137
|
const where = typeof label === 'string' && label.length > 0 ? ` (${capForDisplay(label, DROP_LABEL_SHOWN)})` : '';
|
|
130
138
|
const quoted = `"${capForDisplay(name, DROP_NAME_SHOWN)}"`;
|
|
139
|
+
const badName = () => capForDisplay(SETTINGS_DESCRIBE_BAD_WIRE_NAME(name), DROP_BAD_NAME_SHOWN);
|
|
131
140
|
const ref = reason === 'tool_axes_invalid'
|
|
132
141
|
? msg('config.mcp.toolAxesInvalid', { name: quoted, where, problem: capForDisplay(problem ?? renderMessage(msg('config.mcp.toolAxesFallbackProblem')), DROP_PROBLEM_SHOWN) })
|
|
133
142
|
: reason === 'elicitation_invalid'
|
|
134
143
|
? msg('config.mcp.elicitationInvalid', { name: quoted, where })
|
|
135
|
-
: reason === '
|
|
136
|
-
? msg('config.mcp.
|
|
137
|
-
: reason === '
|
|
138
|
-
? msg('config.mcp.
|
|
139
|
-
:
|
|
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 });
|
|
140
155
|
return renderMessage(ref, opts?.lang);
|
|
141
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
|
+
}
|
|
142
170
|
export function projectMcpConfigs(servers, opts) {
|
|
143
171
|
const specs = [];
|
|
144
172
|
const dropped = [];
|
|
173
|
+
const degraded = [];
|
|
145
174
|
const entries = Object.entries(servers ?? {});
|
|
146
175
|
const exactNames = new Set();
|
|
147
176
|
const trimmedCount = new Map();
|
|
148
177
|
for (const [name] of entries) {
|
|
149
|
-
|
|
150
|
-
if (flaw === undefined)
|
|
178
|
+
if (nameUsable(name))
|
|
151
179
|
exactNames.add(name);
|
|
152
|
-
else if (
|
|
180
|
+
else if (mcpNameDropReasonOf(name) === 'name_edge_whitespace')
|
|
153
181
|
trimmedCount.set(name.trim(), (trimmedCount.get(name.trim()) ?? 0) + 1);
|
|
154
182
|
}
|
|
155
183
|
for (const [name, c] of entries) {
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
const flaw = mcpNameFlaw(name);
|
|
159
|
-
if (flaw !== undefined) {
|
|
184
|
+
if (!nameUsable(name)) {
|
|
185
|
+
const flaw = mcpNameDropReasonOf(name);
|
|
160
186
|
const reason = flaw === 'name_edge_whitespace' && (exactNames.has(name.trim()) || (trimmedCount.get(name.trim()) ?? 0) > 1) ? 'name_collides_after_trim' : flaw;
|
|
161
187
|
dropped.push({ name, reason, notice: dropNotice(name, reason, undefined, opts) });
|
|
162
188
|
continue;
|
|
@@ -164,16 +190,25 @@ export function projectMcpConfigs(servers, opts) {
|
|
|
164
190
|
const out = mcpConfigEntry(name, c);
|
|
165
191
|
if (out.spec !== null) {
|
|
166
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) });
|
|
167
195
|
continue;
|
|
168
196
|
}
|
|
169
|
-
if (out.
|
|
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) {
|
|
170
205
|
dropped.push({ name, reason: 'tool_axes_invalid', problem: out.axesProblem, notice: dropNotice(name, 'tool_axes_invalid', out.axesProblem, opts) });
|
|
171
206
|
}
|
|
172
207
|
else if (out.elicitationInvalid === true) {
|
|
173
208
|
dropped.push({ name, reason: 'elicitation_invalid', notice: dropNotice(name, 'elicitation_invalid', undefined, opts) });
|
|
174
209
|
}
|
|
175
210
|
}
|
|
176
|
-
return { specs, dropped: Object.freeze(dropped) };
|
|
211
|
+
return { specs, dropped: Object.freeze(dropped), degraded: Object.freeze(degraded) };
|
|
177
212
|
}
|
|
178
213
|
function assertionDeclaringServerName(spec) {
|
|
179
214
|
const t = spec?.transport;
|
|
@@ -197,6 +232,6 @@ export function mcpAssertionHeaderNotSentNotice(specs) {
|
|
|
197
232
|
const parts = distinct.slice(0, ASSERTION_NOTICE_NAMES_SHOWN).map((x) => `"${x}"`);
|
|
198
233
|
if (distinct.length > ASSERTION_NOTICE_NAMES_SHOWN)
|
|
199
234
|
parts.push(`+${distinct.length - ASSERTION_NOTICE_NAMES_SHOWN} more`);
|
|
200
|
-
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, ` +
|
|
201
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');
|
|
202
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
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ModelApiWord } from './model/providerPresets.js';
|
|
2
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
2
3
|
export interface OpenAICompletionsProbeBody {
|
|
3
4
|
model: string;
|
|
4
5
|
messages: ReadonlyArray<{
|
|
@@ -129,5 +130,5 @@ export interface ProbeVerdictFacts {
|
|
|
129
130
|
}
|
|
130
131
|
export declare function probeVerdictNotice(facts: ProbeVerdictFacts | null | undefined, ctx?: {
|
|
131
132
|
readonly modelName?: string;
|
|
132
|
-
}): ProbeVerdictNotice;
|
|
133
|
+
}, lang?: UiLanguage): ProbeVerdictNotice;
|
|
133
134
|
export {};
|
|
@@ -2,6 +2,7 @@ import { displayUntrusted } from './displayUntrusted.js';
|
|
|
2
2
|
import { abortableSleep } from './abortableSleep.js';
|
|
3
3
|
import { readThrownSlot } from './wireFailureShape.js';
|
|
4
4
|
import { guardedRead, readOwnDataValue } from './ownKey.js';
|
|
5
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
5
6
|
export const THINKING_FORMATS = Object.freeze([
|
|
6
7
|
'openai',
|
|
7
8
|
'openrouter',
|
|
@@ -698,7 +699,7 @@ function probeSeconds(ms) {
|
|
|
698
699
|
return `${Number.isInteger(sec) ? sec : sec.toFixed(1)}s`;
|
|
699
700
|
}
|
|
700
701
|
const readFacts = (o, key) => guardedRead(() => readOwnDataValue(o, key));
|
|
701
|
-
export function probeVerdictNotice(facts, ctx) {
|
|
702
|
+
export function probeVerdictNotice(facts, ctx, lang) {
|
|
702
703
|
const rawWord = readFacts(facts, 'verdict');
|
|
703
704
|
const word = typeof rawWord === 'string' && PROBE_VERDICTS.includes(rawWord) ? rawWord : 'other';
|
|
704
705
|
const rawStatus = readFacts(facts, 'httpStatus');
|
|
@@ -713,31 +714,31 @@ export function probeVerdictNotice(facts, ctx) {
|
|
|
713
714
|
let recourse;
|
|
714
715
|
switch (word) {
|
|
715
716
|
case 'ok':
|
|
716
|
-
line =
|
|
717
|
+
line = renderMessage(waited === undefined ? msg('model.probe.verdict.ok') : msg('model.probe.verdict.okWaited', { time: probeSeconds(waited) }), lang);
|
|
717
718
|
break;
|
|
718
719
|
case 'auth':
|
|
719
|
-
line =
|
|
720
|
+
line = renderMessage(msg('model.probe.verdict.auth', { http }), lang);
|
|
720
721
|
recourse = 'check_credentials';
|
|
721
722
|
break;
|
|
722
723
|
case 'unreachable':
|
|
723
|
-
line =
|
|
724
|
+
line = renderMessage(waited === undefined ? msg('model.probe.verdict.unreachable') : msg('model.probe.verdict.unreachableWaited', { time: probeSeconds(waited) }), lang);
|
|
724
725
|
break;
|
|
725
726
|
case 'model':
|
|
726
|
-
line =
|
|
727
|
+
line = renderMessage(msg('model.probe.verdict.model', { http }), lang);
|
|
727
728
|
break;
|
|
728
729
|
case 'shape':
|
|
729
|
-
line =
|
|
730
|
+
line = renderMessage(msg('model.probe.verdict.shape', { http }), lang);
|
|
730
731
|
break;
|
|
731
732
|
case 'busy':
|
|
732
|
-
line =
|
|
733
|
+
line = renderMessage(msg('model.probe.verdict.busy', { http }), lang);
|
|
733
734
|
recourse = 'switch_model';
|
|
734
735
|
break;
|
|
735
736
|
case 'no_token':
|
|
736
|
-
line =
|
|
737
|
+
line = renderMessage(waited === undefined ? msg('model.probe.verdict.noToken') : msg('model.probe.verdict.noTokenWaited', { time: probeSeconds(waited) }), lang);
|
|
737
738
|
recourse = 'switch_model';
|
|
738
739
|
break;
|
|
739
740
|
case 'other':
|
|
740
|
-
line =
|
|
741
|
+
line = renderMessage(msg('model.probe.verdict.other', { http }), lang);
|
|
741
742
|
break;
|
|
742
743
|
}
|
|
743
744
|
return Object.freeze(recourse === undefined ? { line: `${prefix}${line}` } : { line: `${prefix}${line}`, recourse });
|
|
@@ -12,11 +12,13 @@ export type ModelIdentityLanes = {
|
|
|
12
12
|
[L in ModelIdentityLane]: ModelIdentityLaneReading;
|
|
13
13
|
};
|
|
14
14
|
export type EngineAnswerObservation = 'answered' | 'not_observed' | 'unreachable';
|
|
15
|
+
export type EngineCatalogAdoptionReading = 'absent' | 'refused' | 'undetermined';
|
|
15
16
|
export interface LocalEngineModelIdentityReading {
|
|
16
17
|
engine: 'local';
|
|
17
18
|
lanes: ModelIdentityLanes;
|
|
18
19
|
engineAnswer?: EngineAnswerObservation;
|
|
19
20
|
engineAcceptsCatalogDefault?: boolean;
|
|
21
|
+
catalogAdoption?: EngineCatalogAdoptionReading;
|
|
20
22
|
routeGap?: ModelRouteGapReading;
|
|
21
23
|
}
|
|
22
24
|
export type ModelRouteGapReading = 'endpoint_missing' | 'lane_credential_missing' | 'none';
|
|
@@ -31,6 +31,10 @@ function routeGapOf(reading) {
|
|
|
31
31
|
const v = own(reading, 'routeGap')?.v;
|
|
32
32
|
return v === 'endpoint_missing' || v === 'lane_credential_missing' || v === 'none' ? v : undefined;
|
|
33
33
|
}
|
|
34
|
+
function catalogAdoptionOf(reading) {
|
|
35
|
+
const v = own(reading, 'catalogAdoption')?.v;
|
|
36
|
+
return v === 'absent' || v === 'refused' || v === 'undetermined' ? v : undefined;
|
|
37
|
+
}
|
|
34
38
|
function analyse(reading) {
|
|
35
39
|
try {
|
|
36
40
|
if (!isPlainObject(reading))
|
|
@@ -47,25 +51,30 @@ function analyse(reading) {
|
|
|
47
51
|
const lanesHit = own(reading, 'lanes')?.v;
|
|
48
52
|
const order = laneOrder();
|
|
49
53
|
if (!isPlainObject(lanesHit)) {
|
|
50
|
-
return { verdict: 'unknown', why: 'lanes', unreadable: [], unreported: [...order], unusable: [], catalogUnconfirmed: null, catalogRefused:
|
|
54
|
+
return { verdict: 'unknown', why: 'lanes', unreadable: [], unreported: [...order], unusable: [], catalogUnconfirmed: null, catalogRefused: null };
|
|
51
55
|
}
|
|
52
56
|
const partial = [];
|
|
53
57
|
const unreadable = [];
|
|
54
58
|
const unreported = [];
|
|
55
59
|
const unusable = [];
|
|
56
|
-
let catalogRefused =
|
|
60
|
+
let catalogRefused = null;
|
|
57
61
|
let catalogUnconfirmed = null;
|
|
58
62
|
for (const lane of order) {
|
|
59
63
|
const s = laneState(lanesHit, lane);
|
|
60
64
|
if (lane === 'modelCatalogFile') {
|
|
61
65
|
if (s === 'complete') {
|
|
66
|
+
if (catalogAdoptionOf(reading) === 'refused') {
|
|
67
|
+
partial.push(lane);
|
|
68
|
+
catalogRefused = 'adoption';
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
62
71
|
const bit = own(reading, 'engineAcceptsCatalogDefault');
|
|
63
72
|
const evidence = catalogDefaultEvidence(s, bit?.v);
|
|
64
73
|
if (evidence !== undefined)
|
|
65
74
|
return { verdict: 'resolvable', why: 'catalog_default', evidence };
|
|
66
75
|
if (bit !== undefined && bit.v === false) {
|
|
67
76
|
partial.push(lane);
|
|
68
|
-
catalogRefused =
|
|
77
|
+
catalogRefused = 'engine';
|
|
69
78
|
}
|
|
70
79
|
else {
|
|
71
80
|
catalogUnconfirmed = bit === undefined || bit.v === undefined ? 'not_reported' : 'unusable';
|
|
@@ -151,7 +160,13 @@ export function modelIdentityDetail(reading) {
|
|
|
151
160
|
const partialClause = others.length > 0
|
|
152
161
|
? `${joinPhrases(others.map(laneLabel))} ${others.length > 1 ? 'carry' : 'carries'} part of a model configuration (such as a gateway address or a credential) but no model name`
|
|
153
162
|
: '';
|
|
154
|
-
if (a.catalogRefused) {
|
|
163
|
+
if (a.catalogRefused === 'adoption') {
|
|
164
|
+
const clause = msg('model.identity.catalogAdoption.refused', { lane: msg(LANE_LABEL_KEYS.modelCatalogFile) });
|
|
165
|
+
return partialClause !== ''
|
|
166
|
+
? renderMessage(msg('model.identity.catalogAdoption.notResolvableWithPartial', { clause, partial: partialClause }))
|
|
167
|
+
: renderMessage(msg('model.identity.catalogAdoption.notResolvable', { clause }));
|
|
168
|
+
}
|
|
169
|
+
if (a.catalogRefused === 'engine') {
|
|
155
170
|
return (`no model name is configured for the local engine to start with — ${laneLabel('modelCatalogFile')} names a default model, but the local engine is reported not to accept a catalog default in place of a startup model name` +
|
|
156
171
|
(partialClause !== '' ? `, and ${partialClause}` : '') +
|
|
157
172
|
', and the engine does not start without one');
|
|
@@ -179,7 +194,10 @@ export function modelIdentityDetail(reading) {
|
|
|
179
194
|
else if (a.catalogUnconfirmed === 'unusable') {
|
|
180
195
|
parts.push(`${laneLabel('modelCatalogFile')} names a default model, but the report of whether the local engine accepts a catalog default in place of a startup model name gave no usable reading`);
|
|
181
196
|
}
|
|
182
|
-
else if (a.catalogRefused) {
|
|
197
|
+
else if (a.catalogRefused === 'adoption') {
|
|
198
|
+
parts.push(renderMessage(msg('model.identity.catalogAdoption.refused', { lane: msg(LANE_LABEL_KEYS.modelCatalogFile) })));
|
|
199
|
+
}
|
|
200
|
+
else if (a.catalogRefused === 'engine') {
|
|
183
201
|
parts.push(`${laneLabel('modelCatalogFile')} names a default model, but the local engine is reported not to accept a catalog default in place of a startup model name`);
|
|
184
202
|
}
|
|
185
203
|
return `whether the local engine has a model name is unknown — ${joinPhrases(parts)}, and no other place this client reads provides one`;
|
package/dist/ownKey.d.ts
CHANGED
|
@@ -33,3 +33,29 @@ export interface HumanInputAttachmentView {
|
|
|
33
33
|
export declare function humanInputAttachmentsOf(frame: {} | null | undefined): HumanInputAttachmentView[] | undefined;
|
|
34
34
|
export declare function markMcpSectionDroppedNamedRows(rows: object, dropped: ReadonlyMap<string, number>): void;
|
|
35
35
|
export declare function mcpSectionDroppedNamedRowsOf(rows: object | null | undefined, name: string): number;
|
|
36
|
+
export interface PromptManifestSectionRow {
|
|
37
|
+
id: string;
|
|
38
|
+
chars: number;
|
|
39
|
+
band?: string;
|
|
40
|
+
locale?: string;
|
|
41
|
+
variant?: string;
|
|
42
|
+
contentHash?: string;
|
|
43
|
+
slot?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface PromptManifestIdentityRow {
|
|
46
|
+
readonly artifact: string;
|
|
47
|
+
readonly layers: PromptIdentityLayersRow;
|
|
48
|
+
readonly epoch: number;
|
|
49
|
+
readonly activatedBy: string;
|
|
50
|
+
}
|
|
51
|
+
export interface PromptIdentityLayersRow {
|
|
52
|
+
readonly catalog: string;
|
|
53
|
+
readonly renderers: Readonly<Record<string, number>>;
|
|
54
|
+
readonly center?: string;
|
|
55
|
+
readonly deploy?: string;
|
|
56
|
+
readonly task?: string;
|
|
57
|
+
readonly binding: string;
|
|
58
|
+
}
|
|
59
|
+
export declare function promptManifestSectionViewOf(row: object): PromptManifestSectionRow | undefined;
|
|
60
|
+
export declare function promptManifestIdentityOfFrame(frame: object): PromptManifestIdentityRow | undefined;
|
|
61
|
+
export declare function promptManifestIdentityOf(raw: {} | null | undefined): PromptManifestIdentityRow | undefined;
|