@@ -6,7 +6,6 @@ import path from 'path';
66import { TextCommunicationProtocol , TextCallTemplate } from "@utcp/text" ;
77import "@utcp/http" ; // Needed for OpenAPI conversion
88import { IUtcpClient } from "@utcp/sdk" ;
9- import { CallTemplateBase } from "@utcp/sdk" ;
109
1110const tempFiles : string [ ] = [ ] ;
1211const mockClient = { } as IUtcpClient ;
@@ -121,43 +120,137 @@ describe("TextCommunicationProtocol", () => {
121120 expect ( result . errors . length ) . toBeGreaterThan ( 0 ) ;
122121 expect ( result . errors [ 0 ] ) . toMatch ( / J S O N / i) ;
123122 } ) ;
123+
124+ test ( "should load a UTCP manual from direct JSON content" , async ( ) => {
125+ const callTemplate : TextCallTemplate = {
126+ name : "direct_content_manual" ,
127+ call_template_type : 'text' ,
128+ content : JSON . stringify ( sampleUtcpManual )
129+ } ;
130+
131+ const result = await protocol . registerManual ( mockClient , callTemplate ) ;
132+
133+ expect ( result . success ) . toBe ( true ) ;
134+ expect ( result . errors ) . toEqual ( [ ] ) ;
135+ expect ( result . manual . tools ) . toHaveLength ( 1 ) ;
136+ expect ( result . manual . tools [ 0 ] ?. name ) . toBe ( "test.tool" ) ;
137+ } ) ;
138+
139+ test ( "should load and convert an OpenAPI spec from direct YAML content" , async ( ) => {
140+ const yaml = await import ( "js-yaml" ) ;
141+ const yamlContent = yaml . dump ( sampleOpenApiSpec ) ;
142+ const callTemplate : TextCallTemplate = {
143+ name : "direct_openapi_manual" ,
144+ call_template_type : 'text' ,
145+ content : yamlContent
146+ } ;
147+
148+ const result = await protocol . registerManual ( mockClient , callTemplate ) ;
149+
150+ expect ( result . success ) . toBe ( true ) ;
151+ expect ( result . manual . tools ) . toHaveLength ( 1 ) ;
152+ expect ( result . manual . tools [ 0 ] ?. name ) . toBe ( "getTest" ) ;
153+ } ) ;
154+
155+ test ( "should prefer content over file_path when both are provided" , async ( ) => {
156+ const filePath = await createTempFile ( "unused.json" , JSON . stringify ( { tools : [ ] } ) ) ;
157+ const callTemplate : TextCallTemplate = {
158+ name : "content_precedence_manual" ,
159+ call_template_type : 'text' ,
160+ file_path : filePath ,
161+ content : JSON . stringify ( sampleUtcpManual )
162+ } ;
163+
164+ const result = await protocol . registerManual ( mockClient , callTemplate ) ;
165+
166+ expect ( result . success ) . toBe ( true ) ;
167+ expect ( result . manual . tools ) . toHaveLength ( 1 ) ;
168+ expect ( result . manual . tools [ 0 ] ?. name ) . toBe ( "test.tool" ) ;
169+ } ) ;
170+
171+ test ( "should fail validation when neither file_path nor content is provided" , async ( ) => {
172+ const callTemplate = {
173+ name : "invalid_manual" ,
174+ call_template_type : 'text'
175+ } ;
176+
177+ const action = async ( ) => await protocol . registerManual ( mockClient , callTemplate ) ;
178+ await expect ( action ( ) ) . rejects . toThrow ( / E i t h e r f i l e _ p a t h o r c o n t e n t m u s t b e p r o v i d e d / ) ;
179+ } ) ;
124180 } ) ;
125181
126182 describe ( "callTool" , ( ) => {
127183 test ( "should return the raw content of the specified file" , async ( ) => {
128184 const fileContent = "This is the raw content of the file." ;
129185 const filePath = await createTempFile ( "content.txt" , fileContent ) ;
130- const callTemplate : CallTemplateBase = {
186+ const callTemplate : TextCallTemplate = {
131187 name : "file_content_tool" ,
132188 call_template_type : 'text' ,
133189 file_path : filePath
134- } as TextCallTemplate ;
190+ } ;
135191
136192 const result = await protocol . callTool ( mockClient , "any.tool" , { } , callTemplate ) ;
137193 expect ( result ) . toBe ( fileContent ) ;
138194 } ) ;
139195
140196 test ( "should throw an error if the file does not exist" , async ( ) => {
141- const callTemplate : CallTemplateBase = {
197+ const callTemplate : TextCallTemplate = {
142198 name : "nonexistent_file_tool" ,
143199 call_template_type : 'text' ,
144200 file_path : "/path/to/nonexistent/file.txt"
145- } as TextCallTemplate ;
201+ } ;
146202
147203 const action = async ( ) => await protocol . callTool ( mockClient , "any.tool" , { } , callTemplate ) ;
148204 await expect ( action ( ) ) . rejects . toThrow ( / n o s u c h f i l e o r d i r e c t o r y / ) ;
149205 } ) ;
206+
207+ test ( "should return direct content when content is provided" , async ( ) => {
208+ const directContent = "This is direct content." ;
209+ const callTemplate : TextCallTemplate = {
210+ name : "direct_content_tool" ,
211+ call_template_type : 'text' ,
212+ content : directContent
213+ } ;
214+
215+ const result = await protocol . callTool ( mockClient , "any.tool" , { } , callTemplate ) ;
216+ expect ( result ) . toBe ( directContent ) ;
217+ } ) ;
218+
219+ test ( "should prefer content over file_path when both are provided" , async ( ) => {
220+ const fileContent = "File content." ;
221+ const directContent = "Direct content wins." ;
222+ const filePath = await createTempFile ( "ignored.txt" , fileContent ) ;
223+ const callTemplate : TextCallTemplate = {
224+ name : "precedence_tool" ,
225+ call_template_type : 'text' ,
226+ file_path : filePath ,
227+ content : directContent
228+ } ;
229+
230+ const result = await protocol . callTool ( mockClient , "any.tool" , { } , callTemplate ) ;
231+ expect ( result ) . toBe ( directContent ) ;
232+ } ) ;
233+
234+ test ( "should throw an error when neither file_path nor content is provided" , async ( ) => {
235+ const callTemplate = {
236+ name : "invalid_tool" ,
237+ call_template_type : 'text'
238+ } ;
239+
240+ const action = async ( ) => await protocol . callTool ( mockClient , "any.tool" , { } , callTemplate ) ;
241+ await expect ( action ( ) ) . rejects . toThrow ( / E i t h e r f i l e _ p a t h o r c o n t e n t m u s t b e p r o v i d e d / ) ;
242+ } ) ;
150243 } ) ;
151244
152245 describe ( "callToolStreaming" , ( ) => {
153246 test ( "should yield the file content as a single chunk" , async ( ) => {
154247 const fileContent = JSON . stringify ( { data : "stream content" } ) ;
155248 const filePath = await createTempFile ( "stream.json" , fileContent ) ;
156- const callTemplate : CallTemplateBase = {
249+ const callTemplate : TextCallTemplate = {
157250 name : "streaming_file_tool" ,
158251 call_template_type : 'text' ,
159252 file_path : filePath
160- } as TextCallTemplate ;
253+ } ;
161254
162255 const stream = protocol . callToolStreaming ( mockClient , "any.tool" , { } , callTemplate ) ;
163256
0 commit comments