oh-my-opencode-cohub 1.12.13 → 1.13.0-beta.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.
Files changed (39) hide show
  1. package/README.md +1 -0
  2. package/dist/cli/index.js +115 -15
  3. package/dist/config/loader.d.ts +5 -16
  4. package/dist/config/loader.d.ts.map +1 -1
  5. package/dist/context/engine.d.ts +15 -1
  6. package/dist/context/engine.d.ts.map +1 -1
  7. package/dist/context/extractor.d.ts +8 -0
  8. package/dist/context/extractor.d.ts.map +1 -1
  9. package/dist/context/truncate.test.d.ts +2 -0
  10. package/dist/context/truncate.test.d.ts.map +1 -0
  11. package/dist/context/types.d.ts +2 -0
  12. package/dist/context/types.d.ts.map +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +924 -109
  15. package/dist/task-manager/quality.d.ts +51 -0
  16. package/dist/task-manager/quality.d.ts.map +1 -0
  17. package/dist/task-manager/quality.test.d.ts +2 -0
  18. package/dist/task-manager/quality.test.d.ts.map +1 -0
  19. package/dist/task-manager/stats.test.d.ts +2 -0
  20. package/dist/task-manager/stats.test.d.ts.map +1 -0
  21. package/dist/task-manager/tracker.d.ts +57 -6
  22. package/dist/task-manager/tracker.d.ts.map +1 -1
  23. package/dist/task-manager/types.d.ts +11 -0
  24. package/dist/task-manager/types.d.ts.map +1 -1
  25. package/dist/tools/adaptive-params.d.ts +63 -0
  26. package/dist/tools/adaptive-params.d.ts.map +1 -0
  27. package/dist/tools/adaptive-params.test.d.ts +2 -0
  28. package/dist/tools/adaptive-params.test.d.ts.map +1 -0
  29. package/dist/tools/council.d.ts +78 -1
  30. package/dist/tools/council.d.ts.map +1 -1
  31. package/dist/tools/council.test.d.ts +2 -0
  32. package/dist/tools/council.test.d.ts.map +1 -0
  33. package/dist/tools/model-stats.d.ts +56 -0
  34. package/dist/tools/model-stats.d.ts.map +1 -0
  35. package/dist/tools/model-stats.test.d.ts +2 -0
  36. package/dist/tools/model-stats.test.d.ts.map +1 -0
  37. package/dist/tui.d.ts.map +1 -1
  38. package/dist/tui.js +26 -5
  39. package/package.json +2 -2
