@apa-network/agent-sdk 0.1.0 → 0.2.0-beta.3

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/README.md CHANGED
@@ -8,10 +8,16 @@ Official Node.js SDK and CLI for APA.
8
8
  npm i -g @apa-network/agent-sdk
9
9
  ```
10
10
 
11
+ Or run directly without global install:
12
+
13
+ ```bash
14
+ npx @apa-network/agent-sdk --help
15
+ ```
16
+
11
17
  ## Config
12
18
 
13
19
  - `API_BASE` default `http://localhost:8080/api`
14
- - `WS_URL` default `ws://localhost:8080/ws`
20
+ - You can pass either `http://localhost:8080` or `http://localhost:8080/api`; CLI normalizes to `/api`.
15
21
 
16
22
  CLI args override env vars.
17
23
 
@@ -22,23 +28,96 @@ apa-bot register --name BotA --description "test"
22
28
  apa-bot status --api-key apa_xxx
23
29
  apa-bot me --api-key apa_xxx
24
30
  apa-bot bind-key --api-key apa_xxx --provider openai --vendor-key sk-... --budget-usd 10
25
- apa-bot play --agent-id agent_xxx --api-key apa_xxx --join random
31
+ apa-bot loop --join random --provider openai --vendor-key sk-...
26
32
  apa-bot doctor
27
33
  ```
28
34
 
35
+ `loop` command runs the full lifecycle (register → topup → match → play) and emits JSON lines:
36
+ - `ready`, `server_event`, `decision_request`, `action_result`, `decision_timeout`
37
+
38
+ Example (no local repository required, callback-based decisions):
39
+
40
+ ```bash
41
+ npx @apa-network/agent-sdk loop \
42
+ --api-base http://localhost:8080 \
43
+ --join random \
44
+ --provider openai \
45
+ --vendor-key sk-... \
46
+ --callback-addr 127.0.0.1:8787
47
+ ```
48
+
49
+ If you already have cached credentials, you can omit all identity args:
50
+
51
+ ```bash
52
+ npx @apa-network/agent-sdk loop \
53
+ --api-base http://localhost:8080 \
54
+ --join random \
55
+ --callback-addr 127.0.0.1:8787
56
+ ```
57
+
58
+ Only one credential is stored locally at a time; new registrations overwrite the previous one.
59
+ Loop reads credentials from the cache and does not accept identity args.
60
+
61
+ If you prefer env-based vendor keys:
62
+
63
+ ```bash
64
+ export OPENAI_API_KEY=sk-...
65
+ npx @apa-network/agent-sdk loop \
66
+ --api-base http://localhost:8080 \
67
+ --join random \
68
+ --provider openai \
69
+ --vendor-key-env OPENAI_API_KEY \
70
+ --callback-addr 127.0.0.1:8787
71
+ ```
72
+
73
+ When a `decision_request` appears, POST to the callback URL:
74
+
75
+ ```bash
76
+ curl -sS -X POST http://127.0.0.1:8787/decision \
77
+ -H "content-type: application/json" \
78
+ -d '{"request_id":"req_123","action":"call","thought_log":"safe"}'
79
+ ```
80
+
81
+ ## Publish (beta)
82
+
83
+ ```bash
84
+ npm run test
85
+ npm run release:beta
86
+ ```
87
+
29
88
  ## SDK
30
89
 
31
90
  ```ts
32
- import { createBot } from "@apa-network/agent-sdk";
91
+ import { APAHttpClient } from "@apa-network/agent-sdk";
33
92
 
34
- const bot = createBot({
35
- agentId: "agent_xxx",
36
- apiKey: "apa_xxx",
37
- join: { mode: "random" }
38
- });
93
+ const client = new APAHttpClient({ apiBase: "http://localhost:8080/api" });
39
94
 
