aweshare 0.5.5 → 0.5.7

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 (63) hide show
  1. package/README.ai.md +7 -7
  2. package/README.md +26 -11
  3. package/apps/agent/dist/config.d.ts +1 -1
  4. package/apps/agent/dist/config.js +2 -0
  5. package/apps/agent/dist/config.js.map +1 -1
  6. package/apps/agent/dist/connection.js +9 -4
  7. package/apps/agent/dist/connection.js.map +1 -1
  8. package/apps/agent/dist/doctor.js +55 -19
  9. package/apps/agent/dist/doctor.js.map +1 -1
  10. package/apps/agent/dist/table.d.ts +19 -2
  11. package/apps/agent/dist/table.js +28 -3
  12. package/apps/agent/dist/table.js.map +1 -1
  13. package/apps/consumer/dist/cli.js +1 -1
  14. package/apps/consumer/dist/cli.js.map +1 -1
  15. package/apps/consumer/dist/table.d.ts +17 -2
  16. package/apps/consumer/dist/table.js +18 -3
  17. package/apps/consumer/dist/table.js.map +1 -1
  18. package/apps/hub/dist/admin.d.ts +2 -0
  19. package/apps/hub/dist/admin.js +33 -1
  20. package/apps/hub/dist/admin.js.map +1 -1
  21. package/apps/hub/dist/cli.js +170 -124
  22. package/apps/hub/dist/cli.js.map +1 -1
  23. package/apps/hub/dist/config.d.ts +6 -1
  24. package/apps/hub/dist/config.js +42 -1
  25. package/apps/hub/dist/config.js.map +1 -1
  26. package/apps/hub/dist/consumer.d.ts +34 -3
  27. package/apps/hub/dist/consumer.js +100 -8
  28. package/apps/hub/dist/consumer.js.map +1 -1
  29. package/apps/hub/dist/db.d.ts +38 -2
  30. package/apps/hub/dist/db.js +80 -8
  31. package/apps/hub/dist/db.js.map +1 -1
  32. package/apps/hub/dist/local.d.ts +12 -2
  33. package/apps/hub/dist/local.js +26 -7
  34. package/apps/hub/dist/local.js.map +1 -1
  35. package/apps/hub/dist/meter.d.ts +6 -1
  36. package/apps/hub/dist/meter.js +14 -0
  37. package/apps/hub/dist/meter.js.map +1 -1
  38. package/apps/hub/dist/server.js +4 -2
  39. package/apps/hub/dist/server.js.map +1 -1
  40. package/apps/hub/dist/table.d.ts +20 -3
  41. package/apps/hub/dist/table.js +35 -10
  42. package/apps/hub/dist/table.js.map +1 -1
  43. package/package.json +2 -1
  44. package/packages/producer-core/dist/adapters.d.ts +3 -6
  45. package/packages/producer-core/dist/adapters.js +8 -7
  46. package/packages/producer-core/dist/adapters.js.map +1 -1
  47. package/packages/producer-core/dist/health.d.ts +25 -2
  48. package/packages/producer-core/dist/health.js +77 -4
  49. package/packages/producer-core/dist/health.js.map +1 -1
  50. package/packages/producer-core/dist/index.d.ts +1 -0
  51. package/packages/producer-core/dist/index.js +1 -0
  52. package/packages/producer-core/dist/index.js.map +1 -1
  53. package/packages/producer-core/dist/job.js +9 -8
  54. package/packages/producer-core/dist/job.js.map +1 -1
  55. package/packages/producer-core/dist/proxy.d.ts +21 -0
  56. package/packages/producer-core/dist/proxy.js +77 -0
  57. package/packages/producer-core/dist/proxy.js.map +1 -0
  58. package/packages/protocol/dist/index.d.ts +1 -0
  59. package/packages/protocol/dist/index.js +1 -0
  60. package/packages/protocol/dist/index.js.map +1 -1
  61. package/packages/protocol/dist/models.d.ts +23 -0
  62. package/packages/protocol/dist/models.js +72 -0
  63. package/packages/protocol/dist/models.js.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,38 @@
1
1
  import type { BackendStatus } from 'aweshare-protocol';
2
+ import type { Logger } from 'pino';
2
3
  export type FailureReason = 'AUTH' | 'QUOTA' | 'HTTP' | 'NETWORK' | 'CANCELLED';
