@codemation/agent-skills 0.1.6 → 0.1.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # @codemation/agent-skills
2
2
 
3
+ ## 0.1.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#78](https://github.com/MadeRelevant/codemation/pull/78) [`f451b1b`](https://github.com/MadeRelevant/codemation/commit/f451b1b4657b59406e15ce5f50b243e487ff99ed) Thanks [@cblokland90](https://github.com/cblokland90)! - Normalize fluent workflow DSL callback helpers around the runtime item contract.
8
+
9
+ `.map(...)`, `.if(...)`, and `.switch({ resolveCaseKey })` now receive `(item, ctx)` so workflow authors can use `item.json` consistently and read prior completed outputs through `ctx.data` without dropping down to direct node configs.
10
+
11
+ ## 0.1.7
12
+
13
+ ### Patch Changes
14
+
15
+ - [#77](https://github.com/MadeRelevant/codemation/pull/77) [`525a311`](https://github.com/MadeRelevant/codemation/commit/525a311fe7868772c923f92e268730dab422cf97) Thanks [@cblokland90](https://github.com/cblokland90)! - Expose the packaged agent skills extractor as an importable module and refresh `.agents/skills/extracted` automatically when running `codemation dev`, `codemation build`, `codemation serve web`, or `codemation dev:plugin`. Add `codemation skills sync` for manual or CI refreshes after upgrading the CLI.
16
+
17
+ - [#71](https://github.com/MadeRelevant/codemation/pull/71) [`3044e73`](https://github.com/MadeRelevant/codemation/commit/3044e73fd3cfb33f8e2cbc579c10baf97ed94658) Thanks [@cblokland90](https://github.com/cblokland90)! - Add inline callable agent tools to the workflow DSL.
18
+
19
+ This introduces `callableTool(...)` as a workflow-friendly helper for app-local agent tools, keeps
20
+ `CallableToolFactory.callableTool(...)` as a compatible factory entry point, teaches `AIAgentNode`
21
+ to execute callable tools with the same tracing and validation model as other tool kinds, and
22
+ updates docs, skills, and the test-dev sample to show the new path.
23
+
24
+ - [#73](https://github.com/MadeRelevant/codemation/pull/73) [`418434a`](https://github.com/MadeRelevant/codemation/commit/418434a6a2ad88a6254a94cb70e6f14b886df348) Thanks [@cblokland90](https://github.com/cblokland90)! - Improve credential UX and add extensible advanced field presentation.
25
+ - Run automatic credential health tests after create/save (including OAuth) and keep the dialog open when the test fails; auto-bind newly created credentials to empty workflow slots; auto-bind when picking an existing credential from the workflow slot dropdown while the slot is unbound.
26
+ - Add `CredentialFieldSchema.visibility` (`default` | `advanced`) and optional `CredentialTypeDefinition.advancedSection` (advanced fields always render in a collapsible block; section labels default when omitted). Next host uses stable test ids and fixes collapsible chevron styling.
27
+ - Credential dialog: title uses the credential type name (e.g. **Add …** / type display name on edit); hide the redundant type dropdown in edit mode.
28
+ - Gmail OAuth: group Client ID with Client secret, move scope preset and custom scopes under an **OAuth scopes** advanced section (collapsed by default).
29
+ - Documentation: `packages/core/docs/credential-ui-fields.md`, AGENTS.md, and credential development skill reference.
30
+
31
+ - [#74](https://github.com/MadeRelevant/codemation/pull/74) [`26ebe63`](https://github.com/MadeRelevant/codemation/commit/26ebe6346db0e9133a2133435a463c3dcd2dc537) Thanks [@cblokland90](https://github.com/cblokland90)! - Unify `workflow().agent()` message authoring with `AIAgent`.
32
+
33
+ `WorkflowAgentOptions` now takes `messages` (the same `AgentMessageConfig` as `AIAgent`) instead of
34
+ `prompt`. The workflow helper passes `messages` through unchanged. Docs, workflow DSL skills, and the
35
+ test-dev sample use `itemValue(...)` for per-item prompts; execution docs note `itemValue` on agent
36
+ `messages`.
37
+
38
+ ## Unreleased
39
+
40
+ ### Patch Changes
41
+
42
+ - Workflow DSL skill: document **`callableTool(...)`** for inline agent tools (with **`CallableToolFactory.callableTool(...)`** as the equivalent factory entry point).
43
+
3
44
  ## 0.1.6
4
45
 
5
46
  ### Patch Changes
package/README.md CHANGED
@@ -6,6 +6,7 @@ Publishable Codemation agent skills packaged as `SKILL.md` directories.
6
6
 
7
7
  - shared Codemation skills for CLI usage, workflow authoring, plugin development, credentials, and framework concepts
8
8
  - a small extraction CLI that copies the packaged skills into a project-local `.agents/skills` directory
9
+ - a programmatic API (`@codemation/agent-skills`) used by `@codemation/cli` to refresh packaged skills on consumer workflows
9
10
 
10
11
  ## Install in a project
11
12
 
@@ -16,6 +17,25 @@ codemation-agent-skills extract --output .agents/skills/extracted
16
17
 
17
18
  The starter templates call the extractor automatically after `pnpm install`.
18
19
 
20
+ ## Framework-managed copy
21
+
22
+ The directory `.agents/skills/extracted` is **framework-managed**: Codemation overwrites packaged `codemation-*` skill folders there and removes stale packaged skill directories when you run `codemation dev`, `codemation build`, `codemation serve web`, or `codemation dev:plugin` (or `codemation skills sync`). Put project-local skills in sibling folders under `.agents/skills`, not inside `extracted`, unless you accept them being replaced.
23
+
24
+ ## Programmatic use
25
+
26
+ ```js
27
+ import { FileSystemGateway, SkillExtractor, resolveAgentSkillsPackageRoot } from "@codemation/agent-skills";
28
+
29
+ const consumerRoot = process.cwd();
30
+ const extractor = new SkillExtractor(
31
+ new FileSystemGateway(),
32
+ resolveAgentSkillsPackageRoot(),
33
+ consumerRoot,
34
+ process.stdout,
35
+ );
36
+ await extractor.extract(".agents/skills/extracted");
37
+ ```
38
+
19
39
  ## Published layout
20
40
 
21
41
  ```text
@@ -2,171 +2,18 @@
2
2
 
3
3
  import path from "node:path";
4
4
  import process from "node:process";
5
- import { cp, mkdir, readdir, rm, stat } from "node:fs/promises";
6
5
  import { fileURLToPath } from "node:url";
7
6
 
8
- export class CommandError extends Error {}
7
+ export {
8
+ CodemationAgentSkillsCli,
9
+ CommandError,
10
+ CommandLineParser,
11
+ FileSystemGateway,
12
+ SkillExtractor,
13
+ resolveAgentSkillsPackageRoot,
14
+ } from "../lib/agent-skills-extractor.mjs";
9
15
 
10
- export class FileSystemGateway {
11
- async copyDirectory(sourcePath, destinationPath) {
12
- await cp(sourcePath, destinationPath, { force: true, recursive: true });
13
- }
14
-
15
- async createDirectory(targetPath) {
16
- await mkdir(targetPath, { recursive: true });
17
- }
18
-
19
- async listDirectoryEntries(targetPath) {
20
- return readdir(targetPath, { withFileTypes: true });
21
- }
22
-
23
- async removePath(targetPath) {
24
- await rm(targetPath, { force: true, recursive: true });
25
- }
26
-
27
- async statPath(targetPath) {
28
- return stat(targetPath);
29
- }
30
- }
31
-
32
- export class SkillExtractor {
33
- constructor(fileSystem, packageRoot, cwd, stdout) {
34
- this.fileSystem = fileSystem;
35
- this.packageRoot = packageRoot;
36
- this.cwd = cwd;
37
- this.stdout = stdout;
38
- }
39
-
40
- async extract(outputArgument) {
41
- const outputPath = path.resolve(this.cwd, outputArgument);
42
- const skillsRoot = path.join(this.packageRoot, "skills");
43
-
44
- await this.fileSystem.createDirectory(outputPath);
45
- const packagedEntries = await this.fileSystem.listDirectoryEntries(skillsRoot);
46
- const packagedSkillNames = new Set(
47
- packagedEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name),
48
- );
49
-
50
- await this.#removeStaleSkillDirectories(outputPath, packagedSkillNames);
51
-
52
- for (const skillName of packagedSkillNames) {
53
- const sourcePath = path.join(skillsRoot, skillName);
54
- const destinationPath = path.join(outputPath, skillName);
55
- await this.fileSystem.removePath(destinationPath);
56
- await this.fileSystem.copyDirectory(sourcePath, destinationPath);
57
- this.stdout.write(`[codemation-agent-skills] extracted ${skillName}\n`);
58
- }
59
- }
60
-
61
- async #removeStaleSkillDirectories(outputPath, packagedSkillNames) {
62
- let existingEntries;
63
- try {
64
- existingEntries = await this.fileSystem.listDirectoryEntries(outputPath);
65
- } catch {
66
- return;
67
- }
68
-
69
- for (const entry of existingEntries) {
70
- if (!entry.isDirectory()) {
71
- continue;
72
- }
73
- if (!entry.name.startsWith("codemation-")) {
74
- continue;
75
- }
76
- if (packagedSkillNames.has(entry.name)) {
77
- continue;
78
- }
79
- await this.fileSystem.removePath(path.join(outputPath, entry.name));
80
- }
81
- }
82
- }
83
-
84
- export class CommandLineParser {
85
- constructor(argv) {
86
- this.argv = argv;
87
- }
88
-
89
- parse() {
90
- const [command, ...rest] = this.argv;
91
- if (!command || command === "--help" || command === "-h") {
92
- return { command: "help" };
93
- }
94
- if (command !== "extract") {
95
- throw new CommandError(`Unknown command "${command}".`);
96
- }
97
-
98
- let output = ".agents/skills/extracted";
99
- for (let index = 0; index < rest.length; index += 1) {
100
- const argument = rest[index];
101
- if (argument === "--output") {
102
- const value = rest[index + 1];
103
- if (!value) {
104
- throw new CommandError("Missing value for --output.");
105
- }
106
- output = value;
107
- index += 1;
108
- continue;
109
- }
110
- if (argument === "--help" || argument === "-h") {
111
- return { command: "help" };
112
- }
113
- throw new CommandError(`Unknown argument "${argument}".`);
114
- }
115
-
116
- return { command: "extract", output };
117
- }
118
- }
119
-
120
- export class CodemationAgentSkillsCli {
121
- constructor(argv, cwd, stdout, stderr) {
122
- this.argv = argv;
123
- this.cwd = cwd;
124
- this.stdout = stdout;
125
- this.stderr = stderr;
126
- this.fileSystem = new FileSystemGateway();
127
- }
128
-
129
- async run() {
130
- try {
131
- const parsed = new CommandLineParser(this.argv).parse();
132
- if (parsed.command === "help") {
133
- this.#writeHelp();
134
- return;
135
- }
136
-
137
- const packageRoot = path.resolve(import.meta.dirname, "..");
138
- const extractor = new SkillExtractor(this.fileSystem, packageRoot, this.cwd, this.stdout);
139
- await extractor.extract(parsed.output);
140
- } catch (error) {
141
- if (error instanceof CommandError) {
142
- this.stderr.write(`${error.message}\n\n`);
143
- this.#writeHelp();
144
- process.exitCode = 1;
145
- return;
146
- }
147
- this.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
148
- process.exitCode = 1;
149
- }
150
- }
151
-
152
- #writeHelp() {
153
- this.stdout.write(
154
- [
155
- "codemation-agent-skills",
156
- "",
157
- "Usage:",
158
- " codemation-agent-skills extract [--output <path>]",
159
- "",
160
- "Commands:",
161
- " extract Copy packaged Codemation skills into a project directory.",
162
- "",
163
- "Options:",
164
- " --output Destination directory. Defaults to .agents/skills/extracted.",
165
- "",
166
- ].join("\n"),
167
- );
168
- }
169
- }
16
+ import { CodemationAgentSkillsCli } from "../lib/agent-skills-extractor.mjs";
170
17
 
171
18
  if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
172
19
  await new CodemationAgentSkillsCli(process.argv.slice(2), process.cwd(), process.stdout, process.stderr).run();
@@ -0,0 +1,41 @@
1
+ import type { Dirent } from "node:fs";
2
+
3
+ export class CommandError extends Error {}
4
+
5
+ export class FileSystemGateway {
6
+ copyDirectory(sourcePath: string, destinationPath: string): Promise<void>;
7
+ createDirectory(targetPath: string): Promise<void>;
8
+ listDirectoryEntries(targetPath: string): Promise<Dirent[]>;
9
+ removePath(targetPath: string): Promise<void>;
10
+ statPath(targetPath: string): Promise<import("node:fs").Stats>;
11
+ }
12
+
13
+ export function resolveAgentSkillsPackageRoot(): string;
14
+
15
+ export class SkillExtractor {
16
+ constructor(
17
+ fileSystem: FileSystemGateway,
18
+ packageRoot: string,
19
+ cwd: string,
20
+ stdout: { write: (chunk: string) => void },
21
+ );
22
+
23
+ extract(outputArgument: string): Promise<void>;
24
+ }
25
+
26
+ export class CommandLineParser {
27
+ constructor(argv: ReadonlyArray<string>);
28
+
29
+ parse(): { command: "help" } | { command: "extract"; output: string };
30
+ }
31
+
32
+ export class CodemationAgentSkillsCli {
33
+ constructor(
34
+ argv: ReadonlyArray<string>,
35
+ cwd: string,
36
+ stdout: { write: (chunk: string) => void },
37
+ stderr: { write: (chunk: string) => void },
38
+ );
39
+
40
+ run(): Promise<void>;
41
+ }
@@ -0,0 +1,178 @@
1
+ import path from "node:path";
2
+ import process from "node:process";
3
+ import { cp, mkdir, readdir, rm, stat } from "node:fs/promises";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ export class CommandError extends Error {}
7
+
8
+ export class FileSystemGateway {
9
+ async copyDirectory(sourcePath, destinationPath) {
10
+ await cp(sourcePath, destinationPath, { force: true, recursive: true });
11
+ }
12
+
13
+ async createDirectory(targetPath) {
14
+ await mkdir(targetPath, { recursive: true });
15
+ }
16
+
17
+ async listDirectoryEntries(targetPath) {
18
+ return readdir(targetPath, { withFileTypes: true });
19
+ }
20
+
21
+ async removePath(targetPath) {
22
+ await rm(targetPath, { force: true, recursive: true });
23
+ }
24
+
25
+ async statPath(targetPath) {
26
+ return stat(targetPath);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Resolves the root directory of the `@codemation/agent-skills` package (contains `skills/`).
32
+ */
33
+ export function resolveAgentSkillsPackageRoot() {
34
+ const libDir = path.dirname(fileURLToPath(import.meta.url));
35
+ return path.resolve(libDir, "..");
36
+ }
37
+
38
+ export class SkillExtractor {
39
+ constructor(fileSystem, packageRoot, cwd, stdout) {
40
+ this.fileSystem = fileSystem;
41
+ this.packageRoot = packageRoot;
42
+ this.cwd = cwd;
43
+ this.stdout = stdout;
44
+ }
45
+
46
+ /**
47
+ * @param {string} outputArgument relative or absolute path for extracted skills
48
+ */
49
+ async extract(outputArgument) {
50
+ const outputPath = path.resolve(this.cwd, outputArgument);
51
+ const skillsRoot = path.join(this.packageRoot, "skills");
52
+
53
+ await this.fileSystem.createDirectory(outputPath);
54
+ const packagedEntries = await this.fileSystem.listDirectoryEntries(skillsRoot);
55
+ const packagedSkillNames = new Set(
56
+ packagedEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name),
57
+ );
58
+
59
+ await this.#removeStaleSkillDirectories(outputPath, packagedSkillNames);
60
+
61
+ for (const skillName of packagedSkillNames) {
62
+ const sourcePath = path.join(skillsRoot, skillName);
63
+ const destinationPath = path.join(outputPath, skillName);
64
+ await this.fileSystem.removePath(destinationPath);
65
+ await this.fileSystem.copyDirectory(sourcePath, destinationPath);
66
+ this.stdout.write(`[codemation-agent-skills] extracted ${skillName}\n`);
67
+ }
68
+ }
69
+
70
+ async #removeStaleSkillDirectories(outputPath, packagedSkillNames) {
71
+ let existingEntries;
72
+ try {
73
+ existingEntries = await this.fileSystem.listDirectoryEntries(outputPath);
74
+ } catch {
75
+ return;
76
+ }
77
+
78
+ for (const entry of existingEntries) {
79
+ if (!entry.isDirectory()) {
80
+ continue;
81
+ }
82
+ if (!entry.name.startsWith("codemation-")) {
83
+ continue;
84
+ }
85
+ if (packagedSkillNames.has(entry.name)) {
86
+ continue;
87
+ }
88
+ await this.fileSystem.removePath(path.join(outputPath, entry.name));
89
+ }
90
+ }
91
+ }
92
+
93
+ export class CommandLineParser {
94
+ constructor(argv) {
95
+ this.argv = argv;
96
+ }
97
+
98
+ parse() {
99
+ const [command, ...rest] = this.argv;
100
+ if (!command || command === "--help" || command === "-h") {
101
+ return { command: "help" };
102
+ }
103
+ if (command !== "extract") {
104
+ throw new CommandError(`Unknown command "${command}".`);
105
+ }
106
+
107
+ let output = ".agents/skills/extracted";
108
+ for (let index = 0; index < rest.length; index += 1) {
109
+ const argument = rest[index];
110
+ if (argument === "--output") {
111
+ const value = rest[index + 1];
112
+ if (!value) {
113
+ throw new CommandError("Missing value for --output.");
114
+ }
115
+ output = value;
116
+ index += 1;
117
+ continue;
118
+ }
119
+ if (argument === "--help" || argument === "-h") {
120
+ return { command: "help" };
121
+ }
122
+ throw new CommandError(`Unknown argument "${argument}".`);
123
+ }
124
+
125
+ return { command: "extract", output };
126
+ }
127
+ }
128
+
129
+ export class CodemationAgentSkillsCli {
130
+ constructor(argv, cwd, stdout, stderr) {
131
+ this.argv = argv;
132
+ this.cwd = cwd;
133
+ this.stdout = stdout;
134
+ this.stderr = stderr;
135
+ this.fileSystem = new FileSystemGateway();
136
+ }
137
+
138
+ async run() {
139
+ try {
140
+ const parsed = new CommandLineParser(this.argv).parse();
141
+ if (parsed.command === "help") {
142
+ this.#writeHelp();
143
+ return;
144
+ }
145
+
146
+ const packageRoot = resolveAgentSkillsPackageRoot();
147
+ const extractor = new SkillExtractor(this.fileSystem, packageRoot, this.cwd, this.stdout);
148
+ await extractor.extract(parsed.output);
149
+ } catch (error) {
150
+ if (error instanceof CommandError) {
151
+ this.stderr.write(`${error.message}\n\n`);
152
+ this.#writeHelp();
153
+ process.exitCode = 1;
154
+ return;
155
+ }
156
+ this.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
157
+ process.exitCode = 1;
158
+ }
159
+ }
160
+
161
+ #writeHelp() {
162
+ this.stdout.write(
163
+ [
164
+ "codemation-agent-skills",
165
+ "",
166
+ "Usage:",
167
+ " codemation-agent-skills extract [--output <path>]",
168
+ "",
169
+ "Commands:",
170
+ " extract Copy packaged Codemation skills into a project directory.",
171
+ "",
172
+ "Options:",
173
+ " --output Destination directory. Defaults to .agents/skills/extracted.",
174
+ "",
175
+ ].join("\n"),
176
+ );
177
+ }
178
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemation/agent-skills",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Reusable agent skills for Codemation projects and plugin development.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -14,6 +14,13 @@
14
14
  },
15
15
  "license": "SEE LICENSE IN LICENSE",
16
16
  "type": "module",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./lib/agent-skills-extractor.d.ts",
20
+ "import": "./lib/agent-skills-extractor.mjs",
21
+ "default": "./lib/agent-skills-extractor.mjs"
22
+ }
23
+ },
17
24
  "bin": {
18
25
  "codemation-agent-skills": "./bin/codemation-agent-skills.mjs"
19
26
  },
@@ -34,6 +41,7 @@
34
41
  "README.md",
35
42
  "CHANGELOG.md",
36
43
  "bin",
44
+ "lib",
37
45
  "skills"
38
46
  ],
39
47
  "scripts": {
@@ -31,6 +31,15 @@ credentials: {
31
31
 
32
32
  Then the runtime can supply a typed session through the named slot.
33
33
 
34
+ ## Advanced fields in the credential dialog
35
+
36
+ Optional or power-user fields (for example custom OAuth scopes) can be tucked behind a single collapsible section:
37
+
38
+ - Set `visibility: "advanced"` on each relevant `CredentialFieldSchema` entry in `publicFields` / `secretFields`.
39
+ - Optionally set `advancedSection: { title?, description?, defaultOpen? }` on `CredentialTypeDefinition` to customize the collapsible header (if omitted, the UI still wraps advanced fields in a collapsed section titled **Advanced**).
40
+
41
+ See **`packages/core/docs/credential-ui-fields.md`** in the repository root layout.
42
+
34
43
  ## Health and activation
35
44
 
36
45
  - deploy the workflow and credential type
@@ -18,6 +18,7 @@ Do not use this skill for CLI-only troubleshooting or deep host architecture que
18
18
  2. The fluent authoring chain is the normal starting point for Codemation apps.
19
19
  3. Finish fluent workflow definitions with `.build()`.
20
20
  4. Activations are **batch-shaped** (`Items`); many steps use **per-item** execution (`execute`, including helper **`defineNode`**) with optional **`inputSchema`** and **`itemValue`** on config fields. Batch reshape steps (split/filter/aggregate, **`defineBatchNode`**) work on the whole batch.
21
+ 5. Fluent callback helpers follow the runtime item contract: `.map(...)`, `.if(...)`, and `.switch({ resolveCaseKey })` receive `(item, ctx)`, so row fields live under `item.json` and earlier completed outputs are available through `ctx.data`.
21
22
 
22
23
  ## Authoring rules
23
24
 
@@ -34,6 +35,20 @@ Do not use this skill for CLI-only troubleshooting or deep host architecture que
34
35
  4. Add transformations or nodes in execution order.
35
36
  5. End with `.build()`.
36
37
 
38
+ ## Agent tools (callable helpers)
39
+
40
+ - For **inline** agent tools in workflow files (no separate `@tool()` class), use **`callableTool(...)`** from `@codemation/core`: supply `name`, Zod `inputSchema` / `outputSchema`, and `execute({ input, item, ctx, ... })`. **`CallableToolFactory.callableTool(...)`** is the same implementation if you prefer the factory style.
41
+ - Prefer **plugin `Tool` classes** when the tool is reusable across packages; use **`AgentToolFactory.asTool(...)`** when exposing an existing runnable node to the agent.
42
+
43
+ ## Workflow agent authoring
44
+
45
+ - Use `.agent(...)` for fluent workflow-defined agent steps.
46
+ - Define agent messages with `messages`, not a workflow-specific prompt shortcut.
47
+ - Use a static `messages` array for fixed prompts.
48
+ - Use `itemValue(...)` when agent messages depend on the current item.
49
+ - Use fluent `.map((item, ctx) => ...)` when workflow data itself needs reshaping before the agent step.
50
+ - `model` may be a provider string such as `"openai:gpt-4o-mini"` or a `ChatModelConfig`.
51
+
37
52
  ## Read next when needed
38
53
 
39
54
  - Read `references/builder-patterns.md` for item-flow rules and fluent authoring patterns.
@@ -8,8 +8,8 @@ export default workflow("wf.example.id")
8
8
  .manualTrigger("Start", {
9
9
  step: "start",
10
10
  })
11
- .map("Transform", (item) => ({
12
- ...item,
11
+ .map("Transform", (item, _ctx) => ({
12
+ ...item.json,
13
13
  transformed: true,
14
14
  }))
15
15
  .build();
@@ -27,6 +27,8 @@ export default workflow("wf.example.id")
27
27
  - items usually carry `json` data and optional `binary` data
28
28
  - runtime nodes receive batches of items, not just one record
29
29
  - author workflow steps with batching in mind
30
+ - fluent `.map(...)`, `.if(...)`, and `.switch({ resolveCaseKey })` callbacks receive `(item, ctx)`
31
+ - read row fields from `item.json` and earlier completed outputs from `ctx.data`
30
32
 
31
33
  ## When to move beyond callbacks
32
34
 
@@ -42,3 +44,16 @@ Promote inline callbacks into custom nodes when:
42
44
  - the fluent DSL is the friendly authoring surface
43
45
  - `@codemation/core` still owns planning, execution, continuation, and runtime contracts
44
46
  - host and node packages add the surrounding product capabilities
47
+
48
+ ## Inline callable agent tools
49
+
50
+ - import `callableTool` from `@codemation/core`
51
+ - build tools with `callableTool({ name, inputSchema, outputSchema, execute, credentialRequirements? })` (equivalent to `CallableToolFactory.callableTool(...)`)
52
+ - pass the result in `AIAgent` `tools: [...]` alongside other tool configs
53
+
54
+ ## Fluent agent steps
55
+
56
+ - use `.agent(...)` for agent steps in fluent workflow definitions
57
+ - define agent prompts with `messages`
58
+ - use `itemValue(...)` when message content depends on `item.json`
59
+ - use `outputSchema` when the workflow should expose typed structured agent output