create-principles-disciple 1.145.11 → 1.145.13
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/_release/product-identity.json +2 -2
- package/codex-adapter/dist/codec/input-decoder.js +11 -3
- package/codex-adapter/package.json +1 -1
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +3 -1
- package/console/dist/server/models/ActivationsConsoleModel.js +39 -5
- package/console/dist/server/models/ApprovalsConsoleModel.d.ts +1 -1
- package/console/dist/server/models/ApprovalsConsoleModel.js +64 -8
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.d.ts +25 -1
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +116 -24
- package/console/dist/server/routes/approvals-grouped.js +5 -2
- package/console/dist/shared/prompt-injection-contract.d.ts +83 -2
- package/console/dist/ui/i18n/en.json +25 -1
- package/console/dist/ui/i18n/zh-CN.json +25 -1
- package/console/dist/ui/pages/activation/ActivationPage.js +56 -5
- package/console/dist/ui/pages/focus/FocusPage.js +87 -21
- package/console/dist/ui/pages/focus/focus-validation.js +12 -0
- package/console/dist/ui/utils/validators.d.ts +6 -0
- package/console/dist/ui/utils/validators.js +93 -4
- package/console/dist/web/assets/app.js +24 -24
- package/core/dist/host/host-adapter.d.ts +27 -0
- package/core/dist/host/host-adapter.d.ts.map +1 -1
- package/core/dist/host/host-adapter.js.map +1 -1
- package/core/dist/host/index.d.ts +1 -1
- package/core/dist/host/index.d.ts.map +1 -1
- package/core/dist/host/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts +2 -0
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +2 -0
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-budget-policy.d.ts +106 -0
- package/core/dist/runtime-v2/activation/prompt-budget-policy.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/prompt-budget-policy.js +229 -0
- package/core/dist/runtime-v2/activation/prompt-budget-policy.js.map +1 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts +2 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js +50 -1
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +3 -3
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +2 -2
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +24 -0
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +22 -0
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/package.json +1 -1
- package/host-runtime/dist/active-principle-prompt.d.ts +23 -1
- package/host-runtime/dist/active-principle-prompt.js +21 -5
- package/host-runtime/dist/index.d.ts +1 -0
- package/host-runtime/dist/index.js +37 -2
- package/host-runtime/dist/prompt-activation-deliverability.d.ts +36 -3
- package/host-runtime/dist/prompt-activation-deliverability.js +44 -26
- package/host-runtime/dist/prompt-injection-budget-observation.d.ts +176 -0
- package/host-runtime/dist/prompt-injection-budget-observation.js +449 -0
- package/host-runtime/dist/prompt-injection-projection.d.ts +39 -1
- package/host-runtime/dist/prompt-injection-projection.js +43 -9
- package/host-runtime/dist/prompt-injection-status.d.ts +47 -5
- package/host-runtime/dist/prompt-injection-status.js +45 -8
- package/host-runtime/package.json +1 -1
- package/package.json +2 -2
- package/pd-cli/dist/commands/runtime-activation.d.ts +3 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +23 -6
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/package.json +1 -1
- package/plugin/dist/bundle.js +430 -430
- package/plugin/dist/governance-audit.js +2 -2
- package/plugin/dist/openclaw-sdk.d.ts +9 -1
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/release-manager/package.json +2 -2
- package/workbuddy-adapter/dist/codec/input-decoder.js +16 -4
- package/workbuddy-adapter/package.json +1 -1
|
@@ -15,11 +15,43 @@
|
|
|
15
15
|
export type PromptInjectionTargetHostName = 'openclaw' | 'codex' | 'workbuddy';
|
|
16
16
|
export type PromptInjectionRouteName = 'legacy_trim' | 'shared_render';
|
|
17
17
|
export type PromptInjectionBudgetScopeName = 'selected_lines' | 'full_directive_context';
|
|
18
|
+
export type PromptBudgetCapacitySourceWire = 'host_effective_window' | 'pi_catalog_exact' | 'legacy_fallback';
|
|
19
|
+
export type PromptBudgetCapacityStatusWire = 'confirmed' | 'unknown';
|
|
20
|
+
/**
|
|
21
|
+
* Bounded machine-readable fallback reason. Closed set mirroring the core
|
|
22
|
+
* `PromptBudgetFallbackReason` plus the console-side observation code
|
|
23
|
+
* `runtime_budget_observation_stale` (PRI-1017: a runtime observation exists
|
|
24
|
+
* but is too old to be presented as the current budget). Never free-form
|
|
25
|
+
* detail or user content.
|
|
26
|
+
*/
|
|
27
|
+
export type PromptBudgetFallbackReasonWire = 'host_capacity_absent' | 'host_capacity_source_untrusted' | 'host_capacity_invalid_value' | 'catalog_unavailable' | 'model_identity_absent' | 'catalog_no_exact_match' | 'catalog_no_match_for_model_id' | 'catalog_ambiguous_model_id' | 'catalog_provider_absent' | 'catalog_metadata_invalid' | 'runtime_budget_observation_stale';
|
|
18
28
|
export interface PromptInjectionPerHostForecast {
|
|
19
29
|
hostKind: PromptInjectionTargetHostName;
|
|
20
30
|
route: PromptInjectionRouteName;
|
|
21
31
|
usedChars: number;
|
|
22
32
|
truncated: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* PRI-1017: the budget THIS host's forecast ran under — per-host forecasts
|
|
35
|
+
* no longer share one headline budget (each host carries its own runtime
|
|
36
|
+
* budget observation or its own honest fallback).
|
|
37
|
+
*/
|
|
38
|
+
budget?: number;
|
|
39
|
+
/** Provenance of this host's `budget` (absent = legacy fixed view). */
|
|
40
|
+
budgetCapacitySource?: PromptBudgetCapacitySourceWire;
|
|
41
|
+
/** confirmed = a real window fact; unknown = fixed fallback for this host. */
|
|
42
|
+
budgetCapacityStatus?: PromptBudgetCapacityStatusWire;
|
|
43
|
+
/**
|
|
44
|
+
* PRI-1017: ISO timestamp of the runtime budget observation this host's
|
|
45
|
+
* budget came from (absent = no observation; the fixed fallback applies).
|
|
46
|
+
* A PAST fact — the UI labels it as the most recent observation, never as
|
|
47
|
+
* a live confirmation.
|
|
48
|
+
*/
|
|
49
|
+
budgetObservedAt?: string;
|
|
50
|
+
/**
|
|
51
|
+
* PRI-1017: this host's OWN fallback reason. Per-host so one host's
|
|
52
|
+
* missing capacity is never attributed to another host.
|
|
53
|
+
*/
|
|
54
|
+
budgetFallbackReason?: PromptBudgetFallbackReasonWire;
|
|
23
55
|
}
|
|
24
56
|
/**
|
|
25
57
|
* PD_PROMPT_CAPACITY_V1 R-A3: per-live-prompt-activation injection status on
|
|
@@ -29,7 +61,14 @@ export interface PromptInjectionPerHostForecast {
|
|
|
29
61
|
*/
|
|
30
62
|
export interface PromptActivationInjectionStatusWire {
|
|
31
63
|
activationId: string;
|
|
32
|
-
|
|
64
|
+
/**
|
|
65
|
+
* SPEC-PD-MODEL-AWARE-PROMPT-BUDGET-001: `model_dependent` = the row's own
|
|
66
|
+
* entry misses the CURRENT projection budget but fits within the supported
|
|
67
|
+
* [min, max] budget range — injectability depends on the runtime model's
|
|
68
|
+
* context window, which this surface cannot see (never displayed as a
|
|
69
|
+
* definite yes or a permanent no).
|
|
70
|
+
*/
|
|
71
|
+
status: 'injectable' | 'oversized' | 'model_dependent' | 'window_excluded' | 'resolution_failed' | 'route_unconfirmed';
|
|
33
72
|
inCurrentWindow?: boolean;
|
|
34
73
|
costChars?: number;
|
|
35
74
|
budget?: number;
|
|
@@ -38,9 +77,11 @@ export interface PromptActivationInjectionStatusWire {
|
|
|
38
77
|
reason?: string;
|
|
39
78
|
perHostFits?: {
|
|
40
79
|
hostKind: PromptInjectionTargetHostName;
|
|
41
|
-
|
|
80
|
+
tierFit: PromptBudgetTierFitName;
|
|
42
81
|
}[];
|
|
43
82
|
}
|
|
83
|
+
/** Tier classification of a single serialized entry vs the supported budget range. */
|
|
84
|
+
export type PromptBudgetTierFitName = 'fits_all_tiers' | 'model_dependent' | 'exceeds_max_tier';
|
|
44
85
|
/** Route context attached to the activations payload (AC-01 visibility). */
|
|
45
86
|
export interface PromptInjectionRouteSummaryWire {
|
|
46
87
|
status: 'confirmed' | 'unconfirmed';
|
|
@@ -51,6 +92,19 @@ export interface PromptInjectionRouteSummaryWire {
|
|
|
51
92
|
nextAction?: string;
|
|
52
93
|
/** Present when no status could be computed at all (fail-loud degradation). */
|
|
53
94
|
globalReason?: string;
|
|
95
|
+
/**
|
|
96
|
+
* PRI-1017: ISO timestamp of the runtime budget observation the per-row
|
|
97
|
+
* `budget` figures were computed under (absent = fixed fallback). A PAST
|
|
98
|
+
* fact — label it as the most recent observation, never as live.
|
|
99
|
+
*/
|
|
100
|
+
budgetObservedAt?: string;
|
|
101
|
+
/** PRI-1017: provenance of the budget basis behind the per-row figures. */
|
|
102
|
+
budgetCapacitySource?: PromptBudgetCapacitySourceWire;
|
|
103
|
+
budgetCapacityStatus?: PromptBudgetCapacityStatusWire;
|
|
104
|
+
/** Present only when the budget basis was confirmed from a real window. */
|
|
105
|
+
budgetContextWindowTokens?: number;
|
|
106
|
+
/** Present only when the rows were measured under the fixed fallback. */
|
|
107
|
+
budgetFallbackReason?: PromptBudgetFallbackReasonWire;
|
|
54
108
|
}
|
|
55
109
|
export interface PromptInjectionBudgetStatus {
|
|
56
110
|
/** Hard char cap of the prompt injection surface (e.g. 2000). */
|
|
@@ -105,4 +159,31 @@ export interface PromptInjectionBudgetStatus {
|
|
|
105
159
|
nextAction?: string;
|
|
106
160
|
/** Present when capacityStatus === 'unconfirmed': per-host forecasts. */
|
|
107
161
|
perHost?: PromptInjectionPerHostForecast[];
|
|
162
|
+
/**
|
|
163
|
+
* PRI-1017: ISO timestamp of the runtime budget OBSERVATION `budget` and
|
|
164
|
+
* the provenance fields came from (absent = no usable observation; the
|
|
165
|
+
* numbers are the console's own fixed-fallback projection). The console
|
|
166
|
+
* holds no live host facts: an observation is the budget the LAST real
|
|
167
|
+
* injection ran under, and the UI must say so — never present it as a
|
|
168
|
+
* live confirmation.
|
|
169
|
+
*/
|
|
170
|
+
budgetObservedAt?: string;
|
|
171
|
+
/**
|
|
172
|
+
* SPEC-PD-MODEL-AWARE-PROMPT-BUDGET-001 §7: provenance of `budget` — the
|
|
173
|
+
* same resolution the real injection runs. `legacy_fallback` + `unknown`
|
|
174
|
+
* means these numbers are the fixed-budget view (no runtime model capacity
|
|
175
|
+
* was confirmed); the UI must present them as such, not as a
|
|
176
|
+
* model-accurate forecast. Absent behaves as the legacy fixed view
|
|
177
|
+
* (pre-SPEC payload compat).
|
|
178
|
+
*/
|
|
179
|
+
budgetCapacitySource?: PromptBudgetCapacitySourceWire;
|
|
180
|
+
/** confirmed = a real context window was resolved; unknown = fixed-budget fallback. */
|
|
181
|
+
budgetCapacityStatus?: PromptBudgetCapacityStatusWire;
|
|
182
|
+
/** The context window the budget was derived from; present only when confirmed. */
|
|
183
|
+
budgetContextWindowTokens?: number;
|
|
184
|
+
/**
|
|
185
|
+
* SPEC §7 v0.2: bounded machine-readable reason — present only when
|
|
186
|
+
* budgetCapacityStatus is 'unknown'. See `PromptBudgetFallbackReasonWire`.
|
|
187
|
+
*/
|
|
188
|
+
budgetFallbackReason?: PromptBudgetFallbackReasonWire;
|
|
108
189
|
}
|
|
@@ -100,13 +100,35 @@
|
|
|
100
100
|
"promptCapacityUnconfirmed": "Host capacity unconfirmed: the applicable hosts of this workspace take different injection routes; the numbers below are not bound to a specific host.",
|
|
101
101
|
"promptCapacitySharedRoute": "shared injection (billed on the full injected block)",
|
|
102
102
|
"promptCapacityListRoute": "list injection (billed on the selected lines)",
|
|
103
|
-
"promptCapacityPerHostEntry": "{{host}}: {{billing}} — {{used}}/{{budget}} chars{{full}}",
|
|
103
|
+
"promptCapacityPerHostEntry": "{{host}}: {{billing}} — {{used}}/{{budget}} chars{{full}}{{observed}}",
|
|
104
104
|
"promptCapacityPerHostFull": " (full)",
|
|
105
|
+
"promptCapacityPerHostObserved": " (budget from this host's most recent runtime observation at {{observedAt}})",
|
|
105
106
|
"promptCapacityViewAsHost": "View as {{host}}",
|
|
106
107
|
"promptCapacityClearHost": "Clear selection",
|
|
107
108
|
"promptScopeShared": "Forecast window (shared route, billed on the full injected block, unit=chars)",
|
|
108
109
|
"promptScopeList": "Forecast window (list route, billed on the selected lines{{full}}, unit=chars)",
|
|
109
110
|
"promptScopeFullRender": "; full injected block ≈ {{count}} chars",
|
|
111
|
+
"promptBudgetModelAwareNote": "Budget resolved from the confirmed model context ({{window}} tokens)",
|
|
112
|
+
"promptBudgetObservedNote": "Budget from the most recent runtime observation (source {{source}}, context {{window}} tokens, observed at {{observedAt}})",
|
|
113
|
+
"promptBudgetFallbackNote": "Estimated with the fixed fallback budget (console not bound to a runtime model{{reason}})",
|
|
114
|
+
"promptBudgetFallbackObservedNote": "The runtime's most recent observation did not confirm host capacity; estimated with the fixed fallback budget ({{reason}}, observed at {{observedAt}})",
|
|
115
|
+
"promptBudgetFallbackReasonSuffix": ", reason: {{code}}",
|
|
116
|
+
"promptBudgetFallbackObservedSuffix": "; the runtime's most recent observation was at {{observedAt}}",
|
|
117
|
+
"budgetCapacitySourceHostWindow": "host effective context window",
|
|
118
|
+
"budgetCapacitySourcePiCatalog": "exact model catalog match",
|
|
119
|
+
"budgetFallbackReason": {
|
|
120
|
+
"host_capacity_absent": "the host provided no context capacity fact",
|
|
121
|
+
"host_capacity_source_untrusted": "the host capacity source is untrusted",
|
|
122
|
+
"host_capacity_invalid_value": "the host capacity value is invalid",
|
|
123
|
+
"catalog_unavailable": "the model catalog is unavailable",
|
|
124
|
+
"model_identity_absent": "model identity is missing",
|
|
125
|
+
"catalog_no_exact_match": "no exact match in the model catalog",
|
|
126
|
+
"catalog_no_match_for_model_id": "the model id is not in the model catalog",
|
|
127
|
+
"catalog_ambiguous_model_id": "the model id is ambiguous in the model catalog",
|
|
128
|
+
"catalog_provider_absent": "the provider id is missing",
|
|
129
|
+
"catalog_metadata_invalid": "the model catalog metadata is invalid",
|
|
130
|
+
"runtime_budget_observation_stale": "the runtime budget observation is stale (older than 24h; not used as the current budget)"
|
|
131
|
+
},
|
|
110
132
|
"artifactUnavailableNote": "The draft artifact this approval points to is no longer in the artifact store (likely superseded by a newer revision), so its content cannot be shown. If in doubt, reject it; the raw artifact ID is shown in the replacement section's current-artifact field.",
|
|
111
133
|
"unlinkedCandidateNote": "No principle name is available for this card: its lineage cannot be resolved to a principle, and no readable title could be extracted from its stored content. Judge it from the approval records below; if you cannot decide, you can reject it.",
|
|
112
134
|
"approveAction": "Approve",
|
|
@@ -1031,6 +1053,8 @@
|
|
|
1031
1053
|
"tagHighRisk": "High Risk",
|
|
1032
1054
|
"tagNeverActivated": "Never Activated",
|
|
1033
1055
|
"injectionLabel": "Injection status",
|
|
1056
|
+
"budgetObservedNote": "The budget figures in the injection status come from the most recent runtime observation (source {{source}}, context {{window}} tokens, observed at {{observedAt}}), not a live confirmation.",
|
|
1057
|
+
"budgetFallbackNote": "The injection status is estimated with the fixed fallback budget ({{reason}}{{observed}}).",
|
|
1034
1058
|
"injectionInjectable": "Injectable (in current window, {{cost}}/{{budget}} chars)",
|
|
1035
1059
|
"injectionWindowRotates": "Out of window this turn: fits alone ({{cost}}/{{budget}} chars); rotation will reach it in later turns (forecast)",
|
|
1036
1060
|
"injectionWindowFifo": "Out of window this turn: fits alone ({{cost}}/{{budget}} chars); this route does not rotate, capacity must free up first",
|
|
@@ -100,13 +100,35 @@
|
|
|
100
100
|
"promptCapacityUnconfirmed": "当前宿主容量未确认:本工作区适用的宿主会走不同的注入路由,以下数字未绑定具体宿主。",
|
|
101
101
|
"promptCapacitySharedRoute": "共享注入(按完整注入块计费)",
|
|
102
102
|
"promptCapacityListRoute": "列表注入(按选中行计费)",
|
|
103
|
-
"promptCapacityPerHostEntry": "{{host}}:{{billing}} — {{used}}/{{budget}} 字符{{full}}",
|
|
103
|
+
"promptCapacityPerHostEntry": "{{host}}:{{billing}} — {{used}}/{{budget}} 字符{{full}}{{observed}}",
|
|
104
104
|
"promptCapacityPerHostFull": "(已满)",
|
|
105
|
+
"promptCapacityPerHostObserved": "(预算来自该宿主最近一次运行时观测,观测于 {{observedAt}})",
|
|
105
106
|
"promptCapacityViewAsHost": "按 {{host}} 查看",
|
|
106
107
|
"promptCapacityClearHost": "清除选择",
|
|
107
108
|
"promptScopeShared": "预测窗口(共享注入路由,按完整注入块计费,单位=字符)",
|
|
108
109
|
"promptScopeList": "预测窗口(列表注入路由,按选中行计费{{full}},单位=字符)",
|
|
109
110
|
"promptScopeFullRender": ",完整注入块约 {{count}} 字符",
|
|
111
|
+
"promptBudgetModelAwareNote": "预算按已确认的模型上下文解析({{window}} tokens)",
|
|
112
|
+
"promptBudgetObservedNote": "预算取自最近一次运行时观测(来源 {{source}},上下文 {{window}} tokens,观测于 {{observedAt}})",
|
|
113
|
+
"promptBudgetFallbackNote": "按固定回退预算估算(控制台未绑定运行时模型{{reason}})",
|
|
114
|
+
"promptBudgetFallbackObservedNote": "运行时最近一次观测未确认宿主容量,预算按固定回退估算({{reason}},观测于 {{observedAt}})",
|
|
115
|
+
"promptBudgetFallbackReasonSuffix": ",原因: {{code}}",
|
|
116
|
+
"promptBudgetFallbackObservedSuffix": ";运行时最近一次观测于 {{observedAt}}",
|
|
117
|
+
"budgetCapacitySourceHostWindow": "宿主有效上下文窗口",
|
|
118
|
+
"budgetCapacitySourcePiCatalog": "模型目录精确匹配",
|
|
119
|
+
"budgetFallbackReason": {
|
|
120
|
+
"host_capacity_absent": "宿主未提供上下文容量事实",
|
|
121
|
+
"host_capacity_source_untrusted": "宿主容量来源不可信",
|
|
122
|
+
"host_capacity_invalid_value": "宿主容量值无效",
|
|
123
|
+
"catalog_unavailable": "模型目录不可用",
|
|
124
|
+
"model_identity_absent": "缺少模型身份",
|
|
125
|
+
"catalog_no_exact_match": "模型目录无精确匹配",
|
|
126
|
+
"catalog_no_match_for_model_id": "模型目录中无此模型 ID",
|
|
127
|
+
"catalog_ambiguous_model_id": "模型 ID 在目录中存在歧义",
|
|
128
|
+
"catalog_provider_absent": "缺少提供商标识",
|
|
129
|
+
"catalog_metadata_invalid": "模型目录元数据无效",
|
|
130
|
+
"runtime_budget_observation_stale": "运行时预算观测已过期(超过 24 小时,不作为当前预算依据)"
|
|
131
|
+
},
|
|
110
132
|
"artifactUnavailableNote": "该审批指向的草稿原件已不在工件库中(可能已被新版本取代),内容无法显示。如无法判断,可选择拒绝;原始工件编号可点「替换待审版本」后在「当前工件」一栏查看。",
|
|
111
133
|
"unlinkedCandidateNote": "这张卡片没有可展示的原则名称:无法把它的血缘解析到某条原则,也没能从其存档内容里提取出可读的标题。请依据下方的审批记录判断;如无法判断,可选择拒绝。",
|
|
112
134
|
"approveAction": "批准",
|
|
@@ -1031,6 +1053,8 @@
|
|
|
1031
1053
|
"tagHighRisk": "高风险",
|
|
1032
1054
|
"tagNeverActivated": "从未激活",
|
|
1033
1055
|
"injectionLabel": "注入状态",
|
|
1056
|
+
"budgetObservedNote": "注入状态中的预算数字取自最近一次运行时观测(来源 {{source}},上下文 {{window}} tokens,观测于 {{observedAt}}),并非实时确认值。",
|
|
1057
|
+
"budgetFallbackNote": "注入状态按固定回退预算估算({{reason}}{{observed}})。",
|
|
1034
1058
|
"injectionInjectable": "可注入(当前窗口内,{{cost}}/{{budget}} 字符)",
|
|
1035
1059
|
"injectionWindowRotates": "本轮未入窗口:单条可装入({{cost}}/{{budget}} 字符),后续轮次会轮到(预测)",
|
|
1036
1060
|
"injectionWindowFifo": "本轮未入窗口:单条可装入({{cost}}/{{budget}} 字符),当前路由不轮转,需腾出容量才会注入",
|
|
@@ -13,6 +13,15 @@ import { ReceiptCoverageDisclosure, getReceiptSourceStatusLabelKey } from "../..
|
|
|
13
13
|
import { validateActivationsData, validateLifecycleMetricsData, isReversibleChannel, } from "./ActivationValidators.js";
|
|
14
14
|
import { enumLabel } from "../../utils/enum-labels.js";
|
|
15
15
|
import { formatDate } from "../../utils/format-date.js";
|
|
16
|
+
function tierFitLabel(t, tierFit) {
|
|
17
|
+
if (tierFit === undefined)
|
|
18
|
+
return t("pages.activation.fitUnknown", { defaultValue: "未知" });
|
|
19
|
+
if (tierFit === "fits_all_tiers")
|
|
20
|
+
return t("pages.activation.fitYes", { defaultValue: "可装入" });
|
|
21
|
+
if (tierFit === "model_dependent")
|
|
22
|
+
return t("pages.activation.fitModelDependent", { defaultValue: "视模型而定" });
|
|
23
|
+
return t("pages.activation.fitNo", { defaultValue: "超长" });
|
|
24
|
+
}
|
|
16
25
|
// Date+time rendering options — mirrors the old default toLocaleString() shape
|
|
17
26
|
// (numeric date, hours/minutes/seconds) while following the UI language.
|
|
18
27
|
const DATETIME_OPTS = {
|
|
@@ -151,7 +160,7 @@ function ActivationFactCard({ record, lifecycleData, receiptCount, onDisable, di
|
|
|
151
160
|
navigate(`/report-problem?${params.toString()}`);
|
|
152
161
|
}, children: t("pages.reportProblem.entryFeedback") }), _jsxs("div", { className: "mt-[14px] mb-2", children: [_jsx("span", { className: "text-ink-2 text-[13px]", children: t("pages.activation.principleLabel") }), " ", _jsx(Link, { to: `/principles/${record.principleId}`, className: "text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `principle-link-${record.principleId}`, title: record.principleId, children: record.action }), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), record.legacyDecisionUnknown && _jsx("div", { className: "mt-3 border-l-2 border-amber px-3 text-[12px] text-amber", children: t('pages.activation.legacyUnknown', { due: record.ownerReviewDueAt ? formatDate(record.ownerReviewDueAt, i18n.language, DATETIME_OPTS) : t('pages.activation.sevenDays') }) }), _jsxs("div", { className: "text-ink-3 text-[13px] leading-relaxed space-y-1", children: [_jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.actionLabel") }), " ", _jsx("span", { className: "text-ink-2", children: record.action })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.targetLabel") }), " ", _jsx("span", { className: "text-ink-2 font-mono text-[12px]", children: record.targetRef })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.activatedAtLabel") }), " ", neverActivated ? (_jsx("span", { className: "text-amber", children: t("pages.activation.neverActivated") })) : (_jsx("span", { className: "text-ink-2 font-mono text-[12px] tabular-nums", children: formatDate(record.activatedAt, i18n.language, DATETIME_OPTS) }))] }), record.promptInjection !== undefined && (_jsxs("div", { className: "flex items-start gap-2", "data-testid": `activation-injection-${record.activationId}`, children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.injectionLabel", { defaultValue: "注入状态" }) }), _jsxs("span", { className: `text-[12.5px] leading-relaxed ${record.promptInjection.status === "injectable"
|
|
153
162
|
? "text-ink-2"
|
|
154
|
-
: record.promptInjection.status === "window_excluded"
|
|
163
|
+
: record.promptInjection.status === "window_excluded" || record.promptInjection.status === "model_dependent"
|
|
155
164
|
? "text-amber"
|
|
156
165
|
: "text-danger"}`, children: [record.promptInjection.status === "injectable" &&
|
|
157
166
|
t("pages.activation.injectionInjectable", {
|
|
@@ -174,15 +183,19 @@ function ActivationFactCard({ record, lifecycleData, receiptCount, onDisable, di
|
|
|
174
183
|
defaultValue: "超长不可注入:单条已 {{cost}} 字符 > 上限 {{budget}} 字符,轮转也救不了——需精简正文",
|
|
175
184
|
cost: record.promptInjection.costChars ?? 0,
|
|
176
185
|
budget: record.promptInjection.budget ?? 0,
|
|
186
|
+
}), record.promptInjection.status === "model_dependent" &&
|
|
187
|
+
t("pages.activation.injectionModelDependent", {
|
|
188
|
+
defaultValue: "取决于模型上下文:单条 {{cost}} 字符在最小预算内装不下、但在支持上限内——较小上下文模型会排除它,较大模型可注入",
|
|
189
|
+
cost: record.promptInjection.costChars ?? 0,
|
|
177
190
|
}), record.promptInjection.status === "resolution_failed" &&
|
|
178
191
|
t("pages.activation.injectionResolutionFailed", {
|
|
179
192
|
defaultValue: "无法判定:{{reason}}",
|
|
180
193
|
reason: record.promptInjection.reason ?? "unknown",
|
|
181
194
|
}), record.promptInjection.status === "route_unconfirmed" && (_jsxs(_Fragment, { children: [t("pages.activation.injectionRouteUnconfirmed", {
|
|
182
195
|
defaultValue: "当前宿主容量未确认:OpenClaw {{oc}} / Codex {{cx}} / WorkBuddy {{wb}}",
|
|
183
|
-
oc:
|
|
184
|
-
cx:
|
|
185
|
-
wb:
|
|
196
|
+
oc: tierFitLabel(t, record.promptInjection.perHostFits?.find((f) => f.hostKind === "openclaw")?.tierFit),
|
|
197
|
+
cx: tierFitLabel(t, record.promptInjection.perHostFits?.find((f) => f.hostKind === "codex")?.tierFit),
|
|
198
|
+
wb: tierFitLabel(t, record.promptInjection.perHostFits?.find((f) => f.hostKind === "workbuddy")?.tierFit),
|
|
186
199
|
}), record.promptInjection.reason !== undefined && (_jsx("span", { className: "block text-ink-4 text-[11.5px]", children: record.promptInjection.reason }))] }))] })] })), canProposeRevision && (_jsxs("div", { className: "mt-2", "data-testid": `activation-revision-${record.activationId}`, children: [!showRevisionInput && revisionResult === null && (_jsx("button", { type: "button", onClick: () => { setShowRevisionInput(true); setRevisionText(""); }, "data-testid": `activation-revision-open-${record.activationId}`, className: "inline-flex items-center border border-line rounded-[3px] px-[10px] py-[4px] text-[12px] hover:border-line-2", children: t("pages.activation.revisionOpen", { defaultValue: "修改为可注入版本" }) })), showRevisionInput && (_jsxs("div", { className: "rounded-[3px] border border-line bg-surface/60 p-2", children: [_jsx("textarea", { value: revisionText, onChange: (e) => setRevisionText(e.target.value), rows: 3, className: "w-full rounded-[2px] border border-line bg-panel px-2 py-1 text-[12.5px]", placeholder: t("pages.activation.revisionPlaceholder", { defaultValue: "输入新的原则正文(保留触发条件、必须动作和必要例外,尽量精简)" }), "data-testid": `activation-revision-input-${record.activationId}` }), _jsxs("div", { className: "mt-1 flex gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: handleProposeRevision, disabled: revisionSubmitting || revisionText.trim().length === 0, "data-testid": `activation-revision-submit-${record.activationId}`, children: revisionSubmitting ? t("common.loading") + "…" : t("pages.activation.revisionSubmit", { defaultValue: "创建待审批的新版本" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setShowRevisionInput(false), children: t("common.cancel", { defaultValue: "取消" }) })] })] })), revisionResult !== null && (_jsxs("div", { className: "rounded-[3px] border border-gov/40 bg-gov/5 p-2 text-[12px] leading-relaxed", "data-testid": `activation-revision-result-${record.activationId}`, children: [_jsx("p", { children: t("pages.activation.revisionResultNote", {
|
|
187
200
|
defaultValue: "新版本已进入待审批(审批号 {{approvalId}})。批准后旧版本自动停用并由新版本替换;拒绝则旧版本继续生效。",
|
|
188
201
|
approvalId: revisionResult.approvalId ?? "",
|
|
@@ -386,7 +399,45 @@ export function ActivationPage() {
|
|
|
386
399
|
const ordinaryActive = activeActivations.filter(record => !pendingRuleCode.includes(record) && !safetyAlerts.includes(record));
|
|
387
400
|
const inactiveActivations = activations.filter((a) => a.status === "inactive");
|
|
388
401
|
const neverActivatedCount = activations.filter((a) => a.activatedAt === null).length;
|
|
389
|
-
return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.activation.eyebrow") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: activeActivations.length === 0, children: t("pages.activation.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.activation.subtitle") }), _jsxs("div", { className: "text-sm leading-relaxed text-ink-2 mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: activeActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryActive") }), " ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: inactiveActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryInactive") }), neverActivatedCount > 0 && (_jsxs(_Fragment, { children: [" ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-amber tabular-nums", children: neverActivatedCount }), " ", _jsx("span", { className: "text-amber", children: t("pages.activation.summaryNeverActivated") })] }))] }), _jsx(CapabilityBoundaryDeclaration, {}), activeActivations.some(record => record.action === 'code_tool_hook_live_activate') && _jsx("div", { className: "mt-4 flex justify-end", children: _jsx(Button, { variant: "destructive", onClick: () => void handleEmergencyPause(), children: t('pages.activation.pauseAll') }) }), degradedNote && (_jsx("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", children: degradedNote })), receiptDegraded && (_jsxs("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", "data-testid": "receipt-counts-degraded", children: [receiptCoverage !== null && (_jsx("span", { className: "block font-medium text-ink-3", children: t(getReceiptSourceStatusLabelKey(receiptCoverage.sourceStatus)) })), t("pages.activation.receiptsUnavailable", { reason: receiptDegraded.reason }), receiptDegraded.nextAction && (_jsx("span", { className: "mt-1 block font-mono text-[12px]", children: receiptDegraded.nextAction }))] })), receiptCounts !== null && receiptCoverage !== null && (_jsx("div", { className: "mt-4 bg-surface/60 border-l-2 border-line px-3 py-2", "data-testid": "receipt-counts-coverage", children: _jsx(ReceiptCoverageDisclosure, { coverage: receiptCoverage }) })), pendingRuleCode.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-pending-rulecode", children: [_jsx(SectionTitle, { id: "section-pending-rulecode", children: t('pages.activation.pendingRules') }), _jsx("p", { className: "mb-3 text-[12px] text-ink-3", children: t('pages.activation.pendingRulesDescription') }), _jsx("div", { className: "space-y-[14px]", children: pendingRuleCode.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), safetyAlerts.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-safety-alerts", children: [_jsx(SectionTitle, { id: "section-safety-alerts", children: t('pages.activation.safetyAlerts') }), _jsx("p", { className: "mb-3 text-[12px] text-danger", children: t('pages.activation.safetyAlertsDescription') }), _jsx("div", { className: "space-y-[14px]", children: safetyAlerts.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-active", children: [_jsx(SectionTitle, { id: "section-active", children: t("pages.activation.sectionActive") }),
|
|
402
|
+
return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.activation.eyebrow") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: activeActivations.length === 0, children: t("pages.activation.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.activation.subtitle") }), _jsxs("div", { className: "text-sm leading-relaxed text-ink-2 mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: activeActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryActive") }), " ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: inactiveActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryInactive") }), neverActivatedCount > 0 && (_jsxs(_Fragment, { children: [" ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-amber tabular-nums", children: neverActivatedCount }), " ", _jsx("span", { className: "text-amber", children: t("pages.activation.summaryNeverActivated") })] }))] }), _jsx(CapabilityBoundaryDeclaration, {}), activeActivations.some(record => record.action === 'code_tool_hook_live_activate') && _jsx("div", { className: "mt-4 flex justify-end", children: _jsx(Button, { variant: "destructive", onClick: () => void handleEmergencyPause(), children: t('pages.activation.pauseAll') }) }), degradedNote && (_jsx("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", children: degradedNote })), receiptDegraded && (_jsxs("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", "data-testid": "receipt-counts-degraded", children: [receiptCoverage !== null && (_jsx("span", { className: "block font-medium text-ink-3", children: t(getReceiptSourceStatusLabelKey(receiptCoverage.sourceStatus)) })), t("pages.activation.receiptsUnavailable", { reason: receiptDegraded.reason }), receiptDegraded.nextAction && (_jsx("span", { className: "mt-1 block font-mono text-[12px]", children: receiptDegraded.nextAction }))] })), receiptCounts !== null && receiptCoverage !== null && (_jsx("div", { className: "mt-4 bg-surface/60 border-l-2 border-line px-3 py-2", "data-testid": "receipt-counts-coverage", children: _jsx(ReceiptCoverageDisclosure, { coverage: receiptCoverage }) })), pendingRuleCode.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-pending-rulecode", children: [_jsx(SectionTitle, { id: "section-pending-rulecode", children: t('pages.activation.pendingRules') }), _jsx("p", { className: "mb-3 text-[12px] text-ink-3", children: t('pages.activation.pendingRulesDescription') }), _jsx("div", { className: "space-y-[14px]", children: pendingRuleCode.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), safetyAlerts.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-safety-alerts", children: [_jsx(SectionTitle, { id: "section-safety-alerts", children: t('pages.activation.safetyAlerts') }), _jsx("p", { className: "mb-3 text-[12px] text-danger", children: t('pages.activation.safetyAlertsDescription') }), _jsx("div", { className: "space-y-[14px]", children: safetyAlerts.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-active", children: [_jsx(SectionTitle, { id: "section-active", children: t("pages.activation.sectionActive") }), (() => {
|
|
403
|
+
const route = activationsData?.promptInjectionRoute;
|
|
404
|
+
if (route?.status !== "confirmed")
|
|
405
|
+
return null;
|
|
406
|
+
// The "observed" copy names a source + window. Only a CONFIRMED
|
|
407
|
+
// observation carries those facts; a usable observation can itself
|
|
408
|
+
// be the runtime's fallback (no trusted host capacity), and showing
|
|
409
|
+
// window=0 with a host-window label would be a fabricated claim.
|
|
410
|
+
if (route.budgetCapacityStatus === "confirmed"
|
|
411
|
+
&& route.budgetObservedAt !== undefined
|
|
412
|
+
&& route.budgetContextWindowTokens !== undefined) {
|
|
413
|
+
return (_jsx("p", { className: "mb-3 text-[12px] text-ink-3", "data-testid": "activation-budget-observed-note", children: t("pages.activation.budgetObservedNote", {
|
|
414
|
+
defaultValue: "注入状态中的预算数字取自最近一次运行时观测(来源 {{source}},上下文 {{window}} tokens,观测于 {{observedAt}}),并非实时确认值。",
|
|
415
|
+
source: route.budgetCapacitySource === "pi_catalog_exact"
|
|
416
|
+
? t("pages.focus.budgetCapacitySourcePiCatalog", { defaultValue: "模型目录精确匹配" })
|
|
417
|
+
: t("pages.focus.budgetCapacitySourceHostWindow", { defaultValue: "宿主有效上下文窗口" }),
|
|
418
|
+
window: route.budgetContextWindowTokens,
|
|
419
|
+
observedAt: route.budgetObservedAt,
|
|
420
|
+
}) }));
|
|
421
|
+
}
|
|
422
|
+
if (route.budgetCapacityStatus === "unknown" && route.budgetFallbackReason !== undefined) {
|
|
423
|
+
const observedSuffix = route.budgetObservedAt !== undefined
|
|
424
|
+
// The runtime's own most recent injection ALSO fell back — the
|
|
425
|
+
// reason is that observation's, not a console-only guess.
|
|
426
|
+
? t("pages.focus.promptBudgetFallbackObservedSuffix", {
|
|
427
|
+
defaultValue: ";运行时最近一次观测于 {{observedAt}}",
|
|
428
|
+
observedAt: route.budgetObservedAt,
|
|
429
|
+
})
|
|
430
|
+
: "";
|
|
431
|
+
return (_jsx("p", { className: "mb-3 text-[12px] text-ink-3", "data-testid": "activation-budget-fallback-note", children: t("pages.activation.budgetFallbackNote", {
|
|
432
|
+
defaultValue: "注入状态按固定回退预算估算({{reason}}{{observed}})。",
|
|
433
|
+
reason: t(`pages.focus.budgetFallbackReason.${route.budgetFallbackReason}`, {
|
|
434
|
+
defaultValue: route.budgetFallbackReason,
|
|
435
|
+
}),
|
|
436
|
+
observed: observedSuffix,
|
|
437
|
+
}) }));
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
})(), ordinaryActive.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: ordinaryActive.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: receiptCounts !== null && !receiptCountsUntrustworthy ? (Object.hasOwn(receiptCounts, record.principleId) ? receiptCounts[record.principleId] : null) : undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: t("pages.activation.emptyActive") }))] }), inactiveActivations.length > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-inactive", children: [_jsx(SectionTitle, { id: "section-inactive", children: t("pages.activation.sectionInactive") }), _jsx("div", { className: "space-y-[14px]", children: inactiveActivations.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: receiptCounts !== null && !receiptCountsUntrustworthy ? (Object.hasOwn(receiptCounts, record.principleId) ? receiptCounts[record.principleId] : null) : undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId))) })] })), neverActivatedCount > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-never-activated", children: [_jsx(SectionTitle, { id: "section-never-activated", children: t("pages.activation.sectionNeverActivated") }), _jsx("div", { className: "space-y-[10px]", children: activations
|
|
390
441
|
.filter((a) => a.activatedAt === null)
|
|
391
442
|
.map((record) => (_jsxs("article", { className: "relative pl-[22px] py-[14px] pr-[18px] bg-panel border border-amber/20 border-l-[3px] border-l-amber rounded-[6px]", children: [_jsxs("div", { className: "text-ink-2 text-sm leading-relaxed", children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.activation.neverActivatedCard") }), " ", "\u2014 ", record.action, " \u00B7 ", getChannelLabel(record.channel, t), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), _jsxs(Link, { to: "/debt", className: "inline-flex items-center mt-2 text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: [t("pages.activation.viewDebt"), " \u2192"] })] }, record.activationId))) })] })), _jsx("footer", { className: "mt-12 pt-6 border-t border-line text-ink-3 text-[13px]", children: t("pages.activation.footer") })] }) }));
|
|
392
443
|
}
|
|
@@ -402,29 +402,84 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
|
|
|
402
402
|
? "border-green/40 bg-green/10 text-green"
|
|
403
403
|
: "border-line bg-surface/80 text-ink-3"}`, role: "status", "data-testid": `decided-banner-${group.principleId}`, children: decidedOutcome === "approved"
|
|
404
404
|
? t("pages.focus.decidedApproved", { defaultValue: "已批准 ✓ 正在写入生效记录…" })
|
|
405
|
-
: t("pages.focus.decidedRejected", { defaultValue: "已拒绝" }) })), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "inline-flex items-center border border-line rounded-[2px] px-[7px] py-1 font-mono text-[11px] text-ink-3 bg-surface/80 uppercase", children: channelLabel }), isReversible && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: primaryChannel === "prompt" ? t("pages.focus.tagReversible") : t("pages.focus.tagLowRisk") }))] }), _jsx("div", { className: "mt-[14px] mb-2 font-semibold text-ink leading-snug", "data-testid": `candidate-title-${group.principleId}`, children: readingLayout.title }), readingLayout.body !== null && (_jsx("div", { className: "mb-2 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": `candidate-body-${group.principleId}`, children: readingLayout.body })), group.artifactUnavailable === true && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `artifact-unavailable-${group.principleId}`, children: t("pages.focus.artifactUnavailableNote") })), unlinkedCandidateNote && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `unlinked-candidate-${group.principleId}`, children: t("pages.focus.unlinkedCandidateNote") })), _jsx("div", { className: "mt-2 px-3 py-2 bg-surface/60 border-l-2 border-gov text-ink-3 text-[13px] leading-snug", children: t("pages.focus.evidenceSummary", { count: group.records.length }) }), actionsLocked && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", "data-testid": `pending-actions-locked-${group.principleId}`, children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: actionsLockedReason }), _jsx(Link, { to: "/settings", "data-testid": `pending-actions-locked-settings-${group.principleId}`, className: "mt-2 inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.ownerDecision.goSettingsCta") })] })), decidedOutcome === null && primaryChannel === "prompt" && promptInjection?.truncated === true && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 px-3 py-2 text-[12.5px] text-amber", "data-testid": `approve-queue-badge-${group.principleId}`, children: [promptInjection.productionRotates === true && group.fitsPromptBudget === true
|
|
406
|
-
? t("pages.focus.
|
|
407
|
-
defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}}
|
|
405
|
+
: t("pages.focus.decidedRejected", { defaultValue: "已拒绝" }) })), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "inline-flex items-center border border-line rounded-[2px] px-[7px] py-1 font-mono text-[11px] text-ink-3 bg-surface/80 uppercase", children: channelLabel }), isReversible && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: primaryChannel === "prompt" ? t("pages.focus.tagReversible") : t("pages.focus.tagLowRisk") }))] }), _jsx("div", { className: "mt-[14px] mb-2 font-semibold text-ink leading-snug", "data-testid": `candidate-title-${group.principleId}`, children: readingLayout.title }), readingLayout.body !== null && (_jsx("div", { className: "mb-2 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": `candidate-body-${group.principleId}`, children: readingLayout.body })), group.artifactUnavailable === true && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `artifact-unavailable-${group.principleId}`, children: t("pages.focus.artifactUnavailableNote") })), unlinkedCandidateNote && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `unlinked-candidate-${group.principleId}`, children: t("pages.focus.unlinkedCandidateNote") })), _jsx("div", { className: "mt-2 px-3 py-2 bg-surface/60 border-l-2 border-gov text-ink-3 text-[13px] leading-snug", children: t("pages.focus.evidenceSummary", { count: group.records.length }) }), actionsLocked && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", "data-testid": `pending-actions-locked-${group.principleId}`, children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: actionsLockedReason }), _jsx(Link, { to: "/settings", "data-testid": `pending-actions-locked-settings-${group.principleId}`, className: "mt-2 inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.ownerDecision.goSettingsCta") })] })), decidedOutcome === null && primaryChannel === "prompt" && promptInjection?.truncated === true && promptInjection.capacityStatus !== "unconfirmed" && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 px-3 py-2 text-[12.5px] text-amber", "data-testid": `approve-queue-badge-${group.principleId}`, children: [promptInjection.productionRotates === true && group.fitsPromptBudget === true && group.promptBudgetTierFit === "model_dependent"
|
|
406
|
+
? t("pages.focus.approveQueueBadgeRotationModelDependent", {
|
|
407
|
+
defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}} 字符)。这条原则的篇幅在较小上下文模型的注入预算内装不下,轮到它时也未必进入提示词——是否生效取决于当时模型的上限。",
|
|
408
408
|
used: promptInjection.usedChars,
|
|
409
409
|
budget: promptInjection.budget,
|
|
410
410
|
})
|
|
411
|
-
: promptInjection.productionRotates === true
|
|
412
|
-
? t("pages.focus.
|
|
413
|
-
defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}}
|
|
411
|
+
: promptInjection.productionRotates === true && group.fitsPromptBudget === true
|
|
412
|
+
? t("pages.focus.approveQueueBadgeRotation", {
|
|
413
|
+
defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}} 字符)。当前按公平轮转选取,新原则会在后续轮次自行轮到,无需停用旧原则。",
|
|
414
414
|
used: promptInjection.usedChars,
|
|
415
415
|
budget: promptInjection.budget,
|
|
416
416
|
})
|
|
417
|
-
:
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
417
|
+
: promptInjection.productionRotates === true
|
|
418
|
+
? t("pages.focus.approveQueueBadgeOversized", {
|
|
419
|
+
defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}} 字符)。这条原则本身已超出注入位上限,轮转也无法让它进入提示词——需要先精简它的内容。",
|
|
420
|
+
used: promptInjection.usedChars,
|
|
421
|
+
budget: promptInjection.budget,
|
|
422
|
+
})
|
|
423
|
+
: t("pages.focus.approveQueueBadge", {
|
|
424
|
+
defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}} 字符)。",
|
|
425
|
+
used: promptInjection.usedChars,
|
|
426
|
+
budget: promptInjection.budget,
|
|
427
|
+
}), _jsxs("div", { className: "mt-1 text-ink-3 text-[11.5px]", "data-testid": `approve-queue-badge-scope-${group.principleId}`, children: [promptInjection.route === "shared_render"
|
|
422
428
|
? t("pages.focus.promptScopeShared")
|
|
423
429
|
: t("pages.focus.promptScopeList", {
|
|
424
430
|
full: promptInjection.fullRenderChars !== undefined
|
|
425
431
|
? t("pages.focus.promptScopeFullRender", { count: promptInjection.fullRenderChars })
|
|
426
432
|
: "",
|
|
427
|
-
}), promptInjection.hostKind !== undefined ? ` · ${promptInjection.hostKind === "openclaw" ? "OpenClaw" : promptInjection.hostKind === "workbuddy" ? "WorkBuddy" : "Codex"}` : ""
|
|
433
|
+
}), promptInjection.hostKind !== undefined ? ` · ${promptInjection.hostKind === "openclaw" ? "OpenClaw" : promptInjection.hostKind === "workbuddy" ? "WorkBuddy" : "Codex"}` : "", ` · ${
|
|
434
|
+
// A "confirmed" claim is only renderable when the window is
|
|
435
|
+
// present: a payload missing it must not print "0 tokens".
|
|
436
|
+
promptInjection.budgetCapacityStatus === "confirmed" && promptInjection.budgetContextWindowTokens !== undefined
|
|
437
|
+
? promptInjection.budgetObservedAt !== undefined
|
|
438
|
+
// PRI-1017: the budget comes from the workspace's most
|
|
439
|
+
// recent RUNTIME OBSERVATION (the last real injection) —
|
|
440
|
+
// say so, with source + window + observation time. Never
|
|
441
|
+
// present a past observation as a live confirmation.
|
|
442
|
+
? t("pages.focus.promptBudgetObservedNote", {
|
|
443
|
+
defaultValue: "预算取自最近一次运行时观测(来源 {{source}},上下文 {{window}} tokens,观测于 {{observedAt}})",
|
|
444
|
+
source: promptInjection.budgetCapacitySource === "pi_catalog_exact"
|
|
445
|
+
? t("pages.focus.budgetCapacitySourcePiCatalog", { defaultValue: "模型目录精确匹配" })
|
|
446
|
+
: t("pages.focus.budgetCapacitySourceHostWindow", { defaultValue: "宿主有效上下文窗口" }),
|
|
447
|
+
window: promptInjection.budgetContextWindowTokens,
|
|
448
|
+
observedAt: promptInjection.budgetObservedAt,
|
|
449
|
+
})
|
|
450
|
+
: t("pages.focus.promptBudgetModelAwareNote", {
|
|
451
|
+
defaultValue: "预算按已确认的模型上下文解析({{window}} tokens)",
|
|
452
|
+
window: promptInjection.budgetContextWindowTokens,
|
|
453
|
+
})
|
|
454
|
+
: promptInjection.budgetObservedAt !== undefined
|
|
455
|
+
// PRI-1017: a fallback that still carries an observation
|
|
456
|
+
// timestamp IS the runtime's own honest fallback (the last
|
|
457
|
+
// injection resolved 2000 with a reason). Saying "console
|
|
458
|
+
// not bound to the runtime model" here would be false — the
|
|
459
|
+
// console DID use the runtime's last observation.
|
|
460
|
+
? t("pages.focus.promptBudgetFallbackObservedNote", {
|
|
461
|
+
defaultValue: "运行时最近一次观测未确认宿主容量,预算按固定回退估算({{reason}},观测于 {{observedAt}})",
|
|
462
|
+
reason: promptInjection.budgetFallbackReason !== undefined
|
|
463
|
+
? t(`pages.focus.budgetFallbackReason.${promptInjection.budgetFallbackReason}`, {
|
|
464
|
+
defaultValue: promptInjection.budgetFallbackReason,
|
|
465
|
+
})
|
|
466
|
+
: "unknown",
|
|
467
|
+
observedAt: promptInjection.budgetObservedAt,
|
|
468
|
+
})
|
|
469
|
+
: t("pages.focus.promptBudgetFallbackNote", {
|
|
470
|
+
defaultValue: "按固定回退预算估算(控制台未绑定运行时模型{{reason}})",
|
|
471
|
+
reason: promptInjection.budgetFallbackReason !== undefined
|
|
472
|
+
? t("pages.focus.promptBudgetFallbackReasonSuffix", {
|
|
473
|
+
defaultValue: ",原因: {{code}}",
|
|
474
|
+
// The raw bounded code stays the default: it is the
|
|
475
|
+
// grep-able identifier shared with events/logs. Locales
|
|
476
|
+
// may override via pages.focus.budgetFallbackReason.<code>.
|
|
477
|
+
code: t(`pages.focus.budgetFallbackReason.${promptInjection.budgetFallbackReason}`, {
|
|
478
|
+
defaultValue: promptInjection.budgetFallbackReason,
|
|
479
|
+
}),
|
|
480
|
+
})
|
|
481
|
+
: "",
|
|
482
|
+
})}`] })] })), group.revisionReviewUnavailable === true && _jsx("p", { role: "alert", className: "mt-3 text-danger", children: t("pages.focus.revisionReviewUnavailable") }), group.revisionReview !== undefined && (_jsxs("div", { className: "mt-3 border border-line p-3 text-[12.5px]", "data-testid": `revision-intent-review-${group.principleId}`, children: [_jsx("p", { children: t("pages.focus.revisionIntentReview", { defaultValue: "修订复核:确认新正文保留触发条件、行动要求和必要例外,并与沿用意图一致。" }) }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.oldStatement }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.newStatement }), _jsx("dl", { className: "mt-2", children: Object.entries(group.revisionReview.intentFields).map(([key, value]) => _jsxs("div", { children: [_jsx("dt", { children: t(`pages.focus.intentField.${key}`, { defaultValue: key }) }), _jsx("dd", { children: value })] }, key)) }), _jsxs("label", { className: "mt-2 flex gap-2", children: [_jsx("input", { type: "checkbox", checked: intentReviewed, onChange: (event) => setIntentReviewed(event.target.checked) }), t("pages.focus.revisionIntentConfirmed", { defaultValue: "我已核对上述意图与新正文一致" })] })] })), _jsxs("div", { className: "flex gap-2 mt-4 flex-wrap items-center", children: [_jsx("button", { type: "button", onClick: handleApprove, disabled: decisionDisabled || (group.revisionReviewUnavailable === true || (group.revisionReview !== undefined && !intentReviewed)), "data-testid": `approve-btn-${group.principleId}`, className: "inline-flex items-center border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: actionLoading ? t("common.loading") + "…" : t("pages.focus.approveAction", { defaultValue: "批准" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput((v) => !v); setShowRejectInput(false); }, disabled: decisionDisabled, "data-testid": `edit-btn-${group.principleId}`, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.editAction", { defaultValue: "替换待审版本" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput((v) => !v); setShowEditInput(false); }, disabled: decisionDisabled, "data-testid": `reject-btn-${group.principleId}`, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.rejectAction", { defaultValue: "拒绝" }) }), _jsx(Link, { to: "/pain", className: "inline-flex items-center text-gov text-[12.5px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.viewFullChain") })] }), showRejectInput && (_jsxs("div", { className: "mt-3 p-3 border border-danger/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.rejectReasonLabel", { defaultValue: "拒绝原因(必填)" }) }), _jsx("textarea", { value: rejectReason, onChange: (e) => setRejectReason(e.target.value), "data-testid": `reject-reason-${group.principleId}`, placeholder: t("pages.focus.rejectReasonPlaceholder", { defaultValue: "请说明拒绝原因" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleReject, disabled: !rejectReason.trim() || actionLoading, "data-testid": `confirm-reject-${group.principleId}`, className: "inline-flex items-center border border-danger text-danger bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-danger/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: t("pages.focus.confirmReject", { defaultValue: "确认拒绝" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput(false); setRejectReason(""); }, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] })), showEditInput && (_jsxs("div", { className: "mt-3 p-3 border border-gov/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.editReasonLabel", { defaultValue: "替换原因(必填)" }) }), _jsxs("div", { className: "mb-2 text-ink-4 text-[12px] font-mono", children: [t("pages.focus.currentArtifactLabel", { defaultValue: "当前工件" }), ": ", currentArtifactId] }), _jsx("input", { type: "text", value: newArtifactId, onChange: (e) => setNewArtifactId(e.target.value), "data-testid": `edit-new-artifact-${group.principleId}`, placeholder: t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] mb-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", "aria-label": t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }) }), _jsx("textarea", { value: editReason, onChange: (e) => setEditReason(e.target.value), "data-testid": `edit-reason-${group.principleId}`, placeholder: t("pages.focus.editReasonPlaceholder", { defaultValue: "请说明为什么需要替换这份待审版本" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleEdit, disabled: !editReason.trim() || !newArtifactId.trim() || actionLoading, "data-testid": `confirm-edit-${group.principleId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: t("pages.focus.confirmEdit", { defaultValue: "确认替换" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput(false); setEditReason(""); setNewArtifactId(""); }, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] }))] }));
|
|
428
483
|
}
|
|
429
484
|
function StagnationSignalCard({ signal }) {
|
|
430
485
|
const { t } = useTranslation();
|
|
@@ -751,15 +806,26 @@ export function FocusPage({ featureFlags }) {
|
|
|
751
806
|
return null;
|
|
752
807
|
return (_jsxs("div", { className: "mb-4 rounded-[3px] border border-amber/40 bg-amber/5 px-3 py-2 text-[12.5px] leading-relaxed text-amber", "data-testid": "prompt-capacity-unconfirmed-banner", children: [_jsx("p", { children: t("pages.focus.promptCapacityUnconfirmed", {
|
|
753
808
|
defaultValue: "当前宿主容量未确认:本工作区适用的宿主会走不同的注入路由,以下数字未绑定具体宿主。",
|
|
754
|
-
}) }), _jsx("ul", { className: "mt-1 list-disc pl-5", children: (unconfirmed.perHost ?? []).map((entry) => (
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
809
|
+
}) }), _jsx("ul", { className: "mt-1 list-disc pl-5", children: (unconfirmed.perHost ?? []).map((entry) => (_jsxs("li", { "data-testid": `prompt-capacity-perhost-${entry.hostKind}`, children: [t("pages.focus.promptCapacityPerHostEntry", {
|
|
810
|
+
host: entry.hostKind === "openclaw" ? "OpenClaw" : entry.hostKind === "workbuddy" ? "WorkBuddy" : "Codex",
|
|
811
|
+
billing: entry.route === "shared_render"
|
|
812
|
+
? t("pages.focus.promptCapacitySharedRoute")
|
|
813
|
+
: t("pages.focus.promptCapacityListRoute"),
|
|
814
|
+
used: entry.usedChars,
|
|
815
|
+
// PRI-1017: each host shows ITS OWN budget basis (runtime
|
|
816
|
+
// observation or its own honest fallback) — never the
|
|
817
|
+
// shared headline number.
|
|
818
|
+
budget: entry.budget ?? unconfirmed.budget,
|
|
819
|
+
full: entry.truncated ? t("pages.focus.promptCapacityPerHostFull") : "",
|
|
820
|
+
observed: entry.budgetObservedAt !== undefined
|
|
821
|
+
? t("pages.focus.promptCapacityPerHostObserved", {
|
|
822
|
+
defaultValue: "(预算来自该宿主最近一次运行时观测,观测于 {{observedAt}})",
|
|
823
|
+
observedAt: entry.budgetObservedAt,
|
|
824
|
+
})
|
|
825
|
+
: "",
|
|
826
|
+
}), entry.budgetFallbackReason !== undefined && (_jsxs("span", { "data-testid": `prompt-capacity-perhost-reason-${entry.hostKind}`, children: [" · ", t(`pages.focus.budgetFallbackReason.${entry.budgetFallbackReason}`, {
|
|
827
|
+
defaultValue: entry.budgetFallbackReason,
|
|
828
|
+
})] }))] }, entry.hostKind))) }), unconfirmed.nextAction !== undefined && (_jsx("p", { className: "mt-1 text-ink-2", children: unconfirmed.nextAction })), _jsxs("div", { className: "mt-2 flex gap-2", children: [["openclaw", "codex", "workbuddy"].map((host) => (_jsx("button", { type: "button", onClick: () => setPromptTargetHost(host), "data-testid": `prompt-capacity-pick-${host}`, className: `inline-flex items-center border rounded-[3px] px-[10px] py-[4px] transition-colors ${promptTargetHost === host ? "border-amber bg-amber/10" : "border-line hover:border-line-2"}`, children: t("pages.focus.promptCapacityViewAsHost", { host: host === "openclaw" ? "OpenClaw" : host === "workbuddy" ? "WorkBuddy" : "Codex" }) }, host))), promptTargetHost !== null && (_jsx("button", { type: "button", onClick: () => setPromptTargetHost(null), "data-testid": "prompt-capacity-pick-clear", className: "inline-flex items-center border border-line rounded-[3px] px-[10px] py-[4px] hover:border-line-2", children: t("pages.focus.promptCapacityClearHost", { defaultValue: "清除选择" }) }))] })] }));
|
|
763
829
|
})(), groupedAvailable && pendingGroups.map((group) => (_jsx(PendingReviewCard, { group: group, actionsLockedReason: ownerActionsLockedReason ?? undefined, promptInjection: groupedData.promptInjection, promptTargetHost: promptTargetHost ?? undefined, onDecisionApplied: () => { void loadData(); } }, group.principleId)))] }), _jsxs("section", { "aria-label": t("pages.focus.ownerAttention.sectionTitle"), className: "mb-7", "data-testid": "owner-attention-section", children: [_jsxs("div", { className: "flex items-baseline gap-2 mb-3", children: [_jsx(SectionTitle, { children: t("pages.focus.ownerAttention.sectionTitle") }), ownerInbox !== null && ownerInboxError === null && (_jsx("span", { className: "font-mono text-ink-4 text-[12px]", "data-testid": "owner-attention-counts", children: `· ${t("pages.focus.ownerAttention.blockedCount", { count: ownerInbox.groups.blocked.length })} · ${t("pages.focus.ownerAttention.recoveryCount", { count: inboxRecovery.length })}` }))] }), ownerInboxError !== null && (_jsx("p", { className: "text-ink-4 text-[12.5px]", children: t("pages.focus.ownerInbox.loadError") })), ownerInbox !== null && ownerInboxError === null && (_jsxs(_Fragment, { children: [ownerInbox.groups.blocked.length === 0
|
|
764
830
|
&& inboxRecovery.length === 0
|
|
765
831
|
&& unmatchedInboxDecisions.length === 0 && (_jsx("p", { className: "text-ink-4 text-[13px]", children: t("pages.focus.ownerAttention.empty") })), unmatchedInboxDecisions.length > 0 && (_jsx("p", { className: "mb-2 text-ink-4 text-[12px] leading-relaxed", "data-testid": "owner-attention-unmatched-note", children: t("pages.focus.ownerAttention.unmatchedTitle") })), unmatchedInboxDecisions.map((item) => (_jsx(InboxItem, { item: item, t: t, note: t("pages.focus.ownerAttention.unmatchedItemNote") }, item.principleId))), inboxBlockedIndividual.map((item) => (_jsx(InboxItem, { item: item, t: t }, item.principleId))), inboxRecovery.map((item) => (_jsx(InboxItem, { item: item, t: t }, item.principleId))), inboxBlockedAggregate.length > 0 && (_jsxs("p", { className: "mt-2 text-ink-4 text-[12.5px] leading-relaxed", "data-testid": "owner-attention-aggregate-notice", children: [t("pages.focus.ownerAttention.blockedAggregate", { count: inboxBlockedAggregate.length }), " ", _jsx(Link, { to: "/principles", className: "text-gov hover:underline", children: t("pages.focus.ownerInbox.viewLibrary") })] })), ownerInbox.historicalUnknown.count > 0 && (_jsxs("p", { className: "text-ink-4 text-[12.5px] leading-relaxed mt-2", "data-testid": "owner-inbox-aggregate-notice", children: [ownerInbox.historicalUnknown.reasonText, " ", _jsx(Link, { to: "/principles", className: "text-gov hover:underline", children: t("pages.focus.ownerInbox.viewLibrary") })] }))] }))] }), experienceMode && experienceData !== null ? (_jsx(ExperienceSummaryCard, { snapshot: experienceData })) : !experienceMode ? (_jsxs("div", { className: "mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", children: [_jsx("div", { className: "flex items-center gap-2 mb-1", children: _jsx("span", { className: `inline-flex items-center rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase ${governanceState === "owner_review_ready" ? "bg-gov/10 text-gov border border-gov/20"
|
|
@@ -64,6 +64,17 @@ function validateApprovalGroup(raw) {
|
|
|
64
64
|
return null;
|
|
65
65
|
fitsPromptBudget = fits;
|
|
66
66
|
}
|
|
67
|
+
// SPEC-PD-MODEL-AWARE-PROMPT-BUDGET-001: promptBudgetTierFit is optional,
|
|
68
|
+
// whitelist-checked. model_dependent qualifies the rotation promise.
|
|
69
|
+
let promptBudgetTierFit;
|
|
70
|
+
if (Object.hasOwn(raw, "promptBudgetTierFit")) {
|
|
71
|
+
const { promptBudgetTierFit: tier } = raw;
|
|
72
|
+
if (tier !== "fits_all_tiers" && tier !== "model_dependent"
|
|
73
|
+
&& tier !== "exceeds_max_tier" && tier !== "unconfirmed") {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
promptBudgetTierFit = tier;
|
|
77
|
+
}
|
|
67
78
|
// PRI-940: artifactUnavailable is optional. ERR-009 discipline — present but
|
|
68
79
|
// wrong type fails loud (return null); absent stays undefined, which keeps
|
|
69
80
|
// the card title rendering exactly as before.
|
|
@@ -80,6 +91,7 @@ function validateApprovalGroup(raw) {
|
|
|
80
91
|
candidateDescription,
|
|
81
92
|
status,
|
|
82
93
|
fitsPromptBudget,
|
|
94
|
+
promptBudgetTierFit,
|
|
83
95
|
artifactUnavailable,
|
|
84
96
|
records: validRecords,
|
|
85
97
|
};
|