Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ All built-in tools are defined in `src/tools/` and registered as LangChain tools
| ---- | ----------- |
| `clarify` | Send clarification questions to the user with optional numbered choices. Zero permissions — always registered. |
| `compactContext` | Reduce conversation context when LLM context length is exceeded. Tiered retention: retain recent, summarize older, drop oldest. |
| `cronJob` | Manage scheduled cron jobs — create, list, update, pause, resume, run, remove. Persisted to `memory/schedules/`. |
| `cronJob` | Manage scheduled cron jobs — create, list, update, pause, resume, run, remove. Persisted to `memory/schedules/`. Available to the orchestrator agent. |
| `createSkill` | Create a spec-compliant skill directory with SKILL.md YAML frontmatter. Optionally scaffolds a `scripts/` directory. |
| `date` | Return current date/time in ISO 8601 UTC or human-readable format. Zero permissions — always registered. |
| `imageGenerate` | Generate images via FAL.ai flux/klein API. |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-25
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Why

The orchestrator agent needs access to the `cronJob` tool to manage scheduled jobs during active sessions. Currently, `cronJob` is classified only for `security-audit` and `performance` agent types, and it is not included in the `ORCHESTRATOR_TOOLS` array. This means the orchestrator cannot create, list, pause, resume, or remove cron jobs — a gap that prevents self-service scheduling during interactive sessions.

## What Changes

- Add `"cronJob"` to the `ORCHESTRATOR_TOOLS` array in `src/tools/index.js`
- Add `"orchestrator"` to the `cronJob` classification in `TOOL_CLASSIFICATIONS` in `src/tools/index.js`
- Update the README.md Built-in Tools table to document that the orchestrator has access to `cronJob`
- Add unit tests verifying the orchestrator has access to `cronJob`

## Capabilities

### Modified Capabilities

- `orchestrator-tools`: Extended to include `cronJob` tool access
- `tool-classifications`: Extended `cronJob` to include `orchestrator` agent type

## Impact

- **Affected code**: `src/tools/index.js`, `README.md`, `tests/unit/` (new test file)
- **Dependencies**: None — `cronJob` tool already exists and is fully implemented
- **Tests**: New test file `tests/unit/tools_orchestrator.test.js`

## Non-goals

- Adding cronJob access to other agent types beyond orchestrator
- Modifying cronJob tool implementation or permissions
- Adding new cronJob actions or capabilities
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## 1. Update ORCHESTRATOR_TOOLS array

- [x] 1.1 Add "cronJob" to ORCHESTRATOR_TOOLS array in src/tools/index.js (line ~161)
- [x] 1.2 Verify the array remains alphabetically ordered or follows existing convention

## 2. Update TOOL_CLASSIFICATIONS

- [x] 2.1 Add "orchestrator" to the cronJob classification in TOOL_CLASSIFICATIONS (line 81)
- [x] 2.2 Verify the classification array follows existing convention (alphabetical order)

## 3. Update README.md

- [x] 3.1 Update the Built-in Tools table in README.md to show orchestrator has access to cronJob
- [x] 3.2 Verify the table formatting is consistent with existing entries

## 4. Write unit tests

- [x] 4.1 Create tests/unit/tools_orchestrator.test.js
- [x] 4.2 Test that "cronJob" is included in ORCHESTRATOR_TOOLS array
- [x] 4.3 Test that "orchestrator" is included in cronJob's TOOL_CLASSIFICATIONS entry
- [x] 4.4 Test that getToolsForAgentTypes returns cronJob when orchestrator type is queried

## 5. Verify

- [x] 5.1 Run npm run test and verify all tests pass
- [x] 5.2 Run npm run lint and fix any lint errors
- [x] 5.3 Run npm run coverage and verify coverage is maintained
3 changes: 2 additions & 1 deletion src/tools/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const TOOL_CLASSIFICATIONS = {
"coding",
],
compactContext: ["debug", "code-review", "research", "coding"],
cronJob: ["security-audit", "performance"],
cronJob: ["orchestrator", "security-audit", "performance"],
createSkill: ["documentation"],
date: [
"search",
Expand Down Expand Up @@ -148,6 +148,7 @@ export function getToolsForAgentTypes(agentTypes, tools) {
export const ORCHESTRATOR_TOOLS = [
"clarify",
"compactContext",
"cronJob",
"date",
"memory",
"process",
Expand Down
86 changes: 86 additions & 0 deletions tests/unit/tools_orchestrator.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { describe, it } from "node:test";
import { deepStrictEqual, ok } from "node:assert";

import {
ORCHESTRATOR_TOOLS,
TOOL_CLASSIFICATIONS,
getToolsForAgentTypes,
} from "../../src/tools/index.js";

// Import TOOLS dynamically since it depends on runtime config
let TOOLS;
async function loadTools() {
if (!TOOLS) {
const mod = await import("../../src/tools/index.js");
TOOLS = mod.TOOLS;
}
return TOOLS;
}

describe("orchestrator - cronJob access", () => {
it("ORCHESTRATOR_TOOLS should include cronJob", () => {
ok(ORCHESTRATOR_TOOLS.includes("cronJob"), "ORCHESTRATOR_TOOLS should include cronJob");
});

it("ORCHESTRATOR_TOOLS should be an array of strings", () => {
deepStrictEqual(
typeof ORCHESTRATOR_TOOLS,
"object",
"ORCHESTRATOR_TOOLS should be an object (array)",
);
deepStrictEqual(
Array.isArray(ORCHESTRATOR_TOOLS),
true,
"ORCHESTRATOR_TOOLS should be an array",
);
ORCHESTRATOR_TOOLS.forEach((tool) => {
deepStrictEqual(typeof tool, "string", `Each tool should be a string, got ${typeof tool}`);
});
});

it("cronJob should be classified for orchestrator", () => {
ok(TOOL_CLASSIFICATIONS.cronJob, "cronJob should have a TOOL_CLASSIFICATIONS entry");
ok(
TOOL_CLASSIFICATIONS.cronJob.includes("orchestrator"),
"cronJob should include orchestrator in its classifications",
);
});

it("cronJob should retain its existing classifications", () => {
ok(
TOOL_CLASSIFICATIONS.cronJob.includes("security-audit"),
"cronJob should still include security-audit",
);
ok(
TOOL_CLASSIFICATIONS.cronJob.includes("performance"),
"cronJob should still include performance",
);
});

it("getToolsForAgentTypes should return cronJob for orchestrator type", async () => {
const tools = await loadTools();
const toolsForOrchestrator = getToolsForAgentTypes(["orchestrator"], tools);
ok(
toolsForOrchestrator.includes("cronJob"),
"getToolsForAgentTypes(['orchestrator']) should include cronJob",
);
});

it("getToolsForAgentTypes should return cronJob for security-audit type", async () => {
const tools = await loadTools();
const toolsForSecurity = getToolsForAgentTypes(["security-audit"], tools);
ok(
toolsForSecurity.includes("cronJob"),
"getToolsForAgentTypes(['security-audit']) should include cronJob",
);
});

it("getToolsForAgentTypes should return cronJob for performance type", async () => {
const tools = await loadTools();
const toolsForPerformance = getToolsForAgentTypes(["performance"], tools);
ok(
toolsForPerformance.includes("cronJob"),
"getToolsForAgentTypes(['performance']) should include cronJob",
);
});
});