Skip to content

Commit 5ccbff5

Browse files
RoyLinRoyLin
authored andcommitted
fix(node-sdk): remove broken documentParserRegistry from plugin classes
AgenticSearch, AgenticParse, and SkillPlugin were #[napi] class instances but SessionOptions.plugins expected #[napi(object)] plain objects. napi-rs failed to extract Option<JsDocumentParserRegistry> from null (class getter for None), causing "Cannot convert undefined or null to object" at runtime. Fix: simplify plugin classes to marker structs with only `kind: String`. SkillPlugin keeps plugin_name + skills fields. The document_parser_registry field is removed from all plugin types — plain text formats work without it (agentic_parse falls back to fs::read_to_string), and binary format parsers require Rust implementation not currently exposed in the Node.js SDK. Also update DocumentParserRegistry doc to clarify it is reserved for future use, and correct README to remove inaccurate PDF/Word/Excel claims.
1 parent 4cbc396 commit 5ccbff5

4 files changed

Lines changed: 98 additions & 77 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ console.log(result.text);
7676
| Plugin | Tool | What it does |
7777
| --------------- | ---------------- | ---------------------------------------------------------------- |
7878
| `AgenticSearch` | `agentic_search` | Natural-language code search with IDF-weighted relevance ranking |
79-
| `AgenticParse` | `agentic_parse` | LLM-enhanced parsing for PDF, Word, CSV, code, and more |
79+
| `AgenticParse` | `agentic_parse` | LLM-enhanced parsing for Markdown, CSV, JSON, TOML, code, and more |
8080

