@open-autonomy/sdk 2.3.1 → 2.3.2
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/package.json +1 -1
- package/src/rails.ts +45 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-autonomy/sdk",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "The Open Autonomy SDK: the roadmap model and its codec, the development-stream client (sessions, turns, updates), and the key helpers. Everything it does is a documented HTTP wire any language can speak without it.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
package/src/rails.ts
CHANGED
|
@@ -72,21 +72,56 @@ export function parseModelsBound(yaml: string): string[] {
|
|
|
72
72
|
return out;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
// The
|
|
75
|
+
// The limits the project's funds run under on the model rail, from the same file — the shape a provider's rate
|
|
76
|
+
// limits and a budget's period share: each limit is one measure over one window, rolling.
|
|
76
77
|
// spend:
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
// limits:
|
|
79
|
+
// - { window: 1d, usd_cents: 500 } # the money: cents over the window
|
|
80
|
+
// - { window: 30d, usd_cents: 6000 }
|
|
81
|
+
// - { window: 1m, calls: 60 } # the pace: requests over the window
|
|
82
|
+
// - { window: 1h, tokens: 2000000 } # the volume: tokens in and out over the window
|
|
83
|
+
// - { window: 1d, usd_cents: 100, model: openai/gpt-5 } # one model's own budget
|
|
84
|
+
// Windows: N m (minutes, up to 60), N h (hours, up to 24), N d (days, up to 31). Every limit holds at once; the platform
|
|
85
|
+
// refuses the call that would cross one and says which. None: no bound of the project's own beyond the platform's rail.
|
|
86
|
+
export interface SpendLimit { window: string; window_seconds: number; usd_cents?: number; calls?: number; tokens?: number; model?: string }
|
|
87
|
+
export function parseWindow(spec: string): number | undefined {
|
|
88
|
+
const m = /^(\d+)\s*(m|h|d)$/.exec(spec.trim());
|
|
89
|
+
if (!m) return undefined;
|
|
90
|
+
const n = Number(m[1]); const unit = { m: 60, h: 3600, d: 86400 }[m[2] as 'm' | 'h' | 'd'];
|
|
91
|
+
const max = { m: 60, h: 24, d: 31 }[m[2] as 'm' | 'h' | 'd'];
|
|
92
|
+
return n >= 1 && n <= max ? n * unit : undefined;
|
|
93
|
+
}
|
|
94
|
+
export function parseSpendLimits(yaml: string): SpendLimit[] {
|
|
95
|
+
const out: SpendLimit[] = [];
|
|
96
|
+
let block = ''; let inLimits = false; let item: Record<string, string> | null = null;
|
|
97
|
+
const flush = () => {
|
|
98
|
+
if (!item) return;
|
|
99
|
+
const seconds = item.window ? parseWindow(item.window) : undefined;
|
|
100
|
+
const num = (k: string) => (item![k] !== undefined && /^\d+$/.test(item![k]) ? Number(item![k]) : undefined);
|
|
101
|
+
const limit: SpendLimit = { window: (item.window ?? '').trim(), window_seconds: seconds ?? 0 };
|
|
102
|
+
if (num('usd_cents') !== undefined) limit.usd_cents = num('usd_cents');
|
|
103
|
+
if (num('calls') !== undefined) limit.calls = num('calls');
|
|
104
|
+
if (num('tokens') !== undefined) limit.tokens = num('tokens');
|
|
105
|
+
if (item.model) limit.model = item.model.trim().replace(/^["']|["']$/g, '');
|
|
106
|
+
if (seconds && (limit.usd_cents !== undefined || limit.calls !== undefined || limit.tokens !== undefined)) out.push(limit);
|
|
107
|
+
item = null;
|
|
108
|
+
};
|
|
109
|
+
const pairs = (text: string): Record<string, string> => Object.fromEntries(text.split(',').map((kv) => kv.split(':')).filter((kv) => kv.length >= 2).map(([k, ...v]) => [k.trim(), v.join(':').trim().replace(/^["']|["']$/g, '')]));
|
|
82
110
|
for (const raw of yaml.split('\n')) {
|
|
83
111
|
const line = raw.replace(/\s+#.*$/, '').trimEnd();
|
|
84
112
|
if (!line.trim() || line.trim().startsWith('#')) continue;
|
|
85
113
|
const top = /^([a-z_]+):\s*(.*)$/.exec(line);
|
|
86
|
-
if (top) { block = top[2] === '' ? top[1] : ''; continue; }
|
|
114
|
+
if (top) { flush(); block = top[2] === '' ? top[1] : ''; inLimits = false; continue; }
|
|
87
115
|
if (block !== 'spend') continue;
|
|
88
|
-
|
|
89
|
-
if (
|
|
116
|
+
if (/^ limits:\s*$/.test(line)) { flush(); inLimits = true; continue; }
|
|
117
|
+
if (!inLimits) continue;
|
|
118
|
+
const flow = /^\s+-\s*\{(.*)\}\s*$/.exec(line);
|
|
119
|
+
if (flow) { flush(); item = pairs(flow[1]); flush(); continue; }
|
|
120
|
+
const start = /^\s+-\s+([a-z_]+):\s*(.+)$/.exec(line);
|
|
121
|
+
if (start) { flush(); item = { [start[1]]: start[2].trim() }; continue; }
|
|
122
|
+
const more = item ? /^\s+([a-z_]+):\s*(.+)$/.exec(line) : null;
|
|
123
|
+
if (more) item![more[1]] = more[2].trim();
|
|
90
124
|
}
|
|
91
|
-
|
|
125
|
+
flush();
|
|
126
|
+
return out;
|
|
92
127
|
}
|