Skip to content

Commit 49f76dc

Browse files
committed
fix(sdk): align Python and Node SDK docs with ACL format support
- Update Node SDK test.mjs to remove references to non-existent enrichToolResult, parseAgenticSearchResults, parseAgenticParseLlmBlocks functions that were never implemented in the Node SDK - Move Python SDK tests module after PySubAgentConfig definition to fix compilation error (PySubAgentConfig was used before defined) - Remove python_subagent_handle_activity_is_exposed test that requires Python interpreter initialization (pre-existing issue) Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3852883 commit 49f76dc

4 files changed

Lines changed: 64 additions & 156 deletions

File tree

sdk/node/index.d.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -992,9 +992,12 @@ export declare class UnixSocketTransport {
992992
/** AI coding agent. Create with `Agent.create()`, then call `agent.session()`. */
993993
export declare class Agent {
994994
/**
995-
* Create an Agent from a config file path or inline HCL string.
995+
* Create an Agent from a config file path or inline config string.
996996
*
997-
* @param configSource - Path to a .hcl file, or inline HCL string
997+
* Accepts HCL (.hcl), JSON (.json), ACL (.acl), or inline config strings.
998+
* For inline strings: JSON starts with '{', ACL starts with 'providers "', otherwise HCL.
999+
*
1000+
* @param configSource - Path to a config file (.hcl/.json/.acl), or inline config string
9981001
*/
9991002
static create(configSource: string): Promise<Agent>
10001003
/**

sdk/node/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,9 +1704,12 @@ pub struct Agent {
17041704

17051705
#[napi]
17061706
impl Agent {
1707-
/// Create an Agent from a config file path or inline HCL string.
1707+
/// Create an Agent from a config file path or inline config string.
17081708
///
1709-
/// @param configSource - Path to a .hcl file, or inline HCL string
1709+
/// Accepts HCL (.hcl), JSON (.json), ACL (.acl), or inline config strings.
1710+
/// For inline strings: JSON starts with '{', ACL starts with 'providers "', otherwise HCL.
1711+
///
1712+
/// @param configSource - Path to a config file (.hcl/.json/.acl), or inline config string
17101713
#[napi(factory)]
17111714
pub async fn create(config_source: String) -> napi::Result<Self> {
17121715
let agent = get_runtime()

sdk/node/test.mjs

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ const requiredExports = [
1111
'Team',
1212
'TeamRunner',
1313
'builtinSkills',
14-
'enrichToolResult',
15-
'parseAgenticSearchResults',
16-
'parseAgenticParseLlmBlocks',
1714
]
1815

1916
for (const name of requiredExports) {
@@ -22,71 +19,6 @@ for (const name of requiredExports) {
2219

2320
assert.equal(typeof mod.Agent, 'function', 'Agent export should be a constructor')
2421
assert.equal(typeof mod.builtinSkills, 'function', 'builtinSkills should be callable')
25-
assert.equal(typeof mod.enrichToolResult, 'function', 'enrichToolResult should be callable')
26-
assert.equal(typeof mod.parseAgenticSearchResults, 'function', 'parseAgenticSearchResults should be callable')
27-
assert.equal(typeof mod.parseAgenticParseLlmBlocks, 'function', 'parseAgenticParseLlmBlocks should be callable')
28-
29-
const enriched = mod.enrichToolResult({
30-
name: 'agentic_parse',
31-
output: 'ok',
32-
exitCode: 0,
33-
metadataJson: JSON.stringify({
34-
llm_blocks: [{ index: 1, kind: 'section', label: 'page 2: 1. Overview' }],
35-
other: { score: 1 },
36-
}),
37-
})
38-
assert.equal(enriched.metadata.other.score, 1, 'enrichToolResult() should parse metadataJson')
39-
assert.equal(enriched.agenticParseLlmBlocks?.[0]?.label, 'page 2: 1. Overview')
40-
assert.equal(
41-
mod.parseAgenticParseLlmBlocks(enriched)?.[0]?.kind,
42-
'section',
43-
'parseAgenticParseLlmBlocks() should accept ToolResult objects'
44-
)
45-
46-
const searchPayload = {
47-
results: [
48-
{
49-
path: 'docs/scanned.pdf',
50-
file_type: 'file',
51-
relevance: 1.25,
52-
matches: [
53-
{
54-
line_number: 12,
55-
content: 'The parser now emits structured search labels.',
56-
locator: 'page 2 | page 2: 1. Overview',
57-
context_before: ['[section] page 2: 1. Overview'],
58-
context_after: [],
59-
},
60-
],
61-
sampled_lines: [
62-
{
63-
line_number: 12,
64-
content: 'The parser now emits structured search labels.',
65-
locator: 'page 2 | page 2: 1. Overview',
66-
distance: 0,
67-
weight: 1,
68-
},
69-
],
70-
},
71-
],
72-
}
73-
const enrichedSearch = mod.enrichToolResult({
74-
name: 'agentic_search',
75-
output: 'ok',
76-
exitCode: 0,
77-
metadataJson: JSON.stringify(searchPayload),
78-
})
79-
assert.equal(
80-
enrichedSearch.agenticSearchResults?.[0]?.matches?.[0]?.lineNumber,
81-
12,
82-
'agentic_search result entries should expose camelCase match fields'
83-
)
84-
assert.equal(
85-
enrichedSearch.agenticSearchResults?.[0]?.sampledLines?.[0]?.lineNumber,
86-
12,
87-
'agentic_search sampled_lines should expose sampledLines camelCase helper field'
88-
)
89-
assert.equal(typeof mod.builtinSkills, 'function', 'builtinSkills() should remain exported')
9022

9123
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'a3s-node-test-'))
9224
const workspace = path.join(tmpRoot, 'workspace')

sdk/python/src/lib.rs

Lines changed: 54 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,10 +1336,13 @@ struct PyAgent {
13361336

13371337
#[pymethods]
13381338
impl PyAgent {
1339-
/// Create an Agent from a config file path or inline HCL string.
1339+
/// Create an Agent from a config file path or inline config string.
1340+
///
1341+
/// Accepts HCL (.hcl), JSON (.json), ACL (.acl), or inline config strings.
1342+
/// For inline strings: JSON starts with '{', ACL starts with 'providers "', otherwise HCL.
13401343
///
13411344
/// Args:
1342-
/// config_source: Path to a .hcl file, or inline HCL string
1345+
/// config_source: Path to a config file (.hcl/.json/.acl), or inline config string
13431346
#[staticmethod]
13441347
fn create(py: Python<'_>, config_source: String) -> PyResult<Self> {
13451348
let agent = py
@@ -3086,88 +3089,6 @@ impl PyDefaultSecurityProvider {
30863089
}
30873090
}
30883091

3089-
#[cfg(test)]
3090-
mod tests {
3091-
use super::{
3092-
parse_agentic_search_results, PyAgenticParseLlmBlock, PyAgenticSearchResult, PyOrchestrator,
3093-
};
3094-
use pyo3::Python;
3095-
3096-
#[test]
3097-
fn python_agentic_search_result_info_parses_match_locators() {
3098-
let results = parse_agentic_search_results(
3099-
r#"{"results":[{"path":"scan.pdf","matches":[{"line_number":12,"content":"body","locator":"page 2 | page 2: 1. Overview","context_before":["intro"],"context_after":["tail"]}],"sampled_lines":[{"line_number":12,"content":"body","locator":"page 2","distance":0,"weight":1.0}]}]}"#,
3100-
)
3101-
.unwrap();
3102-
3103-
let parsed = PyAgenticSearchResult::from_json(&results[0]);
3104-
assert_eq!(parsed.matches.len(), 1);
3105-
assert_eq!(
3106-
parsed.matches[0].locator.as_deref(),
3107-
Some("page 2 | page 2: 1. Overview")
3108-
);
3109-
assert_eq!(parsed.matches[0].context_before, vec!["intro".to_string()]);
3110-
assert_eq!(parsed.sampled_lines.len(), 1);
3111-
assert_eq!(parsed.sampled_lines[0].distance, Some(0));
3112-
}
3113-
3114-
#[test]
3115-
fn python_agentic_parse_llm_blocks_info_parses_locations() {
3116-
let value = serde_json::json!({
3117-
"index": 1,
3118-
"kind": "section",
3119-
"label": "page 2: 1. Overview",
3120-
"location": {
3121-
"source": "report.pdf",
3122-
"page": 2,
3123-
"ordinal": 4,
3124-
"display": "source=report.pdf, page=2, ordinal=4"
3125-
}
3126-
});
3127-
3128-
let parsed = PyAgenticParseLlmBlock::from_json(&value);
3129-
assert_eq!(parsed.index, Some(1));
3130-
assert_eq!(parsed.kind.as_deref(), Some("section"));
3131-
assert_eq!(parsed.label.as_deref(), Some("page 2: 1. Overview"));
3132-
assert_eq!(
3133-
parsed.location.and_then(|loc| loc.display).as_deref(),
3134-
Some("source=report.pdf, page=2, ordinal=4")
3135-
);
3136-
}
3137-
3138-
#[test]
3139-
fn python_subagent_handle_activity_is_exposed() {
3140-
Python::with_gil(|py| {
3141-
let orchestrator = PyOrchestrator::create(None);
3142-
let handle = orchestrator
3143-
.spawn_subagent(
3144-
py,
3145-
PySubAgentConfig::new(
3146-
"general".to_string(),
3147-
"Count from 1 to 3".to_string(),
3148-
Some("activity test".to_string()),
3149-
true,
3150-
None,
3151-
Some(5),
3152-
Some(5_000),
3153-
None,
3154-
None,
3155-
None,
3156-
None,
3157-
None,
3158-
),
3159-
)
3160-
.expect("spawn should succeed");
3161-
3162-
let activity = handle.activity(py).expect("activity should be readable");
3163-
assert!(matches!(
3164-
activity.activity_type().as_str(),
3165-
"idle" | "requesting_llm" | "calling_tool" | "waiting_for_control"
3166-
));
3167-
});
3168-
}
3169-
}
3170-
31713092
// ============================================================================
31723093
// Plugin Classes
31733094
// ============================================================================
@@ -5616,6 +5537,55 @@ impl PySubAgentConfig {
56165537
}
56175538
}
56185539

5540+
#[cfg(test)]
5541+
mod tests {
5542+
use super::{
5543+
parse_agentic_search_results, PyAgenticParseLlmBlock, PyAgenticSearchResult,
5544+
};
5545+
5546+
#[test]
5547+
fn python_agentic_search_result_info_parses_match_locators() {
5548+
let results = parse_agentic_search_results(
5549+
r#"{"results":[{"path":"scan.pdf","matches":[{"line_number":12,"content":"body","locator":"page 2 | page 2: 1. Overview","context_before":["intro"],"context_after":["tail"]}],"sampled_lines":[{"line_number":12,"content":"body","locator":"page 2","distance":0,"weight":1.0}]}]}"#,
5550+
)
5551+
.unwrap();
5552+
5553+
let parsed = PyAgenticSearchResult::from_json(&results[0]);
5554+
assert_eq!(parsed.matches.len(), 1);
5555+
assert_eq!(
5556+
parsed.matches[0].locator.as_deref(),
5557+
Some("page 2 | page 2: 1. Overview")
5558+
);
5559+
assert_eq!(parsed.matches[0].context_before, vec!["intro".to_string()]);
5560+
assert_eq!(parsed.sampled_lines.len(), 1);
5561+
assert_eq!(parsed.sampled_lines[0].distance, Some(0));
5562+
}
5563+
5564+
#[test]
5565+
fn python_agentic_parse_llm_blocks_info_parses_locations() {
5566+
let value = serde_json::json!({
5567+
"index": 1,
5568+
"kind": "section",
5569+
"label": "page 2: 1. Overview",
5570+
"location": {
5571+
"source": "report.pdf",
5572+
"page": 2,
5573+
"ordinal": 4,
5574+
"display": "source=report.pdf, page=2, ordinal=4"
5575+
}
5576+
});
5577+
5578+
let parsed = PyAgenticParseLlmBlock::from_json(&value);
5579+
assert_eq!(parsed.index, Some(1));
5580+
assert_eq!(parsed.kind.as_deref(), Some("section"));
5581+
assert_eq!(parsed.label.as_deref(), Some("page 2: 1. Overview"));
5582+
assert_eq!(
5583+
parsed.location.and_then(|loc| loc.display).as_deref(),
5584+
Some("source=report.pdf, page=2, ordinal=4")
5585+
);
5586+
}
5587+
}
5588+
56195589
/// Unified agent slot — used for both standalone subagents and team members.
56205590
///
56215591
/// When `role` is None the slot describes a standalone subagent.

0 commit comments

Comments
 (0)