@contraagent/api 0.0.0-stage → 0.1.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 (72) hide show
  1. package/README.md +102 -2
  2. package/dist/client.d.ts +54 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +68 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/derive.d.ts +81 -0
  7. package/dist/derive.d.ts.map +1 -0
  8. package/dist/derive.js +89 -0
  9. package/dist/derive.js.map +1 -0
  10. package/dist/export.d.ts +36 -0
  11. package/dist/export.d.ts.map +1 -0
  12. package/dist/export.js +130 -0
  13. package/dist/export.js.map +1 -0
  14. package/dist/feed.d.ts +27 -0
  15. package/dist/feed.d.ts.map +1 -0
  16. package/dist/feed.js +39 -0
  17. package/dist/feed.js.map +1 -0
  18. package/dist/index.d.ts +13 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +13 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/outcomes.d.ts +117 -0
  23. package/dist/outcomes.d.ts.map +1 -0
  24. package/dist/outcomes.js +201 -0
  25. package/dist/outcomes.js.map +1 -0
  26. package/dist/panels.d.ts +31 -0
  27. package/dist/panels.d.ts.map +1 -0
  28. package/dist/panels.js +12 -0
  29. package/dist/panels.js.map +1 -0
  30. package/dist/quota.d.ts +32 -0
  31. package/dist/quota.d.ts.map +1 -0
  32. package/dist/quota.js +46 -0
  33. package/dist/quota.js.map +1 -0
  34. package/dist/reasons.d.ts +25 -0
  35. package/dist/reasons.d.ts.map +1 -0
  36. package/dist/reasons.js +46 -0
  37. package/dist/reasons.js.map +1 -0
  38. package/dist/run-state.d.ts +62 -0
  39. package/dist/run-state.d.ts.map +1 -0
  40. package/dist/run-state.js +109 -0
  41. package/dist/run-state.js.map +1 -0
  42. package/dist/schema.d.ts +3718 -0
  43. package/dist/schema.d.ts.map +1 -0
  44. package/dist/schema.js +3 -0
  45. package/dist/schema.js.map +1 -0
  46. package/dist/spend.d.ts +46 -0
  47. package/dist/spend.d.ts.map +1 -0
  48. package/dist/spend.js +68 -0
  49. package/dist/spend.js.map +1 -0
  50. package/dist/store.d.ts +121 -0
  51. package/dist/store.d.ts.map +1 -0
  52. package/dist/store.js +286 -0
  53. package/dist/store.js.map +1 -0
  54. package/dist/types.d.ts +112 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +19 -0
  57. package/dist/types.js.map +1 -0
  58. package/package.json +43 -4
  59. package/src/client.ts +119 -0
  60. package/src/derive.ts +155 -0
  61. package/src/export.ts +158 -0
  62. package/src/feed.ts +81 -0
  63. package/src/index.ts +12 -0
  64. package/src/outcomes.ts +267 -0
  65. package/src/panels.ts +51 -0
  66. package/src/quota.ts +78 -0
  67. package/src/reasons.ts +57 -0
  68. package/src/run-state.ts +166 -0
  69. package/src/schema.ts +3719 -0
  70. package/src/spend.ts +108 -0
  71. package/src/store.ts +338 -0
  72. package/src/types.ts +165 -0
