@workser/cli 0.6.14 → 0.6.15

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/index.js CHANGED
@@ -3663,6 +3663,137 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
3663
3663
 
3664
3664
  // src/help-content.ts
3665
3665
  var HELP_TOPICS = [
3666
+ {
3667
+ topic: "agent-cloud",
3668
+ title: "Ship an agent inside the app",
3669
+ summary: "Create an AI agent that runs on Workser and can be called from this project's apps.",
3670
+ commands: ["agent-cloud"],
3671
+ source: "skills/workser/reference/agent-cloud.md",
3672
+ body: `# Ship an agent inside the app
3673
+
3674
+ \`workser agent-cloud\` creates an AI agent that runs on **Workser's**
3675
+ infrastructure, keeps its own memory and tools, and can be called from the web,
3676
+ mobile, API or Python apps in this project.
3677
+
3678
+ **This is not \`workser agent\`.** That one hands a subtask to a coding agent on
3679
+ this machine \u2014 a teammate helping you build. This one is a thing the project
3680
+ *ships*: it works for the user after you are gone.
3681
+
3682
+ \`\`\`
3683
+ workser agent-cloud list
3684
+ workser agent-cloud create "Order desk" --instructions "..."
3685
+ workser agent-cloud show <agentId>
3686
+ workser agent-cloud run <agentId> "<what to do>"
3687
+ workser agent-cloud runs <agentId> # recent runs
3688
+ workser agent-cloud runs <runId> # one run, with what it cost
3689
+ \`\`\`
3690
+
3691
+ Every call is scoped to the project this folder belongs to.
3692
+
3693
+ ## Creating one is not finishing one
3694
+
3695
+ An agent created with a name and a sentence knows nothing about the business.
3696
+ Teaching it is the actual work, and it is all here:
3697
+
3698
+ \`\`\`
3699
+ workser agent-cloud set <id> system_prompt="..." handle="orderdesk"
3700
+ workser agent-cloud add <id> skill name="Refunds" instructions_md="..."
3701
+ workser agent-cloud add <id> knowledge name="Price list" content_text="..."
3702
+ workser agent-cloud add <id> tool display_name="Send email" provider="gmail" \\
3703
+ provider_tool_id="GMAIL_SEND_EMAIL"
3704
+ workser agent-cloud add <id> secret key="STRIPE_KEY" value="..."
3705
+ workser agent-cloud add <id> subagent subagent_id=<otherId> name="researcher"
3706
+ workser agent-cloud get <id> skill # what it has
3707
+ workser agent-cloud remove <id> skill <itemId>
3708
+ \`\`\`
3709
+
3710
+ \`add\` takes \`key=value\` pairs and REFUSES a field it does not know, rather than
3711
+ sending it. That matters: the API silently drops unknown fields, so a typo
3712
+ would otherwise be accepted, dropped, and reported as success \u2014 leaving an
3713
+ agent that had been told nothing.
3714
+
3715
+ ## Nothing takes effect until you publish
3716
+
3717
+ **This is the step to not forget.** The runtime resolves the PUBLISHED version
3718
+ of an agent and never the draft, so every \`set\` and \`add\` above is inert until:
3719
+
3720
+ \`\`\`
3721
+ workser agent-cloud publish <id> --note "taught it refunds"
3722
+ \`\`\`
3723
+
3724
+ Before publishing, try the setup without putting it live:
3725
+
3726
+ \`\`\`
3727
+ workser agent-cloud try <id> "a customer wants a refund on order 1042"
3728
+ \`\`\`
3729
+
3730
+ A \`try\` runs the draft, costs the same as a real run, and changes nothing that
3731
+ customers can reach.
3732
+
3733
+ ## Choosing how it thinks and what it runs on
3734
+
3735
+ \`\`\`
3736
+ workser agent-cloud models # cheapest first, on Workser credit
3737
+ workser agent-cloud models --all # includes ones needing your own key
3738
+ workser agent-cloud set <id> default_provider=openrouter default_model=...
3739
+
3740
+ workser agent-cloud machines # video, data analysis, design, ...
3741
+ \`\`\`
3742
+
3743
+ A model marked "needs your own key" will make \`publish\` FAIL unless a matching
3744
+ secret is stored first. Add the key with \`add <id> secret\` before setting it.
3745
+
3746
+ ## When to reach for this
3747
+
3748
+ When the user describes a job that **keeps happening** and needs judgement:
3749
+ "check every order for stock and email me the problems", "read the LINE
3750
+ messages and file them", "reconcile these invoices". That is an agent.
3751
+
3752
+ A one-off transformation is not an agent \u2014 write the code. A fixed sequence of
3753
+ steps with no judgement in it is not an agent either \u2014 that is \`workser
3754
+ workflow\`.
3755
+
3756
+ ## Calling it from the app you are building
3757
+
3758
+ Do NOT shell out to the CLI from app code. Use the SDK, which streams:
3759
+
3760
+ \`\`\`ts
3761
+ import { workser } from '@workser/app';
3762
+
3763
+ const run = await workser.agents.run(agentId, { message }, {
3764
+ referenceUserId: user.id, // who it is acting for
3765
+ });
3766
+
3767
+ for await (const event of workser.agents.stream(run.id)) {
3768
+ // event.type, event.data \u2014 forward these to the browser
3769
+ }
3770
+ \`\`\`
3771
+
3772
+ \`stream()\` reconnects itself through dropped connections, so the person
3773
+ watching sees the agent think. See the \`workser-sdk\` skill, \`reference/agents.md\`.
3774
+
3775
+ ## Things that will bite you
3776
+
3777
+ 1. **A run costs money by the minute.** It is metered \u2014 runtime, workspace, and
3778
+ a per-run fee \u2014 so a loop that starts agents is a loop that spends. Cancel
3779
+ what you abandon: \`workser agent-cloud runs <runId>\` shows the cost.
3780
+
3781
+ 2. **Instructions are the product.** The agent does what its instructions say,
3782
+ in the user's own words. Write them the way you would brief a new colleague:
3783
+ what to do, what to leave alone, when to ask. Vague instructions are the
3784
+ single biggest cause of an agent that "doesn't work".
3785
+
3786
+ 3. **Free plans cannot run agents at all**, and a trial has a small allowance.
3787
+ A \`402\` with \`spend_limit_reached\` is not a bug \u2014 tell the user what it says
3788
+ and point them at their plan.
3789
+
3790
+ 4. **Say who it is for.** An agent acting for one of the app's customers needs
3791
+ \`referenceUserId\`, or its memory and audit trail belong to nobody.
3792
+
3793
+ 5. **Do not invent an agent the user did not ask for.** Creating one is cheap;
3794
+ an agent nobody wanted, quietly costing money per run, is not.
3795
+ `
3796
+ },
3666
3797
  {
3667
3798
  topic: "analysis",
3668
3799
  title: "Analysis \u2014 running Python on this project's data",
@@ -4071,84 +4202,6 @@ Two things worth knowing:
4071
4202
 
4072
4203
  An app that has never been published has no address, so there is nothing to
4073
4204
  check. That is reported as a note, not as a pass.
4074
- `
4075
- },
4076
- {
4077
- topic: "cloud-agents",
4078
- title: "Ship an agent inside the app",
4079
- summary: "Create an AI agent that runs on Workser and can be called from this project's apps.",
4080
- commands: ["cloud-agent"],
4081
- source: "skills/workser/reference/cloud-agents.md",
4082
- body: `# Ship an agent inside the app
4083
-
4084
- \`workser cloud-agent\` creates an AI agent that runs on **Workser's**
4085
- infrastructure, keeps its own memory and tools, and can be called from the web,
4086
- mobile, API or Python apps in this project.
4087
-
4088
- **This is not \`workser agent\`.** That one hands a subtask to a coding agent on
4089
- this machine \u2014 a teammate helping you build. This one is a thing the project
4090
- *ships*: it works for the user after you are gone.
4091
-
4092
- \`\`\`
4093
- workser cloud-agent list
4094
- workser cloud-agent create "Order desk" --instructions "..."
4095
- workser cloud-agent show <agentId>
4096
- workser cloud-agent run <agentId> "<what to do>"
4097
- workser cloud-agent runs <agentId> # recent runs
4098
- workser cloud-agent runs <runId> # one run, with what it cost
4099
- \`\`\`
4100
-
4101
- Every call is scoped to the project this folder belongs to.
4102
-
4103
- ## When to reach for this
4104
-
4105
- When the user describes a job that **keeps happening** and needs judgement:
4106
- "check every order for stock and email me the problems", "read the LINE
4107
- messages and file them", "reconcile these invoices". That is an agent.
4108
-
4109
- A one-off transformation is not an agent \u2014 write the code. A fixed sequence of
4110
- steps with no judgement in it is not an agent either \u2014 that is \`workser
4111
- workflow\`.
4112
-
4113
- ## Calling it from the app you are building
4114
-
4115
- Do NOT shell out to the CLI from app code. Use the SDK, which streams:
4116
-
4117
- \`\`\`ts
4118
- import { workser } from '@workser/app';
4119
-
4120
- const run = await workser.agents.run(agentId, { message }, {
4121
- referenceUserId: user.id, // who it is acting for
4122
- });
4123
-
4124
- for await (const event of workser.agents.stream(run.id)) {
4125
- // event.type, event.data \u2014 forward these to the browser
4126
- }
4127
- \`\`\`
4128
-
4129
- \`stream()\` reconnects itself through dropped connections, so the person
4130
- watching sees the agent think. See the \`workser-sdk\` skill, \`reference/agents.md\`.
4131
-
4132
- ## Things that will bite you
4133
-
4134
- 1. **A run costs money by the minute.** It is metered \u2014 runtime, workspace, and
4135
- a per-run fee \u2014 so a loop that starts agents is a loop that spends. Cancel
4136
- what you abandon: \`workser cloud-agent runs <runId>\` shows the cost.
4137
-
4138
- 2. **Instructions are the product.** The agent does what its instructions say,
4139
- in the user's own words. Write them the way you would brief a new colleague:
4140
- what to do, what to leave alone, when to ask. Vague instructions are the
4141
- single biggest cause of an agent that "doesn't work".
4142
-
4143
- 3. **Free plans cannot run agents at all**, and a trial has a small allowance.
4144
- A \`402\` with \`spend_limit_reached\` is not a bug \u2014 tell the user what it says
4145
- and point them at their plan.
4146
-
4147
- 4. **Say who it is for.** An agent acting for one of the app's customers needs
4148
- \`referenceUserId\`, or its memory and audit trail belong to nobody.
4149
-
4150
- 5. **Do not invent an agent the user did not ask for.** Creating one is cheap;
4151
- an agent nobody wanted, quietly costing money per run, is not.
4152
4205
  `
4153
4206
  },
4154
4207
  {
@@ -7537,21 +7590,21 @@ function formatRole(r) {
7537
7590
  return `${label} ${agent} ${enabled} ${ready}${tail}`;
7538
7591
  }
7539
7592
 
7540
- // src/commands/cloud-agent.ts
7593
+ // src/commands/agent-cloud.ts
7541
7594
  var import_picocolors17 = __toESM(require_picocolors(), 1);
7542
- function registerCloudAgent(program3) {
7543
- const cloud = program3.command("cloud-agent").description(
7595
+ function registerAgentCloud(program3) {
7596
+ const cloud = program3.command("agent-cloud").description(
7544
7597
  "Agents that run in the cloud and can be called from this project's apps (not the local coding agents \u2014 that's `workser agent`)"
7545
7598
  );
7546
7599
  cloud.command("list").description("List this project's cloud agents").action(
7547
7600
  action(async ({ ctx }) => {
7548
- const res = await api(ctx, "/v1/cloud-agents");
7601
+ const res = await api(ctx, "/v1/agent-cloud");
7549
7602
  const agents = res?.agents ?? res ?? [];
7550
7603
  ok(res, () => {
7551
7604
  if (!agents.length) {
7552
7605
  line(import_picocolors17.default.dim("No cloud agents yet."));
7553
7606
  line(
7554
- import_picocolors17.default.dim("Create one: ") + import_picocolors17.default.bold('workser cloud-agent create "Order desk" --instructions "..."')
7607
+ import_picocolors17.default.dim("Create one: ") + import_picocolors17.default.bold('workser agent-cloud create "Order desk" --instructions "..."')
7555
7608
  );
7556
7609
  return;
7557
7610
  }
@@ -7569,7 +7622,7 @@ function registerCloudAgent(program3) {
7569
7622
  "The agent's standing instructions \u2014 what it should always do"
7570
7623
  ).action(
7571
7624
  action(async ({ ctx, args, opts }) => {
7572
- const res = await api(ctx, "/v1/cloud-agents", {
7625
+ const res = await api(ctx, "/v1/agent-cloud", {
7573
7626
  method: "POST",
7574
7627
  body: {
7575
7628
  name: args[0],
@@ -7582,14 +7635,14 @@ function registerCloudAgent(program3) {
7582
7635
  if (res?.id) line(import_picocolors17.default.dim(res.id));
7583
7636
  line("");
7584
7637
  line(
7585
- import_picocolors17.default.dim("Give it work: ") + import_picocolors17.default.bold(`workser cloud-agent run ${res?.id ?? "<id>"} "..."`)
7638
+ import_picocolors17.default.dim("Give it work: ") + import_picocolors17.default.bold(`workser agent-cloud run ${res?.id ?? "<id>"} "..."`)
7586
7639
  );
7587
7640
  });
7588
7641
  })
7589
7642
  );
7590
7643
  cloud.command("show <agentId>").description("One cloud agent, with its configuration").action(
7591
7644
  action(async ({ ctx, args }) => {
7592
- const res = await api(ctx, `/v1/cloud-agents/${encodeURIComponent(args[0])}`);
7645
+ const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}`);
7593
7646
  ok(res, () => {
7594
7647
  line(import_picocolors17.default.bold(res?.name ?? args[0]));
7595
7648
  if (res?.description) line(import_picocolors17.default.dim(res.description));
@@ -7605,13 +7658,13 @@ function registerCloudAgent(program3) {
7605
7658
  action(async ({ ctx, args }) => {
7606
7659
  const res = await api(
7607
7660
  ctx,
7608
- `/v1/cloud-agents/${encodeURIComponent(args[0])}/runs`,
7661
+ `/v1/agent-cloud/${encodeURIComponent(args[0])}/runs`,
7609
7662
  { method: "POST", body: { input: { message: args[1] } } }
7610
7663
  );
7611
7664
  ok(res, () => {
7612
7665
  line(import_picocolors17.default.green("Started run ") + import_picocolors17.default.bold(res?.id ?? ""));
7613
7666
  line(
7614
- import_picocolors17.default.dim("Follow it: ") + import_picocolors17.default.bold(`workser cloud-agent runs ${res?.id ?? "<runId>"}`)
7667
+ import_picocolors17.default.dim("Follow it: ") + import_picocolors17.default.bold(`workser agent-cloud runs ${res?.id ?? "<runId>"}`)
7615
7668
  );
7616
7669
  });
7617
7670
  })
@@ -7626,7 +7679,7 @@ function registerCloudAgent(program3) {
7626
7679
  try {
7627
7680
  const run = await api(
7628
7681
  ctx,
7629
- `/v1/cloud-agents/runs/${encodeURIComponent(id)}`
7682
+ `/v1/agent-cloud/runs/${encodeURIComponent(id)}`
7630
7683
  );
7631
7684
  ok(run, () => printRun(run));
7632
7685
  return;
@@ -7634,7 +7687,7 @@ function registerCloudAgent(program3) {
7634
7687
  }
7635
7688
  const res = await api(
7636
7689
  ctx,
7637
- `/v1/cloud-agents/${encodeURIComponent(id)}/runs`,
7690
+ `/v1/agent-cloud/${encodeURIComponent(id)}/runs`,
7638
7691
  { query: { limit: opts.limit } }
7639
7692
  );
7640
7693
  const runs = res?.runs ?? res ?? [];
@@ -7647,6 +7700,202 @@ function registerCloudAgent(program3) {
7647
7700
  });
7648
7701
  })
7649
7702
  );
7703
+ const COLLECTIONS = {
7704
+ skill: {
7705
+ path: "skills",
7706
+ key: "skills",
7707
+ label: "skill",
7708
+ fields: ["name", "description", "instructions_md"],
7709
+ required: ["name"]
7710
+ },
7711
+ tool: {
7712
+ path: "tools",
7713
+ key: "tools",
7714
+ label: "action",
7715
+ fields: ["display_name", "provider", "provider_tool_id", "description"],
7716
+ required: ["display_name"]
7717
+ },
7718
+ mcp: {
7719
+ path: "mcp-servers",
7720
+ key: "servers",
7721
+ label: "MCP server",
7722
+ fields: ["name", "url"],
7723
+ required: ["name", "url"]
7724
+ },
7725
+ knowledge: {
7726
+ path: "resources",
7727
+ key: "resources",
7728
+ label: "reference material",
7729
+ fields: ["name", "content_text"],
7730
+ required: ["name"]
7731
+ },
7732
+ secret: {
7733
+ path: "secrets",
7734
+ key: "secrets",
7735
+ label: "stored key",
7736
+ fields: ["key", "value", "description"],
7737
+ required: ["key", "value"]
7738
+ },
7739
+ subagent: {
7740
+ path: "subagents",
7741
+ key: "subagents",
7742
+ label: "team member",
7743
+ fields: ["subagent_id", "name", "description"],
7744
+ required: ["subagent_id", "name"]
7745
+ },
7746
+ workflow: {
7747
+ path: "workflows",
7748
+ key: "workflows",
7749
+ label: "workflow",
7750
+ fields: ["workflow_id", "description"],
7751
+ required: ["workflow_id"]
7752
+ }
7753
+ };
7754
+ const kinds = Object.keys(COLLECTIONS).join(" | ");
7755
+ cloud.command("get <agentId> <kind>").description(`What an agent has been given (${kinds})`).action(
7756
+ action(async ({ ctx, args }) => {
7757
+ const spec = COLLECTIONS[args[1]];
7758
+ if (!spec) throw new Error(`Unknown kind "${args[1]}". One of: ${kinds}`);
7759
+ const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/${spec.path}`);
7760
+ const items = res?.[spec.key] ?? [];
7761
+ ok(res, () => {
7762
+ if (!items.length) {
7763
+ line(import_picocolors17.default.dim(`No ${spec.label} yet.`));
7764
+ return;
7765
+ }
7766
+ for (const i of items) {
7767
+ const title = i.name ?? i.display_name ?? i.key ?? i.workflow_id ?? i.id;
7768
+ line(`${import_picocolors17.default.bold(title)} ${import_picocolors17.default.dim(i.id)}`);
7769
+ if (i.description) line(" " + import_picocolors17.default.dim(i.description));
7770
+ if (i.is_enabled === false) line(" " + import_picocolors17.default.yellow("turned off"));
7771
+ }
7772
+ });
7773
+ })
7774
+ );
7775
+ cloud.command("add <agentId> <kind> [pairs...]").description(
7776
+ `Give an agent something (${kinds}). Pairs are key=value, e.g. name="Refunds"`
7777
+ ).action(
7778
+ action(async ({ ctx, args }) => {
7779
+ const spec = COLLECTIONS[args[1]];
7780
+ if (!spec) throw new Error(`Unknown kind "${args[1]}". One of: ${kinds}`);
7781
+ const body = parsePairs(args[2] ?? [], spec.fields);
7782
+ const missing = spec.required.filter((f) => !body[f]);
7783
+ if (missing.length) {
7784
+ throw new Error(
7785
+ `A ${spec.label} needs ${missing.join(" and ")}. Accepted: ${spec.fields.join(", ")}`
7786
+ );
7787
+ }
7788
+ const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/${spec.path}`, {
7789
+ method: "POST",
7790
+ body
7791
+ });
7792
+ ok(res, () => {
7793
+ line(import_picocolors17.default.green(`Added the ${spec.label}.`) + " " + import_picocolors17.default.dim(res?.id ?? ""));
7794
+ line(
7795
+ import_picocolors17.default.dim("Not live yet \u2014 run ") + import_picocolors17.default.bold(`workser agent-cloud publish ${args[0]}`) + import_picocolors17.default.dim(" when the setup is ready.")
7796
+ );
7797
+ });
7798
+ })
7799
+ );
7800
+ cloud.command("remove <agentId> <kind> <itemId>").description(`Take something away from an agent (${kinds})`).action(
7801
+ action(async ({ ctx, args }) => {
7802
+ const spec = COLLECTIONS[args[1]];
7803
+ if (!spec) throw new Error(`Unknown kind "${args[1]}". One of: ${kinds}`);
7804
+ const res = await api(
7805
+ ctx,
7806
+ `/v1/agent-cloud/${encodeURIComponent(args[0])}/${spec.path}/${encodeURIComponent(args[2])}`,
7807
+ { method: "DELETE" }
7808
+ );
7809
+ ok(res, () => line(import_picocolors17.default.green(`Removed the ${spec.label}.`)));
7810
+ })
7811
+ );
7812
+ cloud.command("set <agentId> [pairs...]").description(
7813
+ "Change the brief or the model. Pairs: name, description, system_prompt, handle, default_provider, default_model"
7814
+ ).action(
7815
+ action(async ({ ctx, args }) => {
7816
+ const body = parsePairs(args[1] ?? [], [
7817
+ "name",
7818
+ "description",
7819
+ "system_prompt",
7820
+ "handle",
7821
+ "default_provider",
7822
+ "default_model"
7823
+ ]);
7824
+ if (!Object.keys(body).length) {
7825
+ throw new Error(
7826
+ 'Nothing to change. Example: workser agent-cloud set <id> system_prompt="Always check stock first"'
7827
+ );
7828
+ }
7829
+ const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}`, {
7830
+ method: "PATCH",
7831
+ body
7832
+ });
7833
+ ok(res, () => {
7834
+ line(import_picocolors17.default.green("Saved."));
7835
+ line(
7836
+ import_picocolors17.default.dim("Not live yet \u2014 run ") + import_picocolors17.default.bold(`workser agent-cloud publish ${args[0]}`) + import_picocolors17.default.dim(".")
7837
+ );
7838
+ });
7839
+ })
7840
+ );
7841
+ cloud.command("publish <agentId>").description("Put the current setup live \u2014 nothing takes effect until this runs").option("--note <text>", "What changed, for the version history").action(
7842
+ action(async ({ ctx, args, opts }) => {
7843
+ const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/publish`, {
7844
+ method: "POST",
7845
+ body: { changelog: opts.note }
7846
+ });
7847
+ ok(
7848
+ res,
7849
+ () => line(import_picocolors17.default.green(`Live${res?.version ? ` \u2014 version ${res.version}` : ""}.`))
7850
+ );
7851
+ })
7852
+ );
7853
+ cloud.command("try <agentId> <message>").description("Run the current setup WITHOUT publishing it").action(
7854
+ action(async ({ ctx, args }) => {
7855
+ const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/test-runs`, {
7856
+ method: "POST",
7857
+ body: { input: { message: args[1] } }
7858
+ });
7859
+ ok(res, () => {
7860
+ line(import_picocolors17.default.green("Trying it \u2014 nothing has gone live."));
7861
+ if (res?.run_id) {
7862
+ line(
7863
+ import_picocolors17.default.dim("Watch it: ") + import_picocolors17.default.bold(`workser agent-cloud runs ${res.run_id}`)
7864
+ );
7865
+ }
7866
+ });
7867
+ })
7868
+ );
7869
+ cloud.command("machines").description("The pre-built machines an agent can run on").action(
7870
+ action(async ({ ctx }) => {
7871
+ const res = await api(ctx, "/v1/agent-cloud/catalog/machines");
7872
+ ok(res, () => {
7873
+ for (const m of res?.machines ?? []) {
7874
+ line(`${import_picocolors17.default.bold(m.label)} ${import_picocolors17.default.dim(m.alias)}`);
7875
+ line(" " + import_picocolors17.default.dim(m.description));
7876
+ }
7877
+ });
7878
+ })
7879
+ );
7880
+ cloud.command("models").description("Models this organisation can run an agent on, cheapest first").option("--all", "Include models that need your own provider key").action(
7881
+ action(async ({ ctx, opts }) => {
7882
+ const res = await api(ctx, "/v1/agent-cloud/catalog/models/live");
7883
+ const models = (res?.models ?? []).filter(
7884
+ (m) => opts.all || m.credit_tier === "PLATFORM_CREDITS"
7885
+ );
7886
+ ok(res, () => {
7887
+ if (!models.length) {
7888
+ warn("The live model list could not be read.");
7889
+ return;
7890
+ }
7891
+ for (const m of models.slice(0, 40)) {
7892
+ const price = typeof m.input_price_per_million_usd === "number" ? `$${m.input_price_per_million_usd.toFixed(2)}/M in` : "price unknown";
7893
+ const byok = m.credit_tier === "PLATFORM_CREDITS" ? "" : import_picocolors17.default.yellow(" needs your own key");
7894
+ line(`${import_picocolors17.default.bold(m.id)} ${import_picocolors17.default.dim(price)}${byok}`);
7895
+ }
7896
+ });
7897
+ })
7898
+ );
7650
7899
  }
7651
7900
  function printRun(run, compact = false) {
7652
7901
  const status = String(run?.status ?? "").toLowerCase();
@@ -7682,6 +7931,22 @@ function formatDuration(ms) {
7682
7931
  const minutes = Math.floor(seconds / 60);
7683
7932
  return `${minutes}m ${seconds % 60}s`;
7684
7933
  }
7934
+ function parsePairs(pairs, allowed) {
7935
+ const out = {};
7936
+ for (const raw of pairs) {
7937
+ const at = raw.indexOf("=");
7938
+ if (at < 1) {
7939
+ throw new Error(`"${raw}" is not a key=value pair.`);
7940
+ }
7941
+ const key = raw.slice(0, at).trim();
7942
+ const value = raw.slice(at + 1);
7943
+ if (!allowed.includes(key)) {
7944
+ throw new Error(`"${key}" is not a field here. Accepted: ${allowed.join(", ")}`);
7945
+ }
7946
+ if (value) out[key] = value;
7947
+ }
7948
+ return out;
7949
+ }
7685
7950
 
7686
7951
  // src/commands/verify.ts
7687
7952
  var import_picocolors18 = __toESM(require_picocolors(), 1);
@@ -11489,7 +11754,7 @@ function colour(d) {
11489
11754
 
11490
11755
  // src/index.ts
11491
11756
  var pkg = {
11492
- version: true ? "0.6.14" : "0.0.0-dev"
11757
+ version: true ? "0.6.15" : "0.0.0-dev"
11493
11758
  };
11494
11759
  var program2 = new Command();
11495
11760
  program2.name("workser").description(
@@ -11522,7 +11787,7 @@ registerDomain(program2);
11522
11787
  registerOpen(program2);
11523
11788
  registerDoctor(program2);
11524
11789
  registerAgent(program2);
11525
- registerCloudAgent(program2);
11790
+ registerAgentCloud(program2);
11526
11791
  registerVerify(program2);
11527
11792
  registerApi(program2);
11528
11793
  registerAnalysis(program2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workser/cli",
3
- "version": "0.6.14",
3
+ "version": "0.6.15",
4
4
  "description": "Workser CLI — give your local AI agent native DevOps & infrastructure on Workser. The agent runs `workser …` to provision, deploy, and manage real apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,7 +30,7 @@ load.
30
30
  | Build an automation, or use Gmail/Slack/Stripe/Sheets | `workflow …`, `app …` | `workser help automation` |
31
31
  | Generate an image | `image …` | `workser help images` |
32
32
  | Hand a subtask to another agent | `agent …` | `workser help roles` |
33
- | Ship an AI agent inside the user's app | `cloud-agent …` | `workser help cloud-agents` |
33
+ | Ship an AI agent inside the user's app | `agent-cloud …` | `workser help agent-cloud` |
34
34
  | Recall across conversations; leave this task's team a fact | `memory …`, `workser note` | `workser help memory` |
35
35
  | Record finished output, or ask the user a question | `artifact …`, `ask` | `workser help deliverables` |
36
36
  | Control this machine — files, shell, screen, browser | `tool …` | `workser help computer-use` |
@@ -1,13 +1,13 @@
1
1
  ---
2
- topic: cloud-agents
2
+ topic: agent-cloud
3
3
  title: Ship an agent inside the app
4
4
  summary: Create an AI agent that runs on Workser and can be called from this project's apps.
5
- commands: [cloud-agent]
5
+ commands: [agent-cloud]
6
6
  ---
7
7
 
8
8
  # Ship an agent inside the app
9
9
 
10
- `workser cloud-agent` creates an AI agent that runs on **Workser's**
10
+ `workser agent-cloud` creates an AI agent that runs on **Workser's**
11
11
  infrastructure, keeps its own memory and tools, and can be called from the web,
12
12
  mobile, API or Python apps in this project.
13
13
 
@@ -16,16 +16,69 @@ this machine — a teammate helping you build. This one is a thing the project
16
16
  *ships*: it works for the user after you are gone.
17
17
 
18
18
  ```
19
- workser cloud-agent list
20
- workser cloud-agent create "Order desk" --instructions "..."
21
- workser cloud-agent show <agentId>
22
- workser cloud-agent run <agentId> "<what to do>"
23
- workser cloud-agent runs <agentId> # recent runs
24
- workser cloud-agent runs <runId> # one run, with what it cost
19
+ workser agent-cloud list
20
+ workser agent-cloud create "Order desk" --instructions "..."
21
+ workser agent-cloud show <agentId>
22
+ workser agent-cloud run <agentId> "<what to do>"
23
+ workser agent-cloud runs <agentId> # recent runs
24
+ workser agent-cloud runs <runId> # one run, with what it cost
25
25
  ```
26
26
 
27
27
  Every call is scoped to the project this folder belongs to.
28
28
 
29
+ ## Creating one is not finishing one
30
+
31
+ An agent created with a name and a sentence knows nothing about the business.
32
+ Teaching it is the actual work, and it is all here:
33
+
34
+ ```
35
+ workser agent-cloud set <id> system_prompt="..." handle="orderdesk"
36
+ workser agent-cloud add <id> skill name="Refunds" instructions_md="..."
37
+ workser agent-cloud add <id> knowledge name="Price list" content_text="..."
38
+ workser agent-cloud add <id> tool display_name="Send email" provider="gmail" \
39
+ provider_tool_id="GMAIL_SEND_EMAIL"
40
+ workser agent-cloud add <id> secret key="STRIPE_KEY" value="..."
41
+ workser agent-cloud add <id> subagent subagent_id=<otherId> name="researcher"
42
+ workser agent-cloud get <id> skill # what it has
43
+ workser agent-cloud remove <id> skill <itemId>
44
+ ```
45
+
46
+ `add` takes `key=value` pairs and REFUSES a field it does not know, rather than
47
+ sending it. That matters: the API silently drops unknown fields, so a typo
48
+ would otherwise be accepted, dropped, and reported as success — leaving an
49
+ agent that had been told nothing.
50
+
51
+ ## Nothing takes effect until you publish
52
+
53
+ **This is the step to not forget.** The runtime resolves the PUBLISHED version
54
+ of an agent and never the draft, so every `set` and `add` above is inert until:
55
+
56
+ ```
57
+ workser agent-cloud publish <id> --note "taught it refunds"
58
+ ```
59
+
60
+ Before publishing, try the setup without putting it live:
61
+
62
+ ```
63
+ workser agent-cloud try <id> "a customer wants a refund on order 1042"
64
+ ```
65
+
66
+ A `try` runs the draft, costs the same as a real run, and changes nothing that
67
+ customers can reach.
68
+
69
+ ## Choosing how it thinks and what it runs on
70
+
71
+ ```
72
+ workser agent-cloud models # cheapest first, on Workser credit
73
+ workser agent-cloud models --all # includes ones needing your own key
74
+ workser agent-cloud set <id> default_provider=openrouter default_model=...
75
+
76
+ workser agent-cloud machines # video, data analysis, design, ...
77
+ ```
78
+
79
+ A model marked "needs your own key" will make `publish` FAIL unless a matching
80
+ secret is stored first. Add the key with `add <id> secret` before setting it.
81
+
29
82
  ## When to reach for this
30
83
 
31
84
  When the user describes a job that **keeps happening** and needs judgement:
@@ -59,7 +112,7 @@ watching sees the agent think. See the `workser-sdk` skill, `reference/agents.md
59
112
 
60
113
  1. **A run costs money by the minute.** It is metered — runtime, workspace, and
61
114
  a per-run fee — so a loop that starts agents is a loop that spends. Cancel
62
- what you abandon: `workser cloud-agent runs <runId>` shows the cost.
115
+ what you abandon: `workser agent-cloud runs <runId>` shows the cost.
63
116
 
64
117
  2. **Instructions are the product.** The agent does what its instructions say,
65
118
  in the user's own words. Write them the way you would brief a new colleague: