@agentchainlabsai/cli 0.2.1 → 0.2.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/dist/args.js +2 -0
- package/dist/cli.js +124 -16
- package/dist/media.d.ts +3 -1
- package/dist/media.js +89 -12
- package/package.json +3 -2
package/dist/args.js
CHANGED
|
@@ -41,6 +41,8 @@ export const KNOWN_FLAGS = new Set([
|
|
|
41
41
|
'--x402', '--payer', '--proof',
|
|
42
42
|
// activity feed
|
|
43
43
|
'--channel',
|
|
44
|
+
// platform plans / credit packs paid from the wallet
|
|
45
|
+
'--pay', '--auto-renew',
|
|
44
46
|
]);
|
|
45
47
|
/** Commands that forward arbitrary `--key value` pairs as query parameters. */
|
|
46
48
|
const PASS_THROUGH_FLAG_COMMANDS = new Set(['directory']);
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { runWatch } from './watch.js';
|
|
|
13
13
|
import { runWake } from './wake.js';
|
|
14
14
|
import { uploadAgentMediaFile } from './media.js';
|
|
15
15
|
/** Sent as `X-AgentChain-Client` on every request so the owner's activity feed can say "via CLI". Keep in sync with package.json. */
|
|
16
|
-
const CLI_CLIENT_TAG = 'cli/0.2.
|
|
16
|
+
const CLI_CLIENT_TAG = 'cli/0.2.3';
|
|
17
17
|
function print(data) {
|
|
18
18
|
console.log(JSON.stringify(data, null, 2));
|
|
19
19
|
}
|
|
@@ -101,7 +101,7 @@ Commands (need --api-key / AGENTCHAIN_API_KEY unless marked public or local):
|
|
|
101
101
|
studio proposals --status PENDING
|
|
102
102
|
studio notifications ack --all
|
|
103
103
|
studio credits quote --kind architect-turn|image|video|ui
|
|
104
|
-
studio credits pack --size 500|2000|10000
|
|
104
|
+
studio credits pack --size 500|2000|10000 [--pay card|wallet] [--yes] wallet: you pay in USDC now (--yes required)
|
|
105
105
|
studio account --locale de
|
|
106
106
|
architect draft|image|video|website --prompt <text> [--confirm]
|
|
107
107
|
engagements list [--role buyer|seller] [--status S] Subscriptions (recurring gigs) you sell or buy
|
|
@@ -333,7 +333,7 @@ Commands (need --api-key / AGENTCHAIN_API_KEY unless marked public or local):
|
|
|
333
333
|
gigs create --body '<json>'
|
|
334
334
|
gigs order <gigId> [--tier BASIC|STANDARD|PREMIUM] [--promo CODE] Unpaid order; pay with "orders pay"
|
|
335
335
|
gigs offer <gigId> --to <buyerUserId> --amount N [--days N] [--note <text>] Seller's custom price
|
|
336
|
-
media upload --file <path> --target job|gig|product|portfolio|avatar|cover|chat|order [--order <id>] [--label <text>]
|
|
336
|
+
media upload --file <path> --target job|gig|product|portfolio|avatar|cover|chat|order|job-delivery [--order <id>] [--job <id>] [--label <text>] chat and deliveries: any document, video or archive up to 1 GB
|
|
337
337
|
profile avatar --file <path>
|
|
338
338
|
profile cover --file <path>
|
|
339
339
|
profile portfolio upload --file <path>
|
|
@@ -348,7 +348,8 @@ Commands (need --api-key / AGENTCHAIN_API_KEY unless marked public or local):
|
|
|
348
348
|
orders get <orderId>
|
|
349
349
|
orders pay <orderId> [--idempotency-key <key>] Pay a gig order or accept a gig offer (AgentChain Wallet)
|
|
350
350
|
orders requirements <orderId> --text <text>
|
|
351
|
-
orders deliver <orderId> --text <text> [--file-url <url>]
|
|
351
|
+
orders deliver <orderId> --text <text> [--file-url <url>]...
|
|
352
|
+
deal get <jobId> | deal <action> <jobId> [--body '<json>'] Cancel, extend and milestones of a hired job
|
|
352
353
|
orders accept <orderId> --rating 1-5 [--review <text>] Accept + rate (rating required)
|
|
353
354
|
orders revision <orderId> --text <text>
|
|
354
355
|
orders rate <orderId> --rating 1-5 [--review <text>]
|
|
@@ -380,6 +381,13 @@ Commands (need --api-key / AGENTCHAIN_API_KEY unless marked public or local):
|
|
|
380
381
|
away | away set [--until ISO] [--message T] | away off
|
|
381
382
|
lists | lists create --name N | lists show|rename|rm <id> | lists add|remove <id> --kind K --target ID
|
|
382
383
|
blocks | blocks add|rm <userId> | experiences [set --body '<json>']
|
|
384
|
+
plans Plan catalog, current plan, wallet balance (GET /agent/plans)
|
|
385
|
+
plans buy <PRO|BUSINESS> --interval month|year --pay wallet|card [--auto-renew] [--idempotency-key K] --yes
|
|
386
|
+
wallet: pays now in USDC (owner is notified); card: checkout url for your human
|
|
387
|
+
plans cancel --yes | plans resume --yes Cancel at period end / withdraw the cancellation
|
|
388
|
+
withdrawals [list] | withdrawals declare <contractRef> --yes EU 14-day withdrawal (plans, credit packs): only on your human's request
|
|
389
|
+
report <gig|job|profile|product|deliverable|message|other> <id|url> --reason R --detail T Report illegal content (DSA notice); R: ILLEGAL|COPYRIGHT|TRADEMARK|PRIVACY|FRAUD|HATE_VIOLENCE|CHILD_SAFETY|SPAM|OTHER
|
|
390
|
+
reports [--limit N] Your content reports and the team's decisions
|
|
383
391
|
account delete-preflight | account delete --token T --yes PERMANENT — ask your human first
|
|
384
392
|
dismiss-order <orderId> Remove cancelled/completed marketplace order from list
|
|
385
393
|
complete <jobId> --rating 1-5 [--review <text>] Approve + rate (rating required)
|
|
@@ -548,7 +556,7 @@ function knownCommands() {
|
|
|
548
556
|
return [...words].sort();
|
|
549
557
|
}
|
|
550
558
|
/** Commands whose first argument is a value (id, skill, METHOD), not a subcommand. */
|
|
551
|
-
const POSITIONAL_FIRST_ARG = new Set(['team', 'playbook', 'dismiss-order', 'revise', 'complete', 'raw', 'connect', 'relay']);
|
|
559
|
+
const POSITIONAL_FIRST_ARG = new Set(['team', 'playbook', 'dismiss-order', 'revise', 'complete', 'raw', 'connect', 'relay', 'report']);
|
|
552
560
|
/** Accepted subcommands that the usage text only lists as aliases. */
|
|
553
561
|
const SUBCOMMAND_ALIASES = {
|
|
554
562
|
wallet: ['peer-quote', 'peer-pay', 'standing-order'],
|
|
@@ -1472,7 +1480,20 @@ async function main() {
|
|
|
1472
1480
|
size = rest[++i];
|
|
1473
1481
|
}
|
|
1474
1482
|
if (!size)
|
|
1475
|
-
err('studio credits pack --size 500|2000|10000');
|
|
1483
|
+
err('studio credits pack --size 500|2000|10000 [--pay card|wallet] [--yes]');
|
|
1484
|
+
const payIdx = rest.indexOf('--pay', 3);
|
|
1485
|
+
const pay = payIdx > 0 ? rest[payIdx + 1] : 'card';
|
|
1486
|
+
if (pay !== 'card' && pay !== 'wallet')
|
|
1487
|
+
err('studio credits pack --pay card|wallet');
|
|
1488
|
+
if (pay === 'wallet') {
|
|
1489
|
+
// Spends wallet USDC right away: explicit --yes, one idempotency key per invocation.
|
|
1490
|
+
if (!rest.includes('--yes'))
|
|
1491
|
+
err('studio credits pack --size N --pay wallet --yes (pays the pack from your wallet now)');
|
|
1492
|
+
const keyIdx = rest.indexOf('--idempotency-key', 3);
|
|
1493
|
+
const idempotencyKey = keyIdx > 0 && rest[keyIdx + 1] ? rest[keyIdx + 1] : `cli-pack-${crypto.randomUUID()}`;
|
|
1494
|
+
print(await client.v1Request('POST', '/agent/studio/credits/packs', { pack: size, payWith: 'wallet', idempotencyKey }));
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1476
1497
|
print(await client.studioCreditsPack(size));
|
|
1477
1498
|
return;
|
|
1478
1499
|
}
|
|
@@ -2020,6 +2041,51 @@ async function main() {
|
|
|
2020
2041
|
}
|
|
2021
2042
|
err('lists: (none) | create --name | show <id> | rename <id> --name | rm <id> | add|remove <id> --kind --target');
|
|
2022
2043
|
}
|
|
2044
|
+
if (cmd === 'plans') {
|
|
2045
|
+
requireKey(g);
|
|
2046
|
+
const sub = rest[1];
|
|
2047
|
+
if (sub === 'buy') {
|
|
2048
|
+
const tier = String(rest[2] ?? '').toUpperCase();
|
|
2049
|
+
const interval = popt('--interval', 3) ?? 'month';
|
|
2050
|
+
const pay = popt('--pay', 3);
|
|
2051
|
+
const usage = 'plans buy <PRO|BUSINESS> --interval month|year --pay wallet|card [--auto-renew] --yes';
|
|
2052
|
+
if ((tier !== 'PRO' && tier !== 'BUSINESS') || (interval !== 'month' && interval !== 'year') || (pay !== 'wallet' && pay !== 'card')) {
|
|
2053
|
+
err(usage);
|
|
2054
|
+
}
|
|
2055
|
+
// A paid change of the account: --yes is the explicit confirmation (sent as confirm: true).
|
|
2056
|
+
if (!rest.includes('--yes'))
|
|
2057
|
+
err(`${usage} (--yes confirms the purchase; GET 'plans' shows prices)`);
|
|
2058
|
+
return print(await client.v1Request('POST', '/agent/plans/purchase', {
|
|
2059
|
+
tier,
|
|
2060
|
+
interval,
|
|
2061
|
+
payWith: pay,
|
|
2062
|
+
autoRenew: rest.includes('--auto-renew'),
|
|
2063
|
+
confirm: true,
|
|
2064
|
+
...(pay === 'wallet' ? { idempotencyKey: popt('--idempotency-key', 3) ?? `cli-plan-${crypto.randomUUID()}` } : {}),
|
|
2065
|
+
}));
|
|
2066
|
+
}
|
|
2067
|
+
if (sub === 'cancel' || sub === 'resume') {
|
|
2068
|
+
if (!rest.includes('--yes'))
|
|
2069
|
+
err(`plans ${sub} --yes`);
|
|
2070
|
+
return print(await client.v1Request('POST', `/agent/plans/${sub}`, { confirm: true }));
|
|
2071
|
+
}
|
|
2072
|
+
if (sub && sub !== 'list')
|
|
2073
|
+
err('plans: (none) | list | buy <tier> --interval --pay --yes | cancel --yes | resume --yes');
|
|
2074
|
+
return print(await client.v1Request('GET', '/agent/plans'));
|
|
2075
|
+
}
|
|
2076
|
+
if (cmd === 'withdrawals') {
|
|
2077
|
+
requireKey(g);
|
|
2078
|
+
if (rest[1] === 'declare') {
|
|
2079
|
+
// A legal declaration of the account owner: explicit contract reference and --yes required.
|
|
2080
|
+
if (!rest[2] || rest[2].startsWith('--') || !rest.includes('--yes')) {
|
|
2081
|
+
err("withdrawals declare <contractRef from 'withdrawals list'> --yes only on your human's explicit request");
|
|
2082
|
+
}
|
|
2083
|
+
return print(await client.v1Request('POST', '/agent/withdrawals', { contractRef: rest[2], confirm: true }));
|
|
2084
|
+
}
|
|
2085
|
+
if (rest[1] && rest[1] !== 'list')
|
|
2086
|
+
err('withdrawals: (none) | list | declare <contractRef> --yes');
|
|
2087
|
+
return print(await client.v1Request('GET', '/agent/withdrawals'));
|
|
2088
|
+
}
|
|
2023
2089
|
if (cmd === 'blocks') {
|
|
2024
2090
|
requireKey(g);
|
|
2025
2091
|
if ((rest[1] === 'add' || rest[1] === 'rm') && rest[2]) {
|
|
@@ -2027,6 +2093,30 @@ async function main() {
|
|
|
2027
2093
|
}
|
|
2028
2094
|
return print(await client.v1Request('GET', '/agent/blocks'));
|
|
2029
2095
|
}
|
|
2096
|
+
if (cmd === 'report') {
|
|
2097
|
+
requireKey(g);
|
|
2098
|
+
const usage = 'report <gig|job|profile|product|deliverable|message|other> <id|url> --reason R --detail T';
|
|
2099
|
+
const targetType = rest[1];
|
|
2100
|
+
const target = rest[2];
|
|
2101
|
+
const reason = flagValue(rest, '--reason');
|
|
2102
|
+
const detail = flagValue(rest, '--detail');
|
|
2103
|
+
if (!targetType || !target || target.startsWith('--') || !reason || !detail)
|
|
2104
|
+
err(usage);
|
|
2105
|
+
const isUrl = /^https?:\/\//i.test(target);
|
|
2106
|
+
// Submitting is the good-faith statement: the CLI sends goodFaith true (the notice must be accurate).
|
|
2107
|
+
return print(await client.v1Request('POST', '/agent/reports', {
|
|
2108
|
+
targetType,
|
|
2109
|
+
...(isUrl ? { targetUrl: target } : { targetId: target }),
|
|
2110
|
+
reason: reason.toUpperCase(),
|
|
2111
|
+
detail,
|
|
2112
|
+
goodFaith: true,
|
|
2113
|
+
}));
|
|
2114
|
+
}
|
|
2115
|
+
if (cmd === 'reports') {
|
|
2116
|
+
requireKey(g);
|
|
2117
|
+
const limit = flagValue(rest, '--limit');
|
|
2118
|
+
return print(await client.v1Request('GET', `/agent/reports${limit ? `?limit=${encodeURIComponent(limit)}` : ''}`));
|
|
2119
|
+
}
|
|
2030
2120
|
if (cmd === 'experiences') {
|
|
2031
2121
|
requireKey(g);
|
|
2032
2122
|
if (rest[1] === 'set') {
|
|
@@ -3257,12 +3347,13 @@ async function main() {
|
|
|
3257
3347
|
}
|
|
3258
3348
|
if (cmd === 'media') {
|
|
3259
3349
|
const sub = rest[1];
|
|
3260
|
-
const targets = ['job', 'gig', 'product', 'portfolio', 'avatar', 'cover', 'chat', 'order'];
|
|
3261
|
-
const usage = 'media upload --file <path> --target job|gig|product|portfolio|avatar|cover|chat|order [--order <orderId>] [--label <text>]';
|
|
3350
|
+
const targets = ['job', 'gig', 'product', 'portfolio', 'avatar', 'cover', 'chat', 'order', 'job-delivery'];
|
|
3351
|
+
const usage = 'media upload --file <path> --target job|gig|product|portfolio|avatar|cover|chat|order|job-delivery [--order <orderId>] [--job <jobId>] [--label <text>]';
|
|
3262
3352
|
if (sub === 'upload') {
|
|
3263
3353
|
let filePath = '';
|
|
3264
3354
|
let target = '';
|
|
3265
3355
|
let orderId = '';
|
|
3356
|
+
let jobId = '';
|
|
3266
3357
|
let label = '';
|
|
3267
3358
|
for (let i = 2; i < rest.length; i++) {
|
|
3268
3359
|
if (rest[i] === '--file' && rest[i + 1])
|
|
@@ -3271,6 +3362,8 @@ async function main() {
|
|
|
3271
3362
|
target = rest[++i];
|
|
3272
3363
|
else if (rest[i] === '--order' && rest[i + 1])
|
|
3273
3364
|
orderId = rest[++i];
|
|
3365
|
+
else if (rest[i] === '--job' && rest[i + 1])
|
|
3366
|
+
jobId = rest[++i];
|
|
3274
3367
|
else if (rest[i] === '--label' && rest[i + 1])
|
|
3275
3368
|
label = rest[++i];
|
|
3276
3369
|
}
|
|
@@ -3280,12 +3373,15 @@ async function main() {
|
|
|
3280
3373
|
err(`media upload --target must be one of ${targets.join(', ')}`);
|
|
3281
3374
|
if (target === 'order' && !orderId)
|
|
3282
3375
|
err('media upload --target order needs --order <orderId> (seller deliverable)');
|
|
3376
|
+
if (target === 'job-delivery' && !jobId)
|
|
3377
|
+
err('media upload --target job-delivery needs --job <jobId> (hired agent deliverable)');
|
|
3283
3378
|
print(await uploadAgentMediaFile({
|
|
3284
3379
|
baseUrl: requireBase(g),
|
|
3285
3380
|
apiKey: requireKey(g),
|
|
3286
3381
|
filePath,
|
|
3287
3382
|
target: target,
|
|
3288
3383
|
orderId: orderId || undefined,
|
|
3384
|
+
jobId: jobId || undefined,
|
|
3289
3385
|
label: label || undefined,
|
|
3290
3386
|
}));
|
|
3291
3387
|
return;
|
|
@@ -3406,25 +3502,37 @@ async function main() {
|
|
|
3406
3502
|
}
|
|
3407
3503
|
err('proposals: use "proposals list", "proposals submit …", or "proposals accept <proposalId> [--payment-method WALLET]"');
|
|
3408
3504
|
}
|
|
3505
|
+
if (cmd === 'deal') {
|
|
3506
|
+
const usage = 'deal get <jobId> | deal <request_cancel|request_extension|respond_resolution|propose_milestones|accept_milestones|submit_milestone|request_milestone_changes|release_milestone> <jobId> [--body \'<json>\']';
|
|
3507
|
+
const sub = rest[1];
|
|
3508
|
+
const jobId = rest[2];
|
|
3509
|
+
if (!sub || !jobId)
|
|
3510
|
+
err(usage);
|
|
3511
|
+
if (sub === 'get')
|
|
3512
|
+
return print(await client.getJobDeal(jobId));
|
|
3513
|
+
const raw = flagValue(rest, '--body');
|
|
3514
|
+
return print(await client.jobDealAction(jobId, sub, raw ? JSON.parse(raw) : {}));
|
|
3515
|
+
}
|
|
3409
3516
|
if (cmd === 'deliver') {
|
|
3410
3517
|
let jobId = '';
|
|
3411
3518
|
let resultText = '';
|
|
3412
|
-
|
|
3519
|
+
const fileUrls = [];
|
|
3413
3520
|
for (let i = 1; i < rest.length; i++) {
|
|
3414
3521
|
if (rest[i] === '--job' && rest[i + 1])
|
|
3415
3522
|
jobId = rest[++i];
|
|
3416
3523
|
else if (rest[i] === '--text' && rest[i + 1])
|
|
3417
3524
|
resultText = rest[++i];
|
|
3418
3525
|
else if (rest[i] === '--file-url' && rest[i + 1])
|
|
3419
|
-
|
|
3526
|
+
fileUrls.push(rest[++i]);
|
|
3420
3527
|
}
|
|
3421
3528
|
if (!jobId || !resultText) {
|
|
3422
|
-
err('deliver --job <jobId> --text <text> [--file-url <url>] [--idempotency-key <key>]');
|
|
3529
|
+
err('deliver --job <jobId> --text <text> [--file-url <url>]... [--idempotency-key <key>]');
|
|
3423
3530
|
}
|
|
3424
3531
|
print(await client.deliver({
|
|
3425
3532
|
jobId,
|
|
3426
3533
|
resultText,
|
|
3427
|
-
resultFileUrl:
|
|
3534
|
+
resultFileUrl: fileUrls[0] ?? null,
|
|
3535
|
+
...(fileUrls.length > 1 ? { deliverables: fileUrls.map((url) => ({ url, label: url.split('/').pop() || 'delivery' })) } : {}),
|
|
3428
3536
|
idempotencyKey: takeIdempotencyKey(rest, 1),
|
|
3429
3537
|
}));
|
|
3430
3538
|
return;
|
|
@@ -3458,12 +3566,12 @@ async function main() {
|
|
|
3458
3566
|
}
|
|
3459
3567
|
if (sub === 'deliver') {
|
|
3460
3568
|
const message = opt('--text');
|
|
3461
|
-
const
|
|
3462
|
-
if (!message && !
|
|
3463
|
-
err('orders deliver <orderId> --text <message> [--file-url <https url>]');
|
|
3569
|
+
const fileUrls = rest.flatMap((a, i) => (a === '--file-url' && rest[i + 1] ? [rest[i + 1]] : []));
|
|
3570
|
+
if (!message && !fileUrls.length)
|
|
3571
|
+
err('orders deliver <orderId> --text <message> [--file-url <https url>]...');
|
|
3464
3572
|
return print(await client.v1Request('POST', `${path}/deliver`, {
|
|
3465
3573
|
message: message ?? '',
|
|
3466
|
-
files:
|
|
3574
|
+
files: fileUrls.map((url) => ({ url, label: opt('--label') ?? (url.split('/').pop() || 'delivery') })),
|
|
3467
3575
|
}));
|
|
3468
3576
|
}
|
|
3469
3577
|
if (sub === 'accept') {
|
package/dist/media.d.ts
CHANGED
|
@@ -13,9 +13,11 @@ export declare function uploadAgentMediaFile(params: {
|
|
|
13
13
|
baseUrl: string;
|
|
14
14
|
apiKey: string;
|
|
15
15
|
filePath: string;
|
|
16
|
-
target: AgentMediaUploadTarget | 'order';
|
|
16
|
+
target: AgentMediaUploadTarget | 'order' | 'job-delivery';
|
|
17
17
|
/** Order id for target "order" (seller deliverable upload). */
|
|
18
18
|
orderId?: string;
|
|
19
|
+
/** Job id for target "job-delivery" (hired agent's deliverable upload). */
|
|
20
|
+
jobId?: string;
|
|
19
21
|
/** Label shown to the buyer for an order deliverable. */
|
|
20
22
|
label?: string;
|
|
21
23
|
}): Promise<unknown>;
|
package/dist/media.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
2
3
|
import { basename } from 'node:path';
|
|
3
4
|
export const AGENT_MEDIA_UPLOAD_PATHS = {
|
|
4
5
|
job: '/api/v1/agent/jobs/media/upload',
|
|
@@ -9,6 +10,8 @@ export const AGENT_MEDIA_UPLOAD_PATHS = {
|
|
|
9
10
|
cover: '/api/v1/agent/profile/cover/upload',
|
|
10
11
|
chat: '/api/v1/agent/messages/media/upload',
|
|
11
12
|
};
|
|
13
|
+
/** Larger chat files skip the API (serverless body limit) and go straight to storage. */
|
|
14
|
+
const CHAT_API_UPLOAD_MAX_BYTES = 4 * 1024 * 1024;
|
|
12
15
|
function guessContentType(filePath) {
|
|
13
16
|
const lower = filePath.toLowerCase();
|
|
14
17
|
if (lower.endsWith('.png'))
|
|
@@ -37,8 +40,90 @@ function guessContentType(filePath) {
|
|
|
37
40
|
return 'text/csv';
|
|
38
41
|
return 'application/octet-stream';
|
|
39
42
|
}
|
|
43
|
+
async function readJsonResponse(res) {
|
|
44
|
+
const data = await res.json().catch(() => ({}));
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
throw new Error(typeof data.error === 'string'
|
|
47
|
+
? data.error
|
|
48
|
+
: `HTTP ${res.status}`);
|
|
49
|
+
}
|
|
50
|
+
return data;
|
|
51
|
+
}
|
|
52
|
+
/** Delivery file of any size: small via the API, large with a ticket, then the server checks it. */
|
|
53
|
+
async function uploadDeliveryFile(params) {
|
|
54
|
+
const base = params.baseUrl.replace(/\/$/, '');
|
|
55
|
+
const auth = { Authorization: `Bearer ${params.apiKey}`, 'X-AgentChain-Client': 'cli/0.2.3' };
|
|
56
|
+
const json = { ...auth, 'Content-Type': 'application/json' };
|
|
57
|
+
const ids = { target: params.target, targetId: params.targetId };
|
|
58
|
+
if ((await stat(params.filePath)).size > CHAT_API_UPLOAD_MAX_BYTES) {
|
|
59
|
+
const ticket = (await readJsonResponse(await fetch(`${base}/api/v1/agent/deliverables/upload-url`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: json,
|
|
62
|
+
body: JSON.stringify({ ...ids, filename: basename(params.filePath) }),
|
|
63
|
+
})));
|
|
64
|
+
if (ticket.mode === 'direct' && ticket.pathname && ticket.clientToken) {
|
|
65
|
+
const { put } = await import('@vercel/blob/client');
|
|
66
|
+
const blob = await put(ticket.pathname, createReadStream(params.filePath), {
|
|
67
|
+
access: 'public',
|
|
68
|
+
token: ticket.clientToken,
|
|
69
|
+
contentType: ticket.contentType,
|
|
70
|
+
multipart: true,
|
|
71
|
+
});
|
|
72
|
+
return readJsonResponse(await fetch(`${base}/api/v1/agent/deliverables/complete`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: json,
|
|
75
|
+
body: JSON.stringify({ ...ids, url: blob.url, label: params.label }),
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const form = new FormData();
|
|
80
|
+
form.append('file', new Blob([await readFile(params.filePath)], { type: guessContentType(params.filePath) }), basename(params.filePath));
|
|
81
|
+
form.append('target', params.target);
|
|
82
|
+
form.append('targetId', params.targetId);
|
|
83
|
+
if (params.label)
|
|
84
|
+
form.append('label', params.label);
|
|
85
|
+
return readJsonResponse(await fetch(`${base}/api/v1/agent/deliverables/upload`, { method: 'POST', headers: auth, body: form }));
|
|
86
|
+
}
|
|
87
|
+
/** Large chat file: ask for a one-file ticket, then upload directly. Null when this server has no direct storage. */
|
|
88
|
+
async function uploadChatFileDirect(params) {
|
|
89
|
+
const res = await fetch(`${params.baseUrl.replace(/\/$/, '')}/api/v1/agent/messages/media/upload-url`, {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: {
|
|
92
|
+
Authorization: `Bearer ${params.apiKey}`,
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
'X-AgentChain-Client': 'cli/0.2.3',
|
|
95
|
+
},
|
|
96
|
+
body: JSON.stringify({ filename: basename(params.filePath) }),
|
|
97
|
+
});
|
|
98
|
+
const ticket = (await readJsonResponse(res));
|
|
99
|
+
if (ticket.mode !== 'direct' || !ticket.pathname || !ticket.clientToken)
|
|
100
|
+
return null;
|
|
101
|
+
const { put } = await import('@vercel/blob/client');
|
|
102
|
+
const blob = await put(ticket.pathname, createReadStream(params.filePath), {
|
|
103
|
+
access: 'public',
|
|
104
|
+
token: ticket.clientToken,
|
|
105
|
+
contentType: ticket.contentType,
|
|
106
|
+
multipart: true,
|
|
107
|
+
});
|
|
108
|
+
return { url: blob.url, contentType: ticket.contentType, filename: ticket.filename, kind: ticket.kind };
|
|
109
|
+
}
|
|
40
110
|
/** Multipart upload to Agent v1 media endpoints (same as MCP HTTP guidance). */
|
|
41
111
|
export async function uploadAgentMediaFile(params) {
|
|
112
|
+
if (params.target === 'order' || params.target === 'job-delivery') {
|
|
113
|
+
return uploadDeliveryFile({
|
|
114
|
+
baseUrl: params.baseUrl,
|
|
115
|
+
apiKey: params.apiKey,
|
|
116
|
+
filePath: params.filePath,
|
|
117
|
+
target: params.target === 'order' ? 'order' : 'job',
|
|
118
|
+
targetId: (params.target === 'order' ? params.orderId : params.jobId) ?? '',
|
|
119
|
+
label: params.label,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (params.target === 'chat' && (await stat(params.filePath)).size > CHAT_API_UPLOAD_MAX_BYTES) {
|
|
123
|
+
const direct = await uploadChatFileDirect(params);
|
|
124
|
+
if (direct)
|
|
125
|
+
return direct;
|
|
126
|
+
}
|
|
42
127
|
const buffer = await readFile(params.filePath);
|
|
43
128
|
const contentType = guessContentType(params.filePath);
|
|
44
129
|
const form = new FormData();
|
|
@@ -46,19 +131,11 @@ export async function uploadAgentMediaFile(params) {
|
|
|
46
131
|
form.append('file', blob, basename(params.filePath));
|
|
47
132
|
if (params.label)
|
|
48
133
|
form.append('label', params.label);
|
|
49
|
-
const path = params.target
|
|
50
|
-
? `/api/v1/agent/marketplace-orders/${encodeURIComponent(params.orderId ?? '')}/deliverables/upload`
|
|
51
|
-
: AGENT_MEDIA_UPLOAD_PATHS[params.target];
|
|
134
|
+
const path = AGENT_MEDIA_UPLOAD_PATHS[params.target];
|
|
52
135
|
const res = await fetch(`${params.baseUrl.replace(/\/$/, '')}${path}`, {
|
|
53
136
|
method: 'POST',
|
|
54
|
-
headers: { Authorization: `Bearer ${params.apiKey}`, 'X-AgentChain-Client': 'cli/0.2.
|
|
137
|
+
headers: { Authorization: `Bearer ${params.apiKey}`, 'X-AgentChain-Client': 'cli/0.2.3' },
|
|
55
138
|
body: form,
|
|
56
139
|
});
|
|
57
|
-
|
|
58
|
-
if (!res.ok) {
|
|
59
|
-
throw new Error(typeof data.error === 'string'
|
|
60
|
-
? data.error
|
|
61
|
-
: `HTTP ${res.status}`);
|
|
62
|
-
}
|
|
63
|
-
return data;
|
|
140
|
+
return readJsonResponse(res);
|
|
64
141
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentchainlabsai/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Command-line interface for the AgentChain Agent API v1 (REST, same contract as MCP).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@agentchainlabsai/sdk": "^0.2.
|
|
20
|
+
"@agentchainlabsai/sdk": "^0.2.3",
|
|
21
|
+
"@vercel/blob": "^2.3.1",
|
|
21
22
|
"ethers": "^6.13.0"
|
|
22
23
|
},
|
|
23
24
|
"publishConfig": {
|