Skip to content

Add unit tests for agent-invoker module#260

Closed
nikolasdehor wants to merge 1 commit intoSynkraAI:mainfrom
nikolasdehor:test/agent-invoker-coverage
Closed

Add unit tests for agent-invoker module#260
nikolasdehor wants to merge 1 commit intoSynkraAI:mainfrom
nikolasdehor:test/agent-invoker-coverage

Conversation

@nikolasdehor
Copy link
Contributor

@nikolasdehor nikolasdehor commented Feb 18, 2026

Summary

  • Add 47 unit tests for the agent-invoker orchestration module
  • Cover agent loading, task execution, retry logic, output validation, and audit logging
  • Properly mock fs-extra and js-yaml dependencies

Test Coverage

Area Tests Key Scenarios
Constants 3 Agents, fields, statuses
constructor 5 Defaults, custom options
invokeAgent 9 Success/failure, events, executor
_loadAgent 4 Known/unknown, file loading
_parseTaskMetadata 4 Frontmatter, headings
_isTransientError 6 Transient vs permanent errors
_validateTaskOutput 5 Schema validation
Agent queries 3 Support checks
Invocation audit 7 History, filtering, summary
Total 47

Test plan

  • All 47 tests pass
  • fs-extra and js-yaml properly mocked
  • EventEmitter events tested

Summary by CodeRabbit

  • Tests
    • Added comprehensive unit test suite covering agent invocation workflows, task loading, metadata parsing, error handling, and output validation.
    • Validates constructor behavior, state management, history tracking, and audit capabilities across success and failure scenarios.

Closes #301

Copilot AI review requested due to automatic review settings February 18, 2026 19:52
@vercel
Copy link

vercel bot commented Feb 18, 2026

@nikolasdehor is attempting to deploy a commit to the Pedro Valério Lopez's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

Walkthrough

A comprehensive test suite is added for the AgentInvoker module, verifying constructor behavior, agent and task invocation workflows, internal methods for agent loading and metadata parsing, error handling, output validation, agent discovery, and audit trail functionality.

Changes

Cohort / File(s) Summary
Test Suite for AgentInvoker Module
tests/core/orchestration/agent-invoker.test.js
Comprehensive unit tests covering constructor defaults and option overrides, invokeAgent flow including success/failure paths and event emission, internal methods (_loadAgent, _parseTaskMetadata, _buildContext, _isTransientError, _validateTaskOutput), agent queries with various identifier formats, and audit functionalities (invocation history, filtering, summary statistics, log retrieval).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #259: Addresses comprehensive unit test coverage for the AgentInvoker module with identical test scenarios and assertions.

Suggested labels

core, agents, tests

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add unit tests for agent-invoker module' directly and clearly summarizes the primary change: adding a comprehensive test suite for the AgentInvoker module.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated unit test suite for the .aios-core/core/orchestration/agent-invoker module to validate core orchestration behaviors (agent/task loading, metadata parsing, output validation, and invocation audit helpers).

Changes:

  • Add AgentInvoker unit tests covering constants, constructor defaults, invokeAgent happy/failure paths, and internal helpers.
  • Mock fs-extra and js-yaml to avoid filesystem/YAML parsing dependencies during unit tests.
  • Add tests for audit/history query helpers (getInvocations*, getInvocationSummary, getLogs, clearInvocations).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +6
/**
* Unit tests for agent-invoker module
*
* Tests the AgentInvoker class that provides an interface to invoke
* agents for tasks during orchestration, with retry logic and audit logging.
*/
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file header says these tests cover “retry logic”, but this test suite doesn’t currently exercise retry behavior (e.g., _executeWithRetry retry count/backoff or invocation.retries updates) or timeout behavior (_executeWithTimeout). Either add targeted tests for these behaviors or adjust the header comment/PR description to match what’s actually covered.

Copilot uses AI. Check for mistakes.

