agentnet 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,74 @@
1
+ import { Agent, NatsIO, Gemini } from "../index.js"
2
+
3
+ const basicAgent = await Agent()
4
+ .addIO(NatsIO({
5
+ servers: ['nats://localhost:4222']
6
+ }), {
7
+ tasks: ['basicagent'],
8
+ handoffs: ['mathagents.*']
9
+ })
10
+ .withLLM(Gemini, {
11
+ model: 'gemini-2.0-flash',
12
+ systemInstruction: `
13
+ You are an traveler agency agent.
14
+ Your role is to answer about the traveler (user) reservation.
15
+ `,
16
+ config: {
17
+ temperature: 0,
18
+ toolConfig: {
19
+ functionCallingConfig: {
20
+ mode: 'auto'
21
+ }
22
+ }
23
+ }
24
+ })
25
+ .on('prompt', async (state, input) => {
26
+ return input
27
+ })
28
+ .compile()
29
+
30
+ const mathAgent = await Agent()
31
+ .addIO(NatsIO({
32
+ servers: ['nats://localhost:4222']
33
+ }), {
34
+ tasks: ['mathagents.v1']
35
+ })
36
+ .withLLM(Gemini, {
37
+ model: 'gemini-2.0-flash',
38
+ systemInstruction: `
39
+ You are an traveler agency agent.
40
+ Your role is to answer about the traveler (user) reservation.
41
+ `,
42
+ config: {
43
+ temperature: 0,
44
+ toolConfig: {
45
+ functionCallingConfig: {
46
+ mode: 'auto'
47
+ }
48
+ }
49
+ }
50
+ })
51
+ .addDiscoverySchema({
52
+ name: 'math_agent',
53
+ type: 'function',
54
+ description: 'Solve the math problem',
55
+ parameters: {
56
+ type: 'object',
57
+ properties: {
58
+ question: {
59
+ type: 'string',
60
+ description: 'Math problem to solve',
61
+ }
62
+ },
63
+ required: ['question']
64
+ }
65
+ })
66
+ .on('prompt', async (state, input) => {
67
+ return input
68
+ })
69
+ .compile()
70
+
71
+ const result = await basicAgent.query("How 2 + 2 is?")
72
+ console.log(result)
73
+
74
+
@@ -0,0 +1,65 @@
1
+ import { AgentLoader, AgentClient, NatsIO } from "../index.js"
2
+
3
+ const agents = await AgentLoader('./src/examples/agents.yaml')
4
+
5
+ const agentTravel = await agents.advancedTravelAgent
6
+ agentTravel.tools.flightSearchTool.bind(async (state, input) => {
7
+ return { answer: "The fly is from New York to Los Angeles at 10:00 AM" }
8
+ })
9
+ await agentTravel.compile()
10
+
11
+ const agentWeather = await agents.weatherAgent
12
+ agentWeather.tools.weatherSearchTool.bind(async (state, input) => {
13
+ return { answer: "The weather in New York is sunny" }
14
+ })
15
+ await agentWeather.compile()
16
+
17
+ const agentNews = await agents.newsAgent
18
+ agentNews.tools.newsSearchTool.bind(async (state, input) => {
19
+ return { answer: "Latest news: AI is taking over!" }
20
+ })
21
+ await agentNews.compile()
22
+
23
+ const agentCalculator = await agents.calculatorAgent
24
+ agentCalculator.tools.calculationTool.bind(async (state, input) => {
25
+ return { answer: `The result of ${input.expression} is 42` }
26
+ })
27
+ await agentCalculator.compile()
28
+
29
+ const agentTranslation = await agents.translationAgent
30
+ agentTranslation.tools.translationTool.bind(async (state, input) => {
31
+ return { answer: `'${input.text}' translated to ${input.targetLanguage} is 'Hola Mundo'` }
32
+ })
33
+ await agentTranslation.compile()
34
+
35
+ const agentCalendar = await agents.calendarAgent
36
+ agentCalendar.tools.createEventTool.bind(async (state, input) => {
37
+ return { answer: `Event '${input.title}' created for ${input.startTime}` }
38
+ })
39
+ agentCalendar.tools.listEventsTool.bind(async (state, input) => {
40
+ return { answer: `Events for ${input.startDate}: Meeting at 10 AM` }
41
+ })
42
+ await agentCalendar.compile()
43
+
44
+ const agentStockTicker = await agents.stockTickerAgent
45
+ agentStockTicker.tools.stockPriceTool.bind(async (state, input) => {
46
+ return { answer: `The price of ${input.symbol} is $100` }
47
+ })
48
+ await agentStockTicker.compile()
49
+
50
+ const io = NatsIO({
51
+ servers: ['nats://localhost:4222']
52
+ })
53
+
54
+ const agentClient = AgentClient()
55
+ //const res = await agentClient.queryAgent(agentTravelInstance, "Find me a flight from New York to Los Angeles")
56
+ //console.log(res)
57
+
58
+ // Wait for 2 seconds before proceeding
59
+ await new Promise(resolve => setTimeout(resolve, 2000));
60
+
61
+ const res = await agentClient.queryIo(io, 'advancedTravelAgent', "Find me a flight from New York to Los Angeles. How is the weather in New York? Give me some news. Also create the birthday event for my friend tomorrow 09-05-2025. RETURN TO ME THE RESULTS")
62
+ console.log(res)
63
+
64
+ //const res = await agent.query("Find me a flight from New York to Los Angeles")
65
+ //console.log(res)
@@ -0,0 +1,67 @@
1
+ import { AgentLoaderFile, AgentClient, NatsIO, Bindings, Message, PostgresStore } from "../index.js"
2
+
3
+ // NatsIO instance
4
+ const io = NatsIO({
5
+ servers: ['nats://localhost:4222']
6
+ })
7
+
8
+ // Load the agents from the YAML file
9
+ const agents = await AgentLoaderFile('./src/examples/agents-smartness.yaml', {
10
+ bindings: { [Bindings.NatsIO]: io, [Bindings.Postgres]: PostgresStore() }
11
+ })
12
+
13
+ // Entry point
14
+ const agentSmartness = await agents.smartnessAgent
15
+ await agentSmartness.compile()
16
+
17
+ // Accomodation agent
18
+ const agentAccomodation = await agents.accomodationAgent
19
+ agentAccomodation.tools.getRoomsListTool.bind(async (state, input) => {
20
+ return { answer: "We have Double room with a view of the sea and a single room with a view of the pool, and a suite with a view of the city." }
21
+ })
22
+ agentAccomodation.tools.getRoomDetailTool.bind(async (state, input) => {
23
+ return { answer: "The Double room with a view of the sea has a king size bed, a private balcony, and a view of the sea." }
24
+ })
25
+ agentAccomodation.prompt(async (state, input) => {
26
+ state._accomodationAgent = true
27
+ return input
28
+ })
29
+ await agentAccomodation.compile()
30
+
31
+ // Booking agent
32
+ const agentBooking = await agents.bookingAgent
33
+ agentBooking.tools.bookRoomTool.bind(async (state, input) => {
34
+ return { answer: "The room " + input.roomName + " has been booked for the dates " + input.checkinDate + " to " + input.checkoutDate + "." }
35
+ })
36
+ await agentBooking.compile()
37
+
38
+ // Hotel review agent
39
+ const agentHotelReview = await agents.hotelReviewAgent
40
+ agentHotelReview.tools.getHotelReviewsTool.bind(async (state, input) => {
41
+ return { answer: "The hotel " + input.hotelName + " has a 4.5 star rating and a 9.2 out of 10 guest satisfaction score." }
42
+ })
43
+ await agentHotelReview.compile()
44
+
45
+ // Pricing agent
46
+ const agentPricing = await agents.pricingAgent
47
+ agentPricing.tools.getPricingTool.bind(async (state, input) => {
48
+ return { answer: "The room " + input.roomName + " has a price of 200€ per night." }
49
+ })
50
+ await agentPricing.compile()
51
+
52
+ // Wait for 2 seconds before proceeding in order to allow self discovery
53
+ await new Promise(resolve => setTimeout(resolve, 2000))
54
+
55
+ // Agent client
56
+ const agentClient = AgentClient()
57
+ const message = new Message({
58
+ content: "What rooms do you have from 2025-05-25 to 2025-05-30 for 3 guests For the hotel Flora? Give me the review of the hotel Flora",
59
+ session: {
60
+ id: "67a71e42-a7d8-1db2-ad17-64e1c8546b21"
61
+ }
62
+ })
63
+ const res = await agentClient.queryIo(io, 'smartnessAgent', message)
64
+ console.log("=======\n", res.getContent())
65
+ console.log("=======\n", res.getSession())
66
+ //const res2 = await agentClient.queryIo(io, 'smartnessAgent', "Quanto costa la camera doppia del Flora per il 10-05-2025 per due persone? Prenotala se costa meno di 100€ la camera double con vista mare per il 10-05-2025 al hotel Flora")
67
+ //console.log("=======\n", res2)
@@ -0,0 +1,103 @@
1
+ import { AgentLoaderJSON, Message, Bindings, PostgresStore } from "../index.js"
2
+
3
+ const agentDefinition = {
4
+ "apiVersion": "smartagent.io/v1alpha1",
5
+ "kind": "AgentDefinition",
6
+ "metadata": {
7
+ "name": "accomodationAgent",
8
+ "namespace": "smartchat"
9
+ },
10
+ "spec": {
11
+ "store": {
12
+ "type": "Postgres",
13
+ },
14
+ "llm": {
15
+ "provider": "Gemini",
16
+ "model": "gemini-2.0-flash",
17
+ "systemInstruction": "You are a highly advanced accomodation manager agent. \nPrioritize clarity and helpfulness.\nUse tools effectively to gather information.\n",
18
+ "config": {
19
+ "temperature": 0.5,
20
+ "toolConfig": {
21
+ "functionCallingConfig": {
22
+ "mode": "auto"
23
+ }
24
+ }
25
+ }
26
+ },
27
+ "tools": [
28
+ {
29
+ "name": "getRoomsListTool",
30
+ "description": "Retrieves a list of available rooms based on criteria.",
31
+ "parameters": {
32
+ "type": "object",
33
+ "properties": {
34
+ "checkinDate": {
35
+ "type": "string",
36
+ "description": "The check-in date."
37
+ },
38
+ "checkoutDate": {
39
+ "type": "string",
40
+ "description": "The check-out date."
41
+ },
42
+ "guests": {
43
+ "type": "integer",
44
+ "description": "Number of guests."
45
+ }
46
+ },
47
+ "required": [
48
+ "checkinDate",
49
+ "checkoutDate"
50
+ ]
51
+ }
52
+ },
53
+ {
54
+ "name": "getRoomDetailTool",
55
+ "description": "Retrieves detailed information about a specific room.",
56
+ "parameters": {
57
+ "type": "object",
58
+ "properties": {
59
+ "roomName": {
60
+ "type": "string",
61
+ "description": "The name of the room."
62
+ }
63
+ },
64
+ "required": [
65
+ "roomName"
66
+ ]
67
+ }
68
+ }
69
+ ]
70
+ }
71
+ }
72
+
73
+ // Load the agent definition
74
+ const agents = await AgentLoaderJSON(agentDefinition, {
75
+ bindings: {
76
+ [Bindings.Postgres]: PostgresStore()
77
+ }
78
+ })
79
+
80
+ // Add the binding tools to the agent
81
+ agents.accomodationAgent.tools.getRoomsListTool.bind(async (state, input) => {
82
+ return { answer: "We have Double room with a view of the sea and a single room with a view of the pool, and a suite with a view of the city." }
83
+ })
84
+ agents.accomodationAgent.tools.getRoomDetailTool.bind(async (state, input) => {
85
+ return { answer: "The Double room with a view of the sea has a king size bed, a private balcony, and a view of the sea." }
86
+ })
87
+
88
+ // Compile the agent
89
+ const agentInstance = await agents.accomodationAgent.compile()
90
+ const input = new Message("What rooms do you have from 2025-05-10 to 2025-05-15 for 2 guests?")
91
+
92
+ const input2 = new Message({
93
+ content: "What rooms do you have from 2025-05-10 to 2025-05-15 for 2 guests?",
94
+ session: {
95
+ id: "67a71e42-a7d8-1db2-ad17-64e1c8546b21",
96
+ propertySetId: "123"
97
+ }
98
+ })
99
+
100
+
101
+ const result = await agentInstance.query(input2)
102
+
103
+ console.log(result.getContent())
package/src/index.js ADDED
@@ -0,0 +1,115 @@
1
+ import * as _Agent from "./agent/agent.js";
2
+ import * as _AgentLoader from "./agent/agent-loader.js";
3
+ import * as _AgentClient from "./agent/client.js";
4
+ import _Gemini from "./llm/gemini.js";
5
+ import _GPT from "./llm/gpt.js";
6
+ import {
7
+ redisStore,
8
+ postgresStore,
9
+ memoryStore,
10
+ session
11
+ } from "./store/store.js";
12
+
13
+ export const AgentLoaderFile = _AgentLoader.AgentLoaderFile
14
+ export const AgentLoaderJSON = _AgentLoader.AgentLoaderJSON
15
+
16
+ export const Agent = _Agent.Agent
17
+ export const AgentClient = _AgentClient.AgentClient
18
+ export const LLMRuntime = {
19
+ GPT: _GPT,
20
+ Gemini: _Gemini
21
+ }
22
+
23
+ export const Gemini = _Gemini
24
+ export const GPT = _GPT
25
+
26
+ export const PostgresStore = postgresStore
27
+ export const RedisStore = redisStore
28
+ export const MemoryStore = memoryStore
29
+ export const SessionStore = session
30
+
31
+ import { connect } from "@nats-io/transport-node"
32
+ export const NatsIO = (config) => {
33
+ let connected = false
34
+ let nc = null
35
+ return {
36
+ type: 'NatsIO',
37
+ connect: async () => {
38
+ if (connected) {
39
+ return nc
40
+ }
41
+ nc = await connect(config)
42
+ connected = true
43
+ return nc
44
+ },
45
+ query: async (target, message) => {
46
+ const nc = await this.connect()
47
+ return await nc.request(target, message.serialize(), {replyTo: target + '.reply'})
48
+ }
49
+ }
50
+ }
51
+ export const Bindings = {
52
+ NatsIO: 'NatsIO',
53
+ Postgres: 'Postgres',
54
+ Redis: 'Redis',
55
+ Memory: 'Memory'
56
+ }
57
+
58
+ export class Message {
59
+ #content
60
+ #session
61
+ constructor(input) {
62
+ if (typeof input === 'string') {
63
+ this.#content = input
64
+ } else {
65
+ this.#content = input.content
66
+ this.#session = input.session || {}
67
+ }
68
+ }
69
+ getContent() {
70
+ return this.#content
71
+ }
72
+ getSessionId() {
73
+ return this.#session.id || null
74
+ }
75
+ getSession() {
76
+ return this.#session
77
+ }
78
+ serialize() {
79
+ return JSON.stringify({
80
+ content: this.#content,
81
+ session: this.#session
82
+ })
83
+ }
84
+ deserialize(data) {
85
+ const parsed = JSON.parse(data)
86
+ this.#content = parsed.content
87
+ this.#session = parsed.session || {}
88
+ }
89
+ }
90
+
91
+ export class Response {
92
+ #content
93
+ #session
94
+ constructor(output) {
95
+ this.#content = output.content
96
+ this.#session = output.session
97
+ }
98
+ getContent() {
99
+ return this.#content
100
+ }
101
+ getSession() {
102
+ return this.#session
103
+ }
104
+ serialize() {
105
+ return JSON.stringify({
106
+ content: this.#content,
107
+ session: this.#session
108
+ })
109
+ }
110
+ deserialize(data) {
111
+ const parsed = JSON.parse(data)
112
+ this.#content = parsed.content
113
+ this.#session = parsed.session
114
+ }
115
+ }
@@ -0,0 +1,155 @@
1
+ import { GoogleGenAI } from '@google/genai'
2
+ import { logger } from '../utils/logger.js'
3
+ import { LLMError } from '../errors/index.js'
4
+
5
+ const type = 'gemini'
6
+
7
+ const getClient = async function () {
8
+ try {
9
+ if (!process.env.GEMINI_API_KEY) {
10
+ throw new LLMError(
11
+ 'GEMINI_API_KEY environment variable is not set',
12
+ 'gemini'
13
+ );
14
+ }
15
+
16
+ logger.debug('Initializing Gemini client');
17
+ return new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
18
+ } catch (error) {
19
+ logger.error('Failed to initialize Gemini client', { error });
20
+ throw new LLMError(
21
+ `Failed to initialize Gemini client: ${error.message}`,
22
+ 'gemini',
23
+ { originalError: error }
24
+ );
25
+ }
26
+ }
27
+
28
+ const callModel = async function (llmClientConfig, context) {
29
+ const client = context.client;
30
+ const toolsAndHandoffsMap = context.toolsAndHandoffsMap;
31
+ const conversation = context.conversation;
32
+ const input = {};
33
+
34
+ Object.assign(input, llmClientConfig);
35
+ input['contents'] = conversation;
36
+
37
+ if (input.config !== undefined && input.tools !== undefined) {
38
+ input.config.tools = toolsAndHandoffsMap.tools;
39
+ } else if (toolsAndHandoffsMap.tools.length > 0) {
40
+ if (input.config == undefined) {
41
+ input.config = {};
42
+ }
43
+ input.config.tools = [{ functionDeclarations: toolsAndHandoffsMap.tools }];
44
+ }
45
+
46
+ logger.debug('Calling Gemini model', {
47
+ model: input.model,
48
+ conversationLength: conversation.length,
49
+ toolsCount: toolsAndHandoffsMap.tools.length
50
+ });
51
+
52
+ try {
53
+ const res = await client.models.generateContent(input);
54
+ logger.debug('Gemini response received', {
55
+ responseType: res.response?.candidates ? 'candidates' : 'unknown',
56
+ hasContent: !!res.response?.candidates?.[0]?.content
57
+ });
58
+ return res;
59
+ } catch (error) {
60
+ logger.error('Gemini API error', {
61
+ error,
62
+ modelName: input.model
63
+ });
64
+
65
+ throw new LLMError(
66
+ `Gemini API error: ${error.message}`,
67
+ 'gemini',
68
+ {
69
+ statusCode: error.status || error.statusCode,
70
+ modelName: input.model
71
+ }
72
+ );
73
+ }
74
+ }
75
+
76
+ const onResponse = async function (state, conversation, toolsAndHandoffsMap, response) {
77
+ if (response.text !== undefined) {
78
+ logger.debug('Gemini response contains text, returning directly');
79
+ conversation.push({ role: 'model', parts: [{ text: response.text }] });
80
+ return response.text;
81
+ }
82
+
83
+ logger.debug('Gemini response contains function calls', {
84
+ functionCallCount: response.functionCalls?.length || 0
85
+ });
86
+
87
+ for (const toolCall of response.functionCalls) {
88
+ const args = toolCall.args;
89
+ const name = toolCall.name;
90
+
91
+ logger.debug('Executing tool from Gemini', {
92
+ toolName: name,
93
+ argsPreview: JSON.stringify(args).substring(0, 100)
94
+ });
95
+
96
+ try {
97
+ if (!toolsAndHandoffsMap[name] || !toolsAndHandoffsMap[name].function) {
98
+ throw new Error(`Tool "${name}" not found or has no function implementation`);
99
+ }
100
+
101
+ let result = await toolsAndHandoffsMap[name].function(conversation, state, args);
102
+ if (toolsAndHandoffsMap[name].type === 'handoff') {
103
+ const resultParsed = JSON.parse(result)
104
+ // Update state with the result
105
+ if (resultParsed.session) {
106
+ for (const key of Object.keys(resultParsed.session)) {
107
+ state[key] = resultParsed.session[key]
108
+ }
109
+ }
110
+ }
111
+
112
+ const function_response_part = {
113
+ name: name,
114
+ response: typeof result === 'string' ? { answer: result } : result
115
+ };
116
+
117
+ // Append function call and result of the function execution to contents
118
+ conversation.push({ role: 'model', parts: [{ functionCall: toolCall }] });
119
+ conversation.push({ role: 'user', parts: [{ functionResponse: function_response_part }] });
120
+
121
+ logger.debug('Tool execution successful', { toolName: name });
122
+ } catch (error) {
123
+ logger.error(`Error executing tool "${name}"`, { error });
124
+ // Return error as function response
125
+ const errorResponse = {
126
+ name: name,
127
+ response: { error: error.message }
128
+ };
129
+
130
+ conversation.push({ role: 'model', parts: [{ functionCall: toolCall }] });
131
+ conversation.push({ role: 'user', parts: [{ functionResponse: errorResponse }] });
132
+ }
133
+ }
134
+
135
+ return null;
136
+ }
137
+
138
+ const prompt = async function (conversation, formattedPrompt) {
139
+ logger.debug('Adding user prompt to conversation', {
140
+ promptPreview: formattedPrompt.substring(0, 100)
141
+ });
142
+
143
+ conversation.push({
144
+ role: 'user',
145
+ parts: [{ text: formattedPrompt}]
146
+ });
147
+ }
148
+
149
+ export default {
150
+ type,
151
+ getClient,
152
+ prompt,
153
+ callModel,
154
+ onResponse
155
+ }