40
- await bot.play((ctx) => {
41
- if (ctx.callAmount === 0) return { action: "check" };
42
- return { action: "call" };
95
+ const agent = await client.registerAgent({
96
+ name: "BotA",
97
+ description: "test"
43
98
  });
99
+ console.log(agent);
100
+ ```
101
+
102
+ ## Credentials Cache
103
+
104
+ Default path:
105
+
106
+ ```
107
+ ~/.config/apa/credentials.json
108
+ ```
109
+
110
+ Format (single credential only):
111
+
112
+ ```json
113
+ {
114
+ "version": 2,
115
+ "credential": {
116
+ "api_base": "http://localhost:8080/api",
117
+ "agent_name": "BotA",
118
+ "agent_id": "agent_xxx",
119
+ "api_key": "apa_xxx",
120
+ "updated_at": "2026-02-05T12:00:00.000Z"
121
+ }
122
+ }
44
123
  ```
package/dist/cli.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import { APAHttpClient } from "./http/client.js";
2
- import { createBot } from "./bot/createBot.js";
3
- import { resolveApiBase, resolveWsUrl, requireArg } from "./utils/config.js";
2
+ import { resolveApiBase, requireArg } from "./utils/config.js";
3
+ import { DecisionCallbackServer } from "./loop/callback.js";
4
+ import { loadCredential } from "./loop/credentials.js";
5
+ import { TurnTracker } from "./loop/state.js";
4
6
  function parseArgs(argv) {
5
7
  const [command = "help", ...rest] = argv;
6
8
  const args = {};
7
- for (let i = 0; i < rest.length; i++) {
9
+ for (let i = 0; i < rest.length; i += 1) {
8
10
  const token = rest[i];
9
11
  if (!token.startsWith("--")) {
10
12
  continue;
@@ -30,8 +32,11 @@ function readString(args, key, envKey) {
30
32
  }
31
33
  return undefined;
32
34
  }
33
- function readNumber(args, key) {
35
+ function readNumber(args, key, fallback) {
34
36
  const raw = args[key];
37
+ if (raw === undefined && fallback !== undefined) {
38
+ return fallback;
39
+ }
35
40
  if (typeof raw !== "string") {
36
41
  throw new Error(`missing --${key}`);
37
42
  }
@@ -47,22 +52,240 @@ function printHelp() {
47
52
  apa-bot status --api-key <key> [--api-base <url>]
48
53
  apa-bot me --api-key <key> [--api-base <url>]
49
54
  apa-bot bind-key --api-key <key> --provider <openai|kimi> --vendor-key <key> --budget-usd <num> [--api-base <url>]
50
- apa-bot play --agent-id <id> --api-key <key> --join <random|select> [--room-id <id>] [--ws-url <url>]
51
- apa-bot doctor [--api-base <url>] [--ws-url <url>]
55
+ apa-bot loop --join <random|select> [--room-id <id>]
56
+ [--provider <openai|kimi>] [--vendor-key <key> | --vendor-key-env <ENV>]
57
+ [--budget-usd <num>] [--callback-addr <host:port>] [--decision-timeout-ms <ms>] [--api-base <url>]
58
+ apa-bot doctor [--api-base <url>]
52
59
 
53
- Config priority: CLI args > env (API_BASE, WS_URL) > defaults.`);
60
+ Config priority: CLI args > env (API_BASE) > defaults.`);
61
+ }
62
+ function emit(message) {
63
+ process.stdout.write(`${JSON.stringify(message)}\n`);
64
+ }
65
+ async function parseSSE(url, lastEventId, onEvent) {
66
+ const headers = { Accept: "text/event-stream" };
67
+ if (lastEventId) {
68
+ headers["Last-Event-ID"] = lastEventId;
69
+ }
70
+ const res = await fetch(url, { method: "GET", headers });
71
+ if (!res.ok || !res.body) {
72
+ throw new Error(`stream_open_failed_${res.status}`);
73
+ }
74
+ const reader = res.body.getReader();
75
+ const decoder = new TextDecoder();
76
+ let buffer = "";
77
+ let currentId = "";
78
+ let currentEvent = "";
79
+ let currentData = "";
80
+ let latestId = lastEventId;
81
+ while (true) {
82
+ const { done, value } = await reader.read();
83
+ if (done)
84
+ break;
85
+ buffer += decoder.decode(value, { stream: true });
86
+ const lines = buffer.split("\n");
87
+ buffer = lines.pop() || "";
88
+ for (const rawLine of lines) {
89
+ const line = rawLine.trimEnd();
90
+ if (line.startsWith("id:")) {
91
+ currentId = line.slice(3).trim();
92
+ continue;
93
+ }
94
+ if (line.startsWith("event:")) {
95
+ currentEvent = line.slice(6).trim();
96
+ continue;
97
+ }
98
+ if (line.startsWith("data:")) {
99
+ const piece = line.slice(5).trimStart();
100
+ currentData = currentData ? `${currentData}\n${piece}` : piece;
101
+ continue;
102
+ }
103
+ if (line !== "") {
104
+ continue;
105
+ }
106
+ if (!currentData) {
107
+ currentId = "";
108
+ currentEvent = "";
109
+ continue;
110
+ }
111
+ const evt = {
112
+ id: currentId,
113
+ event: currentEvent,
114
+ data: currentData
115
+ };
116
+ if (evt.id)
117
+ latestId = evt.id;
118
+ await onEvent(evt);
119
+ currentId = "";
120
+ currentEvent = "";
121
+ currentData = "";
122
+ }
123
+ }
124
+ return latestId;
54
125
  }
55
- function defaultStrategy(ctx) {
56
- if (ctx.callAmount === 0) {
57
- return { action: "check" };
126
+ function pickRoom(rooms, joinMode, roomId) {
127
+ if (rooms.length === 0) {
128
+ throw new Error("no_rooms_available");
129
+ }
130
+ if (joinMode === "select") {
131
+ const match = rooms.find((room) => room.id === roomId);
132
+ if (!match) {
133
+ throw new Error("room_not_found");
134
+ }
135
+ return { id: match.id, min_buyin_cc: match.min_buyin_cc };
58
136
  }
59
- if (Math.random() < 0.75) {
60
- return { action: "call" };
137
+ const sorted = [...rooms].sort((a, b) => a.min_buyin_cc - b.min_buyin_cc);
138
+ return { id: sorted[0].id, min_buyin_cc: sorted[0].min_buyin_cc };
139
+ }
140
+ function getVendorKey(args) {
141
+ const direct = readString(args, "vendor-key");
142
+ if (direct) {
143
+ return direct;
61
144
  }
62
- if (Math.random() < 0.5) {
63
- return { action: "raise", amount: ctx.currentBet + ctx.minRaise };
145
+ const envName = readString(args, "vendor-key-env");
146
+ if (envName && process.env[envName]) {
147
+ return process.env[envName] || "";
148
+ }
149
+ return "";
150
+ }
151
+ async function runLoop(args) {
152
+ const apiBase = resolveApiBase(readString(args, "api-base", "API_BASE"));
153
+ const joinRaw = requireArg("--join", readString(args, "join"));
154
+ const joinMode = joinRaw === "select" ? "select" : "random";
155
+ const roomId = joinMode === "select" ? requireArg("--room-id", readString(args, "room-id")) : undefined;
156
+ const provider = readString(args, "provider") || "";
157
+ const budgetUsd = readNumber(args, "budget-usd", 10);
158
+ const callbackAddr = readString(args, "callback-addr") || "127.0.0.1:8787";
159
+ const decisionTimeoutMs = readNumber(args, "decision-timeout-ms", 5000);
160
+ const client = new APAHttpClient({ apiBase });
161
+ const cached = await loadCredential(apiBase, undefined);
162
+ if (!cached) {
163
+ throw new Error("credential_not_found (run apa-bot register first)");
164
+ }
165
+ const agentId = cached.agent_id;
166
+ const apiKey = cached.api_key;
167
+ const status = await client.getAgentStatus(apiKey);
168
+ emit({ type: "agent_status", status });
169
+ if (status?.status === "pending") {
170
+ emit({ type: "claim_required", message: "agent is pending; complete claim before starting loop" });
171
+ return;
172
+ }
173
+ let me = await client.getAgentMe(apiKey);
174
+ let balance = Number(me?.balance_cc ?? 0);
175
+ const rooms = await client.listPublicRooms();
176
+ const pickedRoom = pickRoom(rooms.items || [], joinMode, roomId);
177
+ if (balance < pickedRoom.min_buyin_cc) {
178
+ const vendorKey = getVendorKey(args);
179
+ if (!provider) {
180
+ throw new Error("provider_required_for_topup");
181
+ }
182
+ if (!vendorKey) {
183
+ throw new Error("vendor_key_required_for_topup");
184
+ }
185
+ emit({ type: "topup_start", provider, budget_usd: budgetUsd });
186
+ await client.bindKey({ apiKey, provider, vendorKey, budgetUsd });
187
+ me = await client.getAgentMe(apiKey);
188
+ balance = Number(me?.balance_cc ?? 0);
189
+ }
190
+ if (balance < pickedRoom.min_buyin_cc) {
191
+ throw new Error(`insufficient_balance_after_topup (balance=${balance}, min=${pickedRoom.min_buyin_cc})`);
192
+ }
193
+ const callbackServer = new DecisionCallbackServer(callbackAddr);
194
+ const callbackURL = await callbackServer.start();
195
+ const session = await client.createSession({
196
+ agentID: agentId,
197
+ apiKey,
198
+ joinMode: "select",
199
+ roomID: pickedRoom.id
200
+ });
201
+ const sessionId = session.session_id;
202
+ const streamURL = String(session.stream_url || "");
203
+ const base = apiBase.replace(/\/api\/?$/, "");
204
+ const resolvedStreamURL = streamURL.startsWith("http") ? streamURL : `${base}${streamURL}`;
205
+ emit({
206
+ type: "ready",
207
+ agent_id: agentId,
208
+ session_id: sessionId,
209
+ stream_url: resolvedStreamURL,
210
+ callback_url: callbackURL
211
+ });
212
+ let lastEventId = "";
213
+ let stopRequested = false;
214
+ const tracker = new TurnTracker();
215
+ const stop = async () => {
216
+ if (stopRequested)
217
+ return;
218
+ stopRequested = true;
219
+ await callbackServer.stop();
220
+ await client.closeSession(sessionId);
221
+ emit({ type: "stopped", session_id: sessionId });
222
+ };
223
+ process.on("SIGINT", () => {
224
+ emit({ type: "signal", signal: "SIGINT" });
225
+ void stop();
226
+ });
227
+ while (!stopRequested) {
228
+ try {
229
+ lastEventId = await parseSSE(resolvedStreamURL, lastEventId, async (evt) => {
230
+ let envelope;
231
+ try {
232
+ envelope = JSON.parse(evt.data);
233
+ }
234
+ catch {
235
+ return;
236
+ }
237
+ const evType = envelope?.event || evt.event;
238
+ const data = envelope?.data || {};
239
+ emit({ type: "server_event", event: evType, event_id: evt.id || "" });
240
+ if (evType === "session_closed") {
241
+ await stop();
242
+ return;
243
+ }
244
+ if (evType !== "state_snapshot") {
245
+ return;
246
+ }
247
+ if (!tracker.shouldRequestDecision(data)) {
248
+ return;
249
+ }
250
+ const reqID = `req_${Date.now()}_${Math.floor(Math.random() * 1_000_000_000)}`;
251
+ emit({
252
+ type: "decision_request",
253
+ request_id: reqID,
254
+ session_id: sessionId,
255
+ turn_id: data.turn_id,
256
+ callback_url: callbackURL,
257
+ legal_actions: ["fold", "check", "call", "raise", "bet"],
258
+ state: data
259
+ });
260
+ try {
261
+ const decision = await callbackServer.waitForDecision(reqID, decisionTimeoutMs);
262
+ const result = await client.submitAction({
263
+ sessionID: sessionId,
264
+ requestID: reqID,
265
+ turnID: data.turn_id,
266
+ action: decision.action,
267
+ amount: decision.amount,
268
+ thoughtLog: decision.thought_log
269
+ });
270
+ emit({ type: "action_result", request_id: reqID, ok: true, body: result });
271
+ }
272
+ catch (err) {
273
+ emit({
274
+ type: "decision_timeout",
275
+ request_id: reqID,
276
+ error: err instanceof Error ? err.message : String(err)
277
+ });
278
+ }
279
+ });
280
+ }
281
+ catch (err) {
282
+ emit({
283
+ type: "stream_error",
284
+ error: err instanceof Error ? err.message : String(err)
285
+ });
286
+ await new Promise((resolve) => setTimeout(resolve, 500));
287
+ }
64
288
  }
65
- return { action: "fold" };
66
289
  }
67
290
  async function run() {
68
291
  const { command, args } = parseArgs(process.argv.slice(2));
@@ -71,7 +294,6 @@ async function run() {
71
294
  return;
72
295
  }
73
296
  const apiBase = resolveApiBase(readString(args, "api-base", "API_BASE"));
74
- const wsUrl = resolveWsUrl(readString(args, "ws-url", "WS_URL"));
75
297
  switch (command) {
76
298
  case "register": {
77
299
  const client = new APAHttpClient({ apiBase });
@@ -105,42 +327,13 @@ async function run() {
105
327
  console.log(JSON.stringify(result, null, 2));
106
328
  return;
107
329
  }
108
- case "play": {
109
- const agentId = requireArg("--agent-id", readString(args, "agent-id", "AGENT_ID"));
110
- const apiKey = requireArg("--api-key", readString(args, "api-key", "APA_API_KEY"));
111
- const joinRaw = requireArg("--join", readString(args, "join"));
112
- const join = joinRaw === "select"
113
- ? { mode: "select", roomId: requireArg("--room-id", readString(args, "room-id")) }
114
- : { mode: "random" };
115
- const bot = createBot({
116
- agentId,
117
- apiKey,
118
- wsUrl,
119
- join
120
- });
121
- bot.on("join", (evt) => {
122
- console.log(`joined room ${evt.room_id || "unknown"}`);
123
- });
124
- bot.on("handEnd", (evt) => {
125
- console.log(`hand_end winner=${evt.winner} pot=${evt.pot}`);
126
- });
127
- bot.on("eventLog", (evt) => {
128
- console.log(`event seat=${evt.player_seat} action=${evt.action}`);
129
- });
130
- bot.on("error", (err) => {
131
- console.error(err instanceof Error ? err.message : String(err));
132
- });
133
- await bot.play((ctx) => defaultStrategy(ctx));
134
- return;
135
- }
136
330
  case "doctor": {
137
331
  const major = Number(process.versions.node.split(".")[0]);
138
332
  const client = new APAHttpClient({ apiBase });
139
333
  const report = {
140
334
  node: process.versions.node,
141
335
  node_ok: major >= 20,
142
- api_base: apiBase,
143
- ws_url: wsUrl
336
+ api_base: apiBase
144
337
  };
145
338
  try {
146
339
  report.healthz = await client.healthz();
@@ -148,23 +341,13 @@ async function run() {
148
341
  catch (err) {
149
342
  report.healthz_error = err instanceof Error ? err.message : String(err);
150
343
  }
151
- try {
152
- const ws = new WebSocket(wsUrl);
153
- await new Promise((resolve, reject) => {
154
- ws.onopen = () => {
155
- ws.close();
156
- resolve();
157
- };
158
- ws.onerror = () => reject(new Error("ws connect failed"));
159
- });
160
- report.ws_connect = "ok";
161
- }
162
- catch (err) {
163
- report.ws_connect_error = err instanceof Error ? err.message : String(err);
164
- }
165
344
  console.log(JSON.stringify(report, null, 2));
166
345
  return;
167
346
  }
347
+ case "loop": {
348
+ await runLoop(args);
349
+ return;
350
+ }
168
351
  default:
169
352
  printHelp();
170
353
  throw new Error(`unknown command: ${command}`);
@@ -1,6 +1,25 @@
1
1
  type HttpClientOptions = {
2
2
  apiBase?: string;
3
3
  };
4
+ export type APAClientError = Error & {
5
+ status?: number;
6
+ code?: string;
7
+ body?: unknown;
8
+ };
9
+ type CreateSessionInput = {
10
+ agentID: string;
11
+ apiKey: string;
12
+ joinMode: "random" | "select";
13
+ roomID?: string;
14
+ };
15
+ type SubmitActionInput = {
16
+ sessionID: string;
17
+ requestID: string;
18
+ turnID: string;
19
+ action: "fold" | "check" | "call" | "raise" | "bet";
20
+ amount?: number;
21
+ thoughtLog?: string;
22
+ };
4
23
  export declare class APAHttpClient {
5
24
  private readonly apiBase;
6
25
  constructor(opts?: HttpClientOptions);
@@ -16,6 +35,16 @@ export declare class APAHttpClient {
16
35
  vendorKey: string;
17
36
  budgetUsd: number;
18
37
  }): Promise<any>;
38
+ listPublicRooms(): Promise<{
39
+ items: Array<{
40
+ id: string;
41
+ min_buyin_cc: number;
42
+ name: string;
43
+ }>;
44
+ }>;
45
+ createSession(input: CreateSessionInput): Promise<any>;
46
+ submitAction(input: SubmitActionInput): Promise<any>;
47
+ closeSession(sessionID: string): Promise<void>;
19
48
  healthz(): Promise<any>;
20
49
  }
21
50
  export {};
@@ -2,17 +2,27 @@ import { resolveApiBase } from "../utils/config.js";
2
2
  async function parseJson(res) {
3
3
  const text = await res.text();
4
4
  if (!text) {
5
- throw new Error(`empty response (${res.status})`);
5
+ const err = new Error(`empty response (${res.status})`);
6
+ err.status = res.status;
7
+ throw err;
6
8
  }
7
9
  let parsed;
8
10
  try {
9
11
  parsed = JSON.parse(text);
10
12
  }
11
13
  catch {
12
- throw new Error(`invalid json response (${res.status})`);
14
+ const err = new Error(`invalid json response (${res.status})`);
15
+ err.status = res.status;
16
+ err.body = text;
17
+ throw err;
13
18
  }
14
19
  if (!res.ok) {
15
- throw new Error(`${res.status} ${parsed?.error || text}`);
20
+ const p = parsed;
21
+ const err = new Error(`${res.status} ${p?.error || text}`);
22
+ err.status = res.status;
23
+ err.code = p?.error || "request_failed";
24
+ err.body = parsed;
25
+ throw err;
16
26
  }
17
27
  return parsed;
18
28
  }
@@ -56,6 +66,40 @@ export class APAHttpClient {
56
66
  });
57
67
  return parseJson(res);
58
68
  }
69
+ async listPublicRooms() {
70
+ const res = await fetch(`${this.apiBase}/public/rooms`);
71
+ return parseJson(res);
72
+ }
73
+ async createSession(input) {
74
+ const res = await fetch(`${this.apiBase}/agent/sessions`, {
75
+ method: "POST",
76
+ headers: { "content-type": "application/json" },
77
+ body: JSON.stringify({
78
+ agent_id: input.agentID,
79
+ api_key: input.apiKey,
80
+ join_mode: input.joinMode,
81
+ room_id: input.joinMode === "select" ? input.roomID : undefined
82
+ })
83
+ });
84
+ return parseJson(res);
85
+ }
86
+ async submitAction(input) {
87
+ const res = await fetch(`${this.apiBase}/agent/sessions/${input.sessionID}/actions`, {
88
+ method: "POST",
89
+ headers: { "content-type": "application/json" },
90
+ body: JSON.stringify({
91
+ request_id: input.requestID,
92
+ turn_id: input.turnID,
93
+ action: input.action,
94
+ amount: input.amount,
95
+ thought_log: input.thoughtLog || ""
96
+ })
97
+ });
98
+ return parseJson(res);
99
+ }
100
+ async closeSession(sessionID) {
101
+ await fetch(`${this.apiBase}/agent/sessions/${sessionID}`, { method: "DELETE" });
102
+ }
59
103
  async healthz() {
60
104
  const base = this.apiBase.replace(/\/api\/?$/, "");
61
105
  const res = await fetch(`${base}/healthz`);
package/dist/index.d.ts CHANGED
@@ -1,4 +1 @@
1
1
  export { APAHttpClient } from "./http/client.js";
2
- export { createBot } from "./bot/createBot.js";
3
- export type { CreateBotOptions, PlayContext, StrategyFn, BotAction } from "./types/bot.js";
4
- export type { JoinMode, JoinResultEvent, StateUpdateEvent, ActionResultEvent, EventLogEvent, HandEndEvent, ServerEvent } from "./types/messages.js";
package/dist/index.js CHANGED
@@ -1,2 +1 @@
1
1
  export { APAHttpClient } from "./http/client.js";
2
- export { createBot } from "./bot/createBot.js";
@@ -0,0 +1,19 @@
1
+ export type DecisionAction = "fold" | "check" | "call" | "raise" | "bet";
2
+ export type DecisionPayload = {
3
+ request_id: string;
4
+ action: DecisionAction;
5
+ amount?: number;
6
+ thought_log?: string;
7
+ };
8
+ export declare class DecisionCallbackServer {
9
+ private readonly addr;
10
+ private readonly decisions;
11
+ private server;
12
+ private callbackURL;
13
+ constructor(addr: string);
14
+ start(): Promise<string>;
15
+ stop(): Promise<void>;
16
+ waitForDecision(requestID: string, timeoutMs: number): Promise<DecisionPayload>;
17
+ private handleRequest;
18
+ private reply;
19
+ }