@coltonkirsten/a12s 0.4.0 → 0.4.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/dist/a12s.js +64 -17
- package/dist/src/client.d.ts +17 -4
- package/dist/src/client.js +42 -9
- package/dist/src/fleet.d.ts +14 -3
- package/dist/src/fleet.js +26 -7
- package/dist/src/node.d.ts +2 -1
- package/dist/src/node.js +3 -2
- package/dist/src/types.d.ts +26 -1
- package/package.json +1 -1
package/dist/a12s.js
CHANGED
|
@@ -109,7 +109,7 @@ var A12sClient = class {
|
|
|
109
109
|
}
|
|
110
110
|
async computer(name) {
|
|
111
111
|
const c = (await this.status()).agentComputers.find((x) => x.name === name);
|
|
112
|
-
if (!c) throw new NotFound(404, { code: "not_found", message: `no
|
|
112
|
+
if (!c) throw new NotFound(404, { code: "not_found", message: `no agent computer ${name}` });
|
|
113
113
|
return c;
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
@@ -142,11 +142,12 @@ var A12sClient = class {
|
|
|
142
142
|
events(computers, opts = {}) {
|
|
143
143
|
const names = typeof computers === "string" ? [computers] : computers;
|
|
144
144
|
if ((opts.turn !== void 0 || opts.after !== void 0) && names?.length !== 1) {
|
|
145
|
-
throw new TypeError("events: turn and after need exactly one
|
|
145
|
+
throw new TypeError("events: turn and after need exactly one agent computer");
|
|
146
146
|
}
|
|
147
147
|
return new EventStream((name, live, signal) => {
|
|
148
148
|
const q = opts.turn ? `?turn=${enc(opts.turn)}` : "";
|
|
149
|
-
|
|
149
|
+
const events = this.stream(name, `/v1/agent-computers/${enc(name)}/events${q}`, opts.after, { ...opts, signal, live });
|
|
150
|
+
return opts.turn ? untilTurnFinished(events) : events;
|
|
150
151
|
}, names ?? (async () => (await this.status()).agentComputers.map((c) => c.name)), opts.signal);
|
|
151
152
|
}
|
|
152
153
|
/**
|
|
@@ -195,13 +196,30 @@ var A12sClient = class {
|
|
|
195
196
|
const id = turn ?? (await this.computer(computer)).activeTurn;
|
|
196
197
|
if (id) await this.request("POST", `/v1/agent-computers/${enc(computer)}/turns/${enc(id)}/stop`, {});
|
|
197
198
|
}
|
|
198
|
-
/**
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Stops the agent computer's processes and keeps its disks, session and inbox. It stays asleep until wake(); with
|
|
201
|
+
* `allowWake` its power policy (wakeOnMessage) may wake it instead.
|
|
202
|
+
*/
|
|
203
|
+
async sleep(computer, opts = {}) {
|
|
204
|
+
await this.request("POST", `/v1/agent-computers/${enc(computer)}/power`, {
|
|
205
|
+
state: "asleep",
|
|
206
|
+
...opts.allowWake ? { allowWake: true } : {}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/** Starts a sleeping agent computer; its session resumes on the next Turn. `clearInbox` discards pending Messages. */
|
|
210
|
+
async wake(computer, opts = {}) {
|
|
211
|
+
await this.request("POST", `/v1/agent-computers/${enc(computer)}/power`, {
|
|
212
|
+
state: "awake",
|
|
213
|
+
...opts.clearInbox ? { clearInbox: true, requestId: crypto.randomUUID() } : {}
|
|
214
|
+
});
|
|
201
215
|
}
|
|
202
|
-
/**
|
|
203
|
-
|
|
204
|
-
|
|
216
|
+
/** Holds the inbox: Messages still queue, none is delivered until resume(). */
|
|
217
|
+
hold(computer, opts = {}) {
|
|
218
|
+
return this.request("POST", `/v1/agent-computers/${enc(computer)}/inbox/hold`, opts.reason ? { reason: opts.reason } : {});
|
|
219
|
+
}
|
|
220
|
+
/** Releases a hold; pending Messages are delivered at the next idle moment. */
|
|
221
|
+
resume(computer) {
|
|
222
|
+
return this.request("POST", `/v1/agent-computers/${enc(computer)}/inbox/resume`, {});
|
|
205
223
|
}
|
|
206
224
|
async services() {
|
|
207
225
|
return (await this.request("GET", "/v1/services")).services ?? [];
|
|
@@ -469,8 +487,19 @@ function agentComputerOf(ev) {
|
|
|
469
487
|
function wanted(names, ev) {
|
|
470
488
|
if (!names) return true;
|
|
471
489
|
if (ev.type === "fleet.changed") return (ev.data?.names ?? []).some((n) => names.has(n));
|
|
490
|
+
if (ev.type === "service.phase") return names.has(ev.data?.service);
|
|
472
491
|
return names.has(agentComputerOf(ev));
|
|
473
492
|
}
|
|
493
|
+
async function* untilTurnFinished(events) {
|
|
494
|
+
try {
|
|
495
|
+
for await (const ev of events) {
|
|
496
|
+
yield ev;
|
|
497
|
+
if (ev.type === "turn.finished") return;
|
|
498
|
+
}
|
|
499
|
+
} finally {
|
|
500
|
+
await events.return(void 0);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
474
503
|
var EventStream = class {
|
|
475
504
|
constructor(source, names, signal) {
|
|
476
505
|
this.source = source;
|
|
@@ -728,9 +757,11 @@ var Fleet = class _Fleet {
|
|
|
728
757
|
cur.spec.defaults ??= {};
|
|
729
758
|
const next = await fn(cur.spec) ?? cur.spec;
|
|
730
759
|
try {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
760
|
+
warnWrites(
|
|
761
|
+
await this.client.request("PUT", "/v1/fleet", { fleet: next }, {
|
|
762
|
+
headers: { "if-match": `"${cur.version}"` }
|
|
763
|
+
})
|
|
764
|
+
);
|
|
734
765
|
} catch (err) {
|
|
735
766
|
if (attempt < maxReplaceTries && err instanceof A12sError && err.code === "version_mismatch") continue;
|
|
736
767
|
throw err;
|
|
@@ -776,6 +807,7 @@ var AgentComputers = class {
|
|
|
776
807
|
const r = await this.client.request("PUT", `/v1/agent-computers/${enc2(name)}`, body, {
|
|
777
808
|
headers: writeHeaders({ replace })
|
|
778
809
|
});
|
|
810
|
+
warnWrites(r);
|
|
779
811
|
return r.agentComputer ? new AgentComputer(this.client, r.agentComputer) : this.get(name);
|
|
780
812
|
}
|
|
781
813
|
/** Throws {@link NotFound} if there is none. */
|
|
@@ -813,6 +845,7 @@ var AgentComputer = class {
|
|
|
813
845
|
/** Changes the spec: a key set to null goes back to the Fleet's default. A busy one picks it up when idle. */
|
|
814
846
|
async update(changes) {
|
|
815
847
|
const r = await this.client.request("PATCH", this.path, changes);
|
|
848
|
+
warnWrites(r);
|
|
816
849
|
return r.agentComputer ? this.set(r.agentComputer) : this.reload();
|
|
817
850
|
}
|
|
818
851
|
/** Removes it from the Fleet and stops it; its drives are kept. */
|
|
@@ -845,12 +878,21 @@ var AgentComputer = class {
|
|
|
845
878
|
tools: t.tools.map((tc) => ({ ...tc, isError: tc.isError ?? false }))
|
|
846
879
|
}));
|
|
847
880
|
}
|
|
848
|
-
/** Stops its processes and keeps its disks, session and inbox. */
|
|
849
|
-
sleep() {
|
|
850
|
-
return this.client.sleep(this.name);
|
|
881
|
+
/** Stops its processes and keeps its disks, session and inbox until wake(); `allowWake` lets wakeOnMessage wake it. */
|
|
882
|
+
sleep(opts = {}) {
|
|
883
|
+
return this.client.sleep(this.name, opts);
|
|
851
884
|
}
|
|
852
|
-
|
|
853
|
-
|
|
885
|
+
/** Wakes it; `clearInbox` discards the pending Messages first. */
|
|
886
|
+
wake(opts = {}) {
|
|
887
|
+
return this.client.wake(this.name, opts);
|
|
888
|
+
}
|
|
889
|
+
/** Holds its inbox: Messages still queue, none is delivered until resume(). */
|
|
890
|
+
hold(opts = {}) {
|
|
891
|
+
return this.client.hold(this.name, opts);
|
|
892
|
+
}
|
|
893
|
+
/** Releases a hold on its inbox. */
|
|
894
|
+
resume() {
|
|
895
|
+
return this.client.resume(this.name);
|
|
854
896
|
}
|
|
855
897
|
/** Interrupts a Turn (default: the active one). */
|
|
856
898
|
stop(turn) {
|
|
@@ -877,6 +919,7 @@ var Services = class {
|
|
|
877
919
|
const r = await this.client.request("PUT", `/v1/services/${enc2(name)}`, body, {
|
|
878
920
|
headers: writeHeaders({ replace })
|
|
879
921
|
});
|
|
922
|
+
warnWrites(r);
|
|
880
923
|
return r.service ? new Service(this.client, r.service) : this.get(name);
|
|
881
924
|
}
|
|
882
925
|
/** Throws {@link NotFound} if there is none. */
|
|
@@ -909,6 +952,7 @@ var Service = class {
|
|
|
909
952
|
/** Changes the spec as a JSON merge patch: a key set to null is removed. */
|
|
910
953
|
async update(changes) {
|
|
911
954
|
const r = await this.client.request("PATCH", this.path, changes);
|
|
955
|
+
warnWrites(r);
|
|
912
956
|
if (!r.service) return this.reload();
|
|
913
957
|
this.status = r.service;
|
|
914
958
|
return this;
|
|
@@ -965,6 +1009,9 @@ var Credentials = class {
|
|
|
965
1009
|
await this.client.request("DELETE", `/v1/credentials/${enc2(name)}`);
|
|
966
1010
|
}
|
|
967
1011
|
};
|
|
1012
|
+
function warnWrites(r) {
|
|
1013
|
+
for (const w of r?.warnings ?? []) console.warn(`a12s: ${w}`);
|
|
1014
|
+
}
|
|
968
1015
|
|
|
969
1016
|
// src/index.ts
|
|
970
1017
|
async function connect(opts = {}) {
|
package/dist/src/client.d.ts
CHANGED
|
@@ -106,10 +106,23 @@ export declare class A12sClient {
|
|
|
106
106
|
withdraw(computer: string, id: string): Promise<Message>;
|
|
107
107
|
/** Interrupts a Turn (default: the active one). The Turn ends `interrupted`; nothing is replayed. */
|
|
108
108
|
stop(computer: string, turn?: string): Promise<void>;
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Stops the agent computer's processes and keeps its disks, session and inbox. It stays asleep until wake(); with
|
|
111
|
+
* `allowWake` its power policy (wakeOnMessage) may wake it instead.
|
|
112
|
+
*/
|
|
113
|
+
sleep(computer: string, opts?: {
|
|
114
|
+
allowWake?: boolean;
|
|
115
|
+
}): Promise<void>;
|
|
116
|
+
/** Starts a sleeping agent computer; its session resumes on the next Turn. `clearInbox` discards pending Messages. */
|
|
117
|
+
wake(computer: string, opts?: {
|
|
118
|
+
clearInbox?: boolean;
|
|
119
|
+
}): Promise<void>;
|
|
120
|
+
/** Holds the inbox: Messages still queue, none is delivered until resume(). */
|
|
121
|
+
hold(computer: string, opts?: {
|
|
122
|
+
reason?: string;
|
|
123
|
+
}): Promise<InboxListResponse>;
|
|
124
|
+
/** Releases a hold; pending Messages are delivered at the next idle moment. */
|
|
125
|
+
resume(computer: string): Promise<InboxListResponse>;
|
|
113
126
|
services(): Promise<ServiceStatus[]>;
|
|
114
127
|
service(name: string): Promise<ServiceStatus>;
|
|
115
128
|
/** A scoped token for another program; owner only. The secret is in the response once. */
|
package/dist/src/client.js
CHANGED
|
@@ -82,7 +82,7 @@ export class A12sClient {
|
|
|
82
82
|
async computer(name) {
|
|
83
83
|
const c = (await this.status()).agentComputers.find((x) => x.name === name);
|
|
84
84
|
if (!c)
|
|
85
|
-
throw new NotFound(404, { code: "not_found", message: `no
|
|
85
|
+
throw new NotFound(404, { code: "not_found", message: `no agent computer ${name}` });
|
|
86
86
|
return c;
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
@@ -117,11 +117,12 @@ export class A12sClient {
|
|
|
117
117
|
events(computers, opts = {}) {
|
|
118
118
|
const names = typeof computers === "string" ? [computers] : computers;
|
|
119
119
|
if ((opts.turn !== undefined || opts.after !== undefined) && names?.length !== 1) {
|
|
120
|
-
throw new TypeError("events: turn and after need exactly one
|
|
120
|
+
throw new TypeError("events: turn and after need exactly one agent computer");
|
|
121
121
|
}
|
|
122
122
|
return new EventStream((name, live, signal) => {
|
|
123
123
|
const q = opts.turn ? `?turn=${enc(opts.turn)}` : "";
|
|
124
|
-
|
|
124
|
+
const events = this.stream(name, `/v1/agent-computers/${enc(name)}/events${q}`, opts.after, { ...opts, signal, live });
|
|
125
|
+
return opts.turn ? untilTurnFinished(events) : events;
|
|
125
126
|
}, names ?? (async () => (await this.status()).agentComputers.map((c) => c.name)), opts.signal);
|
|
126
127
|
}
|
|
127
128
|
/**
|
|
@@ -168,13 +169,30 @@ export class A12sClient {
|
|
|
168
169
|
if (id)
|
|
169
170
|
await this.request("POST", `/v1/agent-computers/${enc(computer)}/turns/${enc(id)}/stop`, {});
|
|
170
171
|
}
|
|
171
|
-
/**
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Stops the agent computer's processes and keeps its disks, session and inbox. It stays asleep until wake(); with
|
|
174
|
+
* `allowWake` its power policy (wakeOnMessage) may wake it instead.
|
|
175
|
+
*/
|
|
176
|
+
async sleep(computer, opts = {}) {
|
|
177
|
+
await this.request("POST", `/v1/agent-computers/${enc(computer)}/power`, {
|
|
178
|
+
state: "asleep",
|
|
179
|
+
...(opts.allowWake ? { allowWake: true } : {}),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
/** Starts a sleeping agent computer; its session resumes on the next Turn. `clearInbox` discards pending Messages. */
|
|
183
|
+
async wake(computer, opts = {}) {
|
|
184
|
+
await this.request("POST", `/v1/agent-computers/${enc(computer)}/power`, {
|
|
185
|
+
state: "awake",
|
|
186
|
+
...(opts.clearInbox ? { clearInbox: true, requestId: crypto.randomUUID() } : {}),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/** Holds the inbox: Messages still queue, none is delivered until resume(). */
|
|
190
|
+
hold(computer, opts = {}) {
|
|
191
|
+
return this.request("POST", `/v1/agent-computers/${enc(computer)}/inbox/hold`, opts.reason ? { reason: opts.reason } : {});
|
|
174
192
|
}
|
|
175
|
-
/**
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
/** Releases a hold; pending Messages are delivered at the next idle moment. */
|
|
194
|
+
resume(computer) {
|
|
195
|
+
return this.request("POST", `/v1/agent-computers/${enc(computer)}/inbox/resume`, {});
|
|
178
196
|
}
|
|
179
197
|
async services() {
|
|
180
198
|
return (await this.request("GET", "/v1/services")).services ?? [];
|
|
@@ -492,8 +510,23 @@ function wanted(names, ev) {
|
|
|
492
510
|
return true;
|
|
493
511
|
if (ev.type === "fleet.changed")
|
|
494
512
|
return (ev.data?.names ?? []).some((n) => names.has(n));
|
|
513
|
+
if (ev.type === "service.phase")
|
|
514
|
+
return names.has(ev.data?.service);
|
|
495
515
|
return names.has(agentComputerOf(ev));
|
|
496
516
|
}
|
|
517
|
+
/** A Turn replay: its events up to and including its turn.finished. The server keeps the stream open after. */
|
|
518
|
+
async function* untilTurnFinished(events) {
|
|
519
|
+
try {
|
|
520
|
+
for await (const ev of events) {
|
|
521
|
+
yield ev;
|
|
522
|
+
if (ev.type === "turn.finished")
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
finally {
|
|
527
|
+
await events.return(undefined);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
497
530
|
/** Events of one or more Computers, merged in arrival order. Iterate it with `for await`. */
|
|
498
531
|
export class EventStream {
|
|
499
532
|
source;
|
package/dist/src/fleet.d.ts
CHANGED
|
@@ -95,9 +95,20 @@ export declare class AgentComputer {
|
|
|
95
95
|
limit?: undefined;
|
|
96
96
|
}): TurnStream;
|
|
97
97
|
private pastTurns;
|
|
98
|
-
/** Stops its processes and keeps its disks, session and inbox. */
|
|
99
|
-
sleep(
|
|
100
|
-
|
|
98
|
+
/** Stops its processes and keeps its disks, session and inbox until wake(); `allowWake` lets wakeOnMessage wake it. */
|
|
99
|
+
sleep(opts?: {
|
|
100
|
+
allowWake?: boolean;
|
|
101
|
+
}): Promise<void>;
|
|
102
|
+
/** Wakes it; `clearInbox` discards the pending Messages first. */
|
|
103
|
+
wake(opts?: {
|
|
104
|
+
clearInbox?: boolean;
|
|
105
|
+
}): Promise<void>;
|
|
106
|
+
/** Holds its inbox: Messages still queue, none is delivered until resume(). */
|
|
107
|
+
hold(opts?: {
|
|
108
|
+
reason?: string;
|
|
109
|
+
}): Promise<InboxListResponse>;
|
|
110
|
+
/** Releases a hold on its inbox. */
|
|
111
|
+
resume(): Promise<InboxListResponse>;
|
|
101
112
|
/** Interrupts a Turn (default: the active one). */
|
|
102
113
|
stop(turn?: string): Promise<void>;
|
|
103
114
|
inbox(opts?: InboxListOptions): Promise<InboxListResponse>;
|
package/dist/src/fleet.js
CHANGED
|
@@ -52,9 +52,9 @@ export class Fleet {
|
|
|
52
52
|
cur.spec.defaults ??= {};
|
|
53
53
|
const next = (await fn(cur.spec)) ?? cur.spec;
|
|
54
54
|
try {
|
|
55
|
-
await this.client.request("PUT", "/v1/fleet", { fleet: next }, {
|
|
55
|
+
warnWrites(await this.client.request("PUT", "/v1/fleet", { fleet: next }, {
|
|
56
56
|
headers: { "if-match": `"${cur.version}"` },
|
|
57
|
-
});
|
|
57
|
+
}));
|
|
58
58
|
}
|
|
59
59
|
catch (err) {
|
|
60
60
|
if (attempt < maxReplaceTries && err instanceof A12sError && err.code === "version_mismatch")
|
|
@@ -104,6 +104,7 @@ export class AgentComputers {
|
|
|
104
104
|
const r = await this.client.request("PUT", `/v1/agent-computers/${enc(name)}`, body, {
|
|
105
105
|
headers: writeHeaders({ replace }),
|
|
106
106
|
});
|
|
107
|
+
warnWrites(r);
|
|
107
108
|
return r.agentComputer ? new AgentComputer(this.client, r.agentComputer) : this.get(name);
|
|
108
109
|
}
|
|
109
110
|
/** Throws {@link NotFound} if there is none. */
|
|
@@ -143,6 +144,7 @@ export class AgentComputer {
|
|
|
143
144
|
/** Changes the spec: a key set to null goes back to the Fleet's default. A busy one picks it up when idle. */
|
|
144
145
|
async update(changes) {
|
|
145
146
|
const r = await this.client.request("PATCH", this.path, changes);
|
|
147
|
+
warnWrites(r);
|
|
146
148
|
return r.agentComputer ? this.set(r.agentComputer) : this.reload();
|
|
147
149
|
}
|
|
148
150
|
/** Removes it from the Fleet and stops it; its drives are kept. */
|
|
@@ -177,12 +179,21 @@ export class AgentComputer {
|
|
|
177
179
|
tools: t.tools.map((tc) => ({ ...tc, isError: tc.isError ?? false })),
|
|
178
180
|
}));
|
|
179
181
|
}
|
|
180
|
-
/** Stops its processes and keeps its disks, session and inbox. */
|
|
181
|
-
sleep() {
|
|
182
|
-
return this.client.sleep(this.name);
|
|
182
|
+
/** Stops its processes and keeps its disks, session and inbox until wake(); `allowWake` lets wakeOnMessage wake it. */
|
|
183
|
+
sleep(opts = {}) {
|
|
184
|
+
return this.client.sleep(this.name, opts);
|
|
183
185
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
/** Wakes it; `clearInbox` discards the pending Messages first. */
|
|
187
|
+
wake(opts = {}) {
|
|
188
|
+
return this.client.wake(this.name, opts);
|
|
189
|
+
}
|
|
190
|
+
/** Holds its inbox: Messages still queue, none is delivered until resume(). */
|
|
191
|
+
hold(opts = {}) {
|
|
192
|
+
return this.client.hold(this.name, opts);
|
|
193
|
+
}
|
|
194
|
+
/** Releases a hold on its inbox. */
|
|
195
|
+
resume() {
|
|
196
|
+
return this.client.resume(this.name);
|
|
186
197
|
}
|
|
187
198
|
/** Interrupts a Turn (default: the active one). */
|
|
188
199
|
stop(turn) {
|
|
@@ -210,6 +221,7 @@ export class Services {
|
|
|
210
221
|
const r = await this.client.request("PUT", `/v1/services/${enc(name)}`, body, {
|
|
211
222
|
headers: writeHeaders({ replace }),
|
|
212
223
|
});
|
|
224
|
+
warnWrites(r);
|
|
213
225
|
return r.service ? new Service(this.client, r.service) : this.get(name);
|
|
214
226
|
}
|
|
215
227
|
/** Throws {@link NotFound} if there is none. */
|
|
@@ -244,6 +256,7 @@ export class Service {
|
|
|
244
256
|
/** Changes the spec as a JSON merge patch: a key set to null is removed. */
|
|
245
257
|
async update(changes) {
|
|
246
258
|
const r = await this.client.request("PATCH", this.path, changes);
|
|
259
|
+
warnWrites(r);
|
|
247
260
|
if (!r.service)
|
|
248
261
|
return this.reload();
|
|
249
262
|
this.status = r.service;
|
|
@@ -304,3 +317,9 @@ export class Credentials {
|
|
|
304
317
|
await this.client.request("DELETE", `/v1/credentials/${enc(name)}`);
|
|
305
318
|
}
|
|
306
319
|
}
|
|
320
|
+
/** A write's warnings (a grant to an agent computer that doesn't exist yet, a missing harness credential) go to the
|
|
321
|
+
* console instead of being dropped. */
|
|
322
|
+
function warnWrites(r) {
|
|
323
|
+
for (const w of r?.warnings ?? [])
|
|
324
|
+
console.warn(`a12s: ${w}`);
|
|
325
|
+
}
|
package/dist/src/node.d.ts
CHANGED
|
@@ -23,7 +23,8 @@ export interface ConnectOptions extends A12sClientOptions {
|
|
|
23
23
|
* 2. the Fleet named by `fleet`;
|
|
24
24
|
* 3. the Fleet file in `$A12S_FLEET`, else the nearest `fleet.yaml` in the current directory or a parent;
|
|
25
25
|
* 4. the only Fleet with a running Controller on this machine.
|
|
26
|
-
* For 2–4 it reads `~/.a12s/<fleet>/controller.json`, which `a12s up` writes
|
|
26
|
+
* For 2–4 it reads `~/.a12s/<fleet>/controller.json`, which `a12s up` writes: its URL always, and its owner token
|
|
27
|
+
* unless `token` is given (a prefix or narrow token on this machine).
|
|
27
28
|
*/
|
|
28
29
|
export declare function connect(opts?: ConnectOptions): Promise<A12sClient>;
|
|
29
30
|
/** metadata.name from a Fleet file, in either `metadata: { name: x }` or block form. */
|
package/dist/src/node.js
CHANGED
|
@@ -21,7 +21,8 @@ export class Fleet extends PageFleet {
|
|
|
21
21
|
* 2. the Fleet named by `fleet`;
|
|
22
22
|
* 3. the Fleet file in `$A12S_FLEET`, else the nearest `fleet.yaml` in the current directory or a parent;
|
|
23
23
|
* 4. the only Fleet with a running Controller on this machine.
|
|
24
|
-
* For 2–4 it reads `~/.a12s/<fleet>/controller.json`, which `a12s up` writes
|
|
24
|
+
* For 2–4 it reads `~/.a12s/<fleet>/controller.json`, which `a12s up` writes: its URL always, and its owner token
|
|
25
|
+
* unless `token` is given (a prefix or narrow token on this machine).
|
|
25
26
|
*/
|
|
26
27
|
export async function connect(opts = {}) {
|
|
27
28
|
return new A12sClient(await discover(opts));
|
|
@@ -40,7 +41,7 @@ async function discover(opts) {
|
|
|
40
41
|
catch (err) {
|
|
41
42
|
throw new Error(`Fleet ${fleet} isn't running (no ${path}): run a12s up in its directory first`, { cause: err });
|
|
42
43
|
}
|
|
43
|
-
return { url: `http://127.0.0.1:${cf.port}`, token: cf.token, fetch: opts.fetch };
|
|
44
|
+
return { url: `http://127.0.0.1:${cf.port}`, token: opts.token ?? cf.token, fetch: opts.fetch };
|
|
44
45
|
}
|
|
45
46
|
async function fleetNameNearby(cwd) {
|
|
46
47
|
const file = process.env.A12S_FLEET ? resolve(cwd, process.env.A12S_FLEET) : await findUp(cwd, "fleet.yaml");
|
package/dist/src/types.d.ts
CHANGED
|
@@ -92,6 +92,14 @@ export interface Change {
|
|
|
92
92
|
when: "now" | "idle" | (string & {});
|
|
93
93
|
/** The top-level spec fields that differ, for an update. */
|
|
94
94
|
fields?: string[];
|
|
95
|
+
/** Every leaf that differs, for an update, with its value before and after (absent where the field is). */
|
|
96
|
+
diff?: FieldDiff[];
|
|
97
|
+
}
|
|
98
|
+
/** One leaf of a spec that differs: `path` is dotted field names ("grants.send"); lists and values are leaves. */
|
|
99
|
+
export interface FieldDiff {
|
|
100
|
+
path: string;
|
|
101
|
+
before?: unknown;
|
|
102
|
+
after?: unknown;
|
|
95
103
|
}
|
|
96
104
|
export interface FleetResponse {
|
|
97
105
|
version: number;
|
|
@@ -398,6 +406,15 @@ export interface PhaseData {
|
|
|
398
406
|
phase: Phase;
|
|
399
407
|
error?: Failure;
|
|
400
408
|
}
|
|
409
|
+
/** A Service's phase, health or restart count changed. */
|
|
410
|
+
export interface ServicePhaseData {
|
|
411
|
+
service: string;
|
|
412
|
+
phase: Phase;
|
|
413
|
+
/** "ok", or why the last health check failed. */
|
|
414
|
+
health?: string;
|
|
415
|
+
restarts: number;
|
|
416
|
+
error?: Failure;
|
|
417
|
+
}
|
|
401
418
|
export interface ToolStartedData {
|
|
402
419
|
id: string;
|
|
403
420
|
/** MCP tools are named `mcp__<server>__<tool>`, e.g. `mcp__a12s__send`. */
|
|
@@ -468,10 +485,14 @@ export type EgressDeniedEvent = Ev<"egress.denied", EgressDeniedData>;
|
|
|
468
485
|
export type FleetChangedEvent = Ev<"fleet.changed", FleetChangedData>;
|
|
469
486
|
/** Made by the Controller, on the fleet-wide stream only. */
|
|
470
487
|
export type PhaseEvent = Ev<"agent_computer.phase", PhaseData>;
|
|
488
|
+
/** Made by the Controller, on the fleet-wide stream only, after any change to the agent computer's inbox (a burst is one event). */
|
|
489
|
+
export type InboxChangedEvent = Ev<"inbox.changed", InboxSummary>;
|
|
490
|
+
/** Made by the Controller, on the fleet-wide stream only; `agentComputer` is empty, the Service is in `data`. */
|
|
491
|
+
export type ServicePhaseEvent = Ev<"service.phase", ServicePhaseData>;
|
|
471
492
|
/** Made by the SDK, never journaled: the stream could not resume from its cursor and events were lost. */
|
|
472
493
|
export type GapEvent = Ev<"gap", GapData>;
|
|
473
494
|
/** One event of an agent computer's journal, or the Controller's own on the fleet-wide stream. Narrow on `type` to get typed `data`. */
|
|
474
|
-
export type A12sEvent = TurnStartedEvent | TurnDispatchedEvent | TextDeltaEvent | ToolStartedEvent | ToolFinishedEvent | PermissionEvent | DiagnosticEvent | TurnFinishedEvent | SessionChangedEvent | ResumeFailedEvent | LifecycleEvent | HarnessRestartedEvent | ContinuationAbandonedEvent | TurnRefusedEvent | InboxDiscardedEvent | EgressDeniedEvent | FleetChangedEvent | PhaseEvent | GapEvent;
|
|
495
|
+
export type A12sEvent = TurnStartedEvent | TurnDispatchedEvent | TextDeltaEvent | ToolStartedEvent | ToolFinishedEvent | PermissionEvent | DiagnosticEvent | TurnFinishedEvent | SessionChangedEvent | ResumeFailedEvent | LifecycleEvent | HarnessRestartedEvent | ContinuationAbandonedEvent | TurnRefusedEvent | InboxDiscardedEvent | EgressDeniedEvent | FleetChangedEvent | PhaseEvent | InboxChangedEvent | ServicePhaseEvent | GapEvent;
|
|
475
496
|
export type EventType = A12sEvent["type"];
|
|
476
497
|
/** One tool call in a Turn. A `send` to another Computer is `mcp__a12s__send` with `input.body`. */
|
|
477
498
|
export interface ToolCall {
|
|
@@ -530,6 +551,8 @@ export interface CredentialInfo {
|
|
|
530
551
|
name: string;
|
|
531
552
|
set: boolean;
|
|
532
553
|
usedBy?: string[];
|
|
554
|
+
/** When the value last changed (RFC 3339); absent if unknown. */
|
|
555
|
+
updatedAt?: string;
|
|
533
556
|
}
|
|
534
557
|
export interface CredentialsResponse {
|
|
535
558
|
credentials: CredentialInfo[];
|
|
@@ -540,6 +563,8 @@ export interface Token {
|
|
|
540
563
|
computers: string[];
|
|
541
564
|
prefix?: string;
|
|
542
565
|
createdAt: string;
|
|
566
|
+
/** When it last authenticated (RFC 3339, recorded at most once a minute); absent if never. */
|
|
567
|
+
lastUsedAt?: string;
|
|
543
568
|
secret?: string;
|
|
544
569
|
}
|
|
545
570
|
export {};
|
package/package.json
CHANGED