@workser/cli 0.6.17 → 0.6.19
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,88 @@ 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-media",
|
|
3668
|
+
title: "Pictures, voice, video \u2014 and calling a model without an agent",
|
|
3669
|
+
summary: "What an Agent Cloud agent can make and read, plus one-shot model calls from the app's own code.",
|
|
3670
|
+
commands: ["agent-cloud"],
|
|
3671
|
+
source: "skills/workser/reference/agent-cloud-media.md",
|
|
3672
|
+
body: `# Pictures, voice, video \u2014 and calling a model without an agent
|
|
3673
|
+
|
|
3674
|
+
### Models that are not chat models
|
|
3675
|
+
|
|
3676
|
+
\`models\` used to list chat models and nothing else \u2014 not by choice, but
|
|
3677
|
+
because the catalogue threw every other kind away before anyone could ask for
|
|
3678
|
+
one. It no longer does:
|
|
3679
|
+
|
|
3680
|
+
\`\`\`
|
|
3681
|
+
workser agent-cloud models --kind image # models that draw
|
|
3682
|
+
workser agent-cloud models --kind video
|
|
3683
|
+
workser agent-cloud models --kind speech # text in, a voice out
|
|
3684
|
+
workser agent-cloud models --kind transcription # a voice in, text out
|
|
3685
|
+
workser agent-cloud models --kind embedding # for search by meaning
|
|
3686
|
+
workser agent-cloud models --accepts image # chat models that see photos
|
|
3687
|
+
\`\`\`
|
|
3688
|
+
|
|
3689
|
+
Prices are shown in the unit the model is SOLD in \u2014 \`4.6 credits each\` for a
|
|
3690
|
+
picture, \`credits/1M\` for words. A picture quoted per million would be out by
|
|
3691
|
+
six orders of magnitude.
|
|
3692
|
+
|
|
3693
|
+
\`default_model\` must stay a **chat model**. It is what the agent thinks with;
|
|
3694
|
+
setting it to an image model publishes an agent that never answers anybody.
|
|
3695
|
+
The other kinds are reached through abilities, below.
|
|
3696
|
+
|
|
3697
|
+
## What the agent can make, and what it can read
|
|
3698
|
+
|
|
3699
|
+
These are abilities on the agent, not models you set:
|
|
3700
|
+
|
|
3701
|
+
| Ability | The agent gains |
|
|
3702
|
+
| --- | --- |
|
|
3703
|
+
| \`media_generation.image\` | \`generate_image\` \u2014 answer with a picture, art for a post |
|
|
3704
|
+
| \`media_generation.audio.speech\` | \`generate_speech\` \u2014 reply in voice |
|
|
3705
|
+
| \`media_generation.audio.sound_effects\` | \`generate_sound_effect\` |
|
|
3706
|
+
| \`media_generation.audio.music\` | \`generate_music\` \u2014 a background track |
|
|
3707
|
+
| \`media_generation.video\` | \`generate_video\` \u2014 short clips |
|
|
3708
|
+
| \`perception.image\` | \`describe_image\` \u2014 read a photo a customer sent |
|
|
3709
|
+
| \`perception.video\` | \`describe_video\` |
|
|
3710
|
+
| \`perception.audio\` | \`transcribe_audio\` \u2014 a voice note becomes text |
|
|
3711
|
+
|
|
3712
|
+
Turn on only what the job needs. **Video costs an order of magnitude more than
|
|
3713
|
+
everything else here**, and it is refused outright on a deployment where an
|
|
3714
|
+
operator has not priced it \u2014 that refusal is a configuration fact, not the
|
|
3715
|
+
user's mistake, so relay it rather than retrying.
|
|
3716
|
+
|
|
3717
|
+
Everything these produce comes back as a **URL in the project's storage**, so
|
|
3718
|
+
it can go straight into a reply, a post, or the next tool.
|
|
3719
|
+
|
|
3720
|
+
## When the app itself needs a model, not an agent
|
|
3721
|
+
|
|
3722
|
+
An agent is a sandbox, a tool loop, and minutes of metered runtime. Most of
|
|
3723
|
+
what an app needs a model for is one call that takes a second: a product
|
|
3724
|
+
description, a thumbnail, a spoken confirmation, search that understands
|
|
3725
|
+
meaning. Starting an agent for those is the wrong shape and the wrong price.
|
|
3726
|
+
|
|
3727
|
+
Use \`@workser/app\` in the app's own code:
|
|
3728
|
+
|
|
3729
|
+
\`\`\`ts
|
|
3730
|
+
import { workser } from '@workser/app';
|
|
3731
|
+
|
|
3732
|
+
const blurb = await workser.ai.text('Write a 40-word description of ' + name);
|
|
3733
|
+
const art = await workser.ai.image('product photo of ' + name);
|
|
3734
|
+
const audio = await workser.ai.speech('Your order is confirmed.');
|
|
3735
|
+
const vector = await workser.ai.embed(descriptions); // many in one call
|
|
3736
|
+
for await (const word of workser.ai.stream(question)) process.stdout.write(word);
|
|
3737
|
+
\`\`\`
|
|
3738
|
+
|
|
3739
|
+
Nobody holds a provider key: Workser's own credential is used and the
|
|
3740
|
+
organisation's credit ledger is charged, the same wallet an agent run draws on.
|
|
3741
|
+
It needs no setup in a Workser-deployed app \u2014 the two environment variables are
|
|
3742
|
+
injected at provisioning.
|
|
3743
|
+
|
|
3744
|
+
**The rule:** one answer goes to \`workser.ai\`; work that takes minutes and uses
|
|
3745
|
+
tools goes to an agent.
|
|
3746
|
+
`
|
|
3747
|
+
},
|
|
3666
3748
|
{
|
|
3667
3749
|
topic: "agent-cloud",
|
|
3668
3750
|
title: "Ship an agent inside the app",
|
|
@@ -3743,6 +3825,11 @@ workser agent-cloud machines # video, data analysis, design, ...
|
|
|
3743
3825
|
A model marked "needs your own key" will make \`publish\` FAIL unless a matching
|
|
3744
3826
|
secret is stored first. Add the key with \`add <id> secret\` before setting it.
|
|
3745
3827
|
|
|
3828
|
+
\`default_model\` must stay a **chat model** \u2014 setting it to an image model
|
|
3829
|
+
publishes an agent that never answers anybody. Pictures, video, voice and
|
|
3830
|
+
transcription are abilities, not models you set, and one call from the app's
|
|
3831
|
+
own code needs no agent at all: \`workser help agent-cloud-media\`.
|
|
3832
|
+
|
|
3746
3833
|
## Agents need a paid plan \u2014 the trial does not include them
|
|
3747
3834
|
|
|
3748
3835
|
\`create\` and \`run\` both refuse with **402** on a free or trialling
|
|
@@ -3750,9 +3837,9 @@ organisation. That is a rule, not a fault: every run buys model tokens and
|
|
|
3750
3837
|
holds a machine, so it costs real money the moment it happens.
|
|
3751
3838
|
|
|
3752
3839
|
**When you hit it, hand the plan over \u2014 do not just describe it.** Workser
|
|
3753
|
-
files the refusal on the conversation as a step and
|
|
3754
|
-
|
|
3755
|
-
|
|
3840
|
+
files the refusal on the conversation as a clickable step and artifact, so the
|
|
3841
|
+
person gets something actionable. Say what you were doing, that agents need a
|
|
3842
|
+
plan, and stop.
|
|
3756
3843
|
|
|
3757
3844
|
Do NOT:
|
|
3758
3845
|
|
|
@@ -7898,21 +7985,37 @@ function registerAgentCloud(program3) {
|
|
|
7898
7985
|
});
|
|
7899
7986
|
})
|
|
7900
7987
|
);
|
|
7901
|
-
cloud.command("models").description("Models this organisation can run an agent on, cheapest first").option("--all", "Include models that need your own provider key").
|
|
7988
|
+
cloud.command("models").description("Models this organisation can run an agent on, cheapest first").option("--all", "Include models that need your own provider key").option(
|
|
7989
|
+
"--kind <kind>",
|
|
7990
|
+
"text | image | video | speech | transcription | embedding (comma-separated)"
|
|
7991
|
+
).option("--accepts <inputs>", "Only models that can read this: image, audio, video, file").action(
|
|
7902
7992
|
action(async ({ ctx, opts }) => {
|
|
7903
|
-
const
|
|
7993
|
+
const q = new URLSearchParams();
|
|
7994
|
+
if (opts.kind) q.set("kind", String(opts.kind));
|
|
7995
|
+
if (opts.accepts) q.set("accepts", String(opts.accepts));
|
|
7996
|
+
if (opts.kind && !String(opts.kind).split(",").includes("text")) {
|
|
7997
|
+
q.set("tools_only", "false");
|
|
7998
|
+
}
|
|
7999
|
+
const suffix = q.toString() ? `?${q.toString()}` : "";
|
|
8000
|
+
const res = await api(
|
|
8001
|
+
ctx,
|
|
8002
|
+
`/v1/agent-cloud/catalog/models/gateways${suffix}`
|
|
8003
|
+
);
|
|
7904
8004
|
const models = (res?.models ?? []).filter(
|
|
7905
8005
|
(m) => opts.all || m.credit_tier === "PLATFORM_CREDITS"
|
|
7906
8006
|
);
|
|
7907
8007
|
ok(res, () => {
|
|
7908
8008
|
if (!models.length) {
|
|
7909
|
-
warn(
|
|
8009
|
+
warn(
|
|
8010
|
+
opts.kind ? `No ${opts.kind} models are available on your credits. Try --all.` : "The live model list could not be read."
|
|
8011
|
+
);
|
|
7910
8012
|
return;
|
|
7911
8013
|
}
|
|
7912
8014
|
for (const m of models.slice(0, 40)) {
|
|
7913
|
-
const price = typeof m.input_price_per_million_usd === "number" ? `$${m.input_price_per_million_usd.toFixed(2)}/M in` : "price unknown";
|
|
8015
|
+
const price = m.price_unit === "each" ? typeof m.credits_each === "number" ? `${m.credits_each} credits each` : "price unknown" : typeof m.input_price_per_million_usd === "number" ? `$${m.input_price_per_million_usd.toFixed(2)}/M in` : "price unknown";
|
|
7914
8016
|
const byok = m.credit_tier === "PLATFORM_CREDITS" ? "" : import_picocolors17.default.yellow(" needs your own key");
|
|
7915
|
-
|
|
8017
|
+
const kind = m.kind && m.kind !== "text" ? import_picocolors17.default.dim(` [${m.kind}]`) : "";
|
|
8018
|
+
line(`${import_picocolors17.default.bold(m.model ?? m.id)}${kind} ${import_picocolors17.default.dim(price)}${byok}`);
|
|
7916
8019
|
}
|
|
7917
8020
|
});
|
|
7918
8021
|
})
|
|
@@ -9912,6 +10015,7 @@ function statusTag2(status) {
|
|
|
9912
10015
|
// src/commands/goal.ts
|
|
9913
10016
|
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
9914
10017
|
var STATUSES3 = ["proposed", "agreed", "working", "delivered", "abandoned"];
|
|
10018
|
+
var PACES = ["slice", "phase", "all"];
|
|
9915
10019
|
function registerGoal(program3) {
|
|
9916
10020
|
const goal = program3.command("goal").description("Business goals and the phases that deliver them");
|
|
9917
10021
|
goal.command("list").description("What this project is working towards").action(
|
|
@@ -9949,6 +10053,9 @@ function registerGoal(program3) {
|
|
|
9949
10053
|
).option(
|
|
9950
10054
|
"--criteria <json>",
|
|
9951
10055
|
`what "done" means per phase, in the OWNER's words: '{"Checkout":["A customer can pay by card and gets a receipt"]}'`
|
|
10056
|
+
).option(
|
|
10057
|
+
"--pace <value>",
|
|
10058
|
+
`how much to do before checking in \u2014 slice (one task, then show), phase (the current phase, the default), all (${PACES.join(" | ")})`
|
|
9952
10059
|
).action(
|
|
9953
10060
|
action(async ({ ctx, args, opts }) => {
|
|
9954
10061
|
requireProject(ctx);
|
|
@@ -9981,11 +10088,17 @@ function registerGoal(program3) {
|
|
|
9981
10088
|
);
|
|
9982
10089
|
}
|
|
9983
10090
|
}
|
|
10091
|
+
if (opts.pace !== void 0 && !PACES.includes(opts.pace)) {
|
|
10092
|
+
throw new WorkserError(
|
|
10093
|
+
`Unknown --pace "${opts.pace}". Use one of: ${PACES.join(", ")}.`
|
|
10094
|
+
);
|
|
10095
|
+
}
|
|
9984
10096
|
const row = await api(ctx, "/v1/project-goals", {
|
|
9985
10097
|
body: {
|
|
9986
10098
|
projectId: ctx.projectId,
|
|
9987
10099
|
title: args[0],
|
|
9988
10100
|
outcome: opts.outcome,
|
|
10101
|
+
pace: opts.pace,
|
|
9989
10102
|
phases: phases.map((name) => ({
|
|
9990
10103
|
name,
|
|
9991
10104
|
criteria: (criteria[name] ?? []).map((text, i) => ({
|
|
@@ -10079,13 +10192,18 @@ function registerGoal(program3) {
|
|
|
10079
10192
|
});
|
|
10080
10193
|
})
|
|
10081
10194
|
);
|
|
10082
|
-
goal.command("update <id>").description("Change the shape, or move the goal along").option("--title <text>", "the owner's words for what they want").option("--outcome <text>", "what 'done' means").option("--phase <name...>", "replace the ordered phase list").option("--status <value>", `one of: ${STATUSES3.join(" | ")}`).action(
|
|
10195
|
+
goal.command("update <id>").description("Change the shape, or move the goal along").option("--title <text>", "the owner's words for what they want").option("--outcome <text>", "what 'done' means").option("--phase <name...>", "replace the ordered phase list").option("--status <value>", `one of: ${STATUSES3.join(" | ")}`).option("--pace <value>", `how much to do before checking in (${PACES.join(" | ")})`).action(
|
|
10083
10196
|
action(async ({ ctx, args, opts }) => {
|
|
10084
10197
|
if (opts.status && !STATUSES3.includes(opts.status)) {
|
|
10085
10198
|
throw new WorkserError(
|
|
10086
10199
|
`Unknown status "${opts.status}". Use one of: ${STATUSES3.join(", ")}.`
|
|
10087
10200
|
);
|
|
10088
10201
|
}
|
|
10202
|
+
if (opts.pace && !PACES.includes(opts.pace)) {
|
|
10203
|
+
throw new WorkserError(
|
|
10204
|
+
`Unknown --pace "${opts.pace}". Use one of: ${PACES.join(", ")}.`
|
|
10205
|
+
);
|
|
10206
|
+
}
|
|
10089
10207
|
const row = await api(
|
|
10090
10208
|
ctx,
|
|
10091
10209
|
`/v1/project-goals/${encodeURIComponent(String(args[0]))}`,
|
|
@@ -10095,7 +10213,8 @@ function registerGoal(program3) {
|
|
|
10095
10213
|
title: opts.title,
|
|
10096
10214
|
outcome: opts.outcome,
|
|
10097
10215
|
phases: opts.phase,
|
|
10098
|
-
status: opts.status
|
|
10216
|
+
status: opts.status,
|
|
10217
|
+
pace: opts.pace
|
|
10099
10218
|
}
|
|
10100
10219
|
}
|
|
10101
10220
|
);
|
|
@@ -10119,6 +10238,7 @@ function printGoal(g) {
|
|
|
10119
10238
|
line(statusTag3(g.status));
|
|
10120
10239
|
if (g.outcome) line(`
|
|
10121
10240
|
done means: ${g.outcome}`);
|
|
10241
|
+
if (g.pace) line(import_picocolors32.default.dim(`pace: ${paceLine(g.pace)}`));
|
|
10122
10242
|
const progress = g.progress ?? [];
|
|
10123
10243
|
if (!progress.length) {
|
|
10124
10244
|
line(import_picocolors32.default.dim("\nNo phases agreed yet."));
|
|
@@ -10162,6 +10282,11 @@ function statusTag3(status) {
|
|
|
10162
10282
|
return import_picocolors32.default.yellow("[proposed]");
|
|
10163
10283
|
}
|
|
10164
10284
|
}
|
|
10285
|
+
function paceLine(pace) {
|
|
10286
|
+
if (pace === "slice") return "slice \u2014 do ONE task, then stop and show the owner";
|
|
10287
|
+
if (pace === "all") return "all \u2014 work through the phases; report at the end";
|
|
10288
|
+
return "phase \u2014 the current phase, task by task";
|
|
10289
|
+
}
|
|
10165
10290
|
|
|
10166
10291
|
// src/role-guard.ts
|
|
10167
10292
|
var READS = [
|
|
@@ -11824,7 +11949,7 @@ function colour(d) {
|
|
|
11824
11949
|
|
|
11825
11950
|
// src/index.ts
|
|
11826
11951
|
var pkg = {
|
|
11827
|
-
version: true ? "0.6.
|
|
11952
|
+
version: true ? "0.6.19" : "0.0.0-dev"
|
|
11828
11953
|
};
|
|
11829
11954
|
var program2 = new Command();
|
|
11830
11955
|
program2.name("workser").description(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workser/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.19",
|
|
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",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
topic: agent-cloud-media
|
|
3
|
+
title: Pictures, voice, video — and calling a model without an agent
|
|
4
|
+
summary: What an Agent Cloud agent can make and read, plus one-shot model calls from the app's own code.
|
|
5
|
+
commands: [agent-cloud]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Pictures, voice, video — and calling a model without an agent
|
|
9
|
+
|
|
10
|
+
### Models that are not chat models
|
|
11
|
+
|
|
12
|
+
`models` used to list chat models and nothing else — not by choice, but
|
|
13
|
+
because the catalogue threw every other kind away before anyone could ask for
|
|
14
|
+
one. It no longer does:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
workser agent-cloud models --kind image # models that draw
|
|
18
|
+
workser agent-cloud models --kind video
|
|
19
|
+
workser agent-cloud models --kind speech # text in, a voice out
|
|
20
|
+
workser agent-cloud models --kind transcription # a voice in, text out
|
|
21
|
+
workser agent-cloud models --kind embedding # for search by meaning
|
|
22
|
+
workser agent-cloud models --accepts image # chat models that see photos
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Prices are shown in the unit the model is SOLD in — `4.6 credits each` for a
|
|
26
|
+
picture, `credits/1M` for words. A picture quoted per million would be out by
|
|
27
|
+
six orders of magnitude.
|
|
28
|
+
|
|
29
|
+
`default_model` must stay a **chat model**. It is what the agent thinks with;
|
|
30
|
+
setting it to an image model publishes an agent that never answers anybody.
|
|
31
|
+
The other kinds are reached through abilities, below.
|
|
32
|
+
|
|
33
|
+
## What the agent can make, and what it can read
|
|
34
|
+
|
|
35
|
+
These are abilities on the agent, not models you set:
|
|
36
|
+
|
|
37
|
+
| Ability | The agent gains |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| `media_generation.image` | `generate_image` — answer with a picture, art for a post |
|
|
40
|
+
| `media_generation.audio.speech` | `generate_speech` — reply in voice |
|
|
41
|
+
| `media_generation.audio.sound_effects` | `generate_sound_effect` |
|
|
42
|
+
| `media_generation.audio.music` | `generate_music` — a background track |
|
|
43
|
+
| `media_generation.video` | `generate_video` — short clips |
|
|
44
|
+
| `perception.image` | `describe_image` — read a photo a customer sent |
|
|
45
|
+
| `perception.video` | `describe_video` |
|
|
46
|
+
| `perception.audio` | `transcribe_audio` — a voice note becomes text |
|
|
47
|
+
|
|
48
|
+
Turn on only what the job needs. **Video costs an order of magnitude more than
|
|
49
|
+
everything else here**, and it is refused outright on a deployment where an
|
|
50
|
+
operator has not priced it — that refusal is a configuration fact, not the
|
|
51
|
+
user's mistake, so relay it rather than retrying.
|
|
52
|
+
|
|
53
|
+
Everything these produce comes back as a **URL in the project's storage**, so
|
|
54
|
+
it can go straight into a reply, a post, or the next tool.
|
|
55
|
+
|
|
56
|
+
## When the app itself needs a model, not an agent
|
|
57
|
+
|
|
58
|
+
An agent is a sandbox, a tool loop, and minutes of metered runtime. Most of
|
|
59
|
+
what an app needs a model for is one call that takes a second: a product
|
|
60
|
+
description, a thumbnail, a spoken confirmation, search that understands
|
|
61
|
+
meaning. Starting an agent for those is the wrong shape and the wrong price.
|
|
62
|
+
|
|
63
|
+
Use `@workser/app` in the app's own code:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { workser } from '@workser/app';
|
|
67
|
+
|
|
68
|
+
const blurb = await workser.ai.text('Write a 40-word description of ' + name);
|
|
69
|
+
const art = await workser.ai.image('product photo of ' + name);
|
|
70
|
+
const audio = await workser.ai.speech('Your order is confirmed.');
|
|
71
|
+
const vector = await workser.ai.embed(descriptions); // many in one call
|
|
72
|
+
for await (const word of workser.ai.stream(question)) process.stdout.write(word);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Nobody holds a provider key: Workser's own credential is used and the
|
|
76
|
+
organisation's credit ledger is charged, the same wallet an agent run draws on.
|
|
77
|
+
It needs no setup in a Workser-deployed app — the two environment variables are
|
|
78
|
+
injected at provisioning.
|
|
79
|
+
|
|
80
|
+
**The rule:** one answer goes to `workser.ai`; work that takes minutes and uses
|
|
81
|
+
tools goes to an agent.
|
|
@@ -79,6 +79,11 @@ workser agent-cloud machines # video, data analysis, design, ...
|
|
|
79
79
|
A model marked "needs your own key" will make `publish` FAIL unless a matching
|
|
80
80
|
secret is stored first. Add the key with `add <id> secret` before setting it.
|
|
81
81
|
|
|
82
|
+
`default_model` must stay a **chat model** — setting it to an image model
|
|
83
|
+
publishes an agent that never answers anybody. Pictures, video, voice and
|
|
84
|
+
transcription are abilities, not models you set, and one call from the app's
|
|
85
|
+
own code needs no agent at all: `workser help agent-cloud-media`.
|
|
86
|
+
|
|
82
87
|
## Agents need a paid plan — the trial does not include them
|
|
83
88
|
|
|
84
89
|
`create` and `run` both refuse with **402** on a free or trialling
|
|
@@ -86,9 +91,9 @@ organisation. That is a rule, not a fault: every run buys model tokens and
|
|
|
86
91
|
holds a machine, so it costs real money the moment it happens.
|
|
87
92
|
|
|
88
93
|
**When you hit it, hand the plan over — do not just describe it.** Workser
|
|
89
|
-
files the refusal on the conversation as a step and
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
files the refusal on the conversation as a clickable step and artifact, so the
|
|
95
|
+
person gets something actionable. Say what you were doing, that agents need a
|
|
96
|
+
plan, and stop.
|
|
92
97
|
|
|
93
98
|
Do NOT:
|
|
94
99
|
|