Skip to content

Commit 24cd0a9

Browse files
committed
test(sdk): add integration tests for ConfirmationInheritance in Python and Node SDKs
Adds integration tests that verify the new confirmation_inheritance field is properly exposed and functional in both Python and Node SDKs. Tests verify: 1. WorkerAgentSpec accepts confirmation_inheritance field 2. AgentDefinition returns confirmation_inheritance value 3. Worker registration preserves the field through Rust conversion 4. Optional: Real LLM task delegation (enabled via A3S_CODE_SDK_REAL_AGENT_SMOKE=1) Test files: - sdk/node/test_confirmation_inheritance.mjs: Node SDK integration test - sdk/python/test_confirmation_inheritance.py: Python SDK integration test - sdk/node/run_sdk_integration_tests.sh: Unified test runner script The tests use .a3s/config.acl for LLM configuration via A3S_CONFIG_FILE environment variable, ensuring no API keys are hardcoded. Run: cd sdk/node && ./run_sdk_integration_tests.sh Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 21876ec commit 24cd0a9

3 files changed

Lines changed: 262 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env bash
2+
# Integration test runner for SDK confirmation_inheritance feature
3+
# Reads LLM config from .a3s/config.acl and runs tests for both SDKs
4+
5+
set -euo pipefail
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
9+
CONFIG_FILE="$PROJECT_ROOT/.a3s/config.acl"
10+
11+
if [[ ! -f "$CONFIG_FILE" ]]; then
12+
echo "ERROR: Config file not found: $CONFIG_FILE"
13+
exit 1
14+
fi
15+
16+
echo "==================================================================="
17+
echo "SDK Integration Test: ConfirmationInheritance"
18+
echo "==================================================================="
19+
echo "Config: $CONFIG_FILE"
20+
echo ""
21+
22+
# Export config file path (no secrets here)
23+
export A3S_CONFIG_FILE="$CONFIG_FILE"
24+
25+
# Control test behavior
26+
export A3S_CODE_SDK_REAL_AGENT_SMOKE="${A3S_CODE_SDK_REAL_AGENT_SMOKE:-0}"
27+
export A3S_CODE_SDK_REAL_TIMEOUT_MS="${A3S_CODE_SDK_REAL_TIMEOUT_MS:-180000}"
28+
29+
echo "Test mode: A3S_CODE_SDK_REAL_AGENT_SMOKE=$A3S_CODE_SDK_REAL_AGENT_SMOKE"
30+
echo " (Set to 1 to enable real LLM calls)"
31+
echo ""
32+
33+
# Test 1: Node SDK
34+
echo "-------------------------------------------------------------------"
35+
echo "Test 1: Node SDK"
36+
echo "-------------------------------------------------------------------"
37+
cd "$SCRIPT_DIR"
38+
if [[ ! -f "index.js" ]]; then
39+
echo "ERROR: Node SDK not built. Run: npm run build:debug"
40+
exit 1
41+
fi
42+
43+
node test_confirmation_inheritance.mjs
44+
echo ""
45+
46+
# Test 2: Python SDK
47+
echo "-------------------------------------------------------------------"
48+
echo "Test 2: Python SDK"
49+
echo "-------------------------------------------------------------------"
50+
cd "$PROJECT_ROOT/crates/code/sdk/python"
51+
52+
# Check if Python module is built
53+
PYTHON_BIN="python3"
54+
if [[ -f ".venv/bin/python3" ]]; then
55+
PYTHON_BIN=".venv/bin/python3"
56+
echo "Using Python from venv: $PYTHON_BIN"
57+
fi
58+
59+
if ! $PYTHON_BIN -c "import a3s_code" 2>/dev/null; then
60+
echo "WARNING: Python SDK not built. Building with maturin develop..."
61+
if ! command -v maturin &> /dev/null; then
62+
echo "ERROR: maturin not found. Install with: pip install maturin"
63+
exit 1
64+
fi
65+
maturin develop --quiet
66+
fi
67+
68+
$PYTHON_BIN test_confirmation_inheritance.py
69+
echo ""
70+
71+
echo "==================================================================="
72+
echo "All SDK integration tests passed ✓"
73+
echo "==================================================================="
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Integration test for ConfirmationInheritance in Node SDK.
3+
*
4+
* Tests that the new confirmation_inheritance field is properly exposed
5+
* and works end-to-end with real LLM calls.
6+
*
7+
* Requires: A3S_CONFIG_FILE environment variable pointing to config.acl
8+
*/
9+
10+
import assert from 'node:assert/strict';
11+
import { mkdtempSync, writeFileSync } from 'node:fs';
12+
import { tmpdir } from 'node:os';
13+
import { join, dirname } from 'node:path';
14+
import { fileURLToPath } from 'node:url';
15+
16+
const __dirname = dirname(fileURLToPath(import.meta.url));
17+
const { Agent } = await import(join(__dirname, 'index.js'));
18+
19+
const configFile = process.env.A3S_CONFIG_FILE;
20+
if (!configFile) {
21+
throw new Error('A3S_CONFIG_FILE must point to the ACL config');
22+
}
23+
24+
console.log('[node-sdk-confirmation] Starting integration test...');
25+
console.log(`[node-sdk-confirmation] Config: ${configFile}`);
26+
27+
const agent = await Agent.create(configFile);
28+
const workspace = mkdtempSync(join(tmpdir(), 'a3s-node-confirmation-'));
29+
console.log(`[node-sdk-confirmation] Workspace: ${workspace}`);
30+
31+
// Test 1: WorkerAgentSpec with confirmation_inheritance field
32+
console.log('[node-sdk-confirmation] Test 1: Create WorkerAgentSpec with confirmation_inheritance');
33+
const workerSpec = {
34+
name: 'test-writer',
35+
description: 'Test worker with auto-approve confirmation',
36+
kind: 'implementer',
37+
confirmationInheritance: 'auto_approve',
38+
permissions: {
39+
rules: ['allow(write(*))'],
40+
defaultDecision: 'ask',
41+
enabled: true,
42+
},
43+
maxSteps: 3,
44+
};
45+
46+
const session = agent.session(workspace, {
47+
planningMode: 'disabled',
48+
permissionPolicy: { defaultDecision: 'allow' },
49+
workerAgents: [workerSpec],
50+
});
51+
52+
// Test 2: Verify worker was registered
53+
console.log('[node-sdk-confirmation] Test 2: Verify worker registration');
54+
const toolNames = await session.toolNames();
55+
assert.ok(toolNames.includes('task'), 'task tool should be registered');
56+
57+
// Test 3: Register another worker and check AgentDefinition
58+
console.log('[node-sdk-confirmation] Test 3: Register worker and check AgentDefinition');
59+
const workerSpec2 = {
60+
name: 'test-reader',
61+
description: 'Test worker with deny-on-ask confirmation',
62+
kind: 'read_only',
63+
confirmationInheritance: 'deny_on_ask',
64+
maxSteps: 2,
65+
};
66+
67+
const agentDef = await session.registerWorkerAgent(workerSpec2);
68+
assert.equal(agentDef.name, 'test-reader');
69+
assert.equal(agentDef.confirmationInheritance, 'deny_on_ask');
70+
console.log(`[node-sdk-confirmation] AgentDefinition.confirmationInheritance: ${agentDef.confirmationInheritance}`);
71+
72+
// Test 4: Real LLM task delegation with confirmation_inheritance
73+
if (process.env.A3S_CODE_SDK_REAL_AGENT_SMOKE !== '0') {
74+
console.log('[node-sdk-confirmation] Test 4: Real LLM task delegation');
75+
76+
// Create a test file for the worker to read
77+
const testFile = join(workspace, 'test.txt');
78+
writeFileSync(testFile, 'CONFIRMATION_TEST_CONTENT');
79+
80+
const taskResult = await session.task({
81+
agent: 'test-reader',
82+
description: 'Read test file',
83+
prompt: 'Read the file test.txt and reply with its content',
84+
maxSteps: 2,
85+
});
86+
87+
assert.equal(taskResult.exitCode, 0, `Task should succeed: ${taskResult.output}`);
88+
assert.ok(
89+
taskResult.output.includes('CONFIRMATION_TEST_CONTENT') ||
90+
taskResult.output.includes('test.txt'),
91+
'Task output should reference the test file'
92+
);
93+
console.log('[node-sdk-confirmation] Task delegation successful');
94+
} else {
95+
console.log('[node-sdk-confirmation] Test 4: Skipped (set A3S_CODE_SDK_REAL_AGENT_SMOKE=1 to enable)');
96+
}
97+
98+
console.log('[node-sdk-confirmation] All tests passed ✓');
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
Integration test for ConfirmationInheritance in Python SDK.
3+
4+
Tests that the new confirmation_inheritance field is properly exposed
5+
and works end-to-end with real LLM calls.
6+
7+
Requires: A3S_CONFIG_FILE environment variable pointing to config.acl
8+
"""
9+
10+
import os
11+
import sys
12+
import tempfile
13+
from pathlib import Path
14+
15+
# Import from the built native module
16+
try:
17+
from a3s_code import Agent, WorkerAgentSpec, SessionOptions, PermissionPolicy
18+
except ImportError:
19+
print("ERROR: a3s_code module not found. Build with: cd sdk/python && maturin develop")
20+
sys.exit(1)
21+
22+
config_file = os.environ.get('A3S_CONFIG_FILE')
23+
if not config_file:
24+
print("ERROR: A3S_CONFIG_FILE must point to the ACL config")
25+
sys.exit(1)
26+
27+
print('[python-sdk-confirmation] Starting integration test...')
28+
print(f'[python-sdk-confirmation] Config: {config_file}')
29+
30+
# Read config file content
31+
with open(config_file, 'r') as f:
32+
config_content = f.read()
33+
34+
agent = Agent.create(config_content)
35+
workspace = tempfile.mkdtemp(prefix='a3s-python-confirmation-')
36+
print(f'[python-sdk-confirmation] Workspace: {workspace}')
37+
38+
# Test 1: WorkerAgentSpec with confirmation_inheritance field
39+
print('[python-sdk-confirmation] Test 1: Create WorkerAgentSpec with confirmation_inheritance')
40+
worker_spec = WorkerAgentSpec('test-writer', 'Test worker with auto-approve confirmation', 'implementer')
41+
worker_spec.confirmation_inheritance = 'auto_approve'
42+
worker_spec.max_steps = 3
43+
44+
# Create SessionOptions properly
45+
policy = PermissionPolicy(default_decision='allow')
46+
opts = SessionOptions()
47+
opts.permission_policy = policy
48+
opts.worker_agents = [worker_spec]
49+
50+
session = agent.session(workspace, opts)
51+
52+
# Test 2: Verify worker was registered
53+
print('[python-sdk-confirmation] Test 2: Verify worker registration')
54+
tool_names = session.tool_names()
55+
assert 'task' in tool_names, 'task tool should be registered'
56+
57+
# Test 3: Register another worker and check AgentDefinition
58+
print('[python-sdk-confirmation] Test 3: Register worker and check AgentDefinition')
59+
worker_spec2 = WorkerAgentSpec('test-reader', 'Test worker with deny-on-ask confirmation', 'read_only')
60+
worker_spec2.confirmation_inheritance = 'deny_on_ask'
61+
worker_spec2.max_steps = 2
62+
63+
agent_def = session.register_worker_agent(worker_spec2)
64+
assert agent_def.name == 'test-reader'
65+
assert agent_def.confirmation_inheritance == 'deny_on_ask'
66+
print(f'[python-sdk-confirmation] AgentDefinition.confirmation_inheritance: {agent_def.confirmation_inheritance}')
67+
68+
# Test 4: Real LLM task delegation with confirmation_inheritance
69+
if os.environ.get('A3S_CODE_SDK_REAL_AGENT_SMOKE') != '0':
70+
print('[python-sdk-confirmation] Test 4: Real LLM task delegation')
71+
72+
# Create a test file for the worker to read
73+
test_file = Path(workspace) / 'test.txt'
74+
test_file.write_text('CONFIRMATION_TEST_CONTENT')
75+
76+
task_result = session.task({
77+
'agent': 'test-reader',
78+
'description': 'Read test file',
79+
'prompt': 'Read the file test.txt and reply with its content',
80+
'max_steps': 2,
81+
})
82+
83+
assert task_result['exit_code'] == 0, f"Task should succeed: {task_result['output']}"
84+
output = task_result['output']
85+
assert 'CONFIRMATION_TEST_CONTENT' in output or 'test.txt' in output, \
86+
'Task output should reference the test file'
87+
print('[python-sdk-confirmation] Task delegation successful')
88+
else:
89+
print('[python-sdk-confirmation] Test 4: Skipped (set A3S_CODE_SDK_REAL_AGENT_SMOKE=1 to enable)')
90+
91+
print('[python-sdk-confirmation] All tests passed ✓')

0 commit comments

Comments
 (0)