@@ -27,7 +27,7 @@ import {
2727 type AgentToolCall ,
2828 type AgentToolCallRecord ,
2929} from "@superdurable/dex-agents" ;
30- import { connectorTool } from "@superdurable/dex-agents/connectors" ;
30+ import { ConnectorToolSource , connectorTool } from "@superdurable/dex-agents/connectors" ;
3131import {
3232 AgentSessionTestClient ,
3333 AgentTestEnvironment ,
@@ -49,6 +49,8 @@ import {
4949 CloseAccountInputSchema ,
5050 CloseAccountOperation ,
5151 FakeLedgerProvider ,
52+ GetBalanceInputSchema ,
53+ GetBalanceOperation ,
5254 fakeLedgerConnection ,
5355 fakeLedgerStateDirectoryVariable ,
5456} from "../fixtures/fake-ledger.js" ;
@@ -100,11 +102,24 @@ describe("connector tools refused when the OpenAI Agents session is defined", ()
100102 ) ;
101103 } ) ;
102104
103- test ( "a source tool that the SDK renames to a function tool name is refused" , ( ) => {
105+ function createBalanceToolSource ( toolNames : readonly string [ ] ) : ConnectorToolSource {
106+ const provider = new FakeLedgerProvider ( stateDirectory ) ;
107+ return new ConnectorToolSource (
108+ toolNames . map ( ( name ) =>
109+ connectorTool ( new GetBalanceOperation ( provider ) , fakeLedgerConnection , {
110+ manifest : readFakeLedgerManifest ( ) ,
111+ inputValidator : GetBalanceInputSchema ,
112+ name,
113+ } ) ,
114+ ) ,
115+ ) ;
116+ }
117+
118+ test ( "a source tool that the model sees under a function tool name is refused" , ( ) => {
104119 const startingAgent = createConnectorStartingAgent ( stateDirectory ) . clone ( {
105120 tools : [
106121 tool ( {
107- name : "fake_ledger_get_balance " ,
122+ name : "ledger_balance " ,
108123 description : "A local balance tool." ,
109124 parameters : z . object ( { accountId : z . string ( ) } ) ,
110125 execute : async ( ) => "local" ,
@@ -114,13 +129,26 @@ describe("connector tools refused when the OpenAI Agents session is defined", ()
114129 assert . throws (
115130 ( ) =>
116131 createOpenAIAgentsSessionFlow ( startingAgent , "RenamedConnectorAgent" , {
117- toolSources : [ createLedgerToolSource ( stateDirectory ) ] ,
132+ toolSources : [ createBalanceToolSource ( [ "ledger.balance" ] ) ] ,
118133 } ) ,
119134 {
120135 name : "TypeError" ,
121136 message :
122- "tool fake-ledger_get_balance of a tool source becomes function tool fake_ledger_get_balance, the name of " +
123- "a tool or handoff of the agent graph" ,
137+ "tool ledger.balance of a tool source becomes function tool ledger_balance, the name of a tool or handoff " +
138+ "of the agent graph" ,
139+ } ,
140+ ) ;
141+ } ) ;
142+
143+ test ( "two source tools that the model would see under one name are refused" , ( ) => {
144+ assert . throws (
145+ ( ) =>
146+ createOpenAIAgentsSessionFlow ( createConnectorStartingAgent ( stateDirectory ) , "CollidingSourceToolsAgent" , {
147+ toolSources : [ createBalanceToolSource ( [ "ledger.balance" , "ledger_balance" ] ) ] ,
148+ } ) ,
149+ {
150+ name : "TypeError" ,
151+ message : "tools ledger.balance and ledger_balance of tool sources both become function tool ledger_balance" ,
124152 } ,
125153 ) ;
126154 } ) ;
@@ -245,14 +273,51 @@ describe("connector tools in an OpenAI Agents session on a Dex engine", () => {
245273 ] ) ;
246274 } ) ;
247275
248- test ( "a tool under its default connector name runs through its source" , async ( ) => {
276+ test ( "the model sees each source tool by its source name, with its -" , async ( ) => {
277+ await startHarness ( ) ;
278+ const sessionId = `connector-${ randomUUID ( ) } ` ;
279+ await sessions . startSession ( sessionId , "tools" ) ;
280+ assert . deepEqual ( ( await answerLines ( sessionId , 1 ) ) . sort ( ) , [
281+ "approved_payout" ,
282+ "create_payout" ,
283+ "echo_text" ,
284+ "fake-ledger_get_balance" ,
285+ "fake_ledger_get_balance" ,
286+ "get_balance" ,
287+ "post_note" ,
288+ "post_note_retried" ,
289+ ] ) ;
290+ } ) ;
291+
292+ test ( "two tools that differ only by - and _ each run through their own name and policy" , async ( ) => {
249293 const harness = await startHarness ( ) ;
250294 const sessionId = `connector-${ randomUUID ( ) } ` ;
251- await sessions . startSession ( sessionId , calls ( [ [ "fake_ledger_get_balance" , { accountId : "a-2" } ] ] , "default-name" ) ) ;
252- const [ record ] = await heldRecords ( harness , sessionId , "default-name" , 1 ) ;
253- assert . equal ( record ?. toolName , "fake-ledger_get_balance" ) ;
254- assert . equal ( record ?. status , "succeeded" ) ;
255- assert . deepEqual ( await answerLines ( sessionId , 1 ) , [ 'fake_ledger_get_balance: {"accountId":"a-2","amount":100}' ] ) ;
295+ await sessions . startSession (
296+ sessionId ,
297+ calls (
298+ [
299+ [ "fake-ledger_get_balance" , { accountId : "a-2" } ] ,
300+ [ "fake_ledger_get_balance" , { accountId : "a-3" } ] ,
301+ ] ,
302+ "default-name" ,
303+ ) ,
304+ ) ;
305+ // Only the default name's toolPolicies entry requires approval.
306+ const interrupt = await sessions . waitForPendingInterrupt ( sessionId ) ;
307+ assert . equal ( interrupt . toolName , "fake-ledger_get_balance" ) ;
308+ assert . equal ( await sessions . resolveInterrupt ( sessionId , interrupt . interruptId , true ) , true ) ;
309+ const records = await heldRecords ( harness , sessionId , "default-name" , 2 ) ;
310+ assert . deepEqual (
311+ records . map ( ( record ) => [ record . toolName , record . status ] ) ,
312+ [
313+ [ "fake-ledger_get_balance" , "succeeded" ] ,
314+ [ "fake_ledger_get_balance" , "succeeded" ] ,
315+ ] ,
316+ ) ;
317+ assert . deepEqual ( await answerLines ( sessionId , 1 ) , [
318+ 'fake-ledger_get_balance: {"accountId":"a-2","amount":100}' ,
319+ 'fake_ledger_get_balance: {"accountId":"a-3","amount":100}' ,
320+ ] ) ;
256321 } ) ;
257322
258323 test ( "an approved Mutation runs once after its approval" , async ( ) => {
0 commit comments