8181
```python
8282
from a3s_code import Agent, SessionOptions, AgenticSearch, AgenticParse

sdk/node/index.d.ts

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,21 @@ export interface JsSecurityProvider {
7979
export interface JsDocumentParserRegistry {
8080
kind: string
8181
}
82+
/**
83+
* A plugin descriptor passed in `SessionOptions.plugins`.
84+
*
85+
* Use the typed constructors (`new AgenticSearch()`, `new AgenticParse()`,
86+
* `new SkillPlugin(...)`) to create plugin instances — do not construct this
87+
* object directly.
88+
*/
89+
export interface JsPlugin {
90+
/** Plugin kind: `"agentic_search"`, `"agentic_parse"`, or `"skill_plugin"`. */
91+
kind: string
92+
/** Plugin name (used by SkillPlugin). */
93+
pluginName?: string
94+
/** Skill YAML/markdown content strings (used by SkillPlugin). */
95+
skills?: Array<string>
96+
}
8297
/**
8398
* Union type for AHP transport configuration.
8499
* Accepts any of: StdioTransport, HttpTransport, WebSocketTransport, UnixSocketTransport.
@@ -152,15 +167,16 @@ export interface SessionOptions {
152167
*/
153168
securityProvider?: JsSecurityProvider
154169
/**
155-
* Document parser registry for agentic_search tool.
170+
* Plugin tools to mount onto this session.
171+
*
172+
* Pass instances of plugin classes to enable optional tools:
156173
*
157-
* Pass `new DocumentParserRegistry()` to enable custom document format support.
158-
* By default, only plain text files are searched.
159174
* ```js
160-
* agent.session('.', { documentParserRegistry: new DocumentParserRegistry() });
175+
* agent.session('.', { plugins: [new AgenticSearch()] });
176+
* agent.session('.', { plugins: [new AgenticSearch(), new AgenticParse()] });
161177
* ```
162178
*/
163-
documentParserRegistry?: JsDocumentParserRegistry
179+
plugins?: Array<JsPlugin>
164180
/**
165181
* Custom role/identity prepended before the core agentic prompt.
166182
* Example: "You are a senior Python developer specializing in FastAPI."
@@ -651,20 +667,77 @@ export declare class DefaultSecurityProvider {
651667
constructor()
652668
}
653669
/**
654-
* Document parser registry for agentic_search tool.
670+
* Document parser registry (reserved for future use).
655671
*
656-
* Enables custom document format support (PDF, Excel, Word, etc.) for the
657-
* agentic_search tool. By default, only plain text files are searched.
672+
* Currently only plain-text formats (source code, Markdown, JSON, TOML, YAML, CSV, etc.)
673+
* are supported without additional configuration. Binary formats such as PDF, Excel, or
674+
* Word require a custom `DocumentParser` implementation, which is not yet exposed in the
675+
* Node.js SDK.
676+
*/
677+
export declare class DocumentParserRegistry {
678+
kind: string
679+
constructor()
680+
}
681+
/**
682+
* Multi-phase semantic code search plugin.
683+
*
684+
* Mounts the `agentic_search` tool onto the session. Not registered by default.
658685
*
659686
* ```js
660-
* const registry = new DocumentParserRegistry();
661-
* agent.session('.', { documentParserRegistry: registry });
687+
* agent.session('.', {
688+
* plugins: [new AgenticSearch()],
689+
* });
662690
* ```
663691
*/
664-
export declare class DocumentParserRegistry {
692+
export declare class AgenticSearch {
665693
kind: string
666694
constructor()
667695
}
696+
/**
697+
* LLM-enhanced document parsing plugin.
698+
*
699+
* Mounts the `agentic_parse` tool onto the session. Not registered by default.
700+
* Requires an LLM client (automatically provided from the session).
701+
*
702+
* ```js
703+
* agent.session('.', {
704+
* plugins: [new AgenticParse()],
705+
* });
706+
* ```
707+
*/
708+
export declare class AgenticParse {
709+
kind: string
710+
constructor()
711+
}
712+
/**
713+
* Skill-only plugin — injects custom skills into the session's skill registry
714+
* without registering any tools.
715+
*
716+
* Use this to add custom LLM guidance (instructions, tool restrictions,
717+
* prompting strategies) directly from Node.js. For tools, use MCP servers.
718+
*
719+
* ```js
720+
* import { SkillPlugin } from '@a3s-lab/code';
721+
*
722+
* const plugin = new SkillPlugin('my-plugin', [`
723+
* ---
724+
* name: my-skill
725+
* description: Use bash cautiously
726+
* allowed-tools: "bash(*)"
727+
* kind: instruction
728+
* ---
729+
* Always explain what command you're about to run before executing it.
730+
* `]);
731+
*
732+
* agent.session('.', { plugins: [new AgenticSearch(), plugin] });
733+
* ```
734+
*/
735+
export declare class SkillPlugin {
736+
kind: string
737+
pluginName?: string
738+
skills?: Array<string>
739+
constructor(name: string, skills: Array<string>)
740+
}
668741
/**
669742
* Stdio transport for AHP (Agent Harness Protocol).
670743
*

sdk/node/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,14 +310,17 @@ if (!nativeBinding) {
310310
throw new Error(`Failed to load native binding`)
311311
}
312312

313-
const { EventStream, FileMemoryStore, FileSessionStore, MemorySessionStore, DefaultSecurityProvider, DocumentParserRegistry, StdioTransport, HttpTransport, WebSocketTransport, UnixSocketTransport, Agent, Session, builtinSkills, TeamTaskBoard, Team, TeamRunner, SubAgentHandle, Orchestrator } = nativeBinding
313+
const { EventStream, FileMemoryStore, FileSessionStore, MemorySessionStore, DefaultSecurityProvider, DocumentParserRegistry, AgenticSearch, AgenticParse, SkillPlugin, StdioTransport, HttpTransport, WebSocketTransport, UnixSocketTransport, Agent, Session, builtinSkills, TeamTaskBoard, Team, TeamRunner, SubAgentHandle, Orchestrator } = nativeBinding
314314

315315
module.exports.EventStream = EventStream
316316
module.exports.FileMemoryStore = FileMemoryStore
317317
module.exports.FileSessionStore = FileSessionStore
318318
module.exports.MemorySessionStore = MemorySessionStore
319319
module.exports.DefaultSecurityProvider = DefaultSecurityProvider
320320
module.exports.DocumentParserRegistry = DocumentParserRegistry
321+
module.exports.AgenticSearch = AgenticSearch
322+
module.exports.AgenticParse = AgenticParse
323+
module.exports.SkillPlugin = SkillPlugin
321324
module.exports.StdioTransport = StdioTransport
322325
module.exports.HttpTransport = HttpTransport
323326
module.exports.WebSocketTransport = WebSocketTransport

sdk/node/src/lib.rs

Lines changed: 9 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -473,17 +473,12 @@ impl DefaultSecurityProvider {
473473
}
474474
}
475475

476-
/// Document parser registry.
476+
/// Document parser registry (reserved for future use).
477477
///
478-
/// Enables custom document format support (PDF, Excel, Word, etc.) for
479-
/// plugin tools such as `AgenticSearch` and `AgenticParse`.
480-
///
481-
/// ```js
482-
/// const registry = new DocumentParserRegistry();
483-
/// agent.session('.', {
484-
/// plugins: [new AgenticSearch({ documentParserRegistry: registry })],
485-
/// });
486-
/// ```
478+
/// Currently only plain-text formats (source code, Markdown, JSON, TOML, YAML, CSV, etc.)
479+
/// are supported without additional configuration. Binary formats such as PDF, Excel, or
480+
/// Word require a custom `DocumentParser` implementation, which is not yet exposed in the
481+
/// Node.js SDK.
487482
#[napi]
488483
pub struct DocumentParserRegistry {
489484
pub kind: String,
@@ -513,22 +508,12 @@ impl DocumentParserRegistry {
513508
pub struct JsPlugin {
514509
/// Plugin kind: `"agentic_search"`, `"agentic_parse"`, or `"skill_plugin"`.
515510
pub kind: String,
516-
/// Optional document parser registry for this plugin.
517-
pub document_parser_registry: Option<JsDocumentParserRegistry>,
518511
/// Plugin name (used by SkillPlugin).
519512
pub plugin_name: Option<String>,
520513
/// Skill YAML/markdown content strings (used by SkillPlugin).
521514
pub skills: Option<Vec<String>>,
522515
}
523516

524-
/// Options for the AgenticSearch plugin.
525-
#[napi(object)]
526-
#[derive(Clone, Default)]
527-
pub struct AgenticSearchOptions {
528-
/// Pass a `DocumentParserRegistry` to enable PDF, Excel, Word, etc. support.
529-
pub document_parser_registry: Option<JsDocumentParserRegistry>,
530-
}
531-
532517
/// Multi-phase semantic code search plugin.
533518
///
534519
/// Mounts the `agentic_search` tool onto the session. Not registered by default.
@@ -537,38 +522,22 @@ pub struct AgenticSearchOptions {
537522
/// agent.session('.', {
538523
/// plugins: [new AgenticSearch()],
539524
/// });
540-
///
541-
/// // With document parser support:
542-
/// agent.session('.', {
543-
/// plugins: [new AgenticSearch({ documentParserRegistry: new DocumentParserRegistry() })],
544-
/// });
545525
/// ```
546526
#[napi]
547527
pub struct AgenticSearch {
548528
pub kind: String,
549-
pub document_parser_registry: Option<JsDocumentParserRegistry>,
550529
}
551530

552531
#[napi]
553532
impl AgenticSearch {
554533
#[napi(constructor)]
555-
pub fn new(options: Option<AgenticSearchOptions>) -> Self {
556-
let opts = options.unwrap_or_default();
534+
pub fn new() -> Self {
557535
Self {
558536
kind: "agentic_search".to_string(),
559-
document_parser_registry: opts.document_parser_registry,
560537
}
561538
}
562539
}
563540

564-
/// Options for the AgenticParse plugin.
565-
#[napi(object)]
566-
#[derive(Clone, Default)]
567-
pub struct AgenticParseOptions {
568-
/// Pass a `DocumentParserRegistry` to enable PDF, Excel, Word, etc. support.
569-
pub document_parser_registry: Option<JsDocumentParserRegistry>,
570-
}
571-
572541
/// LLM-enhanced document parsing plugin.
573542
///
574543
/// Mounts the `agentic_parse` tool onto the session. Not registered by default.
@@ -578,28 +547,18 @@ pub struct AgenticParseOptions {
578547
/// agent.session('.', {
579548
/// plugins: [new AgenticParse()],
580549
/// });
581-
///
582-
/// // With document parser support:
583-
/// agent.session('.', {
584-
/// plugins: [
585-
/// new AgenticParse({ documentParserRegistry: new DocumentParserRegistry() }),
586-
/// ],
587-
/// });
588550
/// ```
589551
#[napi]
590552
pub struct AgenticParse {
591553
pub kind: String,
592-
pub document_parser_registry: Option<JsDocumentParserRegistry>,
593554
}
594555

595556
#[napi]
596557
impl AgenticParse {
597558
#[napi(constructor)]
598-
pub fn new(options: Option<AgenticParseOptions>) -> Self {
599-
let opts = options.unwrap_or_default();
559+
pub fn new() -> Self {
600560
Self {
601561
kind: "agentic_parse".to_string(),
602-
document_parser_registry: opts.document_parser_registry,
603562
}
604563
}
605564
}
@@ -629,7 +588,6 @@ impl AgenticParse {
629588
#[napi]
630589
pub struct SkillPlugin {
631590
pub kind: String,
632-
pub document_parser_registry: Option<JsDocumentParserRegistry>,
633591
pub plugin_name: Option<String>,
634592
pub skills: Option<Vec<String>>,
635593
}
@@ -640,7 +598,6 @@ impl SkillPlugin {
640598
pub fn new(name: String, skills: Vec<String>) -> Self {
641599
Self {
642600
kind: "skill_plugin".to_string(),
643-
document_parser_registry: None,
644601
plugin_name: Some(name),
645602
skills: Some(skills),
646603
}
@@ -865,16 +822,8 @@ pub struct SessionOptions {
865822
/// Pass instances of plugin classes to enable optional tools:
866823
///
867824
/// ```js
868-
/// // Semantic code search
869825
/// agent.session('.', { plugins: [new AgenticSearch()] });
870-
///
871-
/// // Document parsing with PDF support
872-
/// agent.session('.', {
873-
/// plugins: [
874-
/// new AgenticSearch({ documentParserRegistry: new DocumentParserRegistry() }),
875-
/// new AgenticParse({ documentParserRegistry: new DocumentParserRegistry() }),
876-
/// ],
877-
/// });
826+
/// agent.session('.', { plugins: [new AgenticSearch(), new AgenticParse()] });
878827
/// ```
879828
pub plugins: Option<Vec<JsPlugin>>,
880829
/// Custom role/identity prepended before the core agentic prompt.
@@ -1197,12 +1146,8 @@ fn js_session_options_to_rust(options: Option<SessionOptions>) -> RustSessionOpt
11971146
opts = opts.with_default_security();
11981147
}
11991148
}
1200-
// Mount plugins — also enable document parsing if any plugin requests it
1149+
// Mount plugins
12011150
for plugin in o.plugins.iter().flatten() {
1202-
if plugin.document_parser_registry.is_some() && opts.document_parser_registry.is_none() {
1203-
opts.document_parser_registry =
1204-
Some(std::sync::Arc::new(a3s_code_core::DocumentParserRegistry::new()));
1205-
}
12061151
match plugin.kind.as_str() {
12071152
"agentic_search" | "agentic-search" => {
12081153
opts.plugins.push(std::sync::Arc::new(

0 commit comments

Comments
 (0)