@sema-agent/client-core 0.68.2 → 0.69.1
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 +91 -0
- package/README.md +7 -6
- package/dist/adapt/arms.js +31 -1
- package/dist/adapt/textStream.d.ts +25 -0
- package/dist/adapt/textStream.js +50 -0
- package/dist/adapter/downstream/eventToSdkMessage.js +50 -14
- package/dist/adapter/runStream.js +9 -1
- package/dist/coreValuePorts.d.ts +161 -0
- package/dist/coreValuePorts.js +98 -0
- package/dist/engineNoticeCodes.d.ts +1 -1
- package/dist/engineNoticeCodes.js +12 -1
- package/dist/gateOutcome.d.ts +27 -13
- package/dist/gateOutcome.js +29 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/mcpPanel.d.ts +45 -1
- package/dist/mcpPanel.js +25 -1
- package/dist/sdkWireTransit.d.ts +1 -1
- package/dist/seam.d.ts +47 -1
- package/dist/seam.js +8 -0
- package/dist/workflowClient.d.ts +20 -0
- package/dist/workflowClient.js +23 -1
- package/dist/workflowMonitor.d.ts +10 -0
- package/dist/workflowMonitor.js +0 -16
- package/docs/INTEGRATION-CLIENTS.md +147 -9
- package/package.json +5 -5
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* coreValuePorts.ts — 引擎(`@sema-agent/core`)**值级**面的端口注入口(CC-07,0.69.0;cli L-249 到期桶 core-value 清零)。
|
|
3
|
+
*
|
|
4
|
+
* ## 这一格要解决的问题
|
|
5
|
+
* 壳(cli)有五组逻辑必须与引擎**跑同一个函数体**才不分歧:自主循环提示词的组装、权限规则「放宽」判据、
|
|
6
|
+
* 工具策略的组合、工具名的协议/退役/语法判别与规则编译校验、讨论工作流的名字。它们此前在壳里**值级直连**
|
|
7
|
+
* `@sema-agent/core`(cli sdk-isolation 门的 `core-value` 桶,retireBy 已过期),而 web / desktop 座位层
|
|
8
|
+
* 结构上装不了引擎 —— 同一句判据在三端里只有一端有。
|
|
9
|
+
*
|
|
10
|
+
* ## 🔴 为什么是端口注入而不是 `export … from '@sema-agent/core'`
|
|
11
|
+
* 与 `hitl/editedRuleTextPrecheck.ts` 逐字同一条硬约束:本包的可移植门是外部包**等值集**(`{diff, @sema-agent/sdk}`)
|
|
12
|
+
* + `--platform=browser` 真打包,而 core 的 barrel 值级拉 `node:crypto` / `node:fs` / `node:path` ⇒ 一条值级
|
|
13
|
+
* re-export 会把整台引擎焊进每一个装本包的端。⇒ **包声明端口 + 诚实缺席读口;Node 宿主在装配根把 core 的真实现
|
|
14
|
+
* 原样装进来(不许包一层判断);浏览器 lane 留缺席走各自的往返/降级形**。
|
|
15
|
+
*
|
|
16
|
+
* ## 形(逐组,签名与 core 7.18.0 `dist/**.d.ts` 逐字同,只把 core 私有型换成**结构等价的镜像**)
|
|
17
|
+
* · `resolveAutonomousLoopPrompt(prompt, opts?)` → `string | null`(core `tools/loop-tick.d.ts`);
|
|
18
|
+
* · `loosenReasons(prior, next)` → `string[]`(core `core/session-permission-rules`;两参用 sdk 的
|
|
19
|
+
* `SessionPermissionRules`,与 core 同名同形);
|
|
20
|
+
* · `combinePolicies(...policies)` / `createAllowDenyPolicy(opts)` → 工具策略(core `core/tool-policy.d.ts`;
|
|
21
|
+
* 策略对本包是**不透明句柄** {@link CoreToolPolicyHandle}:本包不调 `check`,只把它交回引擎/请求装配);
|
|
22
|
+
* · `MCP_NAMESPACE` / `RETIRED_TOOL_NAMES` / `protocolOf(name)` / `ruleToolGrammarOf(toolName)` /
|
|
23
|
+
* `validatePermissionRules(rules, opts?)`(core `core/protocol-table.d.ts` / `core/permission-rules.d.ts`);
|
|
24
|
+
* · `DISCUSSION_WORKFLOW_NAME`(core 常量 `"discussion"`)。
|
|
25
|
+
*
|
|
26
|
+
* ## 🔴 读口纪律(与 `precheckEditedRuleText` 同律)
|
|
27
|
+
* · 没装 ⇒ 返 `undefined`(**诚实缺席**),绝不返一个编出来的值(空数组 / 默认策略 / `"discussion"` 字面量都算编);
|
|
28
|
+
* · 装的必须是 core 的**同一只**实现,原样装 —— 包一层就把「同一函数体」这条唯一的抗漂移保证拆掉;
|
|
29
|
+
* · core 对调用方 bug 的响亮抛(如 `createAllowDenyPolicy` 的 `config.invalid_tool_name_set`)**原样上抛**,本层不吞;
|
|
30
|
+
* · 装口返回**还原函数**(还原到装之前那一只,不是无脑清空 —— 嵌套装载时无脑清空会抹掉外层)。
|
|
31
|
+
*
|
|
32
|
+
* ## 缺席语义(三端)
|
|
33
|
+
* · cli / desktop 主进程(Node,引擎在场):装配根一处 `installCoreValuePorts({...core 那十件...})`,缺席 = 宿主漏装 = bug;
|
|
34
|
+
* · web / desktop 渲染层:结构上装不了 ⇒ 恒缺席;消费点按 `undefined` 走各自的降级形(不判定、交引擎端裁)。
|
|
35
|
+
* 本口的缺席因此**不是**「宿主忘了装」的同义词,别拿它判部署形态(`hasCoreValuePorts()` 只答「装没装」)。
|
|
36
|
+
*/
|
|
37
|
+
import type { SessionPermissionRules } from '@sema-agent/sdk';
|
|
38
|
+
/** core `AutonomousLoopPromptOptions` 的逐形镜像(三键全可选)。 */
|
|
39
|
+
export interface AutonomousLoopPromptOptionsView {
|
|
40
|
+
firstTick?: boolean;
|
|
41
|
+
persistentVariant?: boolean;
|
|
42
|
+
pushNotification?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* core `ToolPolicy` 的**不透明句柄**:本包不调 `check`(那是引擎在 run 里做的事),只把策略原样交回。
|
|
46
|
+
* 结构上只钉「有一只 `check`」—— core 的 `ToolPolicy` / `NamedToolPolicy` 都可赋给它;反向刻意不钉。
|
|
47
|
+
*/
|
|
48
|
+
export interface CoreToolPolicyHandle {
|
|
49
|
+
readonly check: (req: never, signal?: AbortSignal) => CorePermissionResultView | Promise<CorePermissionResultView>;
|
|
50
|
+
readonly projection?: object;
|
|
51
|
+
}
|
|
52
|
+
/** core `PermissionResult` 的最小镜像(本包只钉判别位 `action`;其余位在引擎侧)。 */
|
|
53
|
+
export interface CorePermissionResultView {
|
|
54
|
+
readonly action: 'allow' | 'ask' | 'deny' | (string & {});
|
|
55
|
+
}
|
|
56
|
+
/** core `createAllowDenyPolicy` 的入参镜像。 */
|
|
57
|
+
export interface AllowDenyPolicyOptionsView {
|
|
58
|
+
allow?: string[];
|
|
59
|
+
deny?: string[];
|
|
60
|
+
/** 非裸工具名的 entry(规则内容形)怎么办:`throw`(缺省)在构造时拒;`skip` 丢掉并经 `onInvalidNameIssue` 报。 */
|
|
61
|
+
onInvalidName?: 'throw' | 'skip';
|
|
62
|
+
onInvalidNameIssue?: (issue: AllowDenyInvalidNameIssueView) => void;
|
|
63
|
+
}
|
|
64
|
+
/** `onInvalidName: 'skip'` 时逐条报出的那一件。 */
|
|
65
|
+
export interface AllowDenyInvalidNameIssueView {
|
|
66
|
+
entry: string;
|
|
67
|
+
list: 'allow' | 'deny';
|
|
68
|
+
message: string;
|
|
69
|
+
}
|
|
70
|
+
/** core `ProtocolNamespace` 的镜像(`id` 按开集读:core 今天 `mcp` / `a2a` 两词)。 */
|
|
71
|
+
export interface CoreProtocolNamespaceView {
|
|
72
|
+
readonly id: string;
|
|
73
|
+
readonly prefix: string;
|
|
74
|
+
makeName(peer: string, tool: string): string;
|
|
75
|
+
/** 解不出 ⇒ `undefined`(core `ProtocolPeerTool` 对本包不透明,只钉「解出了一个对象」)。 */
|
|
76
|
+
parse(name: string): object | undefined;
|
|
77
|
+
displayGroupKey(name: string): string;
|
|
78
|
+
}
|
|
79
|
+
/** core `PermissionRule` 的逐形镜像。 */
|
|
80
|
+
export interface PermissionRuleView {
|
|
81
|
+
rule: string;
|
|
82
|
+
behavior: 'deny' | 'ask' | 'allow';
|
|
83
|
+
source?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* core `PermissionRuleIssue` 的镜像。🔴 `code` 按**开集串**读:core 那张码表(`invalid.*` / `unsupported.*`)属主在引擎,
|
|
87
|
+
* 镜像枚举 = 引擎加员当天把一个合法码判没(#157 词表纪律)。
|
|
88
|
+
*/
|
|
89
|
+
export interface PermissionRuleIssueView {
|
|
90
|
+
rule: string;
|
|
91
|
+
code: string;
|
|
92
|
+
message: string;
|
|
93
|
+
}
|
|
94
|
+
/** core `validatePermissionRules` 第二参的镜像(`Pick<PermissionRulePolicyOptions, …>` 四键)。 */
|
|
95
|
+
export interface ValidatePermissionRulesOptionsView {
|
|
96
|
+
primaryFieldGeneric?: 'reject' | 'allow-lexical';
|
|
97
|
+
/** core `Partial<PermissionRuleCaps>`;本包不钉各帽名(属主在引擎),按对象透传。 */
|
|
98
|
+
caps?: object;
|
|
99
|
+
ruleFaces?: (toolName: string) => object | undefined;
|
|
100
|
+
/** core `PathRuleBases`:`cwd` / `root` / `home` 三基各可选(按开集键读)。 */
|
|
101
|
+
pathBases?: {
|
|
102
|
+
readonly [base: string]: string | undefined;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** 十件端口的**形**(每一件的唯一合法实参 = core 导出的同名那一只,原样装)。 */
|
|
106
|
+
export interface CoreValuePorts {
|
|
107
|
+
resolveAutonomousLoopPrompt: (prompt: string, opts?: AutonomousLoopPromptOptionsView) => string | null;
|
|
108
|
+
loosenReasons: (prior: SessionPermissionRules, next: SessionPermissionRules) => string[];
|
|
109
|
+
combinePolicies: (...policies: CoreToolPolicyHandle[]) => CoreToolPolicyHandle;
|
|
110
|
+
createAllowDenyPolicy: (opts: AllowDenyPolicyOptionsView) => CoreToolPolicyHandle;
|
|
111
|
+
MCP_NAMESPACE: CoreProtocolNamespaceView;
|
|
112
|
+
RETIRED_TOOL_NAMES: ReadonlyMap<string, string>;
|
|
113
|
+
protocolOf: (name: string) => CoreProtocolNamespaceView | undefined;
|
|
114
|
+
ruleToolGrammarOf: (toolName: string) => 'command' | 'path' | undefined;
|
|
115
|
+
validatePermissionRules: (rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView) => PermissionRuleIssueView[];
|
|
116
|
+
DISCUSSION_WORKFLOW_NAME: string;
|
|
117
|
+
}
|
|
118
|
+
/** 端口名的闭集(读口逐名一一对应;`hasCoreValuePort(name)` 的入参域)。 */
|
|
119
|
+
export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "RETIRED_TOOL_NAMES", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "DISCUSSION_WORKFLOW_NAME"];
|
|
120
|
+
export type CoreValuePortName = (typeof CORE_VALUE_PORT_NAMES)[number];
|
|
121
|
+
/**
|
|
122
|
+
* 装/卸端口(可以只装一部分:没装的那几件读口照旧缺席)。返回**还原函数**(还原到装之前那一袋)。
|
|
123
|
+
*
|
|
124
|
+
* Node 宿主的装法(**逐字**,别加工):
|
|
125
|
+
* ```ts
|
|
126
|
+
* import { resolveAutonomousLoopPrompt, loosenReasons, combinePolicies, createAllowDenyPolicy,
|
|
127
|
+
* MCP_NAMESPACE, RETIRED_TOOL_NAMES, protocolOf, ruleToolGrammarOf, validatePermissionRules,
|
|
128
|
+
* DISCUSSION_WORKFLOW_NAME } from '@sema-agent/core'
|
|
129
|
+
* installCoreValuePorts({ resolveAutonomousLoopPrompt, loosenReasons, combinePolicies, createAllowDenyPolicy,
|
|
130
|
+
* MCP_NAMESPACE, RETIRED_TOOL_NAMES, protocolOf, ruleToolGrammarOf, validatePermissionRules,
|
|
131
|
+
* DISCUSSION_WORKFLOW_NAME })
|
|
132
|
+
* ```
|
|
133
|
+
* 🔴 传 `null` = 卸;传一袋 = **整袋替换**(不与上一袋合并 —— 合并会让「卸掉一件」这件事无法表达)。
|
|
134
|
+
*/
|
|
135
|
+
export declare function installCoreValuePorts(ports: Partial<CoreValuePorts> | null): () => void;
|
|
136
|
+
/** 装没装(整袋)。`false` 时所有读口缺席。 */
|
|
137
|
+
export declare function hasCoreValuePorts(): boolean;
|
|
138
|
+
/** 某一件装没装(存在性读口哨兵:`boolean` 形)。 */
|
|
139
|
+
export declare function hasCoreValuePort(name: CoreValuePortName): boolean;
|
|
140
|
+
/** 十件里还没装的那几件的名字(宿主自检 / doctor 行用;全装 ⇒ `[]`,整袋没装 ⇒ 十件全列)。 */
|
|
141
|
+
export declare function coreValuePortMisses(): readonly CoreValuePortName[];
|
|
142
|
+
/** 自主循环提示词组装(core `resolveAutonomousLoopPrompt`)。没装 ⇒ `undefined`;装了但 core 判「不组」⇒ `null`(两态不折)。 */
|
|
143
|
+
export declare function resolveAutonomousLoopPrompt(prompt: string, opts?: AutonomousLoopPromptOptionsView): string | null | undefined;
|
|
144
|
+
/** 「`next` 相对 `prior` 放宽了哪些」(core `loosenReasons`;空数组 = 没放宽)。没装 ⇒ `undefined`(不是 `[]`)。 */
|
|
145
|
+
export declare function loosenReasons(prior: SessionPermissionRules, next: SessionPermissionRules): string[] | undefined;
|
|
146
|
+
/** 组合工具策略(core `combinePolicies`,deny-wins)。没装 ⇒ `undefined`。 */
|
|
147
|
+
export declare function combinePolicies(...policies: CoreToolPolicyHandle[]): CoreToolPolicyHandle | undefined;
|
|
148
|
+
/** 白/黑名单策略(core `createAllowDenyPolicy`;`onInvalidName` 缺省 `throw`,core 响亮抛原样上抛)。没装 ⇒ `undefined`。 */
|
|
149
|
+
export declare function createAllowDenyPolicy(opts: AllowDenyPolicyOptionsView): CoreToolPolicyHandle | undefined;
|
|
150
|
+
/** MCP 协议命名空间(core `MCP_NAMESPACE`;`prefix` 今天 `mcp__`)。没装 ⇒ `undefined`。 */
|
|
151
|
+
export declare function mcpNamespace(): CoreProtocolNamespaceView | undefined;
|
|
152
|
+
/** 退役工具名 → 继任名(core `RETIRED_TOOL_NAMES`)。没装 ⇒ `undefined`(不是空 Map)。 */
|
|
153
|
+
export declare function retiredToolNames(): ReadonlyMap<string, string> | undefined;
|
|
154
|
+
/** 名字属于哪个协议命名空间(core `protocolOf`)。没装 ⇒ `undefined`;装了但不属任何协议 ⇒ 也是 `undefined`(两态在这一格上**不可分**,要分先问 `hasCoreValuePort('protocolOf')`)。 */
|
|
155
|
+
export declare function protocolOf(name: string): CoreProtocolNamespaceView | undefined;
|
|
156
|
+
/** 规则内容语法族(core `ruleToolGrammarOf`;`command` / `path`)。没装 ⇒ `undefined`(与「该工具无语法族」同形,要分先问 `hasCoreValuePort`)。 */
|
|
157
|
+
export declare function ruleToolGrammarOf(toolName: string): 'command' | 'path' | undefined;
|
|
158
|
+
/** 规则编译校验(core `validatePermissionRules`;空数组 = 全部编译得了)。没装 ⇒ `undefined`(不是 `[]` —— 那会把「没校」说成「全过」)。 */
|
|
159
|
+
export declare function validatePermissionRules(rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView): PermissionRuleIssueView[] | undefined;
|
|
160
|
+
/** 讨论工作流的名字(core `DISCUSSION_WORKFLOW_NAME`,今天 `"discussion"`)。没装 ⇒ `undefined`(不铸字面量)。 */
|
|
161
|
+
export declare function discussionWorkflowName(): string | undefined;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** 端口名的闭集(读口逐名一一对应;`hasCoreValuePort(name)` 的入参域)。 */
|
|
2
|
+
export const CORE_VALUE_PORT_NAMES = Object.freeze([
|
|
3
|
+
'resolveAutonomousLoopPrompt',
|
|
4
|
+
'loosenReasons',
|
|
5
|
+
'combinePolicies',
|
|
6
|
+
'createAllowDenyPolicy',
|
|
7
|
+
'MCP_NAMESPACE',
|
|
8
|
+
'RETIRED_TOOL_NAMES',
|
|
9
|
+
'protocolOf',
|
|
10
|
+
'ruleToolGrammarOf',
|
|
11
|
+
'validatePermissionRules',
|
|
12
|
+
'DISCUSSION_WORKFLOW_NAME',
|
|
13
|
+
]);
|
|
14
|
+
let installed = null;
|
|
15
|
+
/**
|
|
16
|
+
* 装/卸端口(可以只装一部分:没装的那几件读口照旧缺席)。返回**还原函数**(还原到装之前那一袋)。
|
|
17
|
+
*
|
|
18
|
+
* Node 宿主的装法(**逐字**,别加工):
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { resolveAutonomousLoopPrompt, loosenReasons, combinePolicies, createAllowDenyPolicy,
|
|
21
|
+
* MCP_NAMESPACE, RETIRED_TOOL_NAMES, protocolOf, ruleToolGrammarOf, validatePermissionRules,
|
|
22
|
+
* DISCUSSION_WORKFLOW_NAME } from '@sema-agent/core'
|
|
23
|
+
* installCoreValuePorts({ resolveAutonomousLoopPrompt, loosenReasons, combinePolicies, createAllowDenyPolicy,
|
|
24
|
+
* MCP_NAMESPACE, RETIRED_TOOL_NAMES, protocolOf, ruleToolGrammarOf, validatePermissionRules,
|
|
25
|
+
* DISCUSSION_WORKFLOW_NAME })
|
|
26
|
+
* ```
|
|
27
|
+
* 🔴 传 `null` = 卸;传一袋 = **整袋替换**(不与上一袋合并 —— 合并会让「卸掉一件」这件事无法表达)。
|
|
28
|
+
*/
|
|
29
|
+
export function installCoreValuePorts(ports) {
|
|
30
|
+
const prev = installed;
|
|
31
|
+
installed = ports === null ? null : { ...ports };
|
|
32
|
+
return () => {
|
|
33
|
+
installed = prev;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** 装没装(整袋)。`false` 时所有读口缺席。 */
|
|
37
|
+
export function hasCoreValuePorts() {
|
|
38
|
+
return installed !== null;
|
|
39
|
+
}
|
|
40
|
+
/** 某一件装没装(存在性读口哨兵:`boolean` 形)。 */
|
|
41
|
+
export function hasCoreValuePort(name) {
|
|
42
|
+
return installed !== null && installed[name] !== undefined;
|
|
43
|
+
}
|
|
44
|
+
/** 十件里还没装的那几件的名字(宿主自检 / doctor 行用;全装 ⇒ `[]`,整袋没装 ⇒ 十件全列)。 */
|
|
45
|
+
export function coreValuePortMisses() {
|
|
46
|
+
return CORE_VALUE_PORT_NAMES.filter((n) => installed === null || installed[n] === undefined);
|
|
47
|
+
}
|
|
48
|
+
function port(name) {
|
|
49
|
+
return installed === null ? undefined : installed[name];
|
|
50
|
+
}
|
|
51
|
+
// ── 读口(逐件;没装 ⇒ undefined,绝不编值;core 的响亮抛原样上抛)──────────────────────────────
|
|
52
|
+
/** 自主循环提示词组装(core `resolveAutonomousLoopPrompt`)。没装 ⇒ `undefined`;装了但 core 判「不组」⇒ `null`(两态不折)。 */
|
|
53
|
+
export function resolveAutonomousLoopPrompt(prompt, opts) {
|
|
54
|
+
const fn = port('resolveAutonomousLoopPrompt');
|
|
55
|
+
return fn === undefined ? undefined : fn(prompt, opts);
|
|
56
|
+
}
|
|
57
|
+
/** 「`next` 相对 `prior` 放宽了哪些」(core `loosenReasons`;空数组 = 没放宽)。没装 ⇒ `undefined`(不是 `[]`)。 */
|
|
58
|
+
export function loosenReasons(prior, next) {
|
|
59
|
+
const fn = port('loosenReasons');
|
|
60
|
+
return fn === undefined ? undefined : fn(prior, next);
|
|
61
|
+
}
|
|
62
|
+
/** 组合工具策略(core `combinePolicies`,deny-wins)。没装 ⇒ `undefined`。 */
|
|
63
|
+
export function combinePolicies(...policies) {
|
|
64
|
+
const fn = port('combinePolicies');
|
|
65
|
+
return fn === undefined ? undefined : fn(...policies);
|
|
66
|
+
}
|
|
67
|
+
/** 白/黑名单策略(core `createAllowDenyPolicy`;`onInvalidName` 缺省 `throw`,core 响亮抛原样上抛)。没装 ⇒ `undefined`。 */
|
|
68
|
+
export function createAllowDenyPolicy(opts) {
|
|
69
|
+
const fn = port('createAllowDenyPolicy');
|
|
70
|
+
return fn === undefined ? undefined : fn(opts);
|
|
71
|
+
}
|
|
72
|
+
/** MCP 协议命名空间(core `MCP_NAMESPACE`;`prefix` 今天 `mcp__`)。没装 ⇒ `undefined`。 */
|
|
73
|
+
export function mcpNamespace() {
|
|
74
|
+
return port('MCP_NAMESPACE');
|
|
75
|
+
}
|
|
76
|
+
/** 退役工具名 → 继任名(core `RETIRED_TOOL_NAMES`)。没装 ⇒ `undefined`(不是空 Map)。 */
|
|
77
|
+
export function retiredToolNames() {
|
|
78
|
+
return port('RETIRED_TOOL_NAMES');
|
|
79
|
+
}
|
|
80
|
+
/** 名字属于哪个协议命名空间(core `protocolOf`)。没装 ⇒ `undefined`;装了但不属任何协议 ⇒ 也是 `undefined`(两态在这一格上**不可分**,要分先问 `hasCoreValuePort('protocolOf')`)。 */
|
|
81
|
+
export function protocolOf(name) {
|
|
82
|
+
const fn = port('protocolOf');
|
|
83
|
+
return fn === undefined ? undefined : fn(name);
|
|
84
|
+
}
|
|
85
|
+
/** 规则内容语法族(core `ruleToolGrammarOf`;`command` / `path`)。没装 ⇒ `undefined`(与「该工具无语法族」同形,要分先问 `hasCoreValuePort`)。 */
|
|
86
|
+
export function ruleToolGrammarOf(toolName) {
|
|
87
|
+
const fn = port('ruleToolGrammarOf');
|
|
88
|
+
return fn === undefined ? undefined : fn(toolName);
|
|
89
|
+
}
|
|
90
|
+
/** 规则编译校验(core `validatePermissionRules`;空数组 = 全部编译得了)。没装 ⇒ `undefined`(不是 `[]` —— 那会把「没校」说成「全过」)。 */
|
|
91
|
+
export function validatePermissionRules(rules, opts) {
|
|
92
|
+
const fn = port('validatePermissionRules');
|
|
93
|
+
return fn === undefined ? undefined : fn(rules, opts);
|
|
94
|
+
}
|
|
95
|
+
/** 讨论工作流的名字(core `DISCUSSION_WORKFLOW_NAME`,今天 `"discussion"`)。没装 ⇒ `undefined`(不铸字面量)。 */
|
|
96
|
+
export function discussionWorkflowName() {
|
|
97
|
+
return port('DISCUSSION_WORKFLOW_NAME');
|
|
98
|
+
}
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
/** 一条通告是**说给谁听**的。两值,刻意不设第三值(见模块顶注)。 */
|
|
55
55
|
export type NoticeAudience = 'user' | 'operator';
|
|
56
56
|
/**
|
|
57
|
-
* 引擎**成文码册**的逐字镜像(core `ENGINE_NOTICE_CODES`,**7.17.x
|
|
57
|
+
* 引擎**成文码册**的逐字镜像(core `ENGINE_NOTICE_CODES`,**7.18.0 = 五十六码**(7.17.x 五十二 + #748 两枚 writeFace + #742 两枚 classifier,均 operator);顺序同源)。
|
|
58
58
|
* 🔴 这是一份**抄件**,不是本包的意见 —— 改它必须同 commit 附 core 坐标,且门会先红。
|
|
59
59
|
* ⚠️ `EngineNotice.code` 的型面在上游**故意留 `string`**(宿主把自己的通告转发进同一个水槽是
|
|
60
60
|
* 被支持的形),所以本表是**判据**不是型 —— 别拿它去窄化那个字段。
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
* 出现在本包源码或产物里 => 当场红。
|
|
53
53
|
*/
|
|
54
54
|
/**
|
|
55
|
-
* 引擎**成文码册**的逐字镜像(core `ENGINE_NOTICE_CODES`,**7.17.x
|
|
55
|
+
* 引擎**成文码册**的逐字镜像(core `ENGINE_NOTICE_CODES`,**7.18.0 = 五十六码**(7.17.x 五十二 + #748 两枚 writeFace + #742 两枚 classifier,均 operator);顺序同源)。
|
|
56
56
|
* 🔴 这是一份**抄件**,不是本包的意见 —— 改它必须同 commit 附 core 坐标,且门会先红。
|
|
57
57
|
* ⚠️ `EngineNotice.code` 的型面在上游**故意留 `string`**(宿主把自己的通告转发进同一个水槽是
|
|
58
58
|
* 被支持的形),所以本表是**判据**不是型 —— 别拿它去窄化那个字段。
|
|
@@ -67,6 +67,9 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
67
67
|
'config.models_swapped',
|
|
68
68
|
'config.read_face_swapped',
|
|
69
69
|
'config.read_face_deployment_clamped',
|
|
70
|
+
// core 7.18.0 #748(0.68.3 提货批 CC-05):writeFace 席的两枚运维通告;位置 = governance-codes.d.ts 元组 @6/@7 真字节。
|
|
71
|
+
'config.write_face_swapped',
|
|
72
|
+
'config.write_face_deployment_clamped',
|
|
70
73
|
'config.tool_model_gate_removed',
|
|
71
74
|
'config.tool_model_gate_unknown_class',
|
|
72
75
|
'config.tool_model_gate_env_invalid',
|
|
@@ -83,6 +86,8 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
83
86
|
'peer.held_settled',
|
|
84
87
|
'peer.idle_subscription',
|
|
85
88
|
'classifier.denial_limit',
|
|
89
|
+
// core 7.18.0 #742(CC-05):分类器席坏配置 ⇒ 主模型代判的一条运维通告;元组 @22。
|
|
90
|
+
'classifier.fallback',
|
|
86
91
|
'checkpoint.execution_outcome_unrecorded',
|
|
87
92
|
'delegation.transcript_integrity',
|
|
88
93
|
'delegation.ask_unresolvable',
|
|
@@ -104,6 +109,8 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
104
109
|
'memory.consolidation_refused',
|
|
105
110
|
'memory.consolidation_withheld',
|
|
106
111
|
'route.fallback_to_primary',
|
|
112
|
+
// core 7.18.0 #742(CC-05):分类器候选梯子无可路由席;元组 @44。
|
|
113
|
+
'route.classifier_unroutable',
|
|
107
114
|
'route.base_url_changed_key_unchanged',
|
|
108
115
|
'task.user_steer_undrained',
|
|
109
116
|
'task.user_followup_undrained',
|
|
@@ -137,6 +144,8 @@ export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
137
144
|
'config.models_swapped': 'operator',
|
|
138
145
|
'config.read_face_swapped': 'operator',
|
|
139
146
|
'config.read_face_deployment_clamped': 'operator',
|
|
147
|
+
'config.write_face_swapped': 'operator',
|
|
148
|
+
'config.write_face_deployment_clamped': 'operator',
|
|
140
149
|
'config.tool_model_gate_removed': 'operator',
|
|
141
150
|
'config.tool_model_gate_unknown_class': 'operator',
|
|
142
151
|
'config.tool_model_gate_env_invalid': 'operator',
|
|
@@ -152,6 +161,7 @@ export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
152
161
|
'peer.held_settled': 'user',
|
|
153
162
|
'peer.idle_subscription': 'user',
|
|
154
163
|
'classifier.denial_limit': 'user',
|
|
164
|
+
'classifier.fallback': 'operator',
|
|
155
165
|
'checkpoint.execution_outcome_unrecorded': 'operator',
|
|
156
166
|
'delegation.transcript_integrity': 'operator',
|
|
157
167
|
'delegation.ask_unresolvable': 'user',
|
|
@@ -175,6 +185,7 @@ export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
175
185
|
// 理由 = 这条通告没有 sessionId,一次固化跑在任何会话之外)。
|
|
176
186
|
'memory.consolidation_withheld': 'operator',
|
|
177
187
|
'route.fallback_to_primary': 'operator',
|
|
188
|
+
'route.classifier_unroutable': 'operator',
|
|
178
189
|
'route.base_url_changed_key_unchanged': 'operator',
|
|
179
190
|
'task.user_steer_undrained': 'user',
|
|
180
191
|
'task.user_followup_undrained': 'user',
|
package/dist/gateOutcome.d.ts
CHANGED
|
@@ -51,8 +51,12 @@ import type { DeniedBy, Settlement } from '@sema-agent/sdk';
|
|
|
51
51
|
*/
|
|
52
52
|
export type GateDispositionView = {
|
|
53
53
|
kind: 'allowed';
|
|
54
|
+
/** 0.68.3(core 7.18.0 #742):分类器轮记录;缺席 = 未知(见 {@link GateClassifierRoundView})。 */
|
|
55
|
+
classifier?: GateClassifierRoundView;
|
|
54
56
|
} | {
|
|
55
57
|
kind: 'denied';
|
|
58
|
+
/** 同上 —— 两臂都可带(core `GateDisposition` 两臂各自声明,本层逐臂逐键挑)。 */
|
|
59
|
+
classifier?: GateClassifierRoundView;
|
|
56
60
|
deniedBy: DeniedBy | (string & {});
|
|
57
61
|
/**
|
|
58
62
|
* 0.67.0(core 7.14.0 #688)—— 这次 deny 是**分类器那一轮没能裁决**的哪一形
|
|
@@ -69,6 +73,29 @@ export type GateDispositionView = {
|
|
|
69
73
|
*/
|
|
70
74
|
cause?: string;
|
|
71
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* 0.68.3(core 7.18.0 #742)—— **分类器那一轮到底问了谁**(`AutoModeClassifierRound` 的防御读视图)。
|
|
78
|
+
*
|
|
79
|
+
* 🔴 **缺席 = 未知 ≠ 席自答**(core 提货单 [7281] 逐字):缺席同时覆盖「这不是分类器轮」「老引擎」
|
|
80
|
+
* 「分类器席没配」三形,端**禁**读成「主模型自己判的」。
|
|
81
|
+
* · `modelRequested` / `modelUsed`:请求的席与实际答题的模型(两者不同 ⇒ 走了候选梯子)。
|
|
82
|
+
* · `fallback`:从哪一级退到哪一级、为什么(`cause` = core `AUTO_MODE_FALLBACK_CAUSES` 三词
|
|
83
|
+
* `error` / `timeout` / `parse_error`,**按开集读**;本包不持该表)。缺席 = 没退。
|
|
84
|
+
* ⚠️ core 顶注:prompt 都没能组出来的那一形也记成 `{from: seat, to: main, cause: "error"}`——
|
|
85
|
+
* 「没问过任何模型」与「问了但坏了」在这一位上**分不开**,端别据它渲「分类器席坏了」。
|
|
86
|
+
* 🔴 两个必在位缺一 ⇒ 整只 `classifier` 缺席(半只视图比没有更坏);`fallback` 三键缺一 ⇒ 只丢 `fallback`。
|
|
87
|
+
*/
|
|
88
|
+
export interface GateClassifierRoundView {
|
|
89
|
+
modelRequested: string;
|
|
90
|
+
modelUsed: string;
|
|
91
|
+
fallback?: GateClassifierFallbackView;
|
|
92
|
+
}
|
|
93
|
+
/** 分类器候选梯子的一次退级:从哪一级到哪一级、为什么(`cause` 按开集读)。 */
|
|
94
|
+
export interface GateClassifierFallbackView {
|
|
95
|
+
from: string;
|
|
96
|
+
to: string;
|
|
97
|
+
cause: string;
|
|
98
|
+
}
|
|
72
99
|
/** 结算方的身份座(形由 {@link SettlementView.kind} 决定,本读器不重铸那张配对表)。 */
|
|
73
100
|
export interface SettlementWhoView {
|
|
74
101
|
/** `person` / `engine` / `host` / `none`(开集读)。 */
|
|
@@ -96,19 +123,6 @@ export interface GateOutcomeView {
|
|
|
96
123
|
/** 谁**问**的(core `ASK_ORIGINS`,7.6.0 起十词;**按开集读**)。与 {@link settlement} 同在同缺。 */
|
|
97
124
|
origin?: string;
|
|
98
125
|
}
|
|
99
|
-
/**
|
|
100
|
-
* `tool_end` 帧(或本包投影出的 `tool_end_result` 内部臂、耐久行的 resolved outcome)→ 门记录。
|
|
101
|
-
*
|
|
102
|
-
* 入参是**帧**而不是 `frame.gate`,刻意如此:端不必知道这条记录挂在哪个键上(那正是下一次形变
|
|
103
|
-
* 会动的东西),也不必自己判「这一帧带不带门」。
|
|
104
|
-
*
|
|
105
|
-
* 🔴 `disposition` 是**唯一的承重座**:它读不出来 ⇒ 整只 `undefined`。一条只有 `settlement` 而
|
|
106
|
-
* 说不出「放行还是拒了」的记录,消费端能从它得到的只有误导。
|
|
107
|
-
* 🔴 **不校 I1–I4 那四条不变量**(`settlement` ⇔ `origin` 同在、`ask_resolution` ⇒ 有拒绝类结算……):
|
|
108
|
-
* 筛子的属主是引擎,server 对过不了筛的记录**整条不投**。包再校一遍,只会在上游合法演进的当天
|
|
109
|
-
* 把一条真记录判没,而本层给不出比「原样交给端」更好的降级动作(`wiring_manifest.autoMode`
|
|
110
|
-
* 那一段的反向先例是**同一条帧上的段内自洽**,不是跨系统的不变量,两者刻意不同处置)。
|
|
111
|
-
*/
|
|
112
126
|
export declare function gateOutcomeOf(frame: unknown): GateOutcomeView | undefined;
|
|
113
127
|
/**
|
|
114
128
|
* 这次调用是**被门 park 了**吗 —— 「没在这里结算」的**第二形**(engine 7.64.0 真机黑盒直证)。
|
package/dist/gateOutcome.js
CHANGED
|
@@ -56,6 +56,26 @@ function readSettlement(v) {
|
|
|
56
56
|
* 把一条真记录判没,而本层给不出比「原样交给端」更好的降级动作(`wiring_manifest.autoMode`
|
|
57
57
|
* 那一段的反向先例是**同一条帧上的段内自洽**,不是跨系统的不变量,两者刻意不同处置)。
|
|
58
58
|
*/
|
|
59
|
+
function readClassifierRound(raw) {
|
|
60
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
61
|
+
return undefined;
|
|
62
|
+
const r = raw;
|
|
63
|
+
const modelRequested = str(r.modelRequested);
|
|
64
|
+
const modelUsed = str(r.modelUsed);
|
|
65
|
+
if (modelRequested === undefined || modelUsed === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
const view = { modelRequested, modelUsed };
|
|
68
|
+
const fb = r.fallback;
|
|
69
|
+
if (typeof fb === 'object' && fb !== null && !Array.isArray(fb)) {
|
|
70
|
+
const f = fb;
|
|
71
|
+
const from = str(f.from);
|
|
72
|
+
const to = str(f.to);
|
|
73
|
+
const cause = str(f.cause);
|
|
74
|
+
if (from !== undefined && to !== undefined && cause !== undefined)
|
|
75
|
+
view.fallback = { from, to, cause };
|
|
76
|
+
}
|
|
77
|
+
return view;
|
|
78
|
+
}
|
|
59
79
|
export function gateOutcomeOf(frame) {
|
|
60
80
|
if (typeof frame !== 'object' || frame === null || Array.isArray(frame))
|
|
61
81
|
return undefined;
|
|
@@ -69,8 +89,10 @@ export function gateOutcomeOf(frame) {
|
|
|
69
89
|
const dr = d;
|
|
70
90
|
const dk = str(dr.kind);
|
|
71
91
|
let disposition;
|
|
92
|
+
// 0.68.3(core 7.18.0 #742):两臂都可带 `classifier`;逐键挑、缺席不铸键。
|
|
93
|
+
const classifier = readClassifierRound(dr.classifier);
|
|
72
94
|
if (dk === 'allowed') {
|
|
73
|
-
disposition = { kind: 'allowed' };
|
|
95
|
+
disposition = { kind: 'allowed', ...(classifier !== undefined ? { classifier } : {}) };
|
|
74
96
|
}
|
|
75
97
|
else if (dk === 'denied') {
|
|
76
98
|
const deniedBy = str(dr.deniedBy);
|
|
@@ -79,7 +101,12 @@ export function gateOutcomeOf(frame) {
|
|
|
79
101
|
return undefined;
|
|
80
102
|
// 0.67.0:分类器 deny 的成因位(开集透传、缺席不铸键;判成员在 `classifierDenyCauseOf`)。
|
|
81
103
|
const cause = str(dr.cause);
|
|
82
|
-
disposition = {
|
|
104
|
+
disposition = {
|
|
105
|
+
kind: 'denied',
|
|
106
|
+
deniedBy,
|
|
107
|
+
...(cause !== undefined ? { cause } : {}),
|
|
108
|
+
...(classifier !== undefined ? { classifier } : {}),
|
|
109
|
+
};
|
|
83
110
|
}
|
|
84
111
|
else {
|
|
85
112
|
// 处置词本身不认识 ⇒ 整只不成形:`allowed` / `denied` 是这条记录的**判别位**,猜不得。
|
package/dist/index.d.ts
CHANGED
|
@@ -249,6 +249,7 @@ export { isAskTool } from './hitl/frameRouter.js';
|
|
|
249
249
|
export * from './hitl/hitlHostSurface.js';
|
|
250
250
|
export * from './hitl/toolApprovalWire.js';
|
|
251
251
|
export * from './hitl/editedRuleTextPrecheck.js';
|
|
252
|
+
export * from './coreValuePorts.js';
|
|
252
253
|
export * from './hitl/askGateWire.js';
|
|
253
254
|
export * from './hitl/planReviewWire.js';
|
|
254
255
|
export * from './hitl/gateIdentity.js';
|
package/dist/index.js
CHANGED
|
@@ -433,6 +433,8 @@ export * from './hitl/toolApprovalWire.js';
|
|
|
433
433
|
// `--platform=browser` 真打包,一条这样的边会把整台引擎焊进 web/desktop 的产物。
|
|
434
434
|
// ⇒ 转出口取「类型面 + 注入口 + 诚实缺席读口」三件(逐条理由见模块头注)。
|
|
435
435
|
export * from './hitl/editedRuleTextPrecheck.js';
|
|
436
|
+
// CC-07(0.69.0):core **值级**面十件的端口注入口(cli L-249 core-value 桶清零;同 editedRuleTextPrecheck 形:包声明端口 + 诚实缺席读口)。
|
|
437
|
+
export * from './coreValuePorts.js';
|
|
436
438
|
export * from './hitl/askGateWire.js';
|
|
437
439
|
export * from './hitl/planReviewWire.js';
|
|
438
440
|
// ── A-028.2/.3(#244 族A,2026-08-12):决断卡链的键词汇/呈现台账/归属判据三件 ————————————
|
package/dist/mcpPanel.d.ts
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpPanel.ts — `GET /v1/sessions/:id/mcp` 面板体(sdk `McpStatusPanel`)的**防御读视图**
|
|
3
|
+
* (CC-03,0.68.2;server 7.77.0 S-297 可选键 `lastLegMcp`;回 A-093 ③)。
|
|
4
|
+
*
|
|
5
|
+
* ── 为什么在包里(归层)────────────────────────────────────────────────────────────────────
|
|
6
|
+
* 面板体是三端都要渲的同一份读面:`servers[]` 是「这台部署此刻按需 materialize 出来的连接状态」,
|
|
7
|
+
* `lastLegMcp` 是「这个会话最近一条腿的账本里申报了哪些 MCP」。**两面合法可不同**(部署缺省场景
|
|
8
|
+
* 与按请求注入的名册本来就是两张表),契约 G.7 第 4 条禁止消费端拿它们对账后渲「不一致」。
|
|
9
|
+
* 这条纪律若各端自己写一遍,迟早有一端写反。⇒ 读法(哪些键、坏形怎么办、缺席说什么)只在这里
|
|
10
|
+
* 有一份;端只渲。
|
|
11
|
+
*
|
|
12
|
+
* ── 缺席语义(逐键)──────────────────────────────────────────────────────────────────────────
|
|
13
|
+
* · `lastLegMcp` **整键缺席** = server 的三形同形(新会话 / 最近腿的账本行在保留窗外 / 该腿没推
|
|
14
|
+
* `wiring_manifest`)**或**引擎早于 7.77.0;本视图同样不铸该键。「为什么缺席」这一位答不出来,
|
|
15
|
+
* 也不猜。
|
|
16
|
+
* · `lastLegMcp` **在场但形坏**(`runId` / `at` 不是非空串、`mcp` 读不出一行)⇒ 视图不铸该键,
|
|
17
|
+
* 改立 {@link McpPanelView.lastLegMcpUnreadable}(never false)。「引擎送了一份我读不懂的」与
|
|
18
|
+
* 「引擎没送」对运维是两句话,不折成一个 `undefined`。
|
|
19
|
+
* · `degraded`:只在 server 的超时臂铸(sdk openapi 顶注逐字)⇒ 本视图 never false:在场 = 取不到,
|
|
20
|
+
* 缺席 = 正常 materialize(`servers: []` 那时是「一台都没配」这句正面事实,不是「不知道」)。
|
|
21
|
+
* · `servers[]` 逐行:`name` + `status` 是必需两座(缺一丢该行,坏一行只丢那一行);**非空输入而零行
|
|
22
|
+
* 幸存 ⇒ 整个视图 `undefined`**(「我读不出来」不是「我知道是零」,与 `wiring_manifest.mcp`
|
|
23
|
+
* 同一条规矩)。`status` 按开集读(sdk 只声明 connected/failed 两词,core 未来加词照渲不丢行)。
|
|
24
|
+
* · `error`:server 已脱敏 + 200 字符封顶;本视图仍按 UNTRUSTED-for-display 再过一次
|
|
25
|
+
* {@link capForDisplay}(呈前消毒 + 封长),与本包其余远端文本铸点同律。
|
|
26
|
+
*
|
|
27
|
+
* ── `mcp[]` 条目与 `wiring_manifest` 第三段**同一只读器**─────────────────────────────────────
|
|
28
|
+
* `lastLegMcp.mcp[]` 是该腿 `wiring_manifest.mcp[]` 的逐字回放(server S-297),本视图直接调
|
|
29
|
+
* {@link projectMcpSection} —— 同一形、同一判据、同一缺席律;三端渲这两处用同一个
|
|
30
|
+
* {@link WiringManifestMcpEntry},不会出现「活体腿一种形、账本回放另一种形」。
|
|
31
|
+
*/
|
|
32
|
+
import type { AgentClient } from '@sema-agent/sdk';
|
|
1
33
|
import { type WiringManifestMcpEntry } from './adapter/downstream/eventToSdkMessage.js';
|
|
2
34
|
/** 面板 `servers[]` 一行(sdk `McpServerStatus` 的窄读;开集键不透传,逐键挑)。 */
|
|
3
35
|
export interface McpPanelServerView {
|
|
@@ -46,10 +78,22 @@ export interface McpPanelView {
|
|
|
46
78
|
* (契约 G.7 第 4 条:两面合法可不同)。
|
|
47
79
|
*/
|
|
48
80
|
export declare function projectMcpPanel(body: unknown): McpPanelView | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* 取面板体并投成读视图(CC-03 补件,0.69.0):`GET /v1/sessions/:id/mcp` 经 sdk `client.sessions.mcp`(自 sdk 0.0.75 在场,
|
|
83
|
+
* 与 `runs.subagentOutput` 同一条 transport,鉴权/principal 由 sdk 带 —— 本包**不**裸 fetch,不做第二套鉴权铸点)。
|
|
84
|
+
*
|
|
85
|
+
* 🔴 返回 `undefined` 的三形**同形**(与 {@link projectMcpPanel} 的缺席律一致):传输失败(网络 / 4xx / 5xx / abort)、
|
|
86
|
+
* 体读不出(必填位坏)、`sessionId` 空串(不发请求)。「为什么」不在返回值上 —— 传输失败留一行 `hostLog('debug')`,
|
|
87
|
+
* 端要分「未观测 vs 读不出」用 {@link mcpPanelLastLegDetail} 的 `reachable` 位(`view !== undefined` 即 reachable)。
|
|
88
|
+
* 🔴 `client` 只钉 `sessions` 一格(`Pick`):端传本包 `makeEngineWireClient` 造的实例即可,测试可喂假客户端。
|
|
89
|
+
*/
|
|
90
|
+
export declare function fetchMcpPanel(client: Pick<AgentClient, 'sessions'>, sessionId: string, opts?: {
|
|
91
|
+
signal?: AbortSignal;
|
|
92
|
+
}): Promise<McpPanelView | undefined>;
|
|
49
93
|
/**
|
|
50
94
|
* `lastLegMcp` 那一行措辞的**唯一铸点**(三端共用;别在各端的行装配里另写一遍)。
|
|
51
95
|
*
|
|
52
|
-
* 🔴
|
|
96
|
+
* 🔴 五句刻意逐字互异(黑盒锚;0.69.1 订正:此前写「四句」漏了「面板体读不出」那一句),且**没有一句**提到 `servers[]`:
|
|
53
97
|
* ① 在场 —— 名册 + runId + at;
|
|
54
98
|
* ② `opts.reachable === false` —— 「未观测」:这次进程没读到面板体;
|
|
55
99
|
* ③ 面板读到了但 `lastLegMcp` 整键缺席 —— 「不报」:三形同形 + 老引擎,**不武断咎为版本**;
|
package/dist/mcpPanel.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hostLog } from './host.js';
|
|
1
2
|
import { projectMcpSection } from './adapter/downstream/eventToSdkMessage.js';
|
|
2
3
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
3
4
|
/** `error` 上屏前的封长(server 侧 `slice(200)`,同值)。 */
|
|
@@ -70,10 +71,33 @@ export function projectMcpPanel(body) {
|
|
|
70
71
|
}
|
|
71
72
|
return view;
|
|
72
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* 取面板体并投成读视图(CC-03 补件,0.69.0):`GET /v1/sessions/:id/mcp` 经 sdk `client.sessions.mcp`(自 sdk 0.0.75 在场,
|
|
76
|
+
* 与 `runs.subagentOutput` 同一条 transport,鉴权/principal 由 sdk 带 —— 本包**不**裸 fetch,不做第二套鉴权铸点)。
|
|
77
|
+
*
|
|
78
|
+
* 🔴 返回 `undefined` 的三形**同形**(与 {@link projectMcpPanel} 的缺席律一致):传输失败(网络 / 4xx / 5xx / abort)、
|
|
79
|
+
* 体读不出(必填位坏)、`sessionId` 空串(不发请求)。「为什么」不在返回值上 —— 传输失败留一行 `hostLog('debug')`,
|
|
80
|
+
* 端要分「未观测 vs 读不出」用 {@link mcpPanelLastLegDetail} 的 `reachable` 位(`view !== undefined` 即 reachable)。
|
|
81
|
+
* 🔴 `client` 只钉 `sessions` 一格(`Pick`):端传本包 `makeEngineWireClient` 造的实例即可,测试可喂假客户端。
|
|
82
|
+
*/
|
|
83
|
+
export async function fetchMcpPanel(client, sessionId, opts) {
|
|
84
|
+
if (typeof sessionId !== 'string' || sessionId.length === 0)
|
|
85
|
+
return undefined;
|
|
86
|
+
let body;
|
|
87
|
+
try {
|
|
88
|
+
body = await client.sessions.mcp(sessionId, opts?.signal ? { signal: opts.signal } : undefined);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
const status = e?.status;
|
|
92
|
+
hostLog('debug', `[mcp-panel] ${sessionId}: ${typeof status === 'number' ? status : String(e).slice(0, 160)}`);
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
return projectMcpPanel(body);
|
|
96
|
+
}
|
|
73
97
|
/**
|
|
74
98
|
* `lastLegMcp` 那一行措辞的**唯一铸点**(三端共用;别在各端的行装配里另写一遍)。
|
|
75
99
|
*
|
|
76
|
-
* 🔴
|
|
100
|
+
* 🔴 五句刻意逐字互异(黑盒锚;0.69.1 订正:此前写「四句」漏了「面板体读不出」那一句),且**没有一句**提到 `servers[]`:
|
|
77
101
|
* ① 在场 —— 名册 + runId + at;
|
|
78
102
|
* ② `opts.reachable === false` —— 「未观测」:这次进程没读到面板体;
|
|
79
103
|
* ③ 面板读到了但 `lastLegMcp` 整键缺席 —— 「不报」:三形同形 + 老引擎,**不武断咎为版本**;
|
package/dist/sdkWireTransit.d.ts
CHANGED
|
@@ -38,4 +38,4 @@ export { isApprovalRequestFrameV1, isApprovalRevokeFrameV1 } from '@sema-agent/s
|
|
|
38
38
|
* 🔴 **谁是权威**:权威恒是 `@sema-agent/sdk` 本身。本文件是**别名**,上游改名 ⇒ 本文件当场编译红,
|
|
39
39
|
* 端跟着红 —— 这正是型面转口相对「端各自直连」唯一多出来的那点好处(红在一处,不是散在九处)。
|
|
40
40
|
*/
|
|
41
|
-
export type { TaskRequest, SemaSettings, SkillSpec, AgentEvent, RunReceipt, CancelAck, RunRecord, ToolApprovalRespondAck, FleetTaskRow, FleetWorkflowRow, ApprovalCard, ApprovalRequestFrame, ApprovalRiskAxes, AskDecisionAck, AskDecisionBody, } from '@sema-agent/sdk';
|
|
41
|
+
export type { TaskRequest, SessionPermissionRules, SemaSettings, SkillSpec, AgentEvent, RunReceipt, CancelAck, RunRecord, ToolApprovalRespondAck, FleetTaskRow, FleetWorkflowRow, ApprovalCard, ApprovalRequestFrame, ApprovalRiskAxes, AskDecisionAck, AskDecisionBody, } from '@sema-agent/sdk';
|
package/dist/seam.d.ts
CHANGED
|
@@ -533,7 +533,7 @@ export type ChromeEvent = {
|
|
|
533
533
|
* ⚠️ **只有 live 腿有本帧**(server 7.69.0 亲读:durable/bg 腿把它喂给 rewind 锚而不入账本)
|
|
534
534
|
* ⇒ replay/resume 上映射表是空的;那时正解是**不画分割线**,不是回退成「画在最后一条」。
|
|
535
535
|
*/
|
|
536
|
-
| MessageCommittedChromeEvent | EngineNoticeChromeEvent | TextSegmentEndChromeEvent | WiringManifestChromeEvent | ResultTextDivergedChromeEvent
|
|
536
|
+
| MessageCommittedChromeEvent | EngineNoticeChromeEvent | TextSegmentEndChromeEvent | ThinkingSegmentEndChromeEvent | WiringManifestChromeEvent | ResultTextDivergedChromeEvent
|
|
537
537
|
/**
|
|
538
538
|
* B-078 / L-208(0.65.0):design/172 流内审批协议的**两条帧**。修前它们在标准管线上落
|
|
539
539
|
* `dropped('unsupported_arm')`,壳自己另接一份 ⇒ 只走包管线的宿主(desktop/web)拿不到
|
|
@@ -707,6 +707,52 @@ export interface TextSegmentEndChromeEvent {
|
|
|
707
707
|
/** core 铸的事件身份(uuidv7 形);wire 未必带 ⇒ 缺席时本键不在场。 */
|
|
708
708
|
eventId?: string;
|
|
709
709
|
}
|
|
710
|
+
/**
|
|
711
|
+
* {@link ChromeEvent} 的 `thinking_segment_end` 臂(CC-02,0.68.3;server ≥7.77.0 S-310 `reasoning_end`,
|
|
712
|
+
* sdk ≥9.4.0 `SegmentEndFields` 与 `text_end` 单源)——「**引擎明报:一段推理到此为止,这是它的权威全文**」。
|
|
713
|
+
*
|
|
714
|
+
* ── 与 `text_segment_end` 同一句消费律(sdk 顶注逐字:一个 wire 概念一份形,读法只学一次)────────
|
|
715
|
+
* `reasoning_delta` 逐 chunk 脱敏对**跨 chunk** 的凭据形无能为力,只有整段看得见 ⇒ `content` 是经与
|
|
716
|
+
* `text_end` / `result` **同一只**脱敏器的段权威全文,**可以**与活体增量的拼接不相等。本包在臂上做
|
|
717
|
+
* **整段替换**(思考缓冲 + 活体尾巴),三个 additive 键与 `text_segment_end` **同名同律**(never-false)。
|
|
718
|
+
*
|
|
719
|
+
* ── 与散文段的一处结构差(读这一条再接)──────────────────────────────────────────────────────
|
|
720
|
+
* 思考块**没有 idle-flush**:本包只在三处正常边界提交它(思考→回答边界 / 工具卡前 / turn 收口),
|
|
721
|
+
* 提交是**整块**的 ⇒ 「已提交前缀」在思考面上是**全有或全无**:`committedPrefixDiverged` 在场时,
|
|
722
|
+
* `committedPrefixLen` 恒 = 那条已 committed 思考行的全文长度,而且本臂**多带一把钥匙**
|
|
723
|
+
* {@link ThinkingSegmentEndChromeEvent.committedUuid}(那条行的 `uuid`,本包铸的)—— 思考行**不盖**
|
|
724
|
+
* `_sema_segment_id`(CC-01 只盖文本行,刻意),宿主认行用这把 uuid 就够了(整块换,不切片)。
|
|
725
|
+
*
|
|
726
|
+
* ── 🔴 宿主消费义务(与 `text_segment_end` 逐条同形)─────────────────────────────────────────
|
|
727
|
+
* ① `diverged` 在场 ⇒ **自己拼 `stream_delta{channel:'thinking'}` 上屏**的端按 `content` 重渲该块;
|
|
728
|
+
* 只渲 transcript 平面的端零改动(包已把权威全文换进思考缓冲,下一次提交交的就是它)。
|
|
729
|
+
* ② `committedPrefixDiverged` 在场 ⇒ **所有端都要做**:那条已 committed 的思考行(`uuid === committedUuid`)
|
|
730
|
+
* 是过期的,整块换成 `content`;本包在这一形上**一个字节都不再交**(再交一条 = 同一段推理上屏两遍)。
|
|
731
|
+
* ③ 三键全缺席 ⇒ 照旧只当对账/定界,拿 `content` 再渲一行 = 同一段上屏两遍。
|
|
732
|
+
* ④ 缺席 ≠ 段没结束:只有会报块结束的引擎才发它;按整条流判有没有边界帧。
|
|
733
|
+
*/
|
|
734
|
+
export interface ThinkingSegmentEndChromeEvent {
|
|
735
|
+
kind: 'thinking_segment_end';
|
|
736
|
+
laneProof: LaneProof;
|
|
737
|
+
/** 该段推理的**权威全文**(server ≥7.77.0 经脱敏器;可以与活体增量拼接不相等)。读法见义务 ①③。 */
|
|
738
|
+
content: string;
|
|
739
|
+
/** 活体面那份过期了(never false)。 */
|
|
740
|
+
diverged?: true;
|
|
741
|
+
/** 已 committed 的那条思考行过期了(never false)⇒ 整块换,本包不再交字节。 */
|
|
742
|
+
committedPrefixDiverged?: true;
|
|
743
|
+
/** 已 committed 思考行的全文长度(UTF-16 代码单元;never 0)—— 思考面上恒 = 整块。 */
|
|
744
|
+
committedPrefixLen?: number;
|
|
745
|
+
/** 有已提交思考行时在场:**末条**行的 `uuid`(0.69.0 兼容位;整段归属看 {@link committedUuids})。 */
|
|
746
|
+
committedUuid?: string;
|
|
747
|
+
/**
|
|
748
|
+
* CC-11(0.69.1):有已提交思考行时在场 —— 段内**全部**已提交行的 `uuid`,按提交序(一段推理跨工具卡时多条)。
|
|
749
|
+
* 🔴 `committedPrefixDiverged` 在场 ⇒ 宿主把这些行**全部删掉**、在首行位置放一条 `content`(整段换,不切片);
|
|
750
|
+
* 缺席(`committedPrefixDiverged` 缺席)⇒ 这些行照旧,本包只换了还押着的后段(或零字节)。
|
|
751
|
+
*/
|
|
752
|
+
committedUuids?: readonly string[];
|
|
753
|
+
/** core 铸的事件身份(uuidv7 形);wire 未必带 ⇒ 缺席时本键不在场。 */
|
|
754
|
+
eventId?: string;
|
|
755
|
+
}
|
|
710
756
|
/**
|
|
711
757
|
* {@link ChromeEvent} 的 `approval_request` 臂(B-078 / L-208,0.65.0;design/172 流内审批协议,
|
|
712
758
|
* server ≥7.3.0、7.5.0 起默认开)——「**引擎在这条流上呈了一张审批卡**」。
|