@triflux/remote 10.62.0 → 10.64.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.
@@ -58,6 +58,28 @@ function beginTurn(state) {
58
58
  function acceptEntry(state, entry, marker) {
59
59
  if (entry?.isSidechain) return;
60
60
  const message = entry?.message;
61
+ if (
62
+ entry?.type === "attachment" &&
63
+ entry.attachment?.type === "goal_status"
64
+ ) {
65
+ const goal = entry.attachment;
66
+ const cleared = goal.met === true && goal.sentinel === true;
67
+ state.goal = {
68
+ state: cleared ? "none" : goal.met ? "complete" : "active",
69
+ objective: cleared ? null : goal.condition,
70
+ judgedBy: "evaluator",
71
+ ...(goal.reason !== undefined ? { reason: goal.reason } : {}),
72
+ ...(goal.tokens !== undefined ? { tokensUsed: goal.tokens } : {}),
73
+ updatedAt: entry.timestamp ?? null,
74
+ };
75
+ if (goal.sentinel === true) {
76
+ state.goalSentinel = {
77
+ ...goal,
78
+ updatedAt: entry.timestamp,
79
+ count: (state.goalSentinel?.count ?? 0) + 1,
80
+ };
81
+ }
82
+ }
61
83
  if (entry?.type === "system" && entry.subtype === "compact_boundary") {
62
84
  state.compactCount += 1;
63
85
  state.compact = {
@@ -211,6 +233,8 @@ export async function readClaudeTranscript(transcriptPath, { requestId } = {}) {
211
233
  measuredAt: null,
212
234
  compactCount: 0,
213
235
  compact: null,
236
+ goal: { state: "none", objective: null, judgedBy: "evaluator" },
237
+ goalSentinel: null,
214
238
  };
215
239
  }
216
240
  try {
@@ -248,6 +272,7 @@ export async function readClaudeTranscript(transcriptPath, { requestId } = {}) {
248
272
  model: state.model,
249
273
  measuredAt: state.measuredAt,
250
274
  },
275
+ enqueued: state.queuedContent !== null,
251
276
  userSeen: state.userSeen,
252
277
  response: state.response,
253
278
  error: state.error,
@@ -255,5 +280,7 @@ export async function readClaudeTranscript(transcriptPath, { requestId } = {}) {
255
280
  sectionClosed: state.sectionClosed,
256
281
  compactCount: state.compactCount,
257
282
  compact: state.compact,
283
+ goal: state.goal,
284
+ goalSentinel: state.goalSentinel,
258
285
  };
259
286
  }
@@ -23,14 +23,21 @@ const MODEL_CONTEXT = [
23
23
  },
24
24
  ];
25
25
 
26
- export const CONTEXT_THRESHOLDS = {
26
+ const CONTEXT_THRESHOLDS = {
27
27
  claude: { warnContextPct: 60, maxContextPct: 90 },
28
- codex: { warnContextPct: 15, maxContextPct: 22 },
28
+ codex: { warnContextPct: 60, maxContextPct: 85 },
29
29
  };
30
+ // rollout 실행 창을 못 읽으면 1.05M 표 값이 분모라 실제 창보다 비율이 작게 나온다.
31
+ const CODEX_MODEL_WINDOW_THRESHOLDS = { warnContextPct: 15, maxContextPct: 22 };
30
32
 
31
33
  const rolloutCache = new Map();
32
34
 
33
- export function modelContext(cli, model, estimatedContextTokens = null) {
35
+ export function modelContext(
36
+ cli,
37
+ model,
38
+ estimatedContextTokens = null,
39
+ rolloutContextWindow = null,
40
+ ) {
34
41
  const entry = MODEL_CONTEXT.find(
35
42
  (item) => item.cli === cli && item.model.test(model || ""),
36
43
  );
@@ -38,18 +45,20 @@ export function modelContext(cli, model, estimatedContextTokens = null) {
38
45
  const executionContextLimitTokens =
39
46
  cli === "claude" && process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT === "1"
40
47
  ? 200_000
41
- : null;
42
- const effectiveLimit = Math.min(
43
- contextLimitTokens ?? Infinity,
44
- executionContextLimitTokens ?? Infinity,
45
- );
48
+ : rolloutContextWindow;
49
+ // Codex 는 rollout 이 보고한 창이 실제 실행 한도라 표 값과 무관하게 그 창을 쓴다.
50
+ const effectiveLimit =
51
+ cli === "codex"
52
+ ? (executionContextLimitTokens ?? contextLimitTokens)
53
+ : contextLimitTokens &&
54
+ Math.min(contextLimitTokens, executionContextLimitTokens ?? Infinity);
46
55
  return {
47
56
  estimatedContextTokens,
48
57
  contextLimitTokens,
49
58
  contextLimitSource: entry?.source ?? null,
50
59
  ...(executionContextLimitTokens ? { executionContextLimitTokens } : {}),
51
60
  contextPct:
52
- contextLimitTokens && Number.isFinite(estimatedContextTokens)
61
+ effectiveLimit && Number.isFinite(estimatedContextTokens)
53
62
  ? (estimatedContextTokens / effectiveLimit) * 100
54
63
  : null,
55
64
  };
@@ -60,7 +69,10 @@ export function contextGuard(
60
69
  context,
61
70
  { warnContextPct, maxContextPct } = {},
62
71
  ) {
63
- const defaults = CONTEXT_THRESHOLDS[cli];
72
+ const defaults =
73
+ cli === "codex" && !context?.executionContextLimitTokens
74
+ ? CODEX_MODEL_WINDOW_THRESHOLDS
75
+ : CONTEXT_THRESHOLDS[cli];
64
76
  const warn = warnContextPct ?? defaults?.warnContextPct ?? 0;
65
77
  const max = maxContextPct ?? defaults?.maxContextPct ?? 0;
66
78
  const fields = {
@@ -90,6 +102,7 @@ export function contextGuard(
90
102
  inputSent: false,
91
103
  hint: "세션을 승계한 뒤 새 세션에 요청하라.",
92
104
  ...fields,
105
+ thresholdPct: max,
93
106
  };
94
107
  }
95
108
  return warn > 0 && fields.contextPct >= warn
@@ -137,12 +150,19 @@ function acceptCodexLine(state, line) {
137
150
  } catch {
138
151
  return false;
139
152
  }
153
+ if (entry?.type === "compacted") {
154
+ state.compactCount += 1;
155
+ state.compact = { preTokens: state.tokens, postTokens: null };
156
+ }
140
157
  if (entry?.type === "turn_context")
141
158
  state.model = entry.payload?.model || state.model;
142
159
  if (entry?.type === "event_msg" && entry.payload?.type === "token_count") {
143
160
  const info = entry.payload.info;
144
- if (Number.isFinite(info?.last_token_usage?.total_tokens))
161
+ if (Number.isFinite(info?.last_token_usage?.total_tokens)) {
145
162
  state.tokens = info.last_token_usage.total_tokens;
163
+ if (state.compact && state.compact.postTokens === null)
164
+ state.compact.postTokens = state.tokens;
165
+ }
146
166
  if (Number.isFinite(info?.model_context_window))
147
167
  state.executionContextLimitTokens = info.model_context_window;
148
168
  }
@@ -172,6 +192,8 @@ export async function readCodexContext(rolloutPath, threadId) {
172
192
  decoder: new StringDecoder("utf8"),
173
193
  model: null,
174
194
  tokens: null,
195
+ compactCount: 0,
196
+ compact: null,
175
197
  executionContextLimitTokens: null,
176
198
  };
177
199
  }
@@ -197,8 +219,15 @@ export async function readCodexContext(rolloutPath, threadId) {
197
219
  state.mtimeMs = stat.mtimeMs;
198
220
  rolloutCache.set(rolloutPath, state);
199
221
  return {
200
- ...modelContext("codex", state.model, state.tokens),
222
+ ...modelContext(
223
+ "codex",
224
+ state.model,
225
+ state.tokens,
226
+ state.executionContextLimitTokens,
227
+ ),
201
228
  model: state.model,
229
+ compactCount: state.compactCount,
230
+ compact: state.compact,
202
231
  executionContextLimitTokens: state.executionContextLimitTokens,
203
232
  };
204
233
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@triflux/remote",
3
- "version": "10.62.0",
3
+ "version": "10.64.0",
4
4
  "description": "triflux remote — team mode, psmux, MCP workers.",
5
5
  "type": "module",
6
6
  "main": "hub/index.mjs",