@winspan/claude-forge 0.7.3 → 0.7.5

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 (130) hide show
  1. package/dist/ai-gateway/index.d.ts +3 -0
  2. package/dist/ai-gateway/index.d.ts.map +1 -1
  3. package/dist/ai-gateway/index.js +41 -11
  4. package/dist/ai-gateway/index.js.map +1 -1
  5. package/dist/ai-gateway/model-selector.d.ts +12 -0
  6. package/dist/ai-gateway/model-selector.d.ts.map +1 -1
  7. package/dist/ai-gateway/model-selector.js +20 -0
  8. package/dist/ai-gateway/model-selector.js.map +1 -1
  9. package/dist/ai-gateway/rate-limiter.d.ts +17 -4
  10. package/dist/ai-gateway/rate-limiter.d.ts.map +1 -1
  11. package/dist/ai-gateway/rate-limiter.js +60 -22
  12. package/dist/ai-gateway/rate-limiter.js.map +1 -1
  13. package/dist/ai-gateway/response-cache.d.ts +8 -3
  14. package/dist/ai-gateway/response-cache.d.ts.map +1 -1
  15. package/dist/ai-gateway/response-cache.js +37 -5
  16. package/dist/ai-gateway/response-cache.js.map +1 -1
  17. package/dist/autopilot/task-completion-detector.d.ts +32 -0
  18. package/dist/autopilot/task-completion-detector.d.ts.map +1 -0
  19. package/dist/autopilot/task-completion-detector.js +103 -0
  20. package/dist/autopilot/task-completion-detector.js.map +1 -0
  21. package/dist/daemon/handlers/context-builder.d.ts +8 -7
  22. package/dist/daemon/handlers/context-builder.d.ts.map +1 -1
  23. package/dist/daemon/handlers/context-builder.js +16 -20
  24. package/dist/daemon/handlers/context-builder.js.map +1 -1
  25. package/dist/daemon/handlers/orchestration-context.d.ts +6 -9
  26. package/dist/daemon/handlers/orchestration-context.d.ts.map +1 -1
  27. package/dist/daemon/handlers/stages/01-failure-signal.d.ts +1 -0
  28. package/dist/daemon/handlers/stages/01-failure-signal.d.ts.map +1 -1
  29. package/dist/daemon/handlers/stages/01-failure-signal.js +2 -2
  30. package/dist/daemon/handlers/stages/01-failure-signal.js.map +1 -1
  31. package/dist/daemon/handlers/stages/02-active-intervention.d.ts +1 -0
  32. package/dist/daemon/handlers/stages/02-active-intervention.d.ts.map +1 -1
  33. package/dist/daemon/handlers/stages/02-active-intervention.js +1 -0
  34. package/dist/daemon/handlers/stages/02-active-intervention.js.map +1 -1
  35. package/dist/daemon/handlers/stages/03-init-prompt.d.ts +1 -0
  36. package/dist/daemon/handlers/stages/03-init-prompt.d.ts.map +1 -1
  37. package/dist/daemon/handlers/stages/03-init-prompt.js +2 -2
  38. package/dist/daemon/handlers/stages/03-init-prompt.js.map +1 -1
  39. package/dist/daemon/handlers/stages/04-skill-suggestions.d.ts +1 -0
  40. package/dist/daemon/handlers/stages/04-skill-suggestions.d.ts.map +1 -1
  41. package/dist/daemon/handlers/stages/04-skill-suggestions.js +2 -1
  42. package/dist/daemon/handlers/stages/04-skill-suggestions.js.map +1 -1
  43. package/dist/daemon/handlers/stages/05-conv-config.d.ts +1 -0
  44. package/dist/daemon/handlers/stages/05-conv-config.d.ts.map +1 -1
  45. package/dist/daemon/handlers/stages/05-conv-config.js +1 -0
  46. package/dist/daemon/handlers/stages/05-conv-config.js.map +1 -1
  47. package/dist/daemon/handlers/stages/06-engine-check.d.ts +1 -0
  48. package/dist/daemon/handlers/stages/06-engine-check.d.ts.map +1 -1
  49. package/dist/daemon/handlers/stages/06-engine-check.js +1 -0
  50. package/dist/daemon/handlers/stages/06-engine-check.js.map +1 -1
  51. package/dist/daemon/handlers/stages/07-pipeline-reply.d.ts +1 -0
  52. package/dist/daemon/handlers/stages/07-pipeline-reply.d.ts.map +1 -1
  53. package/dist/daemon/handlers/stages/07-pipeline-reply.js +1 -2
  54. package/dist/daemon/handlers/stages/07-pipeline-reply.js.map +1 -1
  55. package/dist/daemon/handlers/stages/08-esc-interrupt.d.ts +1 -0
  56. package/dist/daemon/handlers/stages/08-esc-interrupt.d.ts.map +1 -1
  57. package/dist/daemon/handlers/stages/08-esc-interrupt.js +1 -0
  58. package/dist/daemon/handlers/stages/08-esc-interrupt.js.map +1 -1
  59. package/dist/daemon/handlers/stages/09-pipeline-active.d.ts +1 -0
  60. package/dist/daemon/handlers/stages/09-pipeline-active.d.ts.map +1 -1
  61. package/dist/daemon/handlers/stages/09-pipeline-active.js +1 -0
  62. package/dist/daemon/handlers/stages/09-pipeline-active.js.map +1 -1
  63. package/dist/daemon/handlers/stages/10-cooldown.d.ts +1 -1
  64. package/dist/daemon/handlers/stages/10-cooldown.d.ts.map +1 -1
  65. package/dist/daemon/handlers/stages/10-cooldown.js +1 -39
  66. package/dist/daemon/handlers/stages/10-cooldown.js.map +1 -1
  67. package/dist/daemon/handlers/stages/11-intent-analysis.d.ts +1 -0
  68. package/dist/daemon/handlers/stages/11-intent-analysis.d.ts.map +1 -1
  69. package/dist/daemon/handlers/stages/11-intent-analysis.js +4 -3
  70. package/dist/daemon/handlers/stages/11-intent-analysis.js.map +1 -1
  71. package/dist/daemon/handlers/stages/12-strategy-advice.d.ts +1 -0
  72. package/dist/daemon/handlers/stages/12-strategy-advice.d.ts.map +1 -1
  73. package/dist/daemon/handlers/stages/12-strategy-advice.js +1 -0
  74. package/dist/daemon/handlers/stages/12-strategy-advice.js.map +1 -1
  75. package/dist/daemon/handlers/stages/13-template-route.d.ts +1 -0
  76. package/dist/daemon/handlers/stages/13-template-route.d.ts.map +1 -1
  77. package/dist/daemon/handlers/stages/13-template-route.js +1 -0
  78. package/dist/daemon/handlers/stages/13-template-route.js.map +1 -1
  79. package/dist/daemon/handlers/stages/14-plan-resume.d.ts +1 -0
  80. package/dist/daemon/handlers/stages/14-plan-resume.d.ts.map +1 -1
  81. package/dist/daemon/handlers/stages/14-plan-resume.js +1 -0
  82. package/dist/daemon/handlers/stages/14-plan-resume.js.map +1 -1
  83. package/dist/daemon/handlers/stages/15-plan-enforcement.d.ts +1 -0
  84. package/dist/daemon/handlers/stages/15-plan-enforcement.d.ts.map +1 -1
  85. package/dist/daemon/handlers/stages/15-plan-enforcement.js +1 -0
  86. package/dist/daemon/handlers/stages/15-plan-enforcement.js.map +1 -1
  87. package/dist/daemon/handlers/stages/16-intervention-level.d.ts +1 -0
  88. package/dist/daemon/handlers/stages/16-intervention-level.d.ts.map +1 -1
  89. package/dist/daemon/handlers/stages/16-intervention-level.js +1 -0
  90. package/dist/daemon/handlers/stages/16-intervention-level.js.map +1 -1
  91. package/dist/daemon/handlers/stages/17-simple-task.d.ts +1 -0
  92. package/dist/daemon/handlers/stages/17-simple-task.d.ts.map +1 -1
  93. package/dist/daemon/handlers/stages/17-simple-task.js +2 -1
  94. package/dist/daemon/handlers/stages/17-simple-task.js.map +1 -1
  95. package/dist/daemon/handlers/stages/18-complex-task.d.ts +1 -0
  96. package/dist/daemon/handlers/stages/18-complex-task.d.ts.map +1 -1
  97. package/dist/daemon/handlers/stages/18-complex-task.js +4 -4
  98. package/dist/daemon/handlers/stages/18-complex-task.js.map +1 -1
  99. package/dist/daemon/handlers/stages/19-moderate-task.d.ts +1 -0
  100. package/dist/daemon/handlers/stages/19-moderate-task.d.ts.map +1 -1
  101. package/dist/daemon/handlers/stages/19-moderate-task.js +3 -2
  102. package/dist/daemon/handlers/stages/19-moderate-task.js.map +1 -1
  103. package/dist/daemon/handlers/stages/stage-interface.d.ts +3 -0
  104. package/dist/daemon/handlers/stages/stage-interface.d.ts.map +1 -1
  105. package/dist/daemon/handlers/stages/stage-scheduler.d.ts +27 -0
  106. package/dist/daemon/handlers/stages/stage-scheduler.d.ts.map +1 -0
  107. package/dist/daemon/handlers/stages/stage-scheduler.js +105 -0
  108. package/dist/daemon/handlers/stages/stage-scheduler.js.map +1 -0
  109. package/dist/daemon/handlers/user-prompt-handler.d.ts +3 -12
  110. package/dist/daemon/handlers/user-prompt-handler.d.ts.map +1 -1
  111. package/dist/daemon/handlers/user-prompt-handler.js +73 -141
  112. package/dist/daemon/handlers/user-prompt-handler.js.map +1 -1
  113. package/dist/pipeline/analyzer.d.ts +2 -0
  114. package/dist/pipeline/analyzer.d.ts.map +1 -1
  115. package/dist/pipeline/analyzer.js +16 -2
  116. package/dist/pipeline/analyzer.js.map +1 -1
  117. package/dist/pipeline/index.d.ts +4 -5
  118. package/dist/pipeline/index.d.ts.map +1 -1
  119. package/dist/pipeline/index.js +49 -28
  120. package/dist/pipeline/index.js.map +1 -1
  121. package/dist/pipeline/phase-manager.d.ts +26 -1
  122. package/dist/pipeline/phase-manager.d.ts.map +1 -1
  123. package/dist/pipeline/phase-manager.js +84 -4
  124. package/dist/pipeline/phase-manager.js.map +1 -1
  125. package/dist/pipeline/store.js +3 -3
  126. package/dist/pipeline/store.js.map +1 -1
  127. package/dist/utils/claude-api.d.ts.map +1 -1
  128. package/dist/utils/claude-api.js +4 -2
  129. package/dist/utils/claude-api.js.map +1 -1
  130. package/package.json +1 -1