4
+ /** Ladder transition a record() caused, for logging: entering degraded,
5
+ * clearing it, or nothing. */
6
+ export type HealthTransition = 'degraded' | 'recovered' | null;
3
7
  /**
4
8
  * Per-backend health state. Degraded backends are reported in heartbeats and
5
- * the hub stops dispatching to their offerings until they recover.
9
+ * the hub stops dispatching to their offerings until they recover. The
10
+ * ladder is two rungs — healthy -> degraded, latched until a success — which
11
+ * for a relay is what awewarm's deeper ladder collapses to: its intermediate
12
+ * rungs trade probe expense against recovery speed, and a relay's probes are
13
+ * cheap pings, not quota-consuming activations. What does carry over from
14
+ * awewarm is the escalating probe schedule above: the longer a backend has
15
+ * been continuously degraded, the quieter its recovery probes become, down
16
+ * to a daily last gasp that never fully gives up.
6
17
  */
7
18
  export declare class HealthGate {
19
+ private readonly now;
8
20
  private consecutive;
9
21
  private degraded;
10
- record(backendId: string, ok: boolean, reason?: FailureReason): void;
22
+ private degradedSince;
23
+ private probeDelayMs;
24
+ private probeNotBefore;
25
+ /** The clock is injected so tests can walk the cap ladder without waiting. */
26
+ constructor(now?: () => number);
27
+ record(backendId: string, ok: boolean, reason?: FailureReason): HealthTransition;
28
+ /** Epoch ms before which a recovery probe for this backend should be
29
+ * skipped (backoff); 0 when no failed probe is being held back. */
30
+ probeNotBeforeMs(backendId: string): number;
11
31
  isDegraded(backendId: string): boolean;
12
32
  statusMap(): Record<string, BackendStatus>;
13
33
  }
34
+ /** Log a ladder transition where it happened — the request path or a probe
35
+ * loop — so "why is it still degraded" is answerable from the logs. */
36
+ export declare function logHealthTransition(log: Logger, backendId: string, transition: HealthTransition, detail?: string): void;
14
37
  /** Map an upstream HTTP status to a failure class (ok responses pass null). */
15
38
  export declare function classifyStatus(status: number): FailureReason | null;
@@ -1,26 +1,89 @@
1
1
  /** AUTH/QUOTA consecutive failures >= threshold -> degraded until a success. */
2
2
  const DEGRADE_THRESHOLD = 2;
3
+ // Recovery-probe backoff, awewarm-style: while degraded, each failed probe
4
+ // doubles the wait before the next one, so an exhausted quota isn't pinged at
5
+ // the base cadence for hours on end. Any success clears the degraded state
6
+ // and the backoff with it. Unlike awewarm — whose probes are quota-consuming
7
+ // activations that must back off a full window — a relay's probes are free
8
+ // pings, so the cap escalates with how long the backend has stayed degraded
9
+ // rather than jumping straight to window-length silence:
10
+ // < 15h cap 5min covers ~3 GLM 5h-window rolls: refresh picked up fast
11
+ // < 45h cap 1h not a window roll anymore — likely needs a human
12
+ // < 105h cap 6h long dead; quiet but still self-healing
13
+ // else cap 24h daily last gasp, keeps auto-recovery alive forever
14
+ const PROBE_BACKOFF_BASE_MS = 30_000;
15
+ const PROBE_FALLBACK_CAP_MS = 24 * 3_600_000;
16
+ const PROBE_CAP_SCHEDULE = [
17
+ { afterMs: 15 * 3_600_000, capMs: 5 * 60_000 },
18
+ { afterMs: 45 * 3_600_000, capMs: 3_600_000 },
19
+ { afterMs: 105 * 3_600_000, capMs: 6 * 3_600_000 },
20
+ { afterMs: Number.POSITIVE_INFINITY, capMs: PROBE_FALLBACK_CAP_MS },
21
+ ];
3
22
  /**
4
23
  * Per-backend health state. Degraded backends are reported in heartbeats and
5
- * the hub stops dispatching to their offerings until they recover.
24
+ * the hub stops dispatching to their offerings until they recover. The
25
+ * ladder is two rungs — healthy -> degraded, latched until a success — which
26
+ * for a relay is what awewarm's deeper ladder collapses to: its intermediate
27
+ * rungs trade probe expense against recovery speed, and a relay's probes are
28
+ * cheap pings, not quota-consuming activations. What does carry over from
29
+ * awewarm is the escalating probe schedule above: the longer a backend has
30
+ * been continuously degraded, the quieter its recovery probes become, down
31
+ * to a daily last gasp that never fully gives up.
6
32
  */
