@sema-agent/server 2.0.0 → 3.0.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/MIGRATION.md +74 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +391 -0
- package/dist/boot/budget-tracing.d.ts +48 -0
- package/dist/boot/budget-tracing.js +86 -0
- package/dist/boot/config-center.d.ts +62 -0
- package/dist/boot/config-center.js +1002 -0
- package/dist/boot/coordinators.d.ts +33 -0
- package/dist/boot/coordinators.js +97 -0
- package/dist/boot/execution-env.d.ts +26 -0
- package/dist/boot/execution-env.js +370 -0
- package/dist/boot/leader.d.ts +27 -0
- package/dist/boot/leader.js +81 -0
- package/dist/boot/reapers.d.ts +53 -0
- package/dist/boot/reapers.js +252 -0
- package/dist/boot/resolve-spec.d.ts +70 -0
- package/dist/boot/resolve-spec.js +1072 -0
- package/dist/boot/runner-deps.d.ts +101 -0
- package/dist/boot/runner-deps.js +343 -0
- package/dist/boot/runtime-caps.d.ts +21 -0
- package/dist/boot/runtime-caps.js +62 -0
- package/dist/boot/session-faces.d.ts +57 -0
- package/dist/boot/session-faces.js +157 -0
- package/dist/boot/shutdown.d.ts +50 -0
- package/dist/boot/shutdown.js +129 -0
- package/dist/boot/stores.d.ts +32 -0
- package/dist/boot/stores.js +361 -0
- package/dist/boot/workflow-orchestration.d.ts +46 -0
- package/dist/boot/workflow-orchestration.js +150 -0
- package/dist/capabilities/scenarios.d.ts +5 -3
- package/dist/capabilities/scenarios.js +5 -3
- package/dist/config-center/apply-effective.js +4 -3
- package/dist/config-lkg.d.ts +2 -1
- package/dist/config-lkg.js +2 -1
- package/dist/config-types.d.ts +47 -7
- package/dist/config.d.ts +30 -13
- package/dist/config.js +562 -387
- package/dist/hooks/hook-llm.js +9 -0
- package/dist/http/routes/approvals-assistant.js +1 -1
- package/dist/http/routes/attachments.js +2 -2
- package/dist/http/routes/memory-policy.js +3 -3
- package/dist/http/routes/runs.js +1 -1
- package/dist/http/routes/session-sync.js +2 -2
- package/dist/http/routes/sessions.js +2 -2
- package/dist/http/routes/tasks.js +2 -2
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/routes/workflows.js +3 -1
- package/dist/http/server.d.ts +1 -1
- package/dist/http/server.js +25 -5
- package/dist/http/sse-log.js +1 -1
- package/dist/main.js +164 -3799
- package/dist/model-select.d.ts +1 -1
- package/dist/model-select.js +1 -1
- package/dist/plugins/checkpoint-store-sql.d.ts +13 -5
- package/dist/plugins/checkpoint-store-sql.js +10 -3
- package/dist/plugins/local-checkpoint-store.js +8 -2
- package/dist/plugins/remote-env-host.d.ts +2 -1
- package/dist/run-local.js +2 -1
- package/dist/session-titler.d.ts +3 -1
- package/dist/session-titler.js +2 -2
- package/dist/trace/project.js +4 -1
- package/package.json +5 -3
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/158 A10:composition root 分段 —— 计费/追踪/预算装配(brain、pricing、cost quota、
|
|
3
|
+
* usage tracker、fleet lease、tracer、side-query 记账、offload/policy/snapshot 三个 core 店)。
|
|
4
|
+
*
|
|
5
|
+
* 纯搬运:函数体逐字来自 `main.ts`(原 933-995 行),缩进不变;新增的只有 import 与包壳。
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ **位置即契约**:`tracer` 与 `sideQueryAccounting` 必须共用**同一组 sink 实例**
|
|
8
|
+
* (costQuota/fleetUsage/fleetLease/modelUsageTracker),故两者同段构造、不可拆到两处各造一份。
|
|
9
|
+
* `breakerState` 由 stores 段先行产出(brain 要它),所以本段排在 stores 之后。
|
|
10
|
+
*/
|
|
11
|
+
import { createBrain } from "../brain.js";
|
|
12
|
+
import { ModelUsageTracker, PromptManifestTracker, buildPricing, createSideQueryAccountant, createTracer } from "../budget.js";
|
|
13
|
+
import { FleetUsageAccumulator } from "../fleet-client.js";
|
|
14
|
+
import { createFleetLeaseFromEnv } from "../fleet-lease.js";
|
|
15
|
+
import { CostQuota } from "../observability/cost-quota.js";
|
|
16
|
+
export function createBudgetAndTracing(ctx) {
|
|
17
|
+
const { config, logger, metrics, backend, breakerState } = ctx;
|
|
18
|
+
const brain = createBrain(config, { breakerState });
|
|
19
|
+
// ③ Cost + ④ trace + ⑤ budget (1.37): inject per-model pricing (authoritative costMicroUsd), bridge
|
|
20
|
+
// core's content-free trace events to /metrics, and accumulate per-principal spend into the cost
|
|
21
|
+
// quota (the tracer reads the principal ALS so council/team sub-task cost is attributed too).
|
|
22
|
+
const pricing = buildPricing(config.models);
|
|
23
|
+
// S9 (SILENT-FALLBACK P0-e): write-behind flush/refresh failures previously vanished in a bare catch —
|
|
24
|
+
// the fleet silently degrades to per-replica counting (soft limits stop being fleet-wide). Every failure
|
|
25
|
+
// ticks the counter + streak gauge; warn once per episode (streak hits 3), info on the recovery edge.
|
|
26
|
+
const counterDegradeHook = (info) => {
|
|
27
|
+
metrics.setGauge("counter_flush_fail_streak", info.streak, { table: info.table, kind: info.kind });
|
|
28
|
+
if (info.streak > 0)
|
|
29
|
+
metrics.inc("counter_flush_failed_total", { table: info.table, kind: info.kind });
|
|
30
|
+
if (info.streak === 3)
|
|
31
|
+
logger.warn("counter_flush_degraded", { table: info.table, kind: info.kind, streak: info.streak, ...(info.error ? { error: info.error } : {}) });
|
|
32
|
+
else if (info.streak === 0 && info.prevStreak >= 3)
|
|
33
|
+
logger.info("counter_flush_recovered", { table: info.table, kind: info.kind, prevStreak: info.prevStreak });
|
|
34
|
+
};
|
|
35
|
+
// Per-principal cumulative cost quota: TiDB-backed (cross-replica, atomic write-behind) when a pool
|
|
36
|
+
// exists, else in-memory per-replica (single-replica / no DB). Both satisfy QuotaTracker. (design/30 P0-1)
|
|
37
|
+
const costQuota = config.maxPrincipalCostUsd > 0
|
|
38
|
+
? backend?.costQuota // local omits costQuota() → in-memory per-process CostQuota (single-replica)
|
|
39
|
+
? backend.costQuota(Math.round(config.maxPrincipalCostUsd * 1e6), config.costQuotaWindowSec * 1000, counterDegradeHook).startRefresh()
|
|
40
|
+
: new CostQuota(Math.round(config.maxPrincipalCostUsd * 1e6), config.costQuotaWindowSec * 1000)
|
|
41
|
+
: undefined;
|
|
42
|
+
// E8 (shell-host contract): per-task × per-model usage accumulator, fed by the tracer and drained by the durable run
|
|
43
|
+
// lifecycle into `model_usage` events (the `TaskStats.modelUsage` echo). One instance, shared tracer↔server.
|
|
44
|
+
const modelUsageTracker = new ModelUsageTracker();
|
|
45
|
+
// [998]② web 观测切片 A 数据面:prompt.assembled 的 manifest 经 tracer 记录、由 durable run 生命周期
|
|
46
|
+
// drain 成 `prompt_assembled` 事件(turns/stream 可读)。与 modelUsageTracker 同款 register 篱笆/生命周期。
|
|
47
|
+
const promptManifestTracker = new PromptManifestTracker();
|
|
48
|
+
// fleet 用量批报的 principal×model 窗口累计器 — 仅当 fleet 面可能启用(center lane 配置了)才建,
|
|
49
|
+
// 否则 tracer 走 undefined = 零行为(非 fleet 部署不多攒一份内存)。真正的启动门在 startFleetClientFromEnv。
|
|
50
|
+
const fleetUsage = config.configCenter && process.env.FLEET_ADVERTISE_ADDRESS ? new FleetUsageAccumulator() : undefined;
|
|
51
|
+
// fleet lease 消费(worker 侧第三接线,D4 AP 模式):协商式 —— center lane 配齐即启(lease 是出站消费面,
|
|
52
|
+
// 不需要 FLEET_ADVERTISE_ADDRESS);非 lease-enforced principal 一次 409 负缓存后走既有本地 CostQuota,
|
|
53
|
+
// 单用户(无 principal)提交门早退 —— 两者零行为变化。
|
|
54
|
+
const fleetLease = createFleetLeaseFromEnv(config, { logger, metrics });
|
|
55
|
+
// weight-at-burn 回调:读 config.modelQuotaWeights(registry hot-apply 的活表;env lane 空 ⇒ 1 兜底)。
|
|
56
|
+
const tracer = createTracer(metrics, costQuota, modelUsageTracker, fleetUsage, fleetLease, (m) => config.modelQuotaWeights[m] ?? 1, promptManifestTracker);
|
|
57
|
+
// [1469] side-query 记账 seam:与 tracer 同一装配点、同一组 sink 实例(codex R3——sideQuery 不发
|
|
58
|
+
// brain.call,四路 sink 必须由 server 半场喂,两臂同语义见 createSideQueryAccountant 头注)。
|
|
59
|
+
const sideQueryAccounting = createSideQueryAccountant(metrics, costQuota, fleetUsage, fleetLease, (m) => config.modelQuotaWeights[m] ?? 1);
|
|
60
|
+
// Durable offload store (core 1.47/1.49): large tool results survive a cross-replica wake. Without a
|
|
61
|
+
// pool, core's task-scoped in-memory default applies (graceful: cross-wake fetch misses → preview stands).
|
|
62
|
+
const toolResultStore = backend?.toolResult ? backend.toolResult() : undefined; // tidb/pg = SQL twins; local = core's FileToolResultStore (core 1.219 — restart-durable refs); no backend → core's in-memory default
|
|
63
|
+
// E6 durable SessionPolicyStore — operator-tightened per-session tool rules core reads at prepare-time (subtract-only).
|
|
64
|
+
// Present on every backend (incl local = core's InMemorySessionPolicyStore); undefined only on the env-only/no-backend
|
|
65
|
+
// worker → feature OFF (core reads no rules). Wired into the PRIMARY Runner below + the PUT/GET policy route + E21 purge.
|
|
66
|
+
const sessionPolicyStore = backend ? backend.sessionPolicy() : undefined;
|
|
67
|
+
// E19 rewind-files — working-tree snapshot/restore keyed by entryId (the same anchor as E18), + the 2c artifact-transfer
|
|
68
|
+
// store. core AUTOMATICALLY snapshots each completed turn + restores on resumeAt when `spec.rewindFiles` is set, for ANY
|
|
69
|
+
// ExecutionEnv when this store is wired (gate-split 1.134.0 removed the isRemoteExecutionEnv skip → host/local-mode
|
|
70
|
+
// + e2b/k8s/ssh/adb/local-docker all active). Durable on tidb/pg (cross-replica + 2c), local = core's
|
|
71
|
+
// InMemoryFileSnapshotStore. Wired into the PRIMARY Runner + the `rewindFiles` cap + E21 purge.
|
|
72
|
+
const fileSnapshotStore = backend ? backend.fileSnapshot() : undefined;
|
|
73
|
+
// [805]③a / [806]④: E19-fix observability — core 1.287 captureManifest TOLERATES enumerate→read-window
|
|
74
|
+
// vanished files (skip, not fail) and reports the count ONLY in its return value; the SQL twins expose it via
|
|
75
|
+
// this optional sink. Metric = the live face of "the fix is absorbing real races" (a warn would be noise — the
|
|
76
|
+
// skip is the CORRECT behavior). GAP (honest): the local lane uses core's own store, which drops the count
|
|
77
|
+
// internally — surfacing it there needs a core seam (noted on the board, not faked here).
|
|
78
|
+
if (fileSnapshotStore && "onSkippedVanished" in fileSnapshotStore) {
|
|
79
|
+
fileSnapshotStore.onSkippedVanished = (count) => metrics.inc("snapshot_skipped_vanished_total", {}, count);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
brain, pricing, counterDegradeHook, costQuota, modelUsageTracker, promptManifestTracker,
|
|
83
|
+
fleetUsage, fleetLease, tracer, sideQueryAccounting, toolResultStore, sessionPolicyStore, fileSnapshotStore,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=budget-tracing.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { CenterPromptSource, type Model } from "@sema-agent/core";
|
|
2
|
+
import { buildPricing } from "../budget.js";
|
|
3
|
+
import { type PromptsDomainFaces } from "../capabilities/center-prompts.js";
|
|
4
|
+
import { type Scenario, type ScenarioDeps, type ScenarioDetail } from "../capabilities/scenarios.js";
|
|
5
|
+
import type { LoadedSkill } from "../capabilities/skills.js";
|
|
6
|
+
import { type ServiceConfig } from "../config.js";
|
|
7
|
+
import type { Logger } from "../observability/logger.js";
|
|
8
|
+
import type { Metrics } from "../observability/metrics.js";
|
|
9
|
+
import { type RestartSignal } from "../sema-registry.js";
|
|
10
|
+
export interface ConfigCenterRuntimeCtx {
|
|
11
|
+
config: ServiceConfig;
|
|
12
|
+
logger: Logger;
|
|
13
|
+
metrics: Metrics;
|
|
14
|
+
/** 🔴 与 main 的 remoteExec loader 共用的**同一个**本地根(split-brain 防线,理由见 main.ts 构造点)。 */
|
|
15
|
+
localRoot: string;
|
|
16
|
+
}
|
|
17
|
+
/** center scenarios overlay 的活引用面(overlay 就地写进 main 持有的两张表)。 */
|
|
18
|
+
export interface CenterScenarioOverlayTargets {
|
|
19
|
+
scenarioDeps: ScenarioDeps;
|
|
20
|
+
scenarios: Record<string, Scenario>;
|
|
21
|
+
scenarioDetails: Record<string, ScenarioDetail>;
|
|
22
|
+
/** overlay 前捕获的六内建名(centerScenarioDetails 的 shadow 判据)。 */
|
|
23
|
+
builtinScenarioNames: string[];
|
|
24
|
+
}
|
|
25
|
+
/** 跨段可变状态的**唯一**对外读口 + 三个原位动作。字段语义见各方法上的注释。 */
|
|
26
|
+
export interface ConfigCenterRuntime {
|
|
27
|
+
/** 配置源形态;`undefined` = 纯 env 部署(本运行时的所有分支不存在)。 */
|
|
28
|
+
readonly providerKind: "remote" | "local" | undefined;
|
|
29
|
+
/** core `CenterPromptSource`(RunnerDeps / subRunner 必须同实例)。 */
|
|
30
|
+
readonly promptSource: CenterPromptSource;
|
|
31
|
+
/** DUAL-MODE §4/§5:local 形从 `config.d/remote-exec.json` 覆写 `config.remoteExec`(坏文件 = fail-closed 抛)。 */
|
|
32
|
+
applyLocalRemoteExec(): Promise<void>;
|
|
33
|
+
/** center skills overlay → plugins 消费 → boot LKG 落盘/skill-stale 判定 → mcp 解析。返回新的 skills 表。 */
|
|
34
|
+
applyCenterCapabilities(skills: LoadedSkill[]): Promise<LoadedSkill[]>;
|
|
35
|
+
/** center 声明场景 overlay(就地写进传入的两张表)。 */
|
|
36
|
+
applyCenterScenarios(t: CenterScenarioOverlayTargets): void;
|
|
37
|
+
/** per-model key resolver 首建(原位调用,见文件头注 5)。 */
|
|
38
|
+
initKeyResolver(): void;
|
|
39
|
+
/** 60s refresh cadence + boot-deferred 到货续接。 */
|
|
40
|
+
startRefreshLoop(a: {
|
|
41
|
+
runnerTierFrozen: boolean;
|
|
42
|
+
pricing: ReturnType<typeof buildPricing>;
|
|
43
|
+
}): void;
|
|
44
|
+
/** 晚绑取值:refresh 热应用会整个换引用(hook LLM / resolveSpec 每次现取)。 */
|
|
45
|
+
getKeyResolver(): ((model: Model) => Promise<{
|
|
46
|
+
apiKey: string;
|
|
47
|
+
} | undefined>) | undefined;
|
|
48
|
+
/** 晚绑取值:center 提示词面(热采用,新任务边界生效)。 */
|
|
49
|
+
getCenterPrompts(): PromptsDomainFaces | undefined;
|
|
50
|
+
/** boot ready 门:roster 未落地 = 计费提交 503 + /health ready:false。 */
|
|
51
|
+
modelReady(): boolean;
|
|
52
|
+
/** /health.restart(orchestrator 自动重启信号)。 */
|
|
53
|
+
restartState(): RestartSignal | undefined;
|
|
54
|
+
/** /health.modelPlaneDeferred(codex R18 卡死的 plane,无 next-boot handoff)。 */
|
|
55
|
+
planeDeferredState(): {
|
|
56
|
+
version: number;
|
|
57
|
+
since: number;
|
|
58
|
+
blocked?: string[];
|
|
59
|
+
} | undefined;
|
|
60
|
+
}
|
|
61
|
+
export declare function createConfigCenterRuntime(ctx: ConfigCenterRuntimeCtx): Promise<ConfigCenterRuntime>;
|
|
62
|
+
//# sourceMappingURL=config-center.d.ts.map
|