@@ -0,0 +1,51 @@
1
+ export type FailureCategory = 'timeout' | 'empty' | 'error' | 'quality-low';
2
+ /** 质量回送配置 */
3
+ export interface QualityConfig {
4
+ /** 是否启用质量回送(默认开启;低分仅标记,不改变任务成败判定) */
5
+ enabled: boolean;
6
+ }
7
+ export declare const DEFAULT_QUALITY_CONFIG: QualityConfig;
8
+ /** 判定器输入(来自 captureResult 提取的数据) */
9
+ export interface QualityInput {
10
+ output: string;
11
+ exitCode?: number;
12
+ decisions: number;
13
+ timedOut?: boolean;
14
+ latencyMs?: number;
15
+ tokens?: {
16
+ input: number;
17
+ output: number;
18
+ };
19
+ }
20
+ /** 判定结果 */
21
+ export interface QualityResult {
22
+ score: number;
23
+ passed: boolean;
24
+ failureCategory?: FailureCategory;
25
+ latencyMs?: number;
26
+ tokens?: {
27
+ input: number;
28
+ output: number;
29
+ };
30
+ }
31
+ /**
32
+ * 输出文本是否命中错误关键词(P1-3 修复):
33
+ * - 高频英文词(error/failed/failure/exception)要求整词边界匹配,
34
+ * 排除成员访问(obj.error)与函数调用(new Error()形式的代码片段;
35
+ * - 否定短语出现在关键词前 N 字符内则跳过该次命中;
36
+ * - 中文与低频英文关键词保留子串匹配,同样受否定窗口保护。
37
+ */
38
+ export declare function hasErrorKeywords(text: string): boolean;
39
+ /**
40
+ * 质量判定(纯函数):
41
+ * - output 非空 +0.25
42
+ * - exit 正常(undefined 或 0)+0.25
43
+ * - 无错误关键词 +0.25
44
+ * - decisions ≥ 1 +0.25
45
+ * - 空输出视为无成果,score 直接归零(最低分,与 category 'empty' 呼应)
46
+ * 及格线 = 四项全过(score 1.0);低于 1.0 仅标记 failureCategory,不判任务失败。
47
+ */
48
+ export declare function assessQuality(input: QualityInput): QualityResult;
49
+ /** 是否启用质量回送(配置开关,默认开启) */
50
+ export declare function isQualityEnabled(config?: Partial<QualityConfig> | null): boolean;
51
+ //# sourceMappingURL=quality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../src/task-manager/quality.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC;AAE5E,aAAa;AACb,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,sBAAsB,EAAE,aAEpC,CAAC;AAEF,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,WAAW;AACX,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AA0CD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA0BtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAgChE;AAED,0BAA0B;AAC1B,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,GAAG,OAAO,CAEhF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=quality.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.test.d.ts","sourceRoot":"","sources":["../../src/task-manager/quality.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stats.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.test.d.ts","sourceRoot":"","sources":["../../src/task-manager/stats.test.ts"],"names":[],"mappings":""}
@@ -1,4 +1,41 @@
1
- import type { TaskStatus, TaskArgs } from './types';
1
+ import type { JobRecord, TaskStatus, TaskArgs } from './types';
2
+ import type { ContextStrategy } from '../context/types';
3
+ /** 统计窗口默认大小:最近 N 条任务 */
4
+ export declare const DEFAULT_STATS_WINDOW = 50;
5
+ /** 统计持久化文件(CLI stats 子命令读取同一路径) */
6
+ export declare const STATS_FILE: string;
7
+ /** 按代理推断默认上下文策略 */
8
+ export declare function defaultStrategyFor(agent: string): ContextStrategy;
9
+ /** 参与统计的指标记录(从 JobRecord 抽取) */
10
+ export interface StatsRecord {
11
+ agent: string;
12
+ strategy: string;
13
+ status: TaskStatus;
14
+ latencyMs?: number;
15
+ tokens?: {
16
+ input: number;
17
+ output: number;
18
+ };
19
+ }
20
+ /** 按 (strategy, agent) 聚合的统计桶 */
21
+ export interface StatsBucket {
22
+ strategy: string;
23
+ agent: string;
24
+ count: number;
25
+ successCount: number;
26
+ successRate: number;
27
+ avgLatencyMs: number;
28
+ latencySamples: number;
29
+ avgTokens: number;
30
+ tokenSamples: number;
31
+ }
32
+ /**
33
+ * 滑动窗口聚合统计(纯函数):
34
+ * - records 需按时间升序传入,仅取最近 window 条
35
+ * - 按 (strategy, agent) 分组,输出成功率 / 平均延迟 / 平均 token
36
+ * - 缺少 latencyMs / tokens 的样本不影响对应均值,仅不计入样本数
37
+ */
38
+ export declare function computeStats(records: StatsRecord[], window?: number): StatsBucket[];
2
39
  export declare class TaskTracker {
3
40
  private jobs;
4
41
  private counters;
@@ -43,11 +80,25 @@ export declare class TaskTracker {
43
80
  getRunningAgents(parentSessionId: string): string[];
44
81
  /** 获取父会话下所有运行中的任务数量 */
45
82
  getRunningCount(parentSessionId: string): number;
46
- /** 根据子 session ID 查找 JobRecord */
47
- getJobBySessionId(sessionId: string): {
48
- alias: string;
49
- agent: string;
50
- } | undefined;
83
+ /** 根据子 session ID 查找完整 JobRecord */
84
+ getJobBySessionId(sessionId: string): JobRecord | undefined;
85
+ /**
86
+ * 质量回送:把任务质量度量写回 JobRecord(负反馈闭环)
87
+ * 由 event hook 在 session.idle 时调用
88
+ */
89
+ updateQuality(sessionId: string, quality: NonNullable<JobRecord['quality']>): void;
90
+ /**
91
+ * 终态收尾:确保 latencyMs 已记录(质量回送缺失时用 createdAt 差值补录)。
92
+ * P2-2: 未判定时 quality.score 保持 undefined(语义≠质量最差),
93
+ * 仅 assessQuality 实际执行过(updateQuality 传入)才携带 score。
94
+ */
95
+ private finalize;
96
+ /** 收集全部终态任务为统计记录(按创建时间升序) */
97
+ private collectStatsRecords;
98
+ /** 当前统计(内存态,按 (strategy, agent) 聚合;window 为滑动窗口条数) */
99
+ getStats(window?: number): StatsBucket[];
100
+ /** 把最近 window 条统计记录持久化到 STATS_FILE,供 CLI stats 子命令读取 */
101
+ persistStats(window?: number): void;
51
102
  /** cancel_task 集成:根据别名或 sessionId 标记任务为已取消并 reconcile */
52
103
  markCancelled(taskId: string): void;
53
104
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/task-manager/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,QAAQ,CAA6B;IAC7C,yCAAyC;IACzC,OAAO,CAAC,uBAAuB,CAAM;IACrC,kDAAkD;IAClD,OAAO,CAAC,oBAAoB,CAAM;IAElC,IAAI,sBAAsB,IAAI,MAAM,CAEnC;IAED,mDAAmD;IACnD,OAAO,CAAC,KAAK;IAOb;;OAEG;IACH,kBAAkB,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM;IA8BnE;;;OAGG;IACH,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAyBtF;;;OAGG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IASnE;;OAEG;IACH,YAAY,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM;IA0E9C;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IASzC;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAKlC,2BAA2B;IAC3B,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE;IAUnD,uBAAuB;IACvB,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM;IAUhD,kCAAkC;IAClC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IASlF,yDAAyD;IACzD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAYpC"}
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/task-manager/tracker.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,17 @@ export interface JobRecord {
14
14
  contextStrategy?: ContextStrategy;
15
15
  /** 依赖的前置任务别名列表 */
16
16
  dependencies?: string[];
17
+ /** 任务质量回送(负反馈闭环,见 quality.ts);低分仅标记不改变成败判定 */
18
+ quality?: {
19
+ /** 0-1 质量评分;undefined 表示未执行 assessQuality(与 score:0 的"质量最差"语义区分) */
20
+ score?: number;
21
+ failureCategory?: 'timeout' | 'empty' | 'error' | 'quality-low';
22
+ latencyMs?: number;
23
+ tokens?: {
24
+ input: number;
25
+ output: number;
26
+ };
27
+ };
17
28
  }
18
29
  export interface TaskArgs {
19
30
  description?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/task-manager/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;AAE3E,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,kBAAkB;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/task-manager/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;AAE3E,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,kBAAkB;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,8CAA8C;IAC9C,OAAO,CAAC,EAAE;QACR,oEAAoE;QACpE,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,eAAe,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC;QAChE,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;KAC5C,CAAC;CACH;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
@@ -0,0 +1,63 @@
1
+ export interface AdaptiveParamsConfig {
2
+ /** 成功率高于该值(0-1)视为优秀,可降低参数(默认 0.8) */
3
+ highRate: number;
4
+ /** 成功率低于该值(0-1)视为偏弱,需提高参数(默认 0.5) */
5
+ lowRate: number;
6
+ /** 判定所需最小样本数:样本不足时不调整、用默认值(默认 5) */
7
+ minSamples: number;
8
+ /** 滞后窗口:同一方向需连续采样 N 次才生效一次(默认 5) */
9
+ hysteresisSamples: number;
10
+ /** retries 下限(默认 1) */
11
+ minRetries: number;
12
+ /** retries 上限(默认 5) */
13
+ maxRetries: number;
14
+ /** timeout 下限 ms(默认 60_000 = 60s) */
15
+ minTimeoutMs: number;
16
+ /** timeout 上限 ms(默认 300_000 = 300s) */
17
+ maxTimeoutMs: number;
18
+ /** 自适应起点 retries(默认 3) */
19
+ defaultRetries: number;
20
+ /** 自适应起点 timeout ms(默认 180_000 = 180s) */
21
+ defaultTimeoutMs: number;
22
+ /** timeout 每档步长 ms(默认 30_000 = 30s) */
23
+ timeoutStepMs: number;
24
+ /** 滑动窗口大小:每个键保留最近 N 条样本(默认 20) */
25
+ windowSize: number;
26
+ }
27
+ export declare const DEFAULT_ADAPTIVE_CONFIG: AdaptiveParamsConfig;
28
+ /** 当前生效的自适应参数 */
29
+ export interface AdaptiveParams {
30
+ retries: number;
31
+ timeoutMs: number;
32
+ }
33
+ /** 调整方向:-1 降参 / 0 不变 / +1 升参 */
34
+ export type AdjustmentDirection = -1 | 0 | 1;
35
+ /** 读取当前配置(返回副本,避免外部篡改) */
36
+ export declare function getAdaptiveParamsConfig(): AdaptiveParamsConfig;
37
+ /** 部分更新配置(未提供的字段保持原值) */
38
+ export declare function configureAdaptiveParams(partial: Partial<AdaptiveParamsConfig>): void;
39
+ /** 清空全部采样历史(测试与运行时重置用) */
40
+ export declare function resetAdaptiveParams(): void;
41
+ /**
42
+ * 根据成功率与样本数判定调整方向(纯函数):
43
+ * - 样本不足 minSamples → 0(未知,不调整,用默认值)
44
+ * - 成功率 > highRate → -1(降参)
45
+ * - 成功率 < lowRate → +1(升参)
46
+ * - 中间区间(含恰等于阈值)→ 0(不调整,避免边界抖动)
47
+ */
48
+ export declare function evaluateAdjustment(successRate: number, sampleCount: number, cfg?: AdaptiveParamsConfig): AdjustmentDirection;
49
+ /** 参数限幅(纯函数):retries ∈ [minRetries, maxRetries],timeout ∈ [minTimeoutMs, maxTimeoutMs] */
50
+ export declare function clampAdaptiveParams(params: AdaptiveParams, cfg?: AdaptiveParamsConfig): AdaptiveParams;
51
+ /** 按方向调整一档参数(纯函数):-1 降、+1 升、0 不变,调整后限幅 */
52
+ export declare function adjustAdaptiveParams(current: AdaptiveParams, direction: AdjustmentDirection, cfg?: AdaptiveParamsConfig): AdaptiveParams;
53
+ /**
54
+ * 记录一次采样结果并推进滞后状态机:
55
+ * - key 形如 "strategy\u0000agent"(与 tracker computeStats 的键一致)
56
+ * - 样本不足 minSamples 时仅积累样本、不推进滞后状态(参数保持默认)
57
+ * - 样本足够后按滑动窗口成功率判定方向;方向与上次相同则 streak+1,否则重置为 1
58
+ * - streak 达到 hysteresisSamples 时生效一次调整,随后清零重新累计
59
+ */
60
+ export declare function recordAdaptiveSample(key: string, success: boolean, cfg?: AdaptiveParamsConfig): void;
61
+ /** 查询当前生效的自适应参数(无历史时返回默认值) */
62
+ export declare function getAdaptiveParams(key: string, cfg?: AdaptiveParamsConfig): AdaptiveParams;
63
+ //# sourceMappingURL=adaptive-params.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive-params.d.ts","sourceRoot":"","sources":["../../src/tools/adaptive-params.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,oBAAoB;IACnC,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,uBAAuB,EAAE,oBAarC,CAAC;AAEF,iBAAiB;AACjB,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gCAAgC;AAChC,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAsB7C,0BAA0B;AAC1B,wBAAgB,uBAAuB,IAAI,oBAAoB,CAE9D;AAED,yBAAyB;AACzB,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAEpF;AAED,0BAA0B;AAC1B,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,oBAA6B,GACjC,mBAAmB,CAKrB;AAED,0FAA0F;AAC1F,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,oBAA6B,GACjC,cAAc,CAKhB;AAED,0CAA0C;AAC1C,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,mBAAmB,EAC9B,GAAG,GAAE,oBAA6B,GACjC,cAAc,CAShB;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,EAChB,GAAG,GAAE,oBAA6B,GACjC,IAAI,CAiCN;AAED,8BAA8B;AAC9B,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,oBAA6B,GAAG,cAAc,CAIjG"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adaptive-params.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive-params.test.d.ts","sourceRoot":"","sources":["../../src/tools/adaptive-params.test.ts"],"names":[],"mappings":""}
@@ -1,6 +1,7 @@
1
1
  import { tool } from '@opencode-ai/plugin';
2
2
  import type { PluginInput } from '@opencode-ai/plugin';
3
3
  import type { createOpencodeClient } from '@opencode-ai/sdk';
4
+ import type { FailureCategory } from '../task-manager/quality.js';
4
5
  export interface CouncillorConfig {
5
6
  /** "provider/model" */
6
7
  model: string;
@@ -21,8 +22,16 @@ export interface CouncilConfig {
21
22
  default_preset?: string;
22
23
  /** Execution mode (default: "parallel") */
23
24
  councillor_execution_mode?: 'parallel' | 'serial';
24
- /** Retries on empty response (default: 3) */
25
+ /** Retry budget for empty responses (default: 3) */
25
26
  councillor_retries?: number;
27
+ /** Consensus agreement threshold 0-1 for convergence (default: 0.6) */
28
+ consensus_threshold?: number;
29
+ /** Hard cap on serial rounds (default: 2) */
30
+ max_rounds?: number;
31
+ /** Global retry budget shared by all councillors (default: 6) */
32
+ max_total_retries?: number;
33
+ /** Global elapsed budget for a whole council run in ms (default: 3 * timeout) */
34
+ max_elapsed_ms?: number;
26
35
  }
27
36
  /** Internal councillor result shape */
28
37
  interface CouncillorResult {
@@ -31,6 +40,72 @@ interface CouncillorResult {
31
40
  status: string;
32
41
  result?: string;
33
42
  error?: string;
43
+ /** Optional structured summary used for consensus detection */
44
+ summary?: CouncillorSummary;
45
+ }
46
+ /** Structured summary extracted from a councillor response (T3) */
47
+ export interface CouncillorSummary {
48
+ conclusions: string[];
49
+ entities: string[];
50
+ }
51
+ /** Consensus detection input */
52
+ export interface ConsensusInput {
53
+ name: string;
54
+ summary: CouncillorSummary;
55
+ }
56
+ /** Consensus detection result */
57
+ export interface ConsensusResult {
58
+ consensus: boolean;
59
+ agreementScores: Record<string, number>;
60
+ averageAgreement: number;
61
+ }
62
+ /** Retry decision outcome (T2 decision table) */
63
+ export type RetryAction = 'retry' | 'needs-human' | 'give-up' | 'budget-exhausted';
64
+ /** Per-category retry limits (empty keeps the legacy councillor_retries default) */
65
+ export declare const RETRY_LIMITS: Record<FailureCategory, number>;
66
+ /** Map an error message to a failure category. */
67
+ export declare function classifyFailure(message: string): FailureCategory;
68
+ /**
69
+ * Heuristically extract a structured summary (conclusion sentences + key
70
+ * entity/decision sentences) from a councillor response text.
71
+ */
72
+ export declare function extractCouncillorSummary(text: string): CouncillorSummary;
73
+ /**
74
+ * Pairwise agreement between two summaries: 0.5 * conclusion overlap
75
+ * + 0.5 * entity overlap (Jaccard on tokens).
76
+ */
77
+ export declare function pairwiseAgreement(a: CouncillorSummary, b: CouncillorSummary): number;
78
+ /**
79
+ * Compute consensus across councillor summaries.
80
+ * Converged when >= ceil(2n/3) councillors have an average pairwise
81
+ * agreement at or above the threshold.
82
+ */
83
+ export declare function computeConsensus(inputs: ConsensusInput[], threshold: number): ConsensusResult;
84
+ /**
85
+ * T2 retry decision table.
86
+ * - consecutiveStreak >= 2 of the same category -> needs-human
87
+ * - per-category retry limit reached -> give-up
88
+ * - shared budget exhausted -> budget-exhausted
89
+ * - otherwise -> retry
90
+ */
91
+ export declare function decideRetryAction(category: FailureCategory, consecutiveStreak: number, categoryRetriesUsed: number, budgetAvailable: boolean, categoryLimit?: number): RetryAction;
92
+ /** Downgrade a variant one step ("max" -> "high" -> "medium" -> "low" -> undefined). */
93
+ export declare function downgradeVariant(variant?: string): string | undefined;
94
+ /** Append retry guidance to the prompt based on the failure category. */
95
+ export declare function appendRetryContext(prompt: string, category: FailureCategory): string;
96
+ /**
97
+ * Shared retry budget (T4): a total retry counter plus an elapsed-time cap.
98
+ * Both runCouncillorWithRetry retries and serial extra rounds draw from it.
99
+ */
100
+ export declare class RetryBudget {
101
+ retriesLeft: number;
102
+ readonly maxElapsedMs: number;
103
+ readonly startedAt: number;
104
+ constructor(maxTotalRetries: number, maxElapsedMs: number, startedAt?: number);
105
+ elapsedMs(): number;
106
+ expired(): boolean;
107
+ /** Consume one retry slot; returns false when exhausted or expired. */
108
+ consumeRetry(): boolean;
34
109
  }
35
110
  export declare class CouncilManager {
36
111
  private client;
@@ -46,6 +121,8 @@ export declare class CouncilManager {
46
121
  result?: string;
47
122
  error?: string;
48
123
  councillorResults: CouncillorResult[];
124
+ consensus?: boolean;
125
+ agreement?: number;
49
126
  }>;
50
127
  private runCouncillors;
51
128
  private runCouncillorWithRetry;
@@ -1 +1 @@
1
- {"version":3,"file":"council.d.ts","sourceRoot":"","sources":["../../src/tools/council.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAW7D,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,cAAc,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2CAA2C;IAC3C,yBAAyB,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IAClD,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,uCAAuC;AACvC,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA+OD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAgB;gBAG5B,MAAM,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,EAC/C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa;IAOvB;;;OAGG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;KACvC,CAAC;YA2DY,cAAc;YA8Cd,sBAAsB;YAkDtB,eAAe;CAgF9B;AAMD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,cAAc,EAAE,cAAc,GAC7B,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAyDzC"}
1
+ {"version":3,"file":"council.d.ts","sourceRoot":"","sources":["../../src/tools/council.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=council.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"council.test.d.ts","sourceRoot":"","sources":["../../src/tools/council.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,56 @@
1
+ import type { FailureCategory } from '../task-manager/quality.js';
2
+ /** 每次尝试的结果分类:成功或某一类失败 */
3
+ export type ModelResultCategory = FailureCategory | 'success';
4
+ /** T7 可配置参数 */
5
+ export interface ModelStatsConfig {
6
+ /** 滑动窗口大小:每个 model 保留最近 N 次尝试(默认 20) */
7
+ windowSize: number;
8
+ /** 高失败率阈值:失败率 > 该值视为高风险(默认 0.5,即 50%) */
9
+ highFailureRate: number;
10
+ /** 判定高风险所需的最小样本数(默认 5) */
11
+ minSamples: number;
12
+ }
13
+ export declare const DEFAULT_MODEL_STATS_CONFIG: ModelStatsConfig;
14
+ /** 单个 model 的统计快照 */
15
+ export interface ModelStats {
16
+ model: string;
17
+ total: number;
18
+ successes: number;
19
+ failures: number;
20
+ empty: number;
21
+ timeout: number;
22
+ error: number;
23
+ qualityLow: number;
24
+ /** 失败率 = failures / total(无样本时为 0) */
25
+ failureRate: number;
26
+ /** 成功率 = successes / total(无样本时为 1,未知模型默认信任) */
27
+ successRate: number;
28
+ }
29
+ /** 读取当前配置(返回副本,避免外部篡改) */
30
+ export declare function getModelStatsConfig(): ModelStatsConfig;
31
+ /** 部分更新配置(未提供的字段保持原值) */
32
+ export declare function configureModelStats(partial: Partial<ModelStatsConfig>): void;
33
+ /** 清空全部历史(测试与运行时重置用) */
34
+ export declare function resetModelStats(): void;
35
+ /** 记录一次尝试结果到滑动窗口,超出窗口大小自动丢弃最旧记录 */
36
+ export declare function recordModelResult(model: string, category: ModelResultCategory): void;
37
+ /** 查询单模型统计(无历史时返回全零快照) */
38
+ export declare function getModelStats(model: string): ModelStats;
39
+ /** 按失败率升序返回全部有历史记录的模型及其统计 */
40
+ export declare function getSortedModels(): Array<{
41
+ model: string;
42
+ stats: ModelStats;
43
+ }>;
44
+ /**
45
+ * 按失败率升序排序 councillor 条目(成功率高的优先),并做软剔除:
46
+ * - 失败率 > highFailureRate 且样本 ≥ minSamples 的模型为高风险;
47
+ * - 存在替代模型(剔除后仍有条目)时跳过高风险模型;
48
+ * - 全部为高风险(无替代)时回退到完整列表,不硬剔除;
49
+ * - 排序使用稳定 sort,同失败率保持原顺序。
50
+ *
51
+ * statsProvider 与 cfg 可注入以便测试,默认使用模块级存储与配置。
52
+ */
53
+ export declare function orderCouncillorsByFailure<T extends {
54
+ model: string;
55
+ }>(entries: Array<[string, T]>, statsProvider?: (model: string) => ModelStats, cfg?: ModelStatsConfig): Array<[string, T]>;
56
+ //# sourceMappingURL=model-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-stats.d.ts","sourceRoot":"","sources":["../../src/tools/model-stats.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,yBAAyB;AACzB,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,SAAS,CAAC;AAE9D,eAAe;AACf,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,eAAe,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,0BAA0B,EAAE,gBAIxC,CAAC;AAEF,qBAAqB;AACrB,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;CACrB;AAWD,0BAA0B;AAC1B,wBAAgB,mBAAmB,IAAI,gBAAgB,CAEtD;AAED,yBAAyB;AACzB,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAE5E;AAED,wBAAwB;AACxB,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAMD,mCAAmC;AACnC,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAOpF;AAED,0BAA0B;AAC1B,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAkCvD;AAED,6BAA6B;AAC7B,wBAAgB,eAAe,IAAI,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC,CAI7E;AAMD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EACnE,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAC3B,aAAa,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAA0B,EAC5D,GAAG,GAAE,gBAAyB,GAC7B,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAapB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=model-stats.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-stats.test.d.ts","sourceRoot":"","sources":["../../src/tools/model-stats.test.ts"],"names":[],"mappings":""}
package/dist/tui.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AA+E/D,QAAA,MAAM,MAAM,EAAE,eA2Gb,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AA+E/D,QAAA,MAAM,MAAM,EAAE,eAqIb,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/tui.js CHANGED
@@ -137,11 +137,31 @@ var plugin = {
137
137
  const theme = api.theme.current;
138
138
  let spinnerIndex = 0;
139
139
  let state = readState();
140
- const timer = setInterval(() => {
141
- state = readState();
142
- spinnerIndex = (spinnerIndex + 1) % SPINNER_FRAMES.length;
140
+ const POLL_INTERVALS = [250, 1000, 2000, 5000];
141
+ let pollStep = 0;
142
+ let lastEventAt = 0;
143
+ let lastSnapshot = JSON.stringify(state);
144
+ let timer;
145
+ const pollTick = () => {
146
+ const nextState = readState();
147
+ const snapshot = JSON.stringify(nextState);
148
+ if (snapshot !== lastSnapshot) {
149
+ lastSnapshot = snapshot;
150
+ lastEventAt = Date.now();
151
+ pollStep = 0;
152
+ } else {
153
+ pollStep = Math.min(pollStep + 1, POLL_INTERVALS.length - 1);
154
+ }
155
+ state = nextState;
143
156
  api.renderer.requestRender();
144
- }, 250);
157
+ timer = setTimeout(pollTick, POLL_INTERVALS[pollStep]);
158
+ };
159
+ timer = setTimeout(pollTick, POLL_INTERVALS[0]);
160
+ const spinnerTimer = setInterval(() => {
161
+ spinnerIndex = (spinnerIndex + 1) % SPINNER_FRAMES.length;
162
+ if (state && state.runningCount > 0)
163
+ api.renderer.requestRender();
164
+ }, 100);
145
165
  api.slots.register({
146
166
  order: 800,
147
167
  slots: {
@@ -220,7 +240,8 @@ var plugin = {
220
240
  }
221
241
  });
222
242
  api.lifecycle.onDispose(() => {
223
- clearInterval(timer);
243
+ clearTimeout(timer);
244
+ clearInterval(spinnerTimer);
224
245
  });
225
246
  }
226
247
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode-cohub",
3
- "version": "1.12.13",
3
+ "version": "1.13.0-beta.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Mr-cjf/oh-my-opencode-cohub.git"
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "scripts": {
29
29
  "build": "bun run scripts/generate-prompts.ts && bun build src/index.ts src/tui.ts --outdir dist --target node --format esm --external @opencode-ai/plugin --external @opencode-ai/plugin/* --external @opencode-ai/sdk --external @opencode-ai/sdk/* --external @opentui/core --external @opentui/solid --external zod && bun build src/cli/index.ts --outdir dist/cli --target node --format esm && tsc --emitDeclarationOnly",
30
- "test": "bun test",
30
+ "test": "bun test ./src",
31
31
  "prepublishOnly": "npm run build"
32
32
  },
33
33
  "keywords": [