7
33
  export class HealthGate {
34
+ now;
8
35
  consecutive = new Map();
9
36
  degraded = new Map();
37
+ degradedSince = new Map();
38
+ probeDelayMs = new Map();
39
+ probeNotBefore = new Map();
40
+ /** The clock is injected so tests can walk the cap ladder without waiting. */
41
+ constructor(now = Date.now) {
42
+ this.now = now;
43
+ }
10
44
  record(backendId, ok, reason) {
11
45
  if (ok) {
12
46
  this.consecutive.delete(backendId);
13
- this.degraded.delete(backendId);
14
- return;
47
+ const wasDegraded = this.degraded.delete(backendId);
48
+ this.degradedSince.delete(backendId);
49
+ this.probeDelayMs.delete(backendId);
50
+ this.probeNotBefore.delete(backendId);
51
+ return wasDegraded ? 'recovered' : null;
15
52
  }
16
53
  if (reason === undefined || reason === 'CANCELLED')
17
- return;
54
+ return null;
55
+ // failures recorded while already degraded are probe outcomes (admission
56
+ // 503s before dialing, so real traffic can't add any) — back the next
57
+ // probe off. The failure that causes the degradation does not: the first
58
+ // probe should stay immediate so a just-refreshed quota or a fresh login
59
+ // is picked up on the next tick.
60
+ const wasDegraded = this.degraded.has(backendId);
18
61
  const current = this.consecutive.get(backendId);
19
62
  const count = current?.reason === reason ? current.count + 1 : 1;
20
63
  this.consecutive.set(backendId, { reason, count });
64
+ let transition = null;
21
65
  if ((reason === 'AUTH' || reason === 'QUOTA') && count >= DEGRADE_THRESHOLD) {
66
+ if (!wasDegraded) {
67
+ transition = 'degraded';
68
+ this.degradedSince.set(backendId, this.now());
69
+ }
22
70
  this.degraded.set(backendId, { state: 'degraded', reason });
23
71
  }
72
+ if (wasDegraded) {
73
+ const since = this.degradedSince.get(backendId) ?? this.now();
74
+ // The final tier is Infinity, so the fallback is only a type-safe guard.
75
+ const cap = PROBE_CAP_SCHEDULE.find((tier) => this.now() - since < tier.afterMs)?.capMs ??
76
+ PROBE_FALLBACK_CAP_MS;
77
+ const delay = Math.min((this.probeDelayMs.get(backendId) ?? PROBE_BACKOFF_BASE_MS / 2) * 2, cap);
78
+ this.probeDelayMs.set(backendId, delay);
79
+ this.probeNotBefore.set(backendId, this.now() + delay);
80
+ }
81
+ return transition;
82
+ }
83
+ /** Epoch ms before which a recovery probe for this backend should be
84
+ * skipped (backoff); 0 when no failed probe is being held back. */
85
+ probeNotBeforeMs(backendId) {
86
+ return this.probeNotBefore.get(backendId) ?? 0;
24
87
  }
25
88
  isDegraded(backendId) {
26
89
  return this.degraded.has(backendId);
@@ -32,6 +95,16 @@ export class HealthGate {
32
95
  return out;
33
96
  }
34
97
  }
98
+ /** Log a ladder transition where it happened — the request path or a probe
99
+ * loop — so "why is it still degraded" is answerable from the logs. */
100
+ export function logHealthTransition(log, backendId, transition, detail) {
101
+ if (transition === 'degraded') {
102
+ log.warn(`backend ${backendId} degraded${detail ? ` (${detail})` : ''}`);
103
+ }
104
+ else if (transition === 'recovered') {
105
+ log.info(`backend ${backendId} recovered${detail ? ` — ${detail}` : ''}`);
106
+ }
107
+ }
35
108
  /** Map an upstream HTTP status to a failure class (ok responses pass null). */
36
109
  export function classifyStatus(status) {
37
110
  if (status < 400)
@@ -1 +1 @@
1
- {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAIA,gFAAgF;AAChF,MAAM,iBAAiB,GAAG,CAAC,CAAA;AAE3B;;;GAGG;AACH,MAAM,OAAO,UAAU;IACb,WAAW,GAAG,IAAI,GAAG,EAAoD,CAAA;IACzE,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAA;IAEnD,MAAM,CAAC,SAAiB,EAAE,EAAW,EAAE,MAAsB;QAC3D,IAAI,EAAE,EAAE,CAAC;YACP,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAC/B,OAAM;QACR,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,WAAW;YAAE,OAAM;QAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAChE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QAClD,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,CAAC,IAAI,KAAK,IAAI,iBAAiB,EAAE,CAAC;YAC5E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAA;QAC7D,CAAC;IACH,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;IAED,SAAS;QACP,MAAM,GAAG,GAAkC,EAAE,CAAA;QAC7C,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ;YAAE,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAA;QAC1D,OAAO,GAAG,CAAA;IACZ,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,MAAM,GAAG,GAAG;QAAE,OAAO,IAAI,CAAA;IAC7B,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,MAAM,CAAA;IACnD,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,OAAO,CAAA;IACpD,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"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"}
@@ -4,3 +4,4 @@ export * from './credentials.js';
4
4
  export * from './health.js';
5
5
  export * from './job.js';
6
6
  export * from './probe.js';
7
+ export * from './proxy.js';
@@ -4,4 +4,5 @@ export * from './credentials.js';
4
4
  export * from './health.js';
5
5
  export * from './job.js';
6
6
  export * from './probe.js';
7
+ export * from './proxy.js';
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
@@ -1,6 +1,7 @@
1
- import { buildUpstreamRequest, forceStoreFalse, } from './adapters.js';
1
+ import { buildUpstreamRequest, prepareCodexBody, } from './adapters.js';
2
2
  import { CredentialError, invalidateCodexCredentials } from './credentials.js';
3
- import { classifyStatus } from './health.js';
3
+ import { classifyStatus, logHealthTransition } from './health.js';
4
+ import { codexNetworkHint, fetchUpstream } from './proxy.js';
4
5
  /** Thrown by a sink whose transport died (e.g. a closed tunnel socket): the
5
6
  * job stops silently — no health record, no error frame nobody would read. */
6
7
  export class SinkClosedError extends Error {
@@ -40,8 +41,8 @@ export class UpstreamJob {
40
41
  // inside the try: a malformed URL must flow to sink.error like any other
41
42
  // failure — execute() must never reject
42
43
  const { url, headers } = buildUpstreamRequest(backend, init);
43
- const body = backend.login !== undefined ? forceStoreFalse(init.body) : init.body;
44
- const resp = await fetch(url, {
44
+ const body = backend.login !== undefined ? prepareCodexBody(init.body) : init.body;
45
+ const resp = await fetchUpstream(backend, url, {
45
46
  method: init.method,
46
47
  headers,
47
48
  // GET/HEAD must carry no body, even an empty one
@@ -52,7 +53,7 @@ export class UpstreamJob {
52
53
  clearTimeout(connectTimer);
53
54
  log.debug(`request ${id} upstream ${backend.id} -> ${resp.status}`);
54
55
  const reason = classifyStatus(resp.status);
55
- health.record(backend.id, reason === null, reason ?? undefined);
56
+ logHealthTransition(log, backend.id, health.record(backend.id, reason === null, reason ?? undefined), `upstream ${resp.status}`);
56
57
  // a 401 on a login backend means the token rotated or expired; drop the
57
58
  // cached login so the next request re-reads auth.json
58
59
  if (resp.status === 401 && backend.login !== undefined)
@@ -80,14 +81,14 @@ export class UpstreamJob {
80
81
  // an unreadable login is an auth failure, not a network one: two in a
81
82
  // row degrade the backend like any other AUTH loss
82
83
  log.warn(`request ${id} upstream ${backend.id}: ${err.message}`);
83
- health.record(backend.id, false, 'AUTH');
84
+ logHealthTransition(log, backend.id, health.record(backend.id, false, 'AUTH'));
84
85
  sink.error('BACKEND_LOGIN', err.message);
85
86
  return;
86
87
  }
87
88
  const timedOut = err instanceof ConnectTimeoutError;
88
89
  log.warn(`request ${id} upstream ${backend.id} failed: ${err instanceof Error ? err.message : err}`);
89
- health.record(backend.id, false, 'NETWORK');
90
- sink.error(timedOut ? 'BACKEND_TIMEOUT' : 'BACKEND_UNREACHABLE', `upstream ${backend.id} failed: ${err instanceof Error ? err.message : String(err)}`);
90
+ logHealthTransition(log, backend.id, health.record(backend.id, false, 'NETWORK'), err instanceof Error ? err.message : undefined);
91
+ sink.error(timedOut ? 'BACKEND_TIMEOUT' : 'BACKEND_UNREACHABLE', `upstream ${backend.id} failed: ${err instanceof Error ? err.message : String(err)}${codexNetworkHint(backend)}`);
91
92
  }
92
93
  }
93
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"job.js","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"job.js","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ResolvedBackend } from './adapters.js';
2
+ export interface CodexProxyOptions {
3
+ httpProxy?: string;
4
+ httpsProxy?: string;
5
+ noProxy?: string;
6
+ source: 'HTTP_PROXY' | 'HTTPS_PROXY' | 'ALL_PROXY';
7
+ }
8
+ /** Proxy settings for the official Codex account upstream only.
9
+ *
10
+ * EnvHttpProxyAgent implements HTTP_PROXY/HTTPS_PROXY/NO_PROXY matching. We
11
+ * also accept ALL_PROXY because coding-agent proxy setups commonly provide it.
12
+ * SOCKS URLs are deliberately ignored: the producer has no SOCKS dependency,
13
+ * and silently treating one as HTTP would send account traffic incorrectly.
14
+ */
15
+ export declare function codexProxyOptions(backend: Pick<ResolvedBackend, 'login'>, env?: NodeJS.ProcessEnv): CodexProxyOptions | null;
16
+ /** Fetch an upstream request, honoring proxy environment variables only for a
17
+ * producer machine's Codex subscription login. */
18
+ export declare function fetchUpstream(backend: Pick<ResolvedBackend, 'login'>, url: string, init: RequestInit): Promise<Response>;
19
+ /** A safe, actionable suffix for network errors. Never include proxy URLs:
20
+ * they can contain credentials. */
21
+ export declare function codexNetworkHint(backend: Pick<ResolvedBackend, 'login'>): string;
@@ -0,0 +1,77 @@
1
+ import { EnvHttpProxyAgent } from 'undici';
2
+ let cachedRoute;
3
+ let cachedSignature;
4
+ function envValue(env, lower, upper) {
5
+ // Match the conventional lower-case precedence used by proxy-aware clients.
6
+ return env[lower] ?? env[upper];
7
+ }
8
+ function httpProxy(value) {
9
+ if (!value)
10
+ return undefined;
11
+ try {
12
+ const protocol = new URL(value).protocol;
13
+ return protocol === 'http:' || protocol === 'https:' ? value : undefined;
14
+ }
15
+ catch {
16
+ return undefined;
17
+ }
18
+ }
19
+ /** Proxy settings for the official Codex account upstream only.
20
+ *
21
+ * EnvHttpProxyAgent implements HTTP_PROXY/HTTPS_PROXY/NO_PROXY matching. We
22
+ * also accept ALL_PROXY because coding-agent proxy setups commonly provide it.
23
+ * SOCKS URLs are deliberately ignored: the producer has no SOCKS dependency,
24
+ * and silently treating one as HTTP would send account traffic incorrectly.
25
+ */
26
+ export function codexProxyOptions(backend, env = process.env) {
27
+ if (backend.login !== 'codex')
28
+ return null;
29
+ const all = httpProxy(envValue(env, 'all_proxy', 'ALL_PROXY'));
30
+ const configuredHttp = httpProxy(envValue(env, 'http_proxy', 'HTTP_PROXY'));
31
+ const configuredHttps = httpProxy(envValue(env, 'https_proxy', 'HTTPS_PROXY'));
32
+ const http = configuredHttp ?? all;
33
+ const https = configuredHttps ?? all;
34
+ if (!http && !https)
35
+ return null;
36
+ const source = configuredHttps ? 'HTTPS_PROXY' : configuredHttp ? 'HTTP_PROXY' : 'ALL_PROXY';
37
+ return {
38
+ httpProxy: http,
39
+ httpsProxy: https,
40
+ noProxy: envValue(env, 'no_proxy', 'NO_PROXY'),
41
+ source,
42
+ };
43
+ }
44
+ function codexProxyRoute(backend) {
45
+ const options = codexProxyOptions(backend);
46
+ const signature = options ? JSON.stringify(options) : '';
47
+ if (cachedSignature === signature && cachedRoute !== undefined)
48
+ return cachedRoute;
49
+ cachedSignature = signature;
50
+ cachedRoute = options
51
+ ? { dispatcher: new EnvHttpProxyAgent(options), source: options.source }
52
+ : null;
53
+ return cachedRoute;
54
+ }
55
+ /** Fetch an upstream request, honoring proxy environment variables only for a
56
+ * producer machine's Codex subscription login. */
57
+ export async function fetchUpstream(backend, url, init) {
58
+ const route = codexProxyRoute(backend);
59
+ if (!route)
60
+ return fetch(url, init);
61
+ // Node's built-in fetch honors undici dispatchers at runtime, but its DOM
62
+ // RequestInit declaration does not expose the undici extension yet. Keeping
63
+ // global fetch preserves the existing test seam and all non-proxy behavior.
64
+ const options = { ...init, dispatcher: route.dispatcher };
65
+ return fetch(url, options);
66
+ }
67
+ /** A safe, actionable suffix for network errors. Never include proxy URLs:
68
+ * they can contain credentials. */
69
+ export function codexNetworkHint(backend) {
70
+ if (backend.login !== 'codex')
71
+ return '';
72
+ const route = codexProxyRoute(backend);
73
+ return route
74
+ ? ` (Codex account request used ${route.source}; check that its HTTP(S) proxy is reachable)`
75
+ : ' (Codex account request went direct; set HTTPS_PROXY, HTTP_PROXY, or ALL_PROXY if ChatGPT requires a proxy)';
76
+ }
77
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
@@ -2,4 +2,5 @@ export * from './alias.js';
2
2
  export * from './errors.js';
3
3
  export * from './frames.js';
4
4
  export * from './messages.js';
5
+ export * from './models.js';
5
6
  export * from './tokens.js';
@@ -2,5 +2,6 @@ export * from './alias.js';
2
2
  export * from './errors.js';
3
3
  export * from './frames.js';
4
4
  export * from './messages.js';
5
+ export * from './models.js';
5
6
  export * from './tokens.js';
6
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Model honesty: an offering's declared `upstreamModel` is only the producer's
3
+ * claim. A response-reported model id is useful consistency evidence, not
4
+ * proof of the underlying weights. selfReportedModel extracts that bounded
5
+ * id and compareModels classifies it against the declaration.
6
+ */
7
+ export type ModelComparison = 'exact' | 'compatible' | 'mismatch' | 'insufficient';
8
+ /**
9
+ * Compare response metadata with the declaration. Exact normalized ids and
10
+ * explicit revision suffixes are affirmative evidence; a less-specific
11
+ * response is insufficient, while adjacent named variants are mismatches.
12
+ */
13
+ export declare function compareModels(declared: string, observed: string): ModelComparison;
14
+ /** Backward-compatible boolean used by existing renderers. Only affirmative
15
+ * evidence is a match; insufficient evidence is never shown as verified. */
16
+ export declare function modelsMatch(declared: string, observed: string): boolean;
17
+ /**
18
+ * The model id a response names about itself in one payload,
19
+ * whichever wire shape carries it: OpenAI top-level `model`, Anthropic
20
+ * `message.model` (message_start), Responses `response.model`. Null when the
21
+ * payload names no model.
22
+ */
23
+ export declare function selfReportedModel(payload: Record<string, unknown>): string | null;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Model honesty: an offering's declared `upstreamModel` is only the producer's
3
+ * claim. A response-reported model id is useful consistency evidence, not
4
+ * proof of the underlying weights. selfReportedModel extracts that bounded
5
+ * id and compareModels classifies it against the declaration.
6
+ */
7
+ /** Response-reported ids are persisted and rendered in operator terminals.
8
+ * Keep that untrusted value bounded and free of control characters. */
9
+ const safeModelId = (id) => id.length > 0 && id.length <= 256 && /^[a-z0-9][a-z0-9._:/-]*$/i.test(id);
10
+ /** Casing and separators vary across otherwise identical ids. Preserve token
11
+ * boundaries, though: deleting them would make gpt-4 and gpt-4o look alike. */
12
+ const canonicalModelId = (id) => id
13
+ .toLowerCase()
14
+ .replace(/[._:]+/g, '-')
15
+ .replace(/-+/g, '-')
16
+ .replace(/^-|-$/g, '');
17
+ /** A response may prefix the id with its vendor (`openai/gpt-4o`). Compare
18
+ * both the full id and the last path component; no arbitrary substring match. */
19
+ const candidates = (id) => {
20
+ if (!safeModelId(id))
21
+ return [];
22
+ const full = canonicalModelId(id);
23
+ const leaf = canonicalModelId(id.split('/').at(-1) ?? '');
24
+ return [...new Set([full, leaf].filter(Boolean))];
25
+ };
26
+ /** Explicit revision suffixes that preserve the model family: YYYY, MMDD,
27
+ * YYYYMMDD or a separated date. Names such as mini/o/sonnet are variants. */
28
+ const isRevisionOf = (family, versioned) => {
29
+ if (!versioned.startsWith(`${family}-`))
30
+ return false;
31
+ const suffix = versioned.slice(family.length + 1);
32
+ return /^\d{4,8}$/.test(suffix) || /^\d{4}-\d{2}(?:-\d{2})?$/.test(suffix);
33
+ };
34
+ /**
35
+ * Compare response metadata with the declaration. Exact normalized ids and
36
+ * explicit revision suffixes are affirmative evidence; a less-specific
37
+ * response is insufficient, while adjacent named variants are mismatches.
38
+ */
39
+ export function compareModels(declared, observed) {
40
+ const declaredIds = candidates(declared);
41
+ const observedIds = candidates(observed);
42
+ if (declaredIds.length === 0 || observedIds.length === 0)
43
+ return 'insufficient';
44
+ if (declaredIds.some((a) => observedIds.includes(a)))
45
+ return 'exact';
46
+ if (declaredIds.some((a) => observedIds.some((b) => isRevisionOf(a, b)))) {
47
+ return 'compatible';
48
+ }
49
+ if (observedIds.some((b) => declaredIds.some((a) => isRevisionOf(b, a)))) {
50
+ return 'insufficient';
51
+ }
52
+ return 'mismatch';
53
+ }
54
+ /** Backward-compatible boolean used by existing renderers. Only affirmative
55
+ * evidence is a match; insufficient evidence is never shown as verified. */
56
+ export function modelsMatch(declared, observed) {
57
+ const result = compareModels(declared, observed);
58
+ return result === 'exact' || result === 'compatible';
59
+ }
60
+ /**
61
+ * The model id a response names about itself in one payload,
62
+ * whichever wire shape carries it: OpenAI top-level `model`, Anthropic
63
+ * `message.model` (message_start), Responses `response.model`. Null when the
64
+ * payload names no model.
65
+ */
66
+ export function selfReportedModel(payload) {
67
+ const message = payload.message;
68
+ const response = payload.response;
69
+ const candidate = payload.model ?? message?.model ?? response?.model;
70
+ return typeof candidate === 'string' && safeModelId(candidate) ? candidate : null;
71
+ }
72
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;uEACuE;AACvE,MAAM,WAAW,GAAG,CAAC,EAAU,EAAW,EAAE,CAC1C,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,GAAG,IAAI,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAE3E;+EAC+E;AAC/E,MAAM,gBAAgB,GAAG,CAAC,EAAU,EAAU,EAAE,CAC9C,EAAE;KACC,WAAW,EAAE;KACb,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;KACvB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;KACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;AAE1B;iFACiF;AACjF,MAAM,UAAU,GAAG,CAAC,EAAU,EAAY,EAAE;IAC1C,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,CAAA;IAC/B,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IACjC,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IACzD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AACnD,CAAC,CAAA;AAED;6EAC6E;AAC7E,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,SAAiB,EAAW,EAAE;IAClE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACjD,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AAC5E,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,QAAgB;IAC9D,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACxC,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACxC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,cAAc,CAAA;IAC/E,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,OAAO,CAAA;IACpE,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO,YAAY,CAAA;IACrB,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO,cAAc,CAAA;IACvB,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;4EAC4E;AAC5E,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,QAAgB;IAC5D,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAChD,OAAO,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,YAAY,CAAA;AACtD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgC;IAChE,MAAM,OAAO,GAAG,OAAO,CAAC,OAA8C,CAAA;IACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAA+C,CAAA;IACxE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,KAAK,CAAA;IACpE,OAAO,OAAO,SAAS,KAAK,QAAQ,IAAI,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;AACnF,CAAC"}