@@ -25,6 +25,9 @@ export declare class AIGateway implements AIProvider {
25
25
  private noCacheLabels;
26
26
  private modelSelector;
27
27
  private cacheTtlMs;
28
+ private maxConcurrent;
29
+ private degradationCount;
30
+ private totalCompletions;
28
31
  constructor(inner: AIProvider, opts?: GatewayOptions);
29
32
  complete(prompt: string, label?: string, options?: CompletionOptions): Promise<string>;
30
33
  getStats(): Readonly<import("../ai-provider/types.js").ApiCallStats>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAO7E,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,kCAAkC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0BAA0B;IAC1B,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAOD;;;GAGG;AACH,qBAAa,SAAU,YAAW,UAAU;IAO9B,OAAO,CAAC,KAAK;IANzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,UAAU,CAAS;gBAEP,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,cAAmB;IAW1D,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IA2C5F,QAAQ;IAIR,WAAW,IAAI,MAAM;CAMtB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAO7E,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,kCAAkC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0BAA0B;IAC1B,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAOD;;;GAGG;AACH,qBAAa,SAAU,YAAW,UAAU;IAU9B,OAAO,CAAC,KAAK;IATzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,gBAAgB,CAAK;gBAET,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,cAAmB;IAY1D,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAoE5F,QAAQ;IAIR,WAAW,IAAI,MAAM;CAStB"}
@@ -18,9 +18,13 @@ export class AIGateway {
18
18
  noCacheLabels;
19
19
  modelSelector;
20
20
  cacheTtlMs;
21
+ maxConcurrent;
22
+ degradationCount = 0;
23
+ totalCompletions = 0;
21
24
  constructor(inner, opts = {}) {
22
25
  this.inner = inner;
23
- this.rateLimiter = new RateLimiter(opts.maxConcurrent ?? 3, opts.minIntervalMs ?? 200);
26
+ this.maxConcurrent = opts.maxConcurrent ?? 3;
27
+ this.rateLimiter = new RateLimiter(this.maxConcurrent, opts.minIntervalMs ?? 200);
24
28
  this.cache = new ResponseCache();
25
29
  this.cacheTtlMs = opts.cacheTtlMs ?? 300_000;
26
30
  this.noCacheLabels = new Set([
@@ -32,7 +36,7 @@ export class AIGateway {
32
36
  async complete(prompt, label, options) {
33
37
  // 可缓存的调用先查缓存
34
38
  const cacheable = label ? !this.noCacheLabels.has(label) : false;
35
- // 先确定模型(用于缓存键)
39
+ // 先确定主模型(用于缓存键)
36
40
  const resolvedModel = this.modelSelector ? this.modelSelector.selectModel(label) : options?.model;
37
41
  if (cacheable) {
38
42
  const cached = this.cache.get(prompt, label, resolvedModel);
@@ -43,19 +47,42 @@ export class AIGateway {
43
47
  }
44
48
  // 限流
45
49
  await this.rateLimiter.acquire();
50
+ this.totalCompletions++;
46
51
  try {
47
- // 分层模型策略:根据 label 选择模型,注入 options.model
52
+ // 分层模型策略 + 降级链
53
+ if (this.modelSelector) {
54
+ const chain = this.modelSelector.getFallbackChain(label);
55
+ const tiers = [chain.primary, ...chain.fallbacks];
56
+ let lastErr;
57
+ for (const tier of tiers) {
58
+ const model = this.modelSelector.modelForTier(tier);
59
+ const tieredOptions = { ...options, model };
60
+ try {
61
+ const result = await withRetry(() => this.inner.complete(prompt, label, tieredOptions), `AI调用(${label ?? 'unlabeled'}/${tier})`, { retryable: true, maxRetries: 2, retryDelayMs: 500, exponentialBackoff: true });
62
+ if (tier !== chain.primary) {
63
+ this.degradationCount++;
64
+ logger.info(`[AI Gateway] 降级成功:${chain.primary} → ${tier}(label=${label ?? '-'})`);
65
+ }
66
+ if (cacheable) {
67
+ this.cache.set(prompt, label, result, this.cacheTtlMs, model);
68
+ }
69
+ return result;
70
+ }
71
+ catch (err) {
72
+ lastErr = err;
73
+ if (tier !== tiers[tiers.length - 1]) {
74
+ logger.warn(`[AI Gateway] ${tier} 调用失败,降级到下一层(label=${label ?? '-'}):${err}`);
75
+ }
76
+ }
77
+ }
78
+ throw lastErr;
79
+ }
80
+ // 无分层策略:原有逻辑
48
81
  const tieredOptions = {
49
82
  ...options,
50
83
  ...(resolvedModel ? { model: resolvedModel } : {}),
51
84
  };
52
- // 带重试的 AI 调用
53
- const result = await withRetry(() => this.inner.complete(prompt, label, tieredOptions), `AI调用(${label ?? 'unlabeled'})`, {
54
- retryable: true,
55
- maxRetries: 3,
56
- retryDelayMs: 1000,
57
- exponentialBackoff: true,
58
- });
85
+ const result = await withRetry(() => this.inner.complete(prompt, label, tieredOptions), `AI调用(${label ?? 'unlabeled'})`, { retryable: true, maxRetries: 3, retryDelayMs: 1000, exponentialBackoff: true });
59
86
  if (cacheable) {
60
87
  this.cache.set(prompt, label, result, this.cacheTtlMs, resolvedModel);
61
88
  }
@@ -72,7 +99,10 @@ export class AIGateway {
72
99
  const inner = this.inner.formatStats();
73
100
  const hitRate = (this.cache.hitRate * 100).toFixed(1);
74
101
  const limiter = this.rateLimiter.stats;
75
- return `${inner}\n[AI Gateway] 缓存命中率: ${hitRate}% | 缓存条目: ${this.cache.size} | 并发: ${limiter.active}/${3}`;
102
+ const degradationRate = this.totalCompletions === 0
103
+ ? '0.0'
104
+ : ((this.degradationCount / this.totalCompletions) * 100).toFixed(1);
105
+ return `${inner}\n[AI Gateway] 缓存命中率: ${hitRate}% | 缓存条目: ${this.cache.size} | 并发: ${limiter.active}/${this.maxConcurrent} | 累计等待: ${limiter.totalWaitMs}ms | 降级率: ${degradationRate}%`;
76
106
  }
77
107
  }
78
108
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai-gateway/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai-gateway/index.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,8 @@
1
1
  export type ModelTier = 'haiku' | 'sonnet' | 'opus';
2
+ export interface FallbackChain {
3
+ primary: ModelTier;
4
+ fallbacks: ModelTier[];
5
+ }
2
6
  export declare class ModelSelector {
3
7
  private tierToModel;
4
8
  constructor(models?: {
@@ -8,5 +12,13 @@ export declare class ModelSelector {
8
12
  });
9
13
  selectTier(label?: string): ModelTier;
10
14
  selectModel(label?: string): string;
15
+ /**
16
+ * 返回降级链:primary 失败时依次尝试 fallbacks。
17
+ * opus → sonnet → haiku
18
+ * sonnet → haiku
19
+ * haiku → (无降级)
20
+ */
21
+ getFallbackChain(label?: string): FallbackChain;
22
+ modelForTier(tier: ModelTier): string;
11
23
  }
12
24
  //# sourceMappingURL=model-selector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-selector.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/model-selector.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAkEpD,qBAAa,aAAa;IACxB,OAAO,CAAC,WAAW,CAA4B;gBAEnC,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IAQvE,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS;IAKrC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;CAGpC"}
1
+ {"version":3,"file":"model-selector.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/model-selector.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,CAAC;IACnB,SAAS,EAAE,SAAS,EAAE,CAAC;CACxB;AAkED,qBAAa,aAAa;IACxB,OAAO,CAAC,WAAW,CAA4B;gBAEnC,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IAQvE,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS;IAKrC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAInC;;;;;OAKG;IACH,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,aAAa;IAY/C,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM;CAGtC"}
@@ -75,5 +75,25 @@ export class ModelSelector {
75
75
  selectModel(label) {
76
76
  return this.tierToModel[this.selectTier(label)];
77
77
  }
78
+ /**
79
+ * 返回降级链:primary 失败时依次尝试 fallbacks。
80
+ * opus → sonnet → haiku
81
+ * sonnet → haiku
82
+ * haiku → (无降级)
83
+ */
84
+ getFallbackChain(label) {
85
+ const primary = this.selectTier(label);
86
+ switch (primary) {
87
+ case 'opus':
88
+ return { primary: 'opus', fallbacks: ['sonnet', 'haiku'] };
89
+ case 'sonnet':
90
+ return { primary: 'sonnet', fallbacks: ['haiku'] };
91
+ case 'haiku':
92
+ return { primary: 'haiku', fallbacks: [] };
93
+ }
94
+ }
95
+ modelForTier(tier) {
96
+ return this.tierToModel[tier];
97
+ }
78
98
  }
79
99
  //# sourceMappingURL=model-selector.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../src/ai-gateway/model-selector.ts"],"names":[],"mappings":"AAEA,qBAAqB;AACrB,MAAM,aAAa,GAA8B;IAC/C,qEAAqE;IACrE,gBAAgB;IAChB,QAAQ,EAAE,OAAO;IACjB,MAAM,EAAE,OAAO;IACf,gBAAgB,EAAE,OAAO;IACzB,MAAM,EAAE,OAAO;IACf,gBAAgB,EAAE,OAAO;IACzB,aAAa;IACb,WAAW,EAAE,OAAO;IACpB,oBAAoB,EAAE,OAAO;IAC7B,mBAAmB,EAAE,OAAO;IAC5B,gBAAgB;IAChB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,OAAO;IAC1B,UAAU;IACV,qBAAqB,EAAE,OAAO;IAC9B,oBAAoB,EAAE,OAAO;IAC7B,eAAe,EAAE,OAAO;IACxB,SAAS,EAAE,OAAO;IAClB,QAAQ,EAAE,OAAO;IACjB,eAAe;IACf,MAAM,EAAE,OAAO;IACf,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,OAAO;IAEhB,gEAAgE;IAChE,OAAO;IACP,cAAc,EAAE,QAAQ;IACxB,+BAA+B,EAAE,QAAQ;IACzC,oBAAoB,EAAE,QAAQ;IAC9B,MAAM,EAAE,QAAQ;IAChB,QAAQ;IACR,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE,QAAQ;IAChB,OAAO;IACP,eAAe,EAAE,QAAQ;IACzB,iBAAiB,EAAE,QAAQ;IAC3B,cAAc,EAAE,QAAQ;IACxB,6BAA6B,EAAE,QAAQ;IACvC,MAAM,EAAE,QAAQ;IAChB,QAAQ;IACR,oBAAoB,EAAE,QAAQ;IAC9B,iBAAiB,EAAE,QAAQ;IAC3B,WAAW;IACX,UAAU,EAAE,QAAQ;IACpB,QAAQ,EAAE,QAAQ;IAElB,sEAAsE;IACtE,UAAU,EAAE,MAAM;IAClB,aAAa,EAAE,MAAM;IACrB,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;CACf,CAAC;AAEF,MAAM,qBAAqB,GAA8B;IACvD,KAAK,EAAE,2BAA2B;IAClC,MAAM,EAAE,mBAAmB;IAC3B,IAAI,EAAE,iBAAiB;CACxB,CAAC;AAEF,MAAM,OAAO,aAAa;IAChB,WAAW,CAA4B;IAE/C,YAAY,MAA2D;QACrE,IAAI,CAAC,WAAW,GAAG;YACjB,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,qBAAqB,CAAC,KAAK;YACnD,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,qBAAqB,CAAC,MAAM;YACtD,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,qBAAqB,CAAC,IAAI;SACjD,CAAC;IACJ,CAAC;IAED,UAAU,CAAC,KAAc;QACvB,IAAI,CAAC,KAAK;YAAE,OAAO,QAAQ,CAAC;QAC5B,OAAO,aAAa,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC;IAC1C,CAAC;IAED,WAAW,CAAC,KAAc;QACxB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAClD,CAAC;CACF"}
1
+ {"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../src/ai-gateway/model-selector.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,33 @@
1
1
  /**
2
- * 全局 AI 调用限流器
3
- * maxConcurrent=3:最多同时 3 个并发 AI 调用
4
- * minIntervalMs=200:两次调用之间最小间隔 200ms
2
+ * 全局 AI 调用限流器(事件驱动队列模型)
3
+ *
4
+ * 设计:
5
+ * - 并发槽位控制:最多 maxConcurrent 个并发 AI 调用
6
+ * - 最小间隔控制:两次调用之间最小间隔 minIntervalMs
7
+ * - FIFO 等待队列:release() 直接唤醒下一个等待者,消除 setTimeout 轮询
5
8
  */
6
9
  export declare class RateLimiter {
7
10
  private maxConcurrent;
8
11
  private minIntervalMs;
9
12
  private activeCount;
10
- private queue;
11
13
  private lastCallAt;
14
+ /** FIFO 等待队列:每个元素是一个 resolve 回调 */
15
+ private queue;
16
+ private drainTimer;
17
+ private totalWaitMs;
12
18
  constructor(maxConcurrent?: number, minIntervalMs?: number);
13
19
  acquire(): Promise<void>;
14
20
  release(): void;
15
21
  get stats(): {
16
22
  active: number;
17
23
  queued: number;
24
+ totalWaitMs: number;
18
25
  };
26
+ private canAcquireNow;
27
+ /**
28
+ * 尝试唤醒队列头部的等待者。
29
+ * 若间隔未满足,延迟到间隔结束后再次尝试。
30
+ */
31
+ private drainQueue;
19
32
  }
20
33
  //# sourceMappingURL=rate-limiter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,WAAW;IAMpB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,aAAa;IANvB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,UAAU,CAAK;gBAGb,aAAa,SAAI,EACjB,aAAa,SAAM;IAGvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB9B,OAAO,IAAI,IAAI;IAQf,IAAI,KAAK,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAE9C;CACF"}
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,qBAAa,WAAW;IASpB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,aAAa;IATvB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAK;IACvB,mCAAmC;IACnC,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,WAAW,CAAK;gBAGd,aAAa,SAAI,EACjB,aAAa,SAAM;IAGvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB9B,OAAO,IAAI,IAAI;IAKf,IAAI,KAAK,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAEnE;IAED,OAAO,CAAC,aAAa;IAWrB;;;OAGG;IACH,OAAO,CAAC,UAAU;CAkBnB"}
@@ -1,45 +1,83 @@
1
1
  /**
2
- * 全局 AI 调用限流器
3
- * maxConcurrent=3:最多同时 3 个并发 AI 调用
4
- * minIntervalMs=200:两次调用之间最小间隔 200ms
2
+ * 全局 AI 调用限流器(事件驱动队列模型)
3
+ *
4
+ * 设计:
5
+ * - 并发槽位控制:最多 maxConcurrent 个并发 AI 调用
6
+ * - 最小间隔控制:两次调用之间最小间隔 minIntervalMs
7
+ * - FIFO 等待队列:release() 直接唤醒下一个等待者,消除 setTimeout 轮询
5
8
  */
6
9
  export class RateLimiter {
7
10
  maxConcurrent;
8
11
  minIntervalMs;
9
12
  activeCount = 0;
10
- queue = [];
11
13
  lastCallAt = 0;
14
+ /** FIFO 等待队列:每个元素是一个 resolve 回调 */
15
+ queue = [];
16
+ drainTimer = null;
17
+ totalWaitMs = 0;
12
18
  constructor(maxConcurrent = 3, minIntervalMs = 200) {
13
19
  this.maxConcurrent = maxConcurrent;
14
20
  this.minIntervalMs = minIntervalMs;
15
21
  }
16
22
  async acquire() {
23
+ // 快速路径:槽位充足且间隔满足,直接获取
24
+ if (this.canAcquireNow()) {
25
+ this.activeCount++;
26
+ this.lastCallAt = Date.now();
27
+ return;
28
+ }
29
+ // 慢速路径:入队等待
30
+ const enqueuedAt = Date.now();
17
31
  return new Promise((resolve) => {
18
- const tryAcquire = () => {
19
- const now = Date.now();
20
- const sinceLastCall = now - this.lastCallAt;
21
- if (this.activeCount < this.maxConcurrent && sinceLastCall >= this.minIntervalMs) {
22
- this.activeCount++;
23
- this.lastCallAt = now;
24
- resolve();
25
- }
26
- else {
27
- const delay = Math.max(this.minIntervalMs - sinceLastCall, this.activeCount >= this.maxConcurrent ? 50 : 0);
28
- setTimeout(tryAcquire, delay);
29
- }
30
- };
31
- tryAcquire();
32
+ this.queue.push(() => {
33
+ this.totalWaitMs += Date.now() - enqueuedAt;
34
+ this.activeCount++;
35
+ this.lastCallAt = Date.now();
36
+ resolve();
37
+ });
38
+ this.drainQueue();
32
39
  });
33
40
  }
34
41
  release() {
35
42
  this.activeCount = Math.max(0, this.activeCount - 1);
36
- if (this.queue.length > 0) {
43
+ this.drainQueue();
44
+ }
45
+ get stats() {
46
+ return { active: this.activeCount, queued: this.queue.length, totalWaitMs: this.totalWaitMs };
47
+ }
48
+ canAcquireNow() {
49
+ // 允许首批并发请求快速获取(填满并发槽位);
50
+ // 当存在已激活请求时,不对新进入的并发请求施加间隔限制。
51
+ if (this.activeCount > 0) {
52
+ return this.activeCount < this.maxConcurrent;
53
+ }
54
+ const sinceLastCall = Date.now() - this.lastCallAt;
55
+ return this.activeCount < this.maxConcurrent && sinceLastCall >= this.minIntervalMs;
56
+ }
57
+ /**
58
+ * 尝试唤醒队列头部的等待者。
59
+ * 若间隔未满足,延迟到间隔结束后再次尝试。
60
+ */
61
+ drainQueue() {
62
+ if (this.queue.length === 0)
63
+ return;
64
+ if (this.activeCount >= this.maxConcurrent)
65
+ return;
66
+ const sinceLastCall = Date.now() - this.lastCallAt;
67
+ if (sinceLastCall >= this.minIntervalMs) {
37
68
  const next = this.queue.shift();
38
69
  next?.();
39
70
  }
40
- }
41
- get stats() {
42
- return { active: this.activeCount, queued: this.queue.length };
71
+ else {
72
+ // 间隔未满足:等到间隔结束后再唤醒(同一时刻仅保留一个定时器)
73
+ const delay = this.minIntervalMs - sinceLastCall;
74
+ if (this.drainTimer)
75
+ return;
76
+ this.drainTimer = setTimeout(() => {
77
+ this.drainTimer = null;
78
+ this.drainQueue();
79
+ }, delay);
80
+ }
43
81
  }
44
82
  }
45
83
  //# sourceMappingURL=rate-limiter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/ai-gateway/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,WAAW;IAMZ;IACA;IANF,WAAW,GAAG,CAAC,CAAC;IAChB,KAAK,GAAsB,EAAE,CAAC;IAC9B,UAAU,GAAG,CAAC,CAAC;IAEvB,YACU,gBAAgB,CAAC,EACjB,gBAAgB,GAAG;QADnB,kBAAa,GAAb,aAAa,CAAI;QACjB,kBAAa,GAAb,aAAa,CAAM;IAC1B,CAAC;IAEJ,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,MAAM,UAAU,GAAG,GAAG,EAAE;gBACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,MAAM,aAAa,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC5C,IAAI,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,aAAa,IAAI,aAAa,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACjF,IAAI,CAAC,WAAW,EAAE,CAAC;oBACnB,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;oBACtB,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,IAAI,CAAC,aAAa,GAAG,aAAa,EAClC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAChD,CAAC;oBACF,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC,CAAC;YACF,UAAU,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QACrD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YAChC,IAAI,EAAE,EAAE,CAAC;QACX,CAAC;IACH,CAAC;IAED,IAAI,KAAK;QACP,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACjE,CAAC;CACF"}
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/ai-gateway/rate-limiter.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,22 @@
1
1
  /**
2
- * AI 响应内存缓存
3
- * key = SHA256(prompt + label) 16 字符
4
- * TTL = 5 分钟(可配置)
2
+ * AI 响应内存缓存(带容量治理)
3
+ * key = SHA256(model + label + prompt)
4
+ * - TTL 过期淘汰
5
+ * - maxEntries 容量上限(近似 LRU)
5
6
  */
6
7
  export declare class ResponseCache {
8
+ private maxEntries;
7
9
  private cache;
8
10
  private hits;
9
11
  private misses;
12
+ constructor(maxEntries?: number);
10
13
  get(prompt: string, label?: string, model?: string): string | undefined;
11
14
  set(prompt: string, label: string | undefined, value: string, ttlMs?: number, model?: string): void;
12
15
  invalidate(): void;
13
16
  get hitRate(): number;
14
17
  get size(): number;
18
+ private evictExpired;
19
+ private evictOverflow;
15
20
  private makeKey;
16
21
  }
17
22
  //# sourceMappingURL=response-cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/response-cache.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IAEnB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAavE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,SAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAKpG,UAAU,IAAI,IAAI;IAIlB,IAAI,OAAO,IAAI,MAAM,CAGpB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,OAAO;CAGhB"}
1
+ {"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/ai-gateway/response-cache.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,qBAAa,aAAa;IAKZ,OAAO,CAAC,UAAU;IAJ9B,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;gBAEC,UAAU,SAAM;IAEpC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAqBvE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,SAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAepG,UAAU,IAAI,IAAI;IAIlB,IAAI,OAAO,IAAI,MAAM,CAGpB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,OAAO;CAGhB"}
@@ -1,13 +1,18 @@
1
1
  import { createHash } from 'crypto';
2
2
  /**
3
- * AI 响应内存缓存
4
- * key = SHA256(prompt + label) 16 字符
5
- * TTL = 5 分钟(可配置)
3
+ * AI 响应内存缓存(带容量治理)
4
+ * key = SHA256(model + label + prompt)
5
+ * - TTL 过期淘汰
6
+ * - maxEntries 容量上限(近似 LRU)
6
7
  */
7
8
  export class ResponseCache {
9
+ maxEntries;
8
10
  cache = new Map();
9
11
  hits = 0;
10
12
  misses = 0;
13
+ constructor(maxEntries = 500) {
14
+ this.maxEntries = maxEntries;
15
+ }
11
16
  get(prompt, label, model) {
12
17
  const key = this.makeKey(prompt, label, model);
13
18
  const entry = this.cache.get(key);
@@ -20,12 +25,23 @@ export class ResponseCache {
20
25
  this.misses++;
21
26
  return undefined;
22
27
  }
28
+ // 近似 LRU:命中时刷新插入顺序
29
+ this.cache.delete(key);
30
+ this.cache.set(key, entry);
23
31
  this.hits++;
24
32
  return entry.value;
25
33
  }
26
34
  set(prompt, label, value, ttlMs = 300_000, model) {
27
35
  const key = this.makeKey(prompt, label, model);
28
- this.cache.set(key, { value, expiresAt: Date.now() + ttlMs });
36
+ const entry = { value, expiresAt: Date.now() + ttlMs };
37
+ // 先清理已过期条目
38
+ this.evictExpired();
39
+ // 更新同 key 时,先删后插(保持最新顺序)
40
+ if (this.cache.has(key))
41
+ this.cache.delete(key);
42
+ this.cache.set(key, entry);
43
+ // 超出容量:淘汰最旧条目(Map 头部)
44
+ this.evictOverflow();
29
45
  }
30
46
  invalidate() {
31
47
  this.cache.clear();
@@ -37,8 +53,24 @@ export class ResponseCache {
37
53
  get size() {
38
54
  return this.cache.size;
39
55
  }
56
+ evictExpired() {
57
+ const now = Date.now();
58
+ for (const [k, entry] of this.cache.entries()) {
59
+ if (entry.expiresAt <= now) {
60
+ this.cache.delete(k);
61
+ }
62
+ }
63
+ }
64
+ evictOverflow() {
65
+ while (this.cache.size > this.maxEntries) {
66
+ const oldestKey = this.cache.keys().next().value;
67
+ if (!oldestKey)
68
+ break;
69
+ this.cache.delete(oldestKey);
70
+ }
71
+ }
40
72
  makeKey(prompt, label, model) {
41
- return createHash('sha256').update(`${model ?? ''}::${label ?? ''}::${prompt}`).digest('hex').slice(0, 16);
73
+ return createHash('sha256').update(`${model ?? ''}::${label ?? ''}::${prompt}`).digest('hex');
42
74
  }
43
75
  }
44
76
  //# sourceMappingURL=response-cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"response-cache.js","sourceRoot":"","sources":["../../src/ai-gateway/response-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAOpC;;;;GAIG;AACH,MAAM,OAAO,aAAa;IAChB,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtC,IAAI,GAAG,CAAC,CAAC;IACT,MAAM,GAAG,CAAC,CAAC;IAEnB,GAAG,CAAC,MAAc,EAAE,KAAc,EAAE,KAAc;QAChD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAAC,OAAO,SAAS,CAAC;QAAC,CAAC;QAChD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,MAAc,EAAE,KAAyB,EAAE,KAAa,EAAE,KAAK,GAAG,OAAO,EAAE,KAAc;QAC3F,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,OAAO;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;QACtC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IAC7C,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAEO,OAAO,CAAC,MAAc,EAAE,KAAc,EAAE,KAAc;QAC5D,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,KAAK,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7G,CAAC;CACF"}
1
+ {"version":3,"file":"response-cache.js","sourceRoot":"","sources":["../../src/ai-gateway/response-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAOpC;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IAKJ;IAJZ,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtC,IAAI,GAAG,CAAC,CAAC;IACT,MAAM,GAAG,CAAC,CAAC;IAEnB,YAAoB,aAAa,GAAG;QAAhB,eAAU,GAAV,UAAU,CAAM;IAAG,CAAC;IAExC,GAAG,CAAC,MAAc,EAAE,KAAc,EAAE,KAAc;QAChD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,MAAc,EAAE,KAAyB,EAAE,KAAa,EAAE,KAAK,GAAG,OAAO,EAAE,KAAc;QAC3F,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAe,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;QAEnE,WAAW;QACX,IAAI,CAAC,YAAY,EAAE,CAAC;QAEpB,yBAAyB;QACzB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE3B,sBAAsB;QACtB,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,OAAO;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;QACtC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IAC7C,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAEO,YAAY;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC9C,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAEO,aAAa;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACjD,IAAI,CAAC,SAAS;gBAAE,MAAM;YACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,MAAc,EAAE,KAAc,EAAE,KAAc;QAC5D,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,KAAK,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChG,CAAC;CACF"}
@@ -0,0 +1,32 @@
1
+ import type { AIProvider } from '../ai-provider/types.js';
2
+ import type { PipelinePhase } from '../pipeline/types.js';
3
+ export interface TaskCompletionContext {
4
+ requirement: string;
5
+ currentPhase: PipelinePhase;
6
+ /** 最近 5 次工具调用名称 */
7
+ recentTools: string[];
8
+ toolCallCount: number;
9
+ /** 当前阶段已完成任务数 */
10
+ completedTaskCount: number;
11
+ /** 当前阶段总任务数 */
12
+ totalTaskCount: number;
13
+ }
14
+ export interface CompletionDetectionResult {
15
+ isComplete: boolean;
16
+ confidence: 'high' | 'medium' | 'low';
17
+ reason: string;
18
+ suggestedAction: 'advance' | 'wait' | 'ask_user';
19
+ }
20
+ /**
21
+ * LLM 语义任务完成检测器
22
+ *
23
+ * 使用 Haiku 快速判断当前阶段是否完成,替代基于工具调用次数的启发式阈值。
24
+ * 保留阈值逻辑作为兜底,防止 LLM 误判导致无限循环。
25
+ */
26
+ export declare class TaskCompletionDetector {
27
+ private aiProvider;
28
+ constructor(aiProvider: AIProvider);
29
+ detect(ctx: TaskCompletionContext): Promise<CompletionDetectionResult>;
30
+ private parseResponse;
31
+ }
32
+ //# sourceMappingURL=task-completion-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-completion-detector.d.ts","sourceRoot":"","sources":["../../src/autopilot/task-completion-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,aAAa,CAAC;IAC5B,mBAAmB;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;CAClD;AA6CD;;;;;GAKG;AACH,qBAAa,sBAAsB;IACrB,OAAO,CAAC,UAAU;gBAAV,UAAU,EAAE,UAAU;IAEpC,MAAM,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA0B5E,OAAO,CAAC,aAAa;CAgCtB"}
@@ -0,0 +1,103 @@
1
+ import { logger } from '../utils/logger.js';
2
+ const PHASE_DESCRIPTIONS = {
3
+ analyze: '需求分析(输出功能点列表、技术方案、风险点)',
4
+ design: '架构设计(输出目录结构、核心接口定义、设计文档)',
5
+ profile: '性能分析(输出 profiling 结果、基准数据、瓶颈定位)',
6
+ code: '编码实现(按设计方案编写源代码文件)',
7
+ test: '测试编写(编写测试文件并运行通过)',
8
+ review: '代码审查(安全性、规范性、性能检查并修复)',
9
+ done: '已完成',
10
+ };
11
+ const COMPLETION_PROMPT = (ctx) => `你是一个软件开发流水线的阶段完成度评估器。
12
+
13
+ ## 当前上下文
14
+
15
+ - **需求**:${ctx.requirement}
16
+ - **当前阶段**:${ctx.currentPhase}(${PHASE_DESCRIPTIONS[ctx.currentPhase]})
17
+ - **任务进度**:${ctx.completedTaskCount}/${ctx.totalTaskCount} 个任务已完成
18
+ - **工具调用总数**:${ctx.toolCallCount}
19
+ - **最近工具调用**:${ctx.recentTools.join(', ') || '(无)'}
20
+
21
+ ## 评估任务
22
+
23
+ 根据以上信息,判断当前阶段是否已经完成,可以推进到下一阶段。
24
+
25
+ ## 评估标准
26
+
27
+ - analyze 阶段:已有探索(Read/Glob/Grep)+ 输出(Write/Edit),或明确说明分析完成
28
+ - design 阶段:已创建设计文档或目录结构(Write/Edit 包含 design/architecture/README)
29
+ - profile 阶段:已执行 profiling 命令(Bash)或写入性能报告
30
+ - code 阶段:已创建源代码文件(Write .ts/.js/.py/.go 等)
31
+ - test 阶段:已写入测试文件(Write/Edit 包含 test/spec)且已运行测试(Bash vitest/jest)
32
+ - review 阶段:已有代码修改(Edit)
33
+
34
+ ## 输出格式
35
+
36
+ 严格输出 JSON,不要有任何其他文字:
37
+ {
38
+ "isComplete": true/false,
39
+ "confidence": "high"/"medium"/"low",
40
+ "reason": "简短说明(中文,不超过 50 字)",
41
+ "suggestedAction": "advance"/"wait"/"ask_user"
42
+ }`;
43
+ /**
44
+ * LLM 语义任务完成检测器
45
+ *
46
+ * 使用 Haiku 快速判断当前阶段是否完成,替代基于工具调用次数的启发式阈值。
47
+ * 保留阈值逻辑作为兜底,防止 LLM 误判导致无限循环。
48
+ */
49
+ export class TaskCompletionDetector {
50
+ aiProvider;
51
+ constructor(aiProvider) {
52
+ this.aiProvider = aiProvider;
53
+ }
54
+ async detect(ctx) {
55
+ try {
56
+ const prompt = COMPLETION_PROMPT(ctx);
57
+ const response = await this.aiProvider.complete(prompt, 'task-completion-detector', {
58
+ maxTokens: 200,
59
+ temperature: 0,
60
+ });
61
+ const result = this.parseResponse(response);
62
+ if (result) {
63
+ logger.info(`[任务完成检测] ${ctx.currentPhase} 阶段:${result.isComplete ? '完成' : '未完成'}(${result.confidence})- ${result.reason}`);
64
+ return result;
65
+ }
66
+ }
67
+ catch (err) {
68
+ logger.warn(`[任务完成检测] LLM 调用失败,降级到保守策略:${err}`);
69
+ }
70
+ // 降级:保守策略(未完成)
71
+ return {
72
+ isComplete: false,
73
+ confidence: 'low',
74
+ reason: 'LLM 检测失败,保守判断为未完成',
75
+ suggestedAction: 'wait',
76
+ };
77
+ }
78
+ parseResponse(response) {
79
+ try {
80
+ // 提取 JSON(可能被 markdown 代码块包裹)
81
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
82
+ if (!jsonMatch)
83
+ return null;
84
+ const parsed = JSON.parse(jsonMatch[0]);
85
+ if (typeof parsed.isComplete !== 'boolean' ||
86
+ !['high', 'medium', 'low'].includes(parsed.confidence) ||
87
+ typeof parsed.reason !== 'string' ||
88
+ !['advance', 'wait', 'ask_user'].includes(parsed.suggestedAction)) {
89
+ return null;
90
+ }
91
+ return {
92
+ isComplete: parsed.isComplete,
93
+ confidence: parsed.confidence,
94
+ reason: parsed.reason,
95
+ suggestedAction: parsed.suggestedAction,
96
+ };
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=task-completion-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-completion-detector.js","sourceRoot":"","sources":["../../src/autopilot/task-completion-detector.ts"],"names":[],"mappings":"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"}