@sema-agent/client-core 0.3.0 → 0.5.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/README.md +57 -4
- package/dist/adapt.d.ts +30 -3
- package/dist/adapt.js +490 -354
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +81 -0
- package/dist/adapter/downstream/eventToSdkMessage.js +330 -0
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +71 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +370 -0
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +26 -0
- package/dist/adapter/downstream/turnUsageToModelUsage.js +12 -0
- package/dist/adapter/runStream.d.ts +38 -0
- package/dist/adapter/runStream.js +177 -0
- package/dist/adapter/types.d.ts +73 -0
- package/dist/adapter/types.js +23 -0
- package/dist/agentsWireCaps.d.ts +112 -0
- package/dist/agentsWireCaps.js +319 -0
- package/dist/attachmentsWireCaps.d.ts +47 -0
- package/dist/attachmentsWireCaps.js +46 -0
- package/dist/classifierVerdictWire.d.ts +45 -0
- package/dist/classifierVerdictWire.js +76 -0
- package/dist/clientContextWireCaps.d.ts +46 -0
- package/dist/clientContextWireCaps.js +48 -0
- package/dist/cloudConfigWireCaps.d.ts +110 -0
- package/dist/cloudConfigWireCaps.js +228 -0
- package/dist/controlRouter.d.ts +191 -0
- package/dist/controlRouter.js +244 -0
- package/dist/effortWire.d.ts +34 -0
- package/dist/effortWire.js +38 -0
- package/dist/engineWireSdk.d.ts +49 -0
- package/dist/engineWireSdk.js +61 -0
- package/dist/forkWireCaps.d.ts +25 -0
- package/dist/forkWireCaps.js +42 -0
- package/dist/hostEnv.d.ts +16 -0
- package/dist/hostEnv.js +17 -0
- package/dist/imagesWireCaps.d.ts +28 -0
- package/dist/imagesWireCaps.js +49 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +62 -0
- package/dist/liveModelCatalog.d.ts +62 -0
- package/dist/liveModelCatalog.js +79 -0
- package/dist/mcpWireCaps.d.ts +41 -0
- package/dist/mcpWireCaps.js +51 -0
- package/dist/modelBudgetRule.d.ts +44 -0
- package/dist/modelBudgetRule.js +73 -0
- package/dist/modelWireCaps.d.ts +17 -0
- package/dist/modelWireCaps.js +16 -0
- package/dist/notifications.d.ts +150 -4
- package/dist/notifications.js +472 -0
- package/dist/permissionWireCaps.d.ts +37 -0
- package/dist/permissionWireCaps.js +46 -0
- package/dist/promptProfileWireCaps.d.ts +17 -0
- package/dist/promptProfileWireCaps.js +20 -0
- package/dist/retainBackgroundWireCaps.d.ts +50 -0
- package/dist/retainBackgroundWireCaps.js +58 -0
- package/dist/rewindWireCaps.d.ts +36 -0
- package/dist/rewindWireCaps.js +41 -0
- package/dist/seam.d.ts +97 -2
- package/dist/selfOrchestrationWireCaps.d.ts +40 -0
- package/dist/selfOrchestrationWireCaps.js +48 -0
- package/dist/sessionModelLatch.d.ts +35 -0
- package/dist/sessionModelLatch.js +63 -0
- package/dist/skillsWireCaps.d.ts +47 -0
- package/dist/skillsWireCaps.js +41 -0
- package/dist/sseIdleTriage.d.ts +94 -0
- package/dist/sseIdleTriage.js +142 -0
- package/dist/ultracodeWireCaps.d.ts +90 -0
- package/dist/ultracodeWireCaps.js +159 -0
- package/dist/webSearchWireCaps.d.ts +54 -0
- package/dist/webSearchWireCaps.js +76 -0
- package/package.json +2 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/sema/forkWireCaps.ts 逐字搬入(零依赖)。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* src/sema/forkWireCaps.ts — Fork wire projection: the top-level `TaskRequest.enableFork` boolean →
|
|
6
|
+
* core fork governance → the model's Agent(subagent_type:"fork") availability (core 1.257 撤除独立
|
|
7
|
+
* Fork 工具,能力收编进 Agent;CC `subagent_type:fork`: the model forks ITSELF into a subagent that
|
|
8
|
+
* INHERITS the parent context + shares the prompt cache, vs Task's clean-context subagent).
|
|
9
|
+
*
|
|
10
|
+
* DEFAULT = CC parity(clay 2026-07-08 拍板,订正:此前壳里引用的「默认对 LLM 不开」是过时拍板):
|
|
11
|
+
* core ≥1.257 的 fork 治理是 opt-OUT——enableFork 缺省 = GRANTED(与 CC 一致)。壳默认 **不 stamp**,
|
|
12
|
+
* 让引擎默认生效(模型默认可用 Agent-fork)。`SEMA_ENABLE_FORK` 保留为显式开关:truthy ⇒ stamp true
|
|
13
|
+
* (对老引擎 <1.257 也点亮),显式 falsy('0'/'false'/'no'/'off')⇒ stamp false(用户关闭的口子,
|
|
14
|
+
* service [503]② 的 fail-OPEN 教训:关必须显式 false,缺省不再是"关")。
|
|
15
|
+
*
|
|
16
|
+
* PURE — no env/file IO of its OWN (callers pass `env`), so it bundles + unit-tests without the
|
|
17
|
+
* settings graph. The CALLER (seamQuery / the -p ask) gates the env read to LIVE mode so the mock
|
|
18
|
+
* request shape never changes.
|
|
19
|
+
*/
|
|
20
|
+
import { hostEnv } from './hostEnv.js';
|
|
21
|
+
/** The env key the shell reads. SEMA_-namespaced so it never collides with a worker's own deploy env. */
|
|
22
|
+
export const ENABLE_FORK_ENV = 'SEMA_ENABLE_FORK';
|
|
23
|
+
function isTruthy(v) {
|
|
24
|
+
const s = v.trim().toLowerCase();
|
|
25
|
+
return s === '1' || s === 'true' || s === 'yes' || s === 'on';
|
|
26
|
+
}
|
|
27
|
+
function isFalsy(v) {
|
|
28
|
+
const s = v.trim().toLowerCase();
|
|
29
|
+
return s === '0' || s === 'false' || s === 'no' || s === 'off';
|
|
30
|
+
}
|
|
31
|
+
/** ENV source → explicit `true`/`false` when the user set SEMA_ENABLE_FORK either way, else
|
|
32
|
+
* `undefined` (⇒ no stamp ⇒ the engine default applies — GRANTED on core ≥1.257, CC parity). */
|
|
33
|
+
export function enableForkFromEnv(env = hostEnv()) {
|
|
34
|
+
const raw = env[ENABLE_FORK_ENV];
|
|
35
|
+
if (typeof raw !== 'string' || raw.trim() === '')
|
|
36
|
+
return undefined;
|
|
37
|
+
if (isTruthy(raw))
|
|
38
|
+
return true;
|
|
39
|
+
if (isFalsy(raw))
|
|
40
|
+
return false;
|
|
41
|
+
return undefined; // unrecognized spelling — don't guess, let the engine default apply
|
|
42
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hostEnv.ts — B2 批引入的**唯一**宿主环境读口(多端改造设计稿 §5.2 浏览器可移植性)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要:搬入的 `*WireCaps` 族有 11 个函数签名是 `(env: NodeJS.ProcessEnv = process.env)`
|
|
5
|
+
* —— 两个问题:① `NodeJS` 命名空间在本包(tsconfig `types: []`、无 @types/node)不存在;
|
|
6
|
+
* ② 浏览器里 `process` 未定义,**不传参调用会 ReferenceError**(不是类型问题,是运行时崩)。
|
|
7
|
+
*
|
|
8
|
+
* 🔴 等价性记账(逐字):Node 下 `hostEnv()` 返回的就是 `process.env` 那个**同一对象**
|
|
9
|
+
* (`globalThis.process === process`),所以壳侧既有「不传 env 参数」的调用点行为一字节不变;
|
|
10
|
+
* 浏览器/worker 下返回 `{}` —— 相当于「所有 env 旋钮未设置」,即各函数自己的缺省档。
|
|
11
|
+
* `EnvLike` 与 `NodeJS.ProcessEnv`(= `Dict<string>`)结构等价,壳侧传 `process.env` 照样过型。
|
|
12
|
+
*/
|
|
13
|
+
/** `process.env` 的结构等价形(`NodeJS.ProcessEnv` 的包内替身)。 */
|
|
14
|
+
export type EnvLike = Record<string, string | undefined>;
|
|
15
|
+
/** 宿主 env(Node = 真 `process.env` 同一对象;无 process 的宿主 = 空表)。 */
|
|
16
|
+
export declare function hostEnv(): EnvLike;
|
package/dist/hostEnv.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hostEnv.ts — B2 批引入的**唯一**宿主环境读口(多端改造设计稿 §5.2 浏览器可移植性)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要:搬入的 `*WireCaps` 族有 11 个函数签名是 `(env: NodeJS.ProcessEnv = process.env)`
|
|
5
|
+
* —— 两个问题:① `NodeJS` 命名空间在本包(tsconfig `types: []`、无 @types/node)不存在;
|
|
6
|
+
* ② 浏览器里 `process` 未定义,**不传参调用会 ReferenceError**(不是类型问题,是运行时崩)。
|
|
7
|
+
*
|
|
8
|
+
* 🔴 等价性记账(逐字):Node 下 `hostEnv()` 返回的就是 `process.env` 那个**同一对象**
|
|
9
|
+
* (`globalThis.process === process`),所以壳侧既有「不传 env 参数」的调用点行为一字节不变;
|
|
10
|
+
* 浏览器/worker 下返回 `{}` —— 相当于「所有 env 旋钮未设置」,即各函数自己的缺省档。
|
|
11
|
+
* `EnvLike` 与 `NodeJS.ProcessEnv`(= `Dict<string>`)结构等价,壳侧传 `process.env` 照样过型。
|
|
12
|
+
*/
|
|
13
|
+
/** 宿主 env(Node = 真 `process.env` 同一对象;无 process 的宿主 = 空表)。 */
|
|
14
|
+
export function hostEnv() {
|
|
15
|
+
const p = globalThis.process;
|
|
16
|
+
return p?.env ?? {};
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/sema/imagesWireCaps.ts 逐字搬入(零依赖)。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* src/sema/imagesWireCaps.ts — PURE projection of a CC user message's IMAGE content blocks → engine ImageInput[]
|
|
6
|
+
* (CC paste-image / drag-image parity). seamQuery imports it.
|
|
7
|
+
*
|
|
8
|
+
* The signature "壳渲染后端空" hole: REPL.tsx:3444 builds Anthropic image blocks
|
|
9
|
+
* { type:'image', source:{ type:'base64', media_type, data } } (or { type:'url', url })
|
|
10
|
+
* into the user message's `content` block array, but seamQuery.objectiveFromMessage kept ONLY `type==='text'`
|
|
11
|
+
* blocks — so pasted images RENDERED but never reached the live engine. core/service already consume
|
|
12
|
+
* `body.images` (main.ts:1296 → core `TaskSpec.images?: ImageInput[]`, types.ts:416 + brain toUserBlocks); this
|
|
13
|
+
* is purely the missing shell-side projection. config-class (model-content the caller chose for their OWN turn).
|
|
14
|
+
*
|
|
15
|
+
* core ImageInput = `{ data: base64, mimeType } | { url }`. We map the Anthropic base64 source
|
|
16
|
+
* (`source.media_type`/`source.data`) → `{ data, mimeType }`, and a url source → `{ url }`.
|
|
17
|
+
*/
|
|
18
|
+
export type ImageInput = {
|
|
19
|
+
data: string;
|
|
20
|
+
mimeType: string;
|
|
21
|
+
} | {
|
|
22
|
+
url: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Extract the IMAGE blocks of a CC user message → ImageInput[]. Reads `message.content` (string | block[]) the
|
|
26
|
+
* same way objectiveFromMessage reads its text; a bare-string content has no images ⇒ []. Malformed blocks drop.
|
|
27
|
+
*/
|
|
28
|
+
export declare function imagesFromMessage(msg: unknown): ImageInput[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/sema/imagesWireCaps.ts 逐字搬入(零依赖)。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* src/sema/imagesWireCaps.ts — PURE projection of a CC user message's IMAGE content blocks → engine ImageInput[]
|
|
6
|
+
* (CC paste-image / drag-image parity). seamQuery imports it.
|
|
7
|
+
*
|
|
8
|
+
* The signature "壳渲染后端空" hole: REPL.tsx:3444 builds Anthropic image blocks
|
|
9
|
+
* { type:'image', source:{ type:'base64', media_type, data } } (or { type:'url', url })
|
|
10
|
+
* into the user message's `content` block array, but seamQuery.objectiveFromMessage kept ONLY `type==='text'`
|
|
11
|
+
* blocks — so pasted images RENDERED but never reached the live engine. core/service already consume
|
|
12
|
+
* `body.images` (main.ts:1296 → core `TaskSpec.images?: ImageInput[]`, types.ts:416 + brain toUserBlocks); this
|
|
13
|
+
* is purely the missing shell-side projection. config-class (model-content the caller chose for their OWN turn).
|
|
14
|
+
*
|
|
15
|
+
* core ImageInput = `{ data: base64, mimeType } | { url }`. We map the Anthropic base64 source
|
|
16
|
+
* (`source.media_type`/`source.data`) → `{ data, mimeType }`, and a url source → `{ url }`.
|
|
17
|
+
*/
|
|
18
|
+
/** Map one Anthropic image block's `source` → ImageInput, or null if malformed/unsupported. */
|
|
19
|
+
function sourceToImageInput(source) {
|
|
20
|
+
if (typeof source !== 'object' || source === null)
|
|
21
|
+
return null;
|
|
22
|
+
const s = source;
|
|
23
|
+
if (s.type === 'base64' && typeof s.data === 'string' && s.data.length > 0) {
|
|
24
|
+
return { data: s.data, mimeType: typeof s.media_type === 'string' && s.media_type ? s.media_type : 'image/png' };
|
|
25
|
+
}
|
|
26
|
+
if (s.type === 'url' && typeof s.url === 'string' && s.url.length > 0) {
|
|
27
|
+
return { url: s.url };
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Extract the IMAGE blocks of a CC user message → ImageInput[]. Reads `message.content` (string | block[]) the
|
|
33
|
+
* same way objectiveFromMessage reads its text; a bare-string content has no images ⇒ []. Malformed blocks drop.
|
|
34
|
+
*/
|
|
35
|
+
export function imagesFromMessage(msg) {
|
|
36
|
+
const m = msg;
|
|
37
|
+
const content = m?.message?.content ?? m?.content;
|
|
38
|
+
if (!Array.isArray(content))
|
|
39
|
+
return [];
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const block of content) {
|
|
42
|
+
if (block && typeof block === 'object' && block.type === 'image') {
|
|
43
|
+
const img = sourceToImageInput(block.source);
|
|
44
|
+
if (img)
|
|
45
|
+
out.push(img);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
* 沿革:@sema-agent/wire-cc-adapter 0.1.0 = seam 类型 + id 确定性派生 + 首批踩坑纯函数;
|
|
6
6
|
* 0.1.2(#52a)= adapt() 管线首批(纯投影臂全落 + 壳态耦合臂投影成 ChromeEvent + 差分守卫);
|
|
7
7
|
* 0.2.0 = 迁入 sema-client-core 独立仓并改名(旧 npm 名 deprecate 指本包);
|
|
8
|
+
* 0.5.0 = **B3 批**(设计稿 §3 B3):`AdapterContext` 扩容(log/probe/signal/setTimer/clearTimer/
|
|
9
|
+
* coalesceIntervalMs,**只加可选位 = minor 不 BREAKING**)· 适配内核搬入(`adapter/types` 运行时
|
|
10
|
+
* 半场 + `adapter/downstream` 三件 + `adapter/runStream`)· runStream **两条外向边切除**
|
|
11
|
+
* (lastTurnUsageStore / planReviewWire ⇒ `last_turn_usage` / `plan_review_park` 两个 chrome 臂)·
|
|
12
|
+
* T38 三清第三清 + T40 IDLE-FLUSH + T57 第五处断闸 + T58 iterator cleanup + T59 abort + T60 收尾腿。
|
|
13
|
+
* 🆕 第三道守卫 `scripts/run-client-core-portability-test.mjs`(内核闭包 1571 文件 → **6 文件**)。
|
|
14
|
+
* 0.4.0 = **B2 批**(设计稿 §3 B2):通知族三文件合并进 notifications.ts(engineTaskNotification 全文 +
|
|
15
|
+
* taskNotificationErrorSupplement 全文 + hookNoticeStore 判定半场)· 17 个 `*WireCaps` + engineWireSdk +
|
|
16
|
+
* sseIdleTriage + classifierVerdictWire 判定半场 + controlRouter + 模型面纯逻辑 4 件 + 新写 hostEnv;
|
|
17
|
+
* 宿主耦合的 6 件(hooksWireCaps/scratchpadWireCaps/liveInitToolFace/engineSessionParam/
|
|
18
|
+
* modelContextResolver/agentModelResolver)**本批不搬**,原因逐条见交接报告。
|
|
8
19
|
* 0.3.0 = **B1 批**(多端改造设计稿 §3 批次表第二批):纯函数/台账 11 文件 + 1 纯类型文件搬入
|
|
9
20
|
* (壳侧 shim 替换随后批)。B1 只搬现行为、零收编、零行为改动;唯一的形状订正是 workflow.ts
|
|
10
21
|
* 补齐 `agent_runs[].errorCode` 类型位(0.2.0 抄件漏项)。
|
|
@@ -15,6 +26,17 @@
|
|
|
15
26
|
* workflow.ts(workflowAgentTaskIds)· subagentContentStore.ts · engineAgentPanelStore.ts ·
|
|
16
27
|
* fleetAgentPanelProjection.ts · liveQuestionStore.ts · engineInlineTaskStats.ts ·
|
|
17
28
|
* engineCapsCache.ts · engineToolLabelStore.ts
|
|
29
|
+
* —— B2 新增:notifications.ts(11 个通知台账 + 队列 port + 两个 probe 槽)·
|
|
30
|
+
* agentsWireCaps.ts(prepare 缓存/投影闭包/一次性告警集)· liveModelCatalog.ts(目录 + refresher)·
|
|
31
|
+
* sessionModelLatch.ts(三个 latch)· ultracodeWireCaps.ts(sticky preset)。
|
|
32
|
+
* —— B3 新增:adapter/runStream.ts(`inFlightTurns` 计数,读口 `isRunStreamActive()`;
|
|
33
|
+
* 两份实例 = 引擎滚动升级门恒读 false ⇒ **turn 中途热换引擎**,正是它当初要防的事)。
|
|
34
|
+
* 🔴 **宿主装配**(B2 起本包有必须由宿主注入才完整的口):`installNotificationQueuePort()` ——
|
|
35
|
+
* 不装 = task-notification 投递静默丢失(`notificationQueuePortMisses()` 恒应为 0)。
|
|
36
|
+
* —— B3 新增(可选口,缺席 = 对应 UI 面在该宿主上是哑的,不是报错):`ctx.emitChrome`
|
|
37
|
+
* (runStream 的两条切边:statusline 真 usage / plan-review 审批卡)· `ctx.setTimer`
|
|
38
|
+
* (T40 IDLE-FLUSH,不给 = 长工具参数生成期已生成内容仍押到下一帧才上屏)· `ctx.signal`
|
|
39
|
+
* (Esc 中断)· `ctx.log` / `ctx.probe`(诊断面)。
|
|
18
40
|
*/
|
|
19
41
|
export * from './seam.js';
|
|
20
42
|
export * from './workflow.js';
|
|
@@ -33,3 +55,33 @@ export * from './engineCapsCache.js';
|
|
|
33
55
|
export * from './engineToolLabelStore.js';
|
|
34
56
|
export * from './fleetTaskDesc.js';
|
|
35
57
|
export type * from './types/engineState.js';
|
|
58
|
+
export * from './hostEnv.js';
|
|
59
|
+
export * from './controlRouter.js';
|
|
60
|
+
export * from './sseIdleTriage.js';
|
|
61
|
+
export * from './engineWireSdk.js';
|
|
62
|
+
export * from './classifierVerdictWire.js';
|
|
63
|
+
export * from './agentsWireCaps.js';
|
|
64
|
+
export * from './attachmentsWireCaps.js';
|
|
65
|
+
export * from './clientContextWireCaps.js';
|
|
66
|
+
export * from './cloudConfigWireCaps.js';
|
|
67
|
+
export * from './forkWireCaps.js';
|
|
68
|
+
export * from './imagesWireCaps.js';
|
|
69
|
+
export * from './mcpWireCaps.js';
|
|
70
|
+
export * from './modelWireCaps.js';
|
|
71
|
+
export * from './permissionWireCaps.js';
|
|
72
|
+
export * from './promptProfileWireCaps.js';
|
|
73
|
+
export * from './retainBackgroundWireCaps.js';
|
|
74
|
+
export * from './rewindWireCaps.js';
|
|
75
|
+
export * from './selfOrchestrationWireCaps.js';
|
|
76
|
+
export * from './skillsWireCaps.js';
|
|
77
|
+
export * from './ultracodeWireCaps.js';
|
|
78
|
+
export * from './webSearchWireCaps.js';
|
|
79
|
+
export * from './liveModelCatalog.js';
|
|
80
|
+
export * from './modelBudgetRule.js';
|
|
81
|
+
export * from './sessionModelLatch.js';
|
|
82
|
+
export * from './effortWire.js';
|
|
83
|
+
export * from './adapter/types.js';
|
|
84
|
+
export * from './adapter/downstream/turnUsageToModelUsage.js';
|
|
85
|
+
export * from './adapter/downstream/eventToSdkMessage.js';
|
|
86
|
+
export * from './adapter/downstream/terminalToSdkResult.js';
|
|
87
|
+
export * from './adapter/runStream.js';
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
* 沿革:@sema-agent/wire-cc-adapter 0.1.0 = seam 类型 + id 确定性派生 + 首批踩坑纯函数;
|
|
6
6
|
* 0.1.2(#52a)= adapt() 管线首批(纯投影臂全落 + 壳态耦合臂投影成 ChromeEvent + 差分守卫);
|
|
7
7
|
* 0.2.0 = 迁入 sema-client-core 独立仓并改名(旧 npm 名 deprecate 指本包);
|
|
8
|
+
* 0.5.0 = **B3 批**(设计稿 §3 B3):`AdapterContext` 扩容(log/probe/signal/setTimer/clearTimer/
|
|
9
|
+
* coalesceIntervalMs,**只加可选位 = minor 不 BREAKING**)· 适配内核搬入(`adapter/types` 运行时
|
|
10
|
+
* 半场 + `adapter/downstream` 三件 + `adapter/runStream`)· runStream **两条外向边切除**
|
|
11
|
+
* (lastTurnUsageStore / planReviewWire ⇒ `last_turn_usage` / `plan_review_park` 两个 chrome 臂)·
|
|
12
|
+
* T38 三清第三清 + T40 IDLE-FLUSH + T57 第五处断闸 + T58 iterator cleanup + T59 abort + T60 收尾腿。
|
|
13
|
+
* 🆕 第三道守卫 `scripts/run-client-core-portability-test.mjs`(内核闭包 1571 文件 → **6 文件**)。
|
|
14
|
+
* 0.4.0 = **B2 批**(设计稿 §3 B2):通知族三文件合并进 notifications.ts(engineTaskNotification 全文 +
|
|
15
|
+
* taskNotificationErrorSupplement 全文 + hookNoticeStore 判定半场)· 17 个 `*WireCaps` + engineWireSdk +
|
|
16
|
+
* sseIdleTriage + classifierVerdictWire 判定半场 + controlRouter + 模型面纯逻辑 4 件 + 新写 hostEnv;
|
|
17
|
+
* 宿主耦合的 6 件(hooksWireCaps/scratchpadWireCaps/liveInitToolFace/engineSessionParam/
|
|
18
|
+
* modelContextResolver/agentModelResolver)**本批不搬**,原因逐条见交接报告。
|
|
8
19
|
* 0.3.0 = **B1 批**(多端改造设计稿 §3 批次表第二批):纯函数/台账 11 文件 + 1 纯类型文件搬入
|
|
9
20
|
* (壳侧 shim 替换随后批)。B1 只搬现行为、零收编、零行为改动;唯一的形状订正是 workflow.ts
|
|
10
21
|
* 补齐 `agent_runs[].errorCode` 类型位(0.2.0 抄件漏项)。
|
|
@@ -15,6 +26,17 @@
|
|
|
15
26
|
* workflow.ts(workflowAgentTaskIds)· subagentContentStore.ts · engineAgentPanelStore.ts ·
|
|
16
27
|
* fleetAgentPanelProjection.ts · liveQuestionStore.ts · engineInlineTaskStats.ts ·
|
|
17
28
|
* engineCapsCache.ts · engineToolLabelStore.ts
|
|
29
|
+
* —— B2 新增:notifications.ts(11 个通知台账 + 队列 port + 两个 probe 槽)·
|
|
30
|
+
* agentsWireCaps.ts(prepare 缓存/投影闭包/一次性告警集)· liveModelCatalog.ts(目录 + refresher)·
|
|
31
|
+
* sessionModelLatch.ts(三个 latch)· ultracodeWireCaps.ts(sticky preset)。
|
|
32
|
+
* —— B3 新增:adapter/runStream.ts(`inFlightTurns` 计数,读口 `isRunStreamActive()`;
|
|
33
|
+
* 两份实例 = 引擎滚动升级门恒读 false ⇒ **turn 中途热换引擎**,正是它当初要防的事)。
|
|
34
|
+
* 🔴 **宿主装配**(B2 起本包有必须由宿主注入才完整的口):`installNotificationQueuePort()` ——
|
|
35
|
+
* 不装 = task-notification 投递静默丢失(`notificationQueuePortMisses()` 恒应为 0)。
|
|
36
|
+
* —— B3 新增(可选口,缺席 = 对应 UI 面在该宿主上是哑的,不是报错):`ctx.emitChrome`
|
|
37
|
+
* (runStream 的两条切边:statusline 真 usage / plan-review 审批卡)· `ctx.setTimer`
|
|
38
|
+
* (T40 IDLE-FLUSH,不给 = 长工具参数生成期已生成内容仍押到下一帧才上屏)· `ctx.signal`
|
|
39
|
+
* (Esc 中断)· `ctx.log` / `ctx.probe`(诊断面)。
|
|
18
40
|
*/
|
|
19
41
|
export * from './seam.js';
|
|
20
42
|
export * from './workflow.js';
|
|
@@ -33,3 +55,43 @@ export * from './printToolResultFrame.js';
|
|
|
33
55
|
export * from './engineCapsCache.js';
|
|
34
56
|
export * from './engineToolLabelStore.js';
|
|
35
57
|
export * from './fleetTaskDesc.js';
|
|
58
|
+
// ── B2 批:通知族合并 / caps-wire 门族 / 模型面纯逻辑 / control 路由(2026-07-27)──────────────
|
|
59
|
+
// 通知族(engineTaskNotification + taskNotificationErrorSupplement + hookNoticeStore 判定半场)
|
|
60
|
+
// 已并入 notifications.js,不需要新增导出行。
|
|
61
|
+
export * from './hostEnv.js';
|
|
62
|
+
export * from './controlRouter.js';
|
|
63
|
+
export * from './sseIdleTriage.js';
|
|
64
|
+
export * from './engineWireSdk.js';
|
|
65
|
+
export * from './classifierVerdictWire.js';
|
|
66
|
+
// caps / wire 门族(17 个 *WireCaps —— 壳侧 hooksWireCaps / scratchpadWireCaps 因宿主耦合未搬,
|
|
67
|
+
// 见 README 的 B2 记账)
|
|
68
|
+
export * from './agentsWireCaps.js';
|
|
69
|
+
export * from './attachmentsWireCaps.js';
|
|
70
|
+
export * from './clientContextWireCaps.js';
|
|
71
|
+
export * from './cloudConfigWireCaps.js';
|
|
72
|
+
export * from './forkWireCaps.js';
|
|
73
|
+
export * from './imagesWireCaps.js';
|
|
74
|
+
export * from './mcpWireCaps.js';
|
|
75
|
+
export * from './modelWireCaps.js';
|
|
76
|
+
export * from './permissionWireCaps.js';
|
|
77
|
+
export * from './promptProfileWireCaps.js';
|
|
78
|
+
export * from './retainBackgroundWireCaps.js';
|
|
79
|
+
export * from './rewindWireCaps.js';
|
|
80
|
+
export * from './selfOrchestrationWireCaps.js';
|
|
81
|
+
export * from './skillsWireCaps.js';
|
|
82
|
+
export * from './ultracodeWireCaps.js';
|
|
83
|
+
export * from './webSearchWireCaps.js';
|
|
84
|
+
// 模型面纯逻辑族
|
|
85
|
+
export * from './liveModelCatalog.js';
|
|
86
|
+
export * from './modelBudgetRule.js';
|
|
87
|
+
export * from './sessionModelLatch.js';
|
|
88
|
+
export * from './effortWire.js';
|
|
89
|
+
// ── B3 批:适配内核(增量合并 + 计量 + 流驱动)(2026-07-27)──────────────────────────────────
|
|
90
|
+
// M/adapter 的 downstream 三件 + types 运行时半场 + runStream 整搬(设计稿 §3 B3)。
|
|
91
|
+
// 🔴 runStream.ts 持 module 级 `inFlightTurns` 计数(isRunStreamActive 的读口)——单例清单新增项:
|
|
92
|
+
// 写方=runStream 自己,读方=壳的引擎滚动升级门(turn 中途绝不热换引擎)。两份实例 = 门恒读 false。
|
|
93
|
+
export * from './adapter/types.js';
|
|
94
|
+
export * from './adapter/downstream/turnUsageToModelUsage.js';
|
|
95
|
+
export * from './adapter/downstream/eventToSdkMessage.js';
|
|
96
|
+
export * from './adapter/downstream/terminalToSdkResult.js';
|
|
97
|
+
export * from './adapter/runStream.js';
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/sema/liveModelCatalog.ts 逐字搬入(零依赖;🔴 catalog/refresher 是单实例态 —— 写口 setLiveModelCatalog/installer 与读口 getLiveModelCatalog 必须同实例)。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* src/sema/liveModelCatalog.ts — the LIVE model-catalog singleton (TEAM-C / clay decision #1 = A).
|
|
6
|
+
*
|
|
7
|
+
* WHY THIS FILE EXISTS
|
|
8
|
+
* --------------------
|
|
9
|
+
* The `/model` picker, the header model line, the /status "Model" row, and the picker's ✔ are all stuck on
|
|
10
|
+
* a STATIC opus[1m] / a STATIC fictional catalog (mock/control/modelOptionsSeam.ts). The live engine actually
|
|
11
|
+
* serves a different fleet — `client.models.list()` returns `{ models, default }` (the REAL catalog), and
|
|
12
|
+
* `done.result.model` echoes the REAL served model (MF-25). This module is the one-shot, process-wide bridge
|
|
13
|
+
* between the LIVE wire read (done once at boot in replEntry's live block) and the SYNCHRONOUS render-time
|
|
14
|
+
* readers (getModelOptions, called inside the picker's React render — it cannot await).
|
|
15
|
+
*
|
|
16
|
+
* SINGLE INSTANCE (build discipline): replEntry.tsx (build-src/src/sema/replEntry.tsx) SETS the catalog and
|
|
17
|
+
* mock/control/modelOptionsSeam.ts (build-src/mock/control/…, the aliased getModelOptions target) READS it.
|
|
18
|
+
* Both resolve this module to ONE staged path (build-src/src/sema/liveModelCatalog.ts), so the singleton is
|
|
19
|
+
* shared — the same single-instance invariant the seam-module fix in scripts/build.sema.mjs guarantees.
|
|
20
|
+
*
|
|
21
|
+
* MOCK PATH UNCHANGED: with SEMA_LIVE_BASEURL unset, no one calls setLiveModelCatalog → the catalog stays
|
|
22
|
+
* null → getModelOptions falls back to the static fleetModels mock and the boot keeps opus[1m]. So the
|
|
23
|
+
* cell-exact mock parity (the /model picker mock rows, the opus[1m] header/status, the /context 20-glyph
|
|
24
|
+
* grid driven by has1mContext('opus[1m]')) is preserved byte-for-byte.
|
|
25
|
+
*/
|
|
26
|
+
/** The neutral wire shape of one model-catalog row (a structural subset of @sema-ai/sdk ModelInfo +
|
|
27
|
+
* mock/control/modelSelect.ts ModelInfo — name/id/provider/reasoning/vision drive the picker badges). */
|
|
28
|
+
export interface LiveModelInfo {
|
|
29
|
+
name: string;
|
|
30
|
+
id?: string;
|
|
31
|
+
provider?: string;
|
|
32
|
+
reasoning?: boolean;
|
|
33
|
+
vision?: boolean;
|
|
34
|
+
[k: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
/** The `GET /v1/models` envelope: the catalog rows + the deployment default model id (display-only). */
|
|
37
|
+
export interface LiveModelCatalog {
|
|
38
|
+
models: LiveModelInfo[];
|
|
39
|
+
/** The served-by-default model id (models.list().default) — the boot mainLoopModel + the picker default desc. */
|
|
40
|
+
default: string;
|
|
41
|
+
}
|
|
42
|
+
/** Install the live catalog (called once at boot from replEntry's live block). null clears it. */
|
|
43
|
+
export declare function setLiveModelCatalog(next: LiveModelCatalog | null): void;
|
|
44
|
+
/** boot 注册的重取器(与 boot fetch 同参)。k3 案(clay 2026-07-20):/config 改 Model ID 后
|
|
45
|
+
* 同会话 /model 仍显旧目录名——目录只在 boot 拉一次。Hub 保存/面板打开时经此重取。 */
|
|
46
|
+
export declare function setLiveModelCatalogRefresher(fn: (() => Promise<LiveModelCatalog | null>) | null): void;
|
|
47
|
+
/** Re-fetch the live catalog (boot 参数);成功即替换 singleton 并返回 true。mock 路径(无
|
|
48
|
+
* refresher)/拉取失败 → false,现值不动(fail-soft,绝不用 null 清掉可用旧目录)。 */
|
|
49
|
+
export declare function refreshLiveModelCatalog(): Promise<boolean>;
|
|
50
|
+
/** Read the live catalog (null = mock path / live read failed → callers fall back to the static mock). */
|
|
51
|
+
export declare function getLiveModelCatalog(): LiveModelCatalog | null;
|
|
52
|
+
/**
|
|
53
|
+
* 件4/MOD-6(F1 模型面批):id/name 双键归一。目录行有两个可寻址键 —— `name`(池 entry id,
|
|
54
|
+
* /model 面板行的 value、@mention 的 handle)和 `id`(上游 modelId);/v1/models 的 `default`
|
|
55
|
+
* 与 boot 回读可能给 id,面板/appState 用 name ⇒ 单键比对时 id≠name 的行匹配不上,面板追加
|
|
56
|
+
* 合成 "Current model" 重复行、✔ 落错行。归一规则:ref 已是某行 name ⇒ 原样;否则命中某行
|
|
57
|
+
* id ⇒ 归一到该行 name;目录缺失(mock 路径)/未命中 ⇒ 原样返回(mock parity 零影响)。
|
|
58
|
+
*/
|
|
59
|
+
export declare function normalizeLiveModelRef(ref: string): string;
|
|
60
|
+
/** 件4(S2 回显):目录 default 的用户名 —— name(池 entry id)优先,id 兜底;null=无目录
|
|
61
|
+
* (mock 路径,调用方回落 CC 字面护 parity)。 */
|
|
62
|
+
export declare function liveDefaultModelName(): string | null;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/sema/liveModelCatalog.ts 逐字搬入(零依赖;🔴 catalog/refresher 是单实例态 —— 写口 setLiveModelCatalog/installer 与读口 getLiveModelCatalog 必须同实例)。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* src/sema/liveModelCatalog.ts — the LIVE model-catalog singleton (TEAM-C / clay decision #1 = A).
|
|
6
|
+
*
|
|
7
|
+
* WHY THIS FILE EXISTS
|
|
8
|
+
* --------------------
|
|
9
|
+
* The `/model` picker, the header model line, the /status "Model" row, and the picker's ✔ are all stuck on
|
|
10
|
+
* a STATIC opus[1m] / a STATIC fictional catalog (mock/control/modelOptionsSeam.ts). The live engine actually
|
|
11
|
+
* serves a different fleet — `client.models.list()` returns `{ models, default }` (the REAL catalog), and
|
|
12
|
+
* `done.result.model` echoes the REAL served model (MF-25). This module is the one-shot, process-wide bridge
|
|
13
|
+
* between the LIVE wire read (done once at boot in replEntry's live block) and the SYNCHRONOUS render-time
|
|
14
|
+
* readers (getModelOptions, called inside the picker's React render — it cannot await).
|
|
15
|
+
*
|
|
16
|
+
* SINGLE INSTANCE (build discipline): replEntry.tsx (build-src/src/sema/replEntry.tsx) SETS the catalog and
|
|
17
|
+
* mock/control/modelOptionsSeam.ts (build-src/mock/control/…, the aliased getModelOptions target) READS it.
|
|
18
|
+
* Both resolve this module to ONE staged path (build-src/src/sema/liveModelCatalog.ts), so the singleton is
|
|
19
|
+
* shared — the same single-instance invariant the seam-module fix in scripts/build.sema.mjs guarantees.
|
|
20
|
+
*
|
|
21
|
+
* MOCK PATH UNCHANGED: with SEMA_LIVE_BASEURL unset, no one calls setLiveModelCatalog → the catalog stays
|
|
22
|
+
* null → getModelOptions falls back to the static fleetModels mock and the boot keeps opus[1m]. So the
|
|
23
|
+
* cell-exact mock parity (the /model picker mock rows, the opus[1m] header/status, the /context 20-glyph
|
|
24
|
+
* grid driven by has1mContext('opus[1m]')) is preserved byte-for-byte.
|
|
25
|
+
*/
|
|
26
|
+
let catalog = null;
|
|
27
|
+
let refresher = null;
|
|
28
|
+
/** Install the live catalog (called once at boot from replEntry's live block). null clears it. */
|
|
29
|
+
export function setLiveModelCatalog(next) {
|
|
30
|
+
catalog = next;
|
|
31
|
+
}
|
|
32
|
+
/** boot 注册的重取器(与 boot fetch 同参)。k3 案(clay 2026-07-20):/config 改 Model ID 后
|
|
33
|
+
* 同会话 /model 仍显旧目录名——目录只在 boot 拉一次。Hub 保存/面板打开时经此重取。 */
|
|
34
|
+
export function setLiveModelCatalogRefresher(fn) {
|
|
35
|
+
refresher = fn;
|
|
36
|
+
}
|
|
37
|
+
/** Re-fetch the live catalog (boot 参数);成功即替换 singleton 并返回 true。mock 路径(无
|
|
38
|
+
* refresher)/拉取失败 → false,现值不动(fail-soft,绝不用 null 清掉可用旧目录)。 */
|
|
39
|
+
export async function refreshLiveModelCatalog() {
|
|
40
|
+
if (!refresher)
|
|
41
|
+
return false;
|
|
42
|
+
try {
|
|
43
|
+
const next = await refresher();
|
|
44
|
+
if (next && Array.isArray(next.models) && next.models.length > 0) {
|
|
45
|
+
catalog = next;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* fail-soft */
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/** Read the live catalog (null = mock path / live read failed → callers fall back to the static mock). */
|
|
55
|
+
export function getLiveModelCatalog() {
|
|
56
|
+
return catalog;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 件4/MOD-6(F1 模型面批):id/name 双键归一。目录行有两个可寻址键 —— `name`(池 entry id,
|
|
60
|
+
* /model 面板行的 value、@mention 的 handle)和 `id`(上游 modelId);/v1/models 的 `default`
|
|
61
|
+
* 与 boot 回读可能给 id,面板/appState 用 name ⇒ 单键比对时 id≠name 的行匹配不上,面板追加
|
|
62
|
+
* 合成 "Current model" 重复行、✔ 落错行。归一规则:ref 已是某行 name ⇒ 原样;否则命中某行
|
|
63
|
+
* id ⇒ 归一到该行 name;目录缺失(mock 路径)/未命中 ⇒ 原样返回(mock parity 零影响)。
|
|
64
|
+
*/
|
|
65
|
+
export function normalizeLiveModelRef(ref) {
|
|
66
|
+
if (!catalog || !ref)
|
|
67
|
+
return ref;
|
|
68
|
+
if (catalog.models.some(m => m.name === ref))
|
|
69
|
+
return ref;
|
|
70
|
+
const row = catalog.models.find(m => typeof m.id === 'string' && m.id === ref);
|
|
71
|
+
return row?.name || ref;
|
|
72
|
+
}
|
|
73
|
+
/** 件4(S2 回显):目录 default 的用户名 —— name(池 entry id)优先,id 兜底;null=无目录
|
|
74
|
+
* (mock 路径,调用方回落 CC 字面护 parity)。 */
|
|
75
|
+
export function liveDefaultModelName() {
|
|
76
|
+
if (!catalog?.default)
|
|
77
|
+
return null;
|
|
78
|
+
return normalizeLiveModelRef(catalog.default);
|
|
79
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/sema/mcpWireCaps.ts 逐字搬入(只 import SDK)。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* src/sema/mcpWireCaps.ts — PURE projection: CC `.mcp.json` server config → core `McpServerSpec` (the wire
|
|
6
|
+
* shape `TaskRequest.mcpServers` carries). Split from mcpWire.ts so it's testable without the heavy
|
|
7
|
+
* `.mcp.json` loader graph (services/mcp/config.ts). Imports only the SDK type (erased at build).
|
|
8
|
+
*
|
|
9
|
+
* core `McpServerSpec.transport` supports ONLY `stdio` + `http` (StreamableHTTP). CC also has sse/sse-ide/
|
|
10
|
+
* ws/ws-ide — core can't mount those (the SSE/WS transport gap, tracked separately) → we SKIP them here
|
|
11
|
+
* (returning null) rather than mis-map. stdio→stdio, http→http; name = the `.mcp.json` record key.
|
|
12
|
+
*
|
|
13
|
+
* Trust: the SHELL only PROJECTS the user's local config; the SERVICE single-user gate (mcpInjectionHonored
|
|
14
|
+
* = requirePrincipal!==true) decides whether to honor it (fail-closed on multi-tenant). So projecting is safe.
|
|
15
|
+
*/
|
|
16
|
+
import type { TaskRequest } from '@sema-agent/sdk';
|
|
17
|
+
/** The wire shape `TaskRequest.mcpServers` carries. SDK 0.0.44's index no longer re-exports the
|
|
18
|
+
* `McpServerSpec` interface by name (types.d.ts still defines it), so derive it STRUCTURALLY from the
|
|
19
|
+
* exported `TaskRequest` — always exactly what the wire accepts, no drift. Re-exported for the shell
|
|
20
|
+
* (mcpWire.ts / seamQuery.ts import it from HERE, not @sema-ai/sdk). */
|
|
21
|
+
export type McpServerSpec = NonNullable<TaskRequest['mcpServers']>[number];
|
|
22
|
+
/** Server caps mirror the service merge cap (task-mcp.ts: ≤32, fail-closed on malformed). */
|
|
23
|
+
export declare const MCP_CAPS: {
|
|
24
|
+
readonly items: 32;
|
|
25
|
+
};
|
|
26
|
+
/** Structural subset of CC's `McpServerConfig` union (services/mcp/types.ts) this projection reads. */
|
|
27
|
+
export interface McpConfigLike {
|
|
28
|
+
/** discriminator; absent ⇒ stdio (CC: type optional for stdio, back-compat). */
|
|
29
|
+
type?: string;
|
|
30
|
+
command?: string;
|
|
31
|
+
args?: string[];
|
|
32
|
+
env?: Record<string, string>;
|
|
33
|
+
url?: string;
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
allowTools?: string[];
|
|
36
|
+
}
|
|
37
|
+
/** Map one CC `.mcp.json` server → core `McpServerSpec`, or null when the transport isn't core-supported
|
|
38
|
+
* (sse/sse-ide/ws/ws-ide) or required fields are missing. */
|
|
39
|
+
export declare function mcpConfigToSpec(name: string, c: McpConfigLike): McpServerSpec | null;
|
|
40
|
+
/** Project a `.mcp.json` server map → capped `McpServerSpec[]` (skips unsupported transports + malformed). */
|
|
41
|
+
export declare function mcpConfigsToSpecs(servers: Record<string, McpConfigLike> | undefined): McpServerSpec[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Server caps mirror the service merge cap (task-mcp.ts: ≤32, fail-closed on malformed). */
|
|
2
|
+
export const MCP_CAPS = { items: 32 };
|
|
3
|
+
/** Map one CC `.mcp.json` server → core `McpServerSpec`, or null when the transport isn't core-supported
|
|
4
|
+
* (sse/sse-ide/ws/ws-ide) or required fields are missing. */
|
|
5
|
+
export function mcpConfigToSpec(name, c) {
|
|
6
|
+
const n = (name ?? '').trim();
|
|
7
|
+
if (!n)
|
|
8
|
+
return null;
|
|
9
|
+
const kind = c.type ?? 'stdio'; // stdio default (CC: `type` optional for stdio)
|
|
10
|
+
if (kind === 'stdio') {
|
|
11
|
+
if (!c.command)
|
|
12
|
+
return null;
|
|
13
|
+
return {
|
|
14
|
+
name: n,
|
|
15
|
+
transport: {
|
|
16
|
+
kind: 'stdio',
|
|
17
|
+
command: c.command,
|
|
18
|
+
...(c.args && c.args.length > 0 ? { args: c.args } : {}),
|
|
19
|
+
...(c.env ? { env: c.env } : {}),
|
|
20
|
+
},
|
|
21
|
+
...(c.allowTools && c.allowTools.length > 0 ? { allowTools: c.allowTools } : {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (kind === 'http') {
|
|
25
|
+
if (!c.url)
|
|
26
|
+
return null;
|
|
27
|
+
return {
|
|
28
|
+
name: n,
|
|
29
|
+
transport: {
|
|
30
|
+
kind: 'http',
|
|
31
|
+
url: c.url,
|
|
32
|
+
...(c.headers ? { headers: c.headers } : {}),
|
|
33
|
+
},
|
|
34
|
+
...(c.allowTools && c.allowTools.length > 0 ? { allowTools: c.allowTools } : {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// sse / sse-ide / ws / ws-ide → core McpServerSpec has no such transport (StreamableHTTP only) → skip.
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/** Project a `.mcp.json` server map → capped `McpServerSpec[]` (skips unsupported transports + malformed). */
|
|
41
|
+
export function mcpConfigsToSpecs(servers) {
|
|
42
|
+
const out = [];
|
|
43
|
+
for (const [name, c] of Object.entries(servers ?? {})) {
|
|
44
|
+
if (out.length >= MCP_CAPS.items)
|
|
45
|
+
break;
|
|
46
|
+
const spec = mcpConfigToSpec(name, c);
|
|
47
|
+
if (spec)
|
|
48
|
+
out.push(spec);
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/sema/modelBudgetRule.ts 逐字搬入(零依赖,纯规则)。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* modelBudgetRule.ts — max-output-tokens 中央规则(clay 2026-07-15 拍板,F2 maxTokens 裁决批)。
|
|
6
|
+
*
|
|
7
|
+
* 裁决(逐字):
|
|
8
|
+
* · 上下文窗口:预设/家族表能匹配用匹配值;匹配不上默认 200000(FALLBACK_CONTEXT_WINDOW)。
|
|
9
|
+
* · maxTokens 默认:32000;上下文窗口 ≥500000 → 64000;恒受两道封顶:
|
|
10
|
+
* ① per-model 已知 cap(providerPresets 精确表,inferFamily 第①层命中带 perModelCap);
|
|
11
|
+
* ② 上下文窗口 ÷ 4(向下取整)。
|
|
12
|
+
* · UI 四档(超集):16K / 32K(默认)/ 64K / 128K;档位 > 上下文窗口÷4 的禁用/跳过
|
|
13
|
+
* (例:128K 上下文 → 顶 32K;1M → 全档可用)。
|
|
14
|
+
* · env 显式值恒赢:CLAUDE_CODE_MAX_OUTPUT_TOKENS 映射与显式 MODEL_MAX_TOKENS 既有行为不动
|
|
15
|
+
* (本模块只算默认,不碰覆盖层 —— 见 ccConfigFallback.applyModelEnvFamilyFallback)。
|
|
16
|
+
*
|
|
17
|
+
* CC 对照锚(有意偏离,记忆档 max-tokens-ruling-deviate-cc):CC 2.1.207 per-model 表
|
|
18
|
+
* `max_output_tokens:{default:32000,upper:64000}`(源 13760)+ CLAUDE_CODE_MAX_OUTPUT_TOKENS env
|
|
19
|
+
* 钳制(源 529278),无 UI 档位、无 ÷4 封顶。sema 面对任意三方模型/网关,家族表大数直接当默认会
|
|
20
|
+
* 超供应商 cap(400)或单轮吃穿预算 —— 故默认收敛到 CC 口径 32K/64K,并加 ÷4 与 per-model 封顶;
|
|
21
|
+
* UI 档位是超集便利面。
|
|
22
|
+
*
|
|
23
|
+
* 注意:providerPresets.json 精确表 / modelFamilies.json 家族表的 maxTokens 字段【保留】——
|
|
24
|
+
* 只作 cap 参考(perModelCap / 显示),不再直接当默认 stamp 值。
|
|
25
|
+
*/
|
|
26
|
+
/** 裁决:预设/家族都匹配不上时的上下文窗口默认(=CC 的 200k 口径)。 */
|
|
27
|
+
export declare const FALLBACK_CONTEXT_WINDOW = 200000;
|
|
28
|
+
/** UI 四档(超集):16K / 32K(默认)/ 64K / 128K。十进制(与 CC 32000/64000 同基)。 */
|
|
29
|
+
export declare const MAXTOK_TIERS: readonly [16000, 32000, 64000, 128000];
|
|
30
|
+
/**
|
|
31
|
+
* 默认 max tokens = min( ctx>=500000 ? 64000 : 32000 , floor(ctx/4) , perModelCap ?? ∞ )。
|
|
32
|
+
* contextWindow 传 null/undefined/非法 = 匹配不上 → 按 200000 算(→ 32000)。
|
|
33
|
+
*/
|
|
34
|
+
export declare function defaultMaxTokensFor(contextWindow: number | null | undefined, perModelCap?: number | null): number;
|
|
35
|
+
/**
|
|
36
|
+
* 该上下文窗口下可用的 UI 档位(> ctx÷4 的禁用/跳过)。可能为空(ctx < 64000,如 32K 上下文
|
|
37
|
+
* 连 16K 档都超 ÷4)—— UI 调用方对空列表降级(提示用 M 自由输入),规则函数不瞎补。
|
|
38
|
+
*/
|
|
39
|
+
export declare function tierChoicesFor(contextWindow: number | null | undefined): number[];
|
|
40
|
+
/**
|
|
41
|
+
* 档位循环:当前值在档内 → 下一档(循环);不在档内(自由输入/家族值)→ 大于当前的最小档,
|
|
42
|
+
* 都不大于则回第一档(与 modelCtxOverride.nextStep 同语义)。无可用档 → null(调用方降级)。
|
|
43
|
+
*/
|
|
44
|
+
export declare function nextMaxTokTier(current: number | null | undefined, contextWindow: number | null | undefined): number | null;
|