@linkedclaw/cli 0.1.0 → 0.1.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/bin.js +215 -100
- package/dist/bin.js.map +1 -1
- package/package.json +3 -3
package/dist/bin.js
CHANGED
|
@@ -3878,7 +3878,7 @@ function withTimeout(p, ms, code) {
|
|
|
3878
3878
|
function escapeRegex(s) {
|
|
3879
3879
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3880
3880
|
}
|
|
3881
|
-
var LinkedClawError, NetworkError, ApiError, ConfigError, HandlerError, CloudClient, RequesterFlows, TOOL_CALL_PATTERNS, SYSTEM_PATTERNS, DEFAULT_OUTPUT_PATTERNS, DEFAULT_STRIP_PATTERNS, DEFAULT_CLOUD_URL, DEFAULT_RELAY_URL, MessageType, RelayClient, nodeWsConnector, DEFAULT_INVOKE_TIMEOUT_MS, DEFAULT_SESSION_TURN_TIMEOUT_MS, DEFAULT_BROADCAST_OFFER_TIMEOUT_MS, DEFAULT_BROADCAST_EXECUTE_TIMEOUT_MS, BROADCAST_SUBMIT_MAX_RETRIES, BROADCAST_SUBMIT_BASE_MS, BROADCAST_SUBMIT_CAP_MS, ProviderRuntime, CORE_VERSION;
|
|
3881
|
+
var LinkedClawError, NetworkError, ApiError, ConfigError, HandlerError, CloudClient, RequesterFlows, TOOL_CALL_PATTERNS, SYSTEM_PATTERNS, DEFAULT_OUTPUT_PATTERNS, DEFAULT_STRIP_PATTERNS, DEFAULT_CLOUD_URL, DEFAULT_RELAY_URL, MessageType, DEFAULT_AUTH_FAILURE_CODES, RelayClient, nodeWsConnector, DEFAULT_INVOKE_TIMEOUT_MS, DEFAULT_SESSION_TURN_TIMEOUT_MS, DEFAULT_BROADCAST_OFFER_TIMEOUT_MS, DEFAULT_BROADCAST_EXECUTE_TIMEOUT_MS, BROADCAST_SUBMIT_MAX_RETRIES, BROADCAST_SUBMIT_BASE_MS, BROADCAST_SUBMIT_CAP_MS, ProviderRuntime, CORE_VERSION;
|
|
3882
3882
|
var init_dist = __esm({
|
|
3883
3883
|
"../core/dist/index.js"() {
|
|
3884
3884
|
"use strict";
|
|
@@ -3953,14 +3953,16 @@ var init_dist = __esm({
|
|
|
3953
3953
|
};
|
|
3954
3954
|
// --- Agents ---------------------------------------------------------
|
|
3955
3955
|
agents = {
|
|
3956
|
+
/**
|
|
3957
|
+
* Server's `GET /api/v1/agents` accepts `capability`, `owner`, `status`,
|
|
3958
|
+
* `sort`. It does NOT paginate via `limit`/`offset` — if you need that,
|
|
3959
|
+
* filter client-side after fetching.
|
|
3960
|
+
*/
|
|
3956
3961
|
search: (query) => this.request("/api/v1/agents", { query }),
|
|
3957
3962
|
get: (agentId) => this.request(`/api/v1/agents/${encodeURIComponent(agentId)}`),
|
|
3958
|
-
create: (body) => this.request("/api/v1/agents", { method: "
|
|
3959
|
-
// ^ Server uses PUT /agents/{id} for update, POST /agents for create on some builds;
|
|
3960
|
-
// prefer POST for first-create. The .catch here is defensive, not load-bearing.
|
|
3961
|
-
// See agents_service.py for exact verb wiring.
|
|
3963
|
+
create: (body) => this.request("/api/v1/agents", { method: "POST", body }),
|
|
3962
3964
|
update: (agentId, body) => this.request(`/api/v1/agents/${encodeURIComponent(agentId)}`, {
|
|
3963
|
-
method: "
|
|
3965
|
+
method: "PUT",
|
|
3964
3966
|
body
|
|
3965
3967
|
}),
|
|
3966
3968
|
delete: (agentId) => this.request(`/api/v1/agents/${encodeURIComponent(agentId)}`, { method: "DELETE" }),
|
|
@@ -3970,27 +3972,42 @@ var init_dist = __esm({
|
|
|
3970
3972
|
sessions = {
|
|
3971
3973
|
list: (query) => this.request("/api/v1/sessions", { query }),
|
|
3972
3974
|
get: (sessionId) => this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}`),
|
|
3973
|
-
|
|
3975
|
+
/**
|
|
3976
|
+
* Server returns `{ events: [...], next_offset: N }`, not a bare array.
|
|
3977
|
+
* Supports `offset` / `limit` query params (default 0 / 100; limit clamped to [1, 1000]).
|
|
3978
|
+
* The events' `seq` field is renamed to `event_seq` in the response.
|
|
3979
|
+
*/
|
|
3980
|
+
events: (sessionId, query) => this.request(
|
|
3981
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/events`,
|
|
3982
|
+
{ query }
|
|
3983
|
+
),
|
|
3974
3984
|
create: (body) => this.request("/api/v1/sessions", { method: "POST", body }),
|
|
3975
3985
|
activate: (sessionId) => this.request(
|
|
3976
3986
|
`/api/v1/sessions/${encodeURIComponent(sessionId)}/activate`,
|
|
3977
3987
|
{ method: "POST" }
|
|
3978
3988
|
),
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3989
|
+
/**
|
|
3990
|
+
* Send a message in an open session.
|
|
3991
|
+
*
|
|
3992
|
+
* Server requires:
|
|
3993
|
+
* - `seq: int ≥ 1`
|
|
3994
|
+
* - `payload: dict` (MUST be an object, not a string)
|
|
3995
|
+
* - JSON size ≤ 64 KiB
|
|
3996
|
+
*/
|
|
3997
|
+
sendMessage: (sessionId, payload, seq) => {
|
|
3998
|
+
const body = { seq, payload };
|
|
3999
|
+
return this.request(
|
|
4000
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`,
|
|
4001
|
+
{ method: "POST", body }
|
|
4002
|
+
);
|
|
4003
|
+
},
|
|
4004
|
+
end: (sessionId, body) => this.request(
|
|
3984
4005
|
`/api/v1/sessions/${encodeURIComponent(sessionId)}/end`,
|
|
3985
|
-
{
|
|
3986
|
-
method: "POST",
|
|
3987
|
-
body: messageCount !== void 0 ? { message_count: messageCount } : void 0
|
|
3988
|
-
}
|
|
3989
|
-
),
|
|
3990
|
-
resume: (sessionId) => this.request(
|
|
3991
|
-
`/api/v1/sessions/${encodeURIComponent(sessionId)}/resume`,
|
|
3992
|
-
{ method: "POST" }
|
|
4006
|
+
{ method: "POST", body: body ?? {} }
|
|
3993
4007
|
),
|
|
4008
|
+
resume: (sessionId) => this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}/resume`, {
|
|
4009
|
+
method: "POST"
|
|
4010
|
+
}),
|
|
3994
4011
|
flag: (sessionId) => this.request(
|
|
3995
4012
|
`/api/v1/sessions/${encodeURIComponent(sessionId)}/flag`,
|
|
3996
4013
|
{ method: "POST" }
|
|
@@ -4006,13 +4023,23 @@ var init_dist = __esm({
|
|
|
4006
4023
|
// --- Broadcasts -----------------------------------------------------
|
|
4007
4024
|
broadcasts = {
|
|
4008
4025
|
list: (query) => this.request("/api/v1/broadcasts", { query }),
|
|
4009
|
-
available: (
|
|
4026
|
+
available: () => this.request("/api/v1/broadcasts/available"),
|
|
4010
4027
|
get: (taskId) => this.request(`/api/v1/broadcasts/${encodeURIComponent(taskId)}`),
|
|
4011
4028
|
create: (body) => this.request("/api/v1/broadcasts", { method: "POST", body }),
|
|
4029
|
+
/**
|
|
4030
|
+
* Accept a broadcast task. Server's `AcceptBroadcastRequest` requires
|
|
4031
|
+
* `agent_id` — the provider must declare which of their agents is accepting.
|
|
4032
|
+
*/
|
|
4012
4033
|
accept: (taskId, body) => this.request(
|
|
4013
4034
|
`/api/v1/broadcasts/${encodeURIComponent(taskId)}/accept`,
|
|
4014
|
-
{ method: "POST", body
|
|
4035
|
+
{ method: "POST", body }
|
|
4015
4036
|
),
|
|
4037
|
+
/**
|
|
4038
|
+
* Submit a broadcast result. Server's `SubmitBroadcastRequest`:
|
|
4039
|
+
* - `result_data: str` — required (free-text summary)
|
|
4040
|
+
* - `result_payload: dict | null` — optional structured payload (≤64 KiB)
|
|
4041
|
+
* - `proof: ProofItem[] | null` — optional evidence
|
|
4042
|
+
*/
|
|
4016
4043
|
submit: (taskId, body) => this.request(
|
|
4017
4044
|
`/api/v1/broadcasts/${encodeURIComponent(taskId)}/submit`,
|
|
4018
4045
|
{ method: "POST", body }
|
|
@@ -4053,16 +4080,19 @@ var init_dist = __esm({
|
|
|
4053
4080
|
search(capability, extra) {
|
|
4054
4081
|
return this.cloud.agents.search({ capability, ...extra });
|
|
4055
4082
|
}
|
|
4083
|
+
/**
|
|
4084
|
+
* Create a session against a provider agent. The server field is
|
|
4085
|
+
* `provider_agent_id` (not `agent_id`). Escrow is computed server-side as
|
|
4086
|
+
* `listing.price_credits × max_messages` — no `max_credits` body field.
|
|
4087
|
+
* Manifests are attached at invoke/message time, not at session create.
|
|
4088
|
+
*/
|
|
4056
4089
|
async hire(params) {
|
|
4057
4090
|
const req = {
|
|
4058
|
-
|
|
4091
|
+
provider_agent_id: params.providerAgentId,
|
|
4059
4092
|
capability: params.capability
|
|
4060
4093
|
};
|
|
4061
4094
|
if (params.maxMessages !== void 0) req.max_messages = params.maxMessages;
|
|
4062
|
-
if (params.maxCredits !== void 0) req.max_credits = params.maxCredits;
|
|
4063
4095
|
if (params.referredBy !== void 0) req.referred_by = params.referredBy;
|
|
4064
|
-
if (params.manifestId !== void 0) req.manifest_id = params.manifestId;
|
|
4065
|
-
if (params.manifest !== void 0) req.manifest = params.manifest;
|
|
4066
4096
|
const session = await this.cloud.sessions.create(req);
|
|
4067
4097
|
if (params.autoActivate === false) {
|
|
4068
4098
|
return { session };
|
|
@@ -4070,11 +4100,19 @@ var init_dist = __esm({
|
|
|
4070
4100
|
const activation = await this.cloud.sessions.activate(session.session_id);
|
|
4071
4101
|
return { session: activation, activation };
|
|
4072
4102
|
}
|
|
4103
|
+
/**
|
|
4104
|
+
* Send a message in an active session.
|
|
4105
|
+
*
|
|
4106
|
+
* Server requires `seq: int ≥ 1` and `payload: dict`. If the caller passes
|
|
4107
|
+
* a plain string we wrap it as `{ text: <string> }` so the server accepts
|
|
4108
|
+
* it — common shape for the default `coding`/`assistant` capabilities.
|
|
4109
|
+
*/
|
|
4073
4110
|
send(sessionId, payload, seq) {
|
|
4074
|
-
|
|
4111
|
+
const normalized = typeof payload === "string" ? { text: payload } : payload;
|
|
4112
|
+
return this.cloud.sessions.sendMessage(sessionId, normalized, seq);
|
|
4075
4113
|
}
|
|
4076
|
-
end(sessionId,
|
|
4077
|
-
return this.cloud.sessions.end(sessionId,
|
|
4114
|
+
end(sessionId, body) {
|
|
4115
|
+
return this.cloud.sessions.end(sessionId, body);
|
|
4078
4116
|
}
|
|
4079
4117
|
invoke(agentId, body) {
|
|
4080
4118
|
return this.cloud.invokes.call(agentId, body);
|
|
@@ -4088,9 +4126,11 @@ var init_dist = __esm({
|
|
|
4088
4126
|
listBroadcasts(query) {
|
|
4089
4127
|
return this.cloud.broadcasts.list(query);
|
|
4090
4128
|
}
|
|
4091
|
-
|
|
4092
|
-
|
|
4129
|
+
/** Provider-side helper: accept a broadcast slot (requires `agent_id`). */
|
|
4130
|
+
acceptBroadcast(taskId, body) {
|
|
4131
|
+
return this.cloud.broadcasts.accept(taskId, body);
|
|
4093
4132
|
}
|
|
4133
|
+
/** Provider-side helper: submit a broadcast result. */
|
|
4094
4134
|
submitBroadcast(taskId, body) {
|
|
4095
4135
|
return this.cloud.broadcasts.submit(taskId, body);
|
|
4096
4136
|
}
|
|
@@ -4144,6 +4184,10 @@ var init_dist = __esm({
|
|
|
4144
4184
|
INVOKE: "invoke",
|
|
4145
4185
|
INVOKE_RESULT: "invoke_result"
|
|
4146
4186
|
};
|
|
4187
|
+
DEFAULT_AUTH_FAILURE_CODES = Object.freeze([
|
|
4188
|
+
1008,
|
|
4189
|
+
...Array.from({ length: 99 }, (_, i) => 4001 + i)
|
|
4190
|
+
]);
|
|
4147
4191
|
RelayClient = class extends EventEmitter {
|
|
4148
4192
|
url;
|
|
4149
4193
|
agentId;
|
|
@@ -4152,11 +4196,15 @@ var init_dist = __esm({
|
|
|
4152
4196
|
heartbeatMs;
|
|
4153
4197
|
reconnectBaseMs;
|
|
4154
4198
|
reconnectMaxMs;
|
|
4199
|
+
authGraceMs;
|
|
4200
|
+
authFailureCloseCodes;
|
|
4155
4201
|
connector;
|
|
4156
4202
|
transport;
|
|
4157
4203
|
heartbeatTimer;
|
|
4204
|
+
authGraceTimer;
|
|
4158
4205
|
stopped = false;
|
|
4159
4206
|
reconnectAttempt = 0;
|
|
4207
|
+
fatalState = null;
|
|
4160
4208
|
constructor(opts) {
|
|
4161
4209
|
super();
|
|
4162
4210
|
this.url = opts.url;
|
|
@@ -4166,8 +4214,16 @@ var init_dist = __esm({
|
|
|
4166
4214
|
this.heartbeatMs = opts.heartbeatMs ?? 3e4;
|
|
4167
4215
|
this.reconnectBaseMs = opts.reconnectBaseMs ?? 1e3;
|
|
4168
4216
|
this.reconnectMaxMs = opts.reconnectMaxMs ?? 3e4;
|
|
4217
|
+
this.authGraceMs = opts.authGraceMs ?? 5e3;
|
|
4218
|
+
this.authFailureCloseCodes = new Set(
|
|
4219
|
+
opts.authFailureCloseCodes ?? DEFAULT_AUTH_FAILURE_CODES
|
|
4220
|
+
);
|
|
4169
4221
|
this.connector = opts.connector ?? nodeWsConnector;
|
|
4170
4222
|
}
|
|
4223
|
+
/** Last detected permanent-auth-failure, or null when OK / still retrying. */
|
|
4224
|
+
getFatal() {
|
|
4225
|
+
return this.fatalState;
|
|
4226
|
+
}
|
|
4171
4227
|
on(event, listener) {
|
|
4172
4228
|
return super.on(event, listener);
|
|
4173
4229
|
}
|
|
@@ -4183,13 +4239,15 @@ var init_dist = __esm({
|
|
|
4183
4239
|
const { transport, ready } = await this.connector(this.url);
|
|
4184
4240
|
this.transport = transport;
|
|
4185
4241
|
transport.addMessageListener((data) => this.handleFrame(data));
|
|
4186
|
-
transport.addCloseListener(
|
|
4187
|
-
|
|
4242
|
+
transport.addCloseListener(
|
|
4243
|
+
(code, reason) => this.handleClose(code, `close ${code}: ${reason}`)
|
|
4244
|
+
);
|
|
4245
|
+
transport.addErrorListener((err) => this.handleClose(null, `error: ${err.message}`));
|
|
4188
4246
|
await ready;
|
|
4189
4247
|
await this.sendIdentify();
|
|
4190
4248
|
this.startHeartbeat();
|
|
4191
|
-
this.reconnectAttempt = 0;
|
|
4192
4249
|
this.emit("connected");
|
|
4250
|
+
this.startAuthGraceTimer();
|
|
4193
4251
|
} catch (err) {
|
|
4194
4252
|
throw new NetworkError(`relay connect failed: ${err.message}`, err);
|
|
4195
4253
|
}
|
|
@@ -4201,6 +4259,7 @@ var init_dist = __esm({
|
|
|
4201
4259
|
async stop() {
|
|
4202
4260
|
this.stopped = true;
|
|
4203
4261
|
this.stopHeartbeat();
|
|
4262
|
+
this.cancelAuthGraceTimer();
|
|
4204
4263
|
if (this.transport) {
|
|
4205
4264
|
try {
|
|
4206
4265
|
await this.transport.close(1e3, "client_stop");
|
|
@@ -4248,11 +4307,39 @@ var init_dist = __esm({
|
|
|
4248
4307
|
const evt = parseInbound(frame);
|
|
4249
4308
|
if (evt) this.emit("event", evt);
|
|
4250
4309
|
}
|
|
4251
|
-
handleClose(reason) {
|
|
4310
|
+
handleClose(code, reason) {
|
|
4252
4311
|
this.stopHeartbeat();
|
|
4312
|
+
this.cancelAuthGraceTimer();
|
|
4253
4313
|
this.transport = void 0;
|
|
4254
4314
|
this.emit("disconnected", reason);
|
|
4255
|
-
if (
|
|
4315
|
+
if (this.stopped) return;
|
|
4316
|
+
if (code !== null && this.authFailureCloseCodes.has(code)) {
|
|
4317
|
+
this.stopped = true;
|
|
4318
|
+
this.fatalState = { reason, code };
|
|
4319
|
+
this.emit("fatal", { reason, code });
|
|
4320
|
+
return;
|
|
4321
|
+
}
|
|
4322
|
+
void this.scheduleReconnect();
|
|
4323
|
+
}
|
|
4324
|
+
startAuthGraceTimer() {
|
|
4325
|
+
this.cancelAuthGraceTimer();
|
|
4326
|
+
if (this.authGraceMs <= 0) {
|
|
4327
|
+
this.reconnectAttempt = 0;
|
|
4328
|
+
return;
|
|
4329
|
+
}
|
|
4330
|
+
this.authGraceTimer = setTimeout(() => {
|
|
4331
|
+
this.authGraceTimer = void 0;
|
|
4332
|
+
if (this.transport) this.reconnectAttempt = 0;
|
|
4333
|
+
}, this.authGraceMs);
|
|
4334
|
+
if (typeof this.authGraceTimer.unref === "function") {
|
|
4335
|
+
this.authGraceTimer.unref();
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
cancelAuthGraceTimer() {
|
|
4339
|
+
if (this.authGraceTimer) {
|
|
4340
|
+
clearTimeout(this.authGraceTimer);
|
|
4341
|
+
this.authGraceTimer = void 0;
|
|
4342
|
+
}
|
|
4256
4343
|
}
|
|
4257
4344
|
async scheduleReconnect() {
|
|
4258
4345
|
this.reconnectAttempt += 1;
|
|
@@ -4320,6 +4407,7 @@ var init_dist = __esm({
|
|
|
4320
4407
|
inFlightBroadcasts = /* @__PURE__ */ new Set();
|
|
4321
4408
|
running = false;
|
|
4322
4409
|
connected = false;
|
|
4410
|
+
fatal = null;
|
|
4323
4411
|
constructor(deps) {
|
|
4324
4412
|
this.cloud = deps.cloud;
|
|
4325
4413
|
this.relay = deps.relay;
|
|
@@ -4331,10 +4419,18 @@ var init_dist = __esm({
|
|
|
4331
4419
|
this.running = true;
|
|
4332
4420
|
this.relay.on("connected", () => {
|
|
4333
4421
|
this.connected = true;
|
|
4422
|
+
this.fatal = null;
|
|
4334
4423
|
});
|
|
4335
4424
|
this.relay.on("disconnected", () => {
|
|
4336
4425
|
this.connected = false;
|
|
4337
4426
|
});
|
|
4427
|
+
this.relay.on("fatal", (info) => {
|
|
4428
|
+
this.fatal = info;
|
|
4429
|
+
this.connected = false;
|
|
4430
|
+
console.error(
|
|
4431
|
+
`linkedclaw: relay rejected our credentials (code=${info.code ?? "?"}: ${info.reason}). Not retrying. Check apiKey/agentId and restart the plugin.`
|
|
4432
|
+
);
|
|
4433
|
+
});
|
|
4338
4434
|
this.relay.on("event", (evt) => {
|
|
4339
4435
|
void this.dispatch(evt);
|
|
4340
4436
|
});
|
|
@@ -4351,7 +4447,8 @@ var init_dist = __esm({
|
|
|
4351
4447
|
activeSessions: this.activeSessions.size,
|
|
4352
4448
|
inFlightInvokes: this.inFlightInvokes.size,
|
|
4353
4449
|
inFlightBroadcasts: this.inFlightBroadcasts.size,
|
|
4354
|
-
...this.config.agentId !== void 0 ? { agentId: this.config.agentId } : {}
|
|
4450
|
+
...this.config.agentId !== void 0 ? { agentId: this.config.agentId } : {},
|
|
4451
|
+
...this.fatal !== null ? { fatal: this.fatal } : {}
|
|
4355
4452
|
};
|
|
4356
4453
|
}
|
|
4357
4454
|
// ────────── dispatch ──────────
|
|
@@ -4526,11 +4623,12 @@ var init_dist = __esm({
|
|
|
4526
4623
|
try {
|
|
4527
4624
|
const decision = await this.runOffer(offer);
|
|
4528
4625
|
if (!decision || !decision.accept) return;
|
|
4626
|
+
const acceptBody = {
|
|
4627
|
+
agent_id: this.config.agentId ?? ""
|
|
4628
|
+
};
|
|
4629
|
+
if (decision.slot_key !== void 0) acceptBody.slot_key = decision.slot_key;
|
|
4529
4630
|
try {
|
|
4530
|
-
await this.cloud.broadcasts.accept(
|
|
4531
|
-
offer.task_id,
|
|
4532
|
-
decision.slot_key !== void 0 ? { slot_key: decision.slot_key } : void 0
|
|
4533
|
-
);
|
|
4631
|
+
await this.cloud.broadcasts.accept(offer.task_id, acceptBody);
|
|
4534
4632
|
} catch {
|
|
4535
4633
|
return;
|
|
4536
4634
|
}
|
|
@@ -4573,13 +4671,16 @@ var init_dist = __esm({
|
|
|
4573
4671
|
return null;
|
|
4574
4672
|
}
|
|
4575
4673
|
}
|
|
4576
|
-
async submitWithRetry(taskId, result,
|
|
4674
|
+
async submitWithRetry(taskId, result, _slotKey) {
|
|
4675
|
+
const payload = this.sanitizeOut(result.result_payload ?? {});
|
|
4676
|
+
const resultData = typeof result.result_data === "string" && result.result_data.length > 0 ? result.result_data : JSON.stringify(payload);
|
|
4577
4677
|
const body = {
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
...slotKey !== void 0 ? { slot_key: slotKey } : {},
|
|
4581
|
-
...result.proof !== void 0 ? { evidence: result.proof } : {}
|
|
4678
|
+
result_data: resultData,
|
|
4679
|
+
result_payload: payload
|
|
4582
4680
|
};
|
|
4681
|
+
if (Array.isArray(result.proof)) {
|
|
4682
|
+
body.proof = result.proof;
|
|
4683
|
+
}
|
|
4583
4684
|
for (let attempt = 0; attempt < BROADCAST_SUBMIT_MAX_RETRIES; attempt += 1) {
|
|
4584
4685
|
try {
|
|
4585
4686
|
await this.cloud.broadcasts.submit(taskId, body);
|
|
@@ -4920,9 +5021,8 @@ function registerProviderCommands(program2) {
|
|
|
4920
5021
|
});
|
|
4921
5022
|
provider.command("listings").description("Show my own agent listings (as provider)").option("--human", "Human-readable output").action(async (opts) => {
|
|
4922
5023
|
await runCommand(async () => {
|
|
4923
|
-
const { cloud
|
|
4924
|
-
|
|
4925
|
-
return all.filter((a) => a.owner_id === (config.agentId ? void 0 : void 0) || true);
|
|
5024
|
+
const { cloud } = buildContext();
|
|
5025
|
+
return cloud.agents.search({ owner: "me" });
|
|
4926
5026
|
}, { human: opts.human });
|
|
4927
5027
|
});
|
|
4928
5028
|
provider.command("run <config>").description("Run a provider daemon: connect WS, dispatch events to handler subprocess").option("--handler-cmd <cmd>", "Shell command to spawn as the handler child process").option("--handler-http <url>", "HTTP webhook URL to POST each event to (alternative to --handler-cmd)").option("--human", "Human-readable status output").action(async (path, opts) => {
|
|
@@ -4979,10 +5079,12 @@ function registerProviderCommands(program2) {
|
|
|
4979
5079
|
await new Promise(() => {
|
|
4980
5080
|
});
|
|
4981
5081
|
});
|
|
4982
|
-
provider.command("pick <bct_id>").description("Manually accept a broadcast task (provider side)").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
|
|
5082
|
+
provider.command("pick <bct_id>").description("Manually accept a broadcast task (provider side)").requiredOption("--agent-id <agt_id>", "Which of your agents is accepting").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
|
|
4983
5083
|
await runCommand(async () => {
|
|
4984
5084
|
const { flows } = buildContext();
|
|
4985
|
-
|
|
5085
|
+
const body = { agent_id: opts.agentId };
|
|
5086
|
+
if (opts.slotKey !== void 0) body.slot_key = opts.slotKey;
|
|
5087
|
+
return flows.acceptBroadcast(taskId, body);
|
|
4986
5088
|
}, { human: opts.human });
|
|
4987
5089
|
});
|
|
4988
5090
|
provider.command("submit <bct_id> <result_file>").description('Submit a broadcast result. result_file = JSON path or "-" for stdin.').option("--human", "Human-readable output").action(async (taskId, resultFile, opts) => {
|
|
@@ -5010,7 +5112,6 @@ function buildCreateAgentRequest(cfg) {
|
|
|
5010
5112
|
}
|
|
5011
5113
|
if (!cfg.pricingModel) throw new Error("provider config missing `pricingModel`");
|
|
5012
5114
|
if (cfg.priceCredits === void 0) throw new Error("provider config missing `priceCredits`");
|
|
5013
|
-
if (!cfg.providerType) throw new Error("provider config missing `providerType`");
|
|
5014
5115
|
return {
|
|
5015
5116
|
slug: cfg.slug,
|
|
5016
5117
|
name: cfg.agentName,
|
|
@@ -5018,7 +5119,6 @@ function buildCreateAgentRequest(cfg) {
|
|
|
5018
5119
|
capabilities: cfg.capabilities,
|
|
5019
5120
|
pricing_model: cfg.pricingModel,
|
|
5020
5121
|
price_credits: cfg.priceCredits,
|
|
5021
|
-
provider_type: cfg.providerType,
|
|
5022
5122
|
...cfg.verifyMethod ? { verify_method: cfg.verifyMethod } : {}
|
|
5023
5123
|
};
|
|
5024
5124
|
}
|
|
@@ -5067,56 +5167,64 @@ import { readFileSync as readFileSync3 } from "fs";
|
|
|
5067
5167
|
import { load as yamlLoad3 } from "js-yaml";
|
|
5068
5168
|
init_output();
|
|
5069
5169
|
function registerRequesterCommands(program2) {
|
|
5070
|
-
program2.command("search <capability>").description("Search public agent listings by capability").option("--
|
|
5170
|
+
program2.command("search <capability>").description("Search public agent listings by capability").option("--owner <owner>", '"me" or a "usr_..." id').option("--status <status>", "filter by status (online/offline/disabled)").option("--sort <sort>", "newest | price_asc | price_desc | trust").option("--human", "Human-readable output").action(async (capability, opts) => {
|
|
5071
5171
|
await runCommand(async () => {
|
|
5072
5172
|
const { flows } = buildContext();
|
|
5073
5173
|
return flows.search(capability, {
|
|
5074
|
-
...opts.
|
|
5075
|
-
...opts.
|
|
5174
|
+
...opts.owner ? { owner: opts.owner } : {},
|
|
5175
|
+
...opts.status ? { status: opts.status } : {},
|
|
5176
|
+
...opts.sort ? { sort: opts.sort } : {}
|
|
5076
5177
|
});
|
|
5077
5178
|
}, { human: opts.human });
|
|
5078
5179
|
});
|
|
5079
|
-
program2.command("hire <agent_id>").description("Create and activate a 1:1 session with an agent").requiredOption("--capability <cap>", "Capability being hired").option("--max-messages <n>", "Message cap
|
|
5080
|
-
"--manifest <json>",
|
|
5081
|
-
'Inline task manifest JSON (literal, @file, or "-" for stdin). Minimum: {"intention":"..."}'
|
|
5082
|
-
).option("--no-activate", "Create session but do not activate (returns session only)").option("--human", "Human-readable output").action(async (agentId, opts) => {
|
|
5180
|
+
program2.command("hire <agent_id>").description("Create and activate a 1:1 session with an agent").requiredOption("--capability <cap>", "Capability being hired").option("--max-messages <n>", "Message cap (server default 1)", (v) => parseInt(v, 10)).option("--referred-by <ref_id>", "Attribution: referrer agent id").option("--no-activate", "Create session but do not activate (returns session only)").option("--human", "Human-readable output").action(async (agentId, opts) => {
|
|
5083
5181
|
await runCommand(async () => {
|
|
5084
5182
|
const { flows } = buildContext();
|
|
5085
|
-
const manifest = await resolveManifestOpt(opts.manifest, opts.manifestId);
|
|
5086
5183
|
return flows.hire({
|
|
5087
|
-
agentId,
|
|
5184
|
+
providerAgentId: agentId,
|
|
5088
5185
|
capability: opts.capability,
|
|
5089
5186
|
...opts.maxMessages !== void 0 ? { maxMessages: opts.maxMessages } : {},
|
|
5090
|
-
...opts.maxCredits !== void 0 ? { maxCredits: opts.maxCredits } : {},
|
|
5091
5187
|
...opts.referredBy !== void 0 ? { referredBy: opts.referredBy } : {},
|
|
5092
|
-
...opts.manifestId !== void 0 ? { manifestId: opts.manifestId } : {},
|
|
5093
|
-
...manifest !== void 0 ? { manifest } : {},
|
|
5094
5188
|
autoActivate: opts.activate !== false
|
|
5095
5189
|
});
|
|
5096
5190
|
}, { human: opts.human });
|
|
5097
5191
|
});
|
|
5098
|
-
program2.command("send <session_id> <message>").description(
|
|
5192
|
+
program2.command("send <session_id> <message>").description(
|
|
5193
|
+
`Send a message in an active session. Message is wrapped as {"text": "..."} if it's a plain string, or passed through if it's a JSON object. Use "-" to read from stdin.`
|
|
5194
|
+
).requiredOption("--seq <n>", "Sequence number (server requires \u2265 1)", (v) => parseInt(v, 10)).option("--json", "Interpret message as a JSON object literal (default: wrap as {text})").option("--human", "Human-readable output").action(async (sessionId, message, opts) => {
|
|
5099
5195
|
await runCommand(async () => {
|
|
5100
5196
|
const { flows } = buildContext();
|
|
5101
|
-
const
|
|
5197
|
+
const raw = message === "-" ? await readStdin() : message;
|
|
5198
|
+
const payload = opts.json ? parseJsonOrFail(raw, "<message>") : raw;
|
|
5102
5199
|
return flows.send(sessionId, payload, opts.seq);
|
|
5103
5200
|
}, { human: opts.human });
|
|
5104
5201
|
});
|
|
5105
|
-
program2.command("end <session_id>").description("Mark a session ended").option("--message-count <n>", "Declare final message count", (v) => parseInt(v, 10)).option("--human", "Human-readable output").action(async (sessionId, opts) => {
|
|
5202
|
+
program2.command("end <session_id>").description("Mark a session ended").option("--message-count <n>", "Declare final message count", (v) => parseInt(v, 10)).option("--final-output <text>", "Final output blurb (optional)").option("--human", "Human-readable output").action(async (sessionId, opts) => {
|
|
5106
5203
|
await runCommand(async () => {
|
|
5107
5204
|
const { flows } = buildContext();
|
|
5108
|
-
|
|
5205
|
+
const body = {};
|
|
5206
|
+
if (opts.messageCount !== void 0) body.message_count = opts.messageCount;
|
|
5207
|
+
if (opts.finalOutput !== void 0) body.final_output = opts.finalOutput;
|
|
5208
|
+
return flows.end(sessionId, body);
|
|
5109
5209
|
}, { human: opts.human });
|
|
5110
5210
|
});
|
|
5111
|
-
program2.command("invoke <agent_id>").description("One-shot stateless invoke").requiredOption("--capability <cap>", "Capability").requiredOption("--input <json>", 'JSON input (or "-" to read from stdin)').option("--max-credits <n>", "Max credits", (v) => parseInt(v, 10)).option("--timeout <s>", "Server-side timeout seconds", (v) => parseInt(v, 10)).option("--referred-by <ref_id>", "Attribution: referrer agent id").option("--manifest-id <mft_id>", "Pre-registered task manifest id").option(
|
|
5211
|
+
program2.command("invoke <agent_id>").description("One-shot stateless invoke").requiredOption("--capability <cap>", "Capability").requiredOption("--input <json>", 'JSON input (or "-" to read from stdin)').option("--max-credits <n>", "Max credits", (v) => parseInt(v, 10)).option("--timeout <s>", "Server-side timeout seconds (5..300, default 60)", (v) => parseInt(v, 10)).option("--referred-by <ref_id>", "Attribution: referrer agent id").option("--manifest-id <mft_id>", "Pre-registered task manifest id").option(
|
|
5112
5212
|
"--manifest <json>",
|
|
5113
5213
|
'Inline task manifest JSON (literal, @file, or "-" for stdin). Minimum: {"intention":"..."}'
|
|
5214
|
+
).option(
|
|
5215
|
+
"--intention <text>",
|
|
5216
|
+
"Shortcut: builds a minimal manifest {intention: <text>} if --manifest/--manifest-id are not set."
|
|
5114
5217
|
).option("--human", "Human-readable output").action(async (agentId, opts) => {
|
|
5115
5218
|
await runCommand(async () => {
|
|
5116
5219
|
const { flows } = buildContext();
|
|
5117
5220
|
const inputJson = opts.input === "-" ? await readStdin() : opts.input;
|
|
5118
5221
|
const input = parseJsonOrFail(inputJson, "--input");
|
|
5119
|
-
const manifest = await resolveManifestOpt(
|
|
5222
|
+
const manifest = await resolveManifestOpt(
|
|
5223
|
+
opts.manifest,
|
|
5224
|
+
opts.manifestId,
|
|
5225
|
+
opts.intention,
|
|
5226
|
+
`invoke: ${opts.capability}`
|
|
5227
|
+
);
|
|
5120
5228
|
const body = { capability: opts.capability, input };
|
|
5121
5229
|
if (opts.maxCredits !== void 0) body.max_credits = opts.maxCredits;
|
|
5122
5230
|
if (opts.timeout !== void 0) body.timeout_seconds = opts.timeout;
|
|
@@ -5127,7 +5235,9 @@ function registerRequesterCommands(program2) {
|
|
|
5127
5235
|
}, { human: opts.human });
|
|
5128
5236
|
});
|
|
5129
5237
|
const broadcast = program2.command("broadcast").description("Broadcast task commands");
|
|
5130
|
-
broadcast.command("create <manifest>").description(
|
|
5238
|
+
broadcast.command("create <manifest>").description(
|
|
5239
|
+
'Create a broadcast task from a YAML/JSON manifest file. Use "-" for stdin. Required fields: capability, instruction, target_providers, credits_per_provider.'
|
|
5240
|
+
).option("--human", "Human-readable output").action(async (manifestPath, opts) => {
|
|
5131
5241
|
await runCommand(async () => {
|
|
5132
5242
|
const { flows } = buildContext();
|
|
5133
5243
|
const raw = manifestPath === "-" ? await readStdin() : readFileSync3(manifestPath, "utf8");
|
|
@@ -5141,37 +5251,37 @@ function registerRequesterCommands(program2) {
|
|
|
5141
5251
|
return flows.getBroadcast(taskId);
|
|
5142
5252
|
}, { human: opts.human });
|
|
5143
5253
|
});
|
|
5144
|
-
broadcast.command("list").description("List broadcasts I own").option("--status <s>", "Filter by status").option("--
|
|
5254
|
+
broadcast.command("list").description("List broadcasts I own").option("--status <s>", "Filter by status").option("--human", "Human-readable output").action(async (opts) => {
|
|
5145
5255
|
await runCommand(async () => {
|
|
5146
5256
|
const { flows } = buildContext();
|
|
5147
5257
|
return flows.listBroadcasts({
|
|
5148
|
-
...opts.status ? { status: opts.status } : {}
|
|
5149
|
-
...opts.capability ? { capability: opts.capability } : {}
|
|
5258
|
+
...opts.status ? { status: opts.status } : {}
|
|
5150
5259
|
});
|
|
5151
5260
|
}, { human: opts.human });
|
|
5152
5261
|
});
|
|
5153
|
-
broadcast.command("available").description("List open broadcasts I could pick up (as provider)").option("--
|
|
5262
|
+
broadcast.command("available").description("List open broadcasts I could pick up (as provider)").option("--human", "Human-readable output").action(async (opts) => {
|
|
5154
5263
|
await runCommand(async () => {
|
|
5155
5264
|
const { cloud } = buildContext();
|
|
5156
|
-
return cloud.broadcasts.available(
|
|
5157
|
-
...opts.capability ? { capability: opts.capability } : {},
|
|
5158
|
-
...opts.limit ? { limit: opts.limit } : {}
|
|
5159
|
-
});
|
|
5265
|
+
return cloud.broadcasts.available();
|
|
5160
5266
|
}, { human: opts.human });
|
|
5161
5267
|
});
|
|
5162
|
-
broadcast.command("accept <bct_id>").description("Accept a broadcast (provider side) \u2014 returns a result_id").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
|
|
5268
|
+
broadcast.command("accept <bct_id>").description("Accept a broadcast (provider side) \u2014 returns a result_id").requiredOption("--agent-id <agt_id>", "Which of your agents is accepting").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
|
|
5163
5269
|
await runCommand(async () => {
|
|
5164
5270
|
const { flows } = buildContext();
|
|
5165
|
-
|
|
5271
|
+
const body = { agent_id: opts.agentId };
|
|
5272
|
+
if (opts.slotKey !== void 0) body.slot_key = opts.slotKey;
|
|
5273
|
+
return flows.acceptBroadcast(taskId, body);
|
|
5166
5274
|
}, { human: opts.human });
|
|
5167
5275
|
});
|
|
5168
|
-
broadcast.command("submit <bct_id>").description(
|
|
5276
|
+
broadcast.command("submit <bct_id>").description(
|
|
5277
|
+
"Submit broadcast result (provider side). Body must include `result_data` (string) and may include `result_payload` (object) and `proof` (array)."
|
|
5278
|
+
).requiredOption("--body <json>", 'JSON body (or "-" to read from stdin)').option("--human", "Human-readable output").action(async (taskId, opts) => {
|
|
5169
5279
|
await runCommand(async () => {
|
|
5170
5280
|
const { flows } = buildContext();
|
|
5171
5281
|
const raw = opts.body === "-" ? await readStdin() : readFileSync3(opts.body, "utf8");
|
|
5172
5282
|
const body = parseJsonOrFail(raw, "--body");
|
|
5173
|
-
if (typeof body !== "object" || body === null ||
|
|
5174
|
-
throw new Error("--body must include
|
|
5283
|
+
if (typeof body !== "object" || body === null || typeof body.result_data !== "string") {
|
|
5284
|
+
throw new Error("--body must include a `result_data` string field");
|
|
5175
5285
|
}
|
|
5176
5286
|
return flows.submitBroadcast(taskId, body);
|
|
5177
5287
|
}, { human: opts.human });
|
|
@@ -5182,7 +5292,7 @@ function registerRequesterCommands(program2) {
|
|
|
5182
5292
|
return cloud.receipts.get(receiptId);
|
|
5183
5293
|
}, { human: opts.human });
|
|
5184
5294
|
});
|
|
5185
|
-
program2.command("trust <agent_id>").description("Get trust summary for an agent").option("--human", "Human-readable output").action(async (agentId, opts) => {
|
|
5295
|
+
program2.command("trust <agent_id>").description("Get trust summary for an agent (per-capability)").option("--human", "Human-readable output").action(async (agentId, opts) => {
|
|
5186
5296
|
await runCommand(async () => {
|
|
5187
5297
|
const { cloud } = buildContext();
|
|
5188
5298
|
return cloud.agents.trust(agentId);
|
|
@@ -5211,24 +5321,29 @@ function parseYamlOrJson(raw) {
|
|
|
5211
5321
|
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return JSON.parse(raw);
|
|
5212
5322
|
return yamlLoad3(raw);
|
|
5213
5323
|
}
|
|
5214
|
-
async function resolveManifestOpt(manifestOpt, manifestId) {
|
|
5215
|
-
if (manifestOpt
|
|
5216
|
-
if (manifestId !== void 0) {
|
|
5324
|
+
async function resolveManifestOpt(manifestOpt, manifestId, intention, defaultIntention) {
|
|
5325
|
+
if (manifestOpt !== void 0 && manifestId !== void 0) {
|
|
5217
5326
|
throw new Error("--manifest and --manifest-id are mutually exclusive");
|
|
5218
5327
|
}
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
raw = await readStdin();
|
|
5222
|
-
} else if (manifestOpt.startsWith("@")) {
|
|
5223
|
-
raw = readFileSync3(manifestOpt.slice(1), "utf8");
|
|
5224
|
-
} else {
|
|
5225
|
-
raw = manifestOpt;
|
|
5328
|
+
if (manifestId !== void 0) {
|
|
5329
|
+
return void 0;
|
|
5226
5330
|
}
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5331
|
+
if (manifestOpt !== void 0) {
|
|
5332
|
+
let raw;
|
|
5333
|
+
if (manifestOpt === "-") {
|
|
5334
|
+
raw = await readStdin();
|
|
5335
|
+
} else if (manifestOpt.startsWith("@")) {
|
|
5336
|
+
raw = readFileSync3(manifestOpt.slice(1), "utf8");
|
|
5337
|
+
} else {
|
|
5338
|
+
raw = manifestOpt;
|
|
5339
|
+
}
|
|
5340
|
+
const parsed = parseJsonOrFail(raw, "--manifest");
|
|
5341
|
+
if (typeof parsed.intention !== "string" || parsed.intention.length === 0) {
|
|
5342
|
+
throw new Error('--manifest must include a non-empty "intention" field');
|
|
5343
|
+
}
|
|
5344
|
+
return parsed;
|
|
5230
5345
|
}
|
|
5231
|
-
return
|
|
5346
|
+
return { intention: intention ?? defaultIntention };
|
|
5232
5347
|
}
|
|
5233
5348
|
|
|
5234
5349
|
// src/bin.ts
|