@rynfar/meridian 1.65.2 → 1.66.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 (33) hide show
  1. package/README.md +9 -3
  2. package/dist/{cli-pdpry6q0.js → cli-5jxyma6z.js} +5 -2
  3. package/dist/{cli-0ed6j0vk.js → cli-m9wqgk1q.js} +50 -16
  4. package/dist/{cli-syjqjygv.js → cli-nzvbaqjp.js} +413 -54
  5. package/dist/cli.js +5 -5
  6. package/dist/{profileCli-ap7eg985.js → profileCli-qhcr87tm.js} +1 -1
  7. package/dist/{profiles-4ajzjqhm.js → profiles-wch9h234.js} +1 -1
  8. package/dist/proxy/adapter.d.ts +14 -0
  9. package/dist/proxy/adapter.d.ts.map +1 -1
  10. package/dist/proxy/adapters/claudecode.d.ts +29 -0
  11. package/dist/proxy/adapters/claudecode.d.ts.map +1 -1
  12. package/dist/proxy/adapters/prime.d.ts.map +1 -1
  13. package/dist/proxy/models.d.ts +26 -8
  14. package/dist/proxy/models.d.ts.map +1 -1
  15. package/dist/proxy/oauthUsage.d.ts.map +1 -1
  16. package/dist/proxy/openai.d.ts +15 -0
  17. package/dist/proxy/openai.d.ts.map +1 -1
  18. package/dist/proxy/openaiResponses.d.ts +4 -11
  19. package/dist/proxy/openaiResponses.d.ts.map +1 -1
  20. package/dist/proxy/retryAfter.d.ts +90 -0
  21. package/dist/proxy/retryAfter.d.ts.map +1 -0
  22. package/dist/proxy/routing.d.ts +11 -0
  23. package/dist/proxy/routing.d.ts.map +1 -1
  24. package/dist/proxy/server.d.ts.map +1 -1
  25. package/dist/proxy/sessionTree.d.ts +113 -0
  26. package/dist/proxy/sessionTree.d.ts.map +1 -0
  27. package/dist/server.js +3 -3
  28. package/dist/telemetry/dashboard.d.ts.map +1 -1
  29. package/dist/telemetry/routes.d.ts +10 -1
  30. package/dist/telemetry/routes.d.ts.map +1 -1
  31. package/dist/telemetry/types.d.ts +16 -0
  32. package/dist/telemetry/types.d.ts.map +1 -1
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -118,9 +118,15 @@ Prime Agent is reliable through Meridian with one active agent. RLM children hav
118
118
  separate session identities and can execute successfully, but concurrent subagent
119
119
  orchestration is not yet production-safe. Observed failure modes include overload
120
120
  amplification, expensive cache churn after fresh-session replay, loss of child-task
121
- context during recovery, undelivered tool envelopes, and incomplete parent-to-child
122
- cancellation. Use a single active Prime Agent for unattended or usage-sensitive work
123
- until coordinated fixes land in Prime Agent and Meridian.
121
+ context during recovery, and undelivered tool envelopes. Use a single active Prime
122
+ Agent for unattended or usage-sensitive work until coordinated fixes land in Prime
123
+ Agent and Meridian.
124
+
125
+ Parent-to-child cancellation is handled on the Meridian side: when the extension
126
+ stamps `parent_session_id` alongside the child's session id, aborting a parent's
127
+ in-flight request aborts every live request in the subtree below it and evicts
128
+ each one's session mapping. See
129
+ [Subagent cancellation](docs/agents.md#prime-agent).
124
130
 
125
131
  Prime Agent can keep Opus on the root session while selecting Sol for an individual
126
132
  child. A child inherits its parent's model unless the `rlm` call supplies an exact
@@ -147,13 +147,16 @@ function cooldownCapMs(type) {
147
147
  return COOLDOWN_CAP_MS[type];
148
148
  }
149
149
  function resolveCooldownUntil(windows, now, defaultMs) {
150
+ return findCooldownReset(windows, now) ?? now + defaultMs;
151
+ }
152
+ function findCooldownReset(windows, now) {
150
153
  for (const type of COOLDOWN_WINDOWS) {
151
154
  const match = windows.find((w) => w.type === type && w.exhausted && (w.resetsAt ?? 0) > now);
152
155
  if (match?.resetsAt) {
153
156
  return Math.min(match.resetsAt, now + cooldownCapMs(type));
154
157
  }
155
158
  }
156
- return now + defaultMs;
159
+ return null;
157
160
  }
158
161
 
159
162
  // src/proxy/profiles.ts
@@ -271,4 +274,4 @@ function listProfiles(profiles, defaultProfile) {
271
274
  }));
