@cargo-ai/cli 1.0.29 → 1.0.31
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/README.md +1 -2
- package/build/commands/ai/message.d.ts.map +1 -1
- package/build/commands/ai/message.js +95 -29
- package/build/commands/content/file.js +3 -3
- package/build/commands/orchestration/batch.d.ts.map +1 -1
- package/build/commands/orchestration/batch.js +25 -7
- package/build/commands/orchestration/release.d.ts.map +1 -1
- package/build/commands/orchestration/release.js +3 -53
- package/build/commands/orchestration/run.d.ts.map +1 -1
- package/build/commands/orchestration/run.js +25 -7
- package/build/commands/workspaceManagement/file.js +3 -3
- package/build/utils/cdkState.d.ts +26 -0
- package/build/utils/cdkState.d.ts.map +1 -0
- package/build/utils/cdkState.js +101 -0
- package/build/utils/loadCompiledAgent.d.ts +5 -0
- package/build/utils/loadCompiledAgent.d.ts.map +1 -0
- package/build/utils/loadCompiledAgent.js +75 -0
- package/build/utils/loadCompiledWorkflow.d.ts +8 -0
- package/build/utils/loadCompiledWorkflow.d.ts.map +1 -0
- package/build/utils/loadCompiledWorkflow.js +38 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -136,11 +136,10 @@ cargo-ai orchestration release deploy-draft --file ./my-workflow.ts --workflow-u
|
|
|
136
136
|
cargo-ai orchestration release deploy-draft --workflow-uuid <uuid> --nodes '[…]' --form-fields '[…]'
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
`--file <path>` loads a
|
|
139
|
+
`--file <path>` loads a `@cargo-ai/workflow-sdk` module (its `export default defineWorkflow(...)`) and sources `nodes` / `formFields` from the compiled output. With `--file`:
|
|
140
140
|
|
|
141
141
|
- `--workflow-uuid` is optional — when omitted, the command best-effort matches the compiled `slug` against existing workflows' `template.slug` and errors if the match is missing or ambiguous.
|
|
142
142
|
- `--version` defaults to the next minor bump over the latest existing release (or `1.0.0` for the first).
|
|
143
|
-
- `--description` defaults to the compiled workflow's description.
|
|
144
143
|
- `--nodes` / `--form-fields` are rejected (they're sourced from the module).
|
|
145
144
|
|
|
146
145
|
Without `--file`, `--workflow-uuid`, `--nodes`, and `--form-fields` are all required (raw JSON path). Constraint either way: there is **no** workflow-create endpoint, so the target workflow must already exist.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAiCxC,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA2RN"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadCompiledAgent, resolveCompiledAgentFromState, } from "../../utils/loadCompiledAgent.js";
|
|
2
|
+
import { ExitCodes, failWith, handleApiCall, info, outputJson, parseJson, pollMessageUntilFinished, } from "../runHandler.js";
|
|
2
3
|
export function registerMessageCommands(parent, getApi) {
|
|
3
4
|
const message = parent
|
|
4
5
|
.command("message")
|
|
5
6
|
.description("Manage chat messages (create, get, list, cancel, remove)");
|
|
6
7
|
message
|
|
7
8
|
.command("create")
|
|
8
|
-
.description("Create a message in a chat. Returns the user message and a pending
|
|
9
|
-
.
|
|
9
|
+
.description("Create a message in a chat. Returns the user message and a pending " +
|
|
10
|
+
"assistant message. Pass --file to test-message a defineAgent " +
|
|
11
|
+
"module inline (its @cargo-ai/cdk handles resolved from " +
|
|
12
|
+
"cargo.state.json — no deploy).")
|
|
13
|
+
.option("--chat-uuid <uuid>", "Chat UUID (string). When omitted, a new draft chat is created automatically.")
|
|
14
|
+
.option("--agent-uuid <uuid>", "Agent UUID for the auto-created chat (string, only used when --chat-uuid is omitted)")
|
|
15
|
+
.option("--release-uuid <uuid>", "Release UUID for the auto-created chat (string, only used when --chat-uuid is omitted)")
|
|
10
16
|
.requiredOption("--parts <json>", "Message parts (JSON array of part objects, required)")
|
|
17
|
+
.option("--file <path>", "Path to a @cargo-ai/cdk module whose default export is a defineAgent() handle. Compiles it, resolves its resource handles to real uuids from cargo.state.json, and sends the agent's prompt/tools/models/capabilities inline — no deploy. Rejected with the inline flags (and --agent-uuid / --release-uuid).")
|
|
11
18
|
.option("--actions <json>", "Actions available to the assistant (JSON array of action objects)")
|
|
12
19
|
.option("--resources <json>", "Resources available to the assistant (JSON array of resource objects)")
|
|
13
20
|
.option("--capabilities <json>", "Capabilities to enable (JSON array of capability objects)")
|
|
@@ -25,6 +32,9 @@ export function registerMessageCommands(parent, getApi) {
|
|
|
25
32
|
.addHelpText("after", `
|
|
26
33
|
Examples:
|
|
27
34
|
$ cargo-ai ai message create --chat-uuid 550e8400-... --parts '[{"type":"text","text":"Hello"}]'
|
|
35
|
+
$ cargo-ai ai message create --parts '[{"type":"text","text":"Hello"}]'
|
|
36
|
+
$ cargo-ai ai message create --agent-uuid 550e8400-... --parts '[{"type":"text","text":"Hello"}]'
|
|
37
|
+
$ cargo-ai ai message create --file ./agents/researcher.ts --parts '[{"type":"text","text":"Research acme.com"}]' --wait-until-finished
|
|
28
38
|
$ cargo-ai ai message create --chat-uuid 550e8400-... --parts '[{"type":"text","text":"Find leads"}]' \\
|
|
29
39
|
--actions '[{"slug":"search","kind":"tool","config":{}}]' --wait-until-finished
|
|
30
40
|
|
|
@@ -34,35 +44,91 @@ Resource object shape: { "slug": string, "kind": "model", "modelUuid": string }
|
|
|
34
44
|
MCP client shape: { "name": string, "url": string }`)
|
|
35
45
|
.action(async (opts) => {
|
|
36
46
|
const api = getApi();
|
|
47
|
+
// --file test-messages a defineAgent module: it supplies the whole
|
|
48
|
+
// LLM / tools / models / capabilities inline (no deploy), so the flags
|
|
49
|
+
// that would otherwise set those — plus the deployed-agent bindings —
|
|
50
|
+
// are rejected in its favour.
|
|
51
|
+
let params;
|
|
52
|
+
if (opts.file !== undefined) {
|
|
53
|
+
const conflicts = [
|
|
54
|
+
["--agent-uuid", opts.agentUuid],
|
|
55
|
+
["--release-uuid", opts.releaseUuid],
|
|
56
|
+
["--actions", opts.actions],
|
|
57
|
+
["--resources", opts.resources],
|
|
58
|
+
["--capabilities", opts.capabilities],
|
|
59
|
+
["--mcp-clients", opts.mcpClients],
|
|
60
|
+
["--system-prompt", opts.systemPrompt],
|
|
61
|
+
["--with-reasoning", opts.withReasoning],
|
|
62
|
+
["--temperature", opts.temperature],
|
|
63
|
+
["--max-steps", opts.maxSteps],
|
|
64
|
+
["--integration-slug", opts.integrationSlug],
|
|
65
|
+
["--connector-uuid", opts.connectorUuid],
|
|
66
|
+
["--language-model-slug", opts.languageModelSlug],
|
|
67
|
+
["--output", opts.output],
|
|
68
|
+
]
|
|
69
|
+
.filter(([, value]) => value !== undefined)
|
|
70
|
+
.map(([flag]) => flag);
|
|
71
|
+
if (conflicts.length > 0) {
|
|
72
|
+
failWith(`${conflicts.join(", ")} not allowed with --file (sourced from the agent).`, { code: ExitCodes.InvalidUsage });
|
|
73
|
+
}
|
|
74
|
+
const compiled = await loadCompiledAgent(opts.file);
|
|
75
|
+
const resolved = resolveCompiledAgentFromState(compiled, opts.file);
|
|
76
|
+
params = {
|
|
77
|
+
actions: resolved.actions,
|
|
78
|
+
resources: resolved.resources,
|
|
79
|
+
capabilities: resolved.capabilities,
|
|
80
|
+
mcpClients: resolved.mcpClients,
|
|
81
|
+
systemPrompt: resolved.systemPrompt,
|
|
82
|
+
withReasoning: resolved.withReasoning,
|
|
83
|
+
temperature: resolved.temperature,
|
|
84
|
+
maxSteps: resolved.maxSteps,
|
|
85
|
+
connectorUuid: resolved.connectorUuid,
|
|
86
|
+
languageModelSlug: resolved.languageModelSlug,
|
|
87
|
+
output: resolved.output,
|
|
88
|
+
};
|
|
89
|
+
if (resolved.connectorUuid !== undefined) {
|
|
90
|
+
const uuid = resolved.connectorUuid;
|
|
91
|
+
const connectorResult = await handleApiCall(() => api.connection.connector.get({ uuid }));
|
|
92
|
+
params.integrationSlug = connectorResult.connector.integrationSlug;
|
|
93
|
+
}
|
|
94
|
+
info(`Test-messaging agent "${compiled.slug}" — no deploy.`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
params = {
|
|
98
|
+
actions: opts.actions !== undefined
|
|
99
|
+
? parseJson(opts.actions, "--actions")
|
|
100
|
+
: undefined,
|
|
101
|
+
resources: opts.resources !== undefined
|
|
102
|
+
? parseJson(opts.resources, "--resources")
|
|
103
|
+
: undefined,
|
|
104
|
+
capabilities: opts.capabilities !== undefined
|
|
105
|
+
? parseJson(opts.capabilities, "--capabilities")
|
|
106
|
+
: undefined,
|
|
107
|
+
mcpClients: opts.mcpClients !== undefined
|
|
108
|
+
? parseJson(opts.mcpClients, "--mcp-clients")
|
|
109
|
+
: undefined,
|
|
110
|
+
systemPrompt: opts.systemPrompt,
|
|
111
|
+
withReasoning: opts.withReasoning,
|
|
112
|
+
temperature: opts.temperature !== undefined
|
|
113
|
+
? parseFloat(opts.temperature)
|
|
114
|
+
: undefined,
|
|
115
|
+
maxSteps: opts.maxSteps !== undefined
|
|
116
|
+
? parseInt(opts.maxSteps, 10)
|
|
117
|
+
: undefined,
|
|
118
|
+
integrationSlug: opts.integrationSlug,
|
|
119
|
+
connectorUuid: opts.connectorUuid,
|
|
120
|
+
languageModelSlug: opts.languageModelSlug,
|
|
121
|
+
output: opts.output !== undefined
|
|
122
|
+
? parseJson(opts.output, "--output")
|
|
123
|
+
: undefined,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
37
126
|
const result = await handleApiCall(() => api.ai.message.create({
|
|
38
127
|
chatUuid: opts.chatUuid,
|
|
128
|
+
agentUuid: opts.agentUuid,
|
|
129
|
+
releaseUuid: opts.releaseUuid,
|
|
39
130
|
parts: parseJson(opts.parts, "--parts"),
|
|
40
|
-
|
|
41
|
-
? parseJson(opts.actions, "--actions")
|
|
42
|
-
: undefined,
|
|
43
|
-
resources: opts.resources !== undefined
|
|
44
|
-
? parseJson(opts.resources, "--resources")
|
|
45
|
-
: undefined,
|
|
46
|
-
capabilities: opts.capabilities !== undefined
|
|
47
|
-
? parseJson(opts.capabilities, "--capabilities")
|
|
48
|
-
: undefined,
|
|
49
|
-
mcpClients: opts.mcpClients !== undefined
|
|
50
|
-
? parseJson(opts.mcpClients, "--mcp-clients")
|
|
51
|
-
: undefined,
|
|
52
|
-
systemPrompt: opts.systemPrompt,
|
|
53
|
-
withReasoning: opts.withReasoning,
|
|
54
|
-
temperature: opts.temperature !== undefined
|
|
55
|
-
? parseFloat(opts.temperature)
|
|
56
|
-
: undefined,
|
|
57
|
-
maxSteps: opts.maxSteps !== undefined
|
|
58
|
-
? parseInt(opts.maxSteps, 10)
|
|
59
|
-
: undefined,
|
|
60
|
-
integrationSlug: opts.integrationSlug,
|
|
61
|
-
connectorUuid: opts.connectorUuid,
|
|
62
|
-
languageModelSlug: opts.languageModelSlug,
|
|
63
|
-
output: opts.output !== undefined
|
|
64
|
-
? parseJson(opts.output, "--output")
|
|
65
|
-
: undefined,
|
|
131
|
+
...params,
|
|
66
132
|
}));
|
|
67
133
|
if (opts.waitUntilFinished === true) {
|
|
68
134
|
const intervalMs = parseInt(opts.pollingInterval, 10);
|
|
@@ -45,11 +45,11 @@ export function registerFileCommands(parent, getApi) {
|
|
|
45
45
|
file
|
|
46
46
|
.command("upload")
|
|
47
47
|
.description("Upload a file")
|
|
48
|
-
.requiredOption("--file
|
|
48
|
+
.requiredOption("--file <path>", "Path to the file to upload")
|
|
49
49
|
.option("--folder-uuid <uuid>", "Folder UUID")
|
|
50
50
|
.action(async (opts) => {
|
|
51
|
-
const buffer = await readFile(opts.
|
|
52
|
-
const name = basename(opts.
|
|
51
|
+
const buffer = await readFile(opts.file);
|
|
52
|
+
const name = basename(opts.file);
|
|
53
53
|
const fileObj = new File([buffer], name);
|
|
54
54
|
const api = getApi();
|
|
55
55
|
await handleApiCall(() => new Promise((resolve, reject) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAexC,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA2QN"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadCompiledWorkflow, resolveCompiledWorkflowFromState, } from "../../utils/loadCompiledWorkflow.js";
|
|
2
|
+
import { ExitCodes, failWith, handleApiCall, info, outputJson, parseJson, pollBatchUntilFinished, } from "../runHandler.js";
|
|
2
3
|
export function registerBatchCommands(parent, getApi) {
|
|
3
4
|
const batch = parent
|
|
4
5
|
.command("batch")
|
|
@@ -60,25 +61,42 @@ export function registerBatchCommands(parent, getApi) {
|
|
|
60
61
|
});
|
|
61
62
|
batch
|
|
62
63
|
.command("create")
|
|
63
|
-
.description("Create a batch"
|
|
64
|
+
.description("Create a batch. Pass --file to test-run a Workflow SDK module (compiled and " +
|
|
65
|
+
"run as custom nodes, with @cargo-ai/cdk handles resolved from cargo.state.json — no deploy).")
|
|
64
66
|
.option("--workflow-uuid <uuid>", "Workflow UUID (string)")
|
|
65
67
|
.requiredOption("--data <json>", 'Batch data source (JSON object, required). Supported kinds: {"kind":"segment","segmentUuid":"..."} or {"kind":"file","s3Filename":"..."}')
|
|
66
68
|
.option("--release-uuid <uuid>", "Release UUID to pin the batch to (string)")
|
|
67
|
-
.option("--
|
|
69
|
+
.option("--file <path>", "Path to a Workflow SDK module (its default export must be the compiled workflow returned by defineWorkflow()). Compiles it, resolves any @cargo-ai/cdk resource handles to real uuids from cargo.state.json, and runs the resulting nodes. Rejected with --nodes.")
|
|
70
|
+
.option("--nodes <json>", "Custom nodes to override the workflow definition (JSON array). Rejected with --file.")
|
|
68
71
|
.option("--wait-until-finished", "Poll the batch until it reaches a terminal status before returning (boolean flag)")
|
|
69
72
|
.option("--polling-interval <ms>", "Polling interval in milliseconds, used with --wait-until-finished (integer, default: 5000)", "5000")
|
|
70
73
|
.addHelpText("after", `
|
|
71
74
|
Examples:
|
|
72
75
|
$ cargo-ai orchestration batch create --data '{"kind":"segment","segmentUuid":"550e8400-..."}'
|
|
73
|
-
$ cargo-ai orchestration batch create --workflow-uuid 550e8400-... --data '{"kind":"file","s3Filename":"input.csv"}' --wait-until-finished
|
|
76
|
+
$ cargo-ai orchestration batch create --workflow-uuid 550e8400-... --data '{"kind":"file","s3Filename":"input.csv"}' --wait-until-finished
|
|
77
|
+
$ cargo-ai orchestration batch create --file ./plays/onboarding.ts --data '{"kind":"segment","segmentUuid":"550e8400-..."}' --wait-until-finished`)
|
|
74
78
|
.action(async (opts) => {
|
|
79
|
+
// `--file` compiles a Workflow SDK module and runs its (state-resolved)
|
|
80
|
+
// nodes ad-hoc; `--nodes` supplies a raw node graph. They're mutually
|
|
81
|
+
// exclusive sources for the same payload field.
|
|
82
|
+
let nodes;
|
|
83
|
+
if (opts.file !== undefined) {
|
|
84
|
+
if (opts.nodes !== undefined) {
|
|
85
|
+
failWith("--nodes is not allowed with --file (sourced from the module)", { code: ExitCodes.InvalidUsage });
|
|
86
|
+
}
|
|
87
|
+
const compiled = await loadCompiledWorkflow(opts.file);
|
|
88
|
+
const resolved = resolveCompiledWorkflowFromState(compiled, opts.file);
|
|
89
|
+
info(`Test-running "${resolved.slug}" (${String(resolved.nodes.length)} node(s)) — no deploy.`);
|
|
90
|
+
nodes = resolved.nodes;
|
|
91
|
+
}
|
|
92
|
+
else if (opts.nodes !== undefined) {
|
|
93
|
+
nodes = parseJson(opts.nodes, "--nodes");
|
|
94
|
+
}
|
|
75
95
|
const api = getApi();
|
|
76
96
|
const result = await handleApiCall(() => api.orchestration.batch.create({
|
|
77
97
|
workflowUuid: opts.workflowUuid,
|
|
78
98
|
releaseUuid: opts.releaseUuid,
|
|
79
|
-
nodes
|
|
80
|
-
? parseJson(opts.nodes, "--nodes")
|
|
81
|
-
: undefined,
|
|
99
|
+
nodes,
|
|
82
100
|
data: parseJson(opts.data, "--data"),
|
|
83
101
|
}));
|
|
84
102
|
if (opts.waitUntilFinished === true) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/release.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/release.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAmCxC,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA+KN"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isAbsolute, resolve } from "node:path";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
1
|
+
import { loadCompiledWorkflow, } from "../../utils/loadCompiledWorkflow.js";
|
|
4
2
|
import { ExitCodes, failWith, handleApiCall, info, outputJson, parseJson, success, } from "../runHandler.js";
|
|
5
3
|
export function registerReleaseCommands(parent, getApi) {
|
|
6
4
|
const release = parent
|
|
@@ -90,7 +88,7 @@ export function registerReleaseCommands(parent, getApi) {
|
|
|
90
88
|
.option("--version <version>", "Release version (e.g. '1.2.0'). With --file, defaults to the next minor bump over the latest existing release; otherwise required by the engine.")
|
|
91
89
|
.option("--nodes <json>", "Nodes (JSON array of node definitions). Required without --file; rejected with --file.")
|
|
92
90
|
.option("--form-fields <json>", "Form fields (JSON array, or 'null'). Required without --file; rejected with --file.")
|
|
93
|
-
.option("--description <text>", "Release description
|
|
91
|
+
.option("--description <text>", "Release description.")
|
|
94
92
|
.option("--options <json>", "Options (JSON object)")
|
|
95
93
|
.option("--dry-run", "With --file: compile and print the nodes + form fields without deploying. Ignored without --file.")
|
|
96
94
|
.action(async (opts) => {
|
|
@@ -157,7 +155,6 @@ async function runFileDeploy(getApi, opts) {
|
|
|
157
155
|
if (opts.dryRun === true) {
|
|
158
156
|
outputJson({
|
|
159
157
|
slug: compiled.slug,
|
|
160
|
-
description: compiled.description,
|
|
161
158
|
nodes: compiled.nodes,
|
|
162
159
|
formFields: compiled.formFields,
|
|
163
160
|
});
|
|
@@ -168,14 +165,13 @@ async function runFileDeploy(getApi, opts) {
|
|
|
168
165
|
const version = opts.version !== undefined
|
|
169
166
|
? opts.version
|
|
170
167
|
: await computeNextVersion(api, workflowUuid);
|
|
171
|
-
const description = opts.description !== undefined ? opts.description : compiled.description;
|
|
172
168
|
info(`Deploying "${compiled.slug}" → workflow ${workflowUuid} as v${version} (${String(compiled.nodes.length)} node(s))…`);
|
|
173
169
|
const payload = {
|
|
174
170
|
workflowUuid,
|
|
175
171
|
version,
|
|
176
172
|
nodes: compiled.nodes,
|
|
177
173
|
formFields: compiled.formFields,
|
|
178
|
-
description,
|
|
174
|
+
description: opts.description,
|
|
179
175
|
options: opts.options !== undefined
|
|
180
176
|
? parseJson(opts.options, "--options")
|
|
181
177
|
: undefined,
|
|
@@ -184,52 +180,6 @@ async function runFileDeploy(getApi, opts) {
|
|
|
184
180
|
success(`Deployed v${version}.`);
|
|
185
181
|
outputJson(result);
|
|
186
182
|
}
|
|
187
|
-
// Load a workflow module via the tsx ESM loader so `.ts` sources (and their
|
|
188
|
-
// imports of `@cargo-ai/workflow-sdk` / `zod`) are transpiled on the fly,
|
|
189
|
-
// returning its default export validated as a compiled workflow.
|
|
190
|
-
async function loadCompiledWorkflow(file) {
|
|
191
|
-
const absPath = isAbsolute(file) ? file : resolve(process.cwd(), file);
|
|
192
|
-
if (!existsSync(absPath)) {
|
|
193
|
-
failWith(`Workflow file not found: ${absPath}`, {
|
|
194
|
-
code: ExitCodes.InvalidUsage,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
let mod;
|
|
198
|
-
try {
|
|
199
|
-
const { tsImport } = await import("tsx/esm/api");
|
|
200
|
-
mod = (await tsImport(pathToFileURL(absPath).href, import.meta.url));
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
failWith(`Failed to load workflow module: ${error instanceof Error ? error.message : String(error)}`, { code: ExitCodes.GenericError });
|
|
204
|
-
}
|
|
205
|
-
const candidate = resolveDefaultExport(mod);
|
|
206
|
-
if (!isCompiledWorkflow(candidate)) {
|
|
207
|
-
failWith("Workflow module must `export default` a compiled workflow (the value returned by defineWorkflow()).", { code: ExitCodes.InvalidUsage });
|
|
208
|
-
}
|
|
209
|
-
return candidate;
|
|
210
|
-
}
|
|
211
|
-
// Peel the extra interop layer tsx adds when a TS source is transpiled to
|
|
212
|
-
// CJS: the ESM namespace's `default` is then the CJS `module.exports`
|
|
213
|
-
// (`{ __esModule: true, default: … }`), so the real value lives one level
|
|
214
|
-
// deeper. True-ESM modules expose it directly.
|
|
215
|
-
function resolveDefaultExport(mod) {
|
|
216
|
-
const top = mod.default;
|
|
217
|
-
if (top !== null && typeof top === "object") {
|
|
218
|
-
const inner = top;
|
|
219
|
-
if (inner["__esModule"] === true && "default" in inner) {
|
|
220
|
-
return inner["default"];
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return top;
|
|
224
|
-
}
|
|
225
|
-
function isCompiledWorkflow(value) {
|
|
226
|
-
if (value === null || typeof value !== "object")
|
|
227
|
-
return false;
|
|
228
|
-
const v = value;
|
|
229
|
-
return (typeof v["slug"] === "string" &&
|
|
230
|
-
Array.isArray(v["nodes"]) &&
|
|
231
|
-
Array.isArray(v["formFields"]));
|
|
232
|
-
}
|
|
233
183
|
// Resolve the target workflow UUID. The platform `Workflow` has no free-form
|
|
234
184
|
// slug field — the closest stable identifier is `template.slug` — and there
|
|
235
185
|
// is no `workflow.create` endpoint, so an explicit `--workflow-uuid` always
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAexC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAsnB5E"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadCompiledWorkflow, resolveCompiledWorkflowFromState, } from "../../utils/loadCompiledWorkflow.js";
|
|
2
|
+
import { ExitCodes, failWith, handleApiCall, info, outputJson, parseJson, pollRunUntilFinished, } from "../runHandler.js";
|
|
2
3
|
export function registerRunCommands(parent, getApi) {
|
|
3
4
|
const run = parent
|
|
4
5
|
.command("run")
|
|
@@ -69,27 +70,44 @@ Examples:
|
|
|
69
70
|
});
|
|
70
71
|
run
|
|
71
72
|
.command("create")
|
|
72
|
-
.description("Create a run"
|
|
73
|
+
.description("Create a run. Pass --file to test-run a Workflow SDK module (compiled and " +
|
|
74
|
+
"run as custom nodes, with @cargo-ai/cdk handles resolved from cargo.state.json — no deploy).")
|
|
73
75
|
.option("--workflow-uuid <uuid>", "Workflow UUID (string)")
|
|
74
76
|
.requiredOption("--data <json>", "Run input data (JSON object, required). The shape depends on your workflow's start node configuration")
|
|
75
77
|
.option("--release-uuid <uuid>", "Release UUID to pin the run to (string)")
|
|
76
|
-
.option("--
|
|
78
|
+
.option("--file <path>", "Path to a Workflow SDK module (its default export must be the compiled workflow returned by defineWorkflow()). Compiles it, resolves any @cargo-ai/cdk resource handles to real uuids from cargo.state.json, and runs the resulting nodes. Rejected with --nodes.")
|
|
79
|
+
.option("--nodes <json>", "Custom nodes to override the workflow definition (JSON array). Rejected with --file.")
|
|
77
80
|
.option("--wait-until-finished", "Poll the run until it reaches a terminal status before returning (boolean flag)")
|
|
78
81
|
.option("--polling-interval <ms>", "Polling interval in milliseconds, used with --wait-until-finished (integer, default: 5000)", "5000")
|
|
79
82
|
.addHelpText("after", `
|
|
80
83
|
Examples:
|
|
81
84
|
$ cargo-ai orchestration run create --data '{"email":"user@example.com"}'
|
|
82
85
|
$ cargo-ai orchestration run create --workflow-uuid 550e8400-... --data '{"id":"123"}' --wait-until-finished
|
|
83
|
-
$ cargo-ai orchestration run create --data '{"id":"123"}' --wait-until-finished --polling-interval 10000
|
|
86
|
+
$ cargo-ai orchestration run create --data '{"id":"123"}' --wait-until-finished --polling-interval 10000
|
|
87
|
+
$ cargo-ai orchestration run create --file ./plays/onboarding.ts --data '{"domain":"acme.com"}' --wait-until-finished`)
|
|
84
88
|
.action(async (opts) => {
|
|
85
89
|
const data = parseJson(opts.data, "--data");
|
|
90
|
+
// `--file` compiles a Workflow SDK module and runs its (state-resolved)
|
|
91
|
+
// nodes ad-hoc; `--nodes` supplies a raw node graph. They're mutually
|
|
92
|
+
// exclusive sources for the same payload field.
|
|
93
|
+
let nodes;
|
|
94
|
+
if (opts.file !== undefined) {
|
|
95
|
+
if (opts.nodes !== undefined) {
|
|
96
|
+
failWith("--nodes is not allowed with --file (sourced from the module)", { code: ExitCodes.InvalidUsage });
|
|
97
|
+
}
|
|
98
|
+
const compiled = await loadCompiledWorkflow(opts.file);
|
|
99
|
+
const resolved = resolveCompiledWorkflowFromState(compiled, opts.file);
|
|
100
|
+
info(`Test-running "${resolved.slug}" (${String(resolved.nodes.length)} node(s)) — no deploy.`);
|
|
101
|
+
nodes = resolved.nodes;
|
|
102
|
+
}
|
|
103
|
+
else if (opts.nodes !== undefined) {
|
|
104
|
+
nodes = parseJson(opts.nodes, "--nodes");
|
|
105
|
+
}
|
|
86
106
|
const api = getApi();
|
|
87
107
|
const result = await handleApiCall(() => api.orchestration.run.create({
|
|
88
108
|
workflowUuid: opts.workflowUuid,
|
|
89
109
|
releaseUuid: opts.releaseUuid,
|
|
90
|
-
nodes
|
|
91
|
-
? parseJson(opts.nodes, "--nodes")
|
|
92
|
-
: undefined,
|
|
110
|
+
nodes,
|
|
93
111
|
data,
|
|
94
112
|
}));
|
|
95
113
|
if (opts.waitUntilFinished === true) {
|
|
@@ -6,10 +6,10 @@ export function registerFileCommands(parent, getApi) {
|
|
|
6
6
|
file
|
|
7
7
|
.command("upload")
|
|
8
8
|
.description("Upload a file")
|
|
9
|
-
.requiredOption("--file
|
|
9
|
+
.requiredOption("--file <path>", "Path to the file to upload")
|
|
10
10
|
.action(async (opts) => {
|
|
11
|
-
const buffer = await readFile(opts.
|
|
12
|
-
const name = basename(opts.
|
|
11
|
+
const buffer = await readFile(opts.file);
|
|
12
|
+
const name = basename(opts.file);
|
|
13
13
|
const fileObj = new File([buffer], name);
|
|
14
14
|
const api = getApi();
|
|
15
15
|
await handleApiCall(() => new Promise((resolve, reject) => {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare function resolveDefaultExport(mod: {
|
|
2
|
+
default?: unknown;
|
|
3
|
+
}): unknown;
|
|
4
|
+
/**
|
|
5
|
+
* Load a `.ts`/`.js` module through the tsx ESM loader (so `.ts` sources and
|
|
6
|
+
* their imports of `@cargo-ai/*` / `zod` are transpiled on the fly) and return
|
|
7
|
+
* its resolved default export. Shared by both `--file` loaders: the workflow
|
|
8
|
+
* loader validates the result as a compiled workflow; the agent loader reads the
|
|
9
|
+
* agent back out of the CDK registry that loading populated (so it must
|
|
10
|
+
* `resetRegistry()` BEFORE calling this). `subject` labels the file in errors
|
|
11
|
+
* (e.g. "Workflow", "Agent").
|
|
12
|
+
*/
|
|
13
|
+
export declare function importModuleDefault(file: string, subject: string): Promise<{
|
|
14
|
+
absPath: string;
|
|
15
|
+
defaultExport: unknown;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Deep-resolve every `@cargo-ai/cdk` handle token in `value` to its real uuid
|
|
19
|
+
* using the nearest cargo.state.json (searched from `file`'s directory upward,
|
|
20
|
+
* then the cwd). `subject` names the thing under test in error messages (e.g. a
|
|
21
|
+
* workflow or agent slug). A value with no tokens (literal-uuid refs, or a pure
|
|
22
|
+
* body) is returned unchanged — no state needed. Fails with an actionable error
|
|
23
|
+
* when state is missing or a referenced resource isn't deployed yet.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveTokensFromState(value: unknown, file: string, subject: string): unknown;
|
|
26
|
+
//# sourceMappingURL=cdkState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdkState.d.ts","sourceRoot":"","sources":["../../src/utils/cdkState.ts"],"names":[],"mappings":"AAmBA,wBAAgB,oBAAoB,CAAC,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CASxE;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAC,CAyBtD;AAaD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAuCT"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Shared helpers for the CLI `--file` paths that compile a
|
|
2
|
+
// `@cargo-ai/cdk`-aware module (a Workflow SDK workflow, or a `defineAgent`) and
|
|
3
|
+
// test-run it against ALREADY-DEPLOYED resources. Both need the same two things:
|
|
4
|
+
// peel the tsx interop layer off a module's default export, and resolve any
|
|
5
|
+
// `@cargo-ai/cdk` handle tokens the module references to their real uuids from
|
|
6
|
+
// the committed cargo.state.json — without deploying the module itself.
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
9
|
+
import { pathToFileURL } from "node:url";
|
|
10
|
+
import { dependenciesOf, readState, resolveTokens } from "@cargo-ai/cdk";
|
|
11
|
+
import { ExitCodes, failWith } from "../commands/runHandler.js";
|
|
12
|
+
// Peel the extra interop layer tsx adds when a TS source is transpiled to CJS:
|
|
13
|
+
// the ESM namespace's `default` is then the CJS `module.exports`
|
|
14
|
+
// (`{ __esModule: true, default: … }`), so the real value lives one level
|
|
15
|
+
// deeper. True-ESM modules expose it directly.
|
|
16
|
+
export function resolveDefaultExport(mod) {
|
|
17
|
+
const top = mod.default;
|
|
18
|
+
if (top !== null && typeof top === "object") {
|
|
19
|
+
const inner = top;
|
|
20
|
+
if (inner["__esModule"] === true && "default" in inner) {
|
|
21
|
+
return inner["default"];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return top;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Load a `.ts`/`.js` module through the tsx ESM loader (so `.ts` sources and
|
|
28
|
+
* their imports of `@cargo-ai/*` / `zod` are transpiled on the fly) and return
|
|
29
|
+
* its resolved default export. Shared by both `--file` loaders: the workflow
|
|
30
|
+
* loader validates the result as a compiled workflow; the agent loader reads the
|
|
31
|
+
* agent back out of the CDK registry that loading populated (so it must
|
|
32
|
+
* `resetRegistry()` BEFORE calling this). `subject` labels the file in errors
|
|
33
|
+
* (e.g. "Workflow", "Agent").
|
|
34
|
+
*/
|
|
35
|
+
export async function importModuleDefault(file, subject) {
|
|
36
|
+
const absPath = isAbsolute(file) ? file : resolve(process.cwd(), file);
|
|
37
|
+
if (!existsSync(absPath)) {
|
|
38
|
+
failWith(`${subject} file not found: ${absPath}`, {
|
|
39
|
+
code: ExitCodes.InvalidUsage,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
let mod;
|
|
43
|
+
try {
|
|
44
|
+
const { tsImport } = await import("tsx/esm/api");
|
|
45
|
+
mod = (await tsImport(pathToFileURL(absPath).href, import.meta.url));
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
failWith(`Failed to load ${subject.toLowerCase()} module: ${error instanceof Error ? error.message : String(error)}`, { code: ExitCodes.GenericError });
|
|
49
|
+
}
|
|
50
|
+
return { absPath, defaultExport: resolveDefaultExport(mod) };
|
|
51
|
+
}
|
|
52
|
+
// Walk up from `startDir` looking for a directory that holds cargo.state.json.
|
|
53
|
+
function findStateRoot(startDir) {
|
|
54
|
+
let dir = startDir;
|
|
55
|
+
for (;;) {
|
|
56
|
+
if (existsSync(join(dir, "cargo.state.json")))
|
|
57
|
+
return dir;
|
|
58
|
+
const parent = dirname(dir);
|
|
59
|
+
if (parent === dir)
|
|
60
|
+
return undefined;
|
|
61
|
+
dir = parent;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Deep-resolve every `@cargo-ai/cdk` handle token in `value` to its real uuid
|
|
66
|
+
* using the nearest cargo.state.json (searched from `file`'s directory upward,
|
|
67
|
+
* then the cwd). `subject` names the thing under test in error messages (e.g. a
|
|
68
|
+
* workflow or agent slug). A value with no tokens (literal-uuid refs, or a pure
|
|
69
|
+
* body) is returned unchanged — no state needed. Fails with an actionable error
|
|
70
|
+
* when state is missing or a referenced resource isn't deployed yet.
|
|
71
|
+
*/
|
|
72
|
+
export function resolveTokensFromState(value, file, subject) {
|
|
73
|
+
const deps = dependenciesOf(value);
|
|
74
|
+
if (deps.size === 0)
|
|
75
|
+
return value;
|
|
76
|
+
const absPath = isAbsolute(file) ? file : resolve(process.cwd(), file);
|
|
77
|
+
const stateRoot = findStateRoot(dirname(absPath)) ?? findStateRoot(process.cwd());
|
|
78
|
+
if (stateRoot === undefined) {
|
|
79
|
+
failWith(`${subject} references ${String(deps.size)} deployed resource(s) ` +
|
|
80
|
+
`(${[...deps].join(", ")}), but no cargo.state.json was found near ` +
|
|
81
|
+
`${absPath} or the current directory. Deploy the resources first with ` +
|
|
82
|
+
"`cargo-ai cdk deploy`, or reference them by literal uuid " +
|
|
83
|
+
"(toolRef / agentRef / connectorRef).", { code: ExitCodes.NotFound });
|
|
84
|
+
}
|
|
85
|
+
const state = readState(stateRoot);
|
|
86
|
+
const outputs = new Map();
|
|
87
|
+
if (state !== undefined) {
|
|
88
|
+
for (const [id, entry] of Object.entries(state.resources)) {
|
|
89
|
+
outputs.set(id, entry.outputs);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const missing = [...deps].filter((id) => !outputs.has(id));
|
|
93
|
+
if (missing.length > 0) {
|
|
94
|
+
failWith(`${String(missing.length)} resource(s) referenced by ${subject} ` +
|
|
95
|
+
`aren't in cargo.state.json yet: ${missing.join(", ")}. A test run ` +
|
|
96
|
+
"resolves existing (already-deployed) resources from state — it won't " +
|
|
97
|
+
"create new ones. Deploy them first with `cargo-ai cdk deploy`, or " +
|
|
98
|
+
"reference them by literal uuid (toolRef / agentRef / connectorRef).", { code: ExitCodes.NotFound });
|
|
99
|
+
}
|
|
100
|
+
return resolveTokens(value, outputs);
|
|
101
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type CompiledAgent } from "@cargo-ai/cdk";
|
|
2
|
+
export type { CompiledAgent } from "@cargo-ai/cdk";
|
|
3
|
+
export declare function loadCompiledAgent(file: string): Promise<CompiledAgent>;
|
|
4
|
+
export declare function resolveCompiledAgentFromState(compiled: CompiledAgent, file: string): CompiledAgent;
|
|
5
|
+
//# sourceMappingURL=loadCompiledAgent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadCompiledAgent.d.ts","sourceRoot":"","sources":["../../src/utils/loadCompiledAgent.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,eAAe,CAAC;AAKvB,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAqCnD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA6C5E;AAQD,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,MAAM,GACX,aAAa,CAQf"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// The `ai message create --file` path: compile a `@cargo-ai/cdk` `defineAgent`
|
|
2
|
+
// module and lower it to the params an `ai message create` accepts, so you can
|
|
3
|
+
// chat against an agent's real prompt / tools / models / capabilities WITHOUT
|
|
4
|
+
// deploying it. Two steps mirror the workflow `--file` flow: `loadCompiledAgent`
|
|
5
|
+
// runs the module's `define*` calls into the shared CDK registry, reads the
|
|
6
|
+
// agent back, and maps its buckets with the SAME transform `cdk deploy` uses
|
|
7
|
+
// (`compileAgent`); `resolveCompiledAgentFromState` then resolves the
|
|
8
|
+
// `@cargo-ai/cdk` handle tokens it still carries to real uuids from
|
|
9
|
+
// cargo.state.json — a faithful test of the agent's core chat behaviour.
|
|
10
|
+
import { compileAgent, resetRegistry, resources, } from "@cargo-ai/cdk";
|
|
11
|
+
import { ExitCodes, failWith } from "../commands/runHandler.js";
|
|
12
|
+
import { importModuleDefault, resolveTokensFromState } from "./cdkState.js";
|
|
13
|
+
function isAgentHandle(value) {
|
|
14
|
+
if (value === null || typeof value !== "object")
|
|
15
|
+
return false;
|
|
16
|
+
const v = value;
|
|
17
|
+
return v["resource"] === "agent" && typeof v["slug"] === "string";
|
|
18
|
+
}
|
|
19
|
+
// Agent config an inline message can't express — rejected up front (rather than
|
|
20
|
+
// silently dropped) so a test run is never quietly less than the deployed agent.
|
|
21
|
+
// Each entry: the spec field, and whether the stored value means "set".
|
|
22
|
+
const UNSUPPORTED = [
|
|
23
|
+
{ field: "evaluator", label: "evaluator", isSet: (v) => v !== null },
|
|
24
|
+
{ field: "heartbeat", label: "heartbeat", isSet: (v) => v !== null },
|
|
25
|
+
{
|
|
26
|
+
field: "triggers",
|
|
27
|
+
label: "triggers",
|
|
28
|
+
isSet: (v) => Array.isArray(v) && v.length > 0,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
field: "suggestedActions",
|
|
32
|
+
label: "suggestedActions",
|
|
33
|
+
isSet: (v) => Array.isArray(v) && v.length > 0,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
// Load a `defineAgent` module and lower it to a `CompiledAgent` (tokens still
|
|
37
|
+
// embedded — resolve them with `resolveCompiledAgentFromState`). `resetRegistry`
|
|
38
|
+
// first so a stale registry (e.g. a prior load in the same process) can't leak
|
|
39
|
+
// resources into this one.
|
|
40
|
+
export async function loadCompiledAgent(file) {
|
|
41
|
+
// Reset BEFORE loading: the import runs the module's `define*` calls, which
|
|
42
|
+
// register into the shared CDK registry we read back below. A stale registry
|
|
43
|
+
// (e.g. a prior load in the same process) would otherwise leak in.
|
|
44
|
+
resetRegistry();
|
|
45
|
+
const { absPath, defaultExport: handle } = await importModuleDefault(file, "Agent");
|
|
46
|
+
if (!isAgentHandle(handle)) {
|
|
47
|
+
failWith("Agent module must `export default` an agent handle (the value returned by defineAgent()).", { code: ExitCodes.InvalidUsage });
|
|
48
|
+
}
|
|
49
|
+
// A file can register several agents (its sub-agents), so pick THE one it
|
|
50
|
+
// exports by slug rather than assuming a single registration.
|
|
51
|
+
const node = resources().find((n) => n.kind === "agent" && n.slug === handle.slug);
|
|
52
|
+
if (node === undefined) {
|
|
53
|
+
failWith(`Agent "${handle.slug}" was not registered by ${absPath}. Ensure the ` +
|
|
54
|
+
"module's default export is the handle returned by defineAgent().", { code: ExitCodes.GenericError });
|
|
55
|
+
}
|
|
56
|
+
const setUnsupported = UNSUPPORTED.filter((u) => u.isSet(node.spec[u.field])).map((u) => u.label);
|
|
57
|
+
if (setUnsupported.length > 0) {
|
|
58
|
+
failWith(`Agent "${handle.slug}" sets ${setUnsupported.join(", ")}, which a test ` +
|
|
59
|
+
"message can't apply (they only take effect on a deployed release). " +
|
|
60
|
+
"Remove them for a test run, or deploy the agent with `cargo-ai cdk " +
|
|
61
|
+
"deploy` and chat against it by uuid.", { code: ExitCodes.InvalidUsage });
|
|
62
|
+
}
|
|
63
|
+
return compileAgent(node.spec);
|
|
64
|
+
}
|
|
65
|
+
// Resolve the agent params' `@cargo-ai/cdk` resource handles (tool / agent /
|
|
66
|
+
// connector / model) to their real uuids using the committed cargo.state.json,
|
|
67
|
+
// so a test message runs against the ALREADY-DEPLOYED resources without
|
|
68
|
+
// deploying the agent itself. Returns the same compiled agent with engine-ready
|
|
69
|
+
// params. An agent with no handle tokens (literal-uuid refs) is returned
|
|
70
|
+
// unchanged — no state needed.
|
|
71
|
+
export function resolveCompiledAgentFromState(compiled, file) {
|
|
72
|
+
// The slug is a plain string (no token), so resolving the whole object is
|
|
73
|
+
// safe and keeps it flat.
|
|
74
|
+
return resolveTokensFromState(compiled, file, `"${compiled.slug}"`);
|
|
75
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type CompiledWorkflow = {
|
|
2
|
+
slug: string;
|
|
3
|
+
nodes: unknown[];
|
|
4
|
+
formFields: unknown[];
|
|
5
|
+
};
|
|
6
|
+
export declare function loadCompiledWorkflow(file: string): Promise<CompiledWorkflow>;
|
|
7
|
+
export declare function resolveCompiledWorkflowFromState(compiled: CompiledWorkflow, file: string): CompiledWorkflow;
|
|
8
|
+
//# sourceMappingURL=loadCompiledWorkflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadCompiledWorkflow.d.ts","sourceRoot":"","sources":["../../src/utils/loadCompiledWorkflow.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,EAAE,CAAC;CACvB,CAAC;AAKF,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,CAAC,CAW3B;AAUD,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,MAAM,GACX,gBAAgB,CAOlB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Shared helpers for the `--file` paths that compile a `@cargo-ai/workflow-sdk`
|
|
2
|
+
// module: `release deploy-draft --file` (deploy it) and `run create --file` /
|
|
3
|
+
// `batch create --file` (test-run it). Loading is identical; `run create` and
|
|
4
|
+
// `batch create` additionally resolve any `@cargo-ai/cdk` resource handles the
|
|
5
|
+
// workflow references to their real uuids from cargo.state.json (see
|
|
6
|
+
// `resolveCompiledWorkflowFromState`).
|
|
7
|
+
import { ExitCodes, failWith } from "../commands/runHandler.js";
|
|
8
|
+
import { importModuleDefault, resolveTokensFromState } from "./cdkState.js";
|
|
9
|
+
// Load a workflow module via the tsx ESM loader so `.ts` sources (and their
|
|
10
|
+
// imports of `@cargo-ai/workflow-sdk` / `zod`) are transpiled on the fly,
|
|
11
|
+
// returning its default export validated as a compiled workflow.
|
|
12
|
+
export async function loadCompiledWorkflow(file) {
|
|
13
|
+
const { defaultExport } = await importModuleDefault(file, "Workflow");
|
|
14
|
+
if (!isCompiledWorkflow(defaultExport)) {
|
|
15
|
+
failWith("Workflow module must `export default` a compiled workflow (the value returned by defineWorkflow()).", { code: ExitCodes.InvalidUsage });
|
|
16
|
+
}
|
|
17
|
+
return defaultExport;
|
|
18
|
+
}
|
|
19
|
+
// Resolve the workflow's `@cargo-ai/cdk` resource handles (tool / agent /
|
|
20
|
+
// connector / model / …) to their real uuids using the committed
|
|
21
|
+
// cargo.state.json, so a test-run executes against the ALREADY-DEPLOYED
|
|
22
|
+
// resources without deploying the workflow itself. Returns the same compiled
|
|
23
|
+
// workflow with an engine-ready node graph (`formFields` carry no tokens, so
|
|
24
|
+
// they pass through). A workflow with no handle tokens (literal-uuid refs via
|
|
25
|
+
// `toolRef`/`connectorRef`, or a pure-native body) is returned unchanged — no
|
|
26
|
+
// state needed.
|
|
27
|
+
export function resolveCompiledWorkflowFromState(compiled, file) {
|
|
28
|
+
const nodes = resolveTokensFromState(compiled.nodes, file, `"${compiled.slug}"`);
|
|
29
|
+
return { ...compiled, nodes };
|
|
30
|
+
}
|
|
31
|
+
function isCompiledWorkflow(value) {
|
|
32
|
+
if (value === null || typeof value !== "object")
|
|
33
|
+
return false;
|
|
34
|
+
const v = value;
|
|
35
|
+
return (typeof v["slug"] === "string" &&
|
|
36
|
+
Array.isArray(v["nodes"]) &&
|
|
37
|
+
Array.isArray(v["formFields"]));
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cargo-ai/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"description": "Command-line interface for the Cargo API",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
14
|
"bin": {
|
|
15
|
-
"cargo-ai": "./build/index.js"
|
|
15
|
+
"cargo-ai": "./build/index.js",
|
|
16
|
+
"cargo": "./build/index.js"
|
|
16
17
|
},
|
|
17
18
|
"files": [
|
|
18
19
|
"build",
|