package/dist/store.js ADDED
@@ -0,0 +1,286 @@
1
+ // The monitor's data, live: the run list, the selected run's feed folded into a
2
+ // `RunState`, and a change notification. No UI framework: a Lit controller, a
3
+ // React hook or plain code can subscribe alike.
4
+ import { ApiError, createMonitorClient } from './client.js';
5
+ import { openRunFeed } from './feed.js';
6
+ import { emptyRunState, reduceRun, rowId } from './run-state.js';
7
+ import { isRunPanel } from './panels.js';
8
+ const DEFAULT_INFO = { title: 'contraagent', panels: [], api_version: '' };
9
+ /** A client given in the options may throw something else: it counts as no response from `url`. */
10
+ const asApiError = (e, url) => (e instanceof ApiError ? e : new ApiError(url, 'network'));
11
+ export class MonitorStore {
12
+ constructor(opts = {}) {
13
+ this.snap = {
14
+ info: DEFAULT_INFO,
15
+ runs: [],
16
+ hosts: null,
17
+ run: '',
18
+ state: emptyRunState(),
19
+ connected: false,
20
+ fresh: new Set(),
21
+ runsLoaded: false,
22
+ error: null,
23
+ trends: null,
24
+ };
25
+ /** The trends asked for last (`loadTrends`), kept fresh with the run list; null: none. */
26
+ this.trendsQuery = null;
27
+ /** Counts the trend requests: an answer to an older one is dropped. */
28
+ this.trendsAsked = 0;
29
+ /** The run list's records (`runsKey`) the trends shown were asked over: a refresh asks again only when they changed. */
30
+ this.trendsOver = null;
31
+ /** A refresh is under way: a call meanwhile does nothing, and the next one is scheduled after it ends. */
32
+ this.refreshing = false;
33
+ /** A trends request a refresh started is under way: no second one until it ends. */
34
+ this.trendsBusy = false;
35
+ /** Why the last request for `info`, for `runs`, and for `hosts` got no answer. */
36
+ this.infoError = null;
37
+ this.runsError = null;
38
+ this.hostsError = null;
39
+ this.infoLoaded = false;
40
+ this.stopped = false;
41
+ this.listeners = new Set();
42
+ this.rowListeners = new Set();
43
+ this.closeFeed = null;
44
+ this.queue = [];
45
+ this.flushTimer = null;
46
+ this.pollTimer = null;
47
+ this.opts = { runsEveryMs: 5000, batchMs: 50, freshMs: 4000, ...opts };
48
+ this.client = opts.client ?? createMonitorClient(opts.baseUrl === undefined ? {} : { baseUrl: opts.baseUrl });
49
+ }
50
+ get snapshot() {
51
+ return this.snap;
52
+ }
53
+ /** Called on every change, with the new snapshot. */
54
+ subscribe(fn) {
55
+ this.listeners.add(fn);
56
+ return () => this.listeners.delete(fn);
57
+ }
58
+ /** Called for each journal row that arrives after the replay: a task that just finished. */
59
+ onNewRow(fn) {
60
+ this.rowListeners.add(fn);
61
+ return () => this.rowListeners.delete(fn);
62
+ }
63
+ /**
64
+ * Load the title, panels and run list, and keep the run list fresh. A request
65
+ * that gets no answer sets `error`; the title and panels are asked for again
66
+ * with each refresh until they arrive.
67
+ */
68
+ async start() {
69
+ this.stopped = false;
70
+ await this.refresh();
71
+ this.schedule();
72
+ }
73
+ /** The next refresh, `runsEveryMs` after this one ended: refreshes never overlap, however slow the answers. */
74
+ schedule() {
75
+ if (this.stopped || this.opts.runsEveryMs <= 0 || this.pollTimer)
76
+ return;
77
+ this.pollTimer = setTimeout(() => {
78
+ this.pollTimer = null;
79
+ void this.refresh().finally(() => this.schedule());
80
+ }, this.opts.runsEveryMs);
81
+ }
82
+ async refresh() {
83
+ if (this.refreshing)
84
+ return;
85
+ this.refreshing = true;
86
+ try {
87
+ if (!this.infoLoaded)
88
+ await this.loadInfo();
89
+ await this.refreshRuns();
90
+ }
91
+ finally {
92
+ this.refreshing = false;
93
+ }
94
+ // The trends are asked for again only when the runs' records or the trend panels (a
95
+ // panel list that arrived after them) changed, and not awaited here: a slow trend
96
+ // panel holds back no run list.
97
+ const query = this.trendsQuery;
98
+ if (query && !this.trendsBusy && !this.stopped && this.trendsKey() !== this.trendsOver) {
99
+ this.trendsBusy = true;
100
+ void this.fetchTrends(query).finally(() => (this.trendsBusy = false));
101
+ }
102
+ }
103
+ /** What the trends are made of, as far as the run list says: each run and its last record; and the trend panels asked for over them. */
104
+ trendsKey() {
105
+ const runs = this.snap.runs.map((r) => `${r.run}\t${r.last_ts}\t${r.attempts}`).join('\n');
106
+ return `${runs}\n\n${this.trendPanelNames().join('\n')}`;
107
+ }
108
+ trendPanelNames() {
109
+ return this.snap.info.panels.filter((p) => p.scope === 'trends').map((p) => p.name);
110
+ }
111
+ /**
112
+ * Load the trends of `query` (`/api/trends`) and the trend panels over it, and keep them
113
+ * fresh with the run list until `closeTrends`. The trends of another query stay shown
114
+ * until the new ones arrive (`loading`).
115
+ */
116
+ async loadTrends(query) {
117
+ const same = this.snap.trends && JSON.stringify(this.snap.trends.query) === JSON.stringify(query);
118
+ this.trendsQuery = query;
119
+ this.set({ trends: { query, data: same ? this.snap.trends.data : (this.snap.trends?.data ?? null), panels: same ? this.snap.trends.panels : {}, loading: true, error: null } });
120
+ await this.fetchTrends(query);
121
+ }
122
+ /** Stop keeping the trends fresh (the page left them). */
123
+ closeTrends() {
124
+ this.trendsQuery = null;
125
+ }
126
+ /**
127
+ * Ask for the trends of `query` and each trend panel over it. Each answer is shown as it
128
+ * arrives, so a slow panel holds back neither the trends nor another panel; an answer to
129
+ * an older request is dropped.
130
+ */
131
+ async fetchTrends(query) {
132
+ const asked = ++this.trendsAsked;
133
+ this.trendsOver = this.trendsKey();
134
+ const view = () => (asked === this.trendsAsked && !this.stopped ? this.snap.trends : null);
135
+ const names = this.trendPanelNames();
136
+ const trends = this.client.trends(query).then((data) => {
137
+ const v = view();
138
+ if (v)
139
+ this.set({ trends: { ...v, query, data, loading: false, error: null } });
140
+ }, (e) => {
141
+ const v = view();
142
+ if (v)
143
+ this.set({ trends: { ...v, query, loading: false, error: asApiError(e, `${this.client.baseUrl}/api/trends`) } });
144
+ });
145
+ const panel = (name, body) => {
146
+ const v = view();
147
+ if (v)
148
+ this.set({ trends: { ...v, panels: { ...v.panels, [name]: body } } });
149
+ };
150
+ const bodies = names.map((n) => this.client.trendsPanel(n, query).then((body) => panel(n, body), (e) => panel(n, { error: String(e) })));
151
+ await Promise.allSettled([trends, ...bodies]);
152
+ }
153
+ async loadInfo() {
154
+ try {
155
+ const before = this.panelNames();
156
+ const info = await this.client.info();
157
+ if (this.stopped)
158
+ return;
159
+ this.infoLoaded = true;
160
+ this.infoError = null;
161
+ this.set({ info });
162
+ // A run opened before the panel list arrived listens for no panel: open it again.
163
+ if (this.snap.run && this.panelNames() !== before)
164
+ this.reopen();
165
+ }
166
+ catch (e) {
167
+ this.infoError = asApiError(e, `${this.client.baseUrl}/api/info`);
168
+ }
169
+ }
170
+ /** Fetch the run list, and on a hub the host list beside it: both refresh together, so a run's host reads the same in both. */
171
+ async refreshRuns() {
172
+ const [runs, hosts] = await Promise.allSettled([this.client.runs(), this.snap.info.hosts ? this.client.hosts() : Promise.resolve(null)]);
173
+ if (this.stopped)
174
+ return;
175
+ // A failed request keeps the last list.
176
+ const patch = {};
177
+ if (runs.status === 'fulfilled') {
178
+ patch.runs = runs.value;
179
+ patch.runsLoaded = true;
180
+ this.runsError = null;
181
+ }
182
+ else
183
+ this.runsError = asApiError(runs.reason, `${this.client.baseUrl}/api/runs`);
184
+ if (hosts.status === 'fulfilled') {
185
+ patch.hosts = hosts.value;
186
+ this.hostsError = null;
187
+ }
188
+ else
189
+ this.hostsError = asApiError(hosts.reason, `${this.client.baseUrl}/api/hosts`);
190
+ const error = this.infoError ?? this.runsError ?? this.hostsError;
191
+ // The same failure again keeps the same `error`.
192
+ if (error?.message !== this.snap.error?.message)
193
+ patch.error = error;
194
+ if (Object.keys(patch).length)
195
+ this.set(patch);
196
+ }
197
+ panelNames() {
198
+ return this.snap.info.panels.filter(isRunPanel).map((p) => p.name).join('\n');
199
+ }
200
+ /** Open the current run's feed again (the server replays it from the start). */
201
+ reopen() {
202
+ const run = this.snap.run;
203
+ this.closeFeed?.();
204
+ this.closeFeed = null;
205
+ this.selectRun(run);
206
+ }
207
+ /** Open `run`'s feed (closing the previous one); '' closes it. */
208
+ selectRun(run) {
209
+ if (run === this.snap.run && (this.closeFeed || !run))
210
+ return;
211
+ this.closeFeed?.();
212
+ this.closeFeed = null;
213
+ this.queue = [];
214
+ this.set({ run, state: emptyRunState(), connected: false, fresh: new Set() });
215
+ if (!run)
216
+ return;
217
+ const panels = this.snap.info.panels.filter(isRunPanel).map((p) => p.name);
218
+ const on = {
219
+ open: () => {
220
+ this.push({ event: 'connected' });
221
+ this.set({ connected: true });
222
+ },
223
+ error: () => this.set({ connected: false }),
224
+ message: (msg) => this.push(msg),
225
+ };
226
+ this.closeFeed = this.opts.openRunFeed
227
+ ? this.opts.openRunFeed(run, panels, on)
228
+ : openRunFeed(run, panels, on, { ...(this.opts.baseUrl === undefined ? {} : { baseUrl: this.opts.baseUrl }), ...this.opts.feed });
229
+ }
230
+ /** Close the feed and stop refreshing; an answer that arrives later is dropped. */
231
+ stop() {
232
+ this.stopped = true;
233
+ this.closeFeed?.();
234
+ this.closeFeed = null;
235
+ if (this.pollTimer)
236
+ clearTimeout(this.pollTimer);
237
+ this.pollTimer = null;
238
+ if (this.flushTimer)
239
+ clearTimeout(this.flushTimer);
240
+ this.flushTimer = null;
241
+ }
242
+ push(a) {
243
+ this.queue.push(a);
244
+ this.flushTimer ??= setTimeout(() => this.flush(), this.opts.batchMs);
245
+ }
246
+ flush() {
247
+ this.flushTimer = null;
248
+ const batch = this.queue;
249
+ this.queue = [];
250
+ // Rows that arrive once the replay is over are new: announce them and mark them fresh.
251
+ let ready = this.snap.state.ready;
252
+ const fresh = [];
253
+ for (const a of batch) {
254
+ if (a.event === 'connected')
255
+ ready = false;
256
+ else if (a.event === 'ready')
257
+ ready = true;
258
+ else if (a.event === 'journal' && ready)
259
+ fresh.push(a.data);
260
+ }
261
+ const state = reduceRun(this.snap.state, batch);
262
+ if (!fresh.length) {
263
+ this.set({ state });
264
+ return;
265
+ }
266
+ const ids = new Set(this.snap.fresh);
267
+ for (const row of fresh)
268
+ ids.add(rowId(row));
269
+ this.set({ state, fresh: ids });
270
+ for (const row of fresh)
271
+ for (const fn of this.rowListeners)
272
+ fn(row);
273
+ setTimeout(() => {
274
+ const left = new Set(this.snap.fresh);
275
+ for (const row of fresh)
276
+ left.delete(rowId(row));
277
+ this.set({ fresh: left });
278
+ }, this.opts.freshMs);
279
+ }
280
+ set(patch) {
281
+ this.snap = { ...this.snap, ...patch };
282
+ for (const fn of this.listeners)
283
+ fn(this.snap);
284
+ }
285
+ }
286
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ import type { components } from './schema.js';
2
+ import type { PanelBody } from './panels.js';
3
+ type S = components['schemas'];
4
+ export type { components, paths } from './schema.js';
5
+ /** A JSON object whose keys a domain chooses (a panel's body, a contract file's content). */
6
+ export type JsonObject = Record<string, unknown>;
7
+ export type Info = S['Info'];
8
+ /** What an export holds (`Info.export`): set only when the monitor reads one. */
9
+ export type ExportInfo = S['ExportInfo'];
10
+ export type PanelInfo = S['PanelInfo'];
11
+ export type RunSummary = S['RunSummary'];
12
+ export type Hosts = S['Hosts'];
13
+ export type HostSummary = S['HostSummary'];
14
+ export type AccountQuota = S['AccountQuota'];
15
+ /** What the runs of a period add up to (`/api/trends`). */
16
+ export type Trends = S['Trends'];
17
+ export type TrendKind = S['TrendKind'];
18
+ export type TrendQuota = S['TrendQuota'];
19
+ export type TrendRun = S['TrendRun'];
20
+ /** Which runs `/api/trends` sums: days `from` to `to` (YYYY-MM-DD) in the time zone `tz`, of one `run_group`. */
21
+ export interface TrendsQuery {
22
+ from?: string;
23
+ to?: string;
24
+ tz?: string;
25
+ run_group?: string;
26
+ }
27
+ export type JournalRow = S['JournalRow'];
28
+ /** How one attempt ended (`JournalRow.stop`): a `Stop` of the Python package, or `skipped`. */
29
+ export type Stop = JournalRow['stop'];
30
+ export type Hop = S['Hop'];
31
+ export type SkippedHop = S['SkippedHop'];
32
+ /** Why a credential rests (a cap or the quota rule): what a `SkippedHop` and a `CredentialRest` share. */
33
+ export type Rest = Pick<S['SkippedHop'], 'credential' | 'window' | 'pct' | 'cap' | 'rule' | 'until'>;
34
+ export type TokenUsage = S['TokenUsage'];
35
+ export type QuotaReading = S['QuotaReading'];
36
+ export type JournalPage = S['JournalPage'];
37
+ export type Executor = NonNullable<S['PlanNode']['executor']>;
38
+ export type Plan = S['Plan'];
39
+ export type PlanNode = S['PlanNode'];
40
+ export type PlanGroup = S['PlanGroup'];
41
+ export type DeferralCause = S['DeferralCause'];
42
+ export type QuotaCap = S['QuotaCap'];
43
+ export type CredentialRest = S['CredentialRest'];
44
+ export type ModelUsage = S['ModelUsage'];
45
+ export type PreflightRecord = S['PreflightRecord'];
46
+ export type DroppedRoute = S['DroppedRoute'];
47
+ export type Substitution = S['Substitution'];
48
+ export type KeptKind = S['KeptKind'];
49
+ export type TaskState = PlanNode['state'];
50
+ export type Frame = S['Frame'];
51
+ export type Loop = S['Loop'];
52
+ export type FlowCallNode = S['FlowCallNode'];
53
+ export type FlowState = FlowCallNode['state'];
54
+ export type TimeBoxRecord = S['TimeBoxRecord'];
55
+ export type Outputs = S['Outputs'];
56
+ export type OutputTally = S['OutputTally'];
57
+ export type ContractRecord = S['ContractRecord'];
58
+ export type ContractSpec = S['ContractSpec'];
59
+ export type ContractField = S['ContractField'];
60
+ export type ContractStatus = NonNullable<ContractSpec['status']>;
61
+ export type FileView = S['FileView'];
62
+ export type TaskDefinition = S['TaskDefinition'];
63
+ export type DefinitionFile = S['DefinitionFile'];
64
+ export type CursorView = S['CursorView'];
65
+ export type UnitPosition = S['UnitPosition'];
66
+ export type Procs = S['Procs'];
67
+ export type ProcNode = S['ProcNode'];
68
+ export type AgentProcess = S['AgentProcess'];
69
+ export type InflightPythonTask = S['InflightPythonTask'];
70
+ export type TaskDetail = S['TaskDetail'];
71
+ export type TaskLaunch = S['TaskLaunch'];
72
+ export type TaskIO = S['TaskIO'];
73
+ export type UpstreamTask = S['UpstreamTask'];
74
+ export type DownstreamTask = S['DownstreamTask'];
75
+ export type StreamPage = S['StreamPage'];
76
+ export type LaunchEvent = S['LaunchEvent'];
77
+ export type MessageUpdateEvent = S['MessageUpdateEvent'];
78
+ export type ToolStartEvent = S['ToolStartEvent'];
79
+ export type ToolEndEvent = S['ToolEndEvent'];
80
+ export type ToolCallEchoEvent = S['ToolCallEchoEvent'];
81
+ export type ToolResultEchoEvent = S['ToolResultEchoEvent'];
82
+ /** Named apart from the DOM's `MessageEvent`. */
83
+ export type TranscriptMessageEvent = S['MessageEvent'];
84
+ export type NoticeEvent = S['NoticeEvent'];
85
+ export type RetryEvent = S['RetryEvent'];
86
+ export type OtherEvent = S['OtherEvent'];
87
+ /** One transcript event as the wire carries it: a known model, or an `OtherEvent`. */
88
+ export type TranscriptEvent = StreamPage['events'][number];
89
+ /** The transcript events the monitor renders, discriminated by `type`. */
90
+ export type KnownTranscriptEvent = LaunchEvent | MessageUpdateEvent | ToolStartEvent | ToolEndEvent | ToolCallEchoEvent | ToolResultEchoEvent | TranscriptMessageEvent | NoticeEvent | RetryEvent;
91
+ /** The event as one of the known models, or null for any other `type`. */
92
+ export declare function knownEvent(e: TranscriptEvent): KnownTranscriptEvent | null;
93
+ /** One message of `/events?run=`: `event` is the SSE event name, `data` its parsed JSON. */
94
+ export type RunMessage = S['RunEvent'];
95
+ type FixedRunMessage = RunMessage extends infer M ? M extends {
96
+ event: infer E;
97
+ } ? string extends E ? never : M : never : never;
98
+ export type PanelEventName = `panel:${string}`;
99
+ /** A panel's message, with its event name typed. */
100
+ export interface PanelMessage {
101
+ event: PanelEventName;
102
+ data: PanelBody;
103
+ }
104
+ /** A run feed message with every `event` name a literal (or `panel:<name>`). */
105
+ export type RunFeedMessage = FixedRunMessage | PanelMessage;
106
+ /** The SSE event names with a fixed meaning, and what each one carries. */
107
+ export type RunEventData = {
108
+ [M in FixedRunMessage as M['event']]: M['data'];
109
+ };
110
+ export type RunEventName = keyof RunEventData;
111
+ export type StreamMessage = S['StreamMessage'];
112
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,19 @@
1
+ const KNOWN_TYPES = new Set([
2
+ 'launch',
3
+ 'message_update',
4
+ 'tool_execution_start',
5
+ 'tool_execution_update',
6
+ 'tool_execution_end',
7
+ 'acall',
8
+ 'aresult',
9
+ 'message_start',
10
+ 'message_end',
11
+ 'turn_end',
12
+ 'notice',
13
+ 'auto_retry_start',
14
+ ]);
15
+ /** The event as one of the known models, or null for any other `type`. */
16
+ export function knownEvent(e) {
17
+ return KNOWN_TYPES.has(e.type) ? e : null;
18
+ }
19
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAuHA,MAAM,WAAW,GAAwB,IAAI,GAAG,CAA+B;IAC7E,QAAQ;IACR,gBAAgB;IAChB,sBAAsB;IACtB,uBAAuB;IACvB,oBAAoB;IACpB,OAAO;IACP,SAAS;IACT,eAAe;IACf,aAAa;IACb,UAAU;IACV,QAAQ;IACR,kBAAkB;CACnB,CAAC,CAAC;AAEH,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,CAAkB;IAC3C,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,CAA0B,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "@contraagent/api",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Typed client for the contraagent monitor API: generated types, REST client, live feeds and the run state they fold into",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "contraagent",
8
+ "coding-agent",
9
+ "monitor",
10
+ "openapi",
11
+ "client",
12
+ "typescript"
13
+ ],
14
+ "homepage": "https://t-tani.github.io/contraagent/",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/t-tani/contraagent.git",
18
+ "directory": "web/packages/api"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/t-tani/contraagent/issues"
22
+ },
23
+ "type": "module",
24
+ "sideEffects": false,
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "src",
34
+ "!src/**/*.test.ts",
35
+ "!src/**/__snapshots__"
36
+ ],
37
+ "devDependencies": {
38
+ "openapi-typescript": "^7.13.0"
39
+ },
40
+ "scripts": {
41
+ "gen": "node scripts/gen.mjs",
42
+ "build": "tsc -p tsconfig.build.json",
43
+ "typecheck": "tsc -p tsconfig.json --noEmit"
44
+ }
45
+ }
package/src/client.ts ADDED
@@ -0,0 +1,119 @@
1
+ // The REST half of the monitor API, typed by the generated `paths`.
2
+ import type {
3
+ Hosts,
4
+ Info,
5
+ JournalPage,
6
+ JsonObject,
7
+ RunSummary,
8
+ StreamPage,
9
+ TaskDefinition,
10
+ TaskDetail,
11
+ Trends,
12
+ TrendsQuery,
13
+ paths,
14
+ } from './types.js';
15
+
16
+ /**
17
+ * Why a request got no JSON answer: `network`, no response (a network error, a
18
+ * refused connection, or a cross-origin response the browser blocked);
19
+ * `status`, a status outside 2xx; `not-json`, a body that is not JSON (empty,
20
+ * or the HTML page a development server answers every path with).
21
+ */
22
+ export type ApiFailure = 'network' | 'status' | 'not-json';
23
+
24
+ /**
25
+ * A request to the monitor's API that got no JSON answer. Its message states
26
+ * the URL, the failure, the status and the media type
27
+ * ("No JSON answer from http://host/api/runs: not-json 200 text/html");
28
+ * `@contraagent/ui` words it for the reader.
29
+ */
30
+ export class ApiError extends Error {
31
+ constructor(
32
+ /** The URL requested. */
33
+ readonly url: string,
34
+ readonly failure: ApiFailure,
35
+ /** The response's status; 0 with no response. */
36
+ readonly status = 0,
37
+ /** The response's media type, such as `text/html`; '' when it states none. */
38
+ readonly type = '',
39
+ ) {
40
+ super(`No JSON answer from ${url}: ${failure} ${status} ${type}`.trim());
41
+ this.name = 'ApiError';
42
+ }
43
+ }
44
+
45
+ export interface ClientOptions {
46
+ /** Where the monitor is served; '' (the default) is the page's own origin. */
47
+ baseUrl?: string;
48
+ fetch?: typeof globalThis.fetch;
49
+ }
50
+
51
+ /** Typed calls for every JSON endpoint of the monitor. Each throws `ApiError` when it gets no JSON answer. */
52
+ export interface MonitorClient {
53
+ readonly baseUrl: string;
54
+ info(): Promise<Info>;
55
+ runs(): Promise<RunSummary[]>;
56
+ /** The hosts behind the runs (a hub: `Info.hosts`). */
57
+ hosts(): Promise<Hosts>;
58
+ journal(run: string, since?: number): Promise<JournalPage>;
59
+ definitions(run: string): Promise<TaskDefinition[]>;
60
+ task(run: string, key: string): Promise<TaskDetail>;
61
+ stream(run: string, key: string, since?: number): Promise<StreamPage>;
62
+ panel(run: string, name: string): Promise<JsonObject>;
63
+ /** What the runs of a period add up to. */
64
+ trends(query?: TrendsQuery): Promise<Trends>;
65
+ /** A trend panel's body over the runs of a period (`Panel(scope="trends")`). */
66
+ trendsPanel(name: string, query?: TrendsQuery): Promise<JsonObject>;
67
+ }
68
+
69
+ /** The monitor's GET endpoints. */
70
+ type Endpoint = { [P in keyof paths]: paths[P] extends { get: object } ? P : never }[keyof paths];
71
+ type Operation<P extends Endpoint> = paths[P] extends { get: infer O } ? O : never;
72
+ /** An endpoint's parameters: `path` fills its `{name}` parts, `query` is its query string. */
73
+ type Params<P extends Endpoint> = Operation<P> extends { parameters: infer X } ? X : never;
74
+ /** An endpoint's JSON answer (status 200). */
75
+ type Answer<P extends Endpoint> =
76
+ Operation<P> extends { responses: { 200: { content: { 'application/json': infer T } } } } ? T : never;
77
+
78
+ export function createMonitorClient(options: ClientOptions = {}): MonitorClient {
79
+ const baseUrl = (options.baseUrl ?? '').replace(/\/$/, '');
80
+ const origin = (baseUrl || globalThis.location?.origin || '').replace(/\/$/, '');
81
+ const fetch = options.fetch ?? globalThis.fetch;
82
+ /** The JSON answer of GET `endpoint`; `ApiError` when there is none. */
83
+ async function get<P extends Endpoint>(endpoint: P, params?: Params<P>): Promise<Answer<P>> {
84
+ const { path = {}, query = {} } = (params ?? {}) as { path?: Record<string, string>; query?: Record<string, number> };
85
+ const url = origin + endpoint.replace(/\{(\w+)\}/g, (part, name: string) => (name in path ? encodeURIComponent(path[name]!) : part));
86
+ const search = Object.entries(query)
87
+ .filter(([, v]) => v !== undefined && v !== null)
88
+ .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
89
+ .join('&');
90
+ const target = search ? `${url}?${search}` : url;
91
+ let response: Response;
92
+ try {
93
+ response = await fetch(new Request(target));
94
+ } catch {
95
+ throw new ApiError(target, 'network');
96
+ }
97
+ const { status, ok } = response;
98
+ const type = (response.headers.get('Content-Type') ?? '').split(';')[0]!.trim().toLowerCase();
99
+ try {
100
+ if (ok) return (await response.json()) as Answer<P>;
101
+ } catch {
102
+ // An empty body, an HTML page, or text that is not JSON.
103
+ }
104
+ throw new ApiError(target, ok ? 'not-json' : 'status', status, type);
105
+ }
106
+ return {
107
+ baseUrl,
108
+ info: () => get('/api/info'),
109
+ runs: () => get('/api/runs'),
110
+ hosts: () => get('/api/hosts'),
111
+ journal: (run, since = 0) => get('/api/runs/{run}/journal', { path: { run }, query: { since } }),
112
+ definitions: (run) => get('/api/runs/{run}/definitions', { path: { run } }),
113
+ task: (run, key) => get('/api/runs/{run}/task/{key}', { path: { run, key } }),
114
+ stream: (run, key, since = 0) => get('/api/runs/{run}/stream/{key}', { path: { run, key }, query: { since } }),
115
+ panel: (run, name) => get('/api/runs/{run}/panels/{name}', { path: { run, name } }),
116
+ trends: (query = {}) => get('/api/trends', { query: { ...query } }),
117
+ trendsPanel: (name, query = {}) => get('/api/trends/panels/{name}', { path: { name }, query: { ...query } }),
118
+ };
119
+ }