Skip to content

Commit 83a5a45

Browse files
authored
Add white-label attribution to agent run CLI
Adds external workspace/user/project attribution flags to CLI agent-run creation and listing paths.
1 parent 36482e9 commit 83a5a45

8 files changed

Lines changed: 90 additions & 4 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@miosa/cli",
3-
"version": "1.0.78",
3+
"version": "1.0.79",
44
"description": "MIOSA platform CLI — projects, sandboxes, deploys, databases, more",
55
"type": "module",
66
"bin": {

src/commands/agent-runs.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ interface AgentRun {
1717
id: string;
1818
target_kind?: string;
1919
target_id?: string;
20+
external_workspace_id?: string;
21+
external_user_id?: string;
22+
external_project_id?: string;
2023
provider?: string;
2124
status?: string;
2225
prompt?: string;
@@ -154,6 +157,9 @@ export function register(program: Command): void {
154157
.option("--computer <id>", "Filter by computer ID")
155158
.option("--workspace <id>", "Filter by workspace ID")
156159
.option("--project <id>", "Filter by project ID")
160+
.option("--external-workspace <id>", "Filter by white-label workspace/customer ID")
161+
.option("--external-user <id>", "Filter by white-label user ID")
162+
.option("--external-project <id>", "Filter by white-label project ID")
157163
.option("--target-kind <kind>", "Filter by target kind")
158164
.option("--target-id <id>", "Filter by target ID")
159165
.option("--status <status>", "Filter by run status")
@@ -166,6 +172,9 @@ export function register(program: Command): void {
166172
computer?: string;
167173
workspace?: string;
168174
project?: string;
175+
externalWorkspace?: string;
176+
externalUser?: string;
177+
externalProject?: string;
169178
targetKind?: string;
170179
targetId?: string;
171180
status?: string;
@@ -182,6 +191,11 @@ export function register(program: Command): void {
182191
const query = new URLSearchParams();
183192
if (opts.workspace) query.set("workspace_id", opts.workspace);
184193
if (opts.project) query.set("project_id", opts.project);
194+
if (opts.externalWorkspace)
195+
query.set("external_workspace_id", opts.externalWorkspace);
196+
if (opts.externalUser) query.set("external_user_id", opts.externalUser);
197+
if (opts.externalProject)
198+
query.set("external_project_id", opts.externalProject);
185199
if (opts.sandbox) {
186200
query.set("target_kind", "sandbox");
187201
query.set("target_id", opts.sandbox);
@@ -210,6 +224,18 @@ export function register(program: Command): void {
210224
renderTable(data, [
211225
{ header: "ID", key: "id", width: 18 },
212226
{ header: "TARGET", key: (row) => `${str(row.target_kind)} ${str(row.target_id)}`, width: 28 },
227+
{
228+
header: "EXTERNAL",
229+
key: (row) =>
230+
[
231+
str(row.external_workspace_id),
232+
str(row.external_user_id),
233+
str(row.external_project_id),
234+
]
235+
.filter(Boolean)
236+
.join(" / "),
237+
width: 30,
238+
},
213239
{ header: "PROVIDER", key: "provider", width: 12 },
214240
{ header: "STATUS", key: (row) => colorStatus(row.status), width: 12 },
215241
{ header: "PROMPT", key: (row) => str(row.prompt), width: 44 },

src/commands/agent.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ type AgentRunOptions = JsonOptions & {
8484
timeout?: string;
8585
agentProfile?: string;
8686
skipAgentProfile?: boolean;
87+
externalWorkspace?: string;
88+
externalUser?: string;
89+
externalProject?: string;
8790
executionPacket?: string;
8891
executionPacketFile?: string;
8992
outputContract?: string;
@@ -412,6 +415,9 @@ async function runPromptTarget(instruction: string, opts: AgentRunOptions): Prom
412415
if (opts.timeout) body["timeout"] = Number.parseInt(opts.timeout, 10);
413416
if (opts.agentProfile) body["agent_runtime_profile_id"] = opts.agentProfile;
414417
if (opts.skipAgentProfile) body["skip_agent_runtime_profile"] = true;
418+
if (opts.externalWorkspace) body["external_workspace_id"] = opts.externalWorkspace;
419+
if (opts.externalUser) body["external_user_id"] = opts.externalUser;
420+
if (opts.externalProject) body["external_project_id"] = opts.externalProject;
415421
const executionPacket = readJsonValue(
416422
opts.executionPacket,
417423
opts.executionPacketFile,
@@ -472,6 +478,9 @@ async function runOpenComputerHostPrompt(
472478
if (opts.model) body["model"] = opts.model;
473479
if (opts.agentProfile) body["agent_runtime_profile_id"] = opts.agentProfile;
474480
if (opts.skipAgentProfile) body["skip_agent_runtime_profile"] = true;
481+
if (opts.externalWorkspace) body["external_workspace_id"] = opts.externalWorkspace;
482+
if (opts.externalUser) body["external_user_id"] = opts.externalUser;
483+
if (opts.externalProject) body["external_project_id"] = opts.externalProject;
475484
const executionPacket = readJsonValue(
476485
opts.executionPacket,
477486
opts.executionPacketFile,
@@ -563,6 +572,9 @@ function buildRun(agent: Command): void {
563572
.option("--timeout <sec>", "Timeout in seconds")
564573
.option("--agent-profile <id>", "Agent runtime profile ID")
565574
.option("--skip-agent-profile", "Do not apply default agent runtime profile")
575+
.option("--external-workspace <id>", "White-label workspace/customer ID for billing attribution")
576+
.option("--external-user <id>", "White-label user ID for billing attribution")
577+
.option("--external-project <id>", "White-label project ID for billing attribution")
566578
.option("--execution-packet <json>", "Execution packet JSON for product context, plan, and acceptance criteria")
567579
.option("--execution-packet-file <file>", "Read execution packet JSON from a file")
568580
.option("--output-contract <json>", "Output contract JSON declaring expected artifacts/previews")

src/commands/sandbox.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,18 @@ export function register(program: Command): void {
648648
"--skip-agent-profile",
649649
"Do not apply the default agent runtime profile",
650650
)
651+
.option(
652+
"--external-workspace <id>",
653+
"White-label workspace/customer ID for billing attribution",
654+
)
655+
.option(
656+
"--external-user <id>",
657+
"White-label user ID for billing attribution",
658+
)
659+
.option(
660+
"--external-project <id>",
661+
"White-label project ID for billing attribution",
662+
)
651663
.option("--timeout <sec>", "Exec timeout in seconds", parseIntegerOption)
652664
.option("--json", "Output as JSON")
653665
.action(
@@ -664,6 +676,9 @@ export function register(program: Command): void {
664676
env?: string[];
665677
agentProfile?: string;
666678
skipAgentProfile?: boolean;
679+
externalWorkspace?: string;
680+
externalUser?: string;
681+
externalProject?: string;
667682
timeout?: number;
668683
} & JsonOptions,
669684
) =>
@@ -707,6 +722,15 @@ export function register(program: Command): void {
707722
if (opts.skipAgentProfile) {
708723
body["skip_agent_runtime_profile"] = true;
709724
}
725+
if (opts.externalWorkspace) {
726+
body["external_workspace_id"] = opts.externalWorkspace;
727+
}
728+
if (opts.externalUser) {
729+
body["external_user_id"] = opts.externalUser;
730+
}
731+
if (opts.externalProject) {
732+
body["external_project_id"] = opts.externalProject;
733+
}
710734
if (opts.timeout != null) body["timeout"] = opts.timeout;
711735

712736
const run = unwrap(

test/commands/agent-runs.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ describe("miosa agent-runs", () => {
4848
const pool = mock.get("https://api.miosa.ai");
4949
pool
5050
.intercept({
51-
path: "/api/v1/agent-runs?target_kind=sandbox&target_id=sbx_123&status=running",
51+
path: "/api/v1/agent-runs?external_workspace_id=clinic-iq&external_user_id=founder-1&external_project_id=landing-page&target_kind=sandbox&target_id=sbx_123&status=running",
5252
method: "GET",
5353
})
5454
.reply(
@@ -113,6 +113,12 @@ describe("miosa agent-runs", () => {
113113
"sbx_123",
114114
"--status",
115115
"running",
116+
"--external-workspace",
117+
"clinic-iq",
118+
"--external-user",
119+
"founder-1",
120+
"--external-project",
121+
"landing-page",
116122
]);
117123
await program.parseAsync([
118124
"node",

test/commands/agent.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ describe("miosa agent", () => {
200200
provider: "codex",
201201
env: { FEATURE_FLAG: "on" },
202202
agent_runtime_profile_id: "prof_123",
203+
external_workspace_id: "clinic-iq",
204+
external_user_id: "founder-1",
205+
external_project_id: "landing-page",
203206
}),
204207
})
205208
.reply(
@@ -237,6 +240,12 @@ describe("miosa agent", () => {
237240
"FEATURE_FLAG=on",
238241
"--agent-profile",
239242
"prof_123",
243+
"--external-workspace",
244+
"clinic-iq",
245+
"--external-user",
246+
"founder-1",
247+
"--external-project",
248+
"landing-page",
240249
]);
241250

242251
expect(JSON.parse(logged.join("\n"))).toMatchObject({

test/commands/sandbox.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,9 @@ describe("miosa sandbox connectors", () => {
14771477
prompt: "hello",
14781478
env: { FEATURE_FLAG: "on" },
14791479
agent_runtime_profile_id: "prof_123",
1480+
external_workspace_id: "clinic-iq",
1481+
external_user_id: "founder-1",
1482+
external_project_id: "landing-page",
14801483
}),
14811484
})
14821485
.reply(
@@ -1506,6 +1509,12 @@ describe("miosa sandbox connectors", () => {
15061509
"FEATURE_FLAG=on",
15071510
"--agent-profile",
15081511
"prof_123",
1512+
"--external-workspace",
1513+
"clinic-iq",
1514+
"--external-user",
1515+
"founder-1",
1516+
"--external-project",
1517+
"landing-page",
15091518
"hello",
15101519
]);
15111520

0 commit comments

Comments
 (0)