triflux 10.2.0 → 10.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hub/reflexion.mjs CHANGED
@@ -8,7 +8,7 @@ const ACTIVE_RULE_CONFIDENCE = 0.5;
8
8
  const ADAPTIVE_PROMOTION_STEP = 0.1;
9
9
  const ADAPTIVE_DECAY_STEP = 0.1;
10
10
  /** @deprecated 세션 기반 decay에서 시간 기반으로 변경됨. 미사용. */
11
- const ADAPTIVE_DECAY_WINDOW = 5;
11
+ const _ADAPTIVE_DECAY_WINDOW = 5;
12
12
  const ADAPTIVE_DELETE_THRESHOLD = 0.3;
13
13
 
14
14
  function clampConfidence(value) {
@@ -129,7 +129,7 @@ function getAdaptiveState(rule = {}) {
129
129
  }
130
130
 
131
131
  /** @deprecated reflexion_entries 기반. adaptive_rules에서는 미사용. 세션 인식 복원 시 재활용 예정. */
132
- function mergeAdaptiveState(rule, errorContext = {}) {
132
+ function _mergeAdaptiveState(rule, errorContext = {}) {
133
133
  const current = getAdaptiveState(rule);
134
134
  const sessionId = pickSessionId(errorContext);
135
135
  const sessionCount = pickSessionCount(
@@ -163,6 +163,63 @@ function filterEntriesByType(entries, type) {
163
163
  );
164
164
  }
165
165
 
166
+ function parseAdaptiveRuleId(ruleId, projectSlug = "") {
167
+ const value = pickString(ruleId);
168
+ if (!value) return null;
169
+ const nulSeparator = value.indexOf("\u0000");
170
+ if (nulSeparator > 0) {
171
+ return {
172
+ project_slug: value.slice(0, nulSeparator),
173
+ pattern: value.slice(nulSeparator + 1),
174
+ };
175
+ }
176
+ if (projectSlug && value.startsWith(`${projectSlug}:`)) {
177
+ return {
178
+ project_slug: projectSlug,
179
+ pattern: value.slice(projectSlug.length + 1),
180
+ };
181
+ }
182
+ return null;
183
+ }
184
+
185
+ function resolveAdaptiveRuleIdentity(
186
+ ruleIdOrProjectSlug,
187
+ patternOrErrorContext,
188
+ ) {
189
+ if (typeof patternOrErrorContext === "string") {
190
+ return {
191
+ project_slug: pickString(ruleIdOrProjectSlug),
192
+ pattern: pickString(patternOrErrorContext),
193
+ };
194
+ }
195
+
196
+ const errorContext =
197
+ patternOrErrorContext && typeof patternOrErrorContext === "object"
198
+ ? patternOrErrorContext
199
+ : {};
200
+ const projectSlug = pickString(pickProjectSlug(errorContext));
201
+ const fromRuleId = parseAdaptiveRuleId(ruleIdOrProjectSlug, projectSlug);
202
+ const errorText = pickString(
203
+ errorContext.error_pattern,
204
+ errorContext.pattern,
205
+ errorContext.error,
206
+ errorContext.errorText,
207
+ errorContext.errorMessage,
208
+ buildErrorText(errorContext),
209
+ );
210
+ const pattern = pickString(normalizeError(errorText), fromRuleId?.pattern);
211
+ return {
212
+ project_slug: pickString(projectSlug, fromRuleId?.project_slug),
213
+ pattern,
214
+ };
215
+ }
216
+
217
+ function listAdaptiveRulesFromStore(store, projectSlug) {
218
+ if (!store?.listAdaptiveRules) return [];
219
+ const rules = store.listAdaptiveRules(projectSlug);
220
+ return Array.isArray(rules) ? rules : [];
221
+ }
222
+
166
223
  /**
167
224
  * 에러 메시지를 정규화된 패턴 시그니처로 변환
168
225
  * 파일 경로, 줄 번호, 타임스탬프, UUID, 숫자 리터럴을 플레이스홀더로 치환
@@ -287,17 +344,28 @@ export function adaptiveRuleFromError(errorContext = {}) {
287
344
 
288
345
  /**
289
346
  * 동일 패턴이 여러 세션에서 재발하면 adaptive rule confidence를 승격
347
+ * 현재 (projectSlug, pattern)과 구형 (ruleId, errorContext) 시그니처를 모두 지원한다.
290
348
  * @param {object} store — store-adapter 인스턴스 (findAdaptiveRule, updateRuleConfidence 필요)
291
- * @param {string} projectSlug
292
- * @param {string} pattern
349
+ * @param {string} ruleIdOrProjectSlug
350
+ * @param {object|string} patternOrErrorContext
293
351
  * @returns {object|null}
294
352
  */
295
- export function promoteRule(store, projectSlug, pattern) {
353
+ export function promoteRule(store, ruleIdOrProjectSlug, patternOrErrorContext) {
296
354
  if (!store.findAdaptiveRule || !store.updateRuleConfidence) return null;
297
- const rule = store.findAdaptiveRule(projectSlug, pattern);
355
+ const identity = resolveAdaptiveRuleIdentity(
356
+ ruleIdOrProjectSlug,
357
+ patternOrErrorContext,
358
+ );
359
+ if (!identity.project_slug || !identity.pattern) return null;
360
+ const rule = store.findAdaptiveRule(identity.project_slug, identity.pattern);
298
361
  if (!rule) return null;
299
362
  const promoted = clampConfidence(rule.confidence + ADAPTIVE_PROMOTION_STEP);
300
- return store.updateRuleConfidence(projectSlug, pattern, promoted, { hit_count_increment: 1 });
363
+ return store.updateRuleConfidence(
364
+ identity.project_slug,
365
+ identity.pattern,
366
+ promoted,
367
+ { hit_count_increment: 1 },
368
+ );
301
369
  }
302
370
 
303
371
  /**
@@ -310,10 +378,11 @@ export function promoteRule(store, projectSlug, pattern) {
310
378
  export function decayRules(store, _sessionCount, projectSlug) {
311
379
  if (!store.listAdaptiveRules) return { updated: [], deleted: [] };
312
380
  const result = { updated: [], deleted: [] };
313
- const rules = store.listAdaptiveRules(projectSlug);
381
+ const rules = listAdaptiveRulesFromStore(store, projectSlug);
314
382
  for (const rule of rules) {
315
383
  // 7일 이상 미관측된 규칙만 decay 대상
316
- const ageDays = (Date.now() - (rule.last_seen_ms || 0)) / (24 * 3600 * 1000);
384
+ const ageDays =
385
+ (Date.now() - (rule.last_seen_ms || 0)) / (24 * 3600 * 1000);
317
386
  if (ageDays < 7) continue;
318
387
  const decayed = clampConfidence(rule.confidence - ADAPTIVE_DECAY_STEP);
319
388
  if (decayed <= ADAPTIVE_DELETE_THRESHOLD) {
@@ -323,7 +392,12 @@ export function decayRules(store, _sessionCount, projectSlug) {
323
392
  continue;
324
393
  }
325
394
  if (decayed < rule.confidence) {
326
- const updated = store.updateRuleConfidence(rule.project_slug, rule.pattern, decayed, { hit_count_increment: 0 });
395
+ const updated = store.updateRuleConfidence(
396
+ rule.project_slug,
397
+ rule.pattern,
398
+ decayed,
399
+ { hit_count_increment: 0 },
400
+ );
327
401
  if (updated) result.updated.push(updated);
328
402
  }
329
403
  }
@@ -337,9 +411,9 @@ export function decayRules(store, _sessionCount, projectSlug) {
337
411
  * @returns {Array}
338
412
  */
339
413
  export function getActiveAdaptiveRules(store, projectSlug) {
340
- if (!store.listAdaptiveRules) return [];
341
- return store.listAdaptiveRules(projectSlug)
342
- .filter((rule) => rule.confidence >= ACTIVE_RULE_CONFIDENCE);
414
+ return listAdaptiveRulesFromStore(store, projectSlug).filter(
415
+ (rule) => rule.confidence >= ACTIVE_RULE_CONFIDENCE,
416
+ );
343
417
  }
344
418
 
345
419
  /**
package/hub/research.mjs CHANGED
@@ -6,6 +6,7 @@ import { join, resolve } from 'node:path';
6
6
  import { TFX_REPORTS_DIR } from './paths.mjs';
7
7
 
8
8
  /**
9
+ * @experimental 런타임 미연결 — 향후 통합 예정
9
10
  * @experimental
10
11
  * 주제에서 검색 쿼리 3-5개를 자동 생성한다.
11
12
  * 한국어 주제 → 한국어 + 영어 혼합, 영어 주제 → 영어 쿼리.