test('strips @ prefix from agent name', async () => {
const result = await invoker.invokeAgent('@dev', 'my-task');
expect(result.success).toBe(true);
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test name says it “strips @ prefix”, but the assertion only checks success. Either rename it to reflect the behavior being tested (e.g., that @dev is accepted) or assert on a concrete normalized outcome (such as the returned/recorded agent name) if that’s the intended contract.

Suggested change
expect(result.success).toBe(true);
expect(result.success).toBe(true);
expect(result.agentName).toBe('dev');

Copilot uses AI. Check for mistakes.
Comment on lines +129 to +134
fs.pathExists.mockResolvedValue(false);

const result = await invoker.invokeAgent('dev', 'nonexistent-task');

// Agent also not found since pathExists returns false
expect(result.success).toBe(false);
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setup here makes fs.pathExists return false for both the agent file and the task file, so this test doesn’t isolate the “task not found” case. Also, the inline comment “Agent also not found…” is inaccurate because _loadAgent('dev') returns a supported agent config even when the file is missing. Consider using mockResolvedValueOnce(...) to make the agent path exist and the task path not exist, and assert that the error contains “Task not found”.

Suggested change
fs.pathExists.mockResolvedValue(false);
const result = await invoker.invokeAgent('dev', 'nonexistent-task');
// Agent also not found since pathExists returns false
expect(result.success).toBe(false);
fs.pathExists
.mockResolvedValueOnce(true) // agent path exists
.mockResolvedValueOnce(false); // task path does not exist
const result = await invoker.invokeAgent('dev', 'nonexistent-task');
expect(result.success).toBe(false);
expect(result.error).toContain('Task not found');

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/core/orchestration/agent-invoker.test.js (2)

157-165: Consider asserting on the event payload for consistency.

The invocationComplete test (line 151) verifies the payload shape (agentName, status), but invocationFailed only checks toHaveBeenCalled(). Adding a similar objectContaining assertion here would strengthen the test and keep the event-test pattern consistent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/orchestration/agent-invoker.test.js` around lines 157 - 165, The
test for 'emits invocationFailed on failure' only checks that the handler was
called; update it to assert the event payload shape like the
'invocationComplete' test by verifying the handler was called with an object
containing at least agentName and status (e.g. agentName === 'unknown-agent' and
a failure status), using Jest's objectContaining matcher against the mock
handler used in the test (handler) after invoking
invoker.invokeAgent('unknown-agent', 'task').

433-440: Minor: indirect assertion in getLogs returns copy test.

Line 439 asserts invoker.logs.length < logs.length, which only proves the pushed fake entry didn't propagate. A more explicit assertion would capture the original length before mutation and compare against it, making the test intent clearer at a glance:

Suggested improvement
     test('getLogs returns copy', async () => {
       await invoker.invokeAgent('dev', 'task');
 
       const logs = invoker.getLogs();
+      const originalLength = logs.length;
       logs.push({ fake: true });
 
-      expect(invoker.logs.length).toBeLessThan(logs.length);
+      expect(invoker.logs).toHaveLength(originalLength);
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/orchestration/agent-invoker.test.js` around lines 433 - 440, In
the "getLogs returns copy" test, make the assertion explicit by storing the
original length from invoker.getLogs() (or invoker.logs) before mutating the
returned array and then asserting that invoker.logs.length equals that original
length after pushing the fake entry; i.e., call
invoker.invokeAgent('dev','task'), const originalLength = invoker.logs.length
(or const logs = invoker.getLogs(); const originalLength = logs.length), mutate
the returned logs, and assert invoker.logs.length === originalLength to prove
getLogs returned a copy rather than using an indirect length comparison.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/core/orchestration/agent-invoker.test.js`:
- Around line 128-135: The test "returns failure when task not found" currently
mocks fs.pathExists globally to false which triggers the Unknown agent path in
_loadAgent; change the mock to isolate the case by using
fs.pathExists.mockResolvedValueOnce(true) for the agent file existence check and
then fs.pathExists.mockResolvedValueOnce(false) (or mockResolvedValue(false)
after the first call) for the task file check so that invoker.invokeAgent('dev',
'nonexistent-task') exercises the valid-agent + missing-task path and asserts
result.success is false.

---

Nitpick comments:
In `@tests/core/orchestration/agent-invoker.test.js`:
- Around line 157-165: The test for 'emits invocationFailed on failure' only
checks that the handler was called; update it to assert the event payload shape
like the 'invocationComplete' test by verifying the handler was called with an
object containing at least agentName and status (e.g. agentName ===
'unknown-agent' and a failure status), using Jest's objectContaining matcher
against the mock handler used in the test (handler) after invoking
invoker.invokeAgent('unknown-agent', 'task').
- Around line 433-440: In the "getLogs returns copy" test, make the assertion
explicit by storing the original length from invoker.getLogs() (or invoker.logs)
before mutating the returned array and then asserting that invoker.logs.length
equals that original length after pushing the fake entry; i.e., call
invoker.invokeAgent('dev','task'), const originalLength = invoker.logs.length
(or const logs = invoker.getLogs(); const originalLength = logs.length), mutate
the returned logs, and assert invoker.logs.length === originalLength to prove
getLogs returned a copy rather than using an indirect length comparison.

Comment on lines +128 to +135
test('returns failure when task not found', async () => {
fs.pathExists.mockResolvedValue(false);

const result = await invoker.invokeAgent('dev', 'nonexistent-task');

// Agent also not found since pathExists returns false
expect(result.success).toBe(false);
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

fd "agent-invoker.js" --type f

Repository: SynkraAI/aios-core

Length of output: 44


🏁 Script executed:

git ls-files | grep -E "agent-invoker|orchestration" | head -20

Repository: SynkraAI/aios-core

Length of output: 1139


🏁 Script executed:

cat -n ".aios-core/core/orchestration/agent-invoker.js"

Repository: SynkraAI/aios-core

Length of output: 19915


🏁 Script executed:

sed -n '120,140p' tests/core/orchestration/agent-invoker.test.js

Repository: SynkraAI/aios-core

Length of output: 747


Test doesn't properly isolate the "task not found" scenario.

With fs.pathExists.mockResolvedValue(false) applied globally, the agent file check fails first (at _loadAgent line 230), causing the method to throw "Unknown agent" before ever reaching the task file lookup. This test actually exercises the "unknown agent" path rather than testing the specific case where a valid agent exists but the task file is missing.

Consider mocking pathExists to return true for the agent file check and false for the task file check using mockResolvedValueOnce:

Suggested fix
     test('returns failure when task not found', async () => {
-      fs.pathExists.mockResolvedValue(false);
+      fs.pathExists
+        .mockResolvedValueOnce(true)   // agent file check passes
+        .mockResolvedValueOnce(false); // task file check fails
       
       const result = await invoker.invokeAgent('dev', 'nonexistent-task');
       
-      // Agent also not found since pathExists returns false
       expect(result.success).toBe(false);
+      expect(result.error).toContain('Task not found');
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/orchestration/agent-invoker.test.js` around lines 128 - 135, The
test "returns failure when task not found" currently mocks fs.pathExists
globally to false which triggers the Unknown agent path in _loadAgent; change
the mock to isolate the case by using fs.pathExists.mockResolvedValueOnce(true)
for the agent file existence check and then
fs.pathExists.mockResolvedValueOnce(false) (or mockResolvedValue(false) after
the first call) for the task file check so that invoker.invokeAgent('dev',
'nonexistent-task') exercises the valid-agent + missing-task path and asserts
result.success is false.

@nikolasdehor
Copy link
Contributor Author

Consolidated into #426

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add unit tests for agent-invoker module

2 participants