272
275
  }
273
276
 
274
- export { getRoutingMode, getPriorityFailbackPolicy, shouldPromotePriorityAssignment, resolvePriorityOrder, choosePriorityProfile, ProfileExhaustion, AssignmentStore, resolveCooldownUntil, loadProfilesFromDisk, setActiveProfile, getActiveProfileId, resetActiveProfile, restoreActiveProfile, enableDiskProfileDiscovery, getEffectiveProfiles, hasProfiles, resolveProfile, listProfiles };
277
+ export { getRoutingMode, getPriorityFailbackPolicy, shouldPromotePriorityAssignment, resolvePriorityOrder, choosePriorityProfile, ProfileExhaustion, AssignmentStore, resolveCooldownUntil, findCooldownReset, loadProfilesFromDisk, setActiveProfile, getActiveProfileId, resetActiveProfile, restoreActiveProfile, enableDiskProfileDiscovery, getEffectiveProfiles, hasProfiles, resolveProfile, listProfiles };
@@ -92,7 +92,7 @@ function supports1mContext(model) {
92
92
  return false;
93
93
  return true;
94
94
  }
95
- function mapModelToClaudeModel(model, subscriptionType, agentMode, profileId) {
95
+ function mapModelToClaudeModel(model, subscriptionType, agentMode, profileId, sessionKey) {
96
96
  if (model.includes("haiku"))
97
97
  return "haiku";
98
98
  const use1m = supports1mContext(model);
@@ -105,7 +105,7 @@ function mapModelToClaudeModel(model, subscriptionType, agentMode, profileId) {
105
105
  if (fableOverrideRaw && fableOverride !== "fable[1m]") {
106
106
  warnUnrecognizedTierOverride("FABLE_MODEL", fableOverrideRaw, "fable");
107
107
  }
108
- if (use1m && !isSubagent && !isExtendedContextKnownUnavailable(profileId))
108
+ if (use1m && !isSubagent && !isExtendedContextKnownUnavailable(profileId, sessionKey))
109
109
  return "fable[1m]";
110
110
  return "fable";
111
111
  }
@@ -117,13 +117,13 @@ function mapModelToClaudeModel(model, subscriptionType, agentMode, profileId) {
117
117
  if (opusOverrideRaw && opusOverride !== "opus[1m]") {
118
118
  warnUnrecognizedTierOverride("OPUS_MODEL", opusOverrideRaw, "opus");
119
119
  }
120
- if (use1m && !isSubagent && !isExtendedContextKnownUnavailable(profileId))
120
+ if (use1m && !isSubagent && !isExtendedContextKnownUnavailable(profileId, sessionKey))
121
121
  return "opus[1m]";
122
122
  return "opus";
123
123
  }
124
124
  const sonnetOverride = process.env.MERIDIAN_SONNET_MODEL ?? process.env.CLAUDE_PROXY_SONNET_MODEL;
125
125
  if (sonnetOverride === "sonnet[1m]") {
126
- if (!use1m || isSubagent || isExtendedContextKnownUnavailable(profileId))
126
+ if (!use1m || isSubagent || isExtendedContextKnownUnavailable(profileId, sessionKey))
127
127
  return "sonnet";
128
128
  return "sonnet[1m]";
129
129
  }
@@ -131,33 +131,67 @@ function mapModelToClaudeModel(model, subscriptionType, agentMode, profileId) {
131
131
  }
132
132
  var EXTRA_USAGE_RETRY_MS = 60 * 60 * 1000;
133
133
  var DEFAULT_BENCH_KEY = "__default__";
134
+ var BENCH_MAX_ENTRIES = 5000;
134
135
  var extendedContextBenchedUntil = new Map;
135
- function benchExtendedContext(profileId, until) {
136
- if (until <= Date.now())
136
+ function profileBenchKey(profileId) {
137
+ return profileId || DEFAULT_BENCH_KEY;
138
+ }
139
+ function sessionBenchKey(profileId, sessionKey) {
140
+ return `${profileBenchKey(profileId)}\x00session:${sessionKey}`;
141
+ }
142
+ function pruneBenchEntries(now) {
143
+ if (extendedContextBenchedUntil.size < BENCH_MAX_ENTRIES)
144
+ return;
145
+ for (const [key, until] of extendedContextBenchedUntil) {
146
+ if (until <= now)
147
+ extendedContextBenchedUntil.delete(key);
148
+ }
149
+ while (extendedContextBenchedUntil.size >= BENCH_MAX_ENTRIES) {
150
+ let soonestKey;
151
+ let soonest = Infinity;
152
+ for (const [key, until] of extendedContextBenchedUntil) {
153
+ if (until < soonest) {
154
+ soonest = until;
155
+ soonestKey = key;
156
+ }
157
+ }
158
+ if (soonestKey === undefined)
159
+ return;
160
+ extendedContextBenchedUntil.delete(soonestKey);
161
+ }
162
+ }
163
+ function benchExtendedContext(key, until) {
164
+ const now = Date.now();
165
+ if (until <= now)
137
166
  return;
138
- const key = profileId || DEFAULT_BENCH_KEY;
139
167
  const existing = extendedContextBenchedUntil.get(key);
140
168
  if (existing !== undefined && existing >= until)
141
169
  return;
170
+ pruneBenchEntries(now);
142
171
  extendedContextBenchedUntil.set(key, until);
143
172
  }
144
- function recordExtendedContextUnavailable(profileId) {
145
- benchExtendedContext(profileId, Date.now() + EXTRA_USAGE_RETRY_MS);
146
- }
147
- function recordExtendedContextRateLimited(profileId, until) {
148
- benchExtendedContext(profileId, until);
149
- }
150
- function isExtendedContextKnownUnavailable(profileId) {
151
- const key = profileId || DEFAULT_BENCH_KEY;
173
+ function benchActive(key, now) {
152
174
  const until = extendedContextBenchedUntil.get(key);
153
175
  if (until === undefined)
154
176
  return false;
155
- if (until <= Date.now()) {
177
+ if (until <= now) {
156
178
  extendedContextBenchedUntil.delete(key);
157
179
  return false;
158
180
  }
159
181
  return true;
160
182
  }
183
+ function recordExtendedContextUnavailable(profileId) {
184
+ benchExtendedContext(profileBenchKey(profileId), Date.now() + EXTRA_USAGE_RETRY_MS);
185
+ }
186
+ function recordExtendedContextRateLimited(profileId, until, sessionKey) {
187
+ benchExtendedContext(sessionKey ? sessionBenchKey(profileId, sessionKey) : profileBenchKey(profileId), until);
188
+ }
189
+ function isExtendedContextKnownUnavailable(profileId, sessionKey) {
190
+ const now = Date.now();
191
+ if (benchActive(profileBenchKey(profileId), now))
192
+ return true;
193
+ return sessionKey ? benchActive(sessionBenchKey(profileId, sessionKey), now) : false;
194
+ }
161
195
  function stripExtendedContext(model) {
162
196
  if (model === "opus[1m]")
163
197
  return "opus";