@bnbagent/studio-cli 0.0.10 → 0.0.11-alpha.1
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/LICENSE +201 -0
- package/README.md +2 -2
- package/dist/_agentcoreName-DZDWEYD3.js +0 -0
- package/dist/_twak-4XF4H5PL.js +0 -0
- package/dist/bag.js +317 -124
- package/dist/chunk-RO726HJG.js +0 -0
- package/dist/{chunk-YFEM4564.js → chunk-TTPOH453.js} +79 -37
- package/dist/chunk-U7IDQ3K5.js +0 -0
- package/dist/{deployCli-NJFCWBSF.js → deployCli-K55GXDVO.js} +1 -1
- package/package.json +11 -12
- package/recipes/runtimes/agentcore/code/{{PKG}}/Dockerfile.tmpl +20 -21
- package/recipes/runtimes/agentcore/code/{{PKG}}/executor.ts.tmpl +36 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
- package/recipes/runtimes/agentcore/recipe.toml +3 -3
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/Dockerfile.tmpl +25 -23
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/agentCard.ts.tmpl +16 -12
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/executor.ts.tmpl +72 -393
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/mcpMain.ts.tmpl +160 -43
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/sellerCore.ts.tmpl +504 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
- package/recipes/runtimes/azure-foundry/recipe.toml +19 -11
- package/recipes/x402-buyer/code/{{PKG}}/x402Buyer.ts.tmpl +6 -4
- package/skills/bnbagent-studio.md +2 -2
- package/skills/references/bnbagent-studio-adding-to-project.md +1 -1
- package/skills/references/bnbagent-studio-buying-from-bazaar.md +1 -1
- package/skills/references/bnbagent-studio-operating.md +4 -4
- package/skills/references/bnbagent-studio-scaffolding-agent.md +4 -4
- package/skills/references/bnbagent-studio-selling-via-8183.md +3 -3
- package/skills/references/bnbagent-studio-selling-via-b402.md +2 -2
- package/skills/references/bnbagent-studio-use-aws-agentcore.md +1 -1
- package/skills/references/bnbagent-studio-use-azure-foundry.md +3 -3
- package/skills/references/bnbagent-studio-use-bnb-trial.md +1 -1
- package/skills/references/bnbagent-studio-wiring-llm-tools.md +3 -3
- package/recipes/runtimes/agentcore/code/{{PKG}}/main.ts.tmpl +0 -347
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/foundryMain.ts.tmpl +0 -422
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/main.ts.tmpl +0 -196
package/dist/chunk-RO726HJG.js
CHANGED
|
File without changes
|
|
@@ -27,6 +27,11 @@ import { build as esbuildBuild } from "esbuild";
|
|
|
27
27
|
|
|
28
28
|
// src/cli/utils/protocol.ts
|
|
29
29
|
var SUPPORTED_FACES = ["A2A", "MCP", "X402"];
|
|
30
|
+
var LEGACY_ENTRY_STEMS = {
|
|
31
|
+
unifiedMain: ["main", "foundryMain"],
|
|
32
|
+
mcpMain: [],
|
|
33
|
+
dualMain: []
|
|
34
|
+
};
|
|
30
35
|
function table(value) {
|
|
31
36
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
32
37
|
}
|
|
@@ -95,7 +100,7 @@ function entryStemOf(faces) {
|
|
|
95
100
|
if (hasA2aFace(faces) && hasMcpFace(faces)) {
|
|
96
101
|
return "dualMain";
|
|
97
102
|
}
|
|
98
|
-
return nativeProtocolOf(faces) === "MCP" ? "mcpMain" : "
|
|
103
|
+
return nativeProtocolOf(faces) === "MCP" ? "mcpMain" : "unifiedMain";
|
|
99
104
|
}
|
|
100
105
|
function devPortOf(faces) {
|
|
101
106
|
return nativeProtocolOf(faces) === "MCP" ? 8e3 : 9e3;
|
|
@@ -151,12 +156,16 @@ async function buildZip(agentDir, outZip, opts = {}) {
|
|
|
151
156
|
return { checksum: sha256File(outZip), entrypoint };
|
|
152
157
|
}
|
|
153
158
|
function resolveEntry(agentDir, stem) {
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
path.join(agentDir, `${stem}.ts`),
|
|
158
|
-
path.join(agentDir, `${stem}.js`)
|
|
159
|
+
const stems = [
|
|
160
|
+
stem,
|
|
161
|
+
...LEGACY_ENTRY_STEMS[stem] ?? []
|
|
159
162
|
];
|
|
163
|
+
const candidates = stems.flatMap((s) => [
|
|
164
|
+
path.join(agentDir, "src", `${s}.ts`),
|
|
165
|
+
path.join(agentDir, "dist", `${s}.js`),
|
|
166
|
+
path.join(agentDir, `${s}.ts`),
|
|
167
|
+
path.join(agentDir, `${s}.js`)
|
|
168
|
+
]);
|
|
160
169
|
for (const candidate of candidates) {
|
|
161
170
|
if (isFile(candidate)) {
|
|
162
171
|
return candidate;
|
|
@@ -166,29 +175,49 @@ function resolveEntry(agentDir, stem) {
|
|
|
166
175
|
`no ${stem}.ts/${stem}.js entry found under ${agentDir} (looked in src/, dist/, and the project root) \u2014 the zip channel bundles the protocol entry the scaffold emitted. Re-scaffold with \`bag init\`, or switch [deploy].platform_artifact to "container".`
|
|
167
176
|
);
|
|
168
177
|
}
|
|
178
|
+
var BUNDLE_OPTIONS = {
|
|
179
|
+
bundle: true,
|
|
180
|
+
platform: "node",
|
|
181
|
+
target: TARGET_NODE,
|
|
182
|
+
format: "esm",
|
|
183
|
+
legalComments: "none",
|
|
184
|
+
sourcemap: false,
|
|
185
|
+
logLevel: "silent",
|
|
186
|
+
banner: {
|
|
187
|
+
js: 'import { createRequire as __bagCreateRequire } from "node:module";const require = __bagCreateRequire(import.meta.url);'
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
function bundleFailure(exc) {
|
|
191
|
+
const msg = exc instanceof Error ? exc.message : String(exc);
|
|
192
|
+
return new Error(
|
|
193
|
+
`bundling the agent for the zip runtime failed \u2014 a dependency likely cannot be bundled (native addon / dynamic import esbuild cannot resolve). Fix the import, or set [deploy].platform_artifact = "container". esbuild said:
|
|
194
|
+
${msg.slice(0, 1e3)}`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
169
197
|
async function bundleEntry(entry, outfile) {
|
|
170
198
|
try {
|
|
171
199
|
await esbuildBuild({
|
|
200
|
+
...BUNDLE_OPTIONS,
|
|
172
201
|
entryPoints: [entry],
|
|
173
202
|
outfile,
|
|
174
|
-
|
|
175
|
-
platform: "node",
|
|
176
|
-
target: TARGET_NODE,
|
|
177
|
-
format: "esm",
|
|
178
|
-
minify: true,
|
|
179
|
-
legalComments: "none",
|
|
180
|
-
sourcemap: false,
|
|
181
|
-
logLevel: "silent",
|
|
182
|
-
banner: {
|
|
183
|
-
js: 'import { createRequire as __bagCreateRequire } from "node:module";const require = __bagCreateRequire(import.meta.url);'
|
|
184
|
-
}
|
|
203
|
+
minify: true
|
|
185
204
|
});
|
|
186
205
|
} catch (exc) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
206
|
+
throw bundleFailure(exc);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async function dryRunBundle(agentDir, opts = {}) {
|
|
210
|
+
const faces = opts.protocols ?? normalizeProtocolFaces(opts.protocol ?? "A2A");
|
|
211
|
+
const entry = resolveEntry(agentDir, entryStemOf(faces));
|
|
212
|
+
try {
|
|
213
|
+
await esbuildBuild({
|
|
214
|
+
...BUNDLE_OPTIONS,
|
|
215
|
+
entryPoints: [entry],
|
|
216
|
+
write: false,
|
|
217
|
+
minify: false
|
|
218
|
+
});
|
|
219
|
+
} catch (exc) {
|
|
220
|
+
throw bundleFailure(exc);
|
|
192
221
|
}
|
|
193
222
|
}
|
|
194
223
|
function stageManifest(agentDir, buildRoot, entrypoint) {
|
|
@@ -714,6 +743,10 @@ var B402_RUNTIME_KEYS = [
|
|
|
714
743
|
"B402_PRIVATE_KEY",
|
|
715
744
|
"B402_PRIVATE_KEY_B64"
|
|
716
745
|
];
|
|
746
|
+
var X402_CAPABLE_RUNTIMES = /* @__PURE__ */ new Set([
|
|
747
|
+
"agentcore",
|
|
748
|
+
"azure-foundry"
|
|
749
|
+
]);
|
|
717
750
|
function commerceRails(cfg) {
|
|
718
751
|
const payments = table3(cfg.payments);
|
|
719
752
|
return {
|
|
@@ -760,21 +793,25 @@ function x402DeploySummary(root, destination, publicUrl) {
|
|
|
760
793
|
const credentials = b402Credentials(agentRoot);
|
|
761
794
|
const activation = `${B402_PAID_ONBOARDING_GUIDANCE} Then run the bnbagent-studio-selling-via-b402 skill, fill the four B402_* variables in .studio/.env.local, and redeploy.`;
|
|
762
795
|
const runtime = String(table3(cfg.stack).runtime ?? "agentcore");
|
|
763
|
-
if (destination !== "platform" && runtime
|
|
764
|
-
return `x402 rail is FORCED DORMANT: the ${runtime} runtime has no x402 path. Deploy to AgentCore (managed platform or self-hosted) to activate the rail.`;
|
|
796
|
+
if (destination !== "platform" && !X402_CAPABLE_RUNTIMES.has(runtime)) {
|
|
797
|
+
return `x402 rail is FORCED DORMANT: the ${runtime} runtime has no x402 path. Deploy to AgentCore or Azure Foundry (managed platform or self-hosted) to activate the rail.`;
|
|
765
798
|
}
|
|
799
|
+
const azure = runtime === "azure-foundry";
|
|
800
|
+
const runtimeLabel = azure ? "Azure Foundry" : "AgentCore";
|
|
801
|
+
const tunnelLine = azure ? 'The front wraps each request as envelope-v1 JSON, {"v":1,"method":"POST","path":"/x402","headers":{...},"body":"<base64>"}, inside an Entra-authenticated Foundry invocation (POST \u2026/agents/<name>/endpoint/protocols/invocations with an https://ai.azure.com bearer). Limits: 1 MiB request, 5 MiB response, no streaming.' : 'The front wraps each request as envelope-v1 JSON, {"v":1,"method":"POST","path":"/x402","headers":{...},"body":"<base64>"}, inside an authenticated AgentCore invocation. The default Bag self-deploy uses Cognito OAuth over HTTPS; IAM runtimes may use SDK/SigV4. Limits: 1 MiB request, 5 MiB response, no streaming.';
|
|
802
|
+
const gatewayDocLine = azure ? "Gateway example: https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/guides/self-hosted-x402-gateway-azure.md" : "Gateway example: https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/guides/self-hosted-x402-gateway.md";
|
|
766
803
|
if (pricing.kind === "invalid") {
|
|
767
804
|
return "x402 rail is DORMANT: price_usd is invalid; run `bag doctor`.";
|
|
768
805
|
}
|
|
769
806
|
if (pricing.kind === "free") {
|
|
770
807
|
if (destination !== "platform") {
|
|
771
808
|
return [
|
|
772
|
-
|
|
809
|
+
`x402 rail is ACTIVE in FREE mode (self-hosted ${runtimeLabel}).`,
|
|
773
810
|
"B402 verify/settle is bypassed; no credentials, token payment, or settlement audit is used.",
|
|
774
811
|
"This target has no anonymous public URL; expose /x402 with your own HTTP front.",
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
812
|
+
tunnelLine,
|
|
813
|
+
`You may invoke ${runtimeLabel} with envelope-v1 directly, but that is not a standard public x402 HTTP endpoint.`,
|
|
814
|
+
gatewayDocLine
|
|
778
815
|
].join("\n");
|
|
779
816
|
}
|
|
780
817
|
const url2 = publicUrl ?? "<available after the platform agentId is assigned>";
|
|
@@ -793,13 +830,14 @@ function x402DeploySummary(root, destination, publicUrl) {
|
|
|
793
830
|
"Compatibility note: current @bnb-chain/b402@0.1.0 makes one settle call and classifies an asynchronous pending response as outcome unknown; reconcile it and do not replay the paid request."
|
|
794
831
|
];
|
|
795
832
|
if (destination !== "platform") {
|
|
833
|
+
const egressLine = azure ? "PAID also needs fixed facilitator egress. Host the gateway on Azure Container Apps in a workload-profiles environment with a VNet + NAT Gateway static IP and allowlist that IP with B402 \u2014 no relay needed." : "PAID also needs fixed facilitator egress. Operate a restricted B402 Relay on a fixed-IP host such as a user-managed VPS, or use AgentCore VPC mode with a private subnet, NAT Gateway, and Elastic IP.";
|
|
796
834
|
return [
|
|
797
|
-
|
|
835
|
+
`x402 rail is ACTIVE (self-hosted ${runtimeLabel}).`,
|
|
798
836
|
"This target has no anonymous public URL; expose /x402 with your own HTTP front.",
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
"Gateway and Relay examples:
|
|
837
|
+
tunnelLine,
|
|
838
|
+
`You may invoke ${runtimeLabel} with envelope-v1 directly, but the caller must unpack the inner HTTP response and the result is not a standard public x402 endpoint.`,
|
|
839
|
+
egressLine,
|
|
840
|
+
gatewayDocLine.replace("Gateway example:", "Gateway and Relay examples:"),
|
|
803
841
|
...settlement
|
|
804
842
|
].join("\n");
|
|
805
843
|
}
|
|
@@ -808,7 +846,7 @@ function x402DeploySummary(root, destination, publicUrl) {
|
|
|
808
846
|
"x402 rail is ACTIVE.",
|
|
809
847
|
`Anonymous paid URL: ${url}`,
|
|
810
848
|
"The managed platform supplies the x402 HTTP Gateway and the fixed-egress B402 Relay; no user-managed gateway, proxy, or VPC is required.",
|
|
811
|
-
|
|
849
|
+
`Payment policy and RSA signing remain inside the ${runtimeLabel} seller. The B402 Relay only forwards the signed request to its fixed facilitator upstream.`,
|
|
812
850
|
...settlement
|
|
813
851
|
].join("\n");
|
|
814
852
|
}
|
|
@@ -820,7 +858,7 @@ function isTable(value) {
|
|
|
820
858
|
}
|
|
821
859
|
|
|
822
860
|
// src/cli/_deploy/deployCli.ts
|
|
823
|
-
var DEPLOY_CLI_VERSION = "0.5.
|
|
861
|
+
var DEPLOY_CLI_VERSION = "0.5.10";
|
|
824
862
|
var DEPLOY_CLI_PACKAGE = `@bnbagent/deploy-cli@${DEPLOY_CLI_VERSION}`;
|
|
825
863
|
var BNB_PLATFORM_API_URL = "https://bnbagent-api.bnbchain.world";
|
|
826
864
|
var BNB_PLATFORM_API_URL_ENV = "BNBAGENT_API_URL";
|
|
@@ -1002,7 +1040,7 @@ function buildDeploySpec(root, opts) {
|
|
|
1002
1040
|
if (opts.inlineSecrets) {
|
|
1003
1041
|
Object.assign(env, opts.inlineSecrets);
|
|
1004
1042
|
}
|
|
1005
|
-
if (opts.target === "bnb/trial" &&
|
|
1043
|
+
if (opts.target === "bnb/trial" && (!hasProtocolsArray || hasX402Face(faces)) && commerceRails(studio).x402 && (x402SellerIsFree(studio) || b402Credentials(agentRoot).complete)) {
|
|
1006
1044
|
doc.x402 = {
|
|
1007
1045
|
publicPaths: ["/x402"],
|
|
1008
1046
|
tunnel: "http-envelope-v1"
|
|
@@ -1014,7 +1052,7 @@ function buildDeploySpec(root, opts) {
|
|
|
1014
1052
|
tunnel: "http-envelope-v1"
|
|
1015
1053
|
};
|
|
1016
1054
|
}
|
|
1017
|
-
if (opts.target === "bnb/trial" &&
|
|
1055
|
+
if (opts.target === "bnb/trial" && hasProtocolsArray && faces.length === 1 && hasX402Face(faces)) {
|
|
1018
1056
|
doc.suppressProtocolFace = true;
|
|
1019
1057
|
}
|
|
1020
1058
|
doc.env = env;
|
|
@@ -1214,6 +1252,7 @@ export {
|
|
|
1214
1252
|
act,
|
|
1215
1253
|
printOut,
|
|
1216
1254
|
printErr,
|
|
1255
|
+
LEGACY_ENTRY_STEMS,
|
|
1217
1256
|
normalizeProtocolFaces,
|
|
1218
1257
|
stackFaces,
|
|
1219
1258
|
hasA2aFace,
|
|
@@ -1223,6 +1262,7 @@ export {
|
|
|
1223
1262
|
entryStemOf,
|
|
1224
1263
|
devPortOf,
|
|
1225
1264
|
recipeModeOf,
|
|
1265
|
+
dryRunBundle,
|
|
1226
1266
|
DEFAULT_B402_PRICE_USD,
|
|
1227
1267
|
DEFAULT_B402_TESTNET_BASE_URL,
|
|
1228
1268
|
B402_DEVELOPER_ACCOUNT_URL,
|
|
@@ -1234,6 +1274,7 @@ export {
|
|
|
1234
1274
|
x402SellerIsFree,
|
|
1235
1275
|
whichBin,
|
|
1236
1276
|
agentcoreFlavor,
|
|
1277
|
+
checkBunx,
|
|
1237
1278
|
checkDocker,
|
|
1238
1279
|
checkTwak,
|
|
1239
1280
|
requiredChecks,
|
|
@@ -1241,6 +1282,7 @@ export {
|
|
|
1241
1282
|
render,
|
|
1242
1283
|
readAwsTarget,
|
|
1243
1284
|
B402_RUNTIME_KEYS,
|
|
1285
|
+
X402_CAPABLE_RUNTIMES,
|
|
1244
1286
|
commerceRails,
|
|
1245
1287
|
b402Credentials,
|
|
1246
1288
|
x402DeploySummary,
|
package/dist/chunk-U7IDQ3K5.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bnbagent/studio-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11-alpha.1",
|
|
4
4
|
"description": "Skills-first toolkit and bag CLI for BNB Chain seller agents: ERC-8004 identity, ERC-8183 escrowed commerce, and x402 payments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bnb-chain",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"directory": "packages/studio-cli"
|
|
26
26
|
},
|
|
27
27
|
"type": "module",
|
|
28
|
-
"packageManager": "pnpm@10.24.0",
|
|
29
28
|
"engines": {
|
|
30
29
|
"node": ">=22"
|
|
31
30
|
},
|
|
@@ -42,16 +41,8 @@
|
|
|
42
41
|
"bin": {
|
|
43
42
|
"bag": "./dist/bag.js"
|
|
44
43
|
},
|
|
45
|
-
"scripts": {
|
|
46
|
-
"build": "tsup",
|
|
47
|
-
"test": "vitest run",
|
|
48
|
-
"lint": "biome check src tests",
|
|
49
|
-
"typecheck": "tsc --noEmit",
|
|
50
|
-
"check": "pnpm typecheck && pnpm lint && pnpm test && pnpm build"
|
|
51
|
-
},
|
|
52
44
|
"dependencies": {
|
|
53
45
|
"@bnbagent/sdk": "0.5.0",
|
|
54
|
-
"@bnbagent/studio-runtime": "0.0.10",
|
|
55
46
|
"ai": "^7.0.29",
|
|
56
47
|
"archiver": "^8.0.0",
|
|
57
48
|
"commander": "^15.0.0",
|
|
@@ -62,7 +53,8 @@
|
|
|
62
53
|
"smol-toml": "^1.3.0",
|
|
63
54
|
"tar": "^7.4.0",
|
|
64
55
|
"viem": "^2.54.0",
|
|
65
|
-
"yaml": "^2.9.0"
|
|
56
|
+
"yaml": "^2.9.0",
|
|
57
|
+
"@bnbagent/studio-runtime": "0.0.11-alpha.1"
|
|
66
58
|
},
|
|
67
59
|
"devDependencies": {
|
|
68
60
|
"@a2a-js/sdk": "^0.3.14",
|
|
@@ -78,5 +70,12 @@
|
|
|
78
70
|
"typescript": "^5.5.0",
|
|
79
71
|
"vitest": "^2.0.0",
|
|
80
72
|
"zod": "^3.25.76"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "tsup",
|
|
76
|
+
"test": "vitest run",
|
|
77
|
+
"lint": "biome check src tests",
|
|
78
|
+
"typecheck": "tsc --noEmit",
|
|
79
|
+
"check": "pnpm typecheck && pnpm lint && pnpm test && pnpm build"
|
|
81
80
|
}
|
|
82
|
-
}
|
|
81
|
+
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Agent image for wallet.kind = "twak" — SHIPPED BY `bag init`.
|
|
1
|
+
# Agent image — SHIPPED BY `bag init`, ONE Dockerfile for BOTH deploy clouds.
|
|
3
2
|
#
|
|
4
|
-
# Why a custom image: the managed
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# locally with Docker and pushes it to ECR.
|
|
3
|
+
# Why a custom image: the managed Node runtimes ship only the project's own
|
|
4
|
+
# bundle, and every signing / on-chain intent for a twak wallet shells out to
|
|
5
|
+
# the `twak` CLI (npm @trustwallet/cli), which must be installed globally in
|
|
6
|
+
# the image. `bag deploy` hands this file to the pinned bnbagent-deploy,
|
|
7
|
+
# which builds the image locally with Docker and pushes it to the target
|
|
8
|
+
# cloud's registry (ECR for AgentCore, ACR for Azure Foundry).
|
|
11
9
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
|
|
10
|
+
# Arch is NOT pinned here: each deploy provider pins it on the build command
|
|
11
|
+
# (`--platform linux/arm64` for AgentCore, `--platform linux/amd64` for
|
|
12
|
+
# Foundry), so the same Dockerfile cross-builds for either cloud. Keep this
|
|
13
|
+
# file classic-builder compatible: no `# syntax=` directive and no
|
|
14
|
+
# BuildKit-only instructions (`RUN --mount=...`), so a plain `docker build`
|
|
15
|
+
# works everywhere.
|
|
16
|
+
FROM public.ecr.aws/docker/library/node:22-slim
|
|
16
17
|
|
|
17
18
|
# The pinned twak CLI.
|
|
18
19
|
#
|
|
@@ -29,8 +30,7 @@ WORKDIR /app
|
|
|
29
30
|
# present; a project without one falls back to a plain install.
|
|
30
31
|
COPY package.json pnpm-lock.yaml* pnpm-workspace.yaml ./
|
|
31
32
|
COPY vendor ./vendor
|
|
32
|
-
RUN
|
|
33
|
-
pnpm install
|
|
33
|
+
RUN pnpm install
|
|
34
34
|
|
|
35
35
|
COPY . .
|
|
36
36
|
RUN pnpm build
|
|
@@ -38,13 +38,12 @@ RUN pnpm build
|
|
|
38
38
|
# Runtime deps only in the final tree (drops typescript etc.).
|
|
39
39
|
RUN pnpm prune --prod
|
|
40
40
|
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# MCP → 0.0.0.0:8000/mcp
|
|
44
|
-
#
|
|
41
|
+
# Hosted-runtime port contracts (the unified entrypoint binds BOTH 9000 and
|
|
42
|
+
# 8088 itself; AGENT_PORT only prepends a primary override):
|
|
43
|
+
# AgentCore A2A → 0.0.0.0:9000 at / MCP → 0.0.0.0:8000/mcp
|
|
44
|
+
# Foundry invocations/responses → 0.0.0.0:8088
|
|
45
45
|
# `bag init` renders {{CONTAINER_PORT}} / {{ENTRYPOINT}} from the selected
|
|
46
|
-
# protocol
|
|
47
|
-
# ({{ENTRYPOINT}} is the BUILT entrypoint, e.g. dist/main.js.)
|
|
46
|
+
# protocol. ({{ENTRYPOINT}} is the BUILT entrypoint, e.g. dist/unifiedMain.js.)
|
|
48
47
|
ENV AGENT_PORT={{CONTAINER_PORT}}
|
|
49
48
|
EXPOSE {{CONTAINER_PORT}}
|
|
50
49
|
CMD ["node", "{{ENTRYPOINT}}"]
|
|
@@ -64,6 +64,42 @@ const log = {
|
|
|
64
64
|
* so prose never triggers an LLM call or a paid action.
|
|
65
65
|
*/
|
|
66
66
|
export class SellerAgentExecutor extends SellerCore implements AgentExecutor {
|
|
67
|
+
/**
|
|
68
|
+
* Text-carrier entrypoint (Foundry invocations / responses SkillRouter).
|
|
69
|
+
*
|
|
70
|
+
* Same skill switch as {@link execute}, but NEVER throws: on a text
|
|
71
|
+
* carrier there is no JSON-RPC error channel, so a fault is returned as an
|
|
72
|
+
* `{"error": ...}` dict and the caller can always reply. The A2A path
|
|
73
|
+
* keeps its own switch below because its fault semantics differ (faults
|
|
74
|
+
* become JSON-RPC -32603 via A2AError).
|
|
75
|
+
*/
|
|
76
|
+
async dispatch(
|
|
77
|
+
data: Record<string, unknown>,
|
|
78
|
+
): Promise<Record<string, unknown>> {
|
|
79
|
+
const skill = data.skill;
|
|
80
|
+
try {
|
|
81
|
+
if (skill === "negotiate") {
|
|
82
|
+
return await this.negotiate(data);
|
|
83
|
+
}
|
|
84
|
+
if (skill === "notify_funded") {
|
|
85
|
+
return await this.notifyFunded(data);
|
|
86
|
+
}
|
|
87
|
+
// Includes a plain text message (no skill envelope → skill is
|
|
88
|
+
// undefined): the seller has no free-form skill, so prose is rejected
|
|
89
|
+
// here.
|
|
90
|
+
return {
|
|
91
|
+
error: `unknown skill: ${JSON.stringify(skill)}`,
|
|
92
|
+
skills: this.skills(),
|
|
93
|
+
};
|
|
94
|
+
} catch (e) {
|
|
95
|
+
// a skill failure must still ACK the buyer
|
|
96
|
+
log.error(`skill ${JSON.stringify(skill)} failed`, e);
|
|
97
|
+
const name = e instanceof Error ? e.constructor.name : "Error";
|
|
98
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
99
|
+
return { error: `${name}: ${msg}`, skill };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
67
103
|
// ── A2A entrypoints ───────────────────────────────────────────────────────
|
|
68
104
|
execute = async (
|
|
69
105
|
context: RequestContext,
|