@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
|
|
7593
|
+
// src/commands/agent-cloud.ts
|
|
7541
7594
|
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
7542
|
-
function
|
|
7543
|
-
const cloud = program3.command("cloud
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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",
|
package/skills/workser/SKILL.md
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
5
|
+
commands: [agent-cloud]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Ship an agent inside the app
|
|
9
9
|
|
|
10
|
-
`workser cloud
|
|
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
|
|
20
|
-
workser cloud
|
|
21
|
-
workser cloud
|
|
22
|
-
workser cloud
|
|
23
|
-
workser cloud
|
|
24
|
-
workser cloud
|
|
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
